"qca,gpio-mask" used to be read between ath9k_hw_init() and ath9k_init_queues(). After12913c3c56it is read in ath9k_of_init(), but it gets overwritten by ath9k_gpio_cap_init() during the call of ath9k_hw_init(), and causes https://github.com/openwrt/openwrt/issues/22340 If keeping the most of12913c3c56, ath9k_gpio_cap_init() could be patched to keep the existing non-zero gpio mask (coming from device tree). Tested on Netgear WNDR4500 v3: [ 22.558083] ath9k 0000:00:00.0: enabling device (0000 -> 0002) [ 22.569548] ath: phy1: Use overridden gpio mask 0xf6ff Signed-off-by: Edward Chow <equu@openmail.cc> Link: https://github.com/openwrt/openwrt/pull/22376 Signed-off-by: Robert Marko <robimarko@gmail.com>
190 lines
4.9 KiB
Diff
190 lines
4.9 KiB
Diff
--- a/drivers/net/wireless/ath/ath9k/init.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/init.c
|
|
@@ -28,6 +28,11 @@
|
|
|
|
#include "ath9k.h"
|
|
|
|
+#ifdef CONFIG_ATH79
|
|
+#include <asm/mach-ath79/ath79.h>
|
|
+#include <asm/mach-ath79/ar71xx_regs.h>
|
|
+#endif
|
|
+
|
|
struct ath9k_eeprom_ctx {
|
|
struct completion complete;
|
|
struct ath_hw *ah;
|
|
@@ -242,6 +247,81 @@ static unsigned int ath9k_reg_rmw(void *
|
|
return val;
|
|
}
|
|
|
|
+#ifdef CONFIG_ATH79
|
|
+#define QCA955X_DDR_CTL_CONFIG 0x108
|
|
+#define QCA955X_DDR_CTL_CONFIG_ACT_WMAC BIT(23)
|
|
+
|
|
+static int ar913x_wmac_reset(void)
|
|
+{
|
|
+ ath79_device_reset_set(AR913X_RESET_AMBA2WMAC);
|
|
+ mdelay(10);
|
|
+
|
|
+ ath79_device_reset_clear(AR913X_RESET_AMBA2WMAC);
|
|
+ mdelay(10);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int ar933x_wmac_reset(void)
|
|
+{
|
|
+ int retries = 20;
|
|
+
|
|
+ ath79_device_reset_set(AR933X_RESET_WMAC);
|
|
+ ath79_device_reset_clear(AR933X_RESET_WMAC);
|
|
+
|
|
+ while (1) {
|
|
+ u32 bootstrap;
|
|
+
|
|
+ bootstrap = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP);
|
|
+ if ((bootstrap & AR933X_BOOTSTRAP_EEPBUSY) == 0)
|
|
+ return 0;
|
|
+
|
|
+ if (retries-- == 0)
|
|
+ break;
|
|
+
|
|
+ udelay(10000);
|
|
+ }
|
|
+
|
|
+ pr_err("ar933x: WMAC reset timed out");
|
|
+ return -ETIMEDOUT;
|
|
+}
|
|
+
|
|
+static int qca955x_wmac_reset(void)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ /* Try to wait for WMAC DDR activity to stop */
|
|
+ for (i = 0; i < 10; i++) {
|
|
+ if (!(__raw_readl(ath79_ddr_base + QCA955X_DDR_CTL_CONFIG) &
|
|
+ QCA955X_DDR_CTL_CONFIG_ACT_WMAC))
|
|
+ break;
|
|
+
|
|
+ udelay(10);
|
|
+ }
|
|
+
|
|
+ ath79_device_reset_set(QCA955X_RESET_RTC);
|
|
+ udelay(10);
|
|
+ ath79_device_reset_clear(QCA955X_RESET_RTC);
|
|
+ udelay(10);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+static int ar9330_get_soc_revision(void)
|
|
+{
|
|
+ if (ath79_soc_rev == 1)
|
|
+ return ath79_soc_rev;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int ath79_get_soc_revision(void)
|
|
+{
|
|
+ return ath79_soc_rev;
|
|
+}
|
|
+#endif
|
|
+
|
|
/**************************/
|
|
/* Initialization */
|
|
/**************************/
|
|
@@ -626,6 +706,7 @@ static int ath9k_of_init(struct ath_soft
|
|
struct ath_common *common = ath9k_hw_common(ah);
|
|
enum ath_bus_type bus_type = common->bus_ops->ath_bus_type;
|
|
char eeprom_name[100];
|
|
+ u32 mask;
|
|
int ret;
|
|
|
|
if (!of_device_is_available(np))
|
|
@@ -633,6 +714,43 @@ static int ath9k_of_init(struct ath_soft
|
|
|
|
ath_dbg(common, CONFIG, "parsing configuration from OF node\n");
|
|
|
|
+ if (!of_property_read_u32(np, "qca,gpio-mask", &mask))
|
|
+ ah->caps.gpio_mask = mask;
|
|
+
|
|
+ if (of_property_read_bool(np, "qca,tx-gain-buffalo"))
|
|
+ ah->config.tx_gain_buffalo = true;
|
|
+
|
|
+#ifdef CONFIG_ATH79
|
|
+ if (ah->hw_version.devid == AR5416_AR9100_DEVID) {
|
|
+ ah->external_reset = ar913x_wmac_reset;
|
|
+ } else if (ah->hw_version.devid == AR9300_DEVID_AR9330) {
|
|
+ ah->get_mac_revision = ar9330_get_soc_revision;
|
|
+ u32 t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP);
|
|
+ ah->is_clk_25mhz = !(t & AR933X_BOOTSTRAP_REF_CLK_40);
|
|
+ ah->external_reset = ar933x_wmac_reset;
|
|
+ } else if (ah->hw_version.devid == AR9300_DEVID_AR9340) {
|
|
+ ah->get_mac_revision = ath79_get_soc_revision;
|
|
+ u32 t = ath79_reset_rr(AR934X_RESET_REG_BOOTSTRAP);
|
|
+ ah->is_clk_25mhz = !(t & AR934X_BOOTSTRAP_REF_CLK_40);
|
|
+ } else if (ah->hw_version.devid == AR9300_DEVID_AR953X) {
|
|
+ ah->get_mac_revision = ath79_get_soc_revision;
|
|
+ /*
|
|
+ * QCA953x only supports 25MHz refclk.
|
|
+ * Some vendors have an invalid bootstrap option
|
|
+ * set, which would break the WMAC here.
|
|
+ */
|
|
+ ah->is_clk_25mhz = true;
|
|
+ } else if (ah->hw_version.devid == AR9300_DEVID_QCA955X) {
|
|
+ u32 t = ath79_reset_rr(QCA955X_RESET_REG_BOOTSTRAP);
|
|
+ ah->is_clk_25mhz = !(t & QCA955X_BOOTSTRAP_REF_CLK_40);
|
|
+ ah->external_reset = qca955x_wmac_reset;
|
|
+ } else if (ah->hw_version.devid == AR9300_DEVID_QCA956X) {
|
|
+ ah->get_mac_revision = ath79_get_soc_revision;
|
|
+ u32 t = ath79_reset_rr(QCA956X_RESET_REG_BOOTSTRAP);
|
|
+ ah->is_clk_25mhz = !(t & QCA956X_BOOTSTRAP_REF_CLK_40);
|
|
+ }
|
|
+#endif
|
|
+
|
|
if (of_property_read_bool(np, "qca,no-eeprom")) {
|
|
/* ath9k-eeprom-<bus>-<id>.bin */
|
|
scnprintf(eeprom_name, sizeof(eeprom_name),
|
|
@@ -651,6 +769,17 @@ static int ath9k_of_init(struct ath_soft
|
|
if (ret == -EPROBE_DEFER)
|
|
return ret;
|
|
|
|
+ np = of_get_child_by_name(np, "led");
|
|
+ if (np && of_device_is_available(np)) {
|
|
+ u32 led_pin;
|
|
+
|
|
+ if (!of_property_read_u32(np, "led-sources", &led_pin))
|
|
+ ah->led_pin = led_pin;
|
|
+
|
|
+ ah->config.led_active_high = !of_property_read_bool(np, "led-active-low");
|
|
+ of_node_put(np);
|
|
+ }
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
|
@@ -2429,6 +2429,7 @@ static bool ath9k_hw_dfs_tested(struct ath_hw *ah)
|
|
static void ath9k_gpio_cap_init(struct ath_hw *ah)
|
|
{
|
|
struct ath9k_hw_capabilities *pCap = &ah->caps;
|
|
+ u32 gpio_mask = pCap->gpio_mask;
|
|
|
|
if (AR_SREV_9271(ah)) {
|
|
pCap->num_gpio_pins = AR9271_NUM_GPIO;
|
|
@@ -2479,6 +2480,12 @@ static void ath9k_gpio_cap_init(struct ath_hw *ah)
|
|
pCap->num_gpio_pins = AR_NUM_GPIO;
|
|
pCap->gpio_mask = AR_GPIO_MASK;
|
|
}
|
|
+
|
|
+ if (gpio_mask) {
|
|
+ pCap->gpio_mask = gpio_mask;
|
|
+ ath_info(ath9k_hw_common(ah), "Use overridden gpio mask 0x%x\n",
|
|
+ gpio_mask);
|
|
+ }
|
|
}
|
|
|
|
int ath9k_hw_fill_cap_info(struct ath_hw *ah)
|