1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (C) Tehuti Networks Ltd. 3 // Copyright (C) 2024 FUJITA Tomonori <fujita.tomonori@gmail.com> 4 5 //! Applied Micro Circuits Corporation QT2025 PHY driver 6 //! 7 //! This driver is based on the vendor driver `QT2025_phy.c`. This source 8 //! and firmware can be downloaded on the EN-9320SFP+ support site. 9 //! 10 //! The QT2025 PHY integrates an Intel 8051 micro-controller. 11 12 use kernel::c_str; 13 use kernel::error::code; 14 use kernel::firmware::Firmware; 15 use kernel::io::poll::read_poll_timeout; 16 use kernel::net::phy::{ 17 self, 18 reg::{Mmd, C45}, 19 Driver, 20 }; 21 use kernel::prelude::*; 22 use kernel::sizes::{SZ_16K, SZ_8K}; 23 use kernel::time::Delta; 24 25 kernel::module_phy_driver! { 26 drivers: [PhyQT2025], 27 device_table: [ 28 phy::DeviceId::new_with_driver::<PhyQT2025>(), 29 ], 30 name: "qt2025_phy", 31 authors: ["FUJITA Tomonori <fujita.tomonori@gmail.com>"], 32 description: "AMCC QT2025 PHY driver", 33 license: "GPL", 34 firmware: ["qt2025-2.0.3.3.fw"], 35 } 36 37 struct PhyQT2025; 38 39 #[vtable] 40 impl Driver for PhyQT2025 { 41 const NAME: &'static CStr = c_str!("QT2025 10Gpbs SFP+"); 42 const PHY_DEVICE_ID: phy::DeviceId = phy::DeviceId::new_with_exact_mask(0x0043a400); 43 44 fn probe(dev: &mut phy::Device) -> Result<()> { 45 // Check the hardware revision code. 46 // Only 0xb3 works with this driver and firmware. 47 let hw_rev = dev.read(C45::new(Mmd::PMAPMD, 0xd001))?; 48 if (hw_rev >> 8) != 0xb3 { 49 return Err(code::ENODEV); 50 } 51 52 // `MICRO_RESETN`: hold the micro-controller in reset while configuring. 53 dev.write(C45::new(Mmd::PMAPMD, 0xc300), 0x0000)?; 54 // `SREFCLK_FREQ`: configure clock frequency of the micro-controller. 55 dev.write(C45::new(Mmd::PMAPMD, 0xc302), 0x0004)?; 56 // Non loopback mode. 57 dev.write(C45::new(Mmd::PMAPMD, 0xc319), 0x0038)?; 58 // `CUS_LAN_WAN_CONFIG`: select between LAN and WAN (WIS) mode. 59 dev.write(C45::new(Mmd::PMAPMD, 0xc31a), 0x0098)?; 60 // The following writes use standardized registers (3.38 through 61 // 3.41 5/10/25GBASE-R PCS test pattern seed B) for something else. 62 // We don't know what. 63 dev.write(C45::new(Mmd::PCS, 0x0026), 0x0e00)?; 64 dev.write(C45::new(Mmd::PCS, 0x0027), 0x0893)?; 65 dev.write(C45::new(Mmd::PCS, 0x0028), 0xa528)?; 66 dev.write(C45::new(Mmd::PCS, 0x0029), 0x0003)?; 67 // Configure transmit and recovered clock. 68 dev.write(C45::new(Mmd::PMAPMD, 0xa30a), 0x06e1)?; 69 // `MICRO_RESETN`: release the micro-controller from the reset state. 70 dev.write(C45::new(Mmd::PMAPMD, 0xc300), 0x0002)?; 71 // The micro-controller will start running from the boot ROM. 72 dev.write(C45::new(Mmd::PCS, 0xe854), 0x00c0)?; 73 74 let fw = Firmware::request(c_str!("qt2025-2.0.3.3.fw"), dev.as_ref())?; 75 if fw.data().len() > SZ_16K + SZ_8K { 76 return Err(code::EFBIG); 77 } 78 79 // The 24kB of program memory space is accessible by MDIO. 80 // The first 16kB of memory is located in the address range 3.8000h - 3.BFFFh. 81 // The next 8kB of memory is located at 4.8000h - 4.9FFFh. 82 let mut dst_offset = 0; 83 let mut dst_mmd = Mmd::PCS; 84 for (src_idx, val) in fw.data().iter().enumerate() { 85 if src_idx == SZ_16K { 86 // Start writing to the next register with no offset 87 dst_offset = 0; 88 dst_mmd = Mmd::PHYXS; 89 } 90 91 dev.write(C45::new(dst_mmd, 0x8000 + dst_offset), (*val).into())?; 92 93 dst_offset += 1; 94 } 95 // The micro-controller will start running from SRAM. 96 dev.write(C45::new(Mmd::PCS, 0xe854), 0x0040)?; 97 98 read_poll_timeout( 99 || dev.read(C45::new(Mmd::PCS, 0xd7fd)), 100 |val| *val != 0x00 && *val != 0x10, 101 Delta::from_millis(50), 102 Delta::from_secs(3), 103 )?; 104 105 Ok(()) 106 } 107 108 fn read_status(dev: &mut phy::Device) -> Result<u16> { 109 dev.genphy_read_status::<C45>() 110 } 111 } 112