diff options
Diffstat (limited to 'main.cpp')
-rw-r--r-- | main.cpp | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..a18bb27 --- /dev/null +++ b/main.cpp @@ -0,0 +1,160 @@ +#include <rcc/rcc.h> +#include <rcc/syscfg.h> +#include <gpio/pin.h> +#include <os/time.h> +#include <net/ethernet.h> +#include <util/rblog.h> + +static Pin eth_pins[] = { + // MDIO, MDC + PA2, PC1, + // REF_CLK, CRS, TX_EN + PA1, PA7, PB11, + // TXD0, TXD1, RXD0, RXD1 + PB12, PB13, PC4, PC5 +}; + +RBLog<256, 2> eth_rblog; + +struct dmadesc_t { + volatile uint32_t status; + volatile uint32_t ctrl; + volatile uint32_t buf; + volatile uint32_t next; +}; + +dmadesc_t dmadesc[2]; +uint8_t eth_buf[2][2048]; + +class ETH_driver { + private: + ETH_t& eth; + + dmadesc_t* dmadescp; + + public: + ETH_driver(ETH_t& e) : eth(e) {} + + void enable() { + // Reset MAC. + ETH.dma_reg.BMR |= 1; + while(ETH.dma_reg.BMR & 1); + + dmadesc[0].status = (1 << 31); // OWN + dmadesc[0].ctrl = (1 << 14) | 2048; // RCH + dmadesc[0].buf = (uint32_t)eth_buf[0]; + dmadesc[0].next = (uint32_t)&dmadesc[1]; + + dmadesc[1].status = (1 << 31); // OWN + dmadesc[1].ctrl = (1 << 14) | 2048; // RCH + dmadesc[1].buf = (uint32_t)eth_buf[1]; + dmadesc[1].next = (uint32_t)&dmadesc[0]; + + dmadescp = &dmadesc[0]; + + ETH.dma_reg.BMR = (1 << 16) | (16 << 8); + ETH.dma_reg.RDLAR = (uint32_t)dmadesc; + ETH.dma_reg.OMR = (1 << 1); // RXSTART + + ETH.mac_reg.CR |= (1 << 14) | (1 << 11) | (1 << 2); + ETH.mac_reg.FFR |= (1 << 31); + } + + uint16_t mdio_read(uint8_t phy, uint8_t reg) { + eth.mac_reg.MIIAR = (phy << 11) | (reg << 6) | (4 << 2) | 1; + + while(eth.mac_reg.MIIAR & 1); + + eth_rblog.log("MDIO read: %#x = %#x", reg, eth.mac_reg.MIIDR); + + return eth.mac_reg.MIIDR; + } + + void mdio_write(uint8_t phy, uint8_t reg, uint16_t data) { + eth_rblog.log("MDIO write: %#x = %#x", reg, data); + + eth.mac_reg.MIIDR = data; + + eth.mac_reg.MIIAR = (phy << 11) | (reg << 6) | (4 << 2) | (1 << 1) | 1; + + while(eth.mac_reg.MIIAR & 1); + } + + void process() { + uint32_t lost_frames = ETH.dma_reg.MFBOCR; + + if(lost_frames) { + eth_rblog.log("Lost frames. MFBOCR = %#x", lost_frames); + } + + uint32_t status = dmadescp->status; + + if(!(status & (1 << 31))) { + eth_rblog.log("Got frame. status = %#x", status); + + if(status & (1 << 9) && status & (1 << 8)) { + uint32_t len = (status & 0x3fff0000) >> 16; + + handle_ethernet((uint8_t*)dmadescp->buf, len); + } + + dmadescp->status = (1 << 31); // OWN + dmadescp = (dmadesc_t*)dmadescp->next; + } + } + + void handle_ethernet(uint8_t* buf, uint32_t len) { + eth_rblog.log("Handling frame. len = %d", len); + + if(len < 18) { + eth_rblog.log("Invalid length, dropping."); + return; + } + + uint16_t ethertype = (buf[12] << 8) | buf[13]; + + eth_rblog.log("Ethertype: %#x", ethertype); + + switch(ethertype) { + case 0x8100: + uint16_t vlan = (buf[14] << 8) | buf[15]; + + eth_rblog.log("VLAN = %d", vlan); + break; + + } + } +}; + +ETH_driver ethd(ETH); + +int main() { + // Initialize system timer. + STK.LOAD = 168000000 / 8 / 1000; // 1000 Hz. + STK.CTRL = 0x03; + + RCC.enable(RCC.GPIOA); + RCC.enable(RCC.GPIOB); + RCC.enable(RCC.GPIOC); + + for(Pin& p : eth_pins) { + p.set_mode(Pin::AF); + p.set_af(11); + p.set_speed(Pin::High); + } + + RCC.enable(RCC.SYSCFG); + + // Select RMII mode. + SYSCFG.PMC |= (1 << 23); + + RCC.enable(RCC.ETHMAC); + RCC.enable(RCC.ETHMACTX); + RCC.enable(RCC.ETHMACRX); + + ethd.enable(); + + while(1) { + ethd.process(); + } +} |