qt2025.rs 3.8 KB

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