diff options
author | Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> | 2011-04-23 22:12:57 +0800 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2011-07-28 15:07:28 +0000 |
commit | 8c3583b634d5705d8f604c0d9392bc273d19c256 (patch) | |
tree | fa2c010c4dbea580526cb91a25ae0e57abc0f099 /arch/arm/mach-at91/setup.c | |
parent | 1ff5b1b411bf8a8157ae949a1b3ed8666d96c1db (diff) | |
download | op-kernel-dev-8c3583b634d5705d8f604c0d9392bc273d19c256.zip op-kernel-dev-8c3583b634d5705d8f604c0d9392bc273d19c256.tar.gz |
at91: use structure to store the current soc
instead of reading the registers everytime
the current implementation respect the following constrain:
- allow 1 to n soc to be enabled
- allow to have a virtual cpu type and subtype
- always detect the cpu type and subtype and report it
- detect if the soc support is enabled
- prepare for sysfs export support
- drop soc specific code via compiler when the soc not enabled
(via cpu_is_xxx)
Today if we read the exid we will have the same value for 9g35 and 9m11
and we will need to check the cidr too
with the new implementation we just need to check the soc subtype
this will also allow to have specific virtual subtype for rm9200 which the
board will have to specify via at91rm9200_set_type(int) as we have no way to
detect it.
this implementation is inspired by the SH cpu detection support
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
Cc: Patrice Vilchez <patrice.vilchez@atmel.com>
Diffstat (limited to 'arch/arm/mach-at91/setup.c')
-rw-r--r-- | arch/arm/mach-at91/setup.c | 209 |
1 files changed, 192 insertions, 17 deletions
diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c index 8962d9a..9ea4183 100644 --- a/arch/arm/mach-at91/setup.c +++ b/arch/arm/mach-at91/setup.c @@ -12,11 +12,24 @@ #include <mach/hardware.h> #include <mach/cpu.h> +#include <mach/at91_dbgu.h> +#include <mach/at91_pmc.h> #include "soc.h" #include "generic.h" -struct at91_soc __initdata at91_boot_soc; +struct at91_init_soc __initdata at91_boot_soc; + +struct at91_socinfo at91_soc_initdata; +EXPORT_SYMBOL(at91_soc_initdata); + +void __init at91rm9200_set_type(int type) +{ + if (type == ARCH_REVISON_9200_PQFP) + at91_soc_initdata.subtype = AT91_SOC_RM9200_BGA; + else + at91_soc_initdata.subtype = AT91_SOC_RM9200_PQFP; +} void __init at91_init_irq_default(void) { @@ -39,33 +52,195 @@ static struct map_desc at91_io_desc __initdata = { .type = MT_DEVICE, }; -void __init at91_map_io(void) +#define AT91_DBGU0 0xfffff200 +#define AT91_DBGU1 0xffffee00 + +static void __init soc_detect(u32 dbgu_base) { - /* Map peripherals */ - iotable_init(&at91_io_desc, 1); + u32 cidr, socid; + + cidr = __raw_readl(AT91_IO_P2V(dbgu_base) + AT91_DBGU_CIDR); + socid = cidr & ~AT91_CIDR_VERSION; - if (cpu_is_at91cap9()) + switch (socid) { + case ARCH_ID_AT91CAP9: { +#ifdef CONFIG_AT91_PMC_UNIT + u32 pmc_ver = at91_sys_read(AT91_PMC_VER); + + if (pmc_ver == ARCH_REVISION_CAP9_B) + at91_soc_initdata.subtype = AT91_SOC_CAP9_REV_B; + else if (pmc_ver == ARCH_REVISION_CAP9_C) + at91_soc_initdata.subtype = AT91_SOC_CAP9_REV_C; +#endif + at91_soc_initdata.type = AT91_SOC_CAP9; at91_boot_soc = at91cap9_soc; - else if (cpu_is_at91rm9200()) + break; + } + + case ARCH_ID_AT91RM9200: + at91_soc_initdata.type = AT91_SOC_RM9200; at91_boot_soc = at91rm9200_soc; - else if (cpu_is_at91sam9260()) + break; + + case ARCH_ID_AT91SAM9260: + at91_soc_initdata.type = AT91_SOC_SAM9260; at91_boot_soc = at91sam9260_soc; - else if (cpu_is_at91sam9261()) + break; + + case ARCH_ID_AT91SAM9261: + at91_soc_initdata.type = AT91_SOC_SAM9261; at91_boot_soc = at91sam9261_soc; - else if (cpu_is_at91sam9263()) + break; + + case ARCH_ID_AT91SAM9263: + at91_soc_initdata.type = AT91_SOC_SAM9263; at91_boot_soc = at91sam9263_soc; - else if (cpu_is_at91sam9g10()) - at91_boot_soc = at91sam9261_soc; - else if (cpu_is_at91sam9g20()) + break; + + case ARCH_ID_AT91SAM9G20: + at91_soc_initdata.type = AT91_SOC_SAM9G20; at91_boot_soc = at91sam9260_soc; - else if (cpu_is_at91sam9g45()) + break; + + case ARCH_ID_AT91SAM9G45: + at91_soc_initdata.type = AT91_SOC_SAM9G45; + if (cidr == ARCH_ID_AT91SAM9G45ES) + at91_soc_initdata.subtype = AT91_SOC_SAM9G45ES; at91_boot_soc = at91sam9g45_soc; - else if (cpu_is_at91sam9rl()) + break; + + case ARCH_ID_AT91SAM9RL64: + at91_soc_initdata.type = AT91_SOC_SAM9RL; at91_boot_soc = at91sam9rl_soc; - else if (cpu_is_at91sam9x5()) + break; + + case ARCH_ID_AT91SAM9X5: + at91_soc_initdata.type = AT91_SOC_SAM9X5; at91_boot_soc = at91sam9x5_soc; - else - panic("Impossible to detect the SOC type"); + break; + } + + /* at91sam9g10 */ + if ((cidr & ~AT91_CIDR_EXT) == ARCH_ID_AT91SAM9G10) { + at91_soc_initdata.type = AT91_SOC_SAM9G10; + at91_boot_soc = at91sam9261_soc; + } + /* at91sam9xe */ + else if ((cidr & AT91_CIDR_ARCH) == ARCH_FAMILY_AT91SAM9XE) { + at91_soc_initdata.type = AT91_SOC_SAM9260; + at91_soc_initdata.subtype = AT91_SOC_SAM9XE; + at91_boot_soc = at91sam9260_soc; + } + + if (!at91_soc_is_detected()) + return; + + at91_soc_initdata.cidr = cidr; + + /* sub version of soc */ + at91_soc_initdata.exid = __raw_readl(AT91_IO_P2V(dbgu_base) + AT91_DBGU_EXID); + + if (at91_soc_initdata.type == AT91_SOC_SAM9G45) { + switch (at91_soc_initdata.exid) { + case ARCH_EXID_AT91SAM9M10: + at91_soc_initdata.subtype = AT91_SOC_SAM9M10; + break; + case ARCH_EXID_AT91SAM9G46: + at91_soc_initdata.subtype = AT91_SOC_SAM9G46; + break; + case ARCH_EXID_AT91SAM9M11: + at91_soc_initdata.subtype = AT91_SOC_SAM9M11; + break; + } + } + + if (at91_soc_initdata.type == AT91_SOC_SAM9X5) { + switch (at91_soc_initdata.exid) { + case ARCH_EXID_AT91SAM9G15: + at91_soc_initdata.subtype = AT91_SOC_SAM9G15; + break; + case ARCH_EXID_AT91SAM9G35: + at91_soc_initdata.subtype = AT91_SOC_SAM9G35; + break; + case ARCH_EXID_AT91SAM9X35: + at91_soc_initdata.subtype = AT91_SOC_SAM9X35; + break; + case ARCH_EXID_AT91SAM9G25: + at91_soc_initdata.subtype = AT91_SOC_SAM9G25; + break; + case ARCH_EXID_AT91SAM9X25: + at91_soc_initdata.subtype = AT91_SOC_SAM9X25; + break; + } + } +} + +static const char *soc_name[] = { + [AT91_SOC_RM9200] = "at91rm9200", + [AT91_SOC_CAP9] = "at91cap9", + [AT91_SOC_SAM9260] = "at91sam9260", + [AT91_SOC_SAM9261] = "at91sam9261", + [AT91_SOC_SAM9263] = "at91sam9263", + [AT91_SOC_SAM9G10] = "at91sam9g10", + [AT91_SOC_SAM9G20] = "at91sam9g20", + [AT91_SOC_SAM9G45] = "at91sam9g45", + [AT91_SOC_SAM9RL] = "at91sam9rl", + [AT91_SOC_SAM9X5] = "at91sam9x5", + [AT91_SOC_NONE] = "Unknown" +}; + +const char *at91_get_soc_type(struct at91_socinfo *c) +{ + return soc_name[c->type]; +} +EXPORT_SYMBOL(at91_get_soc_type); + +static const char *soc_subtype_name[] = { + [AT91_SOC_RM9200_BGA] = "at91rm9200 BGA", + [AT91_SOC_RM9200_PQFP] = "at91rm9200 PQFP", + [AT91_SOC_CAP9_REV_B] = "at91cap9 revB", + [AT91_SOC_CAP9_REV_C] = "at91cap9 revC", + [AT91_SOC_SAM9XE] = "at91sam9xe", + [AT91_SOC_SAM9G45ES] = "at91sam9g45es", + [AT91_SOC_SAM9M10] = "at91sam9m10", + [AT91_SOC_SAM9G46] = "at91sam9g46", + [AT91_SOC_SAM9M11] = "at91sam9m11", + [AT91_SOC_SAM9G15] = "at91sam9g15", + [AT91_SOC_SAM9G35] = "at91sam9g35", + [AT91_SOC_SAM9X35] = "at91sam9x35", + [AT91_SOC_SAM9G25] = "at91sam9g25", + [AT91_SOC_SAM9X25] = "at91sam9x25", + [AT91_SOC_SUBTYPE_NONE] = "Unknown" +}; + +const char *at91_get_soc_subtype(struct at91_socinfo *c) +{ + return soc_subtype_name[c->subtype]; +} +EXPORT_SYMBOL(at91_get_soc_subtype); + +void __init at91_map_io(void) +{ + /* Map peripherals */ + iotable_init(&at91_io_desc, 1); + + at91_soc_initdata.type = AT91_SOC_NONE; + at91_soc_initdata.subtype = AT91_SOC_SUBTYPE_NONE; + + soc_detect(AT91_DBGU0); + if (!at91_soc_is_detected()) + soc_detect(AT91_DBGU1); + + if (!at91_soc_is_detected()) + panic("AT91: Impossible to detect the SOC type"); + + pr_info("AT91: Detected soc type: %s\n", + at91_get_soc_type(&at91_soc_initdata)); + pr_info("AT91: Detected soc subtype: %s\n", + at91_get_soc_subtype(&at91_soc_initdata)); + + if (!at91_soc_is_enabled()) + panic("AT91: Soc not enabled"); if (at91_boot_soc.map_io) at91_boot_soc.map_io(); |