liteeth: do MII/GMII detection in gateware for gmii_mii phy
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Sun, 26 Apr 2015 15:32:25 +0000 (17:32 +0200)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Sun, 26 Apr 2015 16:08:07 +0000 (18:08 +0200)
misoclib/com/liteeth/phy/gmii_mii.py
software/bios/main.c
software/include/net/microudp.h
software/libnet/microudp.c
targets/kc705.py

index b2b9b8d222da8720f6a579241096db9c24c390fe..d1bd7d7fe89d94d7c82e33241ac92045c99c56a0 100644 (file)
@@ -83,58 +83,78 @@ class LiteEthPHYGMIIMIIRX(Module):
 
 
 class LiteEthGMIIMIIModeDetection(Module, AutoCSR):
-    def __init__(self):
-        self._reset = CSRStorage()
-        self._counter = CSRStatus(32)
-        self._mode = CSRStorage()
+    def __init__(self, clk_freq):
         self.mode = Signal()
+        self._mode = CSRStatus()
 
         # # #
 
-        # Note:
-        # For now mode detection is done with gateware and software.
-        # We will probably do it in gateware in the future
-        # (we will need to pass clk_freq parameter to PHY)
+        mode = Signal()
+        update_mode = Signal()
+        self.sync += \
+            If(update_mode,
+                self.mode.eq(mode)
+            )
+        self.comb += self._mode.status.eq(self.mode)
 
         # Principle:
         #  sys_clk >= 125MHz
         #  eth_rx <= 125Mhz
-        # We generate a pulse in eth_rx clock domain that increments
-        # a counter in sys_clk domain.
+        # We generate ticks every 1024 clock cycles in eth_rx domain
+        # and measure ticks period in sys_clk domain.
 
-        # Generate a pulse every 4 clock cycles (eth_rx clock domain)
-        eth_pulse = Signal()
-        eth_counter = Signal(2)
+        # Generate a tick every 1024 clock cycles (eth_rx clock domain)
+        eth_tick = Signal()
+        eth_counter = Signal(10)
         self.sync.eth_rx += eth_counter.eq(eth_counter + 1)
-        self.comb += eth_pulse.eq(eth_counter == 0)
+        self.comb += eth_tick.eq(eth_counter == 0)
 
-        # Synchronize pulse (sys clock domain)
-        sys_pulse = Signal()
+        # Synchronize tick (sys clock domain)
+        sys_tick = Signal()
         eth_ps = PulseSynchronizer("eth_rx", "sys")
         self.comb += [
-            eth_ps.i.eq(eth_pulse),
-            sys_pulse.eq(eth_ps.o)
+            eth_ps.i.eq(eth_tick),
+            sys_tick.eq(eth_ps.o)
         ]
         self.submodules += eth_ps
 
-        # Count pulses (sys clock domain)
-        counter = Counter(32)
-        self.submodules += counter
-        self.comb += [
-            counter.reset.eq(self._reset.storage),
-            counter.ce.eq(sys_pulse)
-        ]
-        self.comb += self._counter.status.eq(counter.value)
+        # sys_clk domain counter
+        sys_counter = Counter(24)
+        self.submodules += sys_counter
+
+        fsm = FSM(reset_state="IDLE")
+        self.submodules += fsm
 
-        # Output mode
-        self.comb += self.mode.eq(self._mode.storage)
+        fsm.act("IDLE",
+            sys_counter.reset.eq(1),
+            If(sys_tick,
+                NextState("COUNT")
+            )
+        )
+        fsm.act("COUNT",
+            sys_counter.ce.eq(1),
+            If(sys_tick,
+                NextState("DETECTION")
+            )
+        )
+        fsm.act("DETECTION",
+            update_mode.eq(1),
+            # if freq < 125MHz-5% use MII mode
+            If(sys_counter.value > int((clk_freq/125000000)*1024*1.05),
+                mode.eq(1)
+            # if freq >= 125MHz-5% use GMII mode
+            ).Else(
+                mode.eq(0)
+            ),
+            NextState("IDLE")
+        )
 
 
 class LiteEthPHYGMIIMII(Module, AutoCSR):
-    def __init__(self, clock_pads, pads, with_hw_init_reset=True):
+    def __init__(self, clock_pads, pads, clk_freq, with_hw_init_reset=True):
         self.dw = 8
         # Note: we can use GMII CRG since it also handles tx clock pad used for MII
-        self.submodules.mode_detection = LiteEthGMIIMIIModeDetection()
+        self.submodules.mode_detection = LiteEthGMIIMIIModeDetection(clk_freq)
         mode = self.mode_detection.mode
         self.submodules.crg = LiteEthPHYGMIICRG(clock_pads, pads, with_hw_init_reset, mode == modes["MII"])
         self.submodules.tx = RenameClockDomains(LiteEthPHYGMIIMIITX(pads, mode), "eth_tx")
