; This is designed to be serial-line downloaded to cdcode. ; ; Our memory map: ; ; [8c000000,8c010000) Stack (r15 set by cdcode) ; [8c010000,8c01????) cdcode ; [8c020000,8c02????) Us ; This code is heavy on the magic numbers. All the other BBA-driving ; code I've found is equally so. :-( .include "regs.s" .include "maple-bits.s" . = 0x8c020000 .sz any .pr any SETS.L #main,r0 jmp @r0 nop SETCONST ; Our "data segment". MAC: .space 6 ; The only things startup.s sets up that cdcode hasn't already done for ; us are (1) fpscr and (2) clearing bss. We don't have bss because we ; aren't linked by a conventional linker, and we don't use floating ; point so we don't care about fpscr. We do, however, need to set up ; the VBR. We also save r10-r14 against returning to cdcode. .align 2 main: mov.l r14,@-r15 mov.l r13,@-r15 mov.l r12,@-r15 mov.l r11,@-r15 mov.l r10,@-r15 ldc r14,gbr stc sr,r1 SETS.L #~[SR_FD|SR_RB|SR_BL],r2 and r2,r1 ldc r1,sr ; Note that r0-r7 may have just changed if we switched banks. mov #0,r1 lds r1,fpscr .sz 0 .pr 0 SETS.L #intvec,r0 ldc r0,vbr ; Real code begins here. ; Make sure all interrupts are blocked. stc sr,r0 or #0xf0,r0 ldc r0,sr ; Set up the PCI bridge. bsr init_gapspci nop bt fail ; Initialize the Ethernet itself. bsr init_ether nop bt fail bra done nop failmsg: .asciz "Setup failed"(13,10) .align 2 fail: SETS.L #failmsg,r1 bsr putstr nop done: bsr putchar mov #13,r1 bsr putchar mov #10,r1 mov.l @r15+,r10 mov.l @r15+,r11 lds r11,pr mov.l @r15+,r12 mov.l @r15+,r13 mov.l @r15+,r14 rts nop g2_lock: ; This is conceptually what NetBSD and libronin call G2_LOCK(). ; It's not quite the same because we always run with ; interrupts disabled, so we don't need to disable them here ; (nor reenable them in g2_unlock). ; ; This saves and restores all registers it uses. ; mov.l r1,@-r15 mov.l r0,@-r15 SETS.L #0xa05f688c,r1 1: mov.l @r1,r0 tst #32,r0 bf 1b mov.l @r15+,r0 rts mov.l @r15+,r1 g2_unlock: ; This is what NetBSD and libronin call G2_UNLOCK(). The only ; thing the NetBSD/libronin one does is reenable interrupts ; disabled by G2_LOCK(); since we always run with interrupts ; disabled, we have nothing to do here. rts nop GAPSPCI_BRIDGE_2_constant: .ascii "GAPSPCI_BRIDGE_2" .align 2 init_gapspci: sts.l pr,@-r15 SETS.L #0xa1001400,r9 SETS.L #0xa1001600,r8 bsr g2_lock nop ; Check the GAPSPCI_BRIDGE_2 constant. SETS.L #GAPSPCI_BRIDGE_2_constant,r2 mov r9,r3 SETS.L #16,r4 1: mov.b @r2+,r0 mov.b @r3+,r1 cmp/eq r0,r1 bf initfail_nomagic dt r4 bf 1b ; GAPSPCI_BRIDGE2 is there. ; I assume this is some kind of magic "please init" value. SETS.L #0x5a14a501,r0 mov r9,r1 add #0x18,r1 mov.l r0,@r1 ; Why 1000000? Because that's what libronin and NetBSD do. :( SETS.L #1000000,r0 1: dt r0 bf 1b ; I assume this is some kind of "init completed OK" check. ; The "not responding" description of failure (see ; failmsg_noresp, as referenced from the code at ; initfail_noresp) is from NetBSD. mov.l @r1,r0 cmp/eq #1,r0 bf initfail_noresp ; Offsets 20, 24, 14, and 34 are unknown to me. ; NetBSD field member names imply 28 is a DMA base address ; register and 2c is a DMA area end pointer. Why we can put a ; fixed value there I don't know; I conjecture there's an ; iommu of some sort.... SETS.L #0x01840000,r0 SETS.L #0x01000000,r1 mov.l r1,@(0x20,r9) mov.l r1,@(0x24,r9) mov.l r0,@(0x28,r9) SETS.L #0x01848000,r0 mov.l r0,@(0x2c,r9) SETS.L #1,r0 mov.l r0,@(0x14,r9) mov.l r0,@(0x34,r9) ; In libronin, these are all opaque magic numbers. NetBSD has ; a bus_space_map call that implies a1001600 is PCI ; configuration space and thus these are PCI registers. Based ; on NetBSD's dev/pci/pcireg.h and the libronin code, I've ; commented this code with guesses as to what's what. ; 0x06 - PCI status (top half of command/status at 0x04) ; 0xf900 - Turn on PARITY_DETECT, SPECIAL_ERROR, MASTER_ABORT, ; MASTER_TARGET_ABORT, TARGET_TARGET_ABORT, and PARITY_ERROR. ; Set DEVSEL_MASK to DEVSEL_FAST and turn off ; BACKTOBACK_SUPPORT, UDF_SUPPORT, 66MHZ_SUPPORT and ; CAPLIST_SUPPORT. (All names from NetBSD.) The 0x000f bits ; have no definitions in dev/pci/pcireg.h. ; The reason I think this is the _top_ half, not the _bottom_ ; half, of the PCI register is twofold: (1) PCI tends to come ; from a peecee perspective, which means little-endian, and ; (2) in view of the NetBSD names for the bits, the code makes ; a lot more sense this way than with the halves swapped. SETS.W #0xf900,r0 mov.w r0,@(0x06,r8) ; Not sure. ROM mapping register maybe? (PCI_MAPREG_ROM) SETS.L #0,r0 mov.l r0,@(0x30,r8) ; Interrupt line? (Low byte of PCI_INTERRUPT_REG) mov r8,r1 add #0x3c,r1 mov.b r0,@r1 ; LAT timer, whatever that is? ; (Second-low byte of PCI_BHLC_REG) mov #0xf0,r0 mov.b r0,@(0x0d,r8) ; Set MEM_ENABLE and MASTER_ENABLE in PCI command (low half of ; command/status - see above) mov.w @(0x04,r8),r0 or #0x06,r0 mov.w r0,@(0x04,r8) ; Not sure. More mapping stuff? (PCI_MAPREG_PCB_END) SETS.L #0x01000000,r1 mov.l r1,@(0x14,r8) ; Don't know _what_ this is. mov r8,r1 add #0x50,r1 mov.b @r1,r0 tst #1,r0 bf initfail_dunno ; It all looks good. bsr g2_unlock nop lds.l @r15+,pr rts clrt failmsg_nomagic: .asciz "PCI bridge magic string not found"(13,10) failmsg_noresp: .asciz "PCI bridge not responding"(13,10) failmsg_dunno: .asciz "PCI bridge not working (offset 0x50)"(13,10) .align 2 initfail_nomagic: SETS.L #failmsg_nomagic,r1 bra 1f nop initfail_noresp: SETS.L #failmsg_noresp,r1 bra 1f nop initfail_dunno: SETS.L #failmsg_dunno,r1 1: bsr putstr nop bsr g2_unlock nop lds.l @r15+,pr rts sett ; Input register offset in r1, output in r0. ; Trashes r1 and the high 3 bytes of r0. rd_b: sts.l pr,@-r15 SETS.L #BBA_BASE,r0 bsr g2_lock add r0,r1 mov.b @r1,r0 lds.l @r15+,pr bra g2_unlock nop ; Input register offset in r1, data in r0. Trashes both. wr_b: mov.l r2,@-r15 sts.l pr,@-r15 SETS.L #BBA_BASE,r2 bsr g2_lock add r2,r1 mov.b r0,@r1 lds.l @r15+,pr bra g2_unlock mov.l @r15+,r2 ; Input register offset in r1, output in r0. Trashes r1. rd_l: sts.l pr,@-r15 SETS.L #BBA_BASE,r0 bsr g2_lock add r0,r1 mov.l @r1,r0 lds.l @r15+,pr bra g2_unlock nop init_ether: ; libronin and NetBSD do things in different orders. In ; particular, libronin does part of the chip setup before ; setting up the rx and tx memory areas; NetBSD does the ; memory setup before fiddling the chip. sts.l pr,@-r15 ; Reset the chip. mov #BBA_RTK_COMMAND_RESET,r0 bsr wr_b mov #BBA_RTK_COMMAND,r1 ; Wait, if necessary, for the chip to finish reset. ; libronin loops 1000000 times here. NetBSD loops only 1000 ; times, but does a DELAY(10) inside the loop. We do the ; former, to avoid needing to build a DELAY(). SETS.L #1000000,r2 1: bsr rd_b mov #BBA_RTK_COMMAND,r1 tst #BBA_RTK_COMMAND_RESET,r0 bt 1f dt r2 bf 1b ; At this point, libronin charges blindly ahead. NetBSD prints ; a message and charges blindly ahead. The latter strikes me ; as saner. SETS.L #reset_fail_msg,r1 bsr putstr nop 1: ; "unlock Config[01234] and BMCR register writes" - libronin ; I'm not totally sure what the NetBSD analog of this, if any, ; is. It looks like "Enter EEPROM access mode", but the value ; written there by NetBSD is 0x80, not 0xc0. The UNLOCK name ; comes from libronin; I'm not sure which block of defines ; these bits would be in NetBSD - there are too many EE* ; defines - so I'm not sure what the NetBSD names are. mov #BBA_RTK_EECMD_UNLOCK,r0 bsr wr_b mov #BBA_RTK_EECMD,r1 ; Fetch our MAC address and save it. bsr rd_l mov #BBA_RTK_MAC_0123,r1 mov r0,r2 bsr rd_l mov #BBA_RTK_MAC_45xx,r1 SETS.L #MAC,r2 mov.b r0,@(4,r2) SHXR #8,r0 mov.b r0,@(5,r2) mov r2,r0 mov.b r0,@r2 SHXR #8,r0 mov.b r0,@(1,r2) SHXR #8,r0 mov.b r0,@(2,r2) SHXR #8,r0 mov.b r0,@(3,r2) ; Report the MAC address. SETS.L #5,r3 2: mov.b @r2+,r1 bsr printhexN mov #2,r0 tst r3,r3 bsr putchar mov #':,r1 1: add #-1,r3 cmp/pz r3 bt 2b bsr putchar mov #13,r1 bsr putchar mov #10,r1 ; "Must enable Tx/Rx before setting transfer thresholds!" says ; libronin; NetBSD doesn't comment any ordering dependency, ; but does this enable before doing the TX and RX config. SETS.L #BBA_RTK_COMMAND_ENABLE_TX|BBA_RTK_COMMAND_ENABLE_RX,r0 bsr wr_b mov #BBA_RTK_COMMAND,r1 ; libronin sets just the DMA burst size, with all other bits 0, ; but says "Check this value: the documentation for IFG ; contradicts ifself.". The libronin comment on the IFG bits ; says that "Enabling these bits violates IEEE 802.3". NetBSD ; comments them as "interframe gap" and "8169 only", with no ; indication of any 802.3 violation, and sets both of them. ; We go with NetBSD. SETS.L #[BBA_RTK_TXCFG_MAXDMA_1024<