2014-10-29 03:18:38 +04:00
/*
* 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
* for more details .
*
* Copyright ( C ) 2003 Atheros Communications , Inc . , All Rights Reserved .
* Copyright ( C ) 2006 FON Technology , SL .
* Copyright ( C ) 2006 Imre Kaloz < kaloz @ openwrt . org >
* Copyright ( C ) 2006 - 2009 Felix Fietkau < nbd @ openwrt . org >
*/
# include <linux/init.h>
# include <linux/interrupt.h>
# include <asm/irq_cpu.h>
# include <asm/reboot.h>
# include <asm/bootinfo.h>
# include <asm/time.h>
2014-10-29 03:18:44 +04:00
# include <ath25_platform.h>
2014-10-29 03:18:39 +04:00
# include "devices.h"
# include "ar5312.h"
2014-10-29 03:18:40 +04:00
# include "ar2315.h"
2014-10-29 03:18:39 +04:00
2014-10-29 03:18:41 +04:00
void ( * ath25_irq_dispatch ) ( void ) ;
2014-10-29 03:18:44 +04:00
static inline bool check_radio_magic ( const void __iomem * addr )
{
addr + = 0x7a ; /* offset for flash magic */
return ( __raw_readb ( addr ) = = 0x5a ) & & ( __raw_readb ( addr + 1 ) = = 0xa5 ) ;
}
static inline bool check_notempty ( const void __iomem * addr )
{
return __raw_readl ( addr ) ! = 0xffffffff ;
}
static inline bool check_board_data ( const void __iomem * addr , bool broken )
{
/* config magic found */
if ( __raw_readl ( addr ) = = ATH25_BD_MAGIC )
return true ;
if ( ! broken )
return false ;
/* broken board data detected, use radio data to find the
* offset , user will fix this */
if ( check_radio_magic ( addr + 0x1000 ) )
return true ;
if ( check_radio_magic ( addr + 0xf8 ) )
return true ;
return false ;
}
static const void __iomem * __init find_board_config ( const void __iomem * limit ,
const bool broken )
{
const void __iomem * addr ;
const void __iomem * begin = limit - 0x1000 ;
const void __iomem * end = limit - 0x30000 ;
for ( addr = begin ; addr > = end ; addr - = 0x1000 )
if ( check_board_data ( addr , broken ) )
return addr ;
return NULL ;
}
static const void __iomem * __init find_radio_config ( const void __iomem * limit ,
const void __iomem * bcfg )
{
const void __iomem * rcfg , * begin , * end ;
/*
* Now find the start of Radio Configuration data , using heuristics :
* Search forward from Board Configuration data by 0x1000 bytes
* at a time until we find non - 0xffffffff .
*/
begin = bcfg + 0x1000 ;
end = limit ;
for ( rcfg = begin ; rcfg < end ; rcfg + = 0x1000 )
if ( check_notempty ( rcfg ) & & check_radio_magic ( rcfg ) )
return rcfg ;
/* AR2316 relocates radio config to new location */
begin = bcfg + 0xf8 ;
end = limit - 0x1000 + 0xf8 ;
for ( rcfg = begin ; rcfg < end ; rcfg + = 0x1000 )
if ( check_notempty ( rcfg ) & & check_radio_magic ( rcfg ) )
return rcfg ;
return NULL ;
}
/*
* 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 ;
unsigned int rcfg_size ;
int broken_boarddata = 0 ;
const void __iomem * bcfg , * rcfg ;
u8 * board_data ;
u8 * radio_data ;
u8 * mac_addr ;
u32 offset ;
2020-01-06 09:43:50 +01:00
flash_base = ioremap ( base , size ) ;
2014-10-29 03:18:44 +04:00
flash_limit = flash_base + size ;
ath25_board . config = NULL ;
ath25_board . radio = NULL ;
/* Copy the board and radio data to RAM, because accessing the mapped
* memory of the flash directly after booting is not safe */
/* Try to find valid board and radio data */
bcfg = find_board_config ( flash_limit , false ) ;
/* If that fails, try to at least find valid radio data */
if ( ! bcfg ) {
bcfg = find_board_config ( flash_limit , true ) ;
broken_boarddata = 1 ;
}
if ( ! bcfg ) {
pr_warn ( " WARNING: No board configuration data found! \n " ) ;
goto error ;
}
board_data = kzalloc ( BOARD_CONFIG_BUFSZ , GFP_KERNEL ) ;
2018-02-22 17:50:12 +00:00
if ( ! board_data )
goto error ;
2014-10-29 03:18:44 +04:00
ath25_board . config = ( struct ath25_boarddata * ) board_data ;
memcpy_fromio ( board_data , bcfg , 0x100 ) ;
if ( broken_boarddata ) {
pr_warn ( " WARNING: broken board data detected \n " ) ;
config = ath25_board . config ;
if ( is_zero_ether_addr ( config - > enet0_mac ) ) {
pr_info ( " Fixing up empty mac addresses \n " ) ;
config - > reset_config_gpio = 0xffff ;
config - > sys_led_gpio = 0xffff ;
2018-06-22 23:29:28 -07:00
eth_random_addr ( config - > wlan0_mac ) ;
2014-10-29 03:18:44 +04:00
config - > wlan0_mac [ 0 ] & = ~ 0x06 ;
2018-06-22 23:29:28 -07:00
eth_random_addr ( config - > enet0_mac ) ;
eth_random_addr ( config - > enet1_mac ) ;
2014-10-29 03:18:44 +04:00
}
}
/* Radio config starts 0x100 bytes after board config, regardless
* of what the physical layout on the flash chip looks like */
rcfg = find_radio_config ( flash_limit , bcfg ) ;
if ( ! rcfg ) {
pr_warn ( " WARNING: Could not find Radio Configuration data \n " ) ;
goto error ;
}
radio_data = board_data + 0x100 + ( ( rcfg - bcfg ) & 0xfff ) ;
ath25_board . radio = radio_data ;
offset = radio_data - board_data ;
pr_info ( " Radio config found at offset 0x%x (0x%x) \n " , rcfg - bcfg ,
offset ) ;
rcfg_size = BOARD_CONFIG_BUFSZ - offset ;
memcpy_fromio ( radio_data , rcfg , rcfg_size ) ;
mac_addr = & radio_data [ 0x1d * 2 ] ;
if ( is_broadcast_ether_addr ( mac_addr ) ) {
pr_info ( " Radio MAC is blank; using board-data \n " ) ;
ether_addr_copy ( mac_addr , ath25_board . config - > wlan0_mac ) ;
}
iounmap ( flash_base ) ;
return 0 ;
error :
iounmap ( flash_base ) ;
return - ENODEV ;
}
2014-10-29 03:18:38 +04:00
static void ath25_halt ( void )
{
local_irq_disable ( ) ;
unreachable ( ) ;
}
void __init plat_mem_setup ( void )
{
_machine_halt = ath25_halt ;
pm_power_off = ath25_halt ;
2014-10-29 03:18:39 +04:00
if ( is_ar5312 ( ) )
ar5312_plat_mem_setup ( ) ;
2014-10-29 03:18:40 +04:00
else
ar2315_plat_mem_setup ( ) ;
2014-10-29 03:18:39 +04:00
2014-10-29 03:18:38 +04:00
/* Disable data watchpoints */
write_c0_watchlo0 ( 0 ) ;
}
asmlinkage void plat_irq_dispatch ( void )
{
2014-10-29 03:18:41 +04:00
ath25_irq_dispatch ( ) ;
2014-10-29 03:18:38 +04:00
}
void __init plat_time_init ( void )
{
2014-10-29 03:18:39 +04:00
if ( is_ar5312 ( ) )
ar5312_plat_time_init ( ) ;
2014-10-29 03:18:40 +04:00
else
ar2315_plat_time_init ( ) ;
2014-10-29 03:18:38 +04:00
}
2015-04-27 18:47:55 -04:00
unsigned int get_c0_compare_int ( void )
2014-10-29 03:18:38 +04:00
{
return CP0_LEGACY_COMPARE_IRQ ;
}
void __init arch_init_irq ( void )
{
clear_c0_status ( ST0_IM ) ;
mips_cpu_irq_init ( ) ;
2014-10-29 03:18:41 +04:00
/* Initialize interrupt controllers */
if ( is_ar5312 ( ) )
ar5312_arch_init_irq ( ) ;
else
ar2315_arch_init_irq ( ) ;
2014-10-29 03:18:38 +04:00
}