index e6b5a8181cf78558ab1602cc0412de46e2ae2a2f..bb854df042c3c992bcc355035974e172930785c5 100644 (file)
@@ -497,21 +497,16 @@ static int test_user_abort(void)
 
 static void boot_sequence(void)
 {
-       int eth_ok;
-
        if(test_user_abort()) {
 #ifdef FLASH_BOOT_ADDRESS
                flashboot();
 #endif
                serialboot();
 #ifdef CSR_ETHPHY_MODE_DETECTION_MODE_ADDR
-               eth_ok = eth_mode_detection();
-#else
-               eth_ok = 1;
+               eth_mode();
 #endif
 #ifdef CSR_ETHMAC_BASE
-               if (eth_ok)
-                       netboot();
+               netboot();
 #endif
                printf("No boot medium found\n");
        }
@@ -531,7 +526,7 @@ int main(int i, char **c)
        crcbios();
        id_print();
 #ifdef CSR_ETHMAC_BASE
-       ethreset();
+       eth_init();
 #endif
 #ifdef CSR_SDRAM_BASE
        sdr_ok = sdrinit();
index 36ac5288209cd95c2e1cd65859806f5f0194614d..f148a3411eef9e0b4f5e85e78627135b596f64cd 100644 (file)
@@ -14,7 +14,7 @@ int microudp_send(unsigned short src_port, unsigned short dst_port, unsigned int
 void microudp_set_callback(udp_callback callback);
 void microudp_service(void);
 
-void ethreset(void);
-int eth_mode_detection(void);
+void eth_init(void);
+void eth_mode(void);
 
 #endif /* __MICROUDP_H */
index 1bb56f24725e19f45155f3e14d9beef7ff121c5e..c92e4453f1e6c1ff1bac1d9dc71c80507e87d1a7 100644 (file)
@@ -433,7 +433,7 @@ static void busy_wait(unsigned int ds)
        while(timer0_value_read()) timer0_update_value_write(1);
 }
 
-void ethreset(void)
+void eth_init(void)
 {
        ethphy_crg_reset_write(0);
        busy_wait(2);
@@ -445,50 +445,15 @@ void ethreset(void)
 }
 
 #ifdef CSR_ETHPHY_MODE_DETECTION_MODE_ADDR
-static int eth_test_frequency(unsigned int freq, unsigned int target, unsigned int margin)
+void eth_mode(void)
 {
-       if (freq < (target - margin))
-               return 0;
-       else if (freq > (target + margin))
-               return 0;
-       else
-               return 1;
-}
-
-int eth_mode_detection(void)
-{
-       unsigned int frequency;
-
-       ethphy_mode_detection_reset_write(1);
-       busy_wait(1);
-       ethphy_mode_detection_reset_write(0);
-       busy_wait(1);
-       frequency = ethphy_mode_detection_counter_read()*4*10;
-       ethphy_mode_detection_reset_write(1);
-
        printf("Ethernet phy mode: ");
-       /* 10Mbps */
-       if(eth_test_frequency(frequency, 2500000, 1000000)) {
-               ethphy_mode_detection_mode_write(1);
-               printf("10Mbps (MII)\n");
-               return 1;
-       /* 100Mbps */
-       } else if(eth_test_frequency(frequency, 25000000, 1000000)) {
-               ethphy_mode_detection_mode_write(1);
-               printf("100Mbps (MII)\n");
-               return 1;
-       /* 1Gbps */
-       } else if(eth_test_frequency(frequency, 125000000, 1000000)) {
-               ethphy_mode_detection_mode_write(0);
-               printf("1Gbps (GMII)\n");
-               return 1;
-       /* Failed */
-        } else {
-               printf("Failed to detect link speed\n");
-               return 0;
-       }
+       if (ethphy_mode_detection_mode_read())
+               printf("MII");
+       else
+               printf("GMII");
+       printf("\n");
 }
 #endif
 
 #endif
-
index cdffafdae969d3750bc1db3d5a74b2d8783dc0c0..b0d477fd6abc3fbede86aa2235a86aa12cba3821 100644 (file)
@@ -122,7 +122,7 @@ class MiniSoC(BaseSoC):
     def __init__(self, platform, **kwargs):
         BaseSoC.__init__(self, platform, **kwargs)
 
-        self.submodules.ethphy = LiteEthPHY(platform.request("eth_clocks"), platform.request("eth"))
+        self.submodules.ethphy = LiteEthPHY(platform.request("eth_clocks"), platform.request("eth"), clk_freq=self.clk_freq)
         self.submodules.ethmac = LiteEthMAC(phy=self.ethphy, dw=32, interface="wishbone")
         self.add_wb_slave(mem_decoder(self.mem_map["ethmac"]), self.ethmac.bus)
         self.add_memory_region("ethmac", self.mem_map["ethmac"]+self.shadow_address, 0x2000)