bmips: add build support for BCM3380 SoC (Netgear CG3100D)#17464
bmips: add build support for BCM3380 SoC (Netgear CG3100D)#17464rikka0w0 wants to merge 40 commits intoopenwrt:mainfrom
Conversation
What's working: 1. UART0 2. CG3100D can load the image and the kernel can start. However, the kernel panics almost immediately. Furthermore, the kernel decompression is very slow. What's not working: Almost everything else
The kernel now boots a little bit further before it gets stuck
This utilizes the LZMA decompression of the BCM3380 stock booloader, which is much faster than OpenWrt's LZMA loader. OpenWrt's LZMA loader is being slow on CG3100D for no reason.
This OpenWrt image will drop you to a shell on the serial console
CPU1 now works. CPU0 starts first, then it brings up CPU1.
Code clean up CPU0: CAUSE3->Mask_Status[2] CPU1: CAUSE4->Mask_Status[3]
|
Hi @rikka0w0 :
Searching a bit in the source code from these boards: static inline void GPIOSetOutput( unsigned int gpioBit, unsigned int value )
{
uint32 mask;
volatile unsigned int *pGPIO = (volatile unsigned int *)0xb4e00108;
mask = ~(1 << gpioBit);
*pGPIO = ((*pGPIO & mask) | (value << gpioBit));
}
#if defined(CONFIG_BCM93380)
/* Chip select 0 */
GPIOSetOutput( 14, 1 );Looks like it enables the SPI chip select 0 pinmux. You could test this code somewhere, for example in setup.c at bmips directory. BTW it should be already enabled by the bootloader, it can be checked using devmem and see the state of the bits at the address 0x14e00108. |
|
Hi @danitool, Thanks for pointing this out. However, I found that the code snippet you provided above only controls the GPIO output state, not the mux. The GPIO_BASE is 0xb4e00100, so This Netgear Open sourced firmware contains some Linux kernel code that has a complete register definition of the BCM3380 SoC. If you unzip the downloaded zip archive inside Here are some register definition from bcm3380/gpio_regs.htypedef union {
struct {
uint32 PmSelectMdio :2;
uint32 PmSelectGmiiTxd :2;
uint32 PmSelectGmiiTx :2;
uint32 PmSelectGmiiRx :2;
uint32 PmSelectGmiiRxd :2;
uint32 PmSelectReserved :2;
uint32 PmSelectGpio3532 :2;
uint32 PmSelectGpio3130 :2;
uint32 PmSelectGpio2924 :2;
uint32 PmSelectGpio2320 :2;
uint32 PmSelectGpio1918 :2;
uint32 PmSelectGpio1716 :2;
uint32 PmSelectGpio1514 :2;
uint32 PmSelectGpio1312 :2;
uint32 PmSelectGpio1106 :2;
uint32 PmSelectGpio0500 :2;
} Bits;
uint32 Reg32;
} GpioPinMuxSel;
typedef union {
struct {
uint32 Reserved :10;
uint32 PmSelectUsb1 :2;
uint32 PmSelectUsb0 :2;
uint32 PmSelectGmiiClk :2;
uint32 PmSelectLed0700 :2;
uint32 PmSelectSpisUart1 :2;
uint32 PmSelectAgci0704 :2;
uint32 PmSelectAgci0300 :2;
uint32 PmSelectPass :2;
uint32 PmSelectHvg :2;
uint32 PmSelectBmu :2;
uint32 PmSelectTpMisc :2;
} Bits;
uint32 Reg32;
} GpioPinMuxSelHi;
typedef union {
struct {
uint32 Reserved :14;
uint32 SpiSSlv :1;
uint32 SpiSlvRst :1;
uint32 Reserved2 :6;
uint32 DlyDis :1;
uint32 Reserved3 :4;
uint32 SerialAddrCfg :4;
uint32 SpiMode :1;
} Bits;
uint32 Reg32;
} GpioSpiConfig;
typedef struct {
uint32 DirLo; // (00)
uint32 DirHi; // (04)
uint32 DataLo; // (08)
uint32 DataHi; // (0C)
uint32 Reserved1; // (10)
GpioSpiConfig SpiConfig; // (14)
uint32 Reserved2; // (18)
GpioVregConfig VregConfig; // (1C)
uint32 Reserved3; // (20)
uint32 Reserved4; // (24)
GpioTestControl Testcontrol; // (28)
uint8 Pad0[0x14]; // (2C)
GpioStrapBus StrapBus; // (40)
GpioStrapOverride StrapOverride; // (44)
uint8 Pad1[0x4]; // (48)
GpioRefPllStatus RefPllStatus; // (4C)
GpioOscCtl OscCtl; // (50)
GpioXtalbufCtrl XtalbufCtrl; // (54)
GpioDiagMemCtl DiagMemCtl; // (58)
uint32 DiagMemSize; // (5C)
uint32 SrcAddr; // (60)
uint32 DestAddr; // (64)
GpioRingOscCtrl0 RingOscCtrlSet0; // (68)
GpioRingOscCtrl1 RingOscCtrlSet1; // (6C)
GpioRbusDiagSel RbusDiagSel; // (70)
uint32 DiagCaptLastWrAddr; // (74)
GpioMipsDdrPllOverride MipsDrrPllOverride; // (78)
GpioDieRevId Dierevid; // (7C)
GpioPinMuxSel PinMuxSel; // (80)
GpioPinMuxSelHi PinMuxSelHi;
GpioSpimasterControl SpimasterControl;
GpioClkrstMisc ClkrstMisc;
uint32 TransportOe;
GpioDiagCaptOvflDet DiagCaptOvflDet;
GpioDiagMemHbCount DiagMemHbCount;
} GpioRegs; |
|
@rikka0w0 #if defined(CONFIG_BCM93380)
*(unsigned long *)0xb4e00188 = (*(unsigned long *)0xb4e00188 | 1<<19) & ~(1<<16);
SPI->spiClkCfg = ((2 << 3) | 7);
#endifAccordingly to the registers you pointed out, it seems it clears the bit 16 and sets the bit 19 at the SpimasterControl , and then it configures the spiclk (probably the speed and also another bit). |
The old uboot binary files was in `staging_dir/target-mips_mips32_musl/image`. Now, it will also be copied to `bin/targets/bmips/$SUBTARGET/u-boot-$UBOOT_TARGET/` E.g.: `bin/targets/bmips/bcm6328/u-boot-xg6846/`. After this commit, the BMIPS U-Boot binaries will be included in the repo. The Makefile in openwrt@f789454 assumes xg6846 is the only possible target.
If HCS_IMAGE is specified, use aeolus or hcsmakeimage to prepend header to the u-boot binary. See `define U-Boot/netgear_cg3100d_ram` in `package/boot/uboot-bmips/Makefile`
6536ef2 to
147992f
Compare
|
Hi, @danitool I also found the same result last night. Today, I read the value of all SPI-related registers found in These are found in the stock bootloader: The only difference happens at 0xb4e00188. In U-Boot, it was all 0. I tried the following in the U-Boot console, and U-Boot can successfully detect the on-board SPI flash: Thanks! |
Pulled from shared/opensource/flash/spiflash.c in https://www.downloads.netgear.com/files/GPL/CG3100L_V5.5.4_EU_V1.0.4_Linux_src.zip OpenWrt can new access the on-board SPI flash Special thanks to danitool
70327b8 to
b336553
Compare
The OpenWrt boot log now contains: b53-switch spi0.3: found switch: BCM53115, rev 8 1. CG3100D has a BCM53115 switch for all of its LAN ports 2. CG3100D does not have a WAN port. 3. BCM53115 connects to CG3100D's UNIMAC1 via GMII, according to the product brief. 4. UNIMAC0 has a built-in phy, but is not used on CG3100D. 5. Missing ethernet driver, so `ethernet_gmii` does nothing. 6. Network does not work yet. 7. May need to look at GPIO16. Stock boot log shows: Reset BCM53115 - Low GPIO-16 5ms
1. Use pinctrl to configure gpio15 as cs3. 2. For now, the implementation is hardcoded in bcm3380_pinctrl_set_mux 3. The pin function of BCM3380 remains mostly unknown 4. The number of GPIOs may not be correct 5. GPIO function not tested yet
1. Control logic comes from reverse engineering of the stock bootloader 2. Current status: Link-up, can receive ethernet frames 3. Need to properly detect and separate each frame
Ethernet Rx works with polling. During the boot, an infinite loop prints received frames. TODO: 1. Backpressure? 2. Test Tx
No ARP support. MAC stays the same as the stock bootloader.
|
I guess this would work on the Cisco EPC3925 too? That's 3380 also - https://oldwiki.archive.openwrt.org/toh/cisco/epc3925 |
After load the OpenWrt initramfs in the stock bootloader, the device can be pinged from the same IP. The kernel will not boot normally but enters an infinite loop. Inside the loop, it polls ethernet frames and only responds to ICMP echo. Only ping works. ARP and other protocols dont. So ping will stop working if the host sends ARP.
Correct. EPC3925 and CG3100D should have very similar hardware design. They may even share the same schematic. I would expect little to none DTS modification to get OpenWrt (with this patch) working on EPC3925. I just figure out how to do networking on BCM3380. The next step is to implement the ethernet driver in the Linux way... |
Tx works The polling function can pickup the packet, but linux is not processing it Disable switch for now
Sometimes the Rx packet length is incorrect. Seems to be the length of the last packet... Disable Tx does not help
The problem is how we interact with the hardware. Not a Linux problem... [ 36.343653] vUnimacDemo: Ethernet Rx Good, len = 0x00000040 [ 36.348962] ff ff ff ff ff ff 00 e0 4c 36 01 bc 08 06 00 01 [ 36.354270] 08 00 06 04 00 01 00 e0 4c 36 01 bc c0 a8 01 64 [ 36.359635] 00 00 00 00 00 00 c0 a8 01 01 00 00 00 00 00 00 [ 36.364932] 00 00 00 00 00 00 00 00 00 00 00 00 70 9a 4d ec [ 36.370283] vUnimacDemo: FCS = 0x709A4DEC [ 36.370302] vUnimacDemo: FCS_CALC = 0x709A4DEC, FCS_RX = 0x709A4DEC [ 36.380108] vUnimacDemo: DstMac: FFFF FFFF FFFF [ 36.384418] vUnimacDemo: SrcMac: 00E0 4C36 01BC [ 36.388767] vUnimacDemo: Type: 0x0806 [ 37.394719] vUnimacDemo: Ethernet Rx Good, len = 0x00000040 [ 37.400038] 00 10 18 ff ff ff 00 e0 4c 36 01 bc 08 00 45 00 [ 37.405360] 00 54 db 5c 40 00 40 01 db 96 c0 a8 01 64 c0 a8 [ 37.410670] 01 01 08 00 a4 de 00 0d 00 01 3c ab a4 67 00 00 [ 37.416018] 00 00 a9 2d 0a 00 00 00 00 00 10 11 12 13 14 15 [ 37.421333] vUnimacDemo: FCS = 0xFC0A6644 [ 37.421351] vUnimacDemo: FCS_CALC = 0xFC0A6644, FCS_RX = 0x12131415 [ 37.431155] vUnimacDemo: FCS mismatch!!!! rx_i = 32, rx_i = 0x00000930 [ 34.988376] vUnimacDemo: FCS mismatch!!!! rx_i = 32, rx_i = 0x00000A86 [ 35.388653] vUnimacDemo: FCS mismatch!!!! rx_i = 32, rx_i = 0x00000930 [ 34.635798] vUnimacDemo: FCS mismatch!!!! rx_i = 32, rx_i = 0x00000BB6 [ 38.023627] vUnimacDemo: FCS mismatch!!!! rx_i = 32, rx_i = 0x00000A60 [ 35.382181] vUnimacDemo: FCS mismatch!!!! rx_i = 32, rx_i = 0x00000956 [ 37.431155] vUnimacDemo: FCS mismatch!!!! rx_i = 32, rx_i = 0x00000930 [ 34.648964] vUnimacDemo: FCS mismatch!!!! rx_i = 32, rx_i = 0x000009A2 [ 37.403495] vUnimacDemo: FCS mismatch!!!! rx_i = 32, rx_i = 0x00000930 [ 35.721239] vUnimacDemo: FCS mismatch!!!! rx_i = 32, rx_i = 0x0000097C [ 36.002724] vUnimacDemo: FCS mismatch!!!! rx_i = 32, rx_len = 0x00000956
The ping is around 100-200ms feels like on the other side of the earth...
1. Disable packet dump (by default) to speed up 2. Set BCM3380_UNIMAC_DUMP_TRAFFIC to 1 to enable packet dump 3. Poll interval was reduced to 1ms (High CPU usage)
|
Okay, guys, I have exciting news to announce! However, several important features are missing in my driver, including:
I will provide more information here, just in case someone with better Linux driver development skills than me wants to join and improve the ethernet driver. The base address of each SoC component can be found here. Its parent folder contains the header files that contain the register definition. The addressing and memory layout are explained here. I found that we need three components to make the ethernet work:
The Unimac core handles most of the MAC configuration stuff, including the MAC address and the maximum frame length. The Unimac interface provides access to the external world, e.g. the MDIO bus. The MBDMA block interacts with FPM and MSP to process incoming and outgoing packets. The FPM manages a circular buffer for packet data. The MSP seems to be a FIFO that holds some 2-byte message. Each message contains a token that describes the length of each packet and its location with in the FPM working memory. Note that the CPU must access the MSP through the SMISB bus (e.g., use The Rx process in the polling implementation is very straightforward. When a packet arrives at the Unimac:
typedef struct LanRxMsg
{
uint32 msgHdr;
#define LANRX_MAC_ID_MASK 0x03C00000
#define LANRX_MAC_ID_SHIFT 22
#define LANRX_QOS_MASK 0x000f0000
#define LANRX_QOS_SHIFT 16
uint32 token;
} LanRxMsg;If the highest 6 bits are not all zero, the stock bootloader considers the message invalid. I don't know why.
Hence, I think to implement an interrupt-based receiver, we need to handle some interrupt produced by the MSP ( |
IOPROC_SMISB.In.IncomingMessageFifo.InMsgCtl.Reg32 |= 1<<15; // NotEmptyIrqSts IOPROC_SMISB.Cntrl.Control.L1Irq4keMask.Reg32 |= 0x04; // InFifoIrqMask Will set bit 2 in L1Irq4keStatus. However, 4ke seems to be another small MIPS processor? The IOP interrupt is somehow not routed to IntControl.Iopirqmask0/1 Set IntControl.IopirqSense to 8 somehow fake the IOP interrupt, even if the IOP has not set any flag at all.
|
I'm trying to get more information from the eCos image ( Unfortunately,
However, if we can compile an eCos binary from We would need the Building |
Add necessary build scripts with

make menuconfigsupport to build images for BCM3380Give you the option to choose the image packer between
hcsmakeimageandBroadcom's aeolus ProgramStore. SeeBCM33xx image packerinTarget Imagesoption.The
hcsmakeimageuses its own lzma decompressor. For some reason, it is extremely slow. Luckily, Broadcom open-sourced the aeolus utility, which allows us to utilize the built-in lzma decompressor of the stock bootloader. The image produced by aeolus is smaller and loads faster.What works
What does not work
Sort by priority. GPIO and pinmux may be easier to support.
We can declare a victory if we can make the ethernet work...
More process can be found here:
https://gist.github.com/rikka0w0/4e4d5feb3a50a8b64224750140f859ef#file-cg3100-md
Boot log:
https://openwrt.org/inbox/toh/openwrt/netgear_cg3100d_v3
Any help is welcomed.