From 07a5ac53d5e58e9a2ce3ec95add0506817163fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=A1vio=20J=2E=20Saraiva?= Date: Mon, 8 Apr 2024 21:36:34 +0100 Subject: [PATCH 1/2] Rustify lxt970a. Extra targets to develop in rust (cargo clippy, cargo doc, cargo fmt). Allow big lines when formatting rust. Use triple-slash comments when generating rust-dynamips.h. --- CMakeLists.txt | 4 + common/dev_lxt970a.c | 14 - common/dev_lxt970a.h | 219 ------------- common/dev_mpc860.c | 166 +--------- rust/dynamips/cbindgen.toml | 1 + rust/dynamips/src/c/dev_lxt907a.rs | 52 ++++ rust/dynamips/src/c/mod.rs | 14 + rust/dynamips/src/lib.rs | 6 + rust/dynamips/src/macros.rs | 14 + rust/dynamips/src/phy/lxt970a.rs | 482 +++++++++++++++++++++++++++++ rust/dynamips/src/phy/mod.rs | 8 + rust/rustfmt.toml | 1 + stable/CMakeLists.txt | 1 - unstable/CMakeLists.txt | 1 - 14 files changed, 598 insertions(+), 385 deletions(-) delete mode 100644 common/dev_lxt970a.c delete mode 100644 common/dev_lxt970a.h create mode 100644 rust/dynamips/src/c/dev_lxt907a.rs create mode 100644 rust/dynamips/src/c/mod.rs create mode 100644 rust/dynamips/src/macros.rs create mode 100644 rust/dynamips/src/phy/lxt970a.rs create mode 100644 rust/dynamips/src/phy/mod.rs create mode 100644 rust/rustfmt.toml diff --git a/CMakeLists.txt b/CMakeLists.txt index 3296fb449..ef1af6b70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,10 @@ FetchContent_MakeAvailable ( Corrosion ) corrosion_import_crate ( MANIFEST_PATH "${CMAKE_SOURCE_DIR}/rust/dynamips/Cargo.toml" PROFILE release-with-debug ) corrosion_experimental_cbindgen( MANIFEST_PATH "${CMAKE_SOURCE_DIR}/rust/dynamips/Cargo.toml" TARGET rust-dynamips HEADER_NAME "rust-dynamips.h" ) list ( APPEND DYNAMIPS_LIBRARIES rust-dynamips ) +add_custom_target ( cargo_fmt COMMAND cargo fmt -v WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/rust" USES_TERMINAL ) +add_custom_target ( cargo_clippy COMMAND cargo clippy -v WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/rust" USES_TERMINAL ) +add_custom_target ( cargo_doc COMMAND cargo doc -v WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/rust" USES_TERMINAL ) +add_custom_target ( cargo_test COMMAND cargo test -v WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/rust" USES_TERMINAL ) add_subdirectory ( man ) add_subdirectory ( common ) diff --git a/common/dev_lxt970a.c b/common/dev_lxt970a.c deleted file mode 100644 index 706137650..000000000 --- a/common/dev_lxt970a.c +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 10/100 Mbps Ethernet PHY. - * - * Based on: - * Intel® LXT970A - * Dual-Speed Fast Ethernet Transceiver - * Order Number: 249099-001 - * January 2001 - * Based on: - * IEEE Std 802.3-2008, Section 2 - */ - -#include "dev_lxt970a.h" - diff --git a/common/dev_lxt970a.h b/common/dev_lxt970a.h deleted file mode 100644 index 71f96c5a5..000000000 --- a/common/dev_lxt970a.h +++ /dev/null @@ -1,219 +0,0 @@ -/* - * 10/100 Mbps Ethernet PHY. - * - * Based on: - * Intel® LXT970A - * Dual-Speed Fast Ethernet Transceiver - * Order Number: 249099-001 - * January 2001 - * Based on: - * IEEE Std 802.3-2008, Section 2 - */ - -#ifndef __DEV_LXT970A_H__ -#define __DEV_LXT970A_H__ - -/* -Abreviations: - RW=x - Read/Write with default value x - RO=x - Read Only with default value x - [xx] - default value determined by pins xx - SC - Self Clearing - LH - Latching High (remains High until read, and then returns to Low) - LL - Latching Low (remains Low until read, and then returns to High) - IGN - IGNored on certain conditions - RTOR - Related To Other Register - -Pin states used for the default values: - MF0 = VMF2 or VMF3 (Enabled) - MF1 = VMF1 or VMF4 (Disabled) - MF2 = VMF2 or VMF3 (Enabled) - MF3 = VMF2 or VMF3 (Enabled) - MF4 = VMF2 or VMF3 (Enabled) - CFG0 = High - CFG1 = High - TRSTE = Low - FDE = High - MDDIS = Low, RESET = High, PWERDWN = Low (2.4.1.2, MDIO Control) -*/ - -/* -Standard MII Registers -*/ - -#define LX970A_CR 0x00 /* Table 45. Control Register (Address 0) */ -#define LX970A_CR_RESET 0x8000 /* Reset (RW=0,SC) */ -#define LX970A_CR_LOOP 0x4000 /* Loopback (RW=0) */ -#define LX970A_CR_SPEEDSELECT 0x2000 /* Speed Selection (RW=1[CFG0],IGN) */ -#define LX970A_CR_ANENABLE 0x1000 /* Auto-Negotiation Enable (RW=1[MF0]) */ -#define LX970A_CR_POWERDOWN 0x0800 /* Power Down (RW=0?) */ -#define LX970A_CR_ISOLATE 0x0400 /* Isolate (RW=0[TRSTE]) */ -#define LX970A_CR_ANRESTART 0x0200 /* Restart Auto-Negotiation (RW=1[CFG0],SC) */ -#define LX970A_CR_DUPLEXMODE 0x0100 /* Duplex Mode (RW=1[FDE],IGN) */ -#define LX970A_CR_COLLISIONTEST 0x0080 /* Collision Test (RW=0,IGN) */ -#define LX970A_CR_TTM 0x0070 /* Transceiver Test Mode (RO=0) */ -#define LX970A_CR_MSENABLE 0x0008 /* Master-Slave Enable (RO=0) */ -#define LX970A_CR_MSVALUE 0x0004 /* Master-Slave Value (RO=0) */ -#define LX970A_CR_RESERVED 0x0003 /* Reserved (RW=0) */ -#define LX970A_CR_RO_MASK 0x007C -#define LX970A_CR_RW_MASK 0xFF83 -#define LX970A_CR_DEFAULT 0x3300 - -#define LX970A_SR 0x01 /* Table 46. Status Register (Address 1) */ -#define LX970A_SR_100T4 0x8000 /* 100BASE-T4 (RO=0) */ -#define LX970A_SR_100TX_FD 0x4000 /* 100BASE-X full-duplex (RO=1) */ -#define LX970A_SR_100TX_HD 0x2000 /* 100BASE-X hald-duplex (RO=1) */ -#define LX970A_SR_10T_FD 0x1000 /* 10 Mb/s full-duplex (RO=1) */ -#define LX970A_SR_10T_HD 0x0800 /* 10 Mb/s half-duplex (RO=1) */ -#define LX970A_SR_100T2_FD 0x0400 /* 100BASE-T2 full-duplex (RO=0) */ -#define LX970A_SR_100T2_HD 0x0200 /* 100BASE-T2 half-duplex (RO=0) */ -#define LX970A_SR_RESERVED 0x0100 /* Reserved (RO=0) */ -#define LX970A_SR_MSCFGFAULT 0x0080 /* Master-Slave Configuration Fault (RO=0) */ -#define LX970A_SR_MFPS 0x0040 /* MF Preamble Suppression (RO=0) */ -#define LX970A_SR_ANCOMPLETE 0x0020 /* Auto-Neg. Complete (RO=0) */ -#define LX970A_SR_REMOTEFAULT 0x0010 /* Remote Fault (RO=0,LH) */ -#define LX970A_SR_ANABILITY 0x0008 /* Auto-Neg. Ability (RO=1) */ -#define LX970A_SR_LINKSTATUS 0x0004 /* Link Status (RO=0,LL) */ -#define LX970A_SR_JABBERDETECT 0x0002 /* Jabber Detect (10BASE-T Only) (RO=0,LH) */ -#define LX970A_SR_EXTCAPABILITY 0x0001 /* Extended Capability (RO=1) */ -#define LX970A_SR_RO_MASK 0xFFFF -#define LX970A_SR_RW_MASK 0x0000 -#define LX970A_SR_DEFAULT 0x7809 - -/* -PHY ID number: - Intel has OUI=00207Bh and ROUI=DE0400h (OUI with bits reversed) - (ROUI << 10) & FFFFFFFFh = 78100000h -*/ - -#define LX970A_PIR1 0x02 /* Table 47. PHY Identification Register 1 (Address 2) */ -#define LX970A_PIR1_PIN 0xFFFF /* PHY ID Number (RO=7810h) */ -#define LX970A_PIR1_RO_MASK 0xFFFF -#define LX970A_PIR1_RW_MASK 0x0000 -#define LX970A_PIR1_DEFAULT 0x7810 - -#define LX970A_PIR2 0x03 /* Table 48. PHY Identification Register 2 (Address 3) */ -#define LX970A_PIR2_PIN 0xFC00 /* PHY ID number (RO=000000b) */ -#define LX970A_PIR2_MANMODELNUM 0x03F0 /* Manufacturer’s model number (RO=000000b) */ -#define LX970A_PIR2_MANREVNUM 0x000F /* Manufacturer’s revision number (RO=0011b) */ -#define LX970A_PIR2_RO_MASK 0xFFFF -#define LX970A_PIR2_RW_MASK 0x0000 -#define LX970A_PIR2_DEFAULT 0x0003 - -#define LX970A_ANAR 0x04 /* Table 49. Auto Negotiation Advertisement Register (Address 4) */ -#define LX970A_ANAR_NEXTPAGE 0x8000 /* Next Page (RO=0) */ -#define LX970A_ANAR_RESERVED_1 0x4000 /* Reserved (RO=0) */ -#define LX970A_ANAR_REMOTEFAULT 0x2000 /* Remote Fault (RW=0) */ -#define LX970A_ANAR_RESERVED_2 0x1800 /* Reserved (RW=0) */ -#define LX970A_ANAR_PAUSE 0x0400 /* Pause (RW=0) */ -#define LX970A_ANAR_100T4 0x0200 /* 100BASE-T4 (RW=0) */ -#define LX970A_ANAR_100TX_FD 0x0100 /* 100BASE-TX (RW=1[FDE,MF4]) */ -#define LX970A_ANAR_100TX_HD 0x0080 /* 100BASE-TX (RW=1[MF4]) */ -#define LX970A_ANAR_10T_FD 0x0040 /* 10BASE-T full-duplex (RW=1[FDE,CFG1]) */ -#define LX970A_ANAR_10T_HD 0x0020 /* 10BASE-T (RW=1[CFG1]) */ -#define LX970A_ANAR_SF 0x001F /* Selector Field, S<4:0> (RW=00001b) */ -#define LX970A_ANAR_RO_MASK 0xC000 -#define LX970A_ANAR_RW_MASK 0x3FFF -#define LX970A_ANAR_DEFAULT 0x01E1 -/* auxiliary */ -#define LX970A_ANAR_SF_IEEE8023 0x0001 /* <00001> = IEEE 802.3 */ - -#define LX970A_ANLPAR 0x05 /* Table 50. Auto Negotiation Link Partner Ability Register (Address 5) */ -#define LX970A_ANLPAR_NEXTPAGE 0x8000 /* Next Page (RO) */ -#define LX970A_ANLPAR_ACKNOWLEDGE 0x4000 /* Acknowledge (RO) */ -#define LX970A_ANLPAR_REMOTEFAULT 0x2000 /* Remote Fault (RO) */ -#define LX970A_ANLPAR_RESERVED 0x1800 /* Reserved (RO) */ -#define LX970A_ANLPAR_PAUSE 0x0400 /* Pause (RO) */ -#define LX970A_ANLPAR_100T4 0x0200 /* 100BASE-T4 (RO) */ -#define LX970A_ANLPAR_100TX_FD 0x0100 /* 100BASE-TX full-duplex (RO) */ -#define LX970A_ANLPAR_100TX_HD 0x0080 /* 100BASE-TX (RO) */ -#define LX970A_ANLPAR_10T_FD 0x0040 /* 10BASE-T full-duplex (RO) */ -#define LX970A_ANLPAR_10T_HD 0x0020 /* 10BASE-T (RO) */ -#define LX970A_ANLPAR_SF 0x001F /* Selector Field S[4:0] (RO) */ -#define LX970A_ANLPAR_RO_MASK 0xFFFF -#define LX970A_ANLPAR_RW_MASK 0x0000 -#define LX970A_ANLPAR_DEFAULT 0x0000 -/* auxiliary */ -#define LX970A_ANLPAR_SF_IEEE8023 0x0001 /* <00001> = IEEE 802.3 */ - -#define LX970A_ANE 0x06 /* Table 51. Auto Negotiation Expansion (Address 6) */ -#define LX970A_ANE_RESERVED 0xFFE0 /* Reserved (RO=0) */ -#define LX970A_ANE_PDETECTFAULT 0x0010 /* Parallel Detection Fault (RO=0,LH) */ -#define LX970A_ANE_LPNPA 0x0008 /* Link Partner Next Page Able (RO=0) */ -#define LX970A_ANE_NPA 0x0004 /* Next Page Able (RO=0) */ -#define LX970A_ANE_PR 0x0002 /* Page Received (RO=0,LH) */ -#define LX970A_ANE_LPANA 0x0001 /* Link Partner Auto Neg Able (RO=0) */ -#define LX970A_ANE_RO_MASK 0xFFFF -#define LX970A_ANE_RW_MASK 0x0000 -#define LX970A_ANE_DEFAULT 0x0000 - -/* -Vendor Specific MII Registers -*/ - -#define LX970A_MR 0x10 /* Table 52. Mirror Register (Address 16, Hex 10) */ -#define LX970A_MR_USERDEFINED 0xFFFF /* User Defined (RW=0) */ -#define LX970A_MR_RO_MASK 0x0000 -#define LX970A_MR_RW_MASK 0xFFFF -#define LX970A_MR_DEFAULT 0x0000 - -#define LX970A_IER 0x11 /* Table 53. Interrupt Enable Register (Address 17, Hex 11) */ -#define LX970A_IER_RESERVED 0xFFF0 /* Reserved (RO=0) */ -#define LX970A_IER_MIIDRVLVL 0x0008 /* MIIDRVLVL (RW=0) */ -#define LX970A_IER_LNK_CRITERIA 0x0004 /* LNK CRITERIA (RW=0) */ -#define LX970A_IER_INTEN 0x0002 /* INTEN (RW=0) */ -#define LX970A_IER_TINT 0x0001 /* TINT (RW=0,IGN) */ -#define LX970A_IER_RO_MASK 0xFFF0 -#define LX970A_IER_RW_MASK 0x000F -#define LX970A_IER_DEFAULT 0x0000 - -#define LX970A_ISR 0x12 /* Table 54. Interrupt Status Register (Address 18, Hex 12) */ -#define LX970A_ISR_MINT 0x8000 /* MINT (RO=0?) */ -#define LX970A_ISR_XTALOK 0x4000 /* XTALOK (RO=0) */ -#define LX970A_ISR_RESERVED 0x3FFF /* Reserved (RO=0) */ -#define LX970A_ISR_RO_MASK 0xFFFF -#define LX970A_ISR_RW_MASK 0x0000 -#define LX970A_ISR_DEFAULT 0x0000 - -#define LX970A_CFGR 0x13 /* Table 55. Configuration Register (Address 19, Hex 13) */ -#define LX970A_CFGR_RESERVED_1 0x8000 /* Reserved (RO=0) */ -#define LX970A_CFGR_TXMITTEST 0x4000 /* Txmit Test (100BASE-TX) (RW=0,RTOR) */ -#define LX970A_CFGR_REPEATERMODE 0x2000 /* Repeater Mode (RW=0[MF1]) */ -#define LX970A_CFGR_MDIOINT 0x1000 /* MDIO_INT (RW=0,IGN) */ -#define LX970A_CFGR_TPLOOPBACK 0x0800 /* TP Loopback (10BASE-T) (RW=0) */ -#define LX970A_CFGR_SQE 0x0400 /* SQE (10BASE-T) (RW=0) */ -#define LX970A_CFGR_JABBER 0x0200 /* Jabber (10BASE-T) (RW=0) */ -#define LX970A_CFGR_LINKTEST 0x0100 /* Link Test (10BASE-T) (RW=0[CFG1,MF0]) */ -#define LX970A_CFGR_LEDC 0x00C0 /* LEDC Programming bits (RW=0) */ -#define LX970A_CFGR_ATXC 0x0020 /* Advance TX Clock (RW=0) */ -#define LX970A_CFGR_5BS_4BN 0x0010 /* 5B Symbol/(100BASE-X only) 4B Nibble (RW=1[MF2]) */ -#define LX970A_CFGR_SCRAMBLER 0x0008 /* Scrambler (100BASE-X only) (RW=1[MF3]) */ -#define LX970A_CFGR_100FX 0x0004 /* 100BASE-FX (RW=1[MF4,MF0]) */ -#define LX970A_CFGR_RESERVED_2 0x0002 /* Reserved (RO=0) */ -#define LX970A_CFGR_TD 0x0001 /* Transmit Disconnect (RW=0) */ -#define LX970A_CFGR_RO_MASK 0x8002 -#define LX970A_CFGR_RW_MASK 0x7FFD -#define LX970A_CFGR_DEFAULT 0x0014 -/* auxiliary */ -#define LX970A_CFGR_LEDC_COLLISION 0x0000 /* 0 0 LEDC indicates collision */ -#define LX970A_CFGR_LEDC_OFF 0x0040 /* 0 1 LEDC is off */ -#define LX970A_CFGR_LEDC_ACTIVITY 0x0080 /* 1 0 LEDC indicates activity */ -#define LX970A_CFGR_LEDC_ALWAYSON 0x00C0 /* 1 1 LEDC is continuously on (for diagnostic use) */ - -#define LX970A_CSR 0x14 /* Table 56. Chip Status Register (Address 20, Hex 14) */ -#define LX970A_CSR_RESERVED_1 0xC000 /* Reserved (RO=0?) */ -#define LX970A_CSR_LINK 0x2000 /* Link (RO=0,RTOR) */ -#define LX970A_CSR_DUPLEXMODE 0x1000 /* Duplex Mode (RO=1[FDE],RTOR) */ -#define LX970A_CSR_SPEED 0x0800 /* Speed (RO=1[CFG0],RTOR) */ -#define LX970A_CSR_RESERVED_2 0x0400 /* Reserved (RO=0?) */ -#define LX970A_CSR_ANCOMPLETE 0x0200 /* Auto-Negotiation Complete (RO=0,LH,RTOR) */ -#define LX970A_CSR_PAGERECEIVED 0x0100 /* Page Received (RO=0,LH,RTOR) */ -#define LX970A_CSR_RESERVED_3 0x00C0 /* Reserved (RO=0) */ -#define LX970A_CSR_RESERVED_4 0x0038 /* Reserved (RO=0?) */ -#define LX970A_CSR_LOWVOLTAGE 0x0004 /* Low-Voltage (RO=0?) */ -#define LX970A_CSR_RESERVED_5 0x0003 /* Reserved (RO=0?) */ -#define LX970A_CSR_RO_MASK 0xFFFF -#define LX970A_CSR_RW_MASK 0x0000 -#define LX970A_CSR_DEFAULT 0x1800 - -#endif diff --git a/common/dev_mpc860.c b/common/dev_mpc860.c index 2efc0200d..d203e5a8c 100644 --- a/common/dev_mpc860.c +++ b/common/dev_mpc860.c @@ -17,7 +17,7 @@ #include "memory.h" #include "device.h" #include "net_io.h" -#include "dev_lxt970a.h" +#include "rust-dynamips.h" #include "dev_mpc860.h" /* Debugging flags */ @@ -405,8 +405,7 @@ struct mpc860_data { /* FEC MII registers */ m_uint32_t fec_mii_data; - m_uint16_t fec_mii_regs[32]; - m_uint8_t fec_mii_last_read_reg; + struct Lxt970A *fec_mii_phy; /* Dual-Port RAM */ m_uint8_t dpram[MPC860_DPRAM_SIZE]; @@ -1207,7 +1206,7 @@ static int dev_mpc860_scc_access(struct mpc860_data *d,m_uint32_t offset, /* link status */ static int mpc860_fec_link_is_up(struct mpc860_data *d) { - return(d->fec_nio && !(d->fec_mii_regs[LX970A_CR] & LX970A_CR_POWERDOWN)); + return(d->fec_nio && lxt970a_link_is_up(d->fec_mii_phy)); } /* Trigger interrupt for FEC */ @@ -1423,115 +1422,16 @@ static int mpc860_fec_handle_rx_pkt(netio_desc_t *nio, return(TRUE); } -/* MII update registers */ -static void mpc860_fec_mii_update_regs(struct mpc860_data *d) -{ - m_uint16_t *regs = d->fec_mii_regs; - if (mpc860_fec_link_is_up(d)) { - /* link up, LX970A_SR_LINKSTATUS is latch down */ - regs[LX970A_CSR] |= LX970A_CSR_LINK; - if (!(regs[LX970A_CR] & LX970A_CR_ANENABLE)) { - /* manual selection */ - if ((regs[LX970A_CR] & LX970A_CR_SPEEDSELECT)) { - /* 100Mbps */ - regs[LX970A_CSR] |= LX970A_CSR_SPEED; - } else { - /* 10 Mbps */ - regs[LX970A_CSR] &= ~LX970A_CSR_SPEED; - } - if ((regs[LX970A_CR] & LX970A_CR_DUPLEXMODE)) { - /* full duplex */ - regs[LX970A_CSR] |= LX970A_CSR_DUPLEXMODE; - } else { - /* half duplex */ - regs[LX970A_CSR] &= ~LX970A_CSR_DUPLEXMODE; - } - } else { - /* auto-negotiation, assume partner is standard 10/100 eth */ - regs[LX970A_ANLPAR] = (LX970A_ANLPAR_ACKNOWLEDGE | - LX970A_ANLPAR_100TX_FD | LX970A_ANLPAR_100TX_HD | - LX970A_ANLPAR_10T_FD | LX970A_ANLPAR_10T_HD); - if ((regs[LX970A_ANAR] & LX970A_ANAR_100TX_FD)) { - /* 100Mbps full duplex */ - regs[LX970A_CSR] |= (LX970A_CSR_DUPLEXMODE | LX970A_CSR_SPEED); - } else if ((regs[LX970A_ANAR] & LX970A_ANAR_100TX_HD)) { - /* 100Mbps half duplex */ - regs[LX970A_CSR] = ((regs[LX970A_CSR] & ~LX970A_CSR_DUPLEXMODE) | LX970A_CSR_SPEED); - } else if ((regs[LX970A_ANAR] & LX970A_ANAR_10T_FD)) { - /* 10Mbps full duplex */ - regs[LX970A_CSR] = (LX970A_CSR_DUPLEXMODE | (regs[LX970A_CSR] & ~LX970A_CSR_SPEED)); - } else { - /* 10Mbps half duplex */ - regs[LX970A_ANAR] |= LX970A_ANAR_10T_HD; - regs[LX970A_CSR] &= ~(LX970A_CSR_DUPLEXMODE | LX970A_CSR_SPEED); - } - d->fec_mii_regs[LX970A_CR] &= ~(LX970A_CR_ANRESTART); - d->fec_mii_regs[LX970A_SR] |= LX970A_SR_ANCOMPLETE; - d->fec_mii_regs[LX970A_CSR] |= LX970A_CSR_ANCOMPLETE; - } - } else { - /* link down or administratively down */ - d->fec_mii_regs[LX970A_SR] &= ~(LX970A_SR_ANCOMPLETE|LX970A_SR_LINKSTATUS); - d->fec_mii_regs[LX970A_CSR] &= ~(LX970A_CSR_LINK|LX970A_CSR_DUPLEXMODE|LX970A_CSR_SPEED|LX970A_CSR_ANCOMPLETE); - } -} - -/* MII register defaults */ -static void mpc860_fec_mii_defaults(struct mpc860_data *d) -{ - /* default is 100Mb/s full duplex and auto-negotiation */ - memset(d->fec_mii_regs, 0, sizeof(d->fec_mii_regs)); - d->fec_mii_regs[LX970A_CR] = LX970A_CR_DEFAULT; - d->fec_mii_regs[LX970A_SR] = LX970A_SR_DEFAULT; - d->fec_mii_regs[LX970A_PIR1] = LX970A_PIR1_DEFAULT; - d->fec_mii_regs[LX970A_PIR2] = LX970A_PIR2_DEFAULT; - d->fec_mii_regs[LX970A_ANAR] = LX970A_ANAR_DEFAULT; - d->fec_mii_regs[LX970A_ANE] = LX970A_ANE_DEFAULT; - d->fec_mii_regs[LX970A_MR] = LX970A_MR_DEFAULT; - d->fec_mii_regs[LX970A_IER] = LX970A_IER_DEFAULT; - d->fec_mii_regs[LX970A_ISR] = LX970A_ISR_DEFAULT; - d->fec_mii_regs[LX970A_CFGR] = LX970A_CFGR_DEFAULT; - d->fec_mii_regs[LX970A_CSR] = LX970A_CSR_DEFAULT; - - /* chip is powered up and stable */ - d->fec_mii_regs[LX970A_ISR] = LX970A_ISR_XTALOK; - - mpc860_fec_mii_update_regs(d); -} - /* MII register read access */ static void mpc860_fec_mii_read_access(struct mpc860_data *d, u_int phy,u_int reg) { - m_uint16_t res; - - res = d->fec_mii_regs[reg]; - - /* update bits */ - switch (reg) { - case LX970A_SR: - /* Latch Low */ - if (mpc860_fec_link_is_up(d)) { - d->fec_mii_regs[reg] &= LX970A_SR_LINKSTATUS; - } - break; - case LX970A_ISR: - if (d->fec_mii_last_read_reg == LX970A_SR) { - d->fec_mii_regs[reg] &= ~LX970A_ISR_MINT; - } - default: - /* XXX Latch High: - LX970A_SR_REMOTEFAULT, LX970A_SR_JABBERDETECT - LX970A_ANE_PDETECTFAULT, LX970A_ANE_PR, - LX970A_CSR_ANC, LX970A_CSR_PAGERECEIVED */ - break; - } + m_uint16_t res = lxt970a_mii_read_access(d->fec_mii_phy, reg); #if DEBUG_FEC - MPC_LOG(d,"FEC: Reading 0x%4.4x (0x%4.4x) from MII phy %d reg %d\n",res,d->fec_mii_regs[reg],phy,reg); + MPC_LOG(d,"FEC: Reading 0x%4.4x from MII phy %d reg %d\n",res,phy,reg); #endif - d->fec_mii_last_read_reg = reg; d->fec_mii_data &= 0xFFFF0000; d->fec_mii_data |= res; } @@ -1540,53 +1440,13 @@ static void mpc860_fec_mii_read_access(struct mpc860_data *d, static void mpc860_fec_mii_write_access(struct mpc860_data *d, u_int phy,u_int reg) { - m_uint16_t data, ro_mask, rw_mask; - int update_regs = FALSE; - - data = d->fec_mii_data & 0xFFFF; + m_uint16_t data = d->fec_mii_data & 0xFFFF; #if DEBUG_FEC MPC_LOG(d,"FEC: Writing 0x%4.4x to MII phy %d reg %d at ia=0x%4.4x,lr=0x%4.4x\n",data,phy,reg,CPU_PPC32(d->vm->boot_cpu)->ia,CPU_PPC32(d->vm->boot_cpu)->lr); #endif - switch (reg) { - case LX970A_CR: - /* reset, self clearing */ - if ((data & LX970A_CR_RESET)) { - mpc860_fec_mii_defaults(d); - return; - } - ro_mask = LX970A_CR_RO_MASK; - rw_mask = LX970A_CR_RW_MASK; - update_regs = TRUE; - break; - case LX970A_ANAR: - ro_mask = LX970A_ANAR_RO_MASK; - rw_mask = LX970A_ANAR_RW_MASK; - break; - case LX970A_MR: - ro_mask = LX970A_MR_RO_MASK; - rw_mask = LX970A_MR_RW_MASK; - break; - case LX970A_IER: - ro_mask = LX970A_IER_RO_MASK; - rw_mask = LX970A_IER_RW_MASK; - break; - case LX970A_CFGR: - ro_mask = LX970A_CFGR_RO_MASK; - rw_mask = LX970A_CFGR_RW_MASK; - break; - default: - /* read-only register */ - ro_mask = 0xFFFF; - rw_mask = 0x0000; - break; - } - - d->fec_mii_regs[reg] = (d->fec_mii_regs[reg] & ro_mask) | (data & rw_mask); - if (update_regs) { - mpc860_fec_mii_update_regs(d); - } + lxt970a_mii_write_access(d->fec_mii_phy, reg, data); } /* MII register access */ @@ -1724,7 +1584,7 @@ int mpc860_fec_set_nio(struct mpc860_data *d,netio_desc_t *nio) d->fec_nio = nio; netio_rxl_add(nio,(netio_rx_handler_t)mpc860_fec_handle_rx_pkt,d,NULL); - mpc860_fec_mii_update_regs(d); + lxt970a_set_has_nio(d->fec_mii_phy, true); return(0); } @@ -1737,7 +1597,7 @@ int mpc860_fec_unset_nio(struct mpc860_data *d) if (d->fec_nio != NULL) { netio_rxl_remove(d->fec_nio); d->fec_nio = NULL; - mpc860_fec_mii_update_regs(d); + lxt970a_set_has_nio(d->fec_mii_phy, false); } return(0); @@ -2067,6 +1927,8 @@ void mpc860_clear_pending_irq(struct mpc860_data *d,m_uint32_t val) void dev_mpc860_shutdown(vm_instance_t *vm,struct mpc860_data *d) { if (d != NULL) { + lxt970a_drop(d->fec_mii_phy); + /* Remove the device */ dev_remove(vm,&d->dev); @@ -2106,7 +1968,11 @@ int dev_mpc860_init(vm_instance_t *vm,char *name, dpram_w16(d,MPC860_SPI_BASE_ADDR,MPC860_SPI_BASE); /* Set MII register defaults */ - mpc860_fec_mii_defaults(d); + d->fec_mii_phy = lxt970a_new(); + if (d->fec_mii_phy == NULL) { + fprintf(stderr,"mpc860: unable to create fec_mii_phy.\n"); + return(-1); + } /* Map this device to the VM */ vm_bind_device(vm,&d->dev); diff --git a/rust/dynamips/cbindgen.toml b/rust/dynamips/cbindgen.toml index f6ad24cd3..6c786e2d7 100644 --- a/rust/dynamips/cbindgen.toml +++ b/rust/dynamips/cbindgen.toml @@ -2,3 +2,4 @@ language = "C" include_version = true include_guard = "RUST_DYNAMIPS_H" pragma_once = true +documentation_style = "c++" diff --git a/rust/dynamips/src/c/dev_lxt907a.rs b/rust/dynamips/src/c/dev_lxt907a.rs new file mode 100644 index 000000000..306fdacc9 --- /dev/null +++ b/rust/dynamips/src/c/dev_lxt907a.rs @@ -0,0 +1,52 @@ +//! C interface for [`crate::phy::lxt970a::Lxt970A`]. + +use crate::c::prelude::*; +use crate::phy::lxt970a::Lxt970A; + +/// Allocate a new PHY. +#[no_mangle] +pub extern "C" fn lxt970a_new() -> *mut Lxt970A { + let phy = Box::new(Lxt970A::new()); + Box::into_raw(phy) // memory managed by C +} + +/// Deallocate a PHY. +#[no_mangle] +pub extern "C" fn lxt970a_drop(phy: *mut Lxt970A) { + let phy = NonNull::new(phy).unwrap(); + let _ = unsafe { Box::from_raw(phy.as_ptr()) }; // memory managed by rust +} + +/// Notify PHY if a nio is available. +#[no_mangle] +pub extern "C" fn lxt970a_set_has_nio(phy: *mut Lxt970A, has_nio: bool) { + let mut phy = NonNull::new(phy).unwrap(); + let phy = unsafe { phy.as_mut() }; + phy.has_nio = has_nio; +} + +/// Check if the link is up. +#[no_mangle] +pub extern "C" fn lxt970a_link_is_up(phy: *mut Lxt970A) -> bool { + let mut phy = NonNull::new(phy).unwrap(); + let phy = unsafe { phy.as_mut() }; + phy.link_is_up() +} + +/// MII register read access. +#[no_mangle] +pub extern "C" fn lxt970a_mii_read_access(phy: *mut Lxt970A, reg: c_uint) -> u16 { + let mut phy = NonNull::new(phy).unwrap(); + let phy = unsafe { phy.as_mut() }; + let reg = usize::try_from(reg).unwrap(); + phy.mii_read_access(reg) +} + +/// MII register write access. +#[no_mangle] +pub extern "C" fn lxt970a_mii_write_access(phy: *mut Lxt970A, reg: c_uint, value: u16) { + let mut phy = NonNull::new(phy).unwrap(); + let phy = unsafe { phy.as_mut() }; + let reg = usize::try_from(reg).unwrap(); + phy.mii_write_access(reg, value) +} diff --git a/rust/dynamips/src/c/mod.rs b/rust/dynamips/src/c/mod.rs new file mode 100644 index 000000000..d66b87e92 --- /dev/null +++ b/rust/dynamips/src/c/mod.rs @@ -0,0 +1,14 @@ +//! Stuff that interacts with C code. + +pub(crate) mod prelude { + #![allow(unused_imports)] + //#![allow(dead_code)] + //#![allow(non_camel_case_types)] + + pub(crate) use crate::macros::opaque_struct; + pub(crate) use std::ffi::*; + pub(crate) use std::ptr::null_mut; + pub(crate) use std::ptr::NonNull; +} + +pub mod dev_lxt907a; diff --git a/rust/dynamips/src/lib.rs b/rust/dynamips/src/lib.rs index e69de29bb..5277ff596 100644 --- a/rust/dynamips/src/lib.rs +++ b/rust/dynamips/src/lib.rs @@ -0,0 +1,6 @@ +//! Crate rust-dynamips +#![allow(clippy::unusual_byte_groupings)] + +pub mod c; +pub mod macros; +pub mod phy; diff --git a/rust/dynamips/src/macros.rs b/rust/dynamips/src/macros.rs new file mode 100644 index 000000000..22cf80ed0 --- /dev/null +++ b/rust/dynamips/src/macros.rs @@ -0,0 +1,14 @@ +//! Macros +#![allow(unused_macros)] + +/// Defines an opaque struct that has unknown data, is pointer aligned(?), and cannot change address. +macro_rules! opaque_struct { + ($name:ident) => { + pub struct $name { + _data: [u8; 0], + _marker: ::std::marker::PhantomData<(*mut u8, ::std::marker::PhantomPinned)>, + } + }; +} + +pub(crate) use opaque_struct; diff --git a/rust/dynamips/src/phy/lxt970a.rs b/rust/dynamips/src/phy/lxt970a.rs new file mode 100644 index 000000000..94cfe577d --- /dev/null +++ b/rust/dynamips/src/phy/lxt970a.rs @@ -0,0 +1,482 @@ +//! 10/100 Mbps PHY +//! +//! # References: +//! * [Intel LXT970A Dual-Speed Fast Ethernet Transceiver, January 2001](https://github.com/flaviojs/dynamips-datasheets/blob/master/ethernet/phy/LXT970A.pdf) +//! * IEEE Std 802.3-2008, Section 2 + +/* +Abreviations: + RW=x - Read/Write with default value x + RO=x - Read Only with default value x + [xx] - default value determined by pins xx + SC - Self Clearing + LH - Latching High (remains High until read, and then returns to Low) + LL - Latching Low (remains Low until read, and then returns to High) + IGN - IGNored on certain conditions + RTOR - Related To Other Register + +Pin states used for the default values: + MF0 = VMF2 or VMF3 (Enabled) + MF1 = VMF1 or VMF4 (Disabled) + MF2 = VMF2 or VMF3 (Enabled) + MF3 = VMF2 or VMF3 (Enabled) + MF4 = VMF2 or VMF3 (Enabled) + CFG0 = High + CFG1 = High + TRSTE = Low + FDE = High + MDDIS = Low, RESET = High, PWERDWN = Low (2.4.1.2, MDIO Control) +*/ + +/* +Standard MII Registers +*/ + +/// Table 45. Control Register (Address 0) +pub const LX970A_CR: usize = 0x00; +/// Reset (RW=0,SC) +pub const LX970A_CR_RESET: u16 = 0x8000; +/// Loopback (RW=0) +pub const LX970A_CR_LOOP: u16 = 0x4000; +/// Speed Selection (RW=1(CFG0),IGN) +pub const LX970A_CR_SPEEDSELECT: u16 = 0x2000; +/// Auto-Negotiation Enable (RW=1(MF0)) +pub const LX970A_CR_ANENABLE: u16 = 0x1000; +/// Power Down (RW=0?) +pub const LX970A_CR_POWERDOWN: u16 = 0x0800; +/// Isolate (RW=0(TRSTE)) +pub const LX970A_CR_ISOLATE: u16 = 0x0400; +/// Restart Auto-Negotiation (RW=1(CFG0),SC) +pub const LX970A_CR_ANRESTART: u16 = 0x0200; +/// Duplex Mode (RW=1(FDE),IGN) +pub const LX970A_CR_DUPLEXMODE: u16 = 0x0100; +/// Collision Test (RW=0,IGN) +pub const LX970A_CR_COLLISIONTEST: u16 = 0x0080; +/// Transceiver Test Mode (RO=0) +pub const LX970A_CR_TTM: u16 = 0x0070; +/// Master-Slave Enable (RO=0) +pub const LX970A_CR_MSENABLE: u16 = 0x0008; +/// Master-Slave Value (RO=0) +pub const LX970A_CR_MSVALUE: u16 = 0x0004; +/// Reserved (RW=0) +pub const LX970A_CR_RESERVED: u16 = 0x0003; +pub const LX970A_CR_RO_MASK: u16 = 0x007C; +pub const LX970A_CR_RW_MASK: u16 = 0xFF83; +pub const LX970A_CR_DEFAULT: u16 = 0x3300; + +/// Table 46. Status Register (Address 1) +pub const LX970A_SR: usize = 0x01; +/// 100BASE-T4 (RO=0) +pub const LX970A_SR_100T4: u16 = 0x8000; +/// 100BASE-X full-duplex (RO=1) +pub const LX970A_SR_100TX_FD: u16 = 0x4000; +/// 100BASE-X hald-duplex (RO=1) +pub const LX970A_SR_100TX_HD: u16 = 0x2000; +/// 10 Mb/s full-duplex (RO=1) +pub const LX970A_SR_10T_FD: u16 = 0x1000; +/// 10 Mb/s half-duplex (RO=1) +pub const LX970A_SR_10T_HD: u16 = 0x0800; +/// 100BASE-T2 full-duplex (RO=0) +pub const LX970A_SR_100T2_FD: u16 = 0x0400; +/// 100BASE-T2 half-duplex (RO=0) +pub const LX970A_SR_100T2_HD: u16 = 0x0200; +/// Reserved (RO=0) +pub const LX970A_SR_RESERVED: u16 = 0x0100; +/// Master-Slave Configuration Fault (RO=0) +pub const LX970A_SR_MSCFGFAULT: u16 = 0x0080; +/// MF Preamble Suppression (RO=0) +pub const LX970A_SR_MFPS: u16 = 0x0040; +/// Auto-Neg. Complete (RO=0) +pub const LX970A_SR_ANCOMPLETE: u16 = 0x0020; +/// Remote Fault (RO=0,LH) +pub const LX970A_SR_REMOTEFAULT: u16 = 0x0010; +/// Auto-Neg. Ability (RO=1) +pub const LX970A_SR_ANABILITY: u16 = 0x0008; +/// Link Status (RO=0,LL) +pub const LX970A_SR_LINKSTATUS: u16 = 0x0004; +/// Jabber Detect (10BASE-T Only) (RO=0,LH) +pub const LX970A_SR_JABBERDETECT: u16 = 0x0002; +/// Extended Capability (RO=1) +pub const LX970A_SR_EXTCAPABILITY: u16 = 0x0001; +pub const LX970A_SR_RO_MASK: u16 = 0xFFFF; +pub const LX970A_SR_RW_MASK: u16 = 0x0000; +pub const LX970A_SR_DEFAULT: u16 = 0x7809; + +/* +PHY ID number: + Intel has OUI=00207Bh and ROUI=DE0400h (OUI with bits reversed) + (ROUI << 10) & FFFFFFFFh = 78100000h +*/ + +/// Table 47. PHY Identification Register 1 (Address 2) +pub const LX970A_PIR1: usize = 0x02; +/// PHY ID Number (RO=7810h) +pub const LX970A_PIR1_PIN: u16 = 0xFFFF; +pub const LX970A_PIR1_RO_MASK: u16 = 0xFFFF; +pub const LX970A_PIR1_RW_MASK: u16 = 0x0000; +pub const LX970A_PIR1_DEFAULT: u16 = 0x7810; + +/// Table 48. PHY Identification Register 2 (Address 3) +pub const LX970A_PIR2: usize = 0x03; +/// PHY ID number (RO=000000b) +pub const LX970A_PIR2_PIN: u16 = 0xFC00; +/// Manufacturer’s model number (RO=000000b) +pub const LX970A_PIR2_MANMODELNUM: u16 = 0x03F0; +/// Manufacturer’s revision number (RO=0011b) +pub const LX970A_PIR2_MANREVNUM: u16 = 0x000F; +pub const LX970A_PIR2_RO_MASK: u16 = 0xFFFF; +pub const LX970A_PIR2_RW_MASK: u16 = 0x0000; +pub const LX970A_PIR2_DEFAULT: u16 = 0x0003; + +/// Table 49. Auto Negotiation Advertisement Register (Address 4) +pub const LX970A_ANAR: usize = 0x04; +/// Next Page (RO=0) +pub const LX970A_ANAR_NEXTPAGE: u16 = 0x8000; +/// Reserved (RO=0) +pub const LX970A_ANAR_RESERVED_1: u16 = 0x4000; +/// Remote Fault (RW=0) +pub const LX970A_ANAR_REMOTEFAULT: u16 = 0x2000; +/// Reserved (RW=0) +pub const LX970A_ANAR_RESERVED_2: u16 = 0x1800; +/// Pause (RW=0) +pub const LX970A_ANAR_PAUSE: u16 = 0x0400; +/// 100BASE-T4 (RW=0) +pub const LX970A_ANAR_100T4: u16 = 0x0200; +/// 100BASE-TX (RW=1(FDE,MF4)) +pub const LX970A_ANAR_100TX_FD: u16 = 0x0100; +/// 100BASE-TX (RW=1(MF4)) +pub const LX970A_ANAR_100TX_HD: u16 = 0x0080; +/// 10BASE-T full-duplex (RW=1(FDE,CFG1)) +pub const LX970A_ANAR_10T_FD: u16 = 0x0040; +/// 10BASE-T (RW=1(CFG1)) +pub const LX970A_ANAR_10T_HD: u16 = 0x0020; +/// Selector Field, S<4:0> (RW=00001b) +pub const LX970A_ANAR_SF: u16 = 0x001F; +pub const LX970A_ANAR_RO_MASK: u16 = 0xC000; +pub const LX970A_ANAR_RW_MASK: u16 = 0x3FFF; +pub const LX970A_ANAR_DEFAULT: u16 = 0x01E1; +/* auxiliary */ +/// <00001> = IEEE 802.3 +pub const LX970A_ANAR_SF_IEEE8023: u16 = 0x0001; + +/// Table 50. Auto Negotiation Link Partner Ability Register (Address 5) +pub const LX970A_ANLPAR: usize = 0x05; +/// Next Page (RO) +pub const LX970A_ANLPAR_NEXTPAGE: u16 = 0x8000; +/// Acknowledge (RO) +pub const LX970A_ANLPAR_ACKNOWLEDGE: u16 = 0x4000; +/// Remote Fault (RO) +pub const LX970A_ANLPAR_REMOTEFAULT: u16 = 0x2000; +/// Reserved (RO) +pub const LX970A_ANLPAR_RESERVED: u16 = 0x1800; +/// Pause (RO) +pub const LX970A_ANLPAR_PAUSE: u16 = 0x0400; +/// 100BASE-T4 (RO) +pub const LX970A_ANLPAR_100T4: u16 = 0x0200; +/// 100BASE-TX full-duplex (RO) +pub const LX970A_ANLPAR_100TX_FD: u16 = 0x0100; +/// 100BASE-TX (RO) +pub const LX970A_ANLPAR_100TX_HD: u16 = 0x0080; +/// 10BASE-T full-duplex (RO) +pub const LX970A_ANLPAR_10T_FD: u16 = 0x0040; +/// 10BASE-T (RO) +pub const LX970A_ANLPAR_10T_HD: u16 = 0x0020; +/// Selector Field S(4:0) (RO) +pub const LX970A_ANLPAR_SF: u16 = 0x001F; +pub const LX970A_ANLPAR_RO_MASK: u16 = 0xFFFF; +pub const LX970A_ANLPAR_RW_MASK: u16 = 0x0000; +pub const LX970A_ANLPAR_DEFAULT: u16 = 0x0000; +/* auxiliary */ +/// <00001> = IEEE 802.3 +pub const LX970A_ANLPAR_SF_IEEE8023: u16 = 0x0001; + +/// Table 51. Auto Negotiation Expansion (Address 6) +pub const LX970A_ANE: usize = 0x06; +/// Reserved (RO=0) +pub const LX970A_ANE_RESERVED: u16 = 0xFFE0; +/// Parallel Detection Fault (RO=0,LH) +pub const LX970A_ANE_PDETECTFAULT: u16 = 0x0010; +/// Link Partner Next Page Able (RO=0) +pub const LX970A_ANE_LPNPA: u16 = 0x0008; +/// Next Page Able (RO=0) +pub const LX970A_ANE_NPA: u16 = 0x0004; +/// Page Received (RO=0,LH) +pub const LX970A_ANE_PR: u16 = 0x0002; +/// Link Partner Auto Neg Able (RO=0) +pub const LX970A_ANE_LPANA: u16 = 0x0001; +pub const LX970A_ANE_RO_MASK: u16 = 0xFFFF; +pub const LX970A_ANE_RW_MASK: u16 = 0x0000; +pub const LX970A_ANE_DEFAULT: u16 = 0x0000; + +/* +Vendor Specific MII Registers +*/ + +/// Table 52. Mirror Register (Address 16, Hex 10) +pub const LX970A_MR: usize = 0x10; +/// User Defined (RW=0) +pub const LX970A_MR_USERDEFINED: u16 = 0xFFFF; +pub const LX970A_MR_RO_MASK: u16 = 0x0000; +pub const LX970A_MR_RW_MASK: u16 = 0xFFFF; +pub const LX970A_MR_DEFAULT: u16 = 0x0000; + +/// Table 53. Interrupt Enable Register (Address 17, Hex 11) +pub const LX970A_IER: usize = 0x11; +/// Reserved (RO=0) +pub const LX970A_IER_RESERVED: u16 = 0xFFF0; +/// MIIDRVLVL (RW=0) +pub const LX970A_IER_MIIDRVLVL: u16 = 0x0008; +/// LNK CRITERIA (RW=0) +pub const LX970A_IER_LNK_CRITERIA: u16 = 0x0004; +/// INTEN (RW=0) +pub const LX970A_IER_INTEN: u16 = 0x0002; +/// TINT (RW=0,IGN) +pub const LX970A_IER_TINT: u16 = 0x0001; +pub const LX970A_IER_RO_MASK: u16 = 0xFFF0; +pub const LX970A_IER_RW_MASK: u16 = 0x000F; +pub const LX970A_IER_DEFAULT: u16 = 0x0000; + +/// Table 54. Interrupt Status Register (Address 18, Hex 12) +pub const LX970A_ISR: usize = 0x12; +/// MINT (RO=0?) +pub const LX970A_ISR_MINT: u16 = 0x8000; +/// XTALOK (RO=0) +pub const LX970A_ISR_XTALOK: u16 = 0x4000; +/// Reserved (RO=0) +pub const LX970A_ISR_RESERVED: u16 = 0x3FFF; +pub const LX970A_ISR_RO_MASK: u16 = 0xFFFF; +pub const LX970A_ISR_RW_MASK: u16 = 0x0000; +pub const LX970A_ISR_DEFAULT: u16 = 0x0000; + +/// Table 55. Configuration Register (Address 19, Hex 13) +pub const LX970A_CFGR: usize = 0x13; +/// Reserved (RO=0) +pub const LX970A_CFGR_RESERVED_1: u16 = 0x8000; +/// Txmit Test (100BASE-TX) (RW=0,RTOR) +pub const LX970A_CFGR_TXMITTEST: u16 = 0x4000; +/// Repeater Mode (RW=0(MF1)) +pub const LX970A_CFGR_REPEATERMODE: u16 = 0x2000; +/// MDIO_INT (RW=0,IGN) +pub const LX970A_CFGR_MDIOINT: u16 = 0x1000; +/// TP Loopback (10BASE-T) (RW=0) +pub const LX970A_CFGR_TPLOOPBACK: u16 = 0x0800; +/// SQE (10BASE-T) (RW=0) +pub const LX970A_CFGR_SQE: u16 = 0x0400; +/// Jabber (10BASE-T) (RW=0) +pub const LX970A_CFGR_JABBER: u16 = 0x0200; +/// Link Test (10BASE-T) (RW=0(CFG1,MF0)) +pub const LX970A_CFGR_LINKTEST: u16 = 0x0100; +/// LEDC Programming bits (RW=0) +pub const LX970A_CFGR_LEDC: u16 = 0x00C0; +/// Advance TX Clock (RW=0) +pub const LX970A_CFGR_ATXC: u16 = 0x0020; +/// 5B Symbol/(100BASE-X only) 4B Nibble (RW=1(MF2)) +pub const LX970A_CFGR_5BS_4BN: u16 = 0x0010; +/// Scrambler (100BASE-X only) (RW=1(MF3)) +pub const LX970A_CFGR_SCRAMBLER: u16 = 0x0008; +/// 100BASE-FX (RW=1(MF4,MF0)) +pub const LX970A_CFGR_100FX: u16 = 0x0004; +/// Reserved (RO=0) +pub const LX970A_CFGR_RESERVED_2: u16 = 0x0002; +/// Transmit Disconnect (RW=0) +pub const LX970A_CFGR_TD: u16 = 0x0001; +pub const LX970A_CFGR_RO_MASK: u16 = 0x8002; +pub const LX970A_CFGR_RW_MASK: u16 = 0x7FFD; +pub const LX970A_CFGR_DEFAULT: u16 = 0x0014; +/* auxiliary */ +/// 0 0 LEDC indicates collision +pub const LX970A_CFGR_LEDC_COLLISION: u16 = 0x0000; +/// 0 1 LEDC is off +pub const LX970A_CFGR_LEDC_OFF: u16 = 0x0040; +/// 1 0 LEDC indicates activity +pub const LX970A_CFGR_LEDC_ACTIVITY: u16 = 0x0080; +/// 1 1 LEDC is continuously on (for diagnostic use) +pub const LX970A_CFGR_LEDC_ALWAYSON: u16 = 0x00C0; + +/// Table 56. Chip Status Register (Address 20, Hex 14) +pub const LX970A_CSR: usize = 0x14; +/// Reserved (RO=0?) +pub const LX970A_CSR_RESERVED_1: u16 = 0xC000; +/// Link (RO=0,RTOR) +pub const LX970A_CSR_LINK: u16 = 0x2000; +/// Duplex Mode (RO=1(FDE),RTOR) +pub const LX970A_CSR_DUPLEXMODE: u16 = 0x1000; +/// Speed (RO=1(CFG0),RTOR) +pub const LX970A_CSR_SPEED: u16 = 0x0800; +/// Reserved (RO=0?) +pub const LX970A_CSR_RESERVED_2: u16 = 0x0400; +/// Auto-Negotiation Complete (RO=0,LH,RTOR) +pub const LX970A_CSR_ANCOMPLETE: u16 = 0x0200; +/// Page Received (RO=0,LH,RTOR) +pub const LX970A_CSR_PAGERECEIVED: u16 = 0x0100; +/// Reserved (RO=0) +pub const LX970A_CSR_RESERVED_3: u16 = 0x00C0; +/// Reserved (RO=0?) +pub const LX970A_CSR_RESERVED_4: u16 = 0x0038; +/// Low-Voltage (RO=0?) +pub const LX970A_CSR_LOWVOLTAGE: u16 = 0x0004; +/// Reserved (RO=0?) +pub const LX970A_CSR_RESERVED_5: u16 = 0x0003; +pub const LX970A_CSR_RO_MASK: u16 = 0xFFFF; +pub const LX970A_CSR_RW_MASK: u16 = 0x0000; +pub const LX970A_CSR_DEFAULT: u16 = 0x1800; + +/// 10/100 Mbps PHY +pub struct Lxt970A { + pub regs: [u16; 32], + pub last_read_was_sr: bool, + /// temporary variable to preserve behavior + pub has_nio: bool, +} +impl Default for Lxt970A { + fn default() -> Self { + let mut x = Self { regs: [0; 32], last_read_was_sr: false, has_nio: false }; + x.set_defaults(); + x + } +} +impl Lxt970A { + pub fn new() -> Self { + Self::default() + } + /// Link status + pub fn link_is_up(&self) -> bool { + self.has_nio && (self.regs[LX970A_CR] & LX970A_CR_POWERDOWN) == 0 + } + /// MII update registers + pub fn update_regs(&mut self) { + if self.link_is_up() { + // link up, LX970A_SR_LINKSTATUS is latch down + self.regs[LX970A_CSR] |= LX970A_CSR_LINK; + if (self.regs[LX970A_CR] & LX970A_CR_ANENABLE) == 0 { + // manual selection + if (self.regs[LX970A_CR] & LX970A_CR_SPEEDSELECT) != 0 { + // 100Mbps + self.regs[LX970A_CSR] |= LX970A_CSR_SPEED; + } else { + // 10 Mbps + self.regs[LX970A_CSR] &= !LX970A_CSR_SPEED; + } + if (self.regs[LX970A_CR] & LX970A_CR_DUPLEXMODE) != 0 { + // full duplex + self.regs[LX970A_CSR] |= LX970A_CSR_DUPLEXMODE; + } else { + // half duplex + self.regs[LX970A_CSR] &= !LX970A_CSR_DUPLEXMODE; + } + } else { + // auto-negotiation, assume partner is standard 10/100 eth + self.regs[LX970A_ANLPAR] = LX970A_ANLPAR_ACKNOWLEDGE + | LX970A_ANLPAR_100TX_FD + | LX970A_ANLPAR_100TX_HD + | LX970A_ANLPAR_10T_FD + | LX970A_ANLPAR_10T_HD; + if (self.regs[LX970A_ANAR] & LX970A_ANAR_100TX_FD) != 0 { + // 100Mbps full duplex + self.regs[LX970A_CSR] |= LX970A_CSR_DUPLEXMODE | LX970A_CSR_SPEED; + } else if (self.regs[LX970A_ANAR] & LX970A_ANAR_100TX_HD) != 0 { + // 100Mbps half duplex + self.regs[LX970A_CSR] = + (self.regs[LX970A_CSR] & !LX970A_CSR_DUPLEXMODE) | LX970A_CSR_SPEED; + } else if (self.regs[LX970A_ANAR] & LX970A_ANAR_10T_FD) != 0 { + // 10Mbps full duplex + self.regs[LX970A_CSR] = + LX970A_CSR_DUPLEXMODE | (self.regs[LX970A_CSR] & !LX970A_CSR_SPEED); + } else { + // 10Mbps half duplex + self.regs[LX970A_ANAR] |= LX970A_ANAR_10T_HD; + self.regs[LX970A_CSR] &= !(LX970A_CSR_DUPLEXMODE | LX970A_CSR_SPEED); + } + self.regs[LX970A_CR] &= !(LX970A_CR_ANRESTART); + self.regs[LX970A_SR] |= LX970A_SR_ANCOMPLETE; + self.regs[LX970A_CSR] |= LX970A_CSR_ANCOMPLETE; + } + } else { + // link down or administratively down + self.regs[LX970A_SR] &= !(LX970A_SR_ANCOMPLETE | LX970A_SR_LINKSTATUS); + self.regs[LX970A_CSR] &= !(LX970A_CSR_LINK + | LX970A_CSR_DUPLEXMODE + | LX970A_CSR_SPEED + | LX970A_CSR_ANCOMPLETE); + } + } + /// MII register defaults + pub fn set_defaults(&mut self) { + // default is 100Mb/s full duplex and auto-negotiation + self.regs = [0; 32]; + self.regs[LX970A_CR] = LX970A_CR_DEFAULT; + self.regs[LX970A_SR] = LX970A_SR_DEFAULT; + self.regs[LX970A_PIR1] = LX970A_PIR1_DEFAULT; + self.regs[LX970A_PIR2] = LX970A_PIR2_DEFAULT; + self.regs[LX970A_ANAR] = LX970A_ANAR_DEFAULT; + self.regs[LX970A_ANE] = LX970A_ANE_DEFAULT; + self.regs[LX970A_MR] = LX970A_MR_DEFAULT; + self.regs[LX970A_IER] = LX970A_IER_DEFAULT; + self.regs[LX970A_ISR] = LX970A_ISR_DEFAULT; + self.regs[LX970A_CFGR] = LX970A_CFGR_DEFAULT; + self.regs[LX970A_CSR] = LX970A_CSR_DEFAULT; + + // chip is powered up and stable + self.regs[LX970A_ISR] = LX970A_ISR_XTALOK; + + self.update_regs(); + } + + /// MII register read access + pub fn mii_read_access(&mut self, reg: usize) -> u16 { + let value = self.regs[reg]; + + // update bits + match reg { + LX970A_SR => { + // Latch Low + if self.link_is_up() { + self.regs[reg] &= LX970A_SR_LINKSTATUS; + } + } + LX970A_ISR => { + if self.last_read_was_sr { + self.regs[reg] &= !LX970A_ISR_MINT; + } + } + _ => { + /* XXX Latch High: + LX970A_SR_REMOTEFAULT, LX970A_SR_JABBERDETECT + LX970A_ANE_PDETECTFAULT, LX970A_ANE_PR, + LX970A_CSR_ANC, LX970A_CSR_PAGERECEIVED */ + } + } + + self.last_read_was_sr = reg == LX970A_SR; + value + } + + /// MII register write access + pub fn mii_write_access(&mut self, reg: usize, value: u16) { + let mut update_regs = false; + let (ro_mask, rw_mask) = match reg { + LX970A_CR => { + // reset, self clearing + if (value & LX970A_CR_RESET) != 0 { + self.set_defaults(); + return; + } + update_regs = true; + (LX970A_CR_RO_MASK, LX970A_CR_RW_MASK) + } + LX970A_ANAR => (LX970A_ANAR_RO_MASK, LX970A_ANAR_RW_MASK), + LX970A_MR => (LX970A_MR_RO_MASK, LX970A_MR_RW_MASK), + LX970A_IER => (LX970A_IER_RO_MASK, LX970A_IER_RW_MASK), + LX970A_CFGR => (LX970A_CFGR_RO_MASK, LX970A_CFGR_RW_MASK), + _ => { + // read-only register + (0xFFFF, 0x0000) + } + }; + + self.regs[reg] = (self.regs[reg] & ro_mask) | (value & rw_mask); + if update_regs { + self.update_regs(); + } + } +} diff --git a/rust/dynamips/src/phy/mod.rs b/rust/dynamips/src/phy/mod.rs new file mode 100644 index 000000000..940537077 --- /dev/null +++ b/rust/dynamips/src/phy/mod.rs @@ -0,0 +1,8 @@ +//! Physical layer stuff +//! +//! TODO MDIO/MII interface? +//! +//! # [PHY](https://en.wikipedia.org/wiki/Physical_layer): +//! * [Intel LXT970A](crate::phy::lxt970a) + +pub mod lxt970a; diff --git a/rust/rustfmt.toml b/rust/rustfmt.toml new file mode 100644 index 000000000..2a35f0230 --- /dev/null +++ b/rust/rustfmt.toml @@ -0,0 +1 @@ +use_small_heuristics = "Max" diff --git a/stable/CMakeLists.txt b/stable/CMakeLists.txt index c907da32c..0dfa87ede 100644 --- a/stable/CMakeLists.txt +++ b/stable/CMakeLists.txt @@ -233,7 +233,6 @@ set ( _files "${COMMON}/fs_fat.c" "${COMMON}/fs_mbr.c" "${COMMON}/fs_nvram.c" - "${COMMON}/dev_lxt970a.c" ) if ( ENABLE_LINUX_ETH ) set ( _files ${_files} "${COMMON}/linux_eth.c" ) diff --git a/unstable/CMakeLists.txt b/unstable/CMakeLists.txt index 76e7ba03d..e0b019614 100644 --- a/unstable/CMakeLists.txt +++ b/unstable/CMakeLists.txt @@ -188,7 +188,6 @@ set ( _files "${COMMON}/fs_fat.c" "${COMMON}/fs_mbr.c" "${COMMON}/fs_nvram.c" - "${COMMON}/dev_lxt970a.c" ) if ( ENABLE_LINUX_ETH ) set ( _files ${_files} "${COMMON}/linux_eth.c" ) From 94386cb9540b9517b908379f18da61ef58edc2fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=A1vio=20J=2E=20Saraiva?= Date: Tue, 9 Apr 2024 18:47:22 +0100 Subject: [PATCH 2/2] Rework Lxt970A. Do fake auto-negotiation and manual selection based on link partner information. Read/write registers according to the spec (RO, LL, LH). Set default values based on chip pins. --- common/dev_mpc860.c | 4 +- rust/Cargo.lock | 9 + rust/dynamips/Cargo.toml | 3 + rust/dynamips/src/c/dev_lxt907a.rs | 19 +- rust/dynamips/src/phy/lxt970a.rs | 1036 ++++++++++++++++------------ rust/rustfmt.toml | 1 + 6 files changed, 632 insertions(+), 440 deletions(-) diff --git a/common/dev_mpc860.c b/common/dev_mpc860.c index d203e5a8c..46252b52f 100644 --- a/common/dev_mpc860.c +++ b/common/dev_mpc860.c @@ -1584,7 +1584,7 @@ int mpc860_fec_set_nio(struct mpc860_data *d,netio_desc_t *nio) d->fec_nio = nio; netio_rxl_add(nio,(netio_rx_handler_t)mpc860_fec_handle_rx_pkt,d,NULL); - lxt970a_set_has_nio(d->fec_mii_phy, true); + lxt970a_set_link_partner(d->fec_mii_phy, true, LXT907A_AN_LP_ABILITY_ASSUMED); return(0); } @@ -1597,7 +1597,7 @@ int mpc860_fec_unset_nio(struct mpc860_data *d) if (d->fec_nio != NULL) { netio_rxl_remove(d->fec_nio); d->fec_nio = NULL; - lxt970a_set_has_nio(d->fec_mii_phy, false); + lxt970a_set_link_partner(d->fec_mii_phy, false, 0); } return(0); diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 11798812a..bc34dc25e 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -5,3 +5,12 @@ version = 3 [[package]] name = "rust-dynamips" version = "0.2.23" +dependencies = [ + "tock-registers", +] + +[[package]] +name = "tock-registers" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b9e2fdb3a1e862c0661768b7ed25390811df1947a8acbfbefe09b47078d93c4" diff --git a/rust/dynamips/Cargo.toml b/rust/dynamips/Cargo.toml index 80e6ec0cc..345f48013 100644 --- a/rust/dynamips/Cargo.toml +++ b/rust/dynamips/Cargo.toml @@ -8,3 +8,6 @@ rust-version = "1.57" # custom profiles need 1.57 [lib] crate-type = ["staticlib"] + +[dependencies] +tock-registers = "0.9.0" diff --git a/rust/dynamips/src/c/dev_lxt907a.rs b/rust/dynamips/src/c/dev_lxt907a.rs index 306fdacc9..8952c03bf 100644 --- a/rust/dynamips/src/c/dev_lxt907a.rs +++ b/rust/dynamips/src/c/dev_lxt907a.rs @@ -1,12 +1,13 @@ //! C interface for [`crate::phy::lxt970a::Lxt970A`]. use crate::c::prelude::*; -use crate::phy::lxt970a::Lxt970A; +use crate::phy::lxt970a::*; /// Allocate a new PHY. #[no_mangle] pub extern "C" fn lxt970a_new() -> *mut Lxt970A { - let phy = Box::new(Lxt970A::new()); + let mut phy = Box::new(Lxt970A::new()); + phy.update_regs(); Box::into_raw(phy) // memory managed by C } @@ -17,12 +18,16 @@ pub extern "C" fn lxt970a_drop(phy: *mut Lxt970A) { let _ = unsafe { Box::from_raw(phy.as_ptr()) }; // memory managed by rust } -/// Notify PHY if a nio is available. +/// Notify PHY about the partner link. #[no_mangle] -pub extern "C" fn lxt970a_set_has_nio(phy: *mut Lxt970A, has_nio: bool) { +pub extern "C" fn lxt970a_set_link_partner(phy: *mut Lxt970A, link_up: bool, an_lp_ability: u16) { let mut phy = NonNull::new(phy).unwrap(); let phy = unsafe { phy.as_mut() }; - phy.has_nio = has_nio; + if link_up { + phy.set_link_partner(Some(an_lp_ability)); + } else { + phy.set_link_partner(None); + } } /// Check if the link is up. @@ -39,7 +44,7 @@ pub extern "C" fn lxt970a_mii_read_access(phy: *mut Lxt970A, reg: c_uint) -> u16 let mut phy = NonNull::new(phy).unwrap(); let phy = unsafe { phy.as_mut() }; let reg = usize::try_from(reg).unwrap(); - phy.mii_read_access(reg) + phy.mii_read_access(reg).unwrap_or(0) } /// MII register write access. @@ -48,5 +53,5 @@ pub extern "C" fn lxt970a_mii_write_access(phy: *mut Lxt970A, reg: c_uint, value let mut phy = NonNull::new(phy).unwrap(); let phy = unsafe { phy.as_mut() }; let reg = usize::try_from(reg).unwrap(); - phy.mii_write_access(reg, value) + phy.mii_write_access(reg, value).unwrap_or(()) } diff --git a/rust/dynamips/src/phy/lxt970a.rs b/rust/dynamips/src/phy/lxt970a.rs index 94cfe577d..03788ebb4 100644 --- a/rust/dynamips/src/phy/lxt970a.rs +++ b/rust/dynamips/src/phy/lxt970a.rs @@ -1,482 +1,656 @@ //! 10/100 Mbps PHY //! -//! # References: +//! # References //! * [Intel LXT970A Dual-Speed Fast Ethernet Transceiver, January 2001](https://github.com/flaviojs/dynamips-datasheets/blob/master/ethernet/phy/LXT970A.pdf) //! * IEEE Std 802.3-2008, Section 2 +//! +//! # MISSING +//! * tests +//! * timings +//! * errors (jabber, parallel detection, manual selection) +//! * some register fields -/* -Abreviations: - RW=x - Read/Write with default value x - RO=x - Read Only with default value x - [xx] - default value determined by pins xx - SC - Self Clearing - LH - Latching High (remains High until read, and then returns to Low) - LL - Latching Low (remains Low until read, and then returns to High) - IGN - IGNored on certain conditions - RTOR - Related To Other Register - -Pin states used for the default values: - MF0 = VMF2 or VMF3 (Enabled) - MF1 = VMF1 or VMF4 (Disabled) - MF2 = VMF2 or VMF3 (Enabled) - MF3 = VMF2 or VMF3 (Enabled) - MF4 = VMF2 or VMF3 (Enabled) - CFG0 = High - CFG1 = High - TRSTE = Low - FDE = High - MDDIS = Low, RESET = High, PWERDWN = Low (2.4.1.2, MDIO Control) -*/ - -/* -Standard MII Registers -*/ - -/// Table 45. Control Register (Address 0) -pub const LX970A_CR: usize = 0x00; -/// Reset (RW=0,SC) -pub const LX970A_CR_RESET: u16 = 0x8000; -/// Loopback (RW=0) -pub const LX970A_CR_LOOP: u16 = 0x4000; -/// Speed Selection (RW=1(CFG0),IGN) -pub const LX970A_CR_SPEEDSELECT: u16 = 0x2000; -/// Auto-Negotiation Enable (RW=1(MF0)) -pub const LX970A_CR_ANENABLE: u16 = 0x1000; -/// Power Down (RW=0?) -pub const LX970A_CR_POWERDOWN: u16 = 0x0800; -/// Isolate (RW=0(TRSTE)) -pub const LX970A_CR_ISOLATE: u16 = 0x0400; -/// Restart Auto-Negotiation (RW=1(CFG0),SC) -pub const LX970A_CR_ANRESTART: u16 = 0x0200; -/// Duplex Mode (RW=1(FDE),IGN) -pub const LX970A_CR_DUPLEXMODE: u16 = 0x0100; -/// Collision Test (RW=0,IGN) -pub const LX970A_CR_COLLISIONTEST: u16 = 0x0080; -/// Transceiver Test Mode (RO=0) -pub const LX970A_CR_TTM: u16 = 0x0070; -/// Master-Slave Enable (RO=0) -pub const LX970A_CR_MSENABLE: u16 = 0x0008; -/// Master-Slave Value (RO=0) -pub const LX970A_CR_MSVALUE: u16 = 0x0004; -/// Reserved (RW=0) -pub const LX970A_CR_RESERVED: u16 = 0x0003; -pub const LX970A_CR_RO_MASK: u16 = 0x007C; -pub const LX970A_CR_RW_MASK: u16 = 0xFF83; -pub const LX970A_CR_DEFAULT: u16 = 0x3300; - -/// Table 46. Status Register (Address 1) -pub const LX970A_SR: usize = 0x01; -/// 100BASE-T4 (RO=0) -pub const LX970A_SR_100T4: u16 = 0x8000; -/// 100BASE-X full-duplex (RO=1) -pub const LX970A_SR_100TX_FD: u16 = 0x4000; -/// 100BASE-X hald-duplex (RO=1) -pub const LX970A_SR_100TX_HD: u16 = 0x2000; -/// 10 Mb/s full-duplex (RO=1) -pub const LX970A_SR_10T_FD: u16 = 0x1000; -/// 10 Mb/s half-duplex (RO=1) -pub const LX970A_SR_10T_HD: u16 = 0x0800; -/// 100BASE-T2 full-duplex (RO=0) -pub const LX970A_SR_100T2_FD: u16 = 0x0400; -/// 100BASE-T2 half-duplex (RO=0) -pub const LX970A_SR_100T2_HD: u16 = 0x0200; -/// Reserved (RO=0) -pub const LX970A_SR_RESERVED: u16 = 0x0100; -/// Master-Slave Configuration Fault (RO=0) -pub const LX970A_SR_MSCFGFAULT: u16 = 0x0080; -/// MF Preamble Suppression (RO=0) -pub const LX970A_SR_MFPS: u16 = 0x0040; -/// Auto-Neg. Complete (RO=0) -pub const LX970A_SR_ANCOMPLETE: u16 = 0x0020; -/// Remote Fault (RO=0,LH) -pub const LX970A_SR_REMOTEFAULT: u16 = 0x0010; -/// Auto-Neg. Ability (RO=1) -pub const LX970A_SR_ANABILITY: u16 = 0x0008; -/// Link Status (RO=0,LL) -pub const LX970A_SR_LINKSTATUS: u16 = 0x0004; -/// Jabber Detect (10BASE-T Only) (RO=0,LH) -pub const LX970A_SR_JABBERDETECT: u16 = 0x0002; -/// Extended Capability (RO=1) -pub const LX970A_SR_EXTCAPABILITY: u16 = 0x0001; -pub const LX970A_SR_RO_MASK: u16 = 0xFFFF; -pub const LX970A_SR_RW_MASK: u16 = 0x0000; -pub const LX970A_SR_DEFAULT: u16 = 0x7809; - -/* -PHY ID number: - Intel has OUI=00207Bh and ROUI=DE0400h (OUI with bits reversed) - (ROUI << 10) & FFFFFFFFh = 78100000h -*/ - -/// Table 47. PHY Identification Register 1 (Address 2) -pub const LX970A_PIR1: usize = 0x02; -/// PHY ID Number (RO=7810h) -pub const LX970A_PIR1_PIN: u16 = 0xFFFF; -pub const LX970A_PIR1_RO_MASK: u16 = 0xFFFF; -pub const LX970A_PIR1_RW_MASK: u16 = 0x0000; -pub const LX970A_PIR1_DEFAULT: u16 = 0x7810; - -/// Table 48. PHY Identification Register 2 (Address 3) -pub const LX970A_PIR2: usize = 0x03; -/// PHY ID number (RO=000000b) -pub const LX970A_PIR2_PIN: u16 = 0xFC00; -/// Manufacturer’s model number (RO=000000b) -pub const LX970A_PIR2_MANMODELNUM: u16 = 0x03F0; -/// Manufacturer’s revision number (RO=0011b) -pub const LX970A_PIR2_MANREVNUM: u16 = 0x000F; -pub const LX970A_PIR2_RO_MASK: u16 = 0xFFFF; -pub const LX970A_PIR2_RW_MASK: u16 = 0x0000; -pub const LX970A_PIR2_DEFAULT: u16 = 0x0003; - -/// Table 49. Auto Negotiation Advertisement Register (Address 4) -pub const LX970A_ANAR: usize = 0x04; -/// Next Page (RO=0) -pub const LX970A_ANAR_NEXTPAGE: u16 = 0x8000; -/// Reserved (RO=0) -pub const LX970A_ANAR_RESERVED_1: u16 = 0x4000; -/// Remote Fault (RW=0) -pub const LX970A_ANAR_REMOTEFAULT: u16 = 0x2000; -/// Reserved (RW=0) -pub const LX970A_ANAR_RESERVED_2: u16 = 0x1800; -/// Pause (RW=0) -pub const LX970A_ANAR_PAUSE: u16 = 0x0400; -/// 100BASE-T4 (RW=0) -pub const LX970A_ANAR_100T4: u16 = 0x0200; -/// 100BASE-TX (RW=1(FDE,MF4)) -pub const LX970A_ANAR_100TX_FD: u16 = 0x0100; -/// 100BASE-TX (RW=1(MF4)) -pub const LX970A_ANAR_100TX_HD: u16 = 0x0080; -/// 10BASE-T full-duplex (RW=1(FDE,CFG1)) -pub const LX970A_ANAR_10T_FD: u16 = 0x0040; -/// 10BASE-T (RW=1(CFG1)) -pub const LX970A_ANAR_10T_HD: u16 = 0x0020; -/// Selector Field, S<4:0> (RW=00001b) -pub const LX970A_ANAR_SF: u16 = 0x001F; -pub const LX970A_ANAR_RO_MASK: u16 = 0xC000; -pub const LX970A_ANAR_RW_MASK: u16 = 0x3FFF; -pub const LX970A_ANAR_DEFAULT: u16 = 0x01E1; -/* auxiliary */ -/// <00001> = IEEE 802.3 -pub const LX970A_ANAR_SF_IEEE8023: u16 = 0x0001; - -/// Table 50. Auto Negotiation Link Partner Ability Register (Address 5) -pub const LX970A_ANLPAR: usize = 0x05; -/// Next Page (RO) -pub const LX970A_ANLPAR_NEXTPAGE: u16 = 0x8000; -/// Acknowledge (RO) -pub const LX970A_ANLPAR_ACKNOWLEDGE: u16 = 0x4000; -/// Remote Fault (RO) -pub const LX970A_ANLPAR_REMOTEFAULT: u16 = 0x2000; -/// Reserved (RO) -pub const LX970A_ANLPAR_RESERVED: u16 = 0x1800; -/// Pause (RO) -pub const LX970A_ANLPAR_PAUSE: u16 = 0x0400; -/// 100BASE-T4 (RO) -pub const LX970A_ANLPAR_100T4: u16 = 0x0200; -/// 100BASE-TX full-duplex (RO) -pub const LX970A_ANLPAR_100TX_FD: u16 = 0x0100; -/// 100BASE-TX (RO) -pub const LX970A_ANLPAR_100TX_HD: u16 = 0x0080; -/// 10BASE-T full-duplex (RO) -pub const LX970A_ANLPAR_10T_FD: u16 = 0x0040; -/// 10BASE-T (RO) -pub const LX970A_ANLPAR_10T_HD: u16 = 0x0020; -/// Selector Field S(4:0) (RO) -pub const LX970A_ANLPAR_SF: u16 = 0x001F; -pub const LX970A_ANLPAR_RO_MASK: u16 = 0xFFFF; -pub const LX970A_ANLPAR_RW_MASK: u16 = 0x0000; -pub const LX970A_ANLPAR_DEFAULT: u16 = 0x0000; -/* auxiliary */ -/// <00001> = IEEE 802.3 -pub const LX970A_ANLPAR_SF_IEEE8023: u16 = 0x0001; - -/// Table 51. Auto Negotiation Expansion (Address 6) -pub const LX970A_ANE: usize = 0x06; -/// Reserved (RO=0) -pub const LX970A_ANE_RESERVED: u16 = 0xFFE0; -/// Parallel Detection Fault (RO=0,LH) -pub const LX970A_ANE_PDETECTFAULT: u16 = 0x0010; -/// Link Partner Next Page Able (RO=0) -pub const LX970A_ANE_LPNPA: u16 = 0x0008; -/// Next Page Able (RO=0) -pub const LX970A_ANE_NPA: u16 = 0x0004; -/// Page Received (RO=0,LH) -pub const LX970A_ANE_PR: u16 = 0x0002; -/// Link Partner Auto Neg Able (RO=0) -pub const LX970A_ANE_LPANA: u16 = 0x0001; -pub const LX970A_ANE_RO_MASK: u16 = 0xFFFF; -pub const LX970A_ANE_RW_MASK: u16 = 0x0000; -pub const LX970A_ANE_DEFAULT: u16 = 0x0000; - -/* -Vendor Specific MII Registers -*/ - -/// Table 52. Mirror Register (Address 16, Hex 10) -pub const LX970A_MR: usize = 0x10; -/// User Defined (RW=0) -pub const LX970A_MR_USERDEFINED: u16 = 0xFFFF; -pub const LX970A_MR_RO_MASK: u16 = 0x0000; -pub const LX970A_MR_RW_MASK: u16 = 0xFFFF; -pub const LX970A_MR_DEFAULT: u16 = 0x0000; - -/// Table 53. Interrupt Enable Register (Address 17, Hex 11) -pub const LX970A_IER: usize = 0x11; -/// Reserved (RO=0) -pub const LX970A_IER_RESERVED: u16 = 0xFFF0; -/// MIIDRVLVL (RW=0) -pub const LX970A_IER_MIIDRVLVL: u16 = 0x0008; -/// LNK CRITERIA (RW=0) -pub const LX970A_IER_LNK_CRITERIA: u16 = 0x0004; -/// INTEN (RW=0) -pub const LX970A_IER_INTEN: u16 = 0x0002; -/// TINT (RW=0,IGN) -pub const LX970A_IER_TINT: u16 = 0x0001; -pub const LX970A_IER_RO_MASK: u16 = 0xFFF0; -pub const LX970A_IER_RW_MASK: u16 = 0x000F; -pub const LX970A_IER_DEFAULT: u16 = 0x0000; - -/// Table 54. Interrupt Status Register (Address 18, Hex 12) -pub const LX970A_ISR: usize = 0x12; -/// MINT (RO=0?) -pub const LX970A_ISR_MINT: u16 = 0x8000; -/// XTALOK (RO=0) -pub const LX970A_ISR_XTALOK: u16 = 0x4000; -/// Reserved (RO=0) -pub const LX970A_ISR_RESERVED: u16 = 0x3FFF; -pub const LX970A_ISR_RO_MASK: u16 = 0xFFFF; -pub const LX970A_ISR_RW_MASK: u16 = 0x0000; -pub const LX970A_ISR_DEFAULT: u16 = 0x0000; - -/// Table 55. Configuration Register (Address 19, Hex 13) -pub const LX970A_CFGR: usize = 0x13; -/// Reserved (RO=0) -pub const LX970A_CFGR_RESERVED_1: u16 = 0x8000; -/// Txmit Test (100BASE-TX) (RW=0,RTOR) -pub const LX970A_CFGR_TXMITTEST: u16 = 0x4000; -/// Repeater Mode (RW=0(MF1)) -pub const LX970A_CFGR_REPEATERMODE: u16 = 0x2000; -/// MDIO_INT (RW=0,IGN) -pub const LX970A_CFGR_MDIOINT: u16 = 0x1000; -/// TP Loopback (10BASE-T) (RW=0) -pub const LX970A_CFGR_TPLOOPBACK: u16 = 0x0800; -/// SQE (10BASE-T) (RW=0) -pub const LX970A_CFGR_SQE: u16 = 0x0400; -/// Jabber (10BASE-T) (RW=0) -pub const LX970A_CFGR_JABBER: u16 = 0x0200; -/// Link Test (10BASE-T) (RW=0(CFG1,MF0)) -pub const LX970A_CFGR_LINKTEST: u16 = 0x0100; -/// LEDC Programming bits (RW=0) -pub const LX970A_CFGR_LEDC: u16 = 0x00C0; -/// Advance TX Clock (RW=0) -pub const LX970A_CFGR_ATXC: u16 = 0x0020; -/// 5B Symbol/(100BASE-X only) 4B Nibble (RW=1(MF2)) -pub const LX970A_CFGR_5BS_4BN: u16 = 0x0010; -/// Scrambler (100BASE-X only) (RW=1(MF3)) -pub const LX970A_CFGR_SCRAMBLER: u16 = 0x0008; -/// 100BASE-FX (RW=1(MF4,MF0)) -pub const LX970A_CFGR_100FX: u16 = 0x0004; -/// Reserved (RO=0) -pub const LX970A_CFGR_RESERVED_2: u16 = 0x0002; -/// Transmit Disconnect (RW=0) -pub const LX970A_CFGR_TD: u16 = 0x0001; -pub const LX970A_CFGR_RO_MASK: u16 = 0x8002; -pub const LX970A_CFGR_RW_MASK: u16 = 0x7FFD; -pub const LX970A_CFGR_DEFAULT: u16 = 0x0014; -/* auxiliary */ -/// 0 0 LEDC indicates collision -pub const LX970A_CFGR_LEDC_COLLISION: u16 = 0x0000; -/// 0 1 LEDC is off -pub const LX970A_CFGR_LEDC_OFF: u16 = 0x0040; -/// 1 0 LEDC indicates activity -pub const LX970A_CFGR_LEDC_ACTIVITY: u16 = 0x0080; -/// 1 1 LEDC is continuously on (for diagnostic use) -pub const LX970A_CFGR_LEDC_ALWAYSON: u16 = 0x00C0; +use std::fmt::Debug; +use tock_registers::interfaces::ReadWriteable; +use tock_registers::interfaces::Readable; +use tock_registers::interfaces::Writeable; +use tock_registers::register_bitfields; +use tock_registers::registers::InMemoryRegister; +use tock_registers::LocalRegisterCopy; +use tock_registers::RegisterLongName; -/// Table 56. Chip Status Register (Address 20, Hex 14) -pub const LX970A_CSR: usize = 0x14; -/// Reserved (RO=0?) -pub const LX970A_CSR_RESERVED_1: u16 = 0xC000; -/// Link (RO=0,RTOR) -pub const LX970A_CSR_LINK: u16 = 0x2000; -/// Duplex Mode (RO=1(FDE),RTOR) -pub const LX970A_CSR_DUPLEXMODE: u16 = 0x1000; -/// Speed (RO=1(CFG0),RTOR) -pub const LX970A_CSR_SPEED: u16 = 0x0800; -/// Reserved (RO=0?) -pub const LX970A_CSR_RESERVED_2: u16 = 0x0400; -/// Auto-Negotiation Complete (RO=0,LH,RTOR) -pub const LX970A_CSR_ANCOMPLETE: u16 = 0x0200; -/// Page Received (RO=0,LH,RTOR) -pub const LX970A_CSR_PAGERECEIVED: u16 = 0x0100; -/// Reserved (RO=0) -pub const LX970A_CSR_RESERVED_3: u16 = 0x00C0; -/// Reserved (RO=0?) -pub const LX970A_CSR_RESERVED_4: u16 = 0x0038; -/// Low-Voltage (RO=0?) -pub const LX970A_CSR_LOWVOLTAGE: u16 = 0x0004; -/// Reserved (RO=0?) -pub const LX970A_CSR_RESERVED_5: u16 = 0x0003; -pub const LX970A_CSR_RO_MASK: u16 = 0xFFFF; -pub const LX970A_CSR_RW_MASK: u16 = 0x0000; -pub const LX970A_CSR_DEFAULT: u16 = 0x1800; +/// Assume the link partner is a similar 10/100 Mbps PHY and ack. +pub const LXT907A_AN_LP_ABILITY_ASSUMED: u16 = 0b0100_0001_1110_0001; /// 10/100 Mbps PHY +#[derive(Debug)] pub struct Lxt970A { - pub regs: [u16; 32], - pub last_read_was_sr: bool, - /// temporary variable to preserve behavior - pub has_nio: bool, + pub regs: Regs, + pub pins: Pins, + pub last_read_was_status: bool, + pub link_partner: Option, } impl Default for Lxt970A { fn default() -> Self { - let mut x = Self { regs: [0; 32], last_read_was_sr: false, has_nio: false }; - x.set_defaults(); - x + Self::new_with_pins(Pins::default()) } } impl Lxt970A { + /// Creates a new PHY with default values. pub fn new() -> Self { Self::default() } + /// Creates a new PHY with values based on the pins. + pub fn new_with_pins(pins: Pins) -> Self { + Self { regs: Regs::new_with_pins(pins), pins, last_read_was_status: false, link_partner: None } + } + /// Set Link Partner (with an_lp_ability) + pub fn set_link_partner(&mut self, link_partner: Option) { + self.link_partner = link_partner; + self.update_regs(); + } /// Link status pub fn link_is_up(&self) -> bool { - self.has_nio && (self.regs[LX970A_CR] & LX970A_CR_POWERDOWN) == 0 + self.regs.control.matches_all(Control::POWER_DOWN::No) && self.regs.chip_status.matches_all(ChipStatus::LINK::Up) } - /// MII update registers + /// Update registers pub fn update_regs(&mut self) { - if self.link_is_up() { - // link up, LX970A_SR_LINKSTATUS is latch down - self.regs[LX970A_CSR] |= LX970A_CSR_LINK; - if (self.regs[LX970A_CR] & LX970A_CR_ANENABLE) == 0 { - // manual selection - if (self.regs[LX970A_CR] & LX970A_CR_SPEEDSELECT) != 0 { - // 100Mbps - self.regs[LX970A_CSR] |= LX970A_CSR_SPEED; + if self.regs.control.matches_all(Control::RESET::Yes) { + // reset + self.regs = Regs::new_with_pins(self.pins); // SC + debug_assert!(self.regs.control.matches_all(Control::RESET::No)); + } + if self.regs.control.matches_all(Control::AN_ENABLE::Yes) { + if self.regs.control.matches_all(Control::AN_RESTART::Yes) { + // restart auto negotiation + self.regs.status.modify(Status::AN_COMPLETE::No); + self.regs.chip_status.modify(ChipStatus::LINK::Down); + self.regs.control.modify(Control::AN_RESTART::No); // SC + } + if self.link_partner.is_some() && self.regs.chip_status.matches_all(ChipStatus::LINK::Down) { + // do auto negotiation + self.regs.an_lp_ability.set(self.link_partner.unwrap()); + //TODO self.regs.an_expansion.modify(AnExpansion::PD_FAULT::Yes); // LH + self.regs.an_expansion.modify(AnExpansion::PAGE_RECEIVED::Yes); // LH + self.regs.chip_status.modify(ChipStatus::PAGE_RECEIVED::Yes); // LH + let mut remote_fault = false; + if self.regs.an_lp_ability.matches_all(AnLpAbility::REMOTE_FAULT::Yes) || !self.regs.an_lp_ability.matches_all(AnLpAbility::SF::Ieee802Dot3) { + remote_fault = true; + } else { + let mut overlap = self.regs.an_advertise.extract(); + overlap.set(overlap.get() & self.regs.an_lp_ability.get()); + if overlap.matches_all(AnAdvertise::ALLOW_100TX_FD::Yes) { + self.regs.chip_status.modify(ChipStatus::SPEED::Speed100Mbps); + self.regs.chip_status.modify(ChipStatus::DUPLEX::FullDuplex); + } else if overlap.matches_all(AnAdvertise::ALLOW_100TX_HD::Yes) { + self.regs.chip_status.modify(ChipStatus::SPEED::Speed100Mbps); + self.regs.chip_status.modify(ChipStatus::DUPLEX::HalfDuplex); + } else if overlap.matches_all(AnAdvertise::ALLOW_10T_FD::Yes) { + self.regs.chip_status.modify(ChipStatus::SPEED::Speed10Mbps); + self.regs.chip_status.modify(ChipStatus::DUPLEX::FullDuplex); + } else if overlap.matches_all(AnAdvertise::ALLOW_10T_HD::Yes) { + self.regs.chip_status.modify(ChipStatus::SPEED::Speed10Mbps); + self.regs.chip_status.modify(ChipStatus::DUPLEX::HalfDuplex); + } else { + remote_fault = true; + } + } + if remote_fault { + self.regs.status.modify(Status::REMOTE_FAULT::Yes); // LH } else { - // 10 Mbps - self.regs[LX970A_CSR] &= !LX970A_CSR_SPEED; + // auto negotiation complete + self.regs.status.modify(Status::AN_COMPLETE::Yes); + self.regs.chip_status.modify(ChipStatus::LINK::Up); } - if (self.regs[LX970A_CR] & LX970A_CR_DUPLEXMODE) != 0 { - // full duplex - self.regs[LX970A_CSR] |= LX970A_CSR_DUPLEXMODE; + } + } else if self.link_partner.is_some() { + // do manual selection + let link_partner = LocalRegisterCopy::::new(self.link_partner.unwrap()); + let mut fault = false; + let allow_100tx_fd = link_partner.matches_all(AnLpAbility::ALLOW_100TX_FD::Yes); + let allow_100tx_hd = link_partner.matches_all(AnLpAbility::ALLOW_100TX_HD::Yes); + if (allow_100tx_fd || allow_100tx_hd) && self.regs.control.matches_all(Control::SPEED::Speed100Mbps) { + self.regs.chip_status.modify(ChipStatus::SPEED::Speed100Mbps); + if allow_100tx_fd && self.regs.control.matches_all(Control::DUPLEX::FullDuplex) { + self.regs.chip_status.modify(ChipStatus::DUPLEX::FullDuplex); } else { - // half duplex - self.regs[LX970A_CSR] &= !LX970A_CSR_DUPLEXMODE; + self.regs.chip_status.modify(ChipStatus::DUPLEX::HalfDuplex); } } else { - // auto-negotiation, assume partner is standard 10/100 eth - self.regs[LX970A_ANLPAR] = LX970A_ANLPAR_ACKNOWLEDGE - | LX970A_ANLPAR_100TX_FD - | LX970A_ANLPAR_100TX_HD - | LX970A_ANLPAR_10T_FD - | LX970A_ANLPAR_10T_HD; - if (self.regs[LX970A_ANAR] & LX970A_ANAR_100TX_FD) != 0 { - // 100Mbps full duplex - self.regs[LX970A_CSR] |= LX970A_CSR_DUPLEXMODE | LX970A_CSR_SPEED; - } else if (self.regs[LX970A_ANAR] & LX970A_ANAR_100TX_HD) != 0 { - // 100Mbps half duplex - self.regs[LX970A_CSR] = - (self.regs[LX970A_CSR] & !LX970A_CSR_DUPLEXMODE) | LX970A_CSR_SPEED; - } else if (self.regs[LX970A_ANAR] & LX970A_ANAR_10T_FD) != 0 { - // 10Mbps full duplex - self.regs[LX970A_CSR] = - LX970A_CSR_DUPLEXMODE | (self.regs[LX970A_CSR] & !LX970A_CSR_SPEED); + self.regs.chip_status.modify(ChipStatus::SPEED::Speed10Mbps); + let allow_10t_fd = link_partner.matches_all(AnLpAbility::ALLOW_10T_FD::Yes); + let allow_10t_hd = link_partner.matches_all(AnLpAbility::ALLOW_10T_HD::Yes); + if allow_10t_fd && self.regs.control.matches_all(Control::DUPLEX::FullDuplex) { + self.regs.chip_status.modify(ChipStatus::DUPLEX::FullDuplex); + } else if allow_10t_hd { + self.regs.chip_status.modify(ChipStatus::DUPLEX::HalfDuplex); } else { - // 10Mbps half duplex - self.regs[LX970A_ANAR] |= LX970A_ANAR_10T_HD; - self.regs[LX970A_CSR] &= !(LX970A_CSR_DUPLEXMODE | LX970A_CSR_SPEED); + fault = true; } - self.regs[LX970A_CR] &= !(LX970A_CR_ANRESTART); - self.regs[LX970A_SR] |= LX970A_SR_ANCOMPLETE; - self.regs[LX970A_CSR] |= LX970A_CSR_ANCOMPLETE; + } + if fault { + //TODO how do I signal an error? + self.regs.chip_status.matches_all(ChipStatus::LINK::Down); + } else { + self.regs.chip_status.matches_all(ChipStatus::LINK::Up); } } else { - // link down or administratively down - self.regs[LX970A_SR] &= !(LX970A_SR_ANCOMPLETE | LX970A_SR_LINKSTATUS); - self.regs[LX970A_CSR] &= !(LX970A_CSR_LINK - | LX970A_CSR_DUPLEXMODE - | LX970A_CSR_SPEED - | LX970A_CSR_ANCOMPLETE); + self.regs.chip_status.matches_all(ChipStatus::LINK::Down); + } + // latches + if self.regs.chip_status.matches_all(ChipStatus::LINK::Down) { + self.regs.status.modify(Status::LINK::Down); // LL } + //TODO self.regs.status.modify(Status::JABBER_DETECTED::Yes); // LH + if self.regs.status.matches_all(Status::AN_COMPLETE::Yes) { + self.regs.chip_status.modify(ChipStatus::AN_COMPLETE::Yes); // LH + } + // chip is powered up and stable + self.regs.int_status.modify(IntStatus::XTAL::Stable); } - /// MII register defaults + /// Set register defaults. pub fn set_defaults(&mut self) { - // default is 100Mb/s full duplex and auto-negotiation - self.regs = [0; 32]; - self.regs[LX970A_CR] = LX970A_CR_DEFAULT; - self.regs[LX970A_SR] = LX970A_SR_DEFAULT; - self.regs[LX970A_PIR1] = LX970A_PIR1_DEFAULT; - self.regs[LX970A_PIR2] = LX970A_PIR2_DEFAULT; - self.regs[LX970A_ANAR] = LX970A_ANAR_DEFAULT; - self.regs[LX970A_ANE] = LX970A_ANE_DEFAULT; - self.regs[LX970A_MR] = LX970A_MR_DEFAULT; - self.regs[LX970A_IER] = LX970A_IER_DEFAULT; - self.regs[LX970A_ISR] = LX970A_ISR_DEFAULT; - self.regs[LX970A_CFGR] = LX970A_CFGR_DEFAULT; - self.regs[LX970A_CSR] = LX970A_CSR_DEFAULT; - - // chip is powered up and stable - self.regs[LX970A_ISR] = LX970A_ISR_XTALOK; - + self.regs = Regs::new_with_pins(self.pins); self.update_regs(); } - /// MII register read access - pub fn mii_read_access(&mut self, reg: usize) -> u16 { - let value = self.regs[reg]; - - // update bits - match reg { - LX970A_SR => { - // Latch Low - if self.link_is_up() { - self.regs[reg] &= LX970A_SR_LINKSTATUS; - } + pub fn mii_read_access(&mut self, idx: usize) -> Option { + if self.regs.control.matches_all(Control::ISOLATE::Yes) { + return None; + } + let value = match idx { + Regs::IDX_CONTROL => self.regs.control.get(), + Regs::IDX_STATUS => self.regs.status.get(), + Regs::IDX_ID1 => self.regs.id1.get(), + Regs::IDX_ID2 => self.regs.id2.get(), + Regs::IDX_AN_ADVERTISE => self.regs.an_advertise.get(), + Regs::IDX_AN_LP_ABILITY => self.regs.an_lp_ability.get(), + Regs::IDX_AN_EXPANSION => self.regs.an_expansion.get(), + Regs::IDX_MIRROR => self.regs.mirror.get(), + Regs::IDX_INT_ENABLE => self.regs.int_enable.get(), + Regs::IDX_INT_STATUS => self.regs.int_status.get(), + Regs::IDX_CONFIG => self.regs.config.get(), + Regs::IDX_CHIP_STATUS => self.regs.chip_status.get(), + _ => 0, + }; + match idx { + Regs::IDX_STATUS => { + let mut reg = self.regs.status.extract(); + reg.modify(Status::REMOTE_FAULT::No); // LH + reg.modify(Status::LINK::Up); // LL + reg.modify(Status::JABBER_DETECTED::No); // LH + self.regs.status.set(reg.get()); } - LX970A_ISR => { - if self.last_read_was_sr { - self.regs[reg] &= !LX970A_ISR_MINT; + Regs::IDX_AN_EXPANSION => { + let mut reg = self.regs.an_expansion.extract(); + reg.modify(AnExpansion::PD_FAULT::No); // LH + reg.modify(AnExpansion::PAGE_RECEIVED::No); // LH + self.regs.an_expansion.set(reg.get()); + } + Regs::IDX_INT_STATUS => { + if self.last_read_was_status { + self.regs.int_status.modify(IntStatus::MII_INT::No); // LH+1 } } - _ => { - /* XXX Latch High: - LX970A_SR_REMOTEFAULT, LX970A_SR_JABBERDETECT - LX970A_ANE_PDETECTFAULT, LX970A_ANE_PR, - LX970A_CSR_ANC, LX970A_CSR_PAGERECEIVED */ + Regs::IDX_CHIP_STATUS => { + let mut reg = self.regs.chip_status.extract(); + reg.modify(ChipStatus::AN_COMPLETE::No); // LH + reg.modify(ChipStatus::PAGE_RECEIVED::No); // LH + self.regs.chip_status.set(reg.get()); } + _ => {} } - - self.last_read_was_sr = reg == LX970A_SR; - value + self.last_read_was_status = idx == Regs::IDX_STATUS; + self.update_regs(); + Some(value) } /// MII register write access - pub fn mii_write_access(&mut self, reg: usize, value: u16) { - let mut update_regs = false; - let (ro_mask, rw_mask) = match reg { - LX970A_CR => { - // reset, self clearing - if (value & LX970A_CR_RESET) != 0 { - self.set_defaults(); - return; + pub fn mii_write_access(&mut self, idx: usize, value: u16) -> Option<()> { + if self.regs.control.matches_all(Control::ISOLATE::Yes) { + // TODO how are you supposed to clear this bit if you can't write? + return None; + } + fn update(reg: &mut InMemoryRegister, rw_mask: u16, value: u16) { + reg.set((reg.get() & !rw_mask) | (value & rw_mask)); + } + match idx { + Regs::IDX_CONTROL => update(&mut self.regs.control, Regs::RW_CONTROL, value), + Regs::IDX_AN_ADVERTISE => update(&mut self.regs.an_advertise, Regs::RW_AN_ADVERTISE, value), + Regs::IDX_MIRROR => update(&mut self.regs.mirror, Regs::RW_MIRROR, value), + Regs::IDX_INT_ENABLE => update(&mut self.regs.int_enable, Regs::RW_INT_ENABLE, value), + Regs::IDX_CONFIG => update(&mut self.regs.config, Regs::RW_CONFIG, value), + _ => {} + }; + self.update_regs(); + Some(()) + } +} + +/// Pins that affect the chip. +#[derive(Debug, Copy, Clone)] +pub struct Pins { + pub mf0: bool, + pub mf1: bool, + pub mf2: bool, + pub mf3: bool, + pub mf4: bool, + pub cfg0: bool, + pub cfg1: bool, + pub fde: bool, + pub trste: bool, +} +impl Default for Pins { + fn default() -> Self { + Self { + mf0: true, // Auto Negotiate + mf1: false, // DTE Mode + mf2: true, // 5B Symbol + mf3: true, // Bypass Scrambler + mf4: true, // 100 Mbps Capability + cfg0: true, // Auto Negotiate Restart + cfg1: true, // 10 Mbps Capability + fde: true, // Full Duplex + trste: false, // Do Not Isolate + } + } +} +impl Pins { + pub fn new() -> Self { + Self::default() + } +} + +/// In-memory registers. +pub struct Regs { + pub control: InMemoryRegister, + pub status: InMemoryRegister, + pub id1: InMemoryRegister, + pub id2: InMemoryRegister, + pub an_advertise: InMemoryRegister, + pub an_lp_ability: InMemoryRegister, + pub an_expansion: InMemoryRegister, + pub mirror: InMemoryRegister, + pub int_enable: InMemoryRegister, + pub int_status: InMemoryRegister, + pub config: InMemoryRegister, + pub chip_status: InMemoryRegister, +} +impl Regs { + pub const IDX_CONTROL: usize = 0; + pub const IDX_STATUS: usize = 1; + pub const IDX_ID1: usize = 2; + pub const IDX_ID2: usize = 3; + pub const IDX_AN_ADVERTISE: usize = 4; + pub const IDX_AN_LP_ABILITY: usize = 5; + pub const IDX_AN_EXPANSION: usize = 6; + pub const IDX_MIRROR: usize = 16; + pub const IDX_INT_ENABLE: usize = 17; + pub const IDX_INT_STATUS: usize = 18; + pub const IDX_CONFIG: usize = 19; + pub const IDX_CHIP_STATUS: usize = 20; + pub const RW_CONTROL: u16 = 0b1111_1111_1000_0011; + pub const RW_AN_ADVERTISE: u16 = 0b0011_1111_1111_1111; + pub const RW_MIRROR: u16 = 0b1111_1111_1111_1111; + pub const RW_INT_ENABLE: u16 = 0b0000_0000_0000_1111; + pub const RW_CONFIG: u16 = 0b1111_1111_1111_1111; + /// Create registers with default values. + pub fn new() -> Regs { + Regs::default() + } + /// Create registers with values based on the pins. + pub fn new_with_pins(pins: Pins) -> Regs { + let regs = Regs::default(); + regs.control.set({ + let mut reg = regs.control.extract(); + if pins.mf0 { + reg.modify(Control::AN_ENABLE::Yes); + if pins.cfg0 { + reg.modify(Control::AN_RESTART::Yes); + } + } else { + if pins.cfg0 { + reg.modify(Control::SPEED::Speed100Mbps); + } + if pins.fde { + reg.modify(Control::DUPLEX::FullDuplex); } - update_regs = true; - (LX970A_CR_RO_MASK, LX970A_CR_RW_MASK) } - LX970A_ANAR => (LX970A_ANAR_RO_MASK, LX970A_ANAR_RW_MASK), - LX970A_MR => (LX970A_MR_RO_MASK, LX970A_MR_RW_MASK), - LX970A_IER => (LX970A_IER_RO_MASK, LX970A_IER_RW_MASK), - LX970A_CFGR => (LX970A_CFGR_RO_MASK, LX970A_CFGR_RW_MASK), - _ => { - // read-only register - (0xFFFF, 0x0000) + if pins.trste { + reg.modify(Control::ISOLATE::Yes); } - }; - - self.regs[reg] = (self.regs[reg] & ro_mask) | (value & rw_mask); - if update_regs { - self.update_regs(); + reg.into() + }); + regs.an_advertise.set({ + let mut reg = regs.an_advertise.extract(); + if pins.mf4 { + reg.modify(AnAdvertise::ALLOW_100TX_HD::Yes); + if pins.fde { + reg.modify(AnAdvertise::ALLOW_100TX_FD::Yes); + } + } + if pins.cfg1 { + reg.modify(AnAdvertise::ALLOW_10T_HD::Yes); + if pins.fde { + reg.modify(AnAdvertise::ALLOW_10T_FD::Yes); + } + } + reg.into() + }); + regs.config.set({ + let mut reg = regs.config.extract(); + if !pins.mf0 { + if pins.cfg1 { + reg.modify(Config::LINK_TEST::No); + } + if pins.mf4 { + reg.modify(Config::CABLE_100FX::Fiber); + } + } + if pins.mf1 { + reg.modify(Config::MODE::Repeater); + } + if pins.mf2 { + reg.modify(Config::CODER::Symbol5b); + } + if pins.mf3 { + reg.modify(Config::SCRAMBLER::Bypass); + } + reg.into() + }); + regs + } +} +impl Default for Regs { + fn default() -> Regs { + Regs { + control: InMemoryRegister::new(0), + status: InMemoryRegister::new(0b0111_1000_0000_1001), + id1: InMemoryRegister::new(0x7810), + id2: InMemoryRegister::new(0b000000_000000_0001), + an_advertise: InMemoryRegister::new(0b00_0_00_000000_00001), + an_lp_ability: InMemoryRegister::new(0), + an_expansion: InMemoryRegister::new(0), + mirror: InMemoryRegister::new(0), + int_enable: InMemoryRegister::new(0), + int_status: InMemoryRegister::new(0), + config: InMemoryRegister::new(0), + chip_status: InMemoryRegister::new(0), } } } +impl Debug for Regs { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + fmt.debug_struct("Regs") + .field("control", &format_args!("0x{:04x}", self.control.get())) + .field("status", &format_args!("0x{:04x}", self.status.get())) + .field("id1", &format_args!("0x{:04x}", self.id1.get())) + .field("id2", &format_args!("0x{:04x}", self.id2.get())) + .field("an_advertise", &format_args!("0x{:04x}", self.an_advertise.get())) + .field("an_lp_ability", &format_args!("0x{:04x}", self.an_lp_ability.get())) + .field("an_expansion", &format_args!("0x{:04x}", self.an_expansion.get())) + .field("mirror", &format_args!("0x{:04x}", self.mirror.get())) + .field("ier", &format_args!("0x{:04x}", self.int_enable.get())) + .field("isr", &format_args!("0x{:04x}", self.int_status.get())) + .field("config", &format_args!("0x{:04x}", self.config.get())) + .field("chip_status", &format_args!("0x{:04x}", self.chip_status.get())) + .finish() + } +} + +/* +Abreviations: + RW=x - Read/Write with default value x + RO=x - Read Only with default value x + SC - Self Clearing + LH - Latching High (remains High until read, and then returns to Low) + LL - Latching Low (remains Low until read, and then returns to High) +*/ + +register_bitfields! [ + u16, + + /* + Standard MII Registers + */ + + /// Table 45. Control Register (Address 0) + Control [ + /// 0.15 Reset, 1=Yes, 0=No (RW=0,SC) + RESET OFFSET(15) NUMBITS(1) [Yes = 1, No = 0], + /// 0.14 Loopback, 1=Enable, 0=Disable (RW=0) + LOOP OFFSET(14) NUMBITS(1) [], + /// 0.13 Speed Selection, 1=100 Mbps, 0=10 Mbps (RW=?/CFG0&!MF0) + SPEED OFFSET(13) NUMBITS(1) [Speed100Mbps = 1, Speed10Mbps = 0], + /// 0.12 Auto Negotiation, 1=Enable, 0=Disable (RW=MF0) + AN_ENABLE OFFSET(12) NUMBITS(1) [Yes = 1, No = 0], + /// 0.11 Power Down, 1=Yes, 0=No (RW=0) + /// When leaving Power Down, you must wait 500 ns minimum before you can write to registers. + POWER_DOWN OFFSET(11) NUMBITS(1) [Yes = 1, No = 0], + /// 0.10 Electrically Isolate from MII, 1=Enable, 0=Normal (RW=TRSTE) + ISOLATE OFFSET(10) NUMBITS(1) [Yes = 1, No = 0], + /// 0.9 Restart Auto Negotiation, 1=Enable, 0=Normal (RW=0/CFG0&MF0,SC) + AN_RESTART OFFSET(9) NUMBITS(1) [Yes = 1, No = 0], + /// 0.8 Duplex Mode, 1=Full Duplex, 0=Half DUplex (RW=0/FDE&!MF0) + DUPLEX OFFSET(8) NUMBITS(1) [FullDuplex = 1, HalfDuplex = 0], + /// 0.7 Collision Test, 1=Enable COL signal test (with loopback), 0=Disable (RW=0) + COLLISION_TEST OFFSET(7) NUMBITS(1) [], + /// 0.6:4 Transceiver Test Mode, 0=Not Supported (RO=0) + TTM OFFSET(4) NUMBITS(3) [], + /// 0.3 Master-Slave Enable, 0=Not Supported (RO=0) + MS_ENABLE OFFSET(3) NUMBITS(1) [], + /// 0.2 Master-Slave Value, 0=Not Supported (RO=0) + MS_VALUE OFFSET(2) NUMBITS(1) [], + /// 0.1:0 Reserved (RW=0) + RESERVED OFFSET(0) NUMBITS(2) [], + ], + /// Table 46. Status Register (Address 1) + Status [ + /// 1.15 100BASE-T4, 0=Not Supported (RO=0) + ABLE_100T4 OFFSET(15) NUMBITS(1) [], + /// 1.14 100BASE-X Full-Duplex, 1=Supported (RO=1) + ABLE_100X_FD OFFSET(14) NUMBITS(1) [], + /// 1.13 100BASE-X Half-Duplex, 1=Supported (RO=1) + ABLE_100X_HD OFFSET(13) NUMBITS(1) [], + /// 1.12 10 Mbps Full-Duplex, 1=Supported (RO=1) + ABLE_10_FD OFFSET(12) NUMBITS(1) [], + /// 1.11 10 Mbps Half-Duplex, 1=Supported (RO=1) + ABLE_10_HD OFFSET(11) NUMBITS(1) [], + /// 1.10 100BASE-T2 Full-Duplex, 0=Not Supported (RO=0) + ABLE_100T2_FD OFFSET(10) NUMBITS(1) [], + /// 1.9 100BASE-T2 Half-Duplex, 0=Not Supported (RO=0) + ABLE_100T2_HD OFFSET(9) NUMBITS(1) [], + /// 1.8 Reserved (RO=0) + RESERVED OFFSET(8) NUMBITS(1) [], + /// 1.7 Master-Slave Configuration Fault, 0=Not Supported (RO=0) + MS_CFG_FAULT OFFSET(7) NUMBITS(1) [], + /// 1.6 MF Preamble Suppression, 0=Not Supported (RO=0) + MF_PS OFFSET(6) NUMBITS(1) [], + /// 1.5 Auto Negotiation Complete, 1=Complete, 0=Not Complete (RO=0) + AN_COMPLETE OFFSET(5) NUMBITS(1) [Yes = 1, No = 0], + /// 1.4 Remote Fault in Link Partner, 1=Yes, 0=No (RO=0,LH) + REMOTE_FAULT OFFSET(4) NUMBITS(1) [Yes = 1, No = 0], + /// 1.3 Auto Negotiation Ability, 1=Supported (RO=1) + AN_ABILITY OFFSET(3) NUMBITS(1) [], + /// 1.2 Link Status, 1=Up, 0=Down (RO=0,LL) + LINK OFFSET(2) NUMBITS(1) [Up = 1, Down = 0], + /// 1.1 Jabber Detected (10BASE-T Only), 1=Yes, 0=No (RO=0,LH) + JABBER_DETECTED OFFSET(1) NUMBITS(1) [Yes = 1, No = 0], + /// 1.0 Extended Capability, 1=Extended (RO=1) + EXT_CAPABILITY OFFSET(1) NUMBITS(1) [], + ], + + /* + PHY ID number: + Intel has OUI=00207Bh and ROUI=DE0400h (OUI with bits reversed) + (ROUI << 10) & FFFFFFFFh = 78100000h + */ + + /// Table 47. PHY Identification Register 1 (Address 2) + Id1 [ + /// 2.15:0 PHY ID Number (RO=0x7810) + ID OFFSET(0) NUMBITS(16) [], + ], + /// Table 48. PHY Identification Register 2 (Address 3) + Id2 [ + /// 3.15:10 PHY ID number (RO=0b000000) + ID OFFSET(10) NUMBITS(6) [], + /// 3.9:4 Manufacturer’s model number (RO=0b000000) + MODEL OFFSET(4) NUMBITS(6) [], + /// 3.3:0 Manufacturer’s revision number (RO=0b0011) + REV OFFSET(0) NUMBITS(4) [], + ], + /// Table 49. Auto Negotiation Advertisement Register (Address 4) + AnAdvertise [ + /// 4.15 Next Page, 0=Not Supported (RO=0) + NEXT_PAGE OFFSET(15) NUMBITS(1) [], + /// 4.14 Reserved (RO=0) + RESERVED_1 OFFSET(14) NUMBITS(1) [], + /// 4.13 Remote Fault, 1=Yes, 0=No (RW=0) + REMOTE_FAULT OFFSET(13) NUMBITS(1) [Yes = 1, No = 0], + /// 4.12:11 Reserved (RW=0) + RESERVED_2 OFFSET(11) NUMBITS(2) [], + /// 4.10 Allow Pause for Full-Duplex, 1=Yes, 0=No (RW=0) + ALLOW_PAUSE_FD OFFSET(10) NUMBITS(1) [Yes = 1, No = 0], + /// 4.9 Allow 100BASE-T4, 1=Yes, 0=No (RW=0) + ALLOW_100T4 OFFSET(9) NUMBITS(1) [Yes = 1, No = 0], + /// 4.8 Allow 100BASE-TX 1=Yes, 0=No (RW=FDE&MF4) + ALLOW_100TX_FD OFFSET(8) NUMBITS(1) [Yes = 1, No = 0], + /// 4.7 Allow 100BASE-TX 1=Yes, 0=No (RW=MF4) + ALLOW_100TX_HD OFFSET(7) NUMBITS(1) [Yes = 1, No = 0], + /// 4.6 Allow 10BASE-T full-duplex (RW=FDE&CFG1) + ALLOW_10T_FD OFFSET(6) NUMBITS(1) [Yes = 1, No = 0], + /// 4.5 Allow 10BASE-T (RW=CFG1) + ALLOW_10T_HD OFFSET(5) NUMBITS(1) [Yes = 1, No = 0], + /// 4.4:0 Selector Field, 0b00001=IEEE 802.3, 0b00010=IEEE 802.9 ISLAN-16T, 0b00000=Reserved, 0b11111=Reserved (RW=0b00001) + SF OFFSET(0) NUMBITS(5) [Ieee802Dot3 = 0b00001], + ], + /// Table 50. Auto Negotiation Link Partner Ability Register (Address 5) + AnLpAbility [ + /// 5.15 Next Page (RO) + NEXT_PAGE OFFSET(15) NUMBITS(1) [], + /// 5.14 Acknowledge (RO) + ACK OFFSET(14) NUMBITS(1) [], + /// 5.13 Remote Fault (RO) + REMOTE_FAULT OFFSET(13) NUMBITS(1) [Yes = 1, No = 0], + /// 5.12:11 Reserved (RO) + RESERVED OFFSET(11) NUMBITS(2) [], + /// 5.10 Allow Pause for Full-Duplex (RO) + ALLOW_PAUSE_FD OFFSET(12) NUMBITS(1) [Yes = 1, No = 0], + /// 5.9 Allow 100BASE-T4 (RO) + ALLOW_100T4 OFFSET(9) NUMBITS(1) [Yes = 1, No = 0], + /// 5.8 Allow 100BASE-TX Full-Duplex (RO) + ALLOW_100TX_FD OFFSET(8) NUMBITS(1) [Yes = 1, No = 0], + /// 5.7 Allow 100BASE-TX Half-Duplex (RO) + ALLOW_100TX_HD OFFSET(7) NUMBITS(1) [Yes = 1, No = 0], + /// 5.6 Allow 10BASE-T Full-Duplex (RO) + ALLOW_10T_FD OFFSET(6) NUMBITS(1) [Yes = 1, No = 0], + /// 5.5 10 Allow BASE-T Half-Duplex (RO) + ALLOW_10T_HD OFFSET(5) NUMBITS(1) [Yes = 1, No = 0], + /// 5.4:0 Selector Field (RO) + SF OFFSET(0) NUMBITS(5) [Ieee802Dot3 = 0b0001], + ], + /// Table 51. Auto Negotiation Expansion (Address 6) + AnExpansion [ + /// 6.15:5 Reserved (RO=0) + RESERVED OFFSET(5) NUMBITS(11) [], + /// 6.4 Parallel Detection Fault, 1=Yes, 0=No (RO=0,LH) + PD_FAULT OFFSET(4) NUMBITS(1) [Yes = 1, No = 0], + /// 6.3 Link Partner Next Page Able, 1=Capable, 0=Incapable (RO=0) + LP_NPA OFFSET(3) NUMBITS(1) [], + /// 6.2 Next Page Able, 0=Not Supported (RO=0) + NPA OFFSET(2) NUMBITS(1) [], + /// 6.1 Page Received (3 consecutive identical), 1=Yes, 0=No (RO=0,LH) + PAGE_RECEIVED OFFSET(1) NUMBITS(1) [Yes = 1, No = 0], + /// 6.0 Link Partner Auto Negotiation Able, 1=Capable, 0=Incapable (RO=0) + LP_ANA OFFSET(0) NUMBITS(1) [], + ], + + /* + Vendor Specific MII Registers + */ + + /// Table 52. Mirror Register (Address 16, Hex 10) + Mirror [ + /// 16.15:0 User Defined (RW=0) + USER_DEFINED OFFSET(0) NUMBITS(16) [], + ], + /// Table 53. Interrupt Enable Register (Address 17, Hex 11) + IntEnable [ + /// 17.15:4 Reserved (RO=0) + RESERVED OFFSET(4) NUMBITS(12) [], + /// 17.3 MII Driver Levels, 1=Reduced, 0=High Strength (RW=0) + MII_DRV_LVL OFFSET(3) NUMBITS(1) [Reduced = 1, HighStrength = 0], + /// 17.2 Link Criteria, 1=Enhanced, 0=Standard (RW=0) + LNK_CRITERIA OFFSET(2) NUMBITS(1) [Enhanced = 1, Standard = 0], + /// 17.1 Enable Interrupts, 1=Enable, 0=Disable (RW=0) + INT_ENABLE OFFSET(1) NUMBITS(1) [], + /// 17.0 Trigger Interrupt, 1=Force, 0=Normal (RW=0) + INT_TRIGGER OFFSET(0) NUMBITS(1) [], + ], + /// Table 54. Interrupt Status Register (Address 18, Hex 12) + IntStatus [ + /// 18.15 MII Interrupt Pending, 1=Yes, 0=No (RO=0,LH+1) + MII_INT OFFSET(15) NUMBITS(1) [Yes = 1, No = 0], + /// 18.14 XTAL OK, 1=Stable, 0=Unstable (RO=0) + XTAL OFFSET(14) NUMBITS(1) [Stable = 1, Unstable = 0], + /// 18.13:0 Reserved (RO=0) + RESERVED OFFSET(0) NUMBITS(14) [], + ], + /// Table 55. Configuration Register (Address 19, Hex 13) + Config [ + /// 19.15 Reserved (RO=0) + RESERVED_1 OFFSET(15) NUMBITS(1) [], + /// 19.14 Txmit Test (100BASE-TX), 1=Enabled, 0=Disabled (RW=0) + TXMIT_TEST OFFSET(14) NUMBITS(1) [], + /// 19.13 Mode, 1=Repeater, 0=Normal (RW=MF1) + MODE OFFSET(13) NUMBITS(1) [Repeater = 1, Normal = 0], + /// 19.12 MDIO Interrupts, 1=Enabled, 0=Normal (RW=0) + MDIO_INT OFFSET(12) NUMBITS(1) [], + /// 19.11 TP Loopback (10BASE-T), 1=Disable, 0=Enable (RW=0) + TP_LOOPBACK OFFSET(11) NUMBITS(1) [], + /// 19.10 SQE (10BASE-T), 1=Enable, 0=Disable (RW=0) + SQE OFFSET(10) NUMBITS(1) [], + /// 19.9 Jabber (10BASE-T), 1=Disable, 0=Enable (RW=0) + NO_JABBER OFFSET(9) NUMBITS(1) [], + /// 19.8 Link Test (10BASE-T), 1=Disable, 0=Enable (RW=CFG1&!MF0) + LINK_TEST OFFSET(8) NUMBITS(1) [No = 1, Yes = 0], + /// 19.7:6 LEDC Programming bits (RW=0b00) + LEDC OFFSET(6) NUMBITS(2) [Collision = 0b00, Off = 0b01, Activity = 0b10, AlwaysOn = 0b11], + /// 19.5 Advance TX Clock, 1=1/2 TX_CLK, 0=Normal (RW=0) + ATXC OFFSET(5) NUMBITS(1) [], + /// 19.4 5B Symbol/(100BASE-X only) 4B Nibble, 1=5B Symbol, 0=4B Nibble (RW=MF2) + CODER OFFSET(4) NUMBITS(1) [Symbol5b = 1, Nibble4b = 0], + /// 19.3 Bypass Scrambler (100BASE-X only), 1=Bypass, 0=Normal (RW=MF3) + SCRAMBLER OFFSET(3) NUMBITS(1) [Bypass = 1, Normal = 0], + /// 19.2 100BASE-FX, 1=Fiber, 0=Twisted Pair (RW=MF4&!MF0)) + CABLE_100FX OFFSET(2) NUMBITS(1) [Fiber = 1, TwistedPair = 0], + /// 19.1 Reserved (RO=0) + RESERVED_2 OFFSET(1) NUMBITS(1) [], + /// 19.0 Transmit Disconnect, 1=Disconnect, 0=Normal (RW=0) + TD OFFSET(0) NUMBITS(1) [], + ], + /// Table 56. Chip Status Register (Address 20, Hex 14) + ChipStatus [ + /// 20.15:14 Reserved (RO=0) + RESERVED_1 OFFSET(14) NUMBITS(2) [], + /// 20.13 Link, 1=Up, 0=Down (RO=0) + LINK OFFSET(13) NUMBITS(1) [Up = 1, Down = 0], + /// 20.12 Duplex Mode, 1=Full Duplex, 0=Half Duplex (RO=?/FDE) + DUPLEX OFFSET(12) NUMBITS(1) [FullDuplex = 1, HalfDuplex = 0], + /// 20.11 Speed, 1=100 Mbps, 0=10Mbps (RO=?/CFG0) + SPEED OFFSET(11) NUMBITS(1) [Speed100Mbps = 1, Speed10Mbps = 0], + /// 20.10 Reserved (RO=0) + RESERVED_2 OFFSET(10) NUMBITS(1) [], + /// 20.9 Auto Negotiation Complete, 1=Yes, 0=No (RO=0,LH) + AN_COMPLETE OFFSET(9) NUMBITS(1) [Yes = 1, No = 0], + /// 20.8 Page Received (3 consecutive identical), 1=Yes, 0=No (RO=0,LH) + PAGE_RECEIVED OFFSET(8) NUMBITS(1) [Yes = 1, No = 0], + /// 20.7:3 Reserved (RO=0) + RESERVED_3 OFFSET(3) NUMBITS(5) [], + /// 20.2 Low-Voltage, 1=Yes, 0=No (RO=0) + LOW_VOLTAGE_FAULT OFFSET(2) NUMBITS(1) [Yes = 1, No = 0], + /// 20.1:0 Reserved (RO=0) + RESERVED_4 OFFSET(0) NUMBITS(2) [], + ], +]; diff --git a/rust/rustfmt.toml b/rust/rustfmt.toml index 2a35f0230..1e7fbee24 100644 --- a/rust/rustfmt.toml +++ b/rust/rustfmt.toml @@ -1 +1,2 @@ use_small_heuristics = "Max" +max_width = 300