mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-28 17:48:58 +00:00
4c8dd973ef
OpenWrt maintains two special out-of-tree DT properties: "qca,disable-5ghz" and "qca,disable-2ghz". These are implemented in a mac80211 ath9k patch "550-ath9k-disable-bands-via-dt.patch". With the things being what they are, now might be a good point to switch the devices to the generic and upstream "ieee80211-freq-limit" property. This property is much broader and works differently. Instead of disabling the drivers logic which would add the affected band and channels. It now disables all channels which are not within the specified frequency range. Reviewed-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com> Tested-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com> # HH5A Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
332 lines
7.9 KiB
Diff
332 lines
7.9 KiB
Diff
--- a/drivers/net/wireless/ath/ath9k/ahb.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
|
|
@@ -20,7 +20,15 @@
|
|
#include <linux/platform_device.h>
|
|
#include <linux/module.h>
|
|
#include <linux/mod_devicetable.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[] = {
|
|
{
|
|
@@ -69,6 +77,236 @@ 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,tx-gain-buffalo"))
|
|
+ pdata->tx_gain_buffalo = true;
|
|
+
|
|
+ if (data->wmac_reset) {
|
|
+ data->wmac_reset();
|
|
+ pdata->external_reset = data->wmac_reset;
|
|
+ }
|
|
+
|
|
+ if (data->dev_id == AR9300_DEVID_AR953X) {
|
|
+ /*
|
|
+ * QCA953x only supports 25MHz refclk.
|
|
+ * Some vendors have an invalid bootstrap option
|
|
+ * set, which would break the WMAC here.
|
|
+ */
|
|
+ pdata->is_clk_25mhz = true;
|
|
+ } else 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;
|
|
@@ -80,6 +324,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");
|
|
@@ -122,13 +377,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;
|
|
@@ -159,6 +417,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;
|
|
}
|
|
@@ -168,6 +429,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,
|
|
};
|
|
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
|
|
+++ b/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"
|
|
@@ -1011,6 +1012,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;
|