aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorSergey Ryazanov <ryazanov.s.a@gmail.com>2014-10-28 19:18:44 -0400
committerRalf Baechle <ralf@linux-mips.org>2014-11-24 01:45:27 -0500
commita7473717483ef3bb78563611bf1b3b82c5515b2e (patch)
treed5e3431409c4aee784c7c8401cf19614aed91d7c /arch/mips
parent1ac91b1f686e9d819b16525baf2e8db3c282edba (diff)
MIPS: ath25: add board configuration detection
All boards based on AR5312/AR2315 SoC have a special structure located at the end of flash. This structure contains board-specific data such as Ethernet and Wireless MAC addresses. The flash is mapped to the memmory at predefined location. Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com> Cc: Linux MIPS <linux-mips@linux-mips.org> Patchwork: https://patchwork.linux-mips.org/patch/8243/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/ath25/ar2315.c6
-rw-r--r--arch/mips/ath25/ar2315.h2
-rw-r--r--arch/mips/ath25/ar5312.c39
-rw-r--r--arch/mips/ath25/ar5312.h2
-rw-r--r--arch/mips/ath25/board.c161
-rw-r--r--arch/mips/ath25/devices.c15
-rw-r--r--arch/mips/ath25/devices.h2
-rw-r--r--arch/mips/include/asm/mach-ath25/ath25_platform.h73
8 files changed, 300 insertions, 0 deletions
diff --git a/arch/mips/ath25/ar2315.c b/arch/mips/ath25/ar2315.c
index d10eac4cd828..3ba8e757add6 100644
--- a/arch/mips/ath25/ar2315.c
+++ b/arch/mips/ath25/ar2315.c
@@ -160,6 +160,12 @@ void __init ar2315_arch_init_irq(void)
160 ar2315_misc_irq_domain = domain; 160 ar2315_misc_irq_domain = domain;
161} 161}
162 162
163void __init ar2315_init_devices(void)
164{
165 /* Find board configuration */
166 ath25_find_config(AR2315_SPI_READ_BASE, AR2315_SPI_READ_SIZE);
167}
168
163static void ar2315_restart(char *command) 169static void ar2315_restart(char *command)
164{ 170{
165 void (*mips_reset_vec)(void) = (void *)0xbfc00000; 171 void (*mips_reset_vec)(void) = (void *)0xbfc00000;
diff --git a/arch/mips/ath25/ar2315.h b/arch/mips/ath25/ar2315.h
index 4af5f4c75f44..877afe63eed5 100644
--- a/arch/mips/ath25/ar2315.h
+++ b/arch/mips/ath25/ar2315.h
@@ -4,6 +4,7 @@
4#ifdef CONFIG_SOC_AR2315 4#ifdef CONFIG_SOC_AR2315
5 5
6void ar2315_arch_init_irq(void); 6void ar2315_arch_init_irq(void);
7void ar2315_init_devices(void);
7void ar2315_plat_time_init(void); 8void ar2315_plat_time_init(void);
8void ar2315_plat_mem_setup(void); 9void ar2315_plat_mem_setup(void);
9void ar2315_arch_init(void); 10void ar2315_arch_init(void);
@@ -11,6 +12,7 @@ void ar2315_arch_init(void);
11#else 12#else
12 13
13static inline void ar2315_arch_init_irq(void) {} 14static inline void ar2315_arch_init_irq(void) {}
15static inline void ar2315_init_devices(void) {}
14static inline void ar2315_plat_time_init(void) {} 16static inline void ar2315_plat_time_init(void) {}
15static inline void ar2315_plat_mem_setup(void) {} 17static inline void ar2315_plat_mem_setup(void) {}
16static inline void ar2315_arch_init(void) {} 18static inline void ar2315_arch_init(void) {}
diff --git a/arch/mips/ath25/ar5312.c b/arch/mips/ath25/ar5312.c
index 398d4fd4dd2d..41bd56d6ab23 100644
--- a/arch/mips/ath25/ar5312.c
+++ b/arch/mips/ath25/ar5312.c
@@ -158,6 +158,45 @@ void __init ar5312_arch_init_irq(void)
158 ar5312_misc_irq_domain = domain; 158 ar5312_misc_irq_domain = domain;
159} 159}
160 160
161static void __init ar5312_flash_init(void)
162{
163 void __iomem *flashctl_base;
164 u32 ctl;
165
166 flashctl_base = ioremap_nocache(AR5312_FLASHCTL_BASE,
167 AR5312_FLASHCTL_SIZE);
168
169 /*
170 * Configure flash bank 0.
171 * Assume 8M window size. Flash will be aliased if it's smaller
172 */
173 ctl = __raw_readl(flashctl_base + AR5312_FLASHCTL0);
174 ctl &= AR5312_FLASHCTL_MW;
175 ctl |= AR5312_FLASHCTL_E | AR5312_FLASHCTL_AC_8M | AR5312_FLASHCTL_RBLE;
176 ctl |= 0x01 << AR5312_FLASHCTL_IDCY_S;
177 ctl |= 0x07 << AR5312_FLASHCTL_WST1_S;
178 ctl |= 0x07 << AR5312_FLASHCTL_WST2_S;
179 __raw_writel(ctl, flashctl_base + AR5312_FLASHCTL0);
180
181 /* Disable other flash banks */
182 ctl = __raw_readl(flashctl_base + AR5312_FLASHCTL1);
183 ctl &= ~(AR5312_FLASHCTL_E | AR5312_FLASHCTL_AC);
184 __raw_writel(ctl, flashctl_base + AR5312_FLASHCTL1);
185 ctl = __raw_readl(flashctl_base + AR5312_FLASHCTL2);
186 ctl &= ~(AR5312_FLASHCTL_E | AR5312_FLASHCTL_AC);
187 __raw_writel(ctl, flashctl_base + AR5312_FLASHCTL2);
188
189 iounmap(flashctl_base);
190}
191
192void __init ar5312_init_devices(void)
193{
194 ar5312_flash_init();
195
196 /* Locate board/radio config data */
197 ath25_find_config(AR5312_FLASH_BASE, AR5312_FLASH_SIZE);
198}
199
161static void ar5312_restart(char *command) 200static void ar5312_restart(char *command)
162{ 201{
163 /* reset the system */ 202 /* reset the system */
diff --git a/arch/mips/ath25/ar5312.h b/arch/mips/ath25/ar5312.h
index 86dfc6d04a6d..470abb0052bd 100644
--- a/arch/mips/ath25/ar5312.h
+++ b/arch/mips/ath25/ar5312.h
@@ -4,6 +4,7 @@
4#ifdef CONFIG_SOC_AR5312 4#ifdef CONFIG_SOC_AR5312
5 5
6void ar5312_arch_init_irq(void); 6void ar5312_arch_init_irq(void);
7void ar5312_init_devices(void);
7void ar5312_plat_time_init(void); 8void ar5312_plat_time_init(void);
8void ar5312_plat_mem_setup(void); 9void ar5312_plat_mem_setup(void);
9void ar5312_arch_init(void); 10void ar5312_arch_init(void);
@@ -11,6 +12,7 @@ void ar5312_arch_init(void);
11#else 12#else
12 13
13static inline void ar5312_arch_init_irq(void) {} 14static inline void ar5312_arch_init_irq(void) {}
15static inline void ar5312_init_devices(void) {}
14static inline void ar5312_plat_time_init(void) {} 16static inline void ar5312_plat_time_init(void) {}
15static inline void ar5312_plat_mem_setup(void) {} 17static inline void ar5312_plat_mem_setup(void) {}
16static inline void ar5312_arch_init(void) {} 18static inline void ar5312_arch_init(void) {}
diff --git a/arch/mips/ath25/board.c b/arch/mips/ath25/board.c
index d4675e04a634..b8bb78282d6a 100644
--- a/arch/mips/ath25/board.c
+++ b/arch/mips/ath25/board.c
@@ -16,12 +16,173 @@
16#include <asm/bootinfo.h> 16#include <asm/bootinfo.h>
17#include <asm/time.h> 17#include <asm/time.h>
18 18
19#include <ath25_platform.h>
19#include "devices.h" 20#include "devices.h"
20#include "ar5312.h" 21#include "ar5312.h"
21#include "ar2315.h" 22#include "ar2315.h"
22 23
23void (*ath25_irq_dispatch)(void); 24void (*ath25_irq_dispatch)(void);
24 25
26static inline bool check_radio_magic(const void __iomem *addr)
27{
28 addr += 0x7a; /* offset for flash magic */
29 return (__raw_readb(addr) == 0x5a) && (__raw_readb(addr + 1) == 0xa5);
30}
31
32static inline bool check_notempty(const void __iomem *addr)
33{
34 return __raw_readl(addr) != 0xffffffff;
35}
36
37static inline bool check_board_data(const void __iomem *addr, bool broken)
38{
39 /* config magic found */
40 if (__raw_readl(addr) == ATH25_BD_MAGIC)
41 return true;
42
43 if (!broken)
44 return false;
45
46 /* broken board data detected, use radio data to find the
47 * offset, user will fix this */
48
49 if (check_radio_magic(addr + 0x1000))
50 return true;
51 if (check_radio_magic(addr + 0xf8))
52 return true;
53
54 return false;
55}
56
57static const void __iomem * __init find_board_config(const void __iomem *limit,
58 const bool broken)
59{
60 const void __iomem *addr;
61 const void __iomem *begin = limit - 0x1000;
62 const void __iomem *end = limit - 0x30000;
63
64 for (addr = begin; addr >= end; addr -= 0x1000)
65 if (check_board_data(addr, broken))
66 return addr;
67
68 return NULL;
69}
70
71static const void __iomem * __init find_radio_config(const void __iomem *limit,
72 const void __iomem *bcfg)
73{
74 const void __iomem *rcfg, *begin, *end;
75
76 /*
77 * Now find the start of Radio Configuration data, using heuristics:
78 * Search forward from Board Configuration data by 0x1000 bytes
79 * at a time until we find non-0xffffffff.
80 */
81 begin = bcfg + 0x1000;
82 end = limit;
83 for (rcfg = begin; rcfg < end; rcfg += 0x1000)
84 if (check_notempty(rcfg) && check_radio_magic(rcfg))
85 return rcfg;
86
87 /* AR2316 relocates radio config to new location */
88 begin = bcfg + 0xf8;
89 end = limit - 0x1000 + 0xf8;
90 for (rcfg = begin; rcfg < end; rcfg += 0x1000)
91 if (check_notempty(rcfg) && check_radio_magic(rcfg))
92 return rcfg;
93
94 return NULL;
95}
96
97/*
98 * NB: Search region size could be larger than the actual flash size,
99 * but this shouldn't be a problem here, because the flash
100 * will simply be mapped multiple times.
101 */
102int __init ath25_find_config(phys_addr_t base, unsigned long size)
103{
104 const void __iomem *flash_base, *flash_limit;
105 struct ath25_boarddata *config;
106 unsigned int rcfg_size;
107 int broken_boarddata = 0;
108 const void __iomem *bcfg, *rcfg;
109 u8 *board_data;
110 u8 *radio_data;
111 u8 *mac_addr;
112 u32 offset;
113
114 flash_base = ioremap_nocache(base, size);
115 flash_limit = flash_base + size;
116
117 ath25_board.config = NULL;
118 ath25_board.radio = NULL;
119
120 /* Copy the board and radio data to RAM, because accessing the mapped
121 * memory of the flash directly after booting is not safe */
122
123 /* Try to find valid board and radio data */
124 bcfg = find_board_config(flash_limit, false);
125
126 /* If that fails, try to at least find valid radio data */
127 if (!bcfg) {
128 bcfg = find_board_config(flash_limit, true);
129 broken_boarddata = 1;
130 }
131
132 if (!bcfg) {
133 pr_warn("WARNING: No board configuration data found!\n");
134 goto error;
135 }
136
137 board_data = kzalloc(BOARD_CONFIG_BUFSZ, GFP_KERNEL);
138 ath25_board.config = (struct ath25_boarddata *)board_data;
139 memcpy_fromio(board_data, bcfg, 0x100);
140 if (broken_boarddata) {
141 pr_warn("WARNING: broken board data detected\n");
142 config = ath25_board.config;
143 if (is_zero_ether_addr(config->enet0_mac)) {
144 pr_info("Fixing up empty mac addresses\n");
145 config->reset_config_gpio = 0xffff;
146 config->sys_led_gpio = 0xffff;
147 random_ether_addr(config->wlan0_mac);
148 config->wlan0_mac[0] &= ~0x06;
149 random_ether_addr(config->enet0_mac);
150 random_ether_addr(config->enet1_mac);
151 }
152 }
153
154 /* Radio config starts 0x100 bytes after board config, regardless
155 * of what the physical layout on the flash chip looks like */
156
157 rcfg = find_radio_config(flash_limit, bcfg);
158 if (!rcfg) {
159 pr_warn("WARNING: Could not find Radio Configuration data\n");
160 goto error;
161 }
162
163 radio_data = board_data + 0x100 + ((rcfg - bcfg) & 0xfff);
164 ath25_board.radio = radio_data;
165 offset = radio_data - board_data;
166 pr_info("Radio config found at offset 0x%x (0x%x)\n", rcfg - bcfg,
167 offset);
168 rcfg_size = BOARD_CONFIG_BUFSZ - offset;
169 memcpy_fromio(radio_data, rcfg, rcfg_size);
170
171 mac_addr = &radio_data[0x1d * 2];
172 if (is_broadcast_ether_addr(mac_addr)) {
173 pr_info("Radio MAC is blank; using board-data\n");
174 ether_addr_copy(mac_addr, ath25_board.config->wlan0_mac);
175 }
176
177 iounmap(flash_base);
178
179 return 0;
180
181error:
182 iounmap(flash_base);
183 return -ENODEV;
184}
185
25static void ath25_halt(void) 186static void ath25_halt(void)
26{ 187{
27 local_irq_disable(); 188 local_irq_disable();
diff --git a/arch/mips/ath25/devices.c b/arch/mips/ath25/devices.c
index 400419d8e7d9..d24dbb1ef8ea 100644
--- a/arch/mips/ath25/devices.c
+++ b/arch/mips/ath25/devices.c
@@ -3,10 +3,13 @@
3#include <linux/serial_8250.h> 3#include <linux/serial_8250.h>
4#include <asm/bootinfo.h> 4#include <asm/bootinfo.h>
5 5
6#include <ath25_platform.h>
6#include "devices.h" 7#include "devices.h"
7#include "ar5312.h" 8#include "ar5312.h"
8#include "ar2315.h" 9#include "ar2315.h"
9 10
11struct ar231x_board_config ath25_board;
12
10const char *get_system_type(void) 13const char *get_system_type(void)
11{ 14{
12 return "Atheros (unknown)"; 15 return "Atheros (unknown)";
@@ -28,6 +31,18 @@ void __init ath25_serial_setup(u32 mapbase, int irq, unsigned int uartclk)
28 early_serial_setup(&s); 31 early_serial_setup(&s);
29} 32}
30 33
34static int __init ath25_register_devices(void)
35{
36 if (is_ar5312())
37 ar5312_init_devices();
38 else
39 ar2315_init_devices();
40
41 return 0;
42}
43
44device_initcall(ath25_register_devices);
45
31static int __init ath25_arch_init(void) 46static int __init ath25_arch_init(void)
32{ 47{
33 if (is_ar5312()) 48 if (is_ar5312())
diff --git a/arch/mips/ath25/devices.h b/arch/mips/ath25/devices.h
index 23b53cb71c72..65e86cc46e49 100644
--- a/arch/mips/ath25/devices.h
+++ b/arch/mips/ath25/devices.h
@@ -7,8 +7,10 @@
7 7
8#define ATH25_IRQ_CPU_CLOCK (MIPS_CPU_IRQ_BASE + 7) /* C0_CAUSE: 0x8000 */ 8#define ATH25_IRQ_CPU_CLOCK (MIPS_CPU_IRQ_BASE + 7) /* C0_CAUSE: 0x8000 */
9 9
10extern struct ar231x_board_config ath25_board;
10extern void (*ath25_irq_dispatch)(void); 11extern void (*ath25_irq_dispatch)(void);
11 12
13int ath25_find_config(phys_addr_t offset, unsigned long size);
12void ath25_serial_setup(u32 mapbase, int irq, unsigned int uartclk); 14void ath25_serial_setup(u32 mapbase, int irq, unsigned int uartclk);
13 15
14static inline bool is_ar2315(void) 16static inline bool is_ar2315(void)
diff --git a/arch/mips/include/asm/mach-ath25/ath25_platform.h b/arch/mips/include/asm/mach-ath25/ath25_platform.h
new file mode 100644
index 000000000000..4f4ee4f9e5ec
--- /dev/null
+++ b/arch/mips/include/asm/mach-ath25/ath25_platform.h
@@ -0,0 +1,73 @@
1#ifndef __ASM_MACH_ATH25_PLATFORM_H
2#define __ASM_MACH_ATH25_PLATFORM_H
3
4#include <linux/etherdevice.h>
5
6/*
7 * This is board-specific data that is stored in a "fixed" location in flash.
8 * It is shared across operating systems, so it should not be changed lightly.
9 * The main reason we need it is in order to extract the ethernet MAC
10 * address(es).
11 */
12struct ath25_boarddata {
13 u32 magic; /* board data is valid */
14#define ATH25_BD_MAGIC 0x35333131 /* "5311", for all 531x/231x platforms */
15 u16 cksum; /* checksum (starting with BD_REV 2) */
16 u16 rev; /* revision of this struct */
17#define BD_REV 4
18 char board_name[64]; /* Name of board */
19 u16 major; /* Board major number */
20 u16 minor; /* Board minor number */
21 u32 flags; /* Board configuration */
22#define BD_ENET0 0x00000001 /* ENET0 is stuffed */
23#define BD_ENET1 0x00000002 /* ENET1 is stuffed */
24#define BD_UART1 0x00000004 /* UART1 is stuffed */
25#define BD_UART0 0x00000008 /* UART0 is stuffed (dma) */
26#define BD_RSTFACTORY 0x00000010 /* Reset factory defaults stuffed */
27#define BD_SYSLED 0x00000020 /* System LED stuffed */
28#define BD_EXTUARTCLK 0x00000040 /* External UART clock */
29#define BD_CPUFREQ 0x00000080 /* cpu freq is valid in nvram */
30#define BD_SYSFREQ 0x00000100 /* sys freq is set in nvram */
31#define BD_WLAN0 0x00000200 /* Enable WLAN0 */
32#define BD_MEMCAP 0x00000400 /* CAP SDRAM @ mem_cap for testing */
33#define BD_DISWATCHDOG 0x00000800 /* disable system watchdog */
34#define BD_WLAN1 0x00001000 /* Enable WLAN1 (ar5212) */
35#define BD_ISCASPER 0x00002000 /* FLAG for AR2312 */
36#define BD_WLAN0_2G_EN 0x00004000 /* FLAG for radio0_2G */
37#define BD_WLAN0_5G_EN 0x00008000 /* FLAG for radio0_2G */
38#define BD_WLAN1_2G_EN 0x00020000 /* FLAG for radio0_2G */
39#define BD_WLAN1_5G_EN 0x00040000 /* FLAG for radio0_2G */
40 u16 reset_config_gpio; /* Reset factory GPIO pin */
41 u16 sys_led_gpio; /* System LED GPIO pin */
42
43 u32 cpu_freq; /* CPU core frequency in Hz */
44 u32 sys_freq; /* System frequency in Hz */
45 u32 cnt_freq; /* Calculated C0_COUNT frequency */
46
47 u8 wlan0_mac[ETH_ALEN];
48 u8 enet0_mac[ETH_ALEN];
49 u8 enet1_mac[ETH_ALEN];
50
51 u16 pci_id; /* Pseudo PCIID for common code */
52 u16 mem_cap; /* cap bank1 in MB */
53
54 /* version 3 */
55 u8 wlan1_mac[ETH_ALEN]; /* (ar5212) */
56};
57
58#define BOARD_CONFIG_BUFSZ 0x1000
59
60/*
61 * Platform device information for the Wireless MAC
62 */
63struct ar231x_board_config {
64 u16 devid;
65
66 /* board config data */
67 struct ath25_boarddata *config;
68
69 /* radio calibration data */
70 const char *radio;
71};
72
73#endif /* __ASM_MACH_ATH25_PLATFORM_H */