atheros: v3.18: remap flash for boardconfig parsing

Rework boardconfig handling code to honestly remap flash memory region.

Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>

SVN-Revision: 44725
This commit is contained in:
Felix Fietkau 2015-03-13 03:01:17 +00:00
parent 6b041d0b1d
commit 9ceee12a49
4 changed files with 74 additions and 77 deletions

View file

@ -77,7 +77,7 @@
+obj-$(CONFIG_SOC_AR2315) += ar2315.o +obj-$(CONFIG_SOC_AR2315) += ar2315.o
--- /dev/null --- /dev/null
+++ b/arch/mips/ath25/board.c +++ b/arch/mips/ath25/board.c
@@ -0,0 +1,234 @@ @@ -0,0 +1,244 @@
+/* +/*
+ * This file is subject to the terms and conditions of the GNU General Public + * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive + * License. See the file "COPYING" in the main directory of this archive
@ -112,57 +112,55 @@
+ +
+void (*ath25_irq_dispatch)(void); +void (*ath25_irq_dispatch)(void);
+ +
+static inline bool check_radio_magic(u8 *addr) +static inline bool check_radio_magic(const void __iomem *addr)
+{ +{
+ addr += 0x7a; /* offset for flash magic */ + addr += 0x7a; /* offset for flash magic */
+ return (addr[0] == 0x5a) && (addr[1] == 0xa5); + return (__raw_readb(addr) == 0x5a) && (__raw_readb(addr + 1) == 0xa5);
+} +}
+ +
+static inline bool check_notempty(u8 *addr) +static inline bool check_notempty(const void __iomem *addr)
+{ +{
+ return *(u32 *)addr != 0xffffffff; + return __raw_readl(addr) != 0xffffffff;
+} +}
+ +
+static inline bool check_board_data(u8 *flash_limit, u8 *addr, bool broken) +static inline bool check_board_data(const void __iomem *addr, bool broken)
+{ +{
+ /* config magic found */ + /* config magic found */
+ if (*((u32 *)addr) == ATH25_BD_MAGIC) + if (__raw_readl(addr) == ATH25_BD_MAGIC)
+ return true; + return true;
+ +
+ if (!broken) + if (!broken)
+ return false; + return false;
+ +
+ if (check_radio_magic(addr + 0xf8)) + /* broken board data detected, use radio data to find the
+ ath25_board.radio = addr + 0xf8; + * offset, user will fix this */
+ if ((addr < flash_limit + 0x10000) &&
+ check_radio_magic(addr + 0x10000))
+ ath25_board.radio = addr + 0x10000;
+ +
+ if (ath25_board.radio) { + if (check_radio_magic(addr + 0x1000))
+ /* broken board data detected, use radio data to find the + return true;
+ * offset, user will fix this */ + if (check_radio_magic(addr + 0xf8))
+ return true; + return true;
+ }
+ +
+ return false; + return false;
+} +}
+ +
+static u8 * __init find_board_config(u8 *flash_limit, bool broken) +static const void __iomem * __init find_board_config(const void __iomem *limit,
+ const bool broken)
+{ +{
+ u8 *addr; + const void __iomem *addr;
+ u8 *begin = flash_limit - 0x1000; + const void __iomem *begin = limit - 0x1000;
+ u8 *end = flash_limit - 0x30000; + const void __iomem *end = limit - 0x30000;
+ +
+ for (addr = begin; addr >= end; addr -= 0x1000) + for (addr = begin; addr >= end; addr -= 0x1000)
+ if (check_board_data(flash_limit, addr, broken)) + if (check_board_data(addr, broken))
+ return addr; + return addr;
+ +
+ return NULL; + return NULL;
+} +}
+ +
+static u8 * __init find_radio_config(u8 *flash_limit, u8 *bcfg) +static const void __iomem * __init find_radio_config(const void __iomem *limit,
+ const void __iomem *bcfg)
+{ +{
+ u8 *rcfg, *begin, *end; + const void __iomem *rcfg, *begin, *end;
+ +
+ /* + /*
+ * Now find the start of Radio Configuration data, using heuristics: + * Now find the start of Radio Configuration data, using heuristics:
@ -170,36 +168,44 @@
+ * at a time until we find non-0xffffffff. + * at a time until we find non-0xffffffff.
+ */ + */
+ begin = bcfg + 0x1000; + begin = bcfg + 0x1000;
+ end = flash_limit; + end = limit;
+ for (rcfg = begin; rcfg < end; rcfg += 0x1000) + for (rcfg = begin; rcfg < end; rcfg += 0x1000)
+ if (check_notempty(rcfg) && check_radio_magic(rcfg)) + if (check_notempty(rcfg) && check_radio_magic(rcfg))
+ return rcfg; + return rcfg;
+ +
+ /* AR2316 relocates radio config to new location */ + /* AR2316 relocates radio config to new location */
+ begin = bcfg + 0xf8; + begin = bcfg + 0xf8;
+ end = flash_limit - 0x1000 + 0xf8; + end = limit - 0x1000 + 0xf8;
+ for (rcfg = begin; rcfg < end; rcfg += 0x1000) + for (rcfg = begin; rcfg < end; rcfg += 0x1000)
+ if (check_notempty(rcfg) && check_radio_magic(rcfg)) + if (check_notempty(rcfg) && check_radio_magic(rcfg))
+ return rcfg; + return rcfg;
+ +
+ pr_warn("WARNING: Could not find Radio Configuration data\n");
+
+ return NULL; + return NULL;
+} +}
+ +
+int __init ath25_find_config(u8 *flash_limit) +/*
+ * NB: Search region size could be larger than the actual flash size,
+ * but this shouldn't be a problem here, because the flash
+ * will simply be mapped multiple times.
+ */
+int __init ath25_find_config(phys_addr_t base, unsigned long size)
+{ +{
+ const void __iomem *flash_base, *flash_limit;
+ struct ath25_boarddata *config; + struct ath25_boarddata *config;
+ unsigned int rcfg_size; + unsigned int rcfg_size;
+ int broken_boarddata = 0; + int broken_boarddata = 0;
+ u8 *bcfg, *rcfg; + const void __iomem *bcfg, *rcfg;
+ u8 *board_data; + u8 *board_data;
+ u8 *radio_data; + u8 *radio_data;
+ u8 *mac_addr; + u8 *mac_addr;
+ u32 offset; + u32 offset;
+ +
+ flash_base = ioremap_nocache(base, size);
+ flash_limit = flash_base + size;
+
+ ath25_board.config = NULL; + ath25_board.config = NULL;
+ ath25_board.radio = NULL; + ath25_board.radio = NULL;
+
+ /* Copy the board and radio data to RAM, because accessing the mapped + /* Copy the board and radio data to RAM, because accessing the mapped
+ * memory of the flash directly after booting is not safe */ + * memory of the flash directly after booting is not safe */
+ +
@ -214,12 +220,12 @@
+ +
+ if (!bcfg) { + if (!bcfg) {
+ pr_warn("WARNING: No board configuration data found!\n"); + pr_warn("WARNING: No board configuration data found!\n");
+ return -ENODEV; + goto error;
+ } + }
+ +
+ board_data = kzalloc(BOARD_CONFIG_BUFSZ, GFP_KERNEL); + board_data = kzalloc(BOARD_CONFIG_BUFSZ, GFP_KERNEL);
+ ath25_board.config = (struct ath25_boarddata *)board_data; + ath25_board.config = (struct ath25_boarddata *)board_data;
+ memcpy(board_data, bcfg, 0x100); + memcpy_fromio(board_data, bcfg, 0x100);
+ if (broken_boarddata) { + if (broken_boarddata) {
+ pr_warn("WARNING: broken board data detected\n"); + pr_warn("WARNING: broken board data detected\n");
+ config = ath25_board.config; + config = ath25_board.config;
@ -237,13 +243,11 @@
+ /* Radio config starts 0x100 bytes after board config, regardless + /* Radio config starts 0x100 bytes after board config, regardless
+ * of what the physical layout on the flash chip looks like */ + * of what the physical layout on the flash chip looks like */
+ +
+ if (ath25_board.radio) + rcfg = find_radio_config(flash_limit, bcfg);
+ rcfg = (u8 *)ath25_board.radio; + if (!rcfg) {
+ else + pr_warn("WARNING: Could not find Radio Configuration data\n");
+ rcfg = find_radio_config(flash_limit, bcfg); + goto error;
+ + }
+ if (!rcfg)
+ return -ENODEV;
+ +
+ radio_data = board_data + 0x100 + ((rcfg - bcfg) & 0xfff); + radio_data = board_data + 0x100 + ((rcfg - bcfg) & 0xfff);
+ ath25_board.radio = radio_data; + ath25_board.radio = radio_data;
@ -251,7 +255,7 @@
+ pr_info("Radio config found at offset 0x%x (0x%x)\n", rcfg - bcfg, + pr_info("Radio config found at offset 0x%x (0x%x)\n", rcfg - bcfg,
+ offset); + offset);
+ rcfg_size = BOARD_CONFIG_BUFSZ - offset; + rcfg_size = BOARD_CONFIG_BUFSZ - offset;
+ memcpy(radio_data, rcfg, rcfg_size); + memcpy_fromio(radio_data, rcfg, rcfg_size);
+ +
+ mac_addr = &radio_data[0x1d * 2]; + mac_addr = &radio_data[0x1d * 2];
+ if (is_broadcast_ether_addr(mac_addr)) { + if (is_broadcast_ether_addr(mac_addr)) {
@ -259,7 +263,13 @@
+ ether_addr_copy(mac_addr, ath25_board.config->wlan0_mac); + ether_addr_copy(mac_addr, ath25_board.config->wlan0_mac);
+ } + }
+ +
+ iounmap(flash_base);
+
+ return 0; + return 0;
+
+error:
+ iounmap(flash_base);
+ return -ENODEV;
+} +}
+ +
+static void ath25_halt(void) +static void ath25_halt(void)
@ -629,7 +639,7 @@
+#endif /* __ASM_MACH_ATH25_WAR_H */ +#endif /* __ASM_MACH_ATH25_WAR_H */
--- /dev/null --- /dev/null
+++ b/arch/mips/ath25/ar2315_regs.h +++ b/arch/mips/ath25/ar2315_regs.h
@@ -0,0 +1,480 @@ @@ -0,0 +1,481 @@
+/* +/*
+ * Register definitions for AR2315+ + * Register definitions for AR2315+
+ * + *
@ -672,7 +682,8 @@
+/* +/*
+ * Address map + * Address map
+ */ + */
+#define AR2315_SPI_READ 0x08000000 /* SPI FLASH */ +#define AR2315_SPI_READ_BASE 0x08000000 /* SPI flash */
+#define AR2315_SPI_READ_SIZE 0x01000000
+#define AR2315_WLAN0 0x10000000 /* Wireless MMR */ +#define AR2315_WLAN0 0x10000000 /* Wireless MMR */
+#define AR2315_PCI 0x10100000 /* PCI MMR */ +#define AR2315_PCI 0x10100000 /* PCI MMR */
+#define AR2315_PCI_SIZE 0x00001000 +#define AR2315_PCI_SIZE 0x00001000
@ -1112,7 +1123,7 @@
+#endif /* __ASM_MACH_ATH25_AR2315_REGS_H */ +#endif /* __ASM_MACH_ATH25_AR2315_REGS_H */
--- /dev/null --- /dev/null
+++ b/arch/mips/ath25/ar5312_regs.h +++ b/arch/mips/ath25/ar5312_regs.h
@@ -0,0 +1,227 @@ @@ -0,0 +1,228 @@
+/* +/*
+ * This file is subject to the terms and conditions of the GNU General Public + * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive + * License. See the file "COPYING" in the main directory of this archive
@ -1170,7 +1181,8 @@
+#define AR5312_GPIO_BASE 0x1c002000 +#define AR5312_GPIO_BASE 0x1c002000
+#define AR5312_RST_BASE 0x1c003000 +#define AR5312_RST_BASE 0x1c003000
+#define AR5312_RST_SIZE 0x00000100 +#define AR5312_RST_SIZE 0x00000100
+#define AR5312_FLASH 0x1e000000 +#define AR5312_FLASH_BASE 0x1e000000
+#define AR5312_FLASH_SIZE 0x00800000
+ +
+/* +/*
+ * Need these defines to determine true number of ethernet MACs + * Need these defines to determine true number of ethernet MACs
@ -1342,7 +1354,7 @@
+#endif /* __ASM_MACH_ATH25_AR5312_REGS_H */ +#endif /* __ASM_MACH_ATH25_AR5312_REGS_H */
--- /dev/null --- /dev/null
+++ b/arch/mips/ath25/ar5312.c +++ b/arch/mips/ath25/ar5312.c
@@ -0,0 +1,483 @@ @@ -0,0 +1,478 @@
+/* +/*
+ * This file is subject to the terms and conditions of the GNU General Public + * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive + * License. See the file "COPYING" in the main directory of this archive
@ -1523,8 +1535,8 @@
+}; +};
+ +
+static struct resource ar5312_flash_resource = { +static struct resource ar5312_flash_resource = {
+ .start = AR5312_FLASH, + .start = AR5312_FLASH_BASE,
+ .end = AR5312_FLASH + 0x800000 - 1, + .end = AR5312_FLASH_BASE + AR5312_FLASH_SIZE - 1,
+ .flags = IORESOURCE_MEM, + .flags = IORESOURCE_MEM,
+}; +};
+ +
@ -1567,12 +1579,7 @@
+}; +};
+#endif +#endif
+ +
+/* +static void __init ar5312_flash_init(void)
+ * NB: This mapping size is larger than the actual flash size,
+ * but this shouldn't be a problem here, because the flash
+ * will simply be mapped multiple times.
+ */
+static char __init *ar5312_flash_limit(void)
+{ +{
+ void __iomem *flashctl_base; + void __iomem *flashctl_base;
+ u32 ctl; + u32 ctl;
@ -1617,8 +1624,6 @@
+ __raw_writel(ctl, flashctl_base + AR5312_FLASHCTL2); + __raw_writel(ctl, flashctl_base + AR5312_FLASHCTL2);
+ +
+ iounmap(flashctl_base); + iounmap(flashctl_base);
+
+ return (char *)KSEG1ADDR(AR5312_FLASH + 0x800000);
+} +}
+ +
+void __init ar5312_init_devices(void) +void __init ar5312_init_devices(void)
@ -1626,8 +1631,10 @@
+ struct ath25_boarddata *config; + struct ath25_boarddata *config;
+ u8 *c; + u8 *c;
+ +
+ ar5312_flash_init();
+
+ /* Locate board/radio config data */ + /* Locate board/radio config data */
+ ath25_find_config(ar5312_flash_limit()); + ath25_find_config(AR5312_FLASH_BASE, AR5312_FLASH_SIZE);
+ config = ath25_board.config; + config = ath25_board.config;
+ +
+ /* AR2313 has CPU minor rev. 10 */ + /* AR2313 has CPU minor rev. 10 */
@ -1828,7 +1835,7 @@
+} +}
--- /dev/null --- /dev/null
+++ b/arch/mips/ath25/ar2315.c +++ b/arch/mips/ath25/ar2315.c
@@ -0,0 +1,428 @@ @@ -0,0 +1,418 @@
+/* +/*
+ * This file is subject to the terms and conditions of the GNU General Public + * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive + * License. See the file "COPYING" in the main directory of this archive
@ -2018,8 +2025,8 @@
+ { + {
+ .name = "spiflash_read", + .name = "spiflash_read",
+ .flags = IORESOURCE_MEM, + .flags = IORESOURCE_MEM,
+ .start = AR2315_SPI_READ, + .start = AR2315_SPI_READ_BASE,
+ .end = AR2315_SPI_READ + 0x1000000 - 1, + .end = AR2315_SPI_READ_BASE + AR2315_SPI_READ_SIZE - 1,
+ }, + },
+ { + {
+ .name = "spiflash_mmr", + .name = "spiflash_mmr",
@ -2056,16 +2063,6 @@
+ .num_resources = ARRAY_SIZE(ar2315_wdt_res) + .num_resources = ARRAY_SIZE(ar2315_wdt_res)
+}; +};
+ +
+/*
+ * NB: We use mapping size that is larger than the actual flash size,
+ * but this shouldn't be a problem here, because the flash will simply
+ * be mapped multiple times.
+ */
+static u8 __init *ar2315_flash_limit(void)
+{
+ return (u8 *)KSEG1ADDR(ar2315_spiflash_res[0].end + 1);
+}
+
+#ifdef CONFIG_LEDS_GPIO +#ifdef CONFIG_LEDS_GPIO
+static struct gpio_led ar2315_leds[6]; +static struct gpio_led ar2315_leds[6];
+static struct gpio_led_platform_data ar2315_led_data = { +static struct gpio_led_platform_data ar2315_led_data = {
@ -2113,7 +2110,7 @@
+void __init ar2315_init_devices(void) +void __init ar2315_init_devices(void)
+{ +{
+ /* Find board configuration */ + /* Find board configuration */
+ ath25_find_config(ar2315_flash_limit()); + ath25_find_config(AR2315_SPI_READ_BASE, AR2315_SPI_READ_SIZE);
+ ar2315_eth_data.macaddr = ath25_board.config->enet0_mac; + ar2315_eth_data.macaddr = ath25_board.config->enet0_mac;
+ +
+ ar2315_init_gpio_leds(); + ar2315_init_gpio_leds();
@ -2365,7 +2362,7 @@
+extern struct ar231x_board_config ath25_board; +extern struct ar231x_board_config ath25_board;
+extern void (*ath25_irq_dispatch)(void); +extern void (*ath25_irq_dispatch)(void);
+ +
+int ath25_find_config(u8 *flash_limit); +int ath25_find_config(phys_addr_t offset, unsigned long size);
+int ath25_add_ethernet(int nr, u32 base, const char *mii_name, u32 mii_base, +int ath25_add_ethernet(int nr, u32 base, const char *mii_name, u32 mii_base,
+ int irq, void *pdata); + int irq, void *pdata);
+void ath25_serial_setup(u32 mapbase, int irq, unsigned int uartclk); +void ath25_serial_setup(u32 mapbase, int irq, unsigned int uartclk);

View file

@ -33,7 +33,7 @@
#ifdef CONFIG_LEDS_GPIO #ifdef CONFIG_LEDS_GPIO
static struct gpio_led ar5312_leds[] = { static struct gpio_led ar5312_leds[] = {
{ .name = "wlan", .gpio = 0, .active_low = 1, }, { .name = "wlan", .gpio = 0, .active_low = 1, },
@@ -299,6 +315,8 @@ void __init ar5312_init_devices(void) @@ -294,6 +310,8 @@ void __init ar5312_init_devices(void)
platform_device_register(&ar5312_physmap_flash); platform_device_register(&ar5312_physmap_flash);

View file

@ -40,11 +40,11 @@
+ .num_resources = ARRAY_SIZE(ar2315_gpio_res) + .num_resources = ARRAY_SIZE(ar2315_gpio_res)
+}; +};
+ +
/* #ifdef CONFIG_LEDS_GPIO
* NB: We use mapping size that is larger than the actual flash size, static struct gpio_led ar2315_leds[6];
* but this shouldn't be a problem here, because the flash will simply static struct gpio_led_platform_data ar2315_led_data = {
@@ -285,6 +313,7 @@ void __init ar2315_init_devices(void) @@ -275,6 +303,7 @@ void __init ar2315_init_devices(void)
ath25_find_config(ar2315_flash_limit()); ath25_find_config(AR2315_SPI_READ_BASE, AR2315_SPI_READ_SIZE);
ar2315_eth_data.macaddr = ath25_board.config->enet0_mac; ar2315_eth_data.macaddr = ath25_board.config->enet0_mac;
+ platform_device_register(&ar2315_gpio); + platform_device_register(&ar2315_gpio);

View file

@ -531,7 +531,7 @@
else if (pending & CAUSEF_IP2) else if (pending & CAUSEF_IP2)
do_IRQ(AR2315_IRQ_MISC_INTRS); do_IRQ(AR2315_IRQ_MISC_INTRS);
else if (pending & CAUSEF_IP7) else if (pending & CAUSEF_IP7)
@@ -450,8 +454,60 @@ void __init ar2315_plat_mem_setup(void) @@ -440,8 +444,60 @@ void __init ar2315_plat_mem_setup(void)
_machine_restart = ar2315_restart; _machine_restart = ar2315_restart;
} }