X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Farm%2Fmach-s3c2410%2Fcpu.c;h=ae1f5bb63f7a809081a31a437aa983b944c66fa1;hb=refs%2Fheads%2Fvserver;hp=42eec7912858757a7618003e3f5df801a13f37de;hpb=a2c21200f1c81b08cb55e417b68150bba439b646;p=linux-2.6.git diff --git a/arch/arm/mach-s3c2410/cpu.c b/arch/arm/mach-s3c2410/cpu.c index 42eec7912..ae1f5bb63 100644 --- a/arch/arm/mach-s3c2410/cpu.c +++ b/arch/arm/mach-s3c2410/cpu.c @@ -1,7 +1,8 @@ /* linux/arch/arm/mach-s3c2410/cpu.c * - * Copyright (c) 2004 Simtec Electronics - * Ben Dooks + * Copyright (c) 2004-2005 Simtec Electronics + * http://www.simtec.co.uk/products/SWLINUX/ + * Ben Dooks * * S3C24XX CPU Support * @@ -25,7 +26,8 @@ #include #include #include -#include +#include +#include #include #include @@ -36,55 +38,111 @@ #include #include +#include #include "cpu.h" +#include "devs.h" +#include "clock.h" +#include "s3c2400.h" #include "s3c2410.h" +#include "s3c2412.h" +#include "s3c244x.h" #include "s3c2440.h" +#include "s3c2442.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 */ +static const char name_s3c2400[] = "S3C2400"; static const char name_s3c2410[] = "S3C2410"; +static const char name_s3c2412[] = "S3C2412"; static const char name_s3c2440[] = "S3C2440"; +static const char name_s3c2442[] = "S3C2442"; 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 = s3c2410_init, - .name = name_s3c2410 + .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 = 0x3241002, - .idmask = 0xffffffff, - .map_io = s3c2410_map_io, - .init = s3c2410_init, - .name = name_s3c2410a + .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 = s3c2440_init, - .name = name_s3c2440 + .idcode = 0x32440000, + .idmask = 0xffffffff, + .map_io = s3c244x_map_io, + .init_clocks = s3c244x_init_clocks, + .init_uarts = s3c244x_init_uarts, + .init = s3c2440_init, + .name = name_s3c2440 }, { - .idcode = 0x32440001, - .idmask = 0xffffffff, - .map_io = s3c2440_map_io, - .init = s3c2440_init, - .name = name_s3c2440a - } + .idcode = 0x32440001, + .idmask = 0xffffffff, + .map_io = s3c244x_map_io, + .init_clocks = s3c244x_init_clocks, + .init_uarts = s3c244x_init_uarts, + .init = s3c2440_init, + .name = name_s3c2440a + }, + { + .idcode = 0x32440aaa, + .idmask = 0xffffffff, + .map_io = s3c244x_map_io, + .init_clocks = s3c244x_init_clocks, + .init_uarts = s3c244x_init_uarts, + .init = s3c2442_init, + .name = name_s3c2442 + }, + { + .idcode = 0x32412001, + .idmask = 0xffffffff, + .map_io = s3c2412_map_io, + .init_clocks = s3c2412_init_clocks, + .init_uarts = s3c2412_init_uarts, + .init = s3c2412_init, + .name = name_s3c2412, + }, + { /* a newer version of the s3c2412 */ + .idcode = 0x32412003, + .idmask = 0xffffffff, + .map_io = s3c2412_map_io, + .init_clocks = s3c2412_init_clocks, + .init_uarts = s3c2412_init_uarts, + .init = s3c2412_init, + .name = name_s3c2412, + }, + { + .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 + }, }; /* minimal IO mapping */ @@ -104,7 +162,7 @@ s3c_lookup_cpu(unsigned long idcode) int count; tab = cpu_ids; - for (count = 0; count < ARRAY_SIZE(cpu_ids); count++) { + for (count = 0; count < ARRAY_SIZE(cpu_ids); count++, tab++) { if ((idcode & tab->idmask) == tab->idcode) return tab; } @@ -112,16 +170,59 @@ s3c_lookup_cpu(unsigned long idcode) 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) { + struct clk **ptr = b->clocks; + + for (i = b->clocks_count; i > 0; i--, ptr++) + s3c24xx_register_clock(*ptr); + } +} + +/* cpu information */ + static struct cpu_table *cpu; +static unsigned long s3c24xx_read_idcode_v5(void) +{ +#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) + return __raw_readl(S3C2412_GSTATUS1); +#else + return 1UL; /* don't look like an 2400 */ +#endif +} + +static unsigned long s3c24xx_read_idcode_v4(void) +{ +#ifndef CONFIG_CPU_S3C2400 + return __raw_readl(S3C2410_GSTATUS1); +#else + return 0UL; +#endif +} + void __init s3c24xx_init_io(struct map_desc *mach_desc, int size) { - unsigned long idcode; + unsigned long idcode = 0x0; /* initialise the io descriptors we need for initialisation */ iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc)); - idcode = __raw_readl(S3C2410_GSTATUS1); + if (cpu_architecture() >= CPU_ARCH_ARMv5) { + idcode = s3c24xx_read_idcode_v5(); + } else { + idcode = s3c24xx_read_idcode_v4(); + } + cpu = s3c_lookup_cpu(idcode); if (cpu == NULL) { @@ -129,24 +230,128 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size) panic("Unknown S3C24XX CPU"); } + printk("CPU %s (id 0x%08lx)\n", cpu->name, idcode); + 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 12MHz) + * != 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); +} + +/* uart management */ + +static int nr_uarts __initdata = 0; + +static struct s3c2410_uartcfg uart_cfgs[3]; + +/* s3c24xx_init_uartdevs + * + * copy the specified platform data and configuration into our central + * set of devices, before the data is thrown away after the init process. + * + * This also fills in the array passed to the serial driver for the + * early initialisation of the console. +*/ + +void __init s3c24xx_init_uartdevs(char *name, + struct s3c24xx_uart_resources *res, + struct s3c2410_uartcfg *cfg, int no) +{ + struct platform_device *platdev; + struct s3c2410_uartcfg *cfgptr = uart_cfgs; + struct s3c24xx_uart_resources *resp; + int uart; + + memcpy(cfgptr, cfg, sizeof(struct s3c2410_uartcfg) * no); + + for (uart = 0; uart < no; uart++, cfg++, cfgptr++) { + platdev = s3c24xx_uart_src[cfgptr->hwport]; + + resp = res + cfgptr->hwport; + + s3c24xx_uart_devs[uart] = platdev; + + platdev->name = name; + platdev->resource = resp->resources; + platdev->num_resources = resp->nr_resources; + + platdev->dev.platform_data = cfgptr; + } + + nr_uarts = no; +} + +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"); - return (cpu->init)(); + ret = (cpu->init)(); + if (ret != 0) + return ret; + + ret = platform_add_devices(s3c24xx_uart_devs, nr_uarts); + 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);