Commit e93984eb authored by Robert Marko's avatar Robert Marko Committed by David S. Miller

net: phy: aquantia: add firmware load support

Aquantia PHY-s require firmware to be loaded before they start operating.
It can be automatically loaded in case when there is a SPI-NOR connected
to Aquantia PHY-s or can be loaded from the host via MDIO.

This patch adds support for loading the firmware via MDIO as in most cases
there is no SPI-NOR being used to save on cost.
Firmware loading code itself is ported from mainline U-boot with cleanups.

The firmware has mixed values both in big and little endian.
PHY core itself is big-endian but it expects values to be in little-endian.
The firmware is little-endian but CRC-16 value for it is stored at the end
of firmware in big-endian.

It seems the PHY does the conversion internally from firmware that is
little-endian to the PHY that is big-endian on using the mailbox
but mailbox returns a big-endian CRC-16 to verify the written data
integrity.
Co-developed-by: default avatarChristian Marangi <ansuelsmth@gmail.com>
Signed-off-by: default avatarRobert Marko <robimarko@gmail.com>
Signed-off-by: default avatarChristian Marangi <ansuelsmth@gmail.com>
Reviewed-by: default avatarAndrew Lunn <andrew@lunn.ch>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e1fbfa4a
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
config AQUANTIA_PHY config AQUANTIA_PHY
tristate "Aquantia PHYs" tristate "Aquantia PHYs"
select CRC_CCITT
help help
Currently supports the Aquantia AQ1202, AQ2104, AQR105, AQR405 Currently supports the Aquantia AQ1202, AQ2104, AQR105, AQR405
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
aquantia-objs += aquantia_main.o aquantia-objs += aquantia_main.o aquantia_firmware.o
ifdef CONFIG_HWMON ifdef CONFIG_HWMON
aquantia-objs += aquantia_hwmon.o aquantia-objs += aquantia_hwmon.o
endif endif
......
...@@ -10,10 +10,35 @@ ...@@ -10,10 +10,35 @@
#include <linux/phy.h> #include <linux/phy.h>
/* Vendor specific 1, MDIO_MMD_VEND1 */ /* Vendor specific 1, MDIO_MMD_VEND1 */
#define VEND1_GLOBAL_SC 0x0
#define VEND1_GLOBAL_SC_SOFT_RESET BIT(15)
#define VEND1_GLOBAL_SC_LOW_POWER BIT(11)
#define VEND1_GLOBAL_FW_ID 0x0020 #define VEND1_GLOBAL_FW_ID 0x0020
#define VEND1_GLOBAL_FW_ID_MAJOR GENMASK(15, 8) #define VEND1_GLOBAL_FW_ID_MAJOR GENMASK(15, 8)
#define VEND1_GLOBAL_FW_ID_MINOR GENMASK(7, 0) #define VEND1_GLOBAL_FW_ID_MINOR GENMASK(7, 0)
#define VEND1_GLOBAL_MAILBOX_INTERFACE1 0x0200
#define VEND1_GLOBAL_MAILBOX_INTERFACE1_EXECUTE BIT(15)
#define VEND1_GLOBAL_MAILBOX_INTERFACE1_WRITE BIT(14)
#define VEND1_GLOBAL_MAILBOX_INTERFACE1_CRC_RESET BIT(12)
#define VEND1_GLOBAL_MAILBOX_INTERFACE1_BUSY BIT(8)
#define VEND1_GLOBAL_MAILBOX_INTERFACE2 0x0201
#define VEND1_GLOBAL_MAILBOX_INTERFACE3 0x0202
#define VEND1_GLOBAL_MAILBOX_INTERFACE3_MSW_ADDR_MASK GENMASK(15, 0)
#define VEND1_GLOBAL_MAILBOX_INTERFACE3_MSW_ADDR(x) FIELD_PREP(VEND1_GLOBAL_MAILBOX_INTERFACE3_MSW_ADDR_MASK, (u16)((x) >> 16))
#define VEND1_GLOBAL_MAILBOX_INTERFACE4 0x0203
#define VEND1_GLOBAL_MAILBOX_INTERFACE4_LSW_ADDR_MASK GENMASK(15, 2)
#define VEND1_GLOBAL_MAILBOX_INTERFACE4_LSW_ADDR(x) FIELD_PREP(VEND1_GLOBAL_MAILBOX_INTERFACE4_LSW_ADDR_MASK, (u16)(x))
#define VEND1_GLOBAL_MAILBOX_INTERFACE5 0x0204
#define VEND1_GLOBAL_MAILBOX_INTERFACE5_MSW_DATA_MASK GENMASK(15, 0)
#define VEND1_GLOBAL_MAILBOX_INTERFACE5_MSW_DATA(x) FIELD_PREP(VEND1_GLOBAL_MAILBOX_INTERFACE5_MSW_DATA_MASK, (u16)((x) >> 16))
#define VEND1_GLOBAL_MAILBOX_INTERFACE6 0x0205
#define VEND1_GLOBAL_MAILBOX_INTERFACE6_LSW_DATA_MASK GENMASK(15, 0)
#define VEND1_GLOBAL_MAILBOX_INTERFACE6_LSW_DATA(x) FIELD_PREP(VEND1_GLOBAL_MAILBOX_INTERFACE6_LSW_DATA_MASK, (u16)(x))
/* The following registers all have similar layouts; first the registers... */ /* The following registers all have similar layouts; first the registers... */
#define VEND1_GLOBAL_CFG_10M 0x0310 #define VEND1_GLOBAL_CFG_10M 0x0310
#define VEND1_GLOBAL_CFG_100M 0x031b #define VEND1_GLOBAL_CFG_100M 0x031b
...@@ -28,6 +53,11 @@ ...@@ -28,6 +53,11 @@
#define VEND1_GLOBAL_CFG_RATE_ADAPT_PAUSE 2 #define VEND1_GLOBAL_CFG_RATE_ADAPT_PAUSE 2
/* Vendor specific 1, MDIO_MMD_VEND2 */ /* Vendor specific 1, MDIO_MMD_VEND2 */
#define VEND1_GLOBAL_CONTROL2 0xc001
#define VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_RST BIT(15)
#define VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_OVD BIT(6)
#define VEND1_GLOBAL_CONTROL2_UP_RUN_STALL BIT(0)
#define VEND1_THERMAL_PROV_HIGH_TEMP_FAIL 0xc421 #define VEND1_THERMAL_PROV_HIGH_TEMP_FAIL 0xc421
#define VEND1_THERMAL_PROV_LOW_TEMP_FAIL 0xc422 #define VEND1_THERMAL_PROV_LOW_TEMP_FAIL 0xc422
#define VEND1_THERMAL_PROV_HIGH_TEMP_WARN 0xc423 #define VEND1_THERMAL_PROV_HIGH_TEMP_WARN 0xc423
...@@ -83,3 +113,5 @@ int aqr_hwmon_probe(struct phy_device *phydev); ...@@ -83,3 +113,5 @@ int aqr_hwmon_probe(struct phy_device *phydev);
#else #else
static inline int aqr_hwmon_probe(struct phy_device *phydev) { return 0; } static inline int aqr_hwmon_probe(struct phy_device *phydev) { return 0; }
#endif #endif
int aqr_firmware_load(struct phy_device *phydev);
This diff is collapsed.
...@@ -658,11 +658,17 @@ static int aqr107_resume(struct phy_device *phydev) ...@@ -658,11 +658,17 @@ static int aqr107_resume(struct phy_device *phydev)
static int aqr107_probe(struct phy_device *phydev) static int aqr107_probe(struct phy_device *phydev)
{ {
int ret;
phydev->priv = devm_kzalloc(&phydev->mdio.dev, phydev->priv = devm_kzalloc(&phydev->mdio.dev,
sizeof(struct aqr107_priv), GFP_KERNEL); sizeof(struct aqr107_priv), GFP_KERNEL);
if (!phydev->priv) if (!phydev->priv)
return -ENOMEM; return -ENOMEM;
ret = aqr_firmware_load(phydev);
if (ret)
return ret;
return aqr_hwmon_probe(phydev); return aqr_hwmon_probe(phydev);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment