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