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