developer | 5d148cb | 2023-06-02 13:08:11 +0800 | [diff] [blame] | 1 | From 2fd17c806f5ad23f9958c358cdc26f618f05d5df Mon Sep 17 00:00:00 2001 |
| 2 | From: Sam Shih <sam.shih@mediatek.com> |
| 3 | Date: Fri, 2 Jun 2023 13:06:32 +0800 |
| 4 | Subject: [PATCH] |
| 5 | [networking][999-2719-net-phy-aquantia-add-firmware-download.patch] |
| 6 | |
| 7 | --- |
| 8 | drivers/net/phy/Kconfig | 33 +- |
| 9 | drivers/net/phy/Makefile | 3 + |
| 10 | drivers/net/phy/aquantia.h | 64 ++ |
| 11 | drivers/net/phy/aquantia_firmware.c | 1090 +++++++++++++++++++++++++++ |
| 12 | drivers/net/phy/aquantia_main.c | 92 ++- |
| 13 | 5 files changed, 1241 insertions(+), 41 deletions(-) |
| 14 | create mode 100644 drivers/net/phy/aquantia_firmware.c |
| 15 | |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 16 | diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig |
developer | 5d148cb | 2023-06-02 13:08:11 +0800 | [diff] [blame] | 17 | index c0e09c99d..d467834eb 100644 |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 18 | --- a/drivers/net/phy/Kconfig |
| 19 | +++ b/drivers/net/phy/Kconfig |
developer | 301205c | 2023-05-24 15:39:32 +0800 | [diff] [blame] | 20 | @@ -372,7 +372,38 @@ config AMD_PHY |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 21 | config AQUANTIA_PHY |
| 22 | tristate "Aquantia PHYs" |
| 23 | ---help--- |
| 24 | - Currently supports the Aquantia AQ1202, AQ2104, AQR105, AQR405 |
| 25 | + Currently supports the Aquantia AQ1202, AQ2104, AQR105, AQR405, AQR113C |
| 26 | + |
| 27 | +config AQUANTIA_PHY_FW_DOWNLOAD |
| 28 | + tristate "Firmware Download Enable" |
| 29 | + depends on AQUANTIA_PHY |
| 30 | + ---help--- |
| 31 | + Currently supports the Aquantia AQR113C |
| 32 | + |
| 33 | +choice |
| 34 | + prompt "Download mode" |
| 35 | + default AQUANTIA_PHY_FW_DOWNLOAD_GANG |
| 36 | + depends on AQUANTIA_PHY_FW_DOWNLOAD |
| 37 | + |
| 38 | + config AQUANTIA_PHY_FW_DOWNLOAD_SINGLE |
| 39 | + bool "Single" |
| 40 | + ---help--- |
| 41 | + If you would like to download firmware in sequential way, |
| 42 | + please select this option. |
| 43 | + |
| 44 | + config AQUANTIA_PHY_FW_DOWNLOAD_GANG |
| 45 | + bool "Gang" |
| 46 | + ---help--- |
| 47 | + If you would like to download firmware in parallel way, |
| 48 | + please select this option. |
| 49 | +endchoice |
| 50 | + |
| 51 | +config AQUANTIA_PHY_FW_FILE |
| 52 | + string "FW File" |
| 53 | + depends on AQUANTIA_PHY |
| 54 | + default "Rhe-05.06-Candidate7-AQR_Mediatek_23B_StartOff_ID45623_VER36657.cld" |
| 55 | + ---help--- |
| 56 | + Currently supports the Aquantia AQR113c |
| 57 | |
| 58 | config AX88796B_PHY |
| 59 | tristate "Asix PHYs" |
| 60 | diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile |
developer | 5d148cb | 2023-06-02 13:08:11 +0800 | [diff] [blame] | 61 | index 8b57d6105..e9653de36 100644 |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 62 | --- a/drivers/net/phy/Makefile |
| 63 | +++ b/drivers/net/phy/Makefile |
developer | 5d148cb | 2023-06-02 13:08:11 +0800 | [diff] [blame] | 64 | @@ -68,6 +68,9 @@ aquantia-objs += aquantia_main.o |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 65 | ifdef CONFIG_HWMON |
| 66 | aquantia-objs += aquantia_hwmon.o |
| 67 | endif |
| 68 | +ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD |
| 69 | +aquantia-objs += aquantia_firmware.o |
| 70 | +endif |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 71 | obj-$(CONFIG_AIROHA_EN8801SC_PHY) += en8801sc.o |
developer | 5d148cb | 2023-06-02 13:08:11 +0800 | [diff] [blame] | 72 | obj-$(CONFIG_AIROHA_EN8811H_PHY) += air_en8811h.o |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 73 | obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o |
| 74 | diff --git a/drivers/net/phy/aquantia.h b/drivers/net/phy/aquantia.h |
developer | 5d148cb | 2023-06-02 13:08:11 +0800 | [diff] [blame] | 75 | index 5a16caab7..ab1c241d3 100644 |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 76 | --- a/drivers/net/phy/aquantia.h |
| 77 | +++ b/drivers/net/phy/aquantia.h |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 78 | @@ -9,8 +9,72 @@ |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 79 | #include <linux/device.h> |
| 80 | #include <linux/phy.h> |
| 81 | |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 82 | +#define MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT 4 |
| 83 | + |
developer | 9431640 | 2022-11-21 08:58:41 +0800 | [diff] [blame] | 84 | +#define PMAPMD_RSVD_VEND_PROV 0xe400 |
| 85 | +#define PMAPMD_RSVD_VEND_PROV_MDI_CONF BIT(0) |
| 86 | + |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 87 | +/* MDIO_MMD_C22EXT */ |
| 88 | +#define MDIO_C22EXT_STAT_SGMII_RX_GOOD_FRAMES 0xd292 |
| 89 | +#define MDIO_C22EXT_STAT_SGMII_RX_BAD_FRAMES 0xd294 |
| 90 | +#define MDIO_C22EXT_STAT_SGMII_RX_FALSE_CARRIER 0xd297 |
| 91 | +#define MDIO_C22EXT_STAT_SGMII_TX_GOOD_FRAMES 0xd313 |
| 92 | +#define MDIO_C22EXT_STAT_SGMII_TX_BAD_FRAMES 0xd315 |
| 93 | +#define MDIO_C22EXT_STAT_SGMII_TX_FALSE_CARRIER 0xd317 |
| 94 | +#define MDIO_C22EXT_STAT_SGMII_TX_COLLISIONS 0xd318 |
| 95 | +#define MDIO_C22EXT_STAT_SGMII_TX_LINE_COLLISIONS 0xd319 |
| 96 | +#define MDIO_C22EXT_STAT_SGMII_TX_FRAME_ALIGN_ERR 0xd31a |
| 97 | +#define MDIO_C22EXT_STAT_SGMII_TX_RUNT_FRAMES 0xd31b |
| 98 | + |
| 99 | +struct aqr107_hw_stat { |
| 100 | + const char *name; |
| 101 | + int reg; |
| 102 | + int size; |
| 103 | +}; |
| 104 | + |
| 105 | +#define SGMII_STAT(n, r, s) { n, MDIO_C22EXT_STAT_SGMII_ ## r, s } |
| 106 | +static const struct aqr107_hw_stat aqr107_hw_stats[] = { |
| 107 | + SGMII_STAT("sgmii_rx_good_frames", RX_GOOD_FRAMES, 26), |
| 108 | + SGMII_STAT("sgmii_rx_bad_frames", RX_BAD_FRAMES, 26), |
| 109 | + SGMII_STAT("sgmii_rx_false_carrier_events", RX_FALSE_CARRIER, 8), |
| 110 | + SGMII_STAT("sgmii_tx_good_frames", TX_GOOD_FRAMES, 26), |
| 111 | + SGMII_STAT("sgmii_tx_bad_frames", TX_BAD_FRAMES, 26), |
| 112 | + SGMII_STAT("sgmii_tx_false_carrier_events", TX_FALSE_CARRIER, 8), |
| 113 | + SGMII_STAT("sgmii_tx_collisions", TX_COLLISIONS, 8), |
| 114 | + SGMII_STAT("sgmii_tx_line_collisions", TX_LINE_COLLISIONS, 8), |
| 115 | + SGMII_STAT("sgmii_tx_frame_alignment_err", TX_FRAME_ALIGN_ERR, 16), |
| 116 | + SGMII_STAT("sgmii_tx_runt_frames", TX_RUNT_FRAMES, 22), |
| 117 | +}; |
| 118 | +#define AQR107_SGMII_STAT_SZ ARRAY_SIZE(aqr107_hw_stats) |
| 119 | + |
| 120 | +struct aqr107_priv { |
| 121 | + u64 sgmii_stats[AQR107_SGMII_STAT_SZ]; |
| 122 | +#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD |
| 123 | + struct phy_device *phydevs[1]; |
developer | 7ddeff0 | 2023-03-22 15:28:46 +0800 | [diff] [blame] | 124 | + struct task_struct *heartbeat_thread; |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 125 | + spinlock_t lock; |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 126 | + bool fw_initialized; |
developer | 093e9b3 | 2022-12-13 16:08:34 +0800 | [diff] [blame] | 127 | + int fw_dl_mode; |
developer | 7ddeff0 | 2023-03-22 15:28:46 +0800 | [diff] [blame] | 128 | + u16 heartbeat; |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 129 | +#endif |
| 130 | +}; |
| 131 | + |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 132 | +int aqr107_set_downshift(struct phy_device *phydev, u8 cnt); |
| 133 | +void aqr107_chip_info(struct phy_device *phydev); |
developer | 9431640 | 2022-11-21 08:58:41 +0800 | [diff] [blame] | 134 | +int aqr107_config_mdi(struct phy_device *phydev); |
| 135 | + |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 136 | #if IS_REACHABLE(CONFIG_HWMON) |
| 137 | int aqr_hwmon_probe(struct phy_device *phydev); |
| 138 | #else |
| 139 | static inline int aqr_hwmon_probe(struct phy_device *phydev) { return 0; } |
| 140 | #endif |
| 141 | + |
| 142 | +#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD |
developer | 93ef6f0 | 2023-08-31 16:09:24 +0800 | [diff] [blame] | 143 | +enum aqr_fw_dl_mode { |
developer | 093e9b3 | 2022-12-13 16:08:34 +0800 | [diff] [blame] | 144 | + FW_DL_SINGLE = 0, |
| 145 | + FW_DL_GNAGLOAD, |
| 146 | +}; |
| 147 | + |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 148 | +int aqr_firmware_heartbeat_thread(void *data); |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 149 | +int aqr_firmware_download(struct phy_device *phydev); |
| 150 | +#endif |
| 151 | diff --git a/drivers/net/phy/aquantia_firmware.c b/drivers/net/phy/aquantia_firmware.c |
| 152 | new file mode 100644 |
developer | 5d148cb | 2023-06-02 13:08:11 +0800 | [diff] [blame] | 153 | index 000000000..d2828aad4 |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 154 | --- /dev/null |
| 155 | +++ b/drivers/net/phy/aquantia_firmware.c |
developer | 93ef6f0 | 2023-08-31 16:09:24 +0800 | [diff] [blame] | 156 | @@ -0,0 +1,1109 @@ |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 157 | +// SPDX-License-Identifier: GPL-2.0 |
| 158 | +/* FW download driver for Aquantia PHY |
| 159 | + */ |
| 160 | + |
| 161 | +#include <linux/phy.h> |
| 162 | +#include <linux/of.h> |
| 163 | +#include <linux/device.h> |
| 164 | +#include <linux/firmware.h> |
| 165 | +#include <linux/kthread.h> |
| 166 | + |
| 167 | +#include "aquantia.h" |
| 168 | + |
| 169 | +#undef AQ_VERBOSE |
| 170 | + |
| 171 | +#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD_SINGLE |
| 172 | +#define MAX_GANGLOAD_DEVICES 1 |
| 173 | +#elif CONFIG_AQUANTIA_PHY_FW_DOWNLOAD_GANG |
| 174 | +#define MAX_GANGLOAD_DEVICES 2 |
| 175 | +#endif |
| 176 | + |
| 177 | +#define AQR_FIRMWARE CONFIG_AQUANTIA_PHY_FW_FILE |
| 178 | + |
| 179 | +/* Vendor specific 1, MDIO_MMD_VEND1 */ |
| 180 | +#define VEND1_STD_CONTROL1 0x0000 |
| 181 | +#define VEND1_STD_CONTROL1_SOFT_RESET BIT(15) |
| 182 | + |
| 183 | +#define VEND1_MAILBOX_INTERFACE1 0x0200 |
| 184 | +#define VEND1_MAILBOX_INTERFACE1_START BIT(15) |
| 185 | +#define VEND1_MAILBOX_INTERFACE1_WRITE FIELD_PREP(BIT(14), 1) |
| 186 | +#define VEND1_MAILBOX_INTERFACE1_READ FIELD_PREP(BIT(14), 0) |
| 187 | +#define VEND1_MAILBOX_INTERFACE1_RESET_CRC BIT(12) |
| 188 | + |
| 189 | +#define VEND1_MAILBOX_INTERFACE2 0x0201 |
| 190 | +#define VEND1_MAILBOX_INTERFACE2_CRC GENMASK(15, 0) |
| 191 | + |
| 192 | +#define VEND1_MAILBOX_INTERFACE3 0x0202 |
| 193 | +#define VEND1_MAILBOX_INTERFACE3_ADDR_MSW GENMASK(15, 0) |
| 194 | + |
| 195 | +#define VEND1_MAILBOX_INTERFACE4 0x0203 |
| 196 | +#define VEND1_MAILBOX_INTERFACE4_ADDR_LSW GENMASK(15, 2) |
| 197 | + |
| 198 | +#define VEND1_MAILBOX_INTERFACE5 0x0204 |
| 199 | +#define VEND1_MAILBOX_INTERFACE5_DATA_MSW GENMASK(15, 0) |
| 200 | + |
| 201 | +#define VEND1_MAILBOX_INTERFACE6 0x0205 |
| 202 | +#define VEND1_MAILBOX_INTERFACE6_DATA_LSW GENMASK(15, 0) |
| 203 | + |
| 204 | +#define VEND1_CONTROL2 0xc001 |
| 205 | +#define VEND1_CONTROL2_UP_RESET BIT(15) |
| 206 | +#define VEND1_CONTROL2_UP_RUNSTALL_OVERRIDE BIT(6) |
| 207 | +#define VEND1_CONTROL2_UP_RUNSTALL BIT(0) |
| 208 | + |
| 209 | +#define VEND1_RESET_CONTROL 0xc006 |
| 210 | +#define VEND1_RESET_CONTROL_MMD_RESET_DISABLE BIT(14) |
| 211 | + |
| 212 | +#define VEND1_GENERAL_PROV2 0xc441 |
| 213 | +#define VEND1_GENERAL_PROV2_MDIO_BROADCAST_ENABLE BIT(14) |
| 214 | + |
| 215 | +#define VEND1_GENERAL_PROV8 0xc447 |
| 216 | +#define VEND1_GENERAL_PROV8_MDIO_BROADCAST_ADDRESS GENMASK(4, 0) |
| 217 | + |
| 218 | +#define VEND1_NVR_PROV3 0xc452 |
| 219 | +#define VEND1_NVR_PROV3_DAISYCHAIN_DISABLE BIT(0) |
| 220 | + |
| 221 | +#define VEND1_RSVD_PROV2 0xc471 |
| 222 | +#define VEND1_RSVD_PROV2_DAISYCHAIN_HOPCOUNT GENMASK(5, 0) |
| 223 | +#define VEND1_RSVD_PROV2_DAISYCHAIN_HOPCOUNT_OVERRIDE BIT(6) |
| 224 | + |
developer | aafac65 | 2023-01-18 09:41:27 +0800 | [diff] [blame] | 225 | +#define VEND1_GLOBAL_RSVD_STAT2 0xc886 |
| 226 | + |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 227 | +/*! The byte address, in processor memory, of the start of the IRAM segment. */ |
| 228 | +#define AQ_IRAM_BASE_ADDRESS 0x40000000 |
| 229 | + |
| 230 | +/*! The byte address, in processor memory, of the start of the DRAM segment. */ |
| 231 | +#define AQ_DRAM_BASE_ADDRESS 0x3FFE0000 |
| 232 | + |
| 233 | +/*! The byte offset from the top of the PHY image to the header content (HHD & EUR devices). */ |
| 234 | +#define AQ_PHY_IMAGE_HEADER_CONTENT_OFFSET_HHD 0x300 |
| 235 | + |
| 236 | +/*! The offset, from the start of DRAM, where the provisioning block begins. */ |
| 237 | +#define AQ_PHY_IMAGE_PROVTABLE_OFFSET 0x680 |
| 238 | + |
| 239 | +/*! The offset, from the start of DRAM, where the provisioning block's ending address is recorded. */ |
| 240 | +#define AQ_PHY_IMAGE_PROVTABLE_TERM_OFFSET 0x028C |
| 241 | + |
| 242 | +/*! The size of the space alloted within the PHY image for the provisioning table. */ |
| 243 | +#define AQ_PHY_IMAGE_PROVTABLE_MAXSIZE 0x800 |
| 244 | + |
| 245 | +/*! The maximum number of ports that can be MDIO bootloaded at once. */ |
| 246 | +#define AQ_MAX_NUM_PHY_IDS 48 |
| 247 | + |
| 248 | +/*! This enumeration is used to describe the different types of |
| 249 | + Aquantia PHY.*/ |
| 250 | +typedef enum |
| 251 | +{ |
| 252 | + /*! 1/2/4-port package, 40nm architechture.*/ |
| 253 | + AQ_DEVICE_APPIA, |
| 254 | + /*! 1/2/4-port package, first-generation 28nm architechture.*/ |
| 255 | + AQ_DEVICE_HHD, |
| 256 | + /*! 1/2/4-port package, second-generation 28nm architechture.*/ |
| 257 | + AQ_DEVICE_EUR, |
| 258 | + /*! 1/2/4-port package, third-generation 28nm architechture.*/ |
| 259 | + AQ_DEVICE_CAL, |
| 260 | + /*! 1/2/4/8-port package, forth-generation 14nm architechture.*/ |
| 261 | + AQ_DEVICE_RHEA, |
| 262 | + /*! 8-port package, fifth-generation 14nm architechture.*/ |
| 263 | + AQ_DEVICE_DIONE |
| 264 | +} AQ_API_Device; |
| 265 | + |
| 266 | +/*! The table used to compute CRC's within the PHY. */ |
| 267 | +const uint16_t AQ_CRC16Table[256] = {0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, |
| 268 | + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, |
| 269 | + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, |
| 270 | + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, |
| 271 | + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, |
| 272 | + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, |
| 273 | + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, |
| 274 | + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, |
| 275 | + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, |
| 276 | + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, |
| 277 | + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, |
| 278 | + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, |
| 279 | + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, |
| 280 | + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, |
| 281 | + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, |
| 282 | + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, |
| 283 | + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, |
| 284 | + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, |
| 285 | + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, |
| 286 | + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, |
| 287 | + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, |
| 288 | + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, |
| 289 | + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, |
| 290 | + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, |
| 291 | + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, |
| 292 | + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, |
| 293 | + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, |
| 294 | + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, |
| 295 | + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, |
| 296 | + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, |
| 297 | + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, |
| 298 | + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0}; |
| 299 | + |
| 300 | +struct task_struct *gangload_kthread = NULL; |
| 301 | +struct phy_device *gangload_phydevs[MAX_GANGLOAD_DEVICES]; |
developer | 9451bcd | 2023-07-18 09:34:05 +0800 | [diff] [blame] | 302 | +static unsigned long gangload_timeout = 0; |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 303 | +static int gangload = 0; |
developer | 93ef6f0 | 2023-08-31 16:09:24 +0800 | [diff] [blame] | 304 | +static DEFINE_SPINLOCK(gangload_lock); |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 305 | + |
developer | 93ef6f0 | 2023-08-31 16:09:24 +0800 | [diff] [blame] | 306 | +static int aqr_firmware_download_single(struct phy_device *phydev, bool force_reload); |
developer | aafac65 | 2023-01-18 09:41:27 +0800 | [diff] [blame] | 307 | + |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 308 | +void AQ_API_EnableMDIO_BootLoadMode |
| 309 | +( |
| 310 | + /*! The target PHY port.*/ |
| 311 | + struct phy_device *phydev, |
| 312 | + /*! The provisioning address to use when the FW starts and applies the |
| 313 | + * bootloaded image's provisioned values. */ |
| 314 | + unsigned int provisioningAddress |
| 315 | +) |
| 316 | +{ |
| 317 | + uint16_t globalNvrProvisioning; |
| 318 | + uint16_t globalReservedProvisioning; |
| 319 | + |
| 320 | + /* disable the daisy-chain */ |
| 321 | + globalNvrProvisioning = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_NVR_PROV3); |
| 322 | + globalNvrProvisioning |= VEND1_NVR_PROV3_DAISYCHAIN_DISABLE; |
| 323 | + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_NVR_PROV3, globalNvrProvisioning); |
| 324 | + |
| 325 | + /* override the hop-count */ |
| 326 | + globalReservedProvisioning = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_RSVD_PROV2); |
| 327 | + globalReservedProvisioning &= ~VEND1_RSVD_PROV2_DAISYCHAIN_HOPCOUNT; |
| 328 | + globalReservedProvisioning |= FIELD_PREP(VEND1_RSVD_PROV2_DAISYCHAIN_HOPCOUNT, |
| 329 | + provisioningAddress); |
| 330 | + globalReservedProvisioning |= VEND1_RSVD_PROV2_DAISYCHAIN_HOPCOUNT_OVERRIDE; |
| 331 | + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_RSVD_PROV2, globalReservedProvisioning); |
| 332 | + |
| 333 | + return; |
| 334 | +} |
| 335 | + |
| 336 | +/*! Prepare the specified port for MDIO bootloading, and set the temporary MDIO |
| 337 | + * address to be used during the bootload process. Disables the daisy-chain, |
| 338 | + * and explicitly sets the port's provisioningAddress. */ |
| 339 | +void AQ_API_EnableGangLoadMode |
| 340 | +( |
| 341 | + /*! The target PHY port.*/ |
| 342 | + struct phy_device *phydev, |
| 343 | + /*! The PHY's MDIO address will be changed to this value during the |
| 344 | + * bootload process. */ |
| 345 | + unsigned int gangLoadAddress |
| 346 | +) |
| 347 | +{ |
| 348 | + uint16_t globalGeneralProvisioning; |
| 349 | + |
| 350 | + /* Enable gangload mode. After doing this, the PHY will be |
| 351 | + * addressable at the MDIO address indicated by gangLoadAddress. |
| 352 | + * Now that the PHY is in gangload mode, MDIO reads are prohibited |
| 353 | + * until AQ_API_DisableGangLoadMode is called. */ |
| 354 | + globalGeneralProvisioning = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GENERAL_PROV8); |
| 355 | + globalGeneralProvisioning &= ~VEND1_GENERAL_PROV8_MDIO_BROADCAST_ADDRESS; |
| 356 | + globalGeneralProvisioning |= FIELD_PREP(VEND1_GENERAL_PROV8_MDIO_BROADCAST_ADDRESS, |
| 357 | + gangLoadAddress); |
| 358 | + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GENERAL_PROV8, globalGeneralProvisioning); |
| 359 | + |
| 360 | + globalGeneralProvisioning = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GENERAL_PROV2); |
| 361 | + globalGeneralProvisioning |= VEND1_GENERAL_PROV2_MDIO_BROADCAST_ENABLE; |
| 362 | + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GENERAL_PROV2, globalGeneralProvisioning); |
| 363 | + |
| 364 | + return; |
| 365 | +} |
| 366 | + |
| 367 | +/*! Restore the PHY's MDIO address to the pin-specified value. Should be |
| 368 | + * called when MDIO bootloading is complete, to return to normal MDIO |
| 369 | + * addressing. |
| 370 | + * <b>This is a gang-load function, hence write-only!</b> */ |
| 371 | +void AQ_API_DisableGangLoadMode |
| 372 | +( |
| 373 | + /*! The target PHY port.*/ |
| 374 | + struct phy_device *phydev, |
| 375 | + /*! The value to write to of AQ_GlobalGeneralProvisioning.u1.word_1. */ |
| 376 | + uint16_t origVal_GGP1 |
| 377 | +) |
| 378 | +{ |
| 379 | + uint16_t globalGeneralProvisioning; |
| 380 | + |
| 381 | + /* Restore the original value of globalGeneralProvisioning.u1, and set |
| 382 | + * the MDIO address reset bit. This will cause the MDIO address to be |
| 383 | + * reset to the value indicated by the pins. */ |
| 384 | + globalGeneralProvisioning = origVal_GGP1; |
| 385 | + globalGeneralProvisioning &= ~VEND1_GENERAL_PROV2_MDIO_BROADCAST_ENABLE; |
| 386 | + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GENERAL_PROV2, globalGeneralProvisioning); |
| 387 | + |
| 388 | + /* The PHY has now exited gang-load mode. */ |
| 389 | + return; |
| 390 | +} |
| 391 | + |
| 392 | +/* Common implementation of MDIO bootload routine, for the entry points: |
| 393 | + * AQ_API_WriteBootLoadImage |
| 394 | + * AQ_API_WriteBootLoadImageWithProvTable |
| 395 | + * AQ_API_WriteBootLoadImageDRAMOnly |
| 396 | + * AQ_API_WriteBootLoadImageWithProvTableDRAMOnly */ |
| 397 | +static int AQ_API_WriteBootLoadImage_impl |
| 398 | +( |
| 399 | + struct phy_device **phydevs, |
| 400 | + int num_phydevs, |
| 401 | + struct phy_device *gandload_phydev, |
| 402 | + int *result, |
| 403 | + const uint32_t* imageSizePointer, |
| 404 | + const uint8_t* image, |
| 405 | + const uint32_t* provTableSizePointer, |
| 406 | + const uint8_t* provTableImage, |
| 407 | + bool dramOnly |
| 408 | +) |
| 409 | +{ |
| 410 | + uint32_t primaryHeaderPtr = 0x00000000; |
| 411 | + uint32_t primaryIramPtr = 0x00000000; |
| 412 | + uint32_t primaryDramPtr = 0x00000000; |
| 413 | + uint32_t primaryIramSize = 0x00000000; |
| 414 | + uint32_t primaryDramSize = 0x00000000; |
| 415 | + uint32_t terminatorPtr = 0x00000000; |
| 416 | + uint32_t phyImageHeaderContentOffset = 0x00000000; |
| 417 | + uint32_t i, j; |
| 418 | + uint32_t imageSize; |
| 419 | + uint32_t provTableImageSize = 0; |
| 420 | + uint32_t bytePointer; |
| 421 | + uint32_t byteSize; |
| 422 | + uint32_t dWordSize; |
| 423 | +#ifdef AQ_PHY_SUPPORTS_BLOCK_READ_WRITE |
| 424 | + uint32_t countPendingOps; /* A count of block MDIO operation pending... necessary to keep a count |
| 425 | + in order to ensure we don't exceed the maximum pending operations. */ |
| 426 | +#endif |
| 427 | + uint16_t globalControl; |
| 428 | + uint16_t msw; |
| 429 | + uint16_t lsw; |
| 430 | + uint16_t crc16Calculated; |
| 431 | + uint16_t provTableCrc16Calculated; |
| 432 | + uint16_t fileCRC; |
| 433 | + uint16_t provTableFileCRC; |
| 434 | + uint16_t mailboxCRC; |
| 435 | + uint16_t mailboxWrite; |
| 436 | + uint16_t recordedGGP1Values[AQ_MAX_NUM_PHY_IDS]; /* When entering/exiting gangload mode, we record and restore |
| 437 | + the AQ_GlobalGeneralProvisioning.u1 register values. */ |
| 438 | + |
| 439 | + /* store the CRC-16 for the image, which is the last two bytes */ |
| 440 | + imageSize = *imageSizePointer; |
| 441 | + |
| 442 | + /* |
| 443 | + * If the imageSize is less than 2, we don't do anything |
| 444 | + */ |
| 445 | + if (imageSize < 2) { |
| 446 | + result[0] = -EINVAL; |
| 447 | + return -EINVAL; |
| 448 | + } |
| 449 | + |
| 450 | + fileCRC = image[imageSize-2] << 8 | image[imageSize-1]; |
| 451 | + |
| 452 | + /*------------------------------------- Check the image integrity ------------------------------------------------*/ |
| 453 | + crc16Calculated = 0x0000; |
| 454 | + for (i = 0; i < imageSize-2; i++) |
| 455 | + { |
| 456 | + crc16Calculated = ((crc16Calculated & 0xFF) << 8) ^ AQ_CRC16Table[(crc16Calculated >> 8) ^ image[i]]; |
| 457 | + } |
| 458 | + |
| 459 | + if (crc16Calculated != fileCRC) |
| 460 | + { |
| 461 | + phydev_err(phydevs[0], "CRC check failed on image file (expected 0x%X, found 0x%X)\n", |
| 462 | + fileCRC, crc16Calculated); |
| 463 | + result[0] = -EINVAL; |
| 464 | + return -EINVAL; |
| 465 | + } |
| 466 | + else |
| 467 | + { |
| 468 | + phydev_info(phydevs[0], "CRC check good on image file (0x%04X)\n", crc16Calculated); |
| 469 | + } |
| 470 | + |
| 471 | + /*-------------------------------- Check the provisioning table image integrity ----------------------------------*/ |
| 472 | + if (provTableSizePointer != NULL && provTableImage != NULL) |
| 473 | + { |
| 474 | + provTableImageSize = (*provTableSizePointer) - 2; |
| 475 | + provTableFileCRC = provTableImage[provTableImageSize + 1] << 8 | |
| 476 | + provTableImage[provTableImageSize]; |
| 477 | + |
| 478 | + provTableCrc16Calculated = 0x0000; |
| 479 | + for (i = 0; i < provTableImageSize; i++) |
| 480 | + { |
| 481 | + provTableCrc16Calculated = ((provTableCrc16Calculated & 0xFF) << 8) ^ |
| 482 | + AQ_CRC16Table[(provTableCrc16Calculated >> 8) ^ provTableImage[i]]; |
| 483 | + } |
| 484 | + |
| 485 | + if (provTableCrc16Calculated != provTableFileCRC) |
| 486 | + { |
| 487 | + phydev_err(phydevs[0], "CRC check failed on provisioning table file (expected 0x%X, found 0x%X)\n", |
| 488 | + provTableFileCRC, provTableCrc16Calculated); |
| 489 | + result[0] = -EINVAL; |
| 490 | + return -EINVAL; |
| 491 | + } |
| 492 | + else |
| 493 | + { |
| 494 | + phydev_info(phydevs[0], "CRC check good on provisioning table file (0x%04X)\n", |
| 495 | + provTableCrc16Calculated); |
| 496 | + } |
| 497 | + } |
| 498 | + |
| 499 | + /*--------------------------- Store 1E.C441 values for later use. Enforce uniformity. ---------------------------*/ |
| 500 | + for (j = 0; j < num_phydevs; j++) |
| 501 | + { |
| 502 | + /* Record the original value of AQ_GlobalGeneralProvisioning.u1.word_1, |
| 503 | + * so that we can restore it later after exiting gangload mode. */ |
| 504 | + recordedGGP1Values[j] = phy_read_mmd(phydevs[j], MDIO_MMD_VEND1, VEND1_GENERAL_PROV2); |
| 505 | + |
| 506 | + /* If any of the PHYs' GGP1 values don't match the others, set the appropriate |
| 507 | + * error code and return. */ |
| 508 | + if (j > 0 && recordedGGP1Values[j] != recordedGGP1Values[0]) |
| 509 | + { |
| 510 | + phydev_err(phydevs[j], "Non-uniform value of 1E.C441 found (expected 0x%X, found 0x%X)\n", |
| 511 | + recordedGGP1Values[0], recordedGGP1Values[j]); |
| 512 | + result[j] = -EINVAL; |
| 513 | + return -EINVAL; |
| 514 | + } |
| 515 | + } |
| 516 | + |
| 517 | + /*--------------------------- Put each PHY into gangload mode at the specified address ---------------------------*/ |
| 518 | + for (j = 0; j < num_phydevs; j++) { |
| 519 | + AQ_API_EnableMDIO_BootLoadMode(phydevs[j], 0); |
| 520 | + AQ_API_EnableGangLoadMode(phydevs[j], gandload_phydev->mdio.addr); |
| 521 | + } |
| 522 | + |
| 523 | + /*------------------------------------- Stall the uP ------------------------------------------------------------*/ |
| 524 | + globalControl = 0x0000; |
| 525 | + globalControl |= VEND1_CONTROL2_UP_RUNSTALL_OVERRIDE; |
| 526 | + globalControl |= VEND1_CONTROL2_UP_RUNSTALL; |
| 527 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_CONTROL2, globalControl); |
| 528 | + |
| 529 | + /*------------------------------------- Initialize the mailbox write command -------------------------------------*/ |
| 530 | + mailboxWrite = 0x0000; |
| 531 | + mailboxWrite |= VEND1_MAILBOX_INTERFACE1_WRITE; |
| 532 | + mailboxWrite |= VEND1_MAILBOX_INTERFACE1_START; |
| 533 | + |
| 534 | + /*------------------------------------- Read the segment addresses and sizes -------------------------------------*/ |
| 535 | + primaryHeaderPtr = (((image[0x9] & 0x0F) << 8) | image[0x8]) << 12; |
| 536 | + |
| 537 | + /* setup image header content offset for HHD/EUR/CAL/RHEA */ |
| 538 | + phyImageHeaderContentOffset = AQ_PHY_IMAGE_HEADER_CONTENT_OFFSET_HHD; |
| 539 | + |
| 540 | + primaryIramPtr = (image[primaryHeaderPtr + phyImageHeaderContentOffset + 0x4 + 2] << 16) | |
| 541 | + (image[primaryHeaderPtr + phyImageHeaderContentOffset + 0x4 + 1] << 8) | |
| 542 | + image[primaryHeaderPtr + phyImageHeaderContentOffset + 0x4]; |
| 543 | + primaryIramSize = (image[primaryHeaderPtr + phyImageHeaderContentOffset + 0x7 + 2] << 16) | |
| 544 | + (image[primaryHeaderPtr + phyImageHeaderContentOffset + 0x7 + 1] << 8) | |
| 545 | + image[primaryHeaderPtr + phyImageHeaderContentOffset + 0x7]; |
| 546 | + primaryDramPtr = (image[primaryHeaderPtr + phyImageHeaderContentOffset + 0xA + 2] << 16) | |
| 547 | + (image[primaryHeaderPtr + phyImageHeaderContentOffset + 0xA + 1] << 8) | |
| 548 | + image[primaryHeaderPtr + phyImageHeaderContentOffset + 0xA]; |
| 549 | + primaryDramSize = (image[primaryHeaderPtr + phyImageHeaderContentOffset + 0xD + 2] << 16) | |
| 550 | + (image[primaryHeaderPtr + phyImageHeaderContentOffset + 0xD + 1] << 8) | |
| 551 | + image[primaryHeaderPtr + phyImageHeaderContentOffset + 0xD]; |
| 552 | + |
| 553 | + /* setup primary image pointer for HHD/EUR/CAL/RHEA */ |
| 554 | + primaryIramPtr += primaryHeaderPtr; |
| 555 | + primaryDramPtr += primaryHeaderPtr; |
| 556 | + |
| 557 | + phydev_info(gandload_phydev, "Segment Addresses and Sizes as read from the PHY ROM image header:\n"); |
| 558 | + phydev_info(gandload_phydev, "Primary Iram Address: 0x%x\n", primaryIramPtr); |
| 559 | + phydev_info(gandload_phydev, "Primary Iram Size: 0x%x\n", primaryIramSize); |
| 560 | + phydev_info(gandload_phydev, "Primary Dram Address: 0x%x\n", primaryDramPtr); |
| 561 | + phydev_info(gandload_phydev, "Primary Dram Size: 0x%x\n", primaryDramSize); |
| 562 | + |
| 563 | + /*------------------ Prepare to merge the provisioning table into the main image ---------------------------------*/ |
| 564 | + if (provTableSizePointer != NULL && provTableImage != NULL) |
| 565 | + { |
| 566 | + /* Locate the terminator of the built-in provisioning table */ |
| 567 | + terminatorPtr = primaryDramPtr + |
| 568 | + ((image[primaryDramPtr + AQ_PHY_IMAGE_PROVTABLE_TERM_OFFSET + 1] << 8) | |
| 569 | + image[primaryDramPtr + AQ_PHY_IMAGE_PROVTABLE_TERM_OFFSET]); |
| 570 | + |
| 571 | + phydev_info(gandload_phydev, "Supplied Provisioning Table At Address: 0x%x\n\n", terminatorPtr); |
| 572 | + |
| 573 | + /* Check that the supplied provisioning table will fit within the alloted |
| 574 | + * space. */ |
| 575 | + if (terminatorPtr - (primaryDramPtr + AQ_PHY_IMAGE_PROVTABLE_OFFSET) + |
| 576 | + provTableImageSize > AQ_PHY_IMAGE_PROVTABLE_MAXSIZE) |
| 577 | + { |
| 578 | + result[0] = -EINVAL; |
| 579 | + return -EINVAL; |
| 580 | + } |
| 581 | + } |
| 582 | + |
| 583 | + /*------------------------------------- Load IRAM and DRAM -------------------------------------------------------*/ |
| 584 | + /* clear the mailbox CRC */ |
| 585 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE1, VEND1_MAILBOX_INTERFACE1_RESET_CRC); |
| 586 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE1, 0x0000); |
| 587 | + |
| 588 | + crc16Calculated = 0; /* This is to calculate what was written through the mailbox */ |
| 589 | + |
| 590 | + if (!dramOnly) |
| 591 | + { |
| 592 | + /* load the IRAM */ |
| 593 | + phydev_info(gandload_phydev, "Loading IRAM:\n"); |
| 594 | + |
| 595 | + /* dWord align the address: note the image addressing is byte based, but is properly aligned on dWord |
| 596 | + boundaries, so the 2 LSbits of the block start are always zero. */ |
| 597 | + msw = (uint16_t) (AQ_IRAM_BASE_ADDRESS >> 16); |
| 598 | + lsw = (AQ_IRAM_BASE_ADDRESS & 0xFFFF) >> 2; |
| 599 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE3, msw); |
| 600 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE4, lsw); |
| 601 | + |
| 602 | + /* set block size so that there are from 0-3 bytes remaining */ |
| 603 | + byteSize = primaryIramSize; |
| 604 | + dWordSize = byteSize >> 2; |
| 605 | + |
| 606 | + bytePointer = primaryIramPtr; |
| 607 | + #ifdef AQ_PHY_SUPPORTS_BLOCK_READ_WRITE |
| 608 | + countPendingOps = 0; |
| 609 | + #endif |
| 610 | + for (i = 0; i < dWordSize; i++) |
| 611 | + { |
| 612 | + /* write 4 bytes of data */ |
| 613 | + if (terminatorPtr && (bytePointer >= terminatorPtr) && (bytePointer < terminatorPtr + provTableImageSize)) |
| 614 | + lsw = provTableImage[bytePointer - terminatorPtr]; |
| 615 | + else |
| 616 | + lsw = image[bytePointer]; |
| 617 | + |
| 618 | + if (terminatorPtr && ((bytePointer+1) >= terminatorPtr) && ((bytePointer+1) < terminatorPtr + provTableImageSize)) |
| 619 | + lsw |= provTableImage[bytePointer + 1 - terminatorPtr] << 8; |
| 620 | + else |
| 621 | + lsw |= image[bytePointer+1] << 8; |
| 622 | + |
| 623 | + bytePointer += 2; |
| 624 | + |
| 625 | + if (terminatorPtr && (bytePointer >= terminatorPtr) && (bytePointer < terminatorPtr + provTableImageSize)) |
| 626 | + msw = provTableImage[bytePointer - terminatorPtr]; |
| 627 | + else |
| 628 | + msw = image[bytePointer]; |
| 629 | + |
| 630 | + if (terminatorPtr && ((bytePointer+1) >= terminatorPtr) && ((bytePointer+1) < terminatorPtr + provTableImageSize)) |
| 631 | + msw |= provTableImage[bytePointer + 1 - terminatorPtr] << 8; |
| 632 | + else |
| 633 | + msw |= image[bytePointer+1] << 8; |
| 634 | + |
| 635 | + bytePointer += 2; |
| 636 | + |
| 637 | + #ifdef AQ_PHY_SUPPORTS_BLOCK_READ_WRITE |
| 638 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE5, msw); |
| 639 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE6, lsw); |
| 640 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE1, mailboxWrite); |
| 641 | + |
| 642 | + countPendingOps += 3; |
| 643 | + /* Check if we've filled our output buffer, and if so, flush. */ |
| 644 | + #ifdef AQ_EXTRA_FLAGS |
| 645 | + if (countPendingOps >= AQ_API_MDIO_MaxBlockOperations(0) - 3) |
| 646 | + #else |
| 647 | + if (countPendingOps >= AQ_API_MDIO_MaxBlockOperations() - 3) |
| 648 | + #endif |
| 649 | + { |
| 650 | + AQ_API_MDIO_BlockOperationExecute(gandload_phydev); |
| 651 | + countPendingOps = 0; |
| 652 | + } |
| 653 | + #else |
| 654 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE5, msw); |
| 655 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE6, lsw); |
| 656 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE1, mailboxWrite); |
| 657 | + #endif |
| 658 | + |
| 659 | + /* update the calculated CRC */ |
| 660 | + crc16Calculated = ((crc16Calculated & 0xFF) << 8) ^ AQ_CRC16Table[(crc16Calculated >> 8) ^ (msw >> 8)]; |
| 661 | + crc16Calculated = ((crc16Calculated & 0xFF) << 8) ^ AQ_CRC16Table[(crc16Calculated >> 8) ^ (msw & 0xFF)]; |
| 662 | + crc16Calculated = ((crc16Calculated & 0xFF) << 8) ^ AQ_CRC16Table[(crc16Calculated >> 8) ^ (lsw >> 8)]; |
| 663 | + crc16Calculated = ((crc16Calculated & 0xFF) << 8) ^ AQ_CRC16Table[(crc16Calculated >> 8) ^ (lsw & 0xFF)]; |
| 664 | + |
| 665 | + #ifdef AQ_VERBOSE |
| 666 | + if (i && ((i % 512) == 0)) phydev_info(gandload_phydev, " Byte: %X:\n", i << 2); |
| 667 | + #endif |
| 668 | + } |
| 669 | + |
| 670 | + #ifdef AQ_PHY_SUPPORTS_BLOCK_READ_WRITE |
| 671 | + /* flush the output buffer one last time. */ |
| 672 | + AQ_API_MDIO_BlockOperationExecute(gandload_phydev); |
| 673 | + countPendingOps = 0; |
| 674 | + #endif |
| 675 | + |
| 676 | + /* Note: this final write right-justifies non-dWord data in the final dWord */ |
| 677 | + switch (byteSize & 0x3) |
| 678 | + { |
| 679 | + case 0x1: |
| 680 | + /* write 1 byte of data */ |
| 681 | + if (terminatorPtr && (bytePointer >= terminatorPtr) && (bytePointer < terminatorPtr + provTableImageSize)) |
| 682 | + lsw = provTableImage[bytePointer - terminatorPtr]; |
| 683 | + else |
| 684 | + lsw = image[bytePointer]; |
| 685 | + |
| 686 | + bytePointer += 1; |
| 687 | + |
| 688 | + msw = 0x0000; |
| 689 | + |
| 690 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE5, msw); |
| 691 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE6, lsw); |
| 692 | + |
| 693 | + /* no polling */ |
| 694 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE1, mailboxWrite); |
| 695 | + break; |
| 696 | + |
| 697 | + case 0x2: |
| 698 | + /* write 2 bytes of data */ |
| 699 | + if (terminatorPtr && (bytePointer >= terminatorPtr) && (bytePointer < terminatorPtr + provTableImageSize)) |
| 700 | + lsw = provTableImage[bytePointer - terminatorPtr]; |
| 701 | + else |
| 702 | + lsw = image[bytePointer]; |
| 703 | + |
| 704 | + if (terminatorPtr && ((bytePointer+1) >= terminatorPtr) && ((bytePointer+1) < terminatorPtr + provTableImageSize)) |
| 705 | + lsw |= provTableImage[bytePointer + 1 - terminatorPtr] << 8; |
| 706 | + else |
| 707 | + lsw |= image[bytePointer+1] << 8; |
| 708 | + |
| 709 | + bytePointer += 2; |
| 710 | + |
| 711 | + msw = 0x0000; |
| 712 | + |
| 713 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE5, msw); |
| 714 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE6, lsw); |
| 715 | + |
| 716 | + /* no polling */ |
| 717 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE1, mailboxWrite); |
| 718 | + break; |
| 719 | + |
| 720 | + case 0x3: |
| 721 | + /* write 3 bytes of data */ |
| 722 | + if (terminatorPtr && (bytePointer >= terminatorPtr) && (bytePointer < terminatorPtr + provTableImageSize)) |
| 723 | + lsw = provTableImage[bytePointer - terminatorPtr]; |
| 724 | + else |
| 725 | + lsw = image[bytePointer]; |
| 726 | + |
| 727 | + if (terminatorPtr && ((bytePointer+1) >= terminatorPtr) && ((bytePointer+1) < terminatorPtr + provTableImageSize)) |
| 728 | + lsw |= provTableImage[bytePointer + 1 - terminatorPtr] << 8; |
| 729 | + else |
| 730 | + lsw |= image[bytePointer+1] << 8; |
| 731 | + |
| 732 | + bytePointer += 2; |
| 733 | + |
| 734 | + if (terminatorPtr && (bytePointer >= terminatorPtr) && (bytePointer < terminatorPtr + provTableImageSize)) |
| 735 | + msw = provTableImage[bytePointer - terminatorPtr]; |
| 736 | + else |
| 737 | + msw = image[bytePointer]; |
| 738 | + |
| 739 | + bytePointer += 1; |
| 740 | + |
| 741 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE5, msw); |
| 742 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE6, lsw); |
| 743 | + |
| 744 | + /* no polling */ |
| 745 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE1, mailboxWrite); |
| 746 | + break; |
| 747 | + } |
| 748 | + |
| 749 | + if (byteSize & 0x3) |
| 750 | + { |
| 751 | + /* update the calculated CRC */ |
| 752 | + crc16Calculated = ((crc16Calculated & 0xFF) << 8) ^ AQ_CRC16Table[(crc16Calculated >> 8) ^ (msw >> 8)]; |
| 753 | + crc16Calculated = ((crc16Calculated & 0xFF) << 8) ^ AQ_CRC16Table[(crc16Calculated >> 8) ^ (msw & 0xFF)]; |
| 754 | + crc16Calculated = ((crc16Calculated & 0xFF) << 8) ^ AQ_CRC16Table[(crc16Calculated >> 8) ^ (lsw >> 8)]; |
| 755 | + crc16Calculated = ((crc16Calculated & 0xFF) << 8) ^ AQ_CRC16Table[(crc16Calculated >> 8) ^ (lsw & 0xFF)]; |
| 756 | + } |
| 757 | + |
| 758 | + phydev_info(gandload_phydev, "CRC-16 after loading IRAM: 0x%X\n", crc16Calculated); |
| 759 | + } |
| 760 | + |
| 761 | + /* load the DRAM */ |
| 762 | + phydev_info(gandload_phydev, "Loading DRAM:\n"); |
| 763 | + |
| 764 | + /* dWord align the address: note the image addressing is byte based, but is properly aligned on dWord |
| 765 | + boundaries, so the 2 LSbits of the block start are always zero. */ |
| 766 | + msw = (uint16_t) (AQ_DRAM_BASE_ADDRESS >> 16); |
| 767 | + lsw = (AQ_DRAM_BASE_ADDRESS & 0xFFFF) >> 2; |
| 768 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE3, msw); |
| 769 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE4, lsw); |
| 770 | + |
| 771 | + /* set block size so that there are from 0-3 bytes remaining */ |
| 772 | + byteSize = primaryDramSize; |
| 773 | + dWordSize = byteSize >> 2; |
| 774 | + |
| 775 | + bytePointer = primaryDramPtr; |
| 776 | +#ifdef AQ_PHY_SUPPORTS_BLOCK_READ_WRITE |
| 777 | + countPendingOps = 0; |
| 778 | +#endif |
| 779 | + for (i = 0; i < dWordSize; i++) |
| 780 | + { |
| 781 | + /* write 4 bytes of data */ |
| 782 | + if (terminatorPtr && (bytePointer >= terminatorPtr) && (bytePointer < terminatorPtr + provTableImageSize)) |
| 783 | + lsw = provTableImage[bytePointer - terminatorPtr]; |
| 784 | + else |
| 785 | + lsw = image[bytePointer]; |
| 786 | + |
| 787 | + if (terminatorPtr && ((bytePointer+1) >= terminatorPtr) && ((bytePointer+1) < terminatorPtr + provTableImageSize)) |
| 788 | + lsw |= provTableImage[bytePointer + 1 - terminatorPtr] << 8; |
| 789 | + else |
| 790 | + lsw |= image[bytePointer+1] << 8; |
| 791 | + |
| 792 | + bytePointer += 2; |
| 793 | + |
| 794 | + if (terminatorPtr && (bytePointer >= terminatorPtr) && (bytePointer < terminatorPtr + provTableImageSize)) |
| 795 | + msw = provTableImage[bytePointer - terminatorPtr]; |
| 796 | + else |
| 797 | + msw = image[bytePointer]; |
| 798 | + |
| 799 | + if (terminatorPtr && ((bytePointer+1) >= terminatorPtr) && ((bytePointer+1) < terminatorPtr + provTableImageSize)) |
| 800 | + msw |= provTableImage[bytePointer + 1 - terminatorPtr] << 8; |
| 801 | + else |
| 802 | + msw |= image[bytePointer+1] << 8; |
| 803 | + |
| 804 | + bytePointer += 2; |
| 805 | + |
| 806 | + #ifdef AQ_PHY_SUPPORTS_BLOCK_READ_WRITE |
| 807 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE5, msw); |
| 808 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE6, lsw); |
| 809 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE1, mailboxWrite); |
| 810 | + |
| 811 | + countPendingOps += 3; |
| 812 | + /* Check if we've filled our output buffer, and if so, flush. */ |
| 813 | + #ifdef AQ_EXTRA_FLAGS |
| 814 | + if (countPendingOps >= AQ_API_MDIO_MaxBlockOperations(0) - 3) |
| 815 | + #else |
| 816 | + if (countPendingOps >= AQ_API_MDIO_MaxBlockOperations() - 3) |
| 817 | + #endif |
| 818 | + { |
| 819 | + AQ_API_MDIO_BlockOperationExecute(gandload_phydev); |
| 820 | + countPendingOps = 0; |
| 821 | + } |
| 822 | + #else |
| 823 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE5, msw); |
| 824 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE6, lsw); |
| 825 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE1, mailboxWrite); |
| 826 | + #endif |
| 827 | + |
| 828 | + /* update the calculated CRC */ |
| 829 | + crc16Calculated = ((crc16Calculated & 0xFF) << 8) ^ AQ_CRC16Table[(crc16Calculated >> 8) ^ (msw >> 8)]; |
| 830 | + crc16Calculated = ((crc16Calculated & 0xFF) << 8) ^ AQ_CRC16Table[(crc16Calculated >> 8) ^ (msw & 0xFF)]; |
| 831 | + crc16Calculated = ((crc16Calculated & 0xFF) << 8) ^ AQ_CRC16Table[(crc16Calculated >> 8) ^ (lsw >> 8)]; |
| 832 | + crc16Calculated = ((crc16Calculated & 0xFF) << 8) ^ AQ_CRC16Table[(crc16Calculated >> 8) ^ (lsw & 0xFF)]; |
| 833 | + |
| 834 | + #ifdef AQ_VERBOSE |
| 835 | + if (i && ((i % 512) == 0)) phydev_info(gandload_phydev, " Byte: %X:\n", i << 2); |
| 836 | + #endif |
| 837 | + } |
| 838 | + |
| 839 | + #ifdef AQ_PHY_SUPPORTS_BLOCK_READ_WRITE |
| 840 | + /* flush the output buffer one last time. */ |
| 841 | + AQ_API_MDIO_BlockOperationExecute(gandload_phydev); |
| 842 | + countPendingOps = 0; |
| 843 | + #endif |
| 844 | + |
| 845 | + /* Note: this final write right-justifies non-dWord data in the final dWord */ |
| 846 | + switch (byteSize & 0x3) |
| 847 | + { |
| 848 | + case 0x1: |
| 849 | + /* write 1 byte of data */ |
| 850 | + if (terminatorPtr && (bytePointer >= terminatorPtr) && (bytePointer < terminatorPtr + provTableImageSize)) |
| 851 | + lsw = provTableImage[bytePointer - terminatorPtr]; |
| 852 | + else |
| 853 | + lsw = image[bytePointer]; |
| 854 | + |
| 855 | + bytePointer += 1; |
| 856 | + |
| 857 | + msw = 0x0000; |
| 858 | + |
| 859 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE5, msw); |
| 860 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE6, lsw); |
| 861 | + |
| 862 | + /* no polling */ |
| 863 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE1, mailboxWrite); |
| 864 | + break; |
| 865 | + |
| 866 | + case 0x2: |
| 867 | + /* write 2 bytes of data */ |
| 868 | + if (terminatorPtr && (bytePointer >= terminatorPtr) && (bytePointer < terminatorPtr + provTableImageSize)) |
| 869 | + lsw = provTableImage[bytePointer - terminatorPtr]; |
| 870 | + else |
| 871 | + lsw = image[bytePointer]; |
| 872 | + |
| 873 | + if (terminatorPtr && ((bytePointer+1) >= terminatorPtr) && ((bytePointer+1) < terminatorPtr + provTableImageSize)) |
| 874 | + lsw |= provTableImage[bytePointer + 1 - terminatorPtr] << 8; |
| 875 | + else |
| 876 | + lsw |= image[bytePointer+1] << 8; |
| 877 | + |
| 878 | + bytePointer += 2; |
| 879 | + |
| 880 | + msw = 0x0000; |
| 881 | + |
| 882 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE5, msw); |
| 883 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE6, lsw); |
| 884 | + |
| 885 | + /* no polling */ |
| 886 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE1, mailboxWrite); |
| 887 | + break; |
| 888 | + |
| 889 | + case 0x3: |
| 890 | + /* write 3 bytes of data */ |
| 891 | + if (terminatorPtr && (bytePointer >= terminatorPtr) && (bytePointer < terminatorPtr + provTableImageSize)) |
| 892 | + lsw = provTableImage[bytePointer - terminatorPtr]; |
| 893 | + else |
| 894 | + lsw = image[bytePointer]; |
| 895 | + |
| 896 | + if (terminatorPtr && ((bytePointer+1) >= terminatorPtr) && ((bytePointer+1) < terminatorPtr + provTableImageSize)) |
| 897 | + lsw |= provTableImage[bytePointer + 1 - terminatorPtr] << 8; |
| 898 | + else |
| 899 | + lsw |= image[bytePointer+1] << 8; |
| 900 | + |
| 901 | + bytePointer += 2; |
| 902 | + |
| 903 | + msw = image[bytePointer]; |
| 904 | + bytePointer += 1; |
| 905 | + |
| 906 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE5, msw); |
| 907 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE6, lsw); |
| 908 | + |
| 909 | + /* no polling */ |
| 910 | + phy_write_mmd(gandload_phydev, MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE1, mailboxWrite); |
| 911 | + break; |
| 912 | + } |
| 913 | + |
| 914 | + if (byteSize & 0x3) |
| 915 | + { |
| 916 | + /* update the calculated CRC */ |
| 917 | + crc16Calculated = ((crc16Calculated & 0xFF) << 8) ^ AQ_CRC16Table[(crc16Calculated >> 8) ^ (msw >> 8)]; |
| 918 | + crc16Calculated = ((crc16Calculated & 0xFF) << 8) ^ AQ_CRC16Table[(crc16Calculated >> 8) ^ (msw & 0xFF)]; |
| 919 | + crc16Calculated = ((crc16Calculated & 0xFF) << 8) ^ AQ_CRC16Table[(crc16Calculated >> 8) ^ (lsw >> 8)]; |
| 920 | + crc16Calculated = ((crc16Calculated & 0xFF) << 8) ^ AQ_CRC16Table[(crc16Calculated >> 8) ^ (lsw & 0xFF)]; |
| 921 | + } |
| 922 | + |
| 923 | + /*------------------------------------- Exit gangload mode -------------------------------------------------------*/ |
| 924 | + AQ_API_DisableGangLoadMode(gandload_phydev, recordedGGP1Values[0]); |
| 925 | + |
| 926 | + /*------------------------------------- Check mailbox CRCs -------------------------------------------------------*/ |
| 927 | + /* check to make sure the mailbox CRC matches the calculated CRC */ |
| 928 | + for (j = 0; j < num_phydevs; j++) { |
| 929 | + mailboxCRC = phy_read_mmd(phydevs[j], MDIO_MMD_VEND1, VEND1_MAILBOX_INTERFACE2); |
| 930 | + if (mailboxCRC != crc16Calculated) |
| 931 | + { |
| 932 | + phydev_err(phydevs[j], "%uth port: Mailbox CRC-16 (0x%X) does not match calculated CRC-16 (0x%X)\n", |
| 933 | + j, mailboxCRC, crc16Calculated); |
| 934 | + result[j] = -EIO; |
| 935 | + } |
| 936 | + else |
| 937 | + { |
| 938 | + phydev_info(phydevs[j], "%uth port: Image load good - mailbox CRC-16 matches (0x%X)\n", |
| 939 | + j, mailboxCRC); |
| 940 | + } |
| 941 | + } |
| 942 | + |
| 943 | + /*------------------------------------- Clear any resets ---------------------------------------------------------*/ |
| 944 | + for (j = 0; j < num_phydevs; j++) { |
| 945 | + phy_write_mmd(phydevs[j], MDIO_MMD_VEND1, VEND1_STD_CONTROL1, 0x0000); |
| 946 | + } |
| 947 | + |
| 948 | + /*------------------------------------- Release the uP -----------------------------------------------------------*/ |
| 949 | + globalControl = 0x0000; |
| 950 | + globalControl |= VEND1_CONTROL2_UP_RUNSTALL_OVERRIDE; |
| 951 | + globalControl |= VEND1_CONTROL2_UP_RUNSTALL; |
| 952 | + for (j = 0; j < num_phydevs; j++) { |
| 953 | + globalControl &= ~VEND1_CONTROL2_UP_RESET; |
| 954 | + phy_write_mmd(phydevs[j], MDIO_MMD_VEND1, VEND1_CONTROL2, globalControl); |
| 955 | + globalControl |= VEND1_CONTROL2_UP_RESET; |
| 956 | + phy_write_mmd(phydevs[j], MDIO_MMD_VEND1, VEND1_CONTROL2, globalControl); |
| 957 | + } |
| 958 | + |
| 959 | + /* Need to wait at least 100us. */ |
| 960 | + udelay(100); |
| 961 | + |
| 962 | + globalControl &= ~VEND1_CONTROL2_UP_RESET; |
| 963 | + globalControl &= ~VEND1_CONTROL2_UP_RUNSTALL; |
| 964 | + /* For post-APPIA devices, always set the uP stall override bit to |
| 965 | + * smooth over any packaging differences WRT the boot load pin. */ |
| 966 | + /* REGDOC: Assign to local representation of bitfield (HHD/APPIA/EUR/CAL/RHEA: 1E.C001.6) */ |
| 967 | + globalControl |= VEND1_CONTROL2_UP_RUNSTALL_OVERRIDE; |
| 968 | + |
| 969 | + for (j = 0; j < num_phydevs; j++) { |
| 970 | + phy_write_mmd(phydevs[j], MDIO_MMD_VEND1, VEND1_CONTROL2, globalControl); |
| 971 | + } |
| 972 | + |
| 973 | + /* NOTE!!! We can't re-enable the daisy-chain here, as this will overwrite the IRAM and DRAM with the FLASH contents*/ |
| 974 | + |
| 975 | + /* If any of the ports was not bootloaded successfully, return AQ_RET_ERROR */ |
| 976 | + for (j = 0; j < num_phydevs; j++) { |
| 977 | + if (result[j] != 0) |
| 978 | + return -EIO; |
| 979 | + } |
| 980 | + |
| 981 | + /* All ports were bootloaded successfully. */ |
| 982 | + return 0; |
| 983 | +} |
| 984 | + |
| 985 | +static int AQ_API_WriteBootLoadImage( |
| 986 | + struct phy_device **phydevs, |
| 987 | + int num_phydevs, |
| 988 | + struct phy_device *gandload_phydev, |
| 989 | + int *result, |
| 990 | + const uint8_t* data, |
| 991 | + size_t size) |
| 992 | +{ |
| 993 | + unsigned int val; |
| 994 | + int j; |
| 995 | + |
| 996 | + for (j = 0; j < num_phydevs; j++) { |
developer | 3c737eb | 2022-12-09 09:44:16 +0800 | [diff] [blame] | 997 | + /* stall the uP */ |
| 998 | + val = phy_read_mmd(phydevs[j], MDIO_MMD_VEND1, VEND1_CONTROL2); |
| 999 | + val |= VEND1_CONTROL2_UP_RUNSTALL_OVERRIDE; |
| 1000 | + val |= VEND1_CONTROL2_UP_RUNSTALL; |
| 1001 | + phy_write_mmd(phydevs[j], MDIO_MMD_VEND1, VEND1_CONTROL2, val); |
| 1002 | + |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1003 | + /* disable the S/W reset to the Global MMD registers */ |
| 1004 | + val = phy_read_mmd(phydevs[j], MDIO_MMD_VEND1, VEND1_RESET_CONTROL); |
| 1005 | + val |= VEND1_RESET_CONTROL_MMD_RESET_DISABLE; |
| 1006 | + phy_write_mmd(phydevs[j], MDIO_MMD_VEND1, VEND1_RESET_CONTROL, val); |
| 1007 | + |
developer | 3c737eb | 2022-12-09 09:44:16 +0800 | [diff] [blame] | 1008 | + /* de-assert Global S/W reset */ |
| 1009 | + val = phy_read_mmd(phydevs[j], MDIO_MMD_VEND1, VEND1_STD_CONTROL1); |
| 1010 | + val &= ~VEND1_STD_CONTROL1_SOFT_RESET; |
| 1011 | + phy_write_mmd(phydevs[j], MDIO_MMD_VEND1, VEND1_STD_CONTROL1, val); |
| 1012 | + |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1013 | + /* assert Global S/W reset */ |
| 1014 | + val = phy_read_mmd(phydevs[j], MDIO_MMD_VEND1, VEND1_STD_CONTROL1); |
| 1015 | + val |= VEND1_STD_CONTROL1_SOFT_RESET; |
| 1016 | + phy_write_mmd(phydevs[j], MDIO_MMD_VEND1, VEND1_STD_CONTROL1, val); |
| 1017 | + |
| 1018 | + /* de-assert Global S/W reset */ |
| 1019 | + val = phy_read_mmd(phydevs[j], MDIO_MMD_VEND1, VEND1_STD_CONTROL1); |
| 1020 | + val &= ~VEND1_STD_CONTROL1_SOFT_RESET; |
| 1021 | + phy_write_mmd(phydevs[j], MDIO_MMD_VEND1, VEND1_STD_CONTROL1, val); |
| 1022 | + |
| 1023 | + /* wait 100ms */ |
| 1024 | + mdelay(100); |
| 1025 | + |
| 1026 | + /* enable the S/W reset to the Global MMD registers */ |
| 1027 | + val = phy_read_mmd(phydevs[j], MDIO_MMD_VEND1, VEND1_RESET_CONTROL); |
| 1028 | + val &= ~VEND1_RESET_CONTROL_MMD_RESET_DISABLE; |
| 1029 | + phy_write_mmd(phydevs[j], MDIO_MMD_VEND1, VEND1_RESET_CONTROL, val); |
| 1030 | + } |
| 1031 | + |
| 1032 | + return AQ_API_WriteBootLoadImage_impl(phydevs, num_phydevs, gandload_phydev, |
| 1033 | + result, (const uint32_t *)&size, data, |
| 1034 | + NULL, NULL, 0); |
| 1035 | +} |
| 1036 | + |
developer | aafac65 | 2023-01-18 09:41:27 +0800 | [diff] [blame] | 1037 | +static int aqr_firmware_check_heartbeat(struct phy_device *phydev) |
| 1038 | +{ |
developer | 7ddeff0 | 2023-03-22 15:28:46 +0800 | [diff] [blame] | 1039 | + struct aqr107_priv *priv = phydev->priv; |
| 1040 | + int stopped = 0, ret; |
developer | aafac65 | 2023-01-18 09:41:27 +0800 | [diff] [blame] | 1041 | + |
| 1042 | + ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_RSVD_STAT2); |
| 1043 | + if (ret < 0) |
| 1044 | + return ret; |
| 1045 | + |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 1046 | + /* heartbeat stopped if the current heartbeat is equal to the previous */ |
developer | 7ddeff0 | 2023-03-22 15:28:46 +0800 | [diff] [blame] | 1047 | + if (priv->heartbeat == ret) |
| 1048 | + stopped = 1; |
developer | aafac65 | 2023-01-18 09:41:27 +0800 | [diff] [blame] | 1049 | + |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 1050 | + /* update heartbeat to the private data */ |
developer | 7ddeff0 | 2023-03-22 15:28:46 +0800 | [diff] [blame] | 1051 | + priv->heartbeat = ret; |
developer | aafac65 | 2023-01-18 09:41:27 +0800 | [diff] [blame] | 1052 | + |
developer | 7ddeff0 | 2023-03-22 15:28:46 +0800 | [diff] [blame] | 1053 | + return stopped; |
developer | aafac65 | 2023-01-18 09:41:27 +0800 | [diff] [blame] | 1054 | +} |
| 1055 | + |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 1056 | +int aqr_firmware_heartbeat_thread(void *data) |
developer | aafac65 | 2023-01-18 09:41:27 +0800 | [diff] [blame] | 1057 | +{ |
| 1058 | + struct phy_device *phydev = data; |
| 1059 | + struct aqr107_priv *priv = phydev->priv; |
developer | 7ddeff0 | 2023-03-22 15:28:46 +0800 | [diff] [blame] | 1060 | + struct device *dev; |
developer | aafac65 | 2023-01-18 09:41:27 +0800 | [diff] [blame] | 1061 | + int ret = 0; |
| 1062 | + |
developer | 7ddeff0 | 2023-03-22 15:28:46 +0800 | [diff] [blame] | 1063 | + dev = &phydev->mdio.dev; |
| 1064 | + |
developer | aafac65 | 2023-01-18 09:41:27 +0800 | [diff] [blame] | 1065 | + for (;;) { |
| 1066 | + if (kthread_should_stop()) |
| 1067 | + break; |
| 1068 | + |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 1069 | + if (priv->fw_initialized == true && |
developer | a361767 | 2023-01-31 10:46:41 +0800 | [diff] [blame] | 1070 | + aqr_firmware_check_heartbeat(phydev) == 1) { |
developer | 7ddeff0 | 2023-03-22 15:28:46 +0800 | [diff] [blame] | 1071 | + dev_err(dev, "Detect heartbeat stopped, start to realod firmware...\n"); |
developer | 93ef6f0 | 2023-08-31 16:09:24 +0800 | [diff] [blame] | 1072 | + aqr_firmware_download_single(phydev, true); |
developer | aafac65 | 2023-01-18 09:41:27 +0800 | [diff] [blame] | 1073 | + } |
| 1074 | + |
| 1075 | + set_current_state(TASK_INTERRUPTIBLE); |
developer | 05838f0 | 2023-03-23 15:54:37 +0800 | [diff] [blame] | 1076 | + schedule_timeout(2 * HZ); |
developer | aafac65 | 2023-01-18 09:41:27 +0800 | [diff] [blame] | 1077 | + } |
| 1078 | + |
| 1079 | + return ret; |
| 1080 | +} |
| 1081 | + |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1082 | +static void aqr_firmware_download_cb(const struct firmware *fw, void *context) |
| 1083 | +{ |
| 1084 | + struct phy_device **phydevs = context; |
| 1085 | + struct phy_device *gandload_phydev = phydevs[0]; |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 1086 | + struct device *dev = &phydevs[0]->mdio.dev; |
developer | 093e9b3 | 2022-12-13 16:08:34 +0800 | [diff] [blame] | 1087 | + struct aqr107_priv *priv = phydevs[0]->priv; |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1088 | + int result[MAX_GANGLOAD_DEVICES]; |
developer | 093e9b3 | 2022-12-13 16:08:34 +0800 | [diff] [blame] | 1089 | + int i, num_phydevs = 0, ret = 0; |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1090 | + |
developer | 9431640 | 2022-11-21 08:58:41 +0800 | [diff] [blame] | 1091 | + if (!fw) |
| 1092 | + return; |
| 1093 | + |
developer | 93ef6f0 | 2023-08-31 16:09:24 +0800 | [diff] [blame] | 1094 | + spin_lock(&gangload_lock); |
| 1095 | + |
developer | 093e9b3 | 2022-12-13 16:08:34 +0800 | [diff] [blame] | 1096 | + num_phydevs = priv->fw_dl_mode == FW_DL_GNAGLOAD ? |
developer | 9451bcd | 2023-07-18 09:34:05 +0800 | [diff] [blame] | 1097 | + gangload : 1; |
developer | 3c737eb | 2022-12-09 09:44:16 +0800 | [diff] [blame] | 1098 | + |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1099 | +retry: |
developer | 93ef6f0 | 2023-08-31 16:09:24 +0800 | [diff] [blame] | 1100 | + if (gandload_phydev->state == PHY_HALTED && priv->fw_initialized == true) { |
| 1101 | + dev_info(dev, "Detect PHY power down, stop to download firmware...\n"); |
developer | 7ddeff0 | 2023-03-22 15:28:46 +0800 | [diff] [blame] | 1102 | + goto out; |
| 1103 | + } |
| 1104 | + |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1105 | + memset(result, 0, sizeof(result)); |
| 1106 | + |
developer | 093e9b3 | 2022-12-13 16:08:34 +0800 | [diff] [blame] | 1107 | + ret = AQ_API_WriteBootLoadImage(phydevs, num_phydevs, gandload_phydev, |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1108 | + result, fw->data, fw->size); |
| 1109 | + if (ret) { |
developer | 093e9b3 | 2022-12-13 16:08:34 +0800 | [diff] [blame] | 1110 | + for (i = 0; i < num_phydevs; i++) { |
developer | 9431640 | 2022-11-21 08:58:41 +0800 | [diff] [blame] | 1111 | + if (result[i] == 0) |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1112 | + continue; |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1113 | + |
| 1114 | + dev = &phydevs[i]->mdio.dev; |
| 1115 | + dev_err(dev, "failed to download firmware %s, ret: %d\n", |
| 1116 | + AQR_FIRMWARE, ret); |
| 1117 | + goto retry; |
| 1118 | + } |
| 1119 | + } |
| 1120 | + |
developer | 5539829 | 2022-12-14 19:03:08 +0800 | [diff] [blame] | 1121 | + /* wait firmware initialization completed */ |
developer | 9431640 | 2022-11-21 08:58:41 +0800 | [diff] [blame] | 1122 | + mdelay(250); |
developer | 5539829 | 2022-12-14 19:03:08 +0800 | [diff] [blame] | 1123 | + |
developer | 093e9b3 | 2022-12-13 16:08:34 +0800 | [diff] [blame] | 1124 | + for (i = 0; i < num_phydevs; i++) { |
developer | 9431640 | 2022-11-21 08:58:41 +0800 | [diff] [blame] | 1125 | + if (result[i] == 0) { |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 1126 | + dev = &phydevs[i]->mdio.dev; |
developer | 9431640 | 2022-11-21 08:58:41 +0800 | [diff] [blame] | 1127 | + priv = phydevs[i]->priv; |
| 1128 | + priv->fw_initialized = true; |
developer | 3c737eb | 2022-12-09 09:44:16 +0800 | [diff] [blame] | 1129 | + |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 1130 | + aqr107_chip_info(phydevs[i]); |
| 1131 | + |
developer | 9431640 | 2022-11-21 08:58:41 +0800 | [diff] [blame] | 1132 | + aqr107_config_mdi(phydevs[i]); |
developer | 3c737eb | 2022-12-09 09:44:16 +0800 | [diff] [blame] | 1133 | + |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 1134 | + aqr107_set_downshift(phydevs[i], |
| 1135 | + MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT); |
| 1136 | + |
| 1137 | + if (phy_is_started(phydevs[i])) { |
developer | 093e9b3 | 2022-12-13 16:08:34 +0800 | [diff] [blame] | 1138 | + phydevs[i]->state = PHY_UP; |
| 1139 | + phy_queue_state_machine(phydevs[i], 0); |
| 1140 | + } |
developer | 9431640 | 2022-11-21 08:58:41 +0800 | [diff] [blame] | 1141 | + } |
| 1142 | + } |
developer | 93ef6f0 | 2023-08-31 16:09:24 +0800 | [diff] [blame] | 1143 | + |
developer | 7ddeff0 | 2023-03-22 15:28:46 +0800 | [diff] [blame] | 1144 | +out: |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1145 | + release_firmware(fw); |
developer | 93ef6f0 | 2023-08-31 16:09:24 +0800 | [diff] [blame] | 1146 | + |
| 1147 | + spin_unlock(&gangload_lock); |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1148 | +} |
| 1149 | + |
developer | 93ef6f0 | 2023-08-31 16:09:24 +0800 | [diff] [blame] | 1150 | +static int aqr_firmware_download_single(struct phy_device *phydev, bool force_reload) |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1151 | +{ |
| 1152 | + struct aqr107_priv *priv = phydev->priv; |
| 1153 | + struct device *dev = &phydev->mdio.dev; |
developer | 093e9b3 | 2022-12-13 16:08:34 +0800 | [diff] [blame] | 1154 | + const struct firmware *fw; |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1155 | + int ret = 0; |
| 1156 | + |
developer | 93ef6f0 | 2023-08-31 16:09:24 +0800 | [diff] [blame] | 1157 | + if (priv->fw_initialized == true && force_reload == false) |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1158 | + return 0; |
| 1159 | + |
developer | 93ef6f0 | 2023-08-31 16:09:24 +0800 | [diff] [blame] | 1160 | + if (priv->phydevs[0] != phydev) { |
| 1161 | + priv->phydevs[0] = phydev; |
| 1162 | + spin_lock_init(&priv->lock); |
| 1163 | + } |
developer | 093e9b3 | 2022-12-13 16:08:34 +0800 | [diff] [blame] | 1164 | + priv->fw_dl_mode = FW_DL_SINGLE; |
developer | 7ddeff0 | 2023-03-22 15:28:46 +0800 | [diff] [blame] | 1165 | + priv->heartbeat = -1; |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1166 | + |
developer | 093e9b3 | 2022-12-13 16:08:34 +0800 | [diff] [blame] | 1167 | + ret = request_firmware(&fw, AQR_FIRMWARE, dev); |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1168 | + if (ret) { |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 1169 | + dev_err(dev, "failed to request firmware %s, ret: %d\n", |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1170 | + AQR_FIRMWARE, ret); |
| 1171 | + } |
| 1172 | + |
developer | 093e9b3 | 2022-12-13 16:08:34 +0800 | [diff] [blame] | 1173 | + aqr_firmware_download_cb(fw, priv->phydevs); |
| 1174 | + |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1175 | + return ret; |
| 1176 | +} |
| 1177 | + |
| 1178 | +static int aqr_firmware_gandload_thread(void *data) |
| 1179 | +{ |
| 1180 | + struct phy_device **phydevs = data; |
| 1181 | + struct device *dev = &phydevs[0]->mdio.dev; |
| 1182 | + int ret = 0; |
| 1183 | + |
| 1184 | + for (;;) { |
| 1185 | + if (kthread_should_stop()) |
| 1186 | + break; |
| 1187 | + |
developer | 9451bcd | 2023-07-18 09:34:05 +0800 | [diff] [blame] | 1188 | + /* either maximum gangload phy devices or timeout is reached */ |
| 1189 | + if (gangload == MAX_GANGLOAD_DEVICES || |
| 1190 | + time_after(jiffies, gangload_timeout)) { |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1191 | + ret = request_firmware_nowait(THIS_MODULE, true, AQR_FIRMWARE, dev, |
| 1192 | + GFP_KERNEL, phydevs, aqr_firmware_download_cb); |
| 1193 | + if (ret) { |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 1194 | + dev_err(dev, "failed to request firmware %s, ret: %d\n", |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1195 | + AQR_FIRMWARE, ret); |
| 1196 | + } |
| 1197 | + break; |
| 1198 | + } |
| 1199 | + |
| 1200 | + set_current_state(TASK_INTERRUPTIBLE); |
| 1201 | + msleep(1); |
| 1202 | + } |
| 1203 | + |
| 1204 | + return ret; |
| 1205 | +} |
| 1206 | + |
| 1207 | +static int aqr_firmware_download_gang(struct phy_device *phydev) |
| 1208 | +{ |
| 1209 | + struct aqr107_priv *priv = phydev->priv; |
| 1210 | + struct device *dev = &phydev->mdio.dev; |
developer | 3c737eb | 2022-12-09 09:44:16 +0800 | [diff] [blame] | 1211 | + int i; |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1212 | + |
| 1213 | + if (priv->fw_initialized == true) |
| 1214 | + return 0; |
| 1215 | + |
| 1216 | + if (!gangload_kthread) { |
developer | 9451bcd | 2023-07-18 09:34:05 +0800 | [diff] [blame] | 1217 | + /* setup a maximum wait time limit for gangload mode */ |
| 1218 | + gangload_timeout = jiffies + 5 * HZ; |
| 1219 | + |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1220 | + /* create a thread for monitor gangload devices */ |
| 1221 | + gangload_kthread = kthread_create(aqr_firmware_gandload_thread, |
| 1222 | + gangload_phydevs, |
| 1223 | + "aqr_firmware_gandload_thread"); |
| 1224 | + if (IS_ERR(gangload_kthread)) { |
| 1225 | + dev_err(dev, |
developer | f3048b6 | 2023-06-05 18:00:04 +0800 | [diff] [blame] | 1226 | + "failed to create aqr_firmware_gandload_thread(%ld)\n", |
| 1227 | + PTR_ERR(gangload_kthread)); |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1228 | + return PTR_ERR(gangload_kthread); |
| 1229 | + } |
| 1230 | + wake_up_process(gangload_kthread); |
| 1231 | + } |
| 1232 | + |
developer | 3c737eb | 2022-12-09 09:44:16 +0800 | [diff] [blame] | 1233 | + for (i = 0; i < gangload; i++) { |
| 1234 | + if (gangload_phydevs[i] == phydev) { |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 1235 | + dev_warn(dev, "Detect duplicate gangload phydev\n"); |
developer | 93ef6f0 | 2023-08-31 16:09:24 +0800 | [diff] [blame] | 1236 | + return 0; |
developer | 3c737eb | 2022-12-09 09:44:16 +0800 | [diff] [blame] | 1237 | + } |
| 1238 | + } |
| 1239 | + |
developer | 93ef6f0 | 2023-08-31 16:09:24 +0800 | [diff] [blame] | 1240 | + /* fall back to single mode if timeout is reached */ |
| 1241 | + if (time_after(jiffies, gangload_timeout)) |
| 1242 | + return aqr_firmware_download_single(phydev, false); |
| 1243 | + |
| 1244 | + if (priv->phydevs[0] != phydev) { |
| 1245 | + priv->phydevs[0] = phydev; |
| 1246 | + spin_lock_init(&priv->lock); |
| 1247 | + } |
developer | 093e9b3 | 2022-12-13 16:08:34 +0800 | [diff] [blame] | 1248 | + priv->fw_dl_mode = FW_DL_GNAGLOAD; |
developer | 7ddeff0 | 2023-03-22 15:28:46 +0800 | [diff] [blame] | 1249 | + priv->heartbeat = -1; |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1250 | + gangload_phydevs[gangload] = phydev; |
| 1251 | + gangload++; |
| 1252 | + |
| 1253 | + return 0; |
| 1254 | +} |
| 1255 | + |
| 1256 | +int aqr_firmware_download(struct phy_device *phydev) |
| 1257 | +{ |
| 1258 | + int ret = 0; |
| 1259 | +#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD_SINGLE |
developer | 93ef6f0 | 2023-08-31 16:09:24 +0800 | [diff] [blame] | 1260 | + ret = aqr_firmware_download_single(phydev, false); |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1261 | +#elif CONFIG_AQUANTIA_PHY_FW_DOWNLOAD_GANG |
| 1262 | + ret = aqr_firmware_download_gang(phydev); |
| 1263 | +#endif |
| 1264 | + return ret; |
| 1265 | +} |
| 1266 | diff --git a/drivers/net/phy/aquantia_main.c b/drivers/net/phy/aquantia_main.c |
developer | 5d148cb | 2023-06-02 13:08:11 +0800 | [diff] [blame] | 1267 | index e7495c9a7..36f1aac4f 100644 |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1268 | --- a/drivers/net/phy/aquantia_main.c |
| 1269 | +++ b/drivers/net/phy/aquantia_main.c |
developer | 301205c | 2023-05-24 15:39:32 +0800 | [diff] [blame] | 1270 | @@ -8,10 +8,12 @@ |
developer | aafac65 | 2023-01-18 09:41:27 +0800 | [diff] [blame] | 1271 | */ |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 1272 | |
developer | aafac65 | 2023-01-18 09:41:27 +0800 | [diff] [blame] | 1273 | #include <linux/kernel.h> |
| 1274 | +#include <linux/kthread.h> |
| 1275 | #include <linux/module.h> |
| 1276 | #include <linux/delay.h> |
| 1277 | #include <linux/bitfield.h> |
developer | 301205c | 2023-05-24 15:39:32 +0800 | [diff] [blame] | 1278 | #include <linux/phy.h> |
| 1279 | +#include <linux/of.h> |
| 1280 | |
| 1281 | #include "aquantia.h" |
| 1282 | |
developer | 5d148cb | 2023-06-02 13:08:11 +0800 | [diff] [blame] | 1283 | @@ -39,7 +41,6 @@ |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 1284 | #define MDIO_AN_VEND_PROV_2500BASET_FULL BIT(10) |
| 1285 | #define MDIO_AN_VEND_PROV_DOWNSHIFT_EN BIT(4) |
| 1286 | #define MDIO_AN_VEND_PROV_DOWNSHIFT_MASK GENMASK(3, 0) |
| 1287 | -#define MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT 4 |
| 1288 | |
| 1289 | #define MDIO_AN_TX_VEND_STATUS1 0xc800 |
| 1290 | #define MDIO_AN_TX_VEND_STATUS1_RATE_MASK GENMASK(3, 1) |
developer | 5d148cb | 2023-06-02 13:08:11 +0800 | [diff] [blame] | 1291 | @@ -73,18 +74,6 @@ |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1292 | #define MDIO_AN_RX_VEND_STAT3 0xe832 |
| 1293 | #define MDIO_AN_RX_VEND_STAT3_AFR BIT(0) |
| 1294 | |
| 1295 | -/* MDIO_MMD_C22EXT */ |
| 1296 | -#define MDIO_C22EXT_STAT_SGMII_RX_GOOD_FRAMES 0xd292 |
| 1297 | -#define MDIO_C22EXT_STAT_SGMII_RX_BAD_FRAMES 0xd294 |
| 1298 | -#define MDIO_C22EXT_STAT_SGMII_RX_FALSE_CARRIER 0xd297 |
| 1299 | -#define MDIO_C22EXT_STAT_SGMII_TX_GOOD_FRAMES 0xd313 |
| 1300 | -#define MDIO_C22EXT_STAT_SGMII_TX_BAD_FRAMES 0xd315 |
| 1301 | -#define MDIO_C22EXT_STAT_SGMII_TX_FALSE_CARRIER 0xd317 |
| 1302 | -#define MDIO_C22EXT_STAT_SGMII_TX_COLLISIONS 0xd318 |
| 1303 | -#define MDIO_C22EXT_STAT_SGMII_TX_LINE_COLLISIONS 0xd319 |
| 1304 | -#define MDIO_C22EXT_STAT_SGMII_TX_FRAME_ALIGN_ERR 0xd31a |
| 1305 | -#define MDIO_C22EXT_STAT_SGMII_TX_RUNT_FRAMES 0xd31b |
| 1306 | - |
| 1307 | /* Vendor specific 1, MDIO_MMD_VEND1 */ |
| 1308 | #define VEND1_GLOBAL_FW_ID 0x0020 |
| 1309 | #define VEND1_GLOBAL_FW_ID_MAJOR GENMASK(15, 8) |
developer | 5d148cb | 2023-06-02 13:08:11 +0800 | [diff] [blame] | 1310 | @@ -124,31 +113,6 @@ |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1311 | #define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL2 BIT(1) |
| 1312 | #define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 BIT(0) |
| 1313 | |
| 1314 | -struct aqr107_hw_stat { |
| 1315 | - const char *name; |
| 1316 | - int reg; |
| 1317 | - int size; |
| 1318 | -}; |
| 1319 | - |
| 1320 | -#define SGMII_STAT(n, r, s) { n, MDIO_C22EXT_STAT_SGMII_ ## r, s } |
| 1321 | -static const struct aqr107_hw_stat aqr107_hw_stats[] = { |
| 1322 | - SGMII_STAT("sgmii_rx_good_frames", RX_GOOD_FRAMES, 26), |
| 1323 | - SGMII_STAT("sgmii_rx_bad_frames", RX_BAD_FRAMES, 26), |
| 1324 | - SGMII_STAT("sgmii_rx_false_carrier_events", RX_FALSE_CARRIER, 8), |
| 1325 | - SGMII_STAT("sgmii_tx_good_frames", TX_GOOD_FRAMES, 26), |
| 1326 | - SGMII_STAT("sgmii_tx_bad_frames", TX_BAD_FRAMES, 26), |
| 1327 | - SGMII_STAT("sgmii_tx_false_carrier_events", TX_FALSE_CARRIER, 8), |
| 1328 | - SGMII_STAT("sgmii_tx_collisions", TX_COLLISIONS, 8), |
| 1329 | - SGMII_STAT("sgmii_tx_line_collisions", TX_LINE_COLLISIONS, 8), |
| 1330 | - SGMII_STAT("sgmii_tx_frame_alignment_err", TX_FRAME_ALIGN_ERR, 16), |
| 1331 | - SGMII_STAT("sgmii_tx_runt_frames", TX_RUNT_FRAMES, 22), |
| 1332 | -}; |
| 1333 | -#define AQR107_SGMII_STAT_SZ ARRAY_SIZE(aqr107_hw_stats) |
| 1334 | - |
| 1335 | -struct aqr107_priv { |
| 1336 | - u64 sgmii_stats[AQR107_SGMII_STAT_SZ]; |
| 1337 | -}; |
| 1338 | - |
| 1339 | static int aqr107_get_sset_count(struct phy_device *phydev) |
| 1340 | { |
| 1341 | return AQR107_SGMII_STAT_SZ; |
developer | 5d148cb | 2023-06-02 13:08:11 +0800 | [diff] [blame] | 1342 | @@ -398,7 +362,7 @@ static int aqr107_get_downshift(struct phy_device *phydev, u8 *data) |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 1343 | return 0; |
| 1344 | } |
| 1345 | |
| 1346 | -static int aqr107_set_downshift(struct phy_device *phydev, u8 cnt) |
| 1347 | +int aqr107_set_downshift(struct phy_device *phydev, u8 cnt) |
| 1348 | { |
| 1349 | int val = 0; |
| 1350 | |
developer | 5d148cb | 2023-06-02 13:08:11 +0800 | [diff] [blame] | 1351 | @@ -458,7 +422,7 @@ static int aqr107_wait_reset_complete(struct phy_device *phydev) |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 1352 | return val ? 0 : -ETIMEDOUT; |
| 1353 | } |
| 1354 | |
| 1355 | -static void aqr107_chip_info(struct phy_device *phydev) |
| 1356 | +void aqr107_chip_info(struct phy_device *phydev) |
| 1357 | { |
| 1358 | u8 fw_major, fw_minor, build_id, prov_id; |
| 1359 | int val; |
developer | 5d148cb | 2023-06-02 13:08:11 +0800 | [diff] [blame] | 1360 | @@ -481,6 +445,21 @@ static void aqr107_chip_info(struct phy_device *phydev) |
developer | 9431640 | 2022-11-21 08:58:41 +0800 | [diff] [blame] | 1361 | fw_major, fw_minor, build_id, prov_id); |
| 1362 | } |
| 1363 | |
| 1364 | +int aqr107_config_mdi(struct phy_device *phydev) |
| 1365 | +{ |
developer | 301205c | 2023-05-24 15:39:32 +0800 | [diff] [blame] | 1366 | + struct device_node *np = phydev->mdio.dev.of_node; |
| 1367 | + u16 val; |
| 1368 | + |
| 1369 | + if (of_property_read_u16(np, "mdi-reversal", &val)) |
| 1370 | + return -ENOENT; |
| 1371 | + |
| 1372 | + if (!FIELD_FIT(PMAPMD_RSVD_VEND_PROV_MDI_CONF, val)) |
| 1373 | + return -E2BIG; |
| 1374 | + |
developer | 9431640 | 2022-11-21 08:58:41 +0800 | [diff] [blame] | 1375 | + return phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, PMAPMD_RSVD_VEND_PROV, |
developer | 301205c | 2023-05-24 15:39:32 +0800 | [diff] [blame] | 1376 | + PMAPMD_RSVD_VEND_PROV_MDI_CONF, val); |
developer | 9431640 | 2022-11-21 08:58:41 +0800 | [diff] [blame] | 1377 | +} |
| 1378 | + |
| 1379 | static int aqr107_config_init(struct phy_device *phydev) |
| 1380 | { |
| 1381 | int ret; |
developer | 5d148cb | 2023-06-02 13:08:11 +0800 | [diff] [blame] | 1382 | @@ -499,6 +478,12 @@ static int aqr107_config_init(struct phy_device *phydev) |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 1383 | ret = aqr107_wait_reset_complete(phydev); |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1384 | if (!ret) |
| 1385 | aqr107_chip_info(phydev); |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1386 | +#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 1387 | + else |
| 1388 | + return aqr_firmware_download(phydev); |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1389 | +#endif |
| 1390 | + |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 1391 | + aqr107_config_mdi(phydev); |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 1392 | |
developer | d7641da | 2023-02-24 13:56:03 +0800 | [diff] [blame] | 1393 | return aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT); |
| 1394 | } |
developer | 93ef6f0 | 2023-08-31 16:09:24 +0800 | [diff] [blame] | 1395 | @@ -574,12 +559,43 @@ static void aqr107_link_change_notify(struct phy_device *phydev) |
developer | 122ffbb | 2022-11-14 12:07:10 +0800 | [diff] [blame] | 1396 | |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 1397 | static int aqr107_suspend(struct phy_device *phydev) |
| 1398 | { |
developer | aafac65 | 2023-01-18 09:41:27 +0800 | [diff] [blame] | 1399 | +#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD |
| 1400 | + struct aqr107_priv *priv = phydev->priv; |
| 1401 | + |
developer | 93ef6f0 | 2023-08-31 16:09:24 +0800 | [diff] [blame] | 1402 | + if (spin_trylock(&priv->lock)) { |
| 1403 | + if (priv->heartbeat_thread) { |
| 1404 | + kthread_stop(priv->heartbeat_thread); |
| 1405 | + priv->heartbeat_thread = NULL; |
| 1406 | + priv->heartbeat = -1; |
| 1407 | + } |
| 1408 | + spin_unlock(&priv->lock); |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 1409 | + } |
developer | aafac65 | 2023-01-18 09:41:27 +0800 | [diff] [blame] | 1410 | +#endif |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 1411 | return phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MDIO_CTRL1, |
| 1412 | MDIO_CTRL1_LPOWER); |
| 1413 | } |
developer | aafac65 | 2023-01-18 09:41:27 +0800 | [diff] [blame] | 1414 | |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 1415 | static int aqr107_resume(struct phy_device *phydev) |
| 1416 | { |
| 1417 | +#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD |
| 1418 | + struct aqr107_priv *priv = phydev->priv; |
| 1419 | + |
developer | 93ef6f0 | 2023-08-31 16:09:24 +0800 | [diff] [blame] | 1420 | + if (spin_trylock(&priv->lock)) { |
| 1421 | + if (!priv->heartbeat_thread) { |
| 1422 | + priv->heartbeat_thread = kthread_create(aqr_firmware_heartbeat_thread, |
| 1423 | + phydev, |
| 1424 | + "aqr_firmware_heartbeat_thread"); |
| 1425 | + if (IS_ERR(priv->heartbeat_thread)) { |
| 1426 | + phydev_err(phydev, |
| 1427 | + "Failed to create aqr_firmware_heartbeat_thread(%ld)\n", |
| 1428 | + PTR_ERR(priv->heartbeat_thread)); |
| 1429 | + priv->heartbeat_thread = NULL; |
| 1430 | + } else |
| 1431 | + wake_up_process(priv->heartbeat_thread); |
| 1432 | + } |
| 1433 | + spin_unlock(&priv->lock); |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 1434 | + } |
developer | 08abacf | 2023-05-18 15:52:22 +0800 | [diff] [blame] | 1435 | +#endif |
| 1436 | return phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MDIO_CTRL1, |
| 1437 | MDIO_CTRL1_LPOWER); |
| 1438 | } |
developer | 5d148cb | 2023-06-02 13:08:11 +0800 | [diff] [blame] | 1439 | -- |
| 1440 | 2.34.1 |
| 1441 | |