File Index
Files and directories
Sign in
FILE

qt2025.rs

File preview with syntax highlighting.

linux-6.19.14/drivers/net/phy/qt2025.rs RUST
  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
 12use kernel::c_str;
 13use kernel::error::code;
 14use kernel::firmware::Firmware;
 15use kernel::io::poll::read_poll_timeout;
 16use kernel::net::phy::{
 17    self,
 18    reg::{Mmd, C45},
 19    Driver,
 20};
 21use kernel::prelude::*;
 22use kernel::sizes::{SZ_16K, SZ_8K};
 23use kernel::time::Delta;
 24
 25kernel::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
 37struct PhyQT2025;
 38
 39#[vtable]
 40impl 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}
~/ Read-only file preview.