--- zzzz-none-000/linux-3.10.107/arch/mips/ath79/dev-wmac.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/arch/mips/ath79/dev-wmac.c 2021-02-04 17:41:59.000000000 +0000 @@ -15,14 +15,26 @@ #include #include #include +#include #include #include +#include #include #include +#include "common.h" #include "dev-wmac.h" -static struct ath9k_platform_data ath79_wmac_data; +#include + +#ifdef ATH79_WLAN_FW_DUMP +void *ath79_wlan_fw_dump_addr; +#endif +static u8 ath79_wmac_mac[ETH_ALEN]; + +static struct ath9k_platform_data ath79_wmac_data = { + .led_pin = -1, +}; static struct resource ath79_wmac_resources[] = { { @@ -44,7 +56,7 @@ }, }; -static void __init ar913x_wmac_setup(void) +static int ar913x_wmac_reset(void) { /* reset the WMAC */ ath79_device_reset_set(AR913X_RESET_AMBA2WMAC); @@ -53,22 +65,78 @@ ath79_device_reset_clear(AR913X_RESET_AMBA2WMAC); mdelay(10); + return 0; +} + +#ifdef ATH79_WLAN_FW_DUMP +int ath79_get_wlan_fw_dump_buffer(void **dump_buff, u32 *buff_size) +{ + int ret = 0; + + if (ath79_wlan_fw_dump_addr) { + *dump_buff = ath79_wlan_fw_dump_addr; + *buff_size = ATH79_FW_DUMP_MEM_SIZE; + } else { + *dump_buff = NULL; + *buff_size = 0; + ret = -1; + } + return ret; +} +EXPORT_SYMBOL(ath79_get_wlan_fw_dump_buffer); +EXPORT_SYMBOL(ath79_wlan_fw_dump_addr); + +void ath79_init_wlan_fw_dump_buffer(void) +{ + ath79_wlan_fw_dump_addr = kmalloc(ATH79_FW_DUMP_MEM_SIZE, GFP_ATOMIC); + if (ath79_wlan_fw_dump_addr) + printk("\n WLAN firmware dump buffer allocation of %d bytes @ address 0x%p- SUCCESS !!!", + ATH79_FW_DUMP_MEM_SIZE, (void *)ath79_wlan_fw_dump_addr); + else + printk("\n WLAN firmware dump buffer allocation-FAILED!!!"); + +} +#endif + +static void __init ar913x_wmac_setup(void) +{ + ar913x_wmac_reset(); + ath79_wmac_resources[0].start = AR913X_WMAC_BASE; ath79_wmac_resources[0].end = AR913X_WMAC_BASE + AR913X_WMAC_SIZE - 1; ath79_wmac_resources[1].start = ATH79_CPU_IRQ(2); ath79_wmac_resources[1].end = ATH79_CPU_IRQ(2); + + ath79_wmac_data.external_reset = ar913x_wmac_reset; } static int ar933x_wmac_reset(void) { + int retries = 20; + ath79_device_reset_set(AR933X_RESET_WMAC); ath79_device_reset_clear(AR933X_RESET_WMAC); - return 0; + 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); + retries++; + } + + pr_err("ar933x: WMAC reset timed out"); + return -ETIMEDOUT; } -static int ar933x_r1_get_wmac_revision(void) +static int ar93xx_get_soc_revision(void) { return ath79_soc_rev; } @@ -93,7 +161,7 @@ ath79_wmac_data.is_clk_25mhz = true; if (ath79_soc_rev == 1) - ath79_wmac_data.get_mac_revision = ar933x_r1_get_wmac_revision; + ath79_wmac_data.get_mac_revision = ar93xx_get_soc_revision; ath79_wmac_data.external_reset = ar933x_wmac_reset; } @@ -114,6 +182,28 @@ ath79_wmac_data.is_clk_25mhz = false; else ath79_wmac_data.is_clk_25mhz = true; + + ath79_wmac_data.get_mac_revision = ar93xx_get_soc_revision; +} + +static void qca953x_wmac_setup(void) +{ + u32 t; + + ath79_wmac_device.name = "qca953x_wmac"; + + ath79_wmac_resources[0].start = QCA953X_WMAC_BASE; + ath79_wmac_resources[0].end = QCA953X_WMAC_BASE + QCA953X_WMAC_SIZE - 1; + ath79_wmac_resources[1].start = ATH79_IP2_IRQ(1); + ath79_wmac_resources[1].end = ATH79_IP2_IRQ(1); + + t = ath79_reset_rr(QCA953X_RESET_REG_BOOTSTRAP); + if (t & QCA953X_BOOTSTRAP_REF_CLK_40) + ath79_wmac_data.is_clk_25mhz = false; + else + ath79_wmac_data.is_clk_25mhz = true; + + ath79_wmac_data.get_mac_revision = ar93xx_get_soc_revision; } static void qca955x_wmac_setup(void) @@ -134,7 +224,198 @@ ath79_wmac_data.is_clk_25mhz = true; } -void __init ath79_register_wmac(u8 *cal_data) +static void qca956x_wmac_setup(void) +{ + u32 t; + + ath79_wmac_device.name = "qca956x_wmac"; + + ath79_wmac_resources[0].start = QCA956X_WMAC_BASE; + ath79_wmac_resources[0].end = QCA956X_WMAC_BASE + QCA956X_WMAC_SIZE - 1; + ath79_wmac_resources[1].start = ATH79_IP2_IRQ(1); + ath79_wmac_resources[1].end = ATH79_IP2_IRQ(1); + + t = ath79_reset_rr(QCA956X_RESET_REG_BOOTSTRAP); + if (t & QCA956X_BOOTSTRAP_REF_CLK_40) + ath79_wmac_data.is_clk_25mhz = false; + else + ath79_wmac_data.is_clk_25mhz = true; + + ath79_wmac_data.get_mac_revision = ar93xx_get_soc_revision; +} + +static void qcn550x_wmac_setup(void) +{ + u32 t; + + ath79_wmac_device.name = "qcn550x_wmac"; + + ath79_wmac_resources[0].start = QCN550X_WMAC_BASE; + ath79_wmac_resources[0].end = QCN550X_WMAC_BASE + QCN550X_WMAC_SIZE - 1; + ath79_wmac_resources[1].start = ATH79_IP2_IRQ(1); + ath79_wmac_resources[1].end = ATH79_IP2_IRQ(1); + + t = ath79_reset_rr(QCN550X_RESET_REG_BOOTSTRAP); + if (t & QCN550X_BOOTSTRAP_REF_CLK_40) + ath79_wmac_data.is_clk_25mhz = false; + else + ath79_wmac_data.is_clk_25mhz = true; + + ath79_wmac_data.get_mac_revision = ar93xx_get_soc_revision; +} + +static bool __init +ar93xx_wmac_otp_read_word(void __iomem *base, int addr, u32 *data) +{ + int timeout = 1000; + u32 val; + + __raw_readl(base + AR9300_OTP_BASE + (4 * addr)); + while (timeout--) { + val = __raw_readl(base + AR9300_OTP_STATUS); + if ((val & AR9300_OTP_STATUS_TYPE) == AR9300_OTP_STATUS_VALID) + break; + + udelay(10); + } + + if (!timeout) + return false; + + *data = __raw_readl(base + AR9300_OTP_READ_DATA); + return true; +} + +static bool __init +ar93xx_wmac_otp_read(void __iomem *base, int addr, u8 *dest, int len) +{ + u32 data; + int i; + + for (i = 0; i < len; i++) { + int offset = 8 * ((addr - i) % 4); + + if (!ar93xx_wmac_otp_read_word(base, (addr - i) / 4, &data)) + return false; + + dest[i] = (data >> offset) & 0xff; + } + + return true; +} + +static bool __init +ar93xx_wmac_otp_uncompress(void __iomem *base, int addr, int len, u8 *dest, + int dest_start, int dest_len) +{ + int dest_bytes = 0; + int offset = 0; + int end = addr - len; + u8 hdr[2]; + + while (addr > end) { + if (!ar93xx_wmac_otp_read(base, addr, hdr, 2)) + return false; + + addr -= 2; + offset += hdr[0]; + + if (offset <= dest_start + dest_len && + offset + len >= dest_start) { + int data_offset = 0; + int dest_offset = 0; + int copy_len; + + if (offset < dest_start) + data_offset = dest_start - offset; + else + dest_offset = offset - dest_start; + + copy_len = len - data_offset; + if (copy_len > dest_len - dest_offset) + copy_len = dest_len - dest_offset; + + ar93xx_wmac_otp_read(base, addr - data_offset, + dest + dest_offset, + copy_len); + + dest_bytes += copy_len; + } + addr -= hdr[1]; + } + return !!dest_bytes; +} + +bool __init ar93xx_wmac_read_mac_address(u8 *dest) +{ + void __iomem *base; + bool ret = false; + int addr = 0x1ff; + unsigned int len; + u32 hdr_u32; + u8 *hdr = (u8 *) &hdr_u32; + u8 mac[6] = { 0x00, 0x02, 0x03, 0x04, 0x05, 0x06 }; + int mac_start = 2, mac_end = 8; + + BUG_ON(!soc_is_ar933x() && !soc_is_ar934x()); + base = ioremap_nocache(AR933X_WMAC_BASE, AR933X_WMAC_SIZE); + while (addr > sizeof(hdr)) { + if (!ar93xx_wmac_otp_read(base, addr, hdr, sizeof(hdr))) + break; + + if (hdr_u32 == 0 || hdr_u32 == ~0) + break; + + len = (hdr[1] << 4) | (hdr[2] >> 4); + addr -= 4; + + switch (hdr[0] >> 5) { + case 0: + if (len < mac_end) + break; + + ar93xx_wmac_otp_read(base, addr - mac_start, mac, 6); + ret = true; + break; + case 3: + ret |= ar93xx_wmac_otp_uncompress(base, addr, len, mac, + mac_start, 6); + break; + default: + break; + } + + addr -= len + 2; + } + + iounmap(base); + if (ret) + memcpy(dest, mac, 6); + + return ret; +} + +void __init ath79_wmac_disable_2ghz(void) +{ + ath79_wmac_data.disable_2ghz = true; +} + +void __init ath79_wmac_disable_5ghz(void) +{ + ath79_wmac_data.disable_5ghz = true; +} + +void __init ath79_wmac_set_tx_gain_buffalo(void) +{ + ath79_wmac_data.tx_gain_buffalo = true; +} + +void __init ath79_wmac_set_led_pin(int gpio) +{ + ath79_wmac_data.led_pin = gpio; +} + +void __init ath79_register_wmac(u8 *cal_data, u8 *mac_addr) { if (soc_is_ar913x()) ar913x_wmac_setup(); @@ -142,8 +423,14 @@ ar933x_wmac_setup(); else if (soc_is_ar934x()) ar934x_wmac_setup(); + else if (soc_is_qca953x()) + qca953x_wmac_setup(); else if (soc_is_qca955x()) qca955x_wmac_setup(); + else if (soc_is_qca956x() || soc_is_tp9343()) + qca956x_wmac_setup(); + else if (soc_is_qcn550x()) + qcn550x_wmac_setup(); else BUG(); @@ -151,5 +438,19 @@ memcpy(ath79_wmac_data.eeprom_data, cal_data, sizeof(ath79_wmac_data.eeprom_data)); + if (mac_addr) { + memcpy(ath79_wmac_mac, mac_addr, sizeof(ath79_wmac_mac)); + ath79_wmac_data.macaddr = ath79_wmac_mac; + } + platform_device_register(&ath79_wmac_device); +#ifdef ATH79_WLAN_FW_DUMP + ath79_init_wlan_fw_dump_buffer(); +#endif +} + +void __init ath79_register_wmac_simple(void) +{ + ath79_register_wmac(NULL, NULL); + ath79_wmac_data.eeprom_name = "soc_wmac.eeprom"; }