Initial commit

This commit is contained in:
logicog
2025-05-10 15:52:02 +02:00
parent d35eaa8a49
commit c4835b7a6c
7 changed files with 1301 additions and 0 deletions
+37
View File
@@ -0,0 +1,37 @@
BOOTLOADER_ADDRESS=0x100
CC = sdcc
CC_FLAGS = -mmcs51
ASM = sdas8051
AFLAGS= -plosgff
all: rtlplayground.bin
SRCS= rtlplayground.c rtl837x_flash.c
OBJS= ${SRCS:.c=.rel}
clean:
if [ -e rtlplayground.bin ]; then rm rtlplayground.bin; fi
if [ -e rtlplayground.asm ]; then rm rtlplayground.asm; fi
rm *.ihx *.lk *.lst *.map *.mem *.rel *.rst *.sym *.bin
%.rel: %.c
$(CC) $(CC_FLAGS) -c $<
%.rel: %.asm
${ASM} ${AFLAGS} $^
# mv -f $(addprefix $(basename $^), .lst .rel .sym) .
rtlplayground.ihx: crtstart.rel $(OBJS)
$(CC) $(CC_FLAGS) -Wl-bHOME=${BOOTLOADER_ADDRESS} -o $@ $^
%.img: %.ihx
objcopy --input-target=ihex -O binary $< $@
%.bin: %.img
if [ -e $@ ]; then rm $@; fi
echo "0000000: 00 40" | xxd -r - $@
cat $< >> $@
.PHONY: clean all
.PRECIOUS: %.rel %.ihx
+41
View File
@@ -0,0 +1,41 @@
.globl __start__stack
;--------------------------------------------------------
; Stack segment in internal ram
;--------------------------------------------------------
.area SSEG (DATA)
__start__stack:
.ds 1
.area VECTOR (CODE)
.globl __interrupt_vect
__interrupt_vect:
ljmp __sdcc_gsinit_startup
ljmp _isr_ext0 ; 0x03
.ds 5
ljmp _isr_timer0 ; 0x0b
.ds 5
ljmp _isr_ext1 ; 0x13
.ds 5
reti
.ds 7
ljmp _isr_serial ; 0x23
.ds 5
reti ; 0x2b TIMER 2 IRQ
.ds 7
reti ; 0x33 NOT used by DW8051
.ds 7
reti ; 0x3b Serial port 1 RX/TX IRQ
.ds 7
ljmp _isr_ext2 ; 0x43
.ds 5
ljmp _isr_ext3 ; 0x4b
.globl __start__stack
.area GSINIT0 (CODE)
__sdcc_gsinit_startup::
mov sp,#__start__stack - 1
.area GSFINAL (CODE)
ljmp _bootloader
+338
View File
@@ -0,0 +1,338 @@
/*
* This is driver implementation for the RTL837x flash controller
* This code is in the Public Domain
*/
#include <stdint.h>
#include "rtl837x_stdio.h"
#include "rtl837x_sfr.h"
// DE62B415D3155829
// JEDEC-ID: ef 40 16
/*
void flash_init()
{
// Configure fast read via divider = 4 and read-cmd being 0xbb (for mmio)
SFR_FLASH_CONFIG = 9;
SFR_FLASH_CONF_RCMD = 0xbb;
SFR_FLASH_CONF_DIV = 4;
// Test Controller Busy
while(SFR_FLASH_EXEC_BUSY);
// Write 0 to status register
SFR_FLASH_DUMMYCICLES = 0;
SFR_FLASH_MODEB = 0;
SFR_FLASH_TLEN = 0x19;
SFR_FLASH_CMD = 1;
SFR_FLASH_DATA0 = 0;
SFR_FLASH_EXEC_GO = 1;
while(SFR_FLASH_EXEC_BUSY);
// Set some idle mode
SFR_FLASH_MODEB = 0x18;
SFR_FLASH_CMD_R = 0xbb; // By default we read with Dual speed
SFR_FLASH_DUMMYCICLES = 4;
}
*/
void flash_init(void)
{
// Configure fast read via divider = 8 and read-cmd being 0xb (for mmio)
SFR_FLASH_CONFIG = 9;
SFR_FLASH_CONF_RCMD = 0xb;
SFR_FLASH_CONF_DIV = 8;
// Test Controller Busy
while(SFR_FLASH_EXEC_BUSY);
// Write 0 to status register
SFR_FLASH_DUMMYCICLES = 8;
SFR_FLASH_MODEB = 0;
SFR_FLASH_TLEN = 0x19;
SFR_FLASH_CMD = 1;
SFR_FLASH_DATA0 = 0;
SFR_FLASH_EXEC_GO = 1;
while(SFR_FLASH_EXEC_BUSY);
// Set some idle mode
SFR_FLASH_MODEB = 0x0;
SFR_FLASH_CMD_R = 0xb; // By default we read with single speed
SFR_FLASH_DUMMYCICLES = 8;
}
uint8_t flash_read_status(void)
{
// Test Controller Busy (we might call this directly after executing a command)
while(SFR_FLASH_EXEC_BUSY);
// setup status read command
SFR_FLASH_TLEN = 0x11;
SFR_FLASH_CMD_R = 5;
// execute and wait for controller done
SFR_FLASH_EXEC_GO = 1;
while(SFR_FLASH_EXEC_BUSY);
return SFR_FLASH_DATA0;
}
void flash_read_uid(void)
{
while (flash_read_status() & 0x1);
print_string("\r\n -uid- \r\n");
// Set slow read mode for UID
SFR_FLASH_MODEB = 0x0;
SFR_FLASH_CMD_R = 0x4b;
SFR_FLASH_DUMMYCICLES = 8;
// Transfer 4 bytes (command + 3 dummy bytes)
SFR_FLASH_TLEN = 4;
SFR_FLASH_ADDR16 = 0;
SFR_FLASH_ADDR8 = 0;
SFR_FLASH_ADDR0 = 0;
SFR_FLASH_EXEC_GO = 1;
while(SFR_FLASH_EXEC_BUSY);
print_byte(SFR_FLASH_DATA0);
print_byte(SFR_FLASH_DATA8);
print_byte(SFR_FLASH_DATA16);
print_byte(SFR_FLASH_DATA24);
SFR_FLASH_EXEC_GO = 1;
SFR_FLASH_DUMMYCICLES = 24;
while(SFR_FLASH_EXEC_BUSY);
print_byte(SFR_FLASH_DATA0);
print_byte(SFR_FLASH_DATA8);
print_byte(SFR_FLASH_DATA16);
print_byte(SFR_FLASH_DATA24);
// Reset slow read mode
SFR_FLASH_MODEB = 0x0;
SFR_FLASH_CMD_R = 0xb;
SFR_FLASH_DUMMYCICLES = 8;
}
void flash_read_jedecid(void)
{
while (flash_read_status() & 0x1);
print_string("\r\n -jedec- \r\n");
/*
// Set slow read mode for UID
SFR_FLASH_MODEB = 0x0;
SFR_FLASH_CMD_R = 0x9f;
SFR_FLASH_DUMMYCICLES = 8;
// Transfer 3 bytes back
SFR_FLASH_TLEN = 0x3;
SFR_FLASH_EXEC_GO = 1;
while(SFR_FLASH_EXEC_BUSY);
print_byte(SFR_FLASH_DATA0);
print_byte(SFR_FLASH_DATA8);
print_byte(SFR_FLASH_DATA16);
print_byte(SFR_FLASH_DATA24);
// Reset slow read mode
SFR_FLASH_MODEB = 0x0;
SFR_FLASH_CMD_R = 0xb;
SFR_FLASH_DUMMYCICLES = 8;
while (flash_read_status() & 0x1);
print_string("\r\n -jedec- b- \r\n");
// Set slow read mode for UID
SFR_FLASH_MODEB = 0x0;
SFR_FLASH_CMD_R = 0x9f;
SFR_FLASH_DUMMYCICLES = 8;
// Transfer 3 bytes back
SFR_FLASH_TLEN = 0x13;
SFR_FLASH_EXEC_GO = 1;
while(SFR_FLASH_EXEC_BUSY);
print_byte(SFR_FLASH_DATA0);
print_byte(SFR_FLASH_DATA8);
print_byte(SFR_FLASH_DATA16);
print_byte(SFR_FLASH_DATA24);
// Reset slow read mode
SFR_FLASH_MODEB = 0x0;
SFR_FLASH_CMD_R = 0xb;
SFR_FLASH_DUMMYCICLES = 8;
while (flash_read_status() & 0x1);
print_string("\r\n -jedec- c \r\n");
*/
// Set read mode for JEDEC ID
SFR_FLASH_MODEB = 0x0;
SFR_FLASH_CMD_R = 0x9f;
SFR_FLASH_DUMMYCICLES = 0;
// Transfer 3 bytes back
SFR_FLASH_TLEN = 0x13;
SFR_FLASH_EXEC_GO = 1;
while(SFR_FLASH_EXEC_BUSY);
print_byte(SFR_FLASH_DATA0);
print_byte(SFR_FLASH_DATA8);
print_byte(SFR_FLASH_DATA16);
print_byte(SFR_FLASH_DATA24);
// Reset slow read mode
SFR_FLASH_MODEB = 0x0;
SFR_FLASH_CMD_R = 0xb;
SFR_FLASH_DUMMYCICLES = 8;
}
void flash_write_enable(void)
{
short status;
// Wait until busy bit clear
do {
status = flash_read_status();
print_short(status);
} while (status & 0x1);
// while (flash_read_status() & 0x1);
print_string("\r\n -setting- \r\n");
SFR_FLASH_TLEN = 0x18;
SFR_FLASH_CMD = 6;
SFR_FLASH_EXEC_GO = 1;
do {
status = flash_read_status();
print_short(status);
} while (!(status & 0x2));
}
/*
void flash_dump(uint32_t addr, uint8_t len)
{
short status;
print_string("\r\n -a- \r\n");
do {
status = flash_read_status();
print_short(status);
} while (status & 0x1);
// while (flash_read_status() & 0x1);
print_string("\r\n -b- \r\n");
// Set fast read mode
SFR_FLASH_MODEB = 0x18;
SFR_FLASH_CMD_R = 0xbb;
SFR_FLASH_DUMMYCICLES = 4;
// Read 4 bytes
SFR_FLASH_TLEN = 4;
while (len) {
SFR_FLASH_ADDR16 = addr >> 16;
SFR_FLASH_ADDR8 = addr >> 8;
SFR_FLASH_ADDR0 = addr;
addr += 4;
SFR_FLASH_EXEC_GO = 1;
while(SFR_FLASH_EXEC_BUSY);
print_short(SFR_FLASH_DATA0);
if (len == 1)
return;
print_short(SFR_FLASH_DATA8);
if (len == 2)
return;
print_short(SFR_FLASH_DATA16);
if (len == 3)
return;
print_short(SFR_FLASH_DATA24);
len -= 4;
}
}
*/
void flash_read_security(uint32_t addr, uint8_t len)
{
while (flash_read_status() & 0x1);
print_string("\r\n -b- \r\n");
// Set slow read mode
SFR_FLASH_MODEB = 0x0;
SFR_FLASH_CMD_R = 0x48; // read security register
SFR_FLASH_DUMMYCICLES = 8; // Add 8 dummy clocks as for fast read
// Transfer 4 bytes (command + 3byte address)
SFR_FLASH_TLEN = 4;
while (len) {
SFR_FLASH_ADDR16 = addr >> 16;
SFR_FLASH_ADDR8 = addr >> 8;
SFR_FLASH_ADDR0 = addr;
addr += 4;
SFR_FLASH_EXEC_GO = 1;
while(SFR_FLASH_EXEC_BUSY);
print_byte(SFR_FLASH_DATA0);
if (len == 1)
return;
print_byte(SFR_FLASH_DATA8);
if (len == 2)
return;
print_byte(SFR_FLASH_DATA16);
if (len == 3)
return;
print_byte(SFR_FLASH_DATA24);
len -= 4;
}
}
void flash_dump(uint32_t addr, uint8_t len)
{
while (flash_read_status() & 0x1);
print_string("\r\n -b- \r\n");
// Set slow read mode
SFR_FLASH_MODEB = 0x0;
SFR_FLASH_CMD_R = 0xb; // Fast read
SFR_FLASH_DUMMYCICLES = 8; // Add 8 dummy clocks after read?
// Transfer 4 bytes (command + 3byte address)
SFR_FLASH_TLEN = 4;
while (len) {
SFR_FLASH_ADDR16 = addr >> 16;
SFR_FLASH_ADDR8 = addr >> 8;
SFR_FLASH_ADDR0 = addr;
addr += 4;
SFR_FLASH_EXEC_GO = 1;
while(SFR_FLASH_EXEC_BUSY);
print_byte(SFR_FLASH_DATA0);
if (len == 1)
return;
print_byte(SFR_FLASH_DATA8);
if (len == 2)
return;
print_byte(SFR_FLASH_DATA16);
if (len == 3)
return;
print_byte(SFR_FLASH_DATA24);
len -= 4;
}
}
+13
View File
@@ -0,0 +1,13 @@
#ifndef _RTL837X_FLASH_H_
#define _RTL837X_FLASH_H_
#include <stdint.h>
uint8_t flash_read_status(void);
void flash_init(void);
void flash_read_uid(void);
void flash_write_enable(void);
void flash_dump(uint32_t addr, uint8_t len);
void flash_read_jedecid(void);
void flash_read_security(uint32_t addr, uint8_t len);
#endif
+69
View File
@@ -0,0 +1,69 @@
/* SFR control registers for switch register access */
__sfr __at(0xa0) SFR_EXEC_GO;
__sfr __at(0xa1) SFR_EXEC_STATUS;
__sfr __at(0xa2) SFR_REG_ADDRH;
__sfr __at(0xa3) SFR_REG_ADDRL;
__sfr __at(0xa4) SFR_DATA_24;
__sfr __at(0xa5) SFR_DATA_16;
__sfr __at(0xa6) SFR_DATA_8;
__sfr __at(0xa7) SFR_DATA_0;
/* SFR control registers for phy access via SMI/MDIO */
__sfr __at(0xc2) SFR_SMI_REG_H;
__sfr __at(0xc3) SFR_SMI_REG_L;
__sfr __at(0xc4) SFR_SMI_DEV;
__sfr __at(0xc5) SFR_SMI_PHYMASK;
#define SFR_SMI_PHY SFR_DATA_16
/* Extended IRQ EIE register for external interrupts */
__sfr __at(0xe8) EIE;
__sbit __at(0xe8) EX2;
__sbit __at(0xe9) EX3;
/* EXIF additional external IRQ control register */
__sfr __at(0x91) EXIF;
/* Extended IRQ EIP register for external interrupt priority */
__sfr __at(0xf8) EIP;
__sbit __at(0xf9) PX3;
/* SFR control registers for serial communication */
__sfr __at(0xc8) T2CON;
__sfr __at(0xca) RCAP2L;
__sfr __at(0xcb) RCAP2H;
/* SFR Bank control register: 0x0-3f. A value of 0 is bank 1 */
__sfr __at(0x96) SFR_BANK;
__sfr __at(0x8e) CKCON;
__sfr __at(0x97) SFR_97;
__sfr __at(0xb9) SFR_b9;
__sfr __at(0xba) SFR_ba;
/* FLASH controller SFRs */
__sfr __at(0x80) SFR_FLASH_EXEC;
__sbit __at(0x82) SFR_FLASH_EXEC_GO;
__sbit __at(0x80) SFR_FLASH_EXEC_BUSY;
__sfr __at(0xb1) SFR_FLASH_CMD_R;
__sfr __at(0xb2) SFR_FLASH_CMD;
__sfr __at(0xbc) SFR_FLASH_CONFIG;
__sfr __at(0x9b) SFR_FLASH_CONF_DIV;
__sfr __at(0x9c) SFR_FLASH_CONF_RCMD;
__sfr __at(0x9d) SFR_FLASH_DUMMYCICLES;
__sfr __at(0x9a) SFR_FLASH_MODEB;
__sfr __at(0x9e) SFR_FLASH_TLEN;
__sfr __at(0xaf) SFR_FLASH_DATA24;
__sfr __at(0xae) SFR_FLASH_DATA16;
__sfr __at(0xad) SFR_FLASH_DATA8;
__sfr __at(0xac) SFR_FLASH_DATA0;
__sfr __at(0xab) SFR_FLASH_ADDR16;
__sfr __at(0xaa) SFR_FLASH_ADDR8;
__sfr __at(0xa9) SFR_FLASH_ADDR0;
+8
View File
@@ -0,0 +1,8 @@
#ifndef _RTL837X_STDIO_H_
#define _RTL837X_STDIO_H_
void print_string(__code char *p);
void print_short(unsigned short a);
void print_byte(unsigned char a);
#endif
+795
View File
@@ -0,0 +1,795 @@
#include <8051.h>
#include <stdint.h>
#include "rtl837x_sfr.h"
#include "rtl837x_flash.h"
#define SYS_TICK_HZ 100
#define SERIAL_BAUD_RATE 57600
/* All RTL839x switches have an external 25MHz Oscillator,
VALID RTL8372/3 CPU frequencies found in switches are:
0x07735940 = 125,000,000
0x03b9aca0 = 62,500,000
0x01dcd650 = 31,250,000
0x013d6200 = 20,800,000
For the following frequencies, divider settings are known
and can be selected on all known HW (Register 0x6040)
*/
#define CLOCK_HZ 125000000
// #define CLOCK_HZ 20800000
// Derive the divider settings for the internal clock
#if CLOCK_HZ == 20800000
#define CLOCK_DIV 3
#elif CLOCK_HZ == 31250000
#define CLOCK_DIV 2
#elif CLOCK_HZ == 62500000
#define CLOCK_DIV 1
#elif CLOCK_HZ == 125000000
#define CLOCK_DIV 0
#endif
#define RTL837X_REG_LED_MODE 0x6520
#define RTL837X_REG_SMI_CTRL 0x6454
#define RTL837X_REG_RESET 0x0024
// Blink rate is defined by setAsicRegBits(0x6520,0xe00000,rate);
#define SFR_EXEC_READ_REG 1
#define SFR_EXEC_WRITE_REG 3
#define SFR_EXEC_READ_SMI 9
#define SFR_EXEC_WRITE_SMI 11
__xdata unsigned short ticks;
#define N_WORDS 10
__xdata signed char cmd_words_b[N_WORDS];
// Buffer for serial input, SBUF_SIZE must be power of 2 < 256
#define SBUF_SIZE 32
__xdata char sbuf_ptr;
__xdata unsigned sbuf[SBUF_SIZE];
__code unsigned char * __code greeting = "HI! This is a minimal prompt to explore the RTL8372!\r\n";
__code unsigned char * __code hex = "0123456789abcdef";
#define N_COMMANDS 1
struct command {
unsigned char *cmd;
unsigned char id;
};
void isr_timer0(void) __interrupt(1)
{
TR0 = 0; // Stop timer 0
TH0 = (0x10000 - (CLOCK_HZ / SYS_TICK_HZ / 32)) >> 8;
TL0 = (0x10000 - (CLOCK_HZ / SYS_TICK_HZ / 32)) % 0xff;
ticks++;
/*
SFR_DATA_24 = 0x00;
SFR_DATA_16 = 0x23;
SFR_DATA_8 = 0xe0;
SFR_DATA_0 = 0xf0;
SFR_REG_ADDRH = RTL837X_REG_LED_MODE >> 8;
SFR_REG_ADDRL = RTL837X_REG_LED_MODE & 0xff;
SFR_EXEC_GO = SFR_EXEC_WRITE_REG;
do {
} while (SFR_EXEC_STATUS != 0);
*/
TR0 = 1; // Re-start timer 0
}
void isr_serial(void) __interrupt(4)
{
if (RI == 1) {
sbuf[sbuf_ptr] = SBUF;
sbuf_ptr = (sbuf_ptr + 1) & (SBUF_SIZE - 1);
RI = 0;
}
}
void write_char(char c)
{
do {
} while (TI == 0);
TI = 0;
SBUF = c;
}
void print_string(__code char *p)
{
while (*p)
write_char(*p++);
}
void print_short(unsigned short a)
{
print_string("0x");
for (signed char i = 12; i >= 0; i -= 4) {
write_char(hex[(a >> i) & 0xf]);
}
}
void print_byte(unsigned char a)
{
write_char(hex[(a >> 4) & 0xf]);
write_char(hex[a & 0xf]);
write_char(' ');
}
/*
* External IRQ 0 Service Routine
* Note that all registers are being put on the STACK because of calling a subroutine
*/
void isr_ext0(void) __interrupt(0)
{
EX0 = 0;
write_char('X');
IT0 = 1;
EX0 = 1;
}
/*
* External IRQ 1 Service Routine, triggered by the NIC recieving a packet
* Note that all registers are being put on the STACK because of calling
* a subroutine (write_char), we shold do better...
*/
void isr_ext1(void) __interrupt(2)
{
// This flag should only be reset after all packets have been read
EX1 = 0;
write_char('Y');
}
/*
* External IRQ 2 Service Routine
* Note that all registers are being put on the STACK because of calling a subroutine
*/
void isr_ext2(void) __interrupt(8)
{
EXIF &= 0xef; // Clear IRQ flag (bit 7) in EXIF
write_char('Z');
PCON |= 1; // Enter Idle mode until interrupt occurs
}
/*
* External IRQ 3 Service Routine
* Note that all registers are being put on the STACK because of calling a subroutine
*/
void isr_ext3(void) __interrupt(9)
{
EXIF &= 0xdf; // Clear IRQ flag (bit 6) in EXIF
write_char('W');
}
void setup_timer0(void)
{
TMOD = 0x11; // Timer 1: Mode 1, Timer 0: Mode 1, i.e. 16 bit counters, no auto-reload
// The TH0 registers contain the high/low byte that is loaded into
// timer0 when T0 overflows to 0x10000
TH0 = (0x10000 - (CLOCK_HZ / SYS_TICK_HZ / 32)) >> 8;
TL0 = (0x10000 - (CLOCK_HZ / SYS_TICK_HZ / 32)) % 0xff;
TCON = 0x10; // Start timer 0
CKCON &= 0xc7;
ET0 = 1; // Enable timer interrupts
}
void reg_read(uint16_t reg_addr)
{
SFR_REG_ADDRH = reg_addr >> 8;
SFR_REG_ADDRL = reg_addr;
SFR_EXEC_GO = SFR_EXEC_READ_REG;
do {
} while (SFR_EXEC_STATUS != 0);
/* The result is now in SFR A4, A5, A6, A7 */
}
void reg_write(uint16_t reg_addr)
{
/* Data to write must be in SFR A4, A5, A6, A7 */
SFR_REG_ADDRH = reg_addr >> 8;
SFR_REG_ADDRL = reg_addr;
SFR_EXEC_GO = SFR_EXEC_WRITE_REG;
do {
} while (SFR_EXEC_STATUS != 0);
}
/* This sets a bit in the 32bit wide switch register reg_addr
*/
void reg_bit_set(uint16_t reg_addr, char bit)
{
reg_read(reg_addr);
unsigned char bit_mask = 1 << (bit & 0x3);
switch (bit >> 3) {
case 0:
SFR_DATA_0 |= bit_mask;
break;
case 1:
SFR_DATA_8 |= bit_mask;
break;
case 2:
SFR_DATA_16 |= bit_mask;
break;
case 3:
SFR_DATA_24 |= bit_mask;
break;
}
reg_write(reg_addr);
}
/* This sets a bit in the 32bit wide switch register reg_addr
*/
void reg_bit_clear(uint16_t reg_addr, char bit)
{
reg_read(reg_addr);
unsigned char bit_mask = 1 << (bit & 0x3);
bit_mask = ~bit_mask;
switch (bit >> 3) {
case 0:
SFR_DATA_0 &= bit_mask;
break;
case 1:
SFR_DATA_8 &= bit_mask;
break;
case 2:
SFR_DATA_16 &= bit_mask;
break;
case 3:
SFR_DATA_24 &= bit_mask;
break;
}
reg_write(reg_addr);
}
/* Read flash using the MMIO capabilities of the DW8051 core
* Bank is < 0x3f and is the MSB
* addr gives the address in the bank
* Note that the address in the flash memory is not simply 0xbbaddr, because
* the size of a bank is merely 0xc000.
*/
unsigned char read_flash(unsigned char bank, __code unsigned char *addr)
{
unsigned char v;
unsigned char current_bank = SFR_BANK;
SFR_BANK = bank;
v = *addr;
SFR_BANK = current_bank;
return v;
}
void reset_chip(void)
{
SFR_DATA_24 = 0x00;
SFR_DATA_16 = 0x00;
SFR_DATA_8 = 0x00;
SFR_DATA_0 = 0x01;
reg_write(RTL837X_REG_RESET);
}
void setup_external_irqs(void)
{
SFR_DATA_24 = 0x00;
SFR_DATA_16 = 0x00;
SFR_DATA_8 = 0x00;
SFR_DATA_0 = 0x42;
reg_write(0x5f84);
SFR_DATA_8 = 0x03;
SFR_DATA_0 = 0xff;
reg_write(0x5f34);
EX0 = 1; // Enable external IRQ 0
IT0 = 1; // External IRQ on falling edge
EX1 = 1; // External IRQ 1 enable
EX2 = 1; // External IRQ 2 enable: bit EIE.0
EX3 = 1; // External IRQ 3 enable: bit EIE.1
PX3 = 1; // Set EIP.1 = 1: External IRQ 3 set to high priority
}
void reset_rtl8224(void)
{
/* Toggle reset pin on RTL8224 on RTL8373 */
reg_bit_clear(0x40, 4);
reg_bit_set(0x50, 4);
reg_bit_set(0x40, 4);
}
/*
* Set dividers for a chosen CPU frequency
*/
void setup_clock(void)
{
reg_read(0x6040);
SFR_DATA_0 &= ~0x30;
SFR_DATA_0 |= CLOCK_DIV << 4; // Divider in bits 4 & 5
SFR_DATA_8 |= 0x01; // This is set in managed mode 125MHz
reg_write(0x6040);
reg_read(0x7f90);
SFR_DATA_0 &= 0xfd;
SFR_DATA_0 |= 0x01;
reg_write(0x7f90);
}
void print_sfr_data(void)
{
write_char('0');
write_char('x');
write_char(hex[SFR_DATA_24 >> 4]);
write_char(hex[SFR_DATA_24 & 0xf]);
write_char(hex[SFR_DATA_16 >> 4]);
write_char(hex[SFR_DATA_16 & 0xf]);
write_char(hex[SFR_DATA_8 >> 4]);
write_char(hex[SFR_DATA_8 & 0xf]);
write_char(hex[SFR_DATA_0 >> 4]);
write_char(hex[SFR_DATA_0 & 0xf]);
}
/*
* Write a register reg of phy phy_id, in page page
* Data to be written must be in SFR a6/a7
*/
void phy_write(unsigned char phy_mask, unsigned char dev_id, unsigned short reg, unsigned short v)
{
SFR_DATA_8 = v >> 8;
SFR_DATA_0 = v;
SFR_SMI_PHYMASK = phy_mask;
SFR_SMI_REG_H = reg >> 8;
SFR_SMI_REG_L = reg;
SFR_SMI_DEV = dev_id << 3 | 2; //
SFR_EXEC_GO = SFR_EXEC_WRITE_SMI;
do {
} while (SFR_EXEC_STATUS != 0);
}
void rtl8372_init(void)
{
// From run, set bits 0-1 to 1
print_string("rtl8372_init called\r\n");
reg_read(0x7f90);
SFR_DATA_0 &= 0xfc;
SFR_DATA_0 |= 0x01;
reg_write(0x7f90);
reg_read(0x6330);
SFR_DATA_0 |= 0xc0; // Set Bits 6, 7
SFR_DATA_16 &= 0xfc; // Delete bits 16, 17
reg_write(0x6330);
reg_read(0x6334); // Also in sdsMode_set
SFR_DATA_8 |= 0x01; // Set bits 3-8, On RTL8373+8224 set bits 0-7
SFR_DATA_0 |= 0xf8;
reg_write(0x6334);
// Enable MDC
reg_read(RTL837X_REG_SMI_CTRL);
SFR_DATA_8 |= 0x70; // Set bits 0xc-0xe to enable MDC for SMI0-SMI2
reg_write(RTL837X_REG_SMI_CTRL);
/* FUN_CODE_2023();
FUN_CODE_01a6();
*/
reg_read(RTL837X_REG_LED_MODE);
// SFR_DATA_24 = 0x00;
SFR_DATA_16 &= 0x1f; // Mask blink rate field (0xe0)
SFR_DATA_16 |= 0x23; // Set blink rate and LED to solid (set bit 1 = bit 17 overall)
// Configure led-mode (serial?)
SFR_DATA_8 &= 0xe3; // 0xe0;
SFR_DATA_8 |= 0x0c;
SFR_DATA_0 &= 0x1f; // 0xf0;
SFR_DATA_0 |= 0xe0;
reg_write(RTL837X_REG_LED_MODE);
/*
BEFORE: 0x0021fdb0
AFTER: 0x0021fdf0
CORRECT:0x0023e0f0;
rVar1 = rtl8373_setAsicRegBits(0x6520,0xe0 0000,rate);
write_xmem_32((uint *)0xb1,0xc);
write_xmem_32((uint *)0xb5,9);
write_xmem_32((uint *)0xb9,3);
rtl8373_setAsicRegBits_call_b1(0x6520);
write_xmem_32((uint *)0xb1,8);
write_xmem_32((uint *)0xb5,5);
write_xmem_32((uint *)0xb9,5);
rtl8373_setAsicRegBits_call_b1(0x6520); // LED Enable
*/
// Clear bits 0,1 of 0x65f8
reg_read(0x65f8);
SFR_DATA_0 &= 0xfc;
reg_write(0x65f8);
// Set 0x65fc to 0xfffff000
SFR_DATA_24 = 0xff;
SFR_DATA_16 = 0xff;
SFR_DATA_8 = 0xf0;
SFR_DATA_0 = 0x00;
reg_write(0x65fc);
// Set bits 0-3 of 0x6600 to 0xf
reg_read(0x6600);
SFR_DATA_0 |= 0x0f;
reg_write(0x6600);
// Set bit 0x1d of 0x65dc, clear bit 1b
reg_bit_set(0x65dc, 0x1d);
reg_bit_clear(0x65dc, 0x1b);
// Set bits 1b/1d of 0x7f8c
reg_bit_set(0x7f8c, 0x1d);
reg_bit_set(0x7f8c, 0x1b);
// Configure LED_SET_0, ledid 0/1
SFR_DATA_24 = 0x00;
SFR_DATA_16 = 0x41;
SFR_DATA_8 = 0x01;
SFR_DATA_0 = 0x75;
reg_write(0x6548);
// Configure LED_SET_0 ledid 2
reg_read(0x6544);
SFR_DATA_8 = 0x00;
SFR_DATA_0 = 0x44;
reg_write(0x6544);
// Further configure LED_SET_0
reg_read(0x6528);
SFR_DATA_0 = 0x11;
reg_write(0x6528);
// Part of the SDS configuration, see sdsMode_set, set bits 0xa-0xe to 0
reg_read(0x6450);
SFR_DATA_8 &= 0x83;
reg_write(0x6450);
// SDS bits 10-1f set to 0
reg_read(0x644c);
SFR_DATA_8 &= 0xe0;
reg_write(0x644c);
/*
FUN_CODE_018d(0,1,0,8);
FUN_CODE_018d(0,1,0,3);
*/
// Set the SerDes mode. Bits 0-4: SDS 0, Bits 5-9: SDS 1. Bits set to 1f
reg_read(0x7b20);
SFR_DATA_8 |= 0x03;
SFR_DATA_0 = 0xff;
reg_write(0x7b20);
/*
calll_4464_bank1();
calll_4464_bank1();
calll_4464_bank1();
*/
/* FUN_CODE_2023();
phy_setting_up_somehow();
FUN_CODE_2023();
phy_setting_up_somehow();
*/
reg_read(0xa90);
SFR_DATA_0 &= 0xf0;
SFR_DATA_0 |= 0xc;
reg_write(0xa90);
// Disable PHYs for configuration
phy_write(0xf0,0x1f,0xa610,0x2858);
// Set bits 0x13 and 0x14 of 0x5fd4
reg_bit_set(0x5fd4, 0x13);
reg_bit_set(0x5fd4, 0x14);
// Configure ports 3-8:
uint16_t reg = 0x1238 + 0x300; // Port base register for the bits we set
for (char i = 0; i < 6; i++) {
reg_bit_set(reg, 0x2);
reg_bit_set(reg, 0x8);
reg_bit_set(reg, 0x8);
reg += 0x100;
}
reg_bit_set(0xb7c, 5);
reg_bit_set(0x6040, 0);
/*
FUN_CODE_2023();
uVar4 = 1;
FUN_CODE_0617(0x23f);
bVar7 = eql_l(a,uVar4);
if (bVar7 == 0) {
FUN_CODE_019c();
FUN_CODE_01a1();
}
else {
uVar4 = 2;
FUN_CODE_0617(0x23f);
bVar7 = eql_l(a,uVar4);
if (bVar7 == 0) {
FUN_CODE_0192();
FUN_CODE_0197();
}
}
*/
/*
FUN_CODE_01bf();
FUN_CODE_01ab();
FUN_CODE_01b0();
FUN_CODE_01ba();
FUN_CODE_01b5();
*/
// Re-enable PHY after configuration
phy_write(0xf0,0x1f,0xa610,0x2058);;
// Set bits 0xc-0x14 of 0x632c to 0x1f8, see rtl8372_init
reg_read(0x632c);
SFR_DATA_8 &= 0x8f;
SFR_DATA_8 |= 0x80;
SFR_DATA_16 &= 0xe0;
SFR_DATA_16 |= 0x1f;
reg_write(0x632c);
}
/*
* Read a phy register via MDIO clause 45
* Input must be: phy_id < 64, device_id < 32, reg < 0x10000)
* The result is in SFR A6 and A7 (SFR_DATA_8, SFR_DATA_0)
*/
void phy_read(unsigned char phy_id, unsigned char device, unsigned short reg)
{
SFR_SMI_PHY = phy_id;
SFR_SMI_REG_H = reg >> 8;
SFR_SMI_REG_L = reg;
SFR_SMI_DEV = device << 3 | 2;
SFR_EXEC_GO = SFR_EXEC_READ_SMI;
do {
} while (SFR_EXEC_STATUS != 0);
}
void led_enable(void)
{
reg_read(RTL837X_REG_LED_MODE);
SFR_DATA_24 = 0x00;
SFR_DATA_16 = 0x23;
SFR_DATA_8 = 0xe0;
SFR_DATA_0 = 0xf0;
// SFR_DATA_0 &= 0xe0;
// SFR_DATA_8 &= 0x1f;
// SFR_DATA_0 |= 0xe0;
// SFR_DATA_8 |= 0x06;
reg_write(RTL837X_REG_LED_MODE);
}
void led_disable(void)
{
SFR_DATA_24 = 0x00;
SFR_DATA_16 = 0x00;
SFR_DATA_8 = 0x00;
SFR_DATA_0 = 0x00;
reg_write(RTL837X_REG_LED_MODE);
}
void port_leds_on(void)
{
reg_read(0x6528);
SFR_DATA_0 = 0x11;
reg_write(0x6528);
}
/* Set up serial port 0 using Timer 2 with an external trigger
* as baud generator.
* The external clock generator uses a crystal at 25MHz.
*/
void setup_serial(void)
{
IE = 0;
T2CON = 0x34; // Enable RCLK/TCLK (serial transmit/receive clock for T2), TR2 (Timer 2 RUN), disable CP/RL2 (bit 0)
SCON = 0x50; // Mode = 1: ASYNC 8N1 with T2 as baud-rate generator, REN_0 Receive enable
// The RCAP2 registers contain the high/low byte that is loaded into
// timer2 when T2 overflows to 0x10000
RCAP2H = (0x10000 - (CLOCK_HZ / SERIAL_BAUD_RATE / 32)) >> 8;
RCAP2L = (0x10000 - (CLOCK_HZ / SERIAL_BAUD_RATE / 32)) % 0xff;
PCON |= 0x80; // Double the Baud Rate
SCON = 0x50;
TI = 1;
RI = 0;
ES = 1; // Enable serial IRQ
}
void print_reg(unsigned short reg)
{
reg_read(reg);
print_sfr_data();
}
void print_phy_reg(unsigned char phy_id, unsigned char device, unsigned short reg)
{
phy_read(phy_id, device, reg);
SFR_DATA_16 = SFR_DATA_24 = 0;
print_sfr_data();
}
__code struct command commands[N_COMMANDS] = {
{ "reset", 1 },
};
unsigned char cmd_compare(unsigned char start, unsigned char * __code cmd)
{
signed char i;
signed char j = 0;
for (i = cmd_words_b[start]; i < cmd_words_b[start + 1] && sbuf[i] != ' '; i++) {
if (!cmd[j])
return 1;
if (sbuf[i++] != cmd[j++])
break;
}
if (i >= cmd_words_b[start + 1] || sbuf[i] == ' ')
return 1;
return 0;
}
void bootloader(void)
{
ticks = 0;
sbuf_ptr = 0;
CKCON = 0;
SFR_97 = 0;
// Set in managed mode:
SFR_b9 = 0x00;
SFR_ba = 0x80;
// Disable all interrupts (global and individually) by setting IE register (SFR A8) to 0
IE = 0;
EIE = 0; // SFR e8: EIE. Disable all external IRQs
// Disable all interrupts (global interrupt enable bit)
EA = 0; // SFR A8.7 / IE.7
// HW setup, serial, timer, external IRQs
setup_clock();
setup_serial();
setup_timer0();
setup_external_irqs();
EA = 1; // Enable all IRQs
// port_leds_on();
print_string("\r\nStarting up...\r\n");
print_string(" Flash controller\r\n");
flash_init();
print_string(" > OK\r\n current status: ");
print_short(flash_read_status());
print_string("\r\n READ JEDEC-ID\r\n");
flash_read_jedecid();
print_string("\r\n Testing read UID\r\n");
flash_read_uid();
print_string("\r\n Testing read Securty Register 1\r\n");
flash_read_security(0x0001000, 40);
print_string("\r\n Testing read Securty Register 2\r\n");
flash_read_security(0x0002000, 40);
print_string("\r\n Testing read Securty Register 3\r\n");
flash_read_security(0x0003000, 40);
// flash_read_uid();
// flash_write_enable();
print_string(" > status: ");
print_short(flash_read_status());
print_string("\r\n Dumping flash at 0x0\r\n");
flash_dump(0, 252);
print_string("\r\n Dumping flash at 0x100\r\n");
flash_dump(0x100, 252);
print_string("\r\nREADING PHY 0x1, 0x4, 0: ");
print_phy_reg(0x1, 0x4, 0);
rtl8372_init();
print_string(greeting);
print_string("READING PHY 0x4, 0x1, 0: ");
print_phy_reg(0x4, 0x1, 0);
print_string("\r\nREADING PHY 0x1, 0x4, 0: ");
print_phy_reg(0x1, 0x4, 0);
print_string("\r\nREADING PHY 0x5, 0x1, 1: ");
print_phy_reg(0x5, 0x1, 1);
print_string("\r\nREADING PHY 0x1, 0x1, 0: ");
print_phy_reg(0x1, 0x1, 0);
print_string("\r\nREADING PHY 0x7, 0x1f, 0xa412:");
print_phy_reg(0x7, 0x1f, 0xa412);
print_string("\r\nCPU version: ");
print_reg(0x4);
print_string("\r\n> ");
char l = sbuf_ptr;
char line_ptr = l;
char is_white = 1;
while (1) {
while (l != sbuf_ptr) {
write_char(sbuf[l]);
// Check whether there is a full line:
if (sbuf[l] == '\n' || sbuf[l] == '\r') {
print_short(ticks);
// Print line and parse command into words
print_string("\r\n CMD: ");
is_white = 1;
unsigned char word = 0;
cmd_words_b[0] = -1;
while (line_ptr != l) {
if (is_white && sbuf[line_ptr] != ' ') {
is_white = 0;
cmd_words_b[word++] = line_ptr;
}
if (sbuf[line_ptr] == ' ')
is_white = 1;
write_char(sbuf[line_ptr++]);
line_ptr &= SBUF_SIZE - 1;
}
cmd_words_b[word++] = line_ptr;
cmd_words_b[word++] = -1;
line_ptr = (l + 1) & (SBUF_SIZE - 1);
// Identify command
signed char i = cmd_words_b[0];
if (i >= 0) {
print_string("\r\n THERE may be a command: ");
print_short(i); print_string("\r\n");
print_short(cmd_words_b[0]); print_string("\r\n");
print_short(cmd_words_b[1]); print_string("\r\n");
print_short(cmd_words_b[2]); print_string("\r\n");
print_short(cmd_words_b[3]); print_string("\r\n");
}
if (cmd_compare(0, "reset")
reset_chip();
}
l++;
l &= (SBUF_SIZE - 1);
}
PCON |= 1; // Enter Idle mode until interrupt occurs
}
}