ath79: make ahb wifi work
authorJohn Crispin <john@phrozen.org>
Mon, 14 May 2018 05:11:56 +0000 (07:11 +0200)
committerJohn Crispin <john@phrozen.org>
Thu, 24 May 2018 13:43:39 +0000 (15:43 +0200)
Signed-off-by: John Crispin <john@phrozen.org>
package/kernel/mac80211/Makefile
package/kernel/mac80211/patches/552-ahb_of.patch [new file with mode: 0644]
target/linux/ath79/dts/ar9330.dtsi
target/linux/ath79/dts/ar9330_glinet_ar150.dts
target/linux/ath79/patches-4.14/0034-MIPS-ath79-ath9k-exports.patch [new file with mode: 0644]

index 01a21096603c390558d2374ae5091cb3f1815dbf..77a3e68f5ccc46bc8de3b95d7d62fb0913eaf1a5 100644 (file)
@@ -203,7 +203,7 @@ endef
 define KernelPackage/ath
   $(call KernelPackage/mac80211/Default)
   TITLE:=Atheros common driver part
-  DEPENDS+= @PCI_SUPPORT||USB_SUPPORT||TARGET_ar71xx||TARGET_ath25 +kmod-mac80211
+  DEPENDS+= @PCI_SUPPORT||USB_SUPPORT||TARGET_ar71xx||TARGET_ath79||TARGET_ath25 +kmod-mac80211
   FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath.ko
   MENU:=1
 endef
@@ -268,7 +268,7 @@ define KernelPackage/ath9k-common
   TITLE:=Atheros 802.11n wireless devices (common code for ath9k and ath9k_htc)
   URL:=https://wireless.wiki.kernel.org/en/users/drivers/ath9k
   HIDDEN:=1
-  DEPENDS+= @PCI_SUPPORT||USB_SUPPORT||TARGET_ar71xx +kmod-ath +@DRIVER_11N_SUPPORT +@DRIVER_11W_SUPPORT
+  DEPENDS+= @PCI_SUPPORT||USB_SUPPORT||TARGET_ar71xx||TARGET_ath79 +kmod-ath +@DRIVER_11N_SUPPORT +@DRIVER_11W_SUPPORT
   FILES:= \
        $(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath9k/ath9k_common.ko \
        $(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath9k/ath9k_hw.ko
@@ -278,7 +278,7 @@ define KernelPackage/ath9k
   $(call KernelPackage/mac80211/Default)
   TITLE:=Atheros 802.11n PCI wireless cards support
   URL:=https://wireless.wiki.kernel.org/en/users/drivers/ath9k
-  DEPENDS+= @PCI_SUPPORT||TARGET_ar71xx +kmod-ath9k-common
+  DEPENDS+= @PCI_SUPPORT||TARGET_ar71xx||TARGET_ath79 +kmod-ath9k-common
   FILES:= \
        $(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath9k/ath9k.ko
   AUTOLOAD:=$(call AutoProbe,ath9k)
@@ -301,7 +301,7 @@ define KernelPackage/ath9k/config
 
        config ATH9K_UBNTHSR
                bool "Support for Ubiquiti UniFi Outdoor+ access point"
-               depends on PACKAGE_kmod-ath9k && TARGET_ar71xx_generic
+               depends on PACKAGE_kmod-ath9k && (TARGET_ar71xx_generic||TARGET_ath79)
                default y
 
 endef
@@ -1618,6 +1618,7 @@ config-$(CONFIG_PACKAGE_ATH_SPECTRAL) += ATH9K_COMMON_SPECTRAL ATH10K_SPECTRAL
 config-$(call config_package,ath9k) += ATH9K
 config-$(call config_package,ath9k-common) += ATH9K_COMMON
 config-$(CONFIG_TARGET_ar71xx) += ATH9K_AHB
+config-$(CONFIG_TARGET_ath79) += ATH9K_AHB
 config-$(CONFIG_TARGET_ipq40xx) += ATH10K_AHB
 config-$(CONFIG_PCI) += ATH9K_PCI
 config-$(CONFIG_ATH_USER_REGD) += ATH_USER_REGD
diff --git a/package/kernel/mac80211/patches/552-ahb_of.patch b/package/kernel/mac80211/patches/552-ahb_of.patch
new file mode 100644 (file)
index 0000000..1af1f44
--- /dev/null
@@ -0,0 +1,334 @@
+Index: backports-2017-11-01/drivers/net/wireless/ath/ath9k/ahb.c
+===================================================================
+--- backports-2017-11-01.orig/drivers/net/wireless/ath/ath9k/ahb.c
++++ backports-2017-11-01/drivers/net/wireless/ath/ath9k/ahb.c
+@@ -19,7 +19,15 @@
+ #include <linux/nl80211.h>
+ #include <linux/platform_device.h>
+ #include <linux/module.h>
++#include <linux/of_device.h>
+ #include "ath9k.h"
++#include <linux/ath9k_platform.h>
++
++#ifdef CONFIG_OF
++#include <asm/mach-ath79/ath79.h>
++#include <asm/mach-ath79/ar71xx_regs.h>
++#include <linux/mtd/mtd.h>
++#endif
+ static const struct platform_device_id ath9k_platform_id_table[] = {
+       {
+@@ -68,6 +76,235 @@ static const struct ath_bus_ops ath_ahb_
+       .eeprom_read = ath_ahb_eeprom_read,
+ };
++#ifdef CONFIG_OF
++
++#define QCA955X_DDR_CTL_CONFIG          0x108
++#define QCA955X_DDR_CTL_CONFIG_ACT_WMAC BIT(23)
++
++static int of_get_wifi_cal(struct device_node *np, struct ath9k_platform_data *pdata)
++{
++#ifdef CONFIG_MTD
++      struct device_node *mtd_np = NULL;
++      size_t retlen;
++      int size, ret;
++      struct mtd_info *mtd;
++      const char *part;
++      const __be32 *list;
++      phandle phandle;
++
++      list = of_get_property(np, "mtd-cal-data", &size);
++      if (!list)
++              return 0;
++
++      if (size != (2 * sizeof(*list)))
++              return 1;
++
++      phandle = be32_to_cpup(list++);
++      if (phandle)
++              mtd_np = of_find_node_by_phandle(phandle);
++
++      if (!mtd_np)
++              return 1;
++
++      part = of_get_property(mtd_np, "label", NULL);
++      if (!part)
++              part = mtd_np->name;
++
++      mtd = get_mtd_device_nm(part);
++      if (IS_ERR(mtd))
++              return 1;
++
++      ret = mtd_read(mtd, be32_to_cpup(list), sizeof(pdata->eeprom_data),
++                      &retlen, (u8*)pdata->eeprom_data);
++      put_mtd_device(mtd);
++
++#endif
++      return 0;
++}
++
++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;
++}
++
++enum {
++      AR913X_WMAC = 0,
++      AR933X_WMAC,
++      AR934X_WMAC,
++      QCA953X_WMAC,
++      QCA955X_WMAC,
++      QCA956X_WMAC,
++};
++
++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;
++}
++
++static const struct of_ath_ahb_data {
++      u16 dev_id;
++      u32 bootstrap_reg;
++      u32 bootstrap_ref;
++
++      int (*soc_revision)(void);
++      int (*wmac_reset)(void);
++} of_ath_ahb_data[] = {
++      [AR913X_WMAC] = {
++              .dev_id = AR5416_AR9100_DEVID,
++              .wmac_reset = ar913x_wmac_reset,
++
++      },
++      [AR933X_WMAC] = {
++              .dev_id = AR9300_DEVID_AR9330,
++              .bootstrap_reg = AR933X_RESET_REG_BOOTSTRAP,
++              .bootstrap_ref = AR933X_BOOTSTRAP_REF_CLK_40,
++              .soc_revision = ar9330_get_soc_revision,
++              .wmac_reset = ar933x_wmac_reset,
++      },
++      [AR934X_WMAC] = {
++              .dev_id = AR9300_DEVID_AR9340,
++              .bootstrap_reg = AR934X_RESET_REG_BOOTSTRAP,
++              .bootstrap_ref = AR934X_BOOTSTRAP_REF_CLK_40,
++              .soc_revision = ath79_get_soc_revision,
++      },
++      [QCA953X_WMAC] = {
++              .dev_id = AR9300_DEVID_AR953X,
++              .bootstrap_reg = QCA953X_RESET_REG_BOOTSTRAP,
++              .bootstrap_ref = QCA953X_BOOTSTRAP_REF_CLK_40,
++              .soc_revision = ath79_get_soc_revision,
++      },
++      [QCA955X_WMAC] = {
++              .dev_id = AR9300_DEVID_QCA955X,
++              .bootstrap_reg = QCA955X_RESET_REG_BOOTSTRAP,
++              .bootstrap_ref = QCA955X_BOOTSTRAP_REF_CLK_40,
++              .wmac_reset = qca955x_wmac_reset,
++      },
++      [QCA956X_WMAC] = {
++              .dev_id = AR9300_DEVID_QCA956X,
++              .bootstrap_reg = QCA956X_RESET_REG_BOOTSTRAP,
++              .bootstrap_ref = QCA956X_BOOTSTRAP_REF_CLK_40,
++              .soc_revision = ath79_get_soc_revision,
++      },
++};
++
++const struct of_device_id of_ath_ahb_match[] = {
++      { .compatible = "qca,ar9130-wmac", .data = &of_ath_ahb_data[AR913X_WMAC] },
++      { .compatible = "qca,ar9330-wmac", .data = &of_ath_ahb_data[AR933X_WMAC] },
++      { .compatible = "qca,ar9340-wmac", .data = &of_ath_ahb_data[AR934X_WMAC] },
++      { .compatible = "qca,qca9530-wmac", .data = &of_ath_ahb_data[QCA953X_WMAC] },
++      { .compatible = "qca,qca9550-wmac", .data = &of_ath_ahb_data[QCA955X_WMAC] },
++      { .compatible = "qca,qca9560-wmac", .data = &of_ath_ahb_data[QCA956X_WMAC] },
++      {},
++};
++MODULE_DEVICE_TABLE(of, of_ath_ahb_match);
++
++static int of_ath_ahb_probe(struct platform_device *pdev)
++{
++      struct ath9k_platform_data *pdata;
++      const struct of_device_id *match;
++      const struct of_ath_ahb_data *data;
++      u8 led_pin;
++
++      match = of_match_device(of_ath_ahb_match, &pdev->dev);
++      data = (const struct of_ath_ahb_data *)match->data;
++
++      pdata = dev_get_platdata(&pdev->dev);
++
++      if (!of_property_read_u8(pdev->dev.of_node, "qca,led-pin", &led_pin))
++              pdata->led_pin = led_pin;
++      else
++              pdata->led_pin = -1;
++
++      if (of_property_read_bool(pdev->dev.of_node, "qca,disable-2ghz"))
++              pdata->disable_2ghz = true;
++
++      if (of_property_read_bool(pdev->dev.of_node, "qca,disable-5ghz"))
++              pdata->disable_5ghz = true;
++
++      if (of_property_read_bool(pdev->dev.of_node, "qca,tx-gain-buffalo"))
++              pdata->tx_gain_buffalo = true;
++
++      if (data->wmac_reset) {
++              data->wmac_reset();
++              pdata->external_reset = data->wmac_reset;
++      }
++
++      if (data->bootstrap_reg && data->bootstrap_ref) {
++              u32 t = ath79_reset_rr(data->bootstrap_reg);
++              if (t & data->bootstrap_ref)
++                      pdata->is_clk_25mhz = false;
++              else
++                      pdata->is_clk_25mhz = true;
++      }
++
++      pdata->get_mac_revision = data->soc_revision;
++
++      if (of_get_wifi_cal(pdev->dev.of_node, pdata))
++              dev_err(&pdev->dev, "failed to load calibration data from mtd device\n");
++
++      return data->dev_id;
++}
++#endif
++
+ static int ath_ahb_probe(struct platform_device *pdev)
+ {
+       void __iomem *mem;
+@@ -79,6 +316,17 @@ static int ath_ahb_probe(struct platform
+       int ret = 0;
+       struct ath_hw *ah;
+       char hw_name[64];
++      u16 dev_id;
++
++      if (id)
++              dev_id = id->driver_data;
++
++#ifdef CONFIG_OF
++      if (pdev->dev.of_node)
++              pdev->dev.platform_data = devm_kzalloc(&pdev->dev,
++                                      sizeof(struct ath9k_platform_data),
++                                      GFP_KERNEL);
++#endif
+       if (!dev_get_platdata(&pdev->dev)) {
+               dev_err(&pdev->dev, "no platform data specified\n");
+@@ -121,13 +369,16 @@ static int ath_ahb_probe(struct platform
+       sc->mem = mem;
+       sc->irq = irq;
++#ifdef CONFIG_OF
++      dev_id = of_ath_ahb_probe(pdev);
++#endif
+       ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc);
+       if (ret) {
+               dev_err(&pdev->dev, "request_irq failed\n");
+               goto err_free_hw;
+       }
+-      ret = ath9k_init_device(id->driver_data, sc, &ath_ahb_bus_ops);
++      ret = ath9k_init_device(dev_id, sc, &ath_ahb_bus_ops);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to initialize device\n");
+               goto err_irq;
+@@ -158,6 +409,9 @@ static int ath_ahb_remove(struct platfor
+               free_irq(sc->irq, sc);
+               ieee80211_free_hw(sc->hw);
+       }
++#ifdef CONFIG_OF
++      pdev->dev.platform_data = NULL;
++#endif
+       return 0;
+ }
+@@ -167,6 +421,9 @@ static struct platform_driver ath_ahb_dr
+       .remove     = ath_ahb_remove,
+       .driver         = {
+               .name   = "ath9k",
++#ifdef CONFIG_OF
++              .of_match_table = of_ath_ahb_match,
++#endif
+       },
+       .id_table    = ath9k_platform_id_table,
+ };
+Index: backports-2017-11-01/drivers/net/wireless/ath/ath9k/ath9k.h
+===================================================================
+--- backports-2017-11-01.orig/drivers/net/wireless/ath/ath9k/ath9k.h
++++ backports-2017-11-01/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -25,6 +25,7 @@
+ #include <linux/time.h>
+ #include <linux/hw_random.h>
+ #include <linux/gpio/driver.h>
++#include <linux/reset.h>
+ #include "common.h"
+ #include "debug.h"
+@@ -1023,6 +1024,9 @@ struct ath_softc {
+       struct ath_hw *sc_ah;
+       void __iomem *mem;
+       int irq;
++#ifdef CONFIG_OF
++      struct reset_control *reset;
++#endif
+       spinlock_t sc_serial_rw;
+       spinlock_t sc_pm_lock;
+       spinlock_t sc_pcu_lock;
index 1439de1e6683a1bd38a03e83f14eb4b51559202e..e1beacb27232ac6b9444b2df19a86dc9fef05b62 100644 (file)
                        compatible = "qca,ar9330-gmac";
                        reg = <0x18070000 0x4>;
                };
+
+               wmac: gmac@18100000 {
+                       compatible = "qca,ar9330-wmac";
+                       reg = <0x18100000 0x20000>;
+
+                       interrupts = <2>;
+
+                       status = "disabled";
+               };
        };
 
        usb_phy: usb-phy {
index 16d86137cbb563dd3c5f4f5d96963e849bc61e25..a7dab83559c886c34476d261975021e701871cc4 100644 (file)
                switch-phy-swap = <0>;
        };
 };
+
+&wmac {
+       status = "okay";
+       mtd-cal-data = <&art 0x1000>;
+       mtd-mac-address = <&art 0x0>;
+};
diff --git a/target/linux/ath79/patches-4.14/0034-MIPS-ath79-ath9k-exports.patch b/target/linux/ath79/patches-4.14/0034-MIPS-ath79-ath9k-exports.patch
new file mode 100644 (file)
index 0000000..fddacc6
--- /dev/null
@@ -0,0 +1,31 @@
+Index: linux-4.14.42/arch/mips/ath79/common.c
+===================================================================
+--- linux-4.14.42.orig/arch/mips/ath79/common.c
++++ linux-4.14.42/arch/mips/ath79/common.c
+@@ -34,11 +34,13 @@ EXPORT_SYMBOL_GPL(ath79_ddr_freq);
+ enum ath79_soc_type ath79_soc;
+ unsigned int ath79_soc_rev;
++EXPORT_SYMBOL_GPL(ath79_soc_rev);
+ void __iomem *ath79_pll_base;
+ void __iomem *ath79_reset_base;
+ EXPORT_SYMBOL_GPL(ath79_reset_base);
+-static void __iomem *ath79_ddr_base;
++void __iomem *ath79_ddr_base;
++EXPORT_SYMBOL_GPL(ath79_ddr_base);
+ static void __iomem *ath79_ddr_wb_flush_base;
+ static void __iomem *ath79_ddr_pci_win_base;
+Index: linux-4.14.42/arch/mips/include/asm/mach-ath79/ath79.h
+===================================================================
+--- linux-4.14.42.orig/arch/mips/include/asm/mach-ath79/ath79.h
++++ linux-4.14.42/arch/mips/include/asm/mach-ath79/ath79.h
+@@ -152,6 +152,7 @@ void ath79_ddr_wb_flush(unsigned int reg
+ void ath79_ddr_set_pci_windows(void);
+ extern void __iomem *ath79_pll_base;
++extern void __iomem *ath79_ddr_base;
+ extern void __iomem *ath79_reset_base;
+ static inline void ath79_pll_wr(unsigned reg, u32 val)