2005-04-17 02:20:36 +04:00
/* linux/arch/arm/mach-s3c2410/cpu.c
*
* Copyright ( c ) 2004 - 2005 Simtec Electronics
* http : //www.simtec.co.uk/products/SWLINUX/
* Ben Dooks < ben @ simtec . co . uk >
*
* S3C24XX CPU Support
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/interrupt.h>
# include <linux/ioport.h>
2005-10-29 22:07:23 +04:00
# include <linux/platform_device.h>
2005-04-17 02:20:36 +04:00
# include <asm/hardware.h>
# include <asm/irq.h>
# include <asm/io.h>
# include <asm/delay.h>
# include <asm/mach/arch.h>
# include <asm/mach/map.h>
# include <asm/arch/regs-gpio.h>
# include "cpu.h"
# include "clock.h"
2006-02-02 00:24:24 +03:00
# include "s3c2400.h"
2005-04-17 02:20:36 +04:00
# include "s3c2410.h"
# include "s3c2440.h"
struct cpu_table {
unsigned long idcode ;
unsigned long idmask ;
void ( * map_io ) ( struct map_desc * mach_desc , int size ) ;
void ( * init_uarts ) ( struct s3c2410_uartcfg * cfg , int no ) ;
void ( * init_clocks ) ( int xtal ) ;
int ( * init ) ( void ) ;
const char * name ;
} ;
/* table of supported CPUs */
2006-02-02 00:24:24 +03:00
static const char name_s3c2400 [ ] = " S3C2400 " ;
2005-04-17 02:20:36 +04:00
static const char name_s3c2410 [ ] = " S3C2410 " ;
static const char name_s3c2440 [ ] = " S3C2440 " ;
static const char name_s3c2410a [ ] = " S3C2410A " ;
static const char name_s3c2440a [ ] = " S3C2440A " ;
static struct cpu_table cpu_ids [ ] __initdata = {
{
. idcode = 0x32410000 ,
. idmask = 0xffffffff ,
. map_io = s3c2410_map_io ,
. init_clocks = s3c2410_init_clocks ,
. init_uarts = s3c2410_init_uarts ,
. init = s3c2410_init ,
. name = name_s3c2410
} ,
{
. idcode = 0x32410002 ,
. idmask = 0xffffffff ,
. map_io = s3c2410_map_io ,
. init_clocks = s3c2410_init_clocks ,
. init_uarts = s3c2410_init_uarts ,
. init = s3c2410_init ,
. name = name_s3c2410a
} ,
{
. idcode = 0x32440000 ,
. idmask = 0xffffffff ,
. map_io = s3c2440_map_io ,
. init_clocks = s3c2440_init_clocks ,
. init_uarts = s3c2440_init_uarts ,
. init = s3c2440_init ,
. name = name_s3c2440
} ,
{
. idcode = 0x32440001 ,
. idmask = 0xffffffff ,
. map_io = s3c2440_map_io ,
. init_clocks = s3c2440_init_clocks ,
. init_uarts = s3c2440_init_uarts ,
. init = s3c2440_init ,
. name = name_s3c2440a
2006-02-02 00:24:24 +03:00
} ,
{
. idcode = 0x0 , /* S3C2400 doesn't have an idcode */
. idmask = 0xffffffff ,
. map_io = s3c2400_map_io ,
. init_clocks = s3c2400_init_clocks ,
. init_uarts = s3c2400_init_uarts ,
. init = s3c2400_init ,
. name = name_s3c2400
} ,
2005-04-17 02:20:36 +04:00
} ;
/* minimal IO mapping */
static struct map_desc s3c_iodesc [ ] __initdata = {
IODESC_ENT ( GPIO ) ,
IODESC_ENT ( IRQ ) ,
IODESC_ENT ( MEMCTRL ) ,
IODESC_ENT ( UART )
} ;
static struct cpu_table *
s3c_lookup_cpu ( unsigned long idcode )
{
struct cpu_table * tab ;
int count ;
tab = cpu_ids ;
for ( count = 0 ; count < ARRAY_SIZE ( cpu_ids ) ; count + + , tab + + ) {
if ( ( idcode & tab - > idmask ) = = tab - > idcode )
return tab ;
}
return NULL ;
}
/* board information */
static struct s3c24xx_board * board ;
void s3c24xx_set_board ( struct s3c24xx_board * b )
{
int i ;
board = b ;
if ( b - > clocks_count ! = 0 ) {
2006-03-24 14:16:13 +03:00
struct clk * * ptr = b - > clocks ;
2005-04-17 02:20:36 +04:00
for ( i = b - > clocks_count ; i > 0 ; i - - , ptr + + )
s3c24xx_register_clock ( * ptr ) ;
}
}
/* cpu information */
static struct cpu_table * cpu ;
void __init s3c24xx_init_io ( struct map_desc * mach_desc , int size )
{
2006-02-02 00:24:24 +03:00
unsigned long idcode = 0x0 ;
2005-04-17 02:20:36 +04:00
/* initialise the io descriptors we need for initialisation */
iotable_init ( s3c_iodesc , ARRAY_SIZE ( s3c_iodesc ) ) ;
2006-02-02 00:24:24 +03:00
# ifndef CONFIG_CPU_S3C2400
2005-04-17 02:20:36 +04:00
idcode = __raw_readl ( S3C2410_GSTATUS1 ) ;
2006-02-02 00:24:24 +03:00
# endif
2005-04-17 02:20:36 +04:00
cpu = s3c_lookup_cpu ( idcode ) ;
if ( cpu = = NULL ) {
printk ( KERN_ERR " Unknown CPU type 0x%08lx \n " , idcode ) ;
panic ( " Unknown S3C24XX CPU " ) ;
}
if ( cpu - > map_io = = NULL | | cpu - > init = = NULL ) {
printk ( KERN_ERR " CPU %s support not enabled \n " , cpu - > name ) ;
panic ( " Unsupported S3C24XX CPU " ) ;
}
printk ( " CPU %s (id 0x%08lx) \n " , cpu - > name , idcode ) ;
( cpu - > map_io ) ( mach_desc , size ) ;
}
/* s3c24xx_init_clocks
*
* Initialise the clock subsystem and associated information from the
* given master crystal value .
*
* xtal = 0 - > use default PLL crystal value ( normally 12 MHz )
* ! = 0 - > PLL crystal value in Hz
*/
void __init s3c24xx_init_clocks ( int xtal )
{
if ( xtal = = 0 )
xtal = 12 * 1000 * 1000 ;
if ( cpu = = NULL )
panic ( " s3c24xx_init_clocks: no cpu setup? \n " ) ;
if ( cpu - > init_clocks = = NULL )
panic ( " s3c24xx_init_clocks: cpu has no clock init \n " ) ;
else
( cpu - > init_clocks ) ( xtal ) ;
}
void __init s3c24xx_init_uarts ( struct s3c2410_uartcfg * cfg , int no )
{
if ( cpu = = NULL )
return ;
if ( cpu - > init_uarts = = NULL ) {
printk ( KERN_ERR " s3c24xx_init_uarts: cpu has no uart init \n " ) ;
} else
( cpu - > init_uarts ) ( cfg , no ) ;
}
static int __init s3c_arch_init ( void )
{
int ret ;
// do the correct init for cpu
if ( cpu = = NULL )
panic ( " s3c_arch_init: NULL cpu \n " ) ;
ret = ( cpu - > init ) ( ) ;
if ( ret ! = 0 )
return ret ;
if ( board ! = NULL ) {
struct platform_device * * ptr = board - > devices ;
int i ;
for ( i = 0 ; i < board - > devices_count ; i + + , ptr + + ) {
ret = platform_device_register ( * ptr ) ;
if ( ret ) {
printk ( KERN_ERR " s3c24xx: failed to add board device %s (%d) @%p \n " , ( * ptr ) - > name , ret , * ptr ) ;
}
}
/* mask any error, we may not need all these board
* devices */
ret = 0 ;
}
return ret ;
}
arch_initcall ( s3c_arch_init ) ;