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