diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f0fd549 --- /dev/null +++ b/Makefile @@ -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 diff --git a/crtstart.asm b/crtstart.asm new file mode 100644 index 0000000..9866afe --- /dev/null +++ b/crtstart.asm @@ -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 diff --git a/rtl837x_flash.c b/rtl837x_flash.c new file mode 100644 index 0000000..4b1656a --- /dev/null +++ b/rtl837x_flash.c @@ -0,0 +1,338 @@ +/* + * This is driver implementation for the RTL837x flash controller + * This code is in the Public Domain + */ + +#include +#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; + } +} diff --git a/rtl837x_flash.h b/rtl837x_flash.h new file mode 100644 index 0000000..8eba812 --- /dev/null +++ b/rtl837x_flash.h @@ -0,0 +1,13 @@ +#ifndef _RTL837X_FLASH_H_ +#define _RTL837X_FLASH_H_ + +#include +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 diff --git a/rtl837x_sfr.h b/rtl837x_sfr.h new file mode 100644 index 0000000..269b762 --- /dev/null +++ b/rtl837x_sfr.h @@ -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; diff --git a/rtl837x_stdio.h b/rtl837x_stdio.h new file mode 100644 index 0000000..0f25c77 --- /dev/null +++ b/rtl837x_stdio.h @@ -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 diff --git a/rtlplayground.c b/rtlplayground.c new file mode 100644 index 0000000..498cf34 --- /dev/null +++ b/rtlplayground.c @@ -0,0 +1,795 @@ +#include <8051.h> +#include + +#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 + } +}