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