summaryrefslogtreecommitdiff
path: root/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'main.cpp')
-rw-r--r--main.cpp160
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();
+ }
+}