from migen.genlib.io import DDROutput
from migen.flow.plumbing import Multiplexer, Demultiplexer
-from migen.genlib.cdc import MultiReg
+from migen.genlib.cdc import PulseSynchronizer
from misoclib.com.liteeth.common import *
from misoclib.com.liteeth.generic import *
]
-class LiteEthGMIIMIIClockCounter(Module, AutoCSR):
+class LiteEthGMIIMIIModeDetection(Module, AutoCSR):
def __init__(self):
self._reset = CSRStorage()
- self._value = CSRStatus(32)
+ self._counter = CSRStatus(32)
+ self._mode = CSRStorage()
+ self.mode = Signal()
# # #
- counter = RenameClockDomains(Counter(32), "eth_rx")
+ # 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)
+
+ # Principle:
+ # sys_clk >= 125MHz
+ # eth_rx <= 125Mhz
+ # We generate a pulse in eth_rx clock domain that increments
+ # a counter in sys_clk domain.
+
+ # Generate a pulse every 4 clock cycles (eth_rx clock domain)
+ eth_pulse = Signal()
+ eth_counter = Signal(2)
+ self.sync.eth_rx += eth_counter.eq(eth_counter + 1)
+ self.comb += eth_pulse.eq(eth_counter == 0)
+
+ # Synchronize pulse (sys clock domain)
+ sys_pulse = Signal()
+ eth_ps = PulseSynchronizer("eth_rx", "sys")
+ self.comb += [
+ eth_ps.i.eq(eth_pulse),
+ sys_pulse.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), # slow, don't need CDC
- counter.ce.eq(1),
+ counter.reset.eq(self._reset.storage),
+ counter.ce.eq(sys_pulse)
]
- self.specials += MultiReg(counter.value, self._value.status)
+ self.comb += self._counter.status.eq(counter.value)
+
+ # Output mode
+ self.comb += self.mode.eq(self._mode.storage)
class LiteEthPHYGMIIMII(Module, AutoCSR):
def __init__(self, clock_pads, pads, with_hw_init_reset=True):
self.dw = 8
- self._mode = CSRStorage()
- mode = self._mode.storage
# Note: we can use GMII CRG since it also handles tx clock pad used for MII
+ self.submodules.mode_detection = LiteEthGMIIMIIModeDetection()
+ mode = self.mode_detection.mode
self.submodules.crg = LiteEthPHYGMIICRG(clock_pads, pads, with_hw_init_reset, mode == modes["MII"])
- self.submodules.clock_counter = LiteEthGMIIMIIClockCounter()
self.submodules.tx = RenameClockDomains(LiteEthPHYGMIIMIITX(pads, mode), "eth_tx")
self.submodules.rx = RenameClockDomains(LiteEthPHYGMIIMIIRX(pads, mode), "eth_rx")
self.sink, self.source = self.tx.sink, self.rx.source
busy_wait(2);
}
-#ifdef CSR_ETHPHY_MODE_ADDR
-void ethmode(void)
+#ifdef CSR_ETHPHY_MODE_DETECTION_MODE_ADDR
+static int eth_test_frequency(unsigned int freq, unsigned int target, unsigned int margin)
{
- ethphy_clock_counter_reset_write(1);
+ 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_clock_counter_reset_write(0);
+ 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: ");
- /* if freq > 120 MHz, use GMII (5MHz margin)*/
- if(ethphy_clock_counter_value_read() > 120000000/10) {
- ethphy_mode_write(0);
- printf("GMII");
- /* else use MII */
- } else {
- ethphy_mode_write(1);
- printf("MII");
+ /* 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;
}
- printf("\n");
-
- ethphy_clock_counter_reset_write(1);
}
#endif