blob: f6e0f953636a09356d44954b535d345388a1ffab [file] [log] [blame]
developer122ffbb2022-11-14 12:07:10 +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
developer94316402022-11-21 08:58:41 +08005@@ -372,7 +372,56 @@ config AMD_PHY
developer122ffbb2022-11-14 12:07:10 +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+
developer94316402022-11-21 08:58:41 +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+
developer122ffbb2022-11-14 12:07:10 +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
developera29111c2023-01-12 10:20:04 +080067@@ -67,5 +67,8 @@ aquantia-objs += aquantia_main.o
developer122ffbb2022-11-14 12:07:10 +080068 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
developer122ffbb2022-11-14 12:07:10 +080074 obj-$(CONFIG_AIROHA_EN8801SC_PHY) += en8801sc.o
75 obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o
76diff --git a/drivers/net/phy/aquantia.h b/drivers/net/phy/aquantia.h
developer08abacf2023-05-18 15:52:22 +080077index 5a16caa..ab1c241 100644
developer122ffbb2022-11-14 12:07:10 +080078--- a/drivers/net/phy/aquantia.h
79+++ b/drivers/net/phy/aquantia.h
developer08abacf2023-05-18 15:52:22 +080080@@ -9,8 +9,72 @@
developer122ffbb2022-11-14 12:07:10 +080081 #include <linux/device.h>
82 #include <linux/phy.h>
83
developer08abacf2023-05-18 15:52:22 +080084+#define MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT 4
85+
developer94316402022-11-21 08:58:41 +080086+#define PMAPMD_RSVD_VEND_PROV 0xe400
87+#define PMAPMD_RSVD_VEND_PROV_MDI_CONF BIT(0)
88+
developer122ffbb2022-11-14 12:07:10 +080089+/* MDIO_MMD_C22EXT */
90+#define MDIO_C22EXT_STAT_SGMII_RX_GOOD_FRAMES 0xd292
91+#define MDIO_C22EXT_STAT_SGMII_RX_BAD_FRAMES 0xd294
92+#define MDIO_C22EXT_STAT_SGMII_RX_FALSE_CARRIER 0xd297
93+#define MDIO_C22EXT_STAT_SGMII_TX_GOOD_FRAMES 0xd313
94+#define MDIO_C22EXT_STAT_SGMII_TX_BAD_FRAMES 0xd315
95+#define MDIO_C22EXT_STAT_SGMII_TX_FALSE_CARRIER 0xd317
96+#define MDIO_C22EXT_STAT_SGMII_TX_COLLISIONS 0xd318
97+#define MDIO_C22EXT_STAT_SGMII_TX_LINE_COLLISIONS 0xd319
98+#define MDIO_C22EXT_STAT_SGMII_TX_FRAME_ALIGN_ERR 0xd31a
99+#define MDIO_C22EXT_STAT_SGMII_TX_RUNT_FRAMES 0xd31b
100+
101+struct aqr107_hw_stat {
102+ const char *name;
103+ int reg;
104+ int size;
105+};
106+
107+#define SGMII_STAT(n, r, s) { n, MDIO_C22EXT_STAT_SGMII_ ## r, s }
108+static const struct aqr107_hw_stat aqr107_hw_stats[] = {
109+ SGMII_STAT("sgmii_rx_good_frames", RX_GOOD_FRAMES, 26),
110+ SGMII_STAT("sgmii_rx_bad_frames", RX_BAD_FRAMES, 26),
111+ SGMII_STAT("sgmii_rx_false_carrier_events", RX_FALSE_CARRIER, 8),
112+ SGMII_STAT("sgmii_tx_good_frames", TX_GOOD_FRAMES, 26),
113+ SGMII_STAT("sgmii_tx_bad_frames", TX_BAD_FRAMES, 26),
114+ SGMII_STAT("sgmii_tx_false_carrier_events", TX_FALSE_CARRIER, 8),
115+ SGMII_STAT("sgmii_tx_collisions", TX_COLLISIONS, 8),
116+ SGMII_STAT("sgmii_tx_line_collisions", TX_LINE_COLLISIONS, 8),
117+ SGMII_STAT("sgmii_tx_frame_alignment_err", TX_FRAME_ALIGN_ERR, 16),
118+ SGMII_STAT("sgmii_tx_runt_frames", TX_RUNT_FRAMES, 22),
119+};
120+#define AQR107_SGMII_STAT_SZ ARRAY_SIZE(aqr107_hw_stats)
121+
122+struct aqr107_priv {
123+ u64 sgmii_stats[AQR107_SGMII_STAT_SZ];
124+#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD
125+ struct phy_device *phydevs[1];
developer7ddeff02023-03-22 15:28:46 +0800126+ struct task_struct *heartbeat_thread;
developer08abacf2023-05-18 15:52:22 +0800127+ spinlock_t lock;
developer122ffbb2022-11-14 12:07:10 +0800128+ bool fw_initialized;
developer093e9b32022-12-13 16:08:34 +0800129+ int fw_dl_mode;
developer7ddeff02023-03-22 15:28:46 +0800130+ u16 heartbeat;
developer122ffbb2022-11-14 12:07:10 +0800131+#endif
132+};
133+
developer08abacf2023-05-18 15:52:22 +0800134+int aqr107_set_downshift(struct phy_device *phydev, u8 cnt);
135+void aqr107_chip_info(struct phy_device *phydev);
developer94316402022-11-21 08:58:41 +0800136+int aqr107_config_mdi(struct phy_device *phydev);
137+
developer122ffbb2022-11-14 12:07:10 +0800138 #if IS_REACHABLE(CONFIG_HWMON)
139 int aqr_hwmon_probe(struct phy_device *phydev);
140 #else
141 static inline int aqr_hwmon_probe(struct phy_device *phydev) { return 0; }
142 #endif
143+
144+#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD
developer093e9b32022-12-13 16:08:34 +0800145+enum {
146+ FW_DL_SINGLE = 0,
147+ FW_DL_GNAGLOAD,
148+};
149+
developer08abacf2023-05-18 15:52:22 +0800150+int aqr_firmware_heartbeat_thread(void *data);
developer122ffbb2022-11-14 12:07:10 +0800151+int aqr_firmware_download(struct phy_device *phydev);
152+#endif
153diff --git a/drivers/net/phy/aquantia_firmware.c b/drivers/net/phy/aquantia_firmware.c
154new file mode 100644
developer08abacf2023-05-18 15:52:22 +0800155index 0000000..622557c
developer122ffbb2022-11-14 12:07:10 +0800156--- /dev/null
157+++ b/drivers/net/phy/aquantia_firmware.c
developer08abacf2023-05-18 15:52:22 +0800158@@ -0,0 +1,1092 @@
developer122ffbb2022-11-14 12:07:10 +0800159+// SPDX-License-Identifier: GPL-2.0
160+/* FW download driver for Aquantia PHY
161+ */
162+
163+#include <linux/phy.h>
164+#include <linux/of.h>
165+#include <linux/device.h>
166+#include <linux/firmware.h>
167+#include <linux/kthread.h>
168+
169+#include "aquantia.h"
170+
171+#undef AQ_VERBOSE
172+
173+#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD_SINGLE
174+#define MAX_GANGLOAD_DEVICES 1
175+#elif CONFIG_AQUANTIA_PHY_FW_DOWNLOAD_GANG
176+#define MAX_GANGLOAD_DEVICES 2
177+#endif
178+
179+#define AQR_FIRMWARE CONFIG_AQUANTIA_PHY_FW_FILE
180+
181+/* Vendor specific 1, MDIO_MMD_VEND1 */
182+#define VEND1_STD_CONTROL1 0x0000
183+#define VEND1_STD_CONTROL1_SOFT_RESET BIT(15)
184+
185+#define VEND1_MAILBOX_INTERFACE1 0x0200
186+#define VEND1_MAILBOX_INTERFACE1_START BIT(15)
187+#define VEND1_MAILBOX_INTERFACE1_WRITE FIELD_PREP(BIT(14), 1)
188+#define VEND1_MAILBOX_INTERFACE1_READ FIELD_PREP(BIT(14), 0)
189+#define VEND1_MAILBOX_INTERFACE1_RESET_CRC BIT(12)
190+
191+#define VEND1_MAILBOX_INTERFACE2 0x0201
192+#define VEND1_MAILBOX_INTERFACE2_CRC GENMASK(15, 0)
193+
194+#define VEND1_MAILBOX_INTERFACE3 0x0202
195+#define VEND1_MAILBOX_INTERFACE3_ADDR_MSW GENMASK(15, 0)
196+
197+#define VEND1_MAILBOX_INTERFACE4 0x0203
198+#define VEND1_MAILBOX_INTERFACE4_ADDR_LSW GENMASK(15, 2)
199+
200+#define VEND1_MAILBOX_INTERFACE5 0x0204
201+#define VEND1_MAILBOX_INTERFACE5_DATA_MSW GENMASK(15, 0)
202+
203+#define VEND1_MAILBOX_INTERFACE6 0x0205
204+#define VEND1_MAILBOX_INTERFACE6_DATA_LSW GENMASK(15, 0)
205+
206+#define VEND1_CONTROL2 0xc001
207+#define VEND1_CONTROL2_UP_RESET BIT(15)
208+#define VEND1_CONTROL2_UP_RUNSTALL_OVERRIDE BIT(6)
209+#define VEND1_CONTROL2_UP_RUNSTALL BIT(0)
210+
211+#define VEND1_RESET_CONTROL 0xc006
212+#define VEND1_RESET_CONTROL_MMD_RESET_DISABLE BIT(14)
213+
214+#define VEND1_GENERAL_PROV2 0xc441
215+#define VEND1_GENERAL_PROV2_MDIO_BROADCAST_ENABLE BIT(14)
216+
217+#define VEND1_GENERAL_PROV8 0xc447
218+#define VEND1_GENERAL_PROV8_MDIO_BROADCAST_ADDRESS GENMASK(4, 0)
219+
220+#define VEND1_NVR_PROV3 0xc452
221+#define VEND1_NVR_PROV3_DAISYCHAIN_DISABLE BIT(0)
222+
223+#define VEND1_RSVD_PROV2 0xc471
224+#define VEND1_RSVD_PROV2_DAISYCHAIN_HOPCOUNT GENMASK(5, 0)
225+#define VEND1_RSVD_PROV2_DAISYCHAIN_HOPCOUNT_OVERRIDE BIT(6)
226+
developeraafac652023-01-18 09:41:27 +0800227+#define VEND1_GLOBAL_RSVD_STAT2 0xc886
228+
developer122ffbb2022-11-14 12:07:10 +0800229+/*! The byte address, in processor memory, of the start of the IRAM segment. */
230+#define AQ_IRAM_BASE_ADDRESS 0x40000000
231+
232+/*! The byte address, in processor memory, of the start of the DRAM segment. */
233+#define AQ_DRAM_BASE_ADDRESS 0x3FFE0000
234+
235+/*! The byte offset from the top of the PHY image to the header content (HHD & EUR devices). */
236+#define AQ_PHY_IMAGE_HEADER_CONTENT_OFFSET_HHD 0x300
237+
238+/*! The offset, from the start of DRAM, where the provisioning block begins. */
239+#define AQ_PHY_IMAGE_PROVTABLE_OFFSET 0x680
240+
241+/*! The offset, from the start of DRAM, where the provisioning block's ending address is recorded. */
242+#define AQ_PHY_IMAGE_PROVTABLE_TERM_OFFSET 0x028C
243+
244+/*! The size of the space alloted within the PHY image for the provisioning table. */
245+#define AQ_PHY_IMAGE_PROVTABLE_MAXSIZE 0x800
246+
247+/*! The maximum number of ports that can be MDIO bootloaded at once. */
248+#define AQ_MAX_NUM_PHY_IDS 48
249+
250+/*! This enumeration is used to describe the different types of
251+ Aquantia PHY.*/
252+typedef enum
253+{
254+ /*! 1/2/4-port package, 40nm architechture.*/
255+ AQ_DEVICE_APPIA,
256+ /*! 1/2/4-port package, first-generation 28nm architechture.*/
257+ AQ_DEVICE_HHD,
258+ /*! 1/2/4-port package, second-generation 28nm architechture.*/
259+ AQ_DEVICE_EUR,
260+ /*! 1/2/4-port package, third-generation 28nm architechture.*/
261+ AQ_DEVICE_CAL,
262+ /*! 1/2/4/8-port package, forth-generation 14nm architechture.*/
263+ AQ_DEVICE_RHEA,
264+ /*! 8-port package, fifth-generation 14nm architechture.*/
265+ AQ_DEVICE_DIONE
266+} AQ_API_Device;
267+
268+/*! The table used to compute CRC's within the PHY. */
269+const uint16_t AQ_CRC16Table[256] = {0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
270+ 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
271+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
272+ 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
273+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
274+ 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
275+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
276+ 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
277+ 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
278+ 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
279+ 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
280+ 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
281+ 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
282+ 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
283+ 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
284+ 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
285+ 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
286+ 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
287+ 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
288+ 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
289+ 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
290+ 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
291+ 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
292+ 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
293+ 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
294+ 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
295+ 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
296+ 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
297+ 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
298+ 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
299+ 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
300+ 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0};
301+
302+struct task_struct *gangload_kthread = NULL;
303+struct phy_device *gangload_phydevs[MAX_GANGLOAD_DEVICES];
304+static int gangload = 0;
305+
developeraafac652023-01-18 09:41:27 +0800306+static int aqr_firmware_download_single(struct phy_device *phydev);
307+
developer122ffbb2022-11-14 12:07:10 +0800308+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++) {
developer3c737eb2022-12-09 09:44:16 +0800997+ /* 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+
developer122ffbb2022-11-14 12:07:10 +08001003+ /* 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+
developer3c737eb2022-12-09 09:44:16 +08001008+ /* 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+
developer122ffbb2022-11-14 12:07:10 +08001013+ /* 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+
developeraafac652023-01-18 09:41:27 +08001037+static int aqr_firmware_check_heartbeat(struct phy_device *phydev)
1038+{
developer7ddeff02023-03-22 15:28:46 +08001039+ struct aqr107_priv *priv = phydev->priv;
1040+ int stopped = 0, ret;
developeraafac652023-01-18 09:41:27 +08001041+
1042+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_RSVD_STAT2);
1043+ if (ret < 0)
1044+ return ret;
1045+
developer08abacf2023-05-18 15:52:22 +08001046+ /* heartbeat stopped if the current heartbeat is equal to the previous */
developer7ddeff02023-03-22 15:28:46 +08001047+ if (priv->heartbeat == ret)
1048+ stopped = 1;
developeraafac652023-01-18 09:41:27 +08001049+
developer08abacf2023-05-18 15:52:22 +08001050+ /* update heartbeat to the private data */
developer7ddeff02023-03-22 15:28:46 +08001051+ priv->heartbeat = ret;
developeraafac652023-01-18 09:41:27 +08001052+
developer7ddeff02023-03-22 15:28:46 +08001053+ return stopped;
developeraafac652023-01-18 09:41:27 +08001054+}
1055+
developer08abacf2023-05-18 15:52:22 +08001056+int aqr_firmware_heartbeat_thread(void *data)
developeraafac652023-01-18 09:41:27 +08001057+{
1058+ struct phy_device *phydev = data;
1059+ struct aqr107_priv *priv = phydev->priv;
developer7ddeff02023-03-22 15:28:46 +08001060+ struct device *dev;
developeraafac652023-01-18 09:41:27 +08001061+ int ret = 0;
1062+
developer7ddeff02023-03-22 15:28:46 +08001063+ dev = &phydev->mdio.dev;
1064+
developeraafac652023-01-18 09:41:27 +08001065+ for (;;) {
1066+ if (kthread_should_stop())
1067+ break;
1068+
developer08abacf2023-05-18 15:52:22 +08001069+ if (priv->fw_initialized == true &&
developera3617672023-01-31 10:46:41 +08001070+ aqr_firmware_check_heartbeat(phydev) == 1) {
developer7ddeff02023-03-22 15:28:46 +08001071+ dev_err(dev, "Detect heartbeat stopped, start to realod firmware...\n");
developeraafac652023-01-18 09:41:27 +08001072+ priv->fw_initialized = false;
developer08abacf2023-05-18 15:52:22 +08001073+ priv->fw_dl_mode = FW_DL_SINGLE;
developeraafac652023-01-18 09:41:27 +08001074+ aqr_firmware_download_single(phydev);
1075+ }
1076+
1077+ set_current_state(TASK_INTERRUPTIBLE);
developer05838f02023-03-23 15:54:37 +08001078+ schedule_timeout(2 * HZ);
developeraafac652023-01-18 09:41:27 +08001079+ }
1080+
1081+ return ret;
1082+}
1083+
developer122ffbb2022-11-14 12:07:10 +08001084+static void aqr_firmware_download_cb(const struct firmware *fw, void *context)
1085+{
1086+ struct phy_device **phydevs = context;
1087+ struct phy_device *gandload_phydev = phydevs[0];
developer08abacf2023-05-18 15:52:22 +08001088+ struct device *dev = &phydevs[0]->mdio.dev;
developer093e9b32022-12-13 16:08:34 +08001089+ struct aqr107_priv *priv = phydevs[0]->priv;
developer122ffbb2022-11-14 12:07:10 +08001090+ int result[MAX_GANGLOAD_DEVICES];
developer093e9b32022-12-13 16:08:34 +08001091+ int i, num_phydevs = 0, ret = 0;
developer122ffbb2022-11-14 12:07:10 +08001092+
developer94316402022-11-21 08:58:41 +08001093+ if (!fw)
1094+ return;
1095+
developer093e9b32022-12-13 16:08:34 +08001096+ num_phydevs = priv->fw_dl_mode == FW_DL_GNAGLOAD ?
1097+ MAX_GANGLOAD_DEVICES : 1;
developer3c737eb2022-12-09 09:44:16 +08001098+
developer122ffbb2022-11-14 12:07:10 +08001099+retry:
developer7ddeff02023-03-22 15:28:46 +08001100+ if (gandload_phydev->state == PHY_HALTED) {
developer7ddeff02023-03-22 15:28:46 +08001101+ dev_info(dev, "Detect PHY power down, stop to reload firmware...\n");
1102+ goto out;
1103+ }
1104+
developer122ffbb2022-11-14 12:07:10 +08001105+ memset(result, 0, sizeof(result));
1106+
developer093e9b32022-12-13 16:08:34 +08001107+ ret = AQ_API_WriteBootLoadImage(phydevs, num_phydevs, gandload_phydev,
developer122ffbb2022-11-14 12:07:10 +08001108+ result, fw->data, fw->size);
1109+ if (ret) {
developer093e9b32022-12-13 16:08:34 +08001110+ for (i = 0; i < num_phydevs; i++) {
developer94316402022-11-21 08:58:41 +08001111+ if (result[i] == 0)
developer122ffbb2022-11-14 12:07:10 +08001112+ continue;
developer122ffbb2022-11-14 12:07:10 +08001113+
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+
developer55398292022-12-14 19:03:08 +08001121+ /* wait firmware initialization completed */
developer94316402022-11-21 08:58:41 +08001122+ mdelay(250);
developer55398292022-12-14 19:03:08 +08001123+
developer093e9b32022-12-13 16:08:34 +08001124+ for (i = 0; i < num_phydevs; i++) {
developer94316402022-11-21 08:58:41 +08001125+ if (result[i] == 0) {
developer08abacf2023-05-18 15:52:22 +08001126+ dev = &phydevs[i]->mdio.dev;
developer94316402022-11-21 08:58:41 +08001127+ priv = phydevs[i]->priv;
1128+ priv->fw_initialized = true;
developer3c737eb2022-12-09 09:44:16 +08001129+
developer08abacf2023-05-18 15:52:22 +08001130+ aqr107_chip_info(phydevs[i]);
1131+
developer94316402022-11-21 08:58:41 +08001132+#ifdef CONFIG_AQUANTIA_PHY_MDI_SWAP
1133+ aqr107_config_mdi(phydevs[i]);
1134+#endif
developer3c737eb2022-12-09 09:44:16 +08001135+
developer08abacf2023-05-18 15:52:22 +08001136+ aqr107_set_downshift(phydevs[i],
1137+ MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT);
1138+
1139+ if (phy_is_started(phydevs[i])) {
developer093e9b32022-12-13 16:08:34 +08001140+ phydevs[i]->state = PHY_UP;
1141+ phy_queue_state_machine(phydevs[i], 0);
1142+ }
developer94316402022-11-21 08:58:41 +08001143+ }
1144+ }
developer7ddeff02023-03-22 15:28:46 +08001145+out:
developer122ffbb2022-11-14 12:07:10 +08001146+ release_firmware(fw);
1147+}
1148+
developeraafac652023-01-18 09:41:27 +08001149+static int aqr_firmware_download_single(struct phy_device *phydev)
developer122ffbb2022-11-14 12:07:10 +08001150+{
1151+ struct aqr107_priv *priv = phydev->priv;
1152+ struct device *dev = &phydev->mdio.dev;
developer093e9b32022-12-13 16:08:34 +08001153+ const struct firmware *fw;
developer122ffbb2022-11-14 12:07:10 +08001154+ int ret = 0;
1155+
1156+ if (priv->fw_initialized == true)
1157+ return 0;
1158+
developer08abacf2023-05-18 15:52:22 +08001159+ spin_lock_init(&priv->lock);
developer093e9b32022-12-13 16:08:34 +08001160+ priv->fw_dl_mode = FW_DL_SINGLE;
developer122ffbb2022-11-14 12:07:10 +08001161+ priv->phydevs[0] = phydev;
developer7ddeff02023-03-22 15:28:46 +08001162+ priv->heartbeat = -1;
developer122ffbb2022-11-14 12:07:10 +08001163+
developer093e9b32022-12-13 16:08:34 +08001164+ ret = request_firmware(&fw, AQR_FIRMWARE, dev);
developer122ffbb2022-11-14 12:07:10 +08001165+ if (ret) {
developer08abacf2023-05-18 15:52:22 +08001166+ dev_err(dev, "failed to request firmware %s, ret: %d\n",
developer122ffbb2022-11-14 12:07:10 +08001167+ AQR_FIRMWARE, ret);
1168+ }
1169+
developer093e9b32022-12-13 16:08:34 +08001170+ aqr_firmware_download_cb(fw, priv->phydevs);
1171+
developer122ffbb2022-11-14 12:07:10 +08001172+ return ret;
1173+}
1174+
1175+static int aqr_firmware_gandload_thread(void *data)
1176+{
1177+ struct phy_device **phydevs = data;
1178+ struct device *dev = &phydevs[0]->mdio.dev;
1179+ int ret = 0;
1180+
1181+ for (;;) {
1182+ if (kthread_should_stop())
1183+ break;
1184+
1185+ /* reach maximum gangload phy devices */
1186+ if (gangload == MAX_GANGLOAD_DEVICES) {
1187+ ret = request_firmware_nowait(THIS_MODULE, true, AQR_FIRMWARE, dev,
1188+ GFP_KERNEL, phydevs, aqr_firmware_download_cb);
1189+ if (ret) {
developer08abacf2023-05-18 15:52:22 +08001190+ dev_err(dev, "failed to request firmware %s, ret: %d\n",
developer122ffbb2022-11-14 12:07:10 +08001191+ AQR_FIRMWARE, ret);
1192+ }
1193+ break;
1194+ }
1195+
1196+ set_current_state(TASK_INTERRUPTIBLE);
1197+ msleep(1);
1198+ }
1199+
1200+ return ret;
1201+}
1202+
1203+static int aqr_firmware_download_gang(struct phy_device *phydev)
1204+{
1205+ struct aqr107_priv *priv = phydev->priv;
1206+ struct device *dev = &phydev->mdio.dev;
developer3c737eb2022-12-09 09:44:16 +08001207+ int i;
developer122ffbb2022-11-14 12:07:10 +08001208+
1209+ if (priv->fw_initialized == true)
1210+ return 0;
1211+
1212+ if (!gangload_kthread) {
1213+ /* create a thread for monitor gangload devices */
1214+ gangload_kthread = kthread_create(aqr_firmware_gandload_thread,
1215+ gangload_phydevs,
1216+ "aqr_firmware_gandload_thread");
1217+ if (IS_ERR(gangload_kthread)) {
1218+ dev_err(dev,
developer08abacf2023-05-18 15:52:22 +08001219+ "failed to create aqr_firmware_gandload_thread\n");
developer122ffbb2022-11-14 12:07:10 +08001220+ return PTR_ERR(gangload_kthread);
1221+ }
1222+ wake_up_process(gangload_kthread);
1223+ }
1224+
developer3c737eb2022-12-09 09:44:16 +08001225+ for (i = 0; i < gangload; i++) {
1226+ if (gangload_phydevs[i] == phydev) {
developer08abacf2023-05-18 15:52:22 +08001227+ dev_warn(dev, "Detect duplicate gangload phydev\n");
developer3c737eb2022-12-09 09:44:16 +08001228+ return -EINVAL;
1229+ }
1230+ }
1231+
developer08abacf2023-05-18 15:52:22 +08001232+ spin_lock_init(&priv->lock);
developer093e9b32022-12-13 16:08:34 +08001233+ priv->fw_dl_mode = FW_DL_GNAGLOAD;
developer7ddeff02023-03-22 15:28:46 +08001234+ priv->heartbeat = -1;
developer122ffbb2022-11-14 12:07:10 +08001235+ gangload_phydevs[gangload] = phydev;
1236+ gangload++;
1237+
1238+ return 0;
1239+}
1240+
1241+int aqr_firmware_download(struct phy_device *phydev)
1242+{
1243+ int ret = 0;
1244+#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD_SINGLE
1245+ ret = aqr_firmware_download_single(phydev);
1246+#elif CONFIG_AQUANTIA_PHY_FW_DOWNLOAD_GANG
1247+ ret = aqr_firmware_download_gang(phydev);
1248+#endif
1249+ return ret;
1250+}
1251diff --git a/drivers/net/phy/aquantia_main.c b/drivers/net/phy/aquantia_main.c
developer08abacf2023-05-18 15:52:22 +08001252index a8c828b..d98757f 100644
developer122ffbb2022-11-14 12:07:10 +08001253--- a/drivers/net/phy/aquantia_main.c
1254+++ b/drivers/net/phy/aquantia_main.c
developeraafac652023-01-18 09:41:27 +08001255@@ -8,6 +8,7 @@
1256 */
developer08abacf2023-05-18 15:52:22 +08001257
developeraafac652023-01-18 09:41:27 +08001258 #include <linux/kernel.h>
1259+#include <linux/kthread.h>
1260 #include <linux/module.h>
1261 #include <linux/delay.h>
1262 #include <linux/bitfield.h>
developer08abacf2023-05-18 15:52:22 +08001263@@ -39,7 +40,6 @@
1264 #define MDIO_AN_VEND_PROV_2500BASET_FULL BIT(10)
1265 #define MDIO_AN_VEND_PROV_DOWNSHIFT_EN BIT(4)
1266 #define MDIO_AN_VEND_PROV_DOWNSHIFT_MASK GENMASK(3, 0)
1267-#define MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT 4
1268
1269 #define MDIO_AN_TX_VEND_STATUS1 0xc800
1270 #define MDIO_AN_TX_VEND_STATUS1_RATE_MASK GENMASK(3, 1)
developer122ffbb2022-11-14 12:07:10 +08001271@@ -73,18 +73,6 @@
1272 #define MDIO_AN_RX_VEND_STAT3 0xe832
1273 #define MDIO_AN_RX_VEND_STAT3_AFR BIT(0)
1274
1275-/* MDIO_MMD_C22EXT */
1276-#define MDIO_C22EXT_STAT_SGMII_RX_GOOD_FRAMES 0xd292
1277-#define MDIO_C22EXT_STAT_SGMII_RX_BAD_FRAMES 0xd294
1278-#define MDIO_C22EXT_STAT_SGMII_RX_FALSE_CARRIER 0xd297
1279-#define MDIO_C22EXT_STAT_SGMII_TX_GOOD_FRAMES 0xd313
1280-#define MDIO_C22EXT_STAT_SGMII_TX_BAD_FRAMES 0xd315
1281-#define MDIO_C22EXT_STAT_SGMII_TX_FALSE_CARRIER 0xd317
1282-#define MDIO_C22EXT_STAT_SGMII_TX_COLLISIONS 0xd318
1283-#define MDIO_C22EXT_STAT_SGMII_TX_LINE_COLLISIONS 0xd319
1284-#define MDIO_C22EXT_STAT_SGMII_TX_FRAME_ALIGN_ERR 0xd31a
1285-#define MDIO_C22EXT_STAT_SGMII_TX_RUNT_FRAMES 0xd31b
1286-
1287 /* Vendor specific 1, MDIO_MMD_VEND1 */
1288 #define VEND1_GLOBAL_FW_ID 0x0020
1289 #define VEND1_GLOBAL_FW_ID_MAJOR GENMASK(15, 8)
1290@@ -124,31 +112,6 @@
1291 #define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL2 BIT(1)
1292 #define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 BIT(0)
1293
1294-struct aqr107_hw_stat {
1295- const char *name;
1296- int reg;
1297- int size;
1298-};
1299-
1300-#define SGMII_STAT(n, r, s) { n, MDIO_C22EXT_STAT_SGMII_ ## r, s }
1301-static const struct aqr107_hw_stat aqr107_hw_stats[] = {
1302- SGMII_STAT("sgmii_rx_good_frames", RX_GOOD_FRAMES, 26),
1303- SGMII_STAT("sgmii_rx_bad_frames", RX_BAD_FRAMES, 26),
1304- SGMII_STAT("sgmii_rx_false_carrier_events", RX_FALSE_CARRIER, 8),
1305- SGMII_STAT("sgmii_tx_good_frames", TX_GOOD_FRAMES, 26),
1306- SGMII_STAT("sgmii_tx_bad_frames", TX_BAD_FRAMES, 26),
1307- SGMII_STAT("sgmii_tx_false_carrier_events", TX_FALSE_CARRIER, 8),
1308- SGMII_STAT("sgmii_tx_collisions", TX_COLLISIONS, 8),
1309- SGMII_STAT("sgmii_tx_line_collisions", TX_LINE_COLLISIONS, 8),
1310- SGMII_STAT("sgmii_tx_frame_alignment_err", TX_FRAME_ALIGN_ERR, 16),
1311- SGMII_STAT("sgmii_tx_runt_frames", TX_RUNT_FRAMES, 22),
1312-};
1313-#define AQR107_SGMII_STAT_SZ ARRAY_SIZE(aqr107_hw_stats)
1314-
1315-struct aqr107_priv {
1316- u64 sgmii_stats[AQR107_SGMII_STAT_SZ];
1317-};
1318-
1319 static int aqr107_get_sset_count(struct phy_device *phydev)
1320 {
1321 return AQR107_SGMII_STAT_SZ;
developer08abacf2023-05-18 15:52:22 +08001322@@ -422,7 +361,7 @@ static int aqr107_get_downshift(struct phy_device *phydev, u8 *data)
1323 return 0;
1324 }
1325
1326-static int aqr107_set_downshift(struct phy_device *phydev, u8 cnt)
1327+int aqr107_set_downshift(struct phy_device *phydev, u8 cnt)
1328 {
1329 int val = 0;
1330
1331@@ -482,7 +421,7 @@ static int aqr107_wait_reset_complete(struct phy_device *phydev)
1332 return val ? 0 : -ETIMEDOUT;
1333 }
1334
1335-static void aqr107_chip_info(struct phy_device *phydev)
1336+void aqr107_chip_info(struct phy_device *phydev)
1337 {
1338 u8 fw_major, fw_minor, build_id, prov_id;
1339 int val;
1340@@ -505,6 +444,17 @@ static void aqr107_chip_info(struct phy_device *phydev)
developer94316402022-11-21 08:58:41 +08001341 fw_major, fw_minor, build_id, prov_id);
1342 }
1343
1344+int aqr107_config_mdi(struct phy_device *phydev)
1345+{
1346+#ifdef CONFIG_AQUANTIA_PHY_MDI_REVERSED
1347+ return phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, PMAPMD_RSVD_VEND_PROV,
1348+ PMAPMD_RSVD_VEND_PROV_MDI_CONF, 1);
1349+#else
1350+ return phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, PMAPMD_RSVD_VEND_PROV,
1351+ PMAPMD_RSVD_VEND_PROV_MDI_CONF, 0);
1352+#endif
1353+}
1354+
1355 static int aqr107_config_init(struct phy_device *phydev)
1356 {
1357 int ret;
developer08abacf2023-05-18 15:52:22 +08001358@@ -520,6 +470,14 @@ static int aqr107_config_init(struct phy_device *phydev)
1359 ret = aqr107_wait_reset_complete(phydev);
developer122ffbb2022-11-14 12:07:10 +08001360 if (!ret)
1361 aqr107_chip_info(phydev);
developer122ffbb2022-11-14 12:07:10 +08001362+#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD
developer08abacf2023-05-18 15:52:22 +08001363+ else
1364+ return aqr_firmware_download(phydev);
developer122ffbb2022-11-14 12:07:10 +08001365+#endif
1366+
developer08abacf2023-05-18 15:52:22 +08001367+#ifdef CONFIG_AQUANTIA_PHY_MDI_SWAP
1368+ aqr107_config_mdi(phydev);
1369+#endif
1370
developerd7641da2023-02-24 13:56:03 +08001371 return aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT);
1372 }
developer08abacf2023-05-18 15:52:22 +08001373@@ -604,12 +556,39 @@ static void aqr107_link_change_notify(struct phy_device *phydev)
developer122ffbb2022-11-14 12:07:10 +08001374
developer08abacf2023-05-18 15:52:22 +08001375 static int aqr107_suspend(struct phy_device *phydev)
1376 {
developeraafac652023-01-18 09:41:27 +08001377+#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD
1378+ struct aqr107_priv *priv = phydev->priv;
1379+
developer08abacf2023-05-18 15:52:22 +08001380+ spin_lock(&priv->lock);
1381+ if (priv->heartbeat_thread) {
1382+ kthread_stop(priv->heartbeat_thread);
1383+ priv->heartbeat_thread = NULL;
1384+ priv->heartbeat = -1;
1385+ }
1386+ spin_unlock(&priv->lock);
developeraafac652023-01-18 09:41:27 +08001387+#endif
developer08abacf2023-05-18 15:52:22 +08001388 return phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MDIO_CTRL1,
1389 MDIO_CTRL1_LPOWER);
1390 }
developeraafac652023-01-18 09:41:27 +08001391
developer08abacf2023-05-18 15:52:22 +08001392 static int aqr107_resume(struct phy_device *phydev)
1393 {
1394+#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD
1395+ struct aqr107_priv *priv = phydev->priv;
1396+
1397+ spin_lock(&priv->lock);
1398+ if (!priv->heartbeat_thread) {
1399+ priv->heartbeat_thread = kthread_create(aqr_firmware_heartbeat_thread,
1400+ phydev,
1401+ "aqr_firmware_heartbeat_thread");
1402+ if (IS_ERR(priv->heartbeat_thread)) {
1403+ phydev_err(phydev,
1404+ "Failed to create aqr_firmware_heartbeat_thread\n");
1405+ }
1406+ wake_up_process(priv->heartbeat_thread);
1407+ }
1408+ spin_unlock(&priv->lock);
1409+#endif
1410 return phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MDIO_CTRL1,
1411 MDIO_CTRL1_LPOWER);
1412 }