2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
6 * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved.
7 * Copyright (C) 2006 FON Technology, SL.
8 * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
9 * Copyright (C) 2006-2009 Felix Fietkau <nbd@openwrt.org>
12 #include <linux/init.h>
13 #include <linux/interrupt.h>
14 #include <asm/irq_cpu.h>
15 #include <asm/reboot.h>
16 #include <asm/bootinfo.h>
19 #include <ath25_platform.h>
24 void (*ath25_irq_dispatch
)(void);
26 static inline bool check_radio_magic(const void __iomem
*addr
)
28 addr
+= 0x7a; /* offset for flash magic */
29 return (__raw_readb(addr
) == 0x5a) && (__raw_readb(addr
+ 1) == 0xa5);
32 static inline bool check_notempty(const void __iomem
*addr
)
34 return __raw_readl(addr
) != 0xffffffff;
37 static inline bool check_board_data(const void __iomem
*addr
, bool broken
)
39 /* config magic found */
40 if (__raw_readl(addr
) == ATH25_BD_MAGIC
)
46 /* broken board data detected, use radio data to find the
47 * offset, user will fix this */
49 if (check_radio_magic(addr
+ 0x1000))
51 if (check_radio_magic(addr
+ 0xf8))
57 static const void __iomem
* __init
find_board_config(const void __iomem
*limit
,
60 const void __iomem
*addr
;
61 const void __iomem
*begin
= limit
- 0x1000;
62 const void __iomem
*end
= limit
- 0x30000;
64 for (addr
= begin
; addr
>= end
; addr
-= 0x1000)
65 if (check_board_data(addr
, broken
))
71 static const void __iomem
* __init
find_radio_config(const void __iomem
*limit
,
72 const void __iomem
*bcfg
)
74 const void __iomem
*rcfg
, *begin
, *end
;
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.
81 begin
= bcfg
+ 0x1000;
83 for (rcfg
= begin
; rcfg
< end
; rcfg
+= 0x1000)
84 if (check_notempty(rcfg
) && check_radio_magic(rcfg
))
87 /* AR2316 relocates radio config to new location */
89 end
= limit
- 0x1000 + 0xf8;
90 for (rcfg
= begin
; rcfg
< end
; rcfg
+= 0x1000)
91 if (check_notempty(rcfg
) && check_radio_magic(rcfg
))
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.
102 int __init
ath25_find_config(phys_addr_t base
, unsigned long size
)
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
;
114 flash_base
= ioremap_nocache(base
, size
);
115 flash_limit
= flash_base
+ size
;
117 ath25_board
.config
= NULL
;
118 ath25_board
.radio
= NULL
;
120 /* Copy the board and radio data to RAM, because accessing the mapped
121 * memory of the flash directly after booting is not safe */
123 /* Try to find valid board and radio data */
124 bcfg
= find_board_config(flash_limit
, false);
126 /* If that fails, try to at least find valid radio data */
128 bcfg
= find_board_config(flash_limit
, true);
129 broken_boarddata
= 1;
133 pr_warn("WARNING: No board configuration data found!\n");
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
);
154 /* Radio config starts 0x100 bytes after board config, regardless
155 * of what the physical layout on the flash chip looks like */
157 rcfg
= find_radio_config(flash_limit
, bcfg
);
159 pr_warn("WARNING: Could not find Radio Configuration data\n");
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
,
168 rcfg_size
= BOARD_CONFIG_BUFSZ
- offset
;
169 memcpy_fromio(radio_data
, rcfg
, rcfg_size
);
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
);
186 static void ath25_halt(void)
192 void __init
plat_mem_setup(void)
194 _machine_halt
= ath25_halt
;
195 pm_power_off
= ath25_halt
;
198 ar5312_plat_mem_setup();
200 ar2315_plat_mem_setup();
202 /* Disable data watchpoints */
203 write_c0_watchlo0(0);
206 asmlinkage
void plat_irq_dispatch(void)
208 ath25_irq_dispatch();
211 void __init
plat_time_init(void)
214 ar5312_plat_time_init();
216 ar2315_plat_time_init();
219 unsigned int __cpuinit
get_c0_compare_int(void)
221 return CP0_LEGACY_COMPARE_IRQ
;
224 void __init
arch_init_irq(void)
226 clear_c0_status(ST0_IM
);
229 /* Initialize interrupt controllers */
231 ar5312_arch_init_irq();
233 ar2315_arch_init_irq();