mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 12:42:02 +00:00
ux500: dynamic SOC detection
Dynamically detect the DBx500 SOC an revision based on the ASIC ID. Signed-off-by: Rabin Vincent <rabin.vincent@stericsson.com> Signed-off-by: Linus Walleij <linus.walleij@stericsson.com>
This commit is contained in:
parent
5dc55e0a39
commit
abf12d719a
@ -2,7 +2,8 @@
|
||||
# Makefile for the linux kernel, U8500 machine.
|
||||
#
|
||||
|
||||
obj-y := clock.o cpu.o devices.o devices-common.o
|
||||
obj-y := clock.o cpu.o devices.o devices-common.o \
|
||||
id.o
|
||||
obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o dma-db5500.o
|
||||
obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o prcmu.o
|
||||
obj-$(CONFIG_MACH_U8500) += board-mop500.o board-mop500-sdi.o \
|
||||
|
@ -21,9 +21,12 @@
|
||||
|
||||
#include "devices-db5500.h"
|
||||
|
||||
static struct map_desc u5500_io_desc[] __initdata = {
|
||||
static struct map_desc u5500_uart_io_desc[] __initdata = {
|
||||
__IO_DEV_DESC(U5500_UART0_BASE, SZ_4K),
|
||||
__IO_DEV_DESC(U5500_UART2_BASE, SZ_4K),
|
||||
};
|
||||
|
||||
static struct map_desc u5500_io_desc[] __initdata = {
|
||||
__IO_DEV_DESC(U5500_GIC_CPU_BASE, SZ_4K),
|
||||
__IO_DEV_DESC(U5500_GIC_DIST_BASE, SZ_4K),
|
||||
__IO_DEV_DESC(U5500_L2CC_BASE, SZ_4K),
|
||||
@ -153,6 +156,13 @@ static void __init db5500_add_gpios(void)
|
||||
|
||||
void __init u5500_map_io(void)
|
||||
{
|
||||
/*
|
||||
* Map the UARTs early so that the DEBUG_LL stuff continues to work.
|
||||
*/
|
||||
iotable_init(u5500_uart_io_desc, ARRAY_SIZE(u5500_uart_io_desc));
|
||||
|
||||
ux500_map_io();
|
||||
|
||||
iotable_init(u5500_io_desc, ARRAY_SIZE(u5500_io_desc));
|
||||
}
|
||||
|
||||
|
@ -29,9 +29,12 @@ static struct platform_device *platform_devs[] __initdata = {
|
||||
};
|
||||
|
||||
/* minimum static i/o mapping required to boot U8500 platforms */
|
||||
static struct map_desc u8500_io_desc[] __initdata = {
|
||||
static struct map_desc u8500_uart_io_desc[] __initdata = {
|
||||
__IO_DEV_DESC(U8500_UART0_BASE, SZ_4K),
|
||||
__IO_DEV_DESC(U8500_UART2_BASE, SZ_4K),
|
||||
};
|
||||
|
||||
static struct map_desc u8500_io_desc[] __initdata = {
|
||||
__IO_DEV_DESC(U8500_GIC_CPU_BASE, SZ_4K),
|
||||
__IO_DEV_DESC(U8500_GIC_DIST_BASE, SZ_4K),
|
||||
__IO_DEV_DESC(U8500_L2CC_BASE, SZ_4K),
|
||||
@ -51,7 +54,6 @@ static struct map_desc u8500_io_desc[] __initdata = {
|
||||
__IO_DEV_DESC(U8500_GPIO1_BASE, SZ_4K),
|
||||
__IO_DEV_DESC(U8500_GPIO2_BASE, SZ_4K),
|
||||
__IO_DEV_DESC(U8500_GPIO3_BASE, SZ_4K),
|
||||
__MEM_DEV_DESC(U8500_BOOT_ROM_BASE, SZ_1M),
|
||||
};
|
||||
|
||||
static struct map_desc u8500_ed_io_desc[] __initdata = {
|
||||
@ -68,71 +70,15 @@ static struct map_desc u8500_v2_io_desc[] __initdata = {
|
||||
__IO_DEV_DESC(U8500_PRCMU_TCDM_BASE, SZ_4K),
|
||||
};
|
||||
|
||||
/*
|
||||
* Functions to differentiate between later ASICs
|
||||
* We look into the end of the ROM to locate the hardcoded ASIC ID.
|
||||
* This is only needed to differentiate between minor revisions and
|
||||
* process variants of an ASIC, the major revisions are encoded in
|
||||
* the cpuid.
|
||||
*/
|
||||
#define U8500_ASIC_ID_LOC_ED_V1 (U8500_BOOT_ROM_BASE + 0x1FFF4)
|
||||
#define U8500_ASIC_ID_LOC_V2 (U8500_BOOT_ROM_BASE + 0x1DBF4)
|
||||
#define U8500_ASIC_REV_ED 0x01
|
||||
#define U8500_ASIC_REV_V10 0xA0
|
||||
#define U8500_ASIC_REV_V11 0xA1
|
||||
#define U8500_ASIC_REV_V20 0xB0
|
||||
|
||||
/**
|
||||
* struct db8500_asic_id - fields of the ASIC ID
|
||||
* @process: the manufacturing process, 0x40 is 40 nm
|
||||
* 0x00 is "standard"
|
||||
* @partnumber: hithereto 0x8500 for DB8500
|
||||
* @revision: version code in the series
|
||||
* This field definion is not formally defined but makes
|
||||
* sense.
|
||||
*/
|
||||
struct db8500_asic_id {
|
||||
u8 process;
|
||||
u16 partnumber;
|
||||
u8 revision;
|
||||
};
|
||||
|
||||
/* This isn't going to change at runtime */
|
||||
static struct db8500_asic_id db8500_id;
|
||||
|
||||
static void __init get_db8500_asic_id(void)
|
||||
{
|
||||
u32 asicid;
|
||||
|
||||
if (cpu_is_u8500v1() || cpu_is_u8500ed())
|
||||
asicid = readl(__io_address(U8500_ASIC_ID_LOC_ED_V1));
|
||||
else if (cpu_is_u8500v2())
|
||||
asicid = readl(__io_address(U8500_ASIC_ID_LOC_V2));
|
||||
else
|
||||
BUG();
|
||||
|
||||
db8500_id.process = (asicid >> 24);
|
||||
db8500_id.partnumber = (asicid >> 16) & 0xFFFFU;
|
||||
db8500_id.revision = asicid & 0xFFU;
|
||||
}
|
||||
|
||||
bool cpu_is_u8500v10(void)
|
||||
{
|
||||
return (db8500_id.revision == U8500_ASIC_REV_V10);
|
||||
}
|
||||
|
||||
bool cpu_is_u8500v11(void)
|
||||
{
|
||||
return (db8500_id.revision == U8500_ASIC_REV_V11);
|
||||
}
|
||||
|
||||
bool cpu_is_u8500v20(void)
|
||||
{
|
||||
return (db8500_id.revision == U8500_ASIC_REV_V20);
|
||||
}
|
||||
|
||||
void __init u8500_map_io(void)
|
||||
{
|
||||
/*
|
||||
* Map the UARTs early so that the DEBUG_LL stuff continues to work.
|
||||
*/
|
||||
iotable_init(u8500_uart_io_desc, ARRAY_SIZE(u8500_uart_io_desc));
|
||||
|
||||
ux500_map_io();
|
||||
|
||||
iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc));
|
||||
|
||||
if (cpu_is_u8500ed())
|
||||
@ -141,9 +87,6 @@ void __init u8500_map_io(void)
|
||||
iotable_init(u8500_v1_io_desc, ARRAY_SIZE(u8500_v1_io_desc));
|
||||
else if (cpu_is_u8500v2())
|
||||
iotable_init(u8500_v2_io_desc, ARRAY_SIZE(u8500_v2_io_desc));
|
||||
|
||||
/* Read out the ASIC ID as early as we can */
|
||||
get_db8500_asic_id();
|
||||
}
|
||||
|
||||
static resource_size_t __initdata db8500_gpio_base[] = {
|
||||
@ -173,20 +116,6 @@ static void __init db8500_add_gpios(void)
|
||||
*/
|
||||
void __init u8500_init_devices(void)
|
||||
{
|
||||
/* Display some ASIC boilerplate */
|
||||
pr_info("DB8500: process: %02x, revision ID: 0x%02x\n",
|
||||
db8500_id.process, db8500_id.revision);
|
||||
if (cpu_is_u8500ed())
|
||||
pr_info("DB8500: Early Drop (ED)\n");
|
||||
else if (cpu_is_u8500v10())
|
||||
pr_info("DB8500: version 1.0\n");
|
||||
else if (cpu_is_u8500v11())
|
||||
pr_info("DB8500: version 1.1\n");
|
||||
else if (cpu_is_u8500v20())
|
||||
pr_info("DB8500: version 2.0\n");
|
||||
else
|
||||
pr_warning("ASIC: UNKNOWN SILICON VERSION!\n");
|
||||
|
||||
if (cpu_is_u8500ed())
|
||||
dma40_u8500ed_fixup();
|
||||
|
||||
|
@ -27,10 +27,6 @@
|
||||
static void __iomem *l2x0_base;
|
||||
#endif
|
||||
|
||||
void __init ux500_map_io(void)
|
||||
{
|
||||
}
|
||||
|
||||
void __init ux500_init_irq(void)
|
||||
{
|
||||
void __iomem *dist_base;
|
||||
|
107
arch/arm/mach-ux500/id.c
Normal file
107
arch/arm/mach-ux500/id.c
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) ST-Ericsson SA 2010
|
||||
*
|
||||
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <asm/cputype.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/mach/map.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/setup.h>
|
||||
|
||||
struct dbx500_asic_id dbx500_id;
|
||||
|
||||
static unsigned int ux500_read_asicid(phys_addr_t addr)
|
||||
{
|
||||
phys_addr_t base = addr & ~0xfff;
|
||||
struct map_desc desc = {
|
||||
.virtual = IO_ADDRESS(base),
|
||||
.pfn = __phys_to_pfn(base),
|
||||
.length = SZ_16K,
|
||||
.type = MT_DEVICE,
|
||||
};
|
||||
|
||||
iotable_init(&desc, 1);
|
||||
|
||||
/* As in devicemaps_init() */
|
||||
local_flush_tlb_all();
|
||||
flush_cache_all();
|
||||
|
||||
return readl(__io_address(addr));
|
||||
}
|
||||
|
||||
static void ux500_print_soc_info(unsigned int asicid)
|
||||
{
|
||||
unsigned int rev = dbx500_revision();
|
||||
|
||||
pr_info("DB%4x ", dbx500_partnumber());
|
||||
|
||||
if (rev == 0x01)
|
||||
pr_cont("Early Drop");
|
||||
else if (rev >= 0xA0)
|
||||
pr_cont("v%d.%d" , (rev >> 4) - 0xA + 1, rev & 0xf);
|
||||
else
|
||||
pr_cont("Unknown");
|
||||
|
||||
pr_cont(" [%#010x]\n", asicid);
|
||||
}
|
||||
|
||||
static unsigned int partnumber(unsigned int asicid)
|
||||
{
|
||||
return (asicid >> 8) & 0xffff;
|
||||
}
|
||||
|
||||
/*
|
||||
* SOC MIDR ASICID ADDRESS ASICID VALUE
|
||||
* DB8500ed 0x410fc090 0x9001FFF4 0x00850001
|
||||
* DB8500v1 0x411fc091 0x9001FFF4 0x008500A0
|
||||
* DB8500v1.1 0x411fc091 0x9001FFF4 0x008500A1
|
||||
* DB8500v2 0x412fc091 0x9001DBF4 0x008500B0
|
||||
* DB5500v1 0x412fc091 0x9001FFF4 0x005500A0
|
||||
*/
|
||||
|
||||
void __init ux500_map_io(void)
|
||||
{
|
||||
unsigned int cpuid = read_cpuid_id();
|
||||
unsigned int asicid = 0;
|
||||
phys_addr_t addr = 0;
|
||||
|
||||
switch (cpuid) {
|
||||
case 0x410fc090: /* DB8500ed */
|
||||
case 0x411fc091: /* DB8500v1 */
|
||||
addr = 0x9001FFF4;
|
||||
break;
|
||||
|
||||
case 0x412fc091: /* DB8500v2 / DB5500v1 */
|
||||
asicid = ux500_read_asicid(0x9001DBF4);
|
||||
if (partnumber(asicid) == 0x8500)
|
||||
/* DB8500v2 */
|
||||
break;
|
||||
|
||||
/* DB5500v1 */
|
||||
addr = 0x9001FFF4;
|
||||
break;
|
||||
}
|
||||
|
||||
if (addr)
|
||||
asicid = ux500_read_asicid(addr);
|
||||
|
||||
if (!asicid) {
|
||||
pr_err("Unable to identify SoC\n");
|
||||
ux500_unknown_soc();
|
||||
}
|
||||
|
||||
dbx500_id.process = asicid >> 24;
|
||||
dbx500_id.partnumber = partnumber(asicid);
|
||||
dbx500_id.revision = asicid & 0xff;
|
||||
|
||||
ux500_print_soc_info(asicid);
|
||||
}
|
@ -34,57 +34,9 @@
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <asm/cputype.h>
|
||||
|
||||
static inline bool cpu_is_u8500(void)
|
||||
{
|
||||
#ifdef CONFIG_UX500_SOC_DB8500
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define CPUID_DB8500ED 0x410fc090
|
||||
#define CPUID_DB8500V1 0x411fc091
|
||||
#define CPUID_DB8500V2 0x412fc091
|
||||
|
||||
static inline bool cpu_is_u8500ed(void)
|
||||
{
|
||||
return cpu_is_u8500() && (read_cpuid_id() == CPUID_DB8500ED);
|
||||
}
|
||||
|
||||
static inline bool cpu_is_u8500v1(void)
|
||||
{
|
||||
return cpu_is_u8500() && (read_cpuid_id() == CPUID_DB8500V1);
|
||||
}
|
||||
|
||||
static inline bool cpu_is_u8500v2(void)
|
||||
{
|
||||
return cpu_is_u8500() && (read_cpuid_id() == CPUID_DB8500V2);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UX500_SOC_DB8500
|
||||
bool cpu_is_u8500v10(void);
|
||||
bool cpu_is_u8500v11(void);
|
||||
bool cpu_is_u8500v20(void);
|
||||
#else
|
||||
static inline bool cpu_is_u8500v10(void) { return false; }
|
||||
static inline bool cpu_is_u8500v11(void) { return false; }
|
||||
static inline bool cpu_is_u8500v20(void) { return false; }
|
||||
#endif
|
||||
|
||||
static inline bool cpu_is_u5500(void)
|
||||
{
|
||||
#ifdef CONFIG_UX500_SOC_DB5500
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
#include <mach/id.h>
|
||||
|
||||
#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x)
|
||||
#define ux500_unknown_soc() BUG()
|
||||
|
||||
#endif
|
||||
|
||||
|
80
arch/arm/mach-ux500/include/mach/id.h
Normal file
80
arch/arm/mach-ux500/include/mach/id.h
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) ST-Ericsson SA 2010
|
||||
*
|
||||
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
*/
|
||||
|
||||
#ifndef __MACH_UX500_ID
|
||||
#define __MACH_UX500_ID
|
||||
|
||||
/**
|
||||
* struct dbx500_asic_id - fields of the ASIC ID
|
||||
* @process: the manufacturing process, 0x40 is 40 nm 0x00 is "standard"
|
||||
* @partnumber: hithereto 0x8500 for DB8500
|
||||
* @revision: version code in the series
|
||||
*/
|
||||
struct dbx500_asic_id {
|
||||
u16 partnumber;
|
||||
u8 revision;
|
||||
u8 process;
|
||||
};
|
||||
|
||||
extern struct dbx500_asic_id dbx500_id;
|
||||
|
||||
static inline unsigned int __attribute_const__ dbx500_partnumber(void)
|
||||
{
|
||||
return dbx500_id.partnumber;
|
||||
}
|
||||
|
||||
static inline unsigned int __attribute_const__ dbx500_revision(void)
|
||||
{
|
||||
return dbx500_id.revision;
|
||||
}
|
||||
|
||||
/*
|
||||
* SOCs
|
||||
*/
|
||||
|
||||
static inline bool __attribute_const__ cpu_is_u8500(void)
|
||||
{
|
||||
return dbx500_partnumber() == 0x8500;
|
||||
}
|
||||
|
||||
static inline bool __attribute_const__ cpu_is_u5500(void)
|
||||
{
|
||||
return dbx500_partnumber() == 0x5500;
|
||||
}
|
||||
|
||||
/*
|
||||
* 8500 revisions
|
||||
*/
|
||||
|
||||
static inline bool __attribute_const__ cpu_is_u8500ed(void)
|
||||
{
|
||||
return cpu_is_u8500() && dbx500_revision() == 0x00;
|
||||
}
|
||||
|
||||
static inline bool __attribute_const__ cpu_is_u8500v1(void)
|
||||
{
|
||||
return cpu_is_u8500() && (dbx500_revision() & 0xf0) == 0xA0;
|
||||
}
|
||||
|
||||
static inline bool __attribute_const__ cpu_is_u8500v10(void)
|
||||
{
|
||||
return cpu_is_u8500() && dbx500_revision() == 0xA0;
|
||||
}
|
||||
|
||||
static inline bool __attribute_const__ cpu_is_u8500v11(void)
|
||||
{
|
||||
return cpu_is_u8500() && dbx500_revision() == 0xA1;
|
||||
}
|
||||
|
||||
static inline bool __attribute_const__ cpu_is_u8500v2(void)
|
||||
{
|
||||
return cpu_is_u8500() && ((dbx500_revision() & 0xf0) == 0xB0);
|
||||
}
|
||||
|
||||
#define ux500_unknown_soc() BUG()
|
||||
|
||||
#endif
|
@ -14,6 +14,7 @@
|
||||
#include <asm/mach/time.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
void __init ux500_map_io(void);
|
||||
extern void __init u5500_map_io(void);
|
||||
extern void __init u8500_map_io(void);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user