ARM: ux500: core U9540 support
authorLinus Walleij <linus.walleij@linaro.org>
Mon, 23 Jan 2012 10:54:44 +0000 (11:54 +0100)
committerLinus Walleij <linus.walleij@linaro.org>
Tue, 1 May 2012 22:25:13 +0000 (00:25 +0200)
This adds support for the U9540 variant of the U8500 series. This
is an application processor without internal modem. This is the
most basic part with ASIC ID, CPU-related fixes, IRQ list, register
ranges, timer, UART, and L2 cache setup. This is based on a patch
by Michel Jaouen which was rewritten to fit with the latest 3.3
kernel.

ChangeLog v1->v2: deleted the irqs-db9540.h file since we expect to
  migrate to using Device Tree for getting the IRQs to devices.
ChangeLog v2->v3: introduced a fixed virtual offset for the ROM
  as suggested by Arnd Bergmann.

Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Sebastien Pasdeloup <sebastien.pasdeloup-nonst@stericsson.com>
Signed-off-by: Michel Jaouen <michel.jaouen@stericsson.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
13 files changed:
arch/arm/mach-ux500/board-mop500-uib.c
arch/arm/mach-ux500/cache-l2x0.c
arch/arm/mach-ux500/clock.c
arch/arm/mach-ux500/cpu-db8500.c
arch/arm/mach-ux500/cpu.c
arch/arm/mach-ux500/id.c
arch/arm/mach-ux500/include/mach/db8500-regs.h
arch/arm/mach-ux500/include/mach/hardware.h
arch/arm/mach-ux500/include/mach/id.h
arch/arm/mach-ux500/include/mach/irqs.h
arch/arm/mach-ux500/platsmp.c
arch/arm/mach-ux500/timer.c
drivers/cpufreq/db8500-cpufreq.c

index 5af36aa56c08c140f899c702537ca0867d6f135c..b29a788f498cbcd93e96f7c21329785bab4dd094 100644 (file)
@@ -102,7 +102,7 @@ static int __init mop500_uib_init(void)
        struct i2c_adapter *i2c0;
        int ret;
 
-       if (!cpu_is_u8500())
+       if (!cpu_is_u8500_family())
                return -ENODEV;
 
        if (uib) {
index 77a75ed0df6729ff85452ce216ab1ef9f354fd57..677bb7683c71067efec6029aebca36252b6b143a 100644 (file)
@@ -36,9 +36,11 @@ static int __init ux500_l2x0_unlock(void)
 
 static int __init ux500_l2x0_init(void)
 {
+       u32 aux_val = 0x3e000000;
+
        if (cpu_is_u5500())
                l2x0_base = __io_address(U5500_L2CC_BASE);
-       else if (cpu_is_u8500())
+       else if (cpu_is_u8500_family())
                l2x0_base = __io_address(U8500_L2CC_BASE);
        else
                ux500_unknown_soc();
@@ -46,11 +48,19 @@ static int __init ux500_l2x0_init(void)
        /* Unlock before init */
        ux500_l2x0_unlock();
 
+       /* DB9540's L2 has 128KB way size */
+       if (cpu_is_u9540())
+               /* 128KB way size */
+               aux_val |= (0x4 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT);
+       else
+               /* 64KB way size */
+               aux_val |= (0x3 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT);
+
        /* 64KB way size, 8 way associativity, force WA */
        if (of_have_populated_dt())
-               l2x0_of_init(0x3e060000, 0xc0000fff);
+               l2x0_of_init(aux_val, 0xc0000fff);
        else
-               l2x0_init(l2x0_base, 0x3e060000, 0xc0000fff);
+               l2x0_init(l2x0_base, aux_val, 0xc0000fff);
 
        /*
         * We can't disable l2 as we are in non secure mode, currently
index ec35f0aa5665a99d23f11c73ec552ab6e83f3aca..cc87f7788ff582463dad84743e2cf6112aac444f 100644 (file)
@@ -151,7 +151,7 @@ static unsigned long clk_mtu_get_rate(struct clk *clk)
 
        if (cpu_is_u5500())
                addr = __io_address(U5500_PRCMU_BASE);
-       else if (cpu_is_u8500())
+       else if (cpu_is_u8500_family())
                addr = __io_address(U8500_PRCMU_BASE);
        else
                ux500_unknown_soc();
index 9bd8163896cfa241a76839aa7be5830b3f052eaf..0bdcdd96fdc8f9c369ded0b87bacdcf2f70b5ca0 100644 (file)
@@ -34,8 +34,8 @@ 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 = {
+/*  U8500 and U9540 common io_desc */
+static struct map_desc u8500_common_io_desc[] __initdata = {
        /* SCU base also covers GIC CPU BASE and TWD with its 4K page */
        __IO_DEV_DESC(U8500_SCU_BASE, SZ_4K),
        __IO_DEV_DESC(U8500_GIC_DIST_BASE, SZ_4K),
@@ -66,7 +66,7 @@ void __init u8500_map_io(void)
 
        ux500_map_io();
 
-       iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc));
+       iotable_init(u8500_common_io_desc, ARRAY_SIZE(u8500_common_io_desc));
 
        _PRCMU_BASE = __io_address(U8500_PRCMU_BASE);
 }
index d11f3892a27dffe6a596a5c279ecdd355b44f280..857e48167526dc92862d23269a06155904539123 100644 (file)
@@ -43,7 +43,7 @@ void __init ux500_init_irq(void)
        if (cpu_is_u5500()) {
                dist_base = __io_address(U5500_GIC_DIST_BASE);
                cpu_base = __io_address(U5500_GIC_CPU_BASE);
-       } else if (cpu_is_u8500()) {
+       } else if (cpu_is_u8500_family()) {
                dist_base = __io_address(U8500_GIC_DIST_BASE);
                cpu_base = __io_address(U8500_GIC_CPU_BASE);
        } else
@@ -62,7 +62,7 @@ void __init ux500_init_irq(void)
         */
        if (cpu_is_u5500())
                db5500_prcmu_early_init();
-       if (cpu_is_u8500())
+       if (cpu_is_u8500_family())
                db8500_prcmu_early_init();
        clk_init();
 }
index 15a0f63b2e2bace8f8c82797f0ba1ae6483da4e1..d1579920139fbc104bbe8ccf52847e17a30c43c2 100644 (file)
@@ -23,7 +23,7 @@ static unsigned int ux500_read_asicid(phys_addr_t addr)
 {
        phys_addr_t base = addr & ~0xfff;
        struct map_desc desc = {
-               .virtual        = IO_ADDRESS(base),
+               .virtual        = UX500_VIRT_ROM,
                .pfn            = __phys_to_pfn(base),
                .length         = SZ_16K,
                .type           = MT_DEVICE,
@@ -35,7 +35,7 @@ static unsigned int ux500_read_asicid(phys_addr_t addr)
        local_flush_tlb_all();
        flush_cache_all();
 
-       return readl(__io_address(addr));
+       return readl(IOMEM(UX500_VIRT_ROM + (addr & 0xfff)));
 }
 
 static void ux500_print_soc_info(unsigned int asicid)
@@ -67,6 +67,7 @@ static unsigned int partnumber(unsigned int asicid)
  * DB8500v2    0x412fc091      0x9001DBF4              0x008500B0
  * DB8520v2.2  0x412fc091      0x9001DBF4              0x008500B2
  * DB5500v1    0x412fc091      0x9001FFF4              0x005500A0
+ * DB9540      0x413fc090      0xFFFFDBF4              0x009540xx
  */
 
 void __init ux500_map_io(void)
@@ -91,6 +92,10 @@ void __init ux500_map_io(void)
                /* DB5500v1 */
                addr = 0x9001FFF4;
                break;
+
+       case 0x413fc090: /* DB9540 */
+               addr = 0xFFFFDBF4;
+               break;
        }
 
        if (addr)
index 9ec20b96d8f2bd33f256ae74e127dd592e6e6095..1530d493879d534b647d67862fa4073ff2018e26 100644 (file)
 /* ASIC ID is at 0xbf4 offset within this region */
 #define U8500_ASIC_ID_BASE     0x9001D000
 
+#define U9540_BOOT_ROM_BASE    0xFFFE0000
+/* ASIC ID is at 0xbf4 offset within this region */
+#define U9540_ASIC_ID_BASE     0xFFFFD000
+
 #define U8500_PER6_BASE                0xa03c0000
 #define U8500_PER7_BASE                0xa03d0000
 #define U8500_PER5_BASE                0xa03e0000
 #define U8500_SCR_BASE         (U8500_PER4_BASE + 0x05000)
 #define U8500_DMC_BASE         (U8500_PER4_BASE + 0x06000)
 #define U8500_PRCMU_BASE       (U8500_PER4_BASE + 0x07000)
+#define U9540_DMC1_BASE                (U8500_PER4_BASE + 0x0A000)
 #define U8500_PRCMU_TCDM_BASE  (U8500_PER4_BASE + 0x68000)
+#define U9540_PRCMU_TCDM_BASE  (U8500_PER4_BASE + 0x6A000)
 #define U8500_PRCMU_TCPM_BASE   (U8500_PER4_BASE + 0x60000)
 #define U8500_PRCMU_TIMER_3_BASE (U8500_PER4_BASE + 0x07338)
 #define U8500_PRCMU_TIMER_4_BASE (U8500_PER4_BASE + 0x07450)
index f84698936d360d198aeba20313ddbce4b936ff67..836165778a2d2ef390f6cb01cf62867d931e04bf 100644 (file)
@@ -17,6 +17,8 @@
  */
 #define U8500_IO_VIRTUAL       0xf0000000
 #define U8500_IO_PHYSICAL      0xa0000000
+/* This is where we map in the ROM to check ASIC IDs */
+#define UX500_VIRT_ROM         0xf0000000
 
 /* This macro is used in assembly, so no cast */
 #define IO_ADDRESS(x)           \
@@ -24,6 +26,7 @@
 
 /* typesafe io address */
 #define __io_address(n)                IOMEM(IO_ADDRESS(n))
+
 /* Used by some plat-nomadik code */
 #define io_p2v(n)              __io_address(n)
 
index 833d6a6edc9b0ebd10755b4b62af9e865ab40225..c6e2db9e9e5143db632a422fee1ff46067651715 100644 (file)
@@ -41,6 +41,16 @@ static inline bool __attribute_const__ cpu_is_u8500(void)
        return dbx500_partnumber() == 0x8500;
 }
 
+static inline bool __attribute_const__ cpu_is_u9540(void)
+{
+       return dbx500_partnumber() == 0x9540;
+}
+
+static inline bool cpu_is_u8500_family(void)
+{
+       return cpu_is_u8500() || cpu_is_u9540();
+}
+
 static inline bool __attribute_const__ cpu_is_u5500(void)
 {
        return dbx500_partnumber() == 0x5500;
@@ -111,7 +121,12 @@ static inline bool cpu_is_u8500v21(void)
 
 static inline bool cpu_is_u8500v20_or_later(void)
 {
-       return cpu_is_u8500() && !cpu_is_u8500v10() && !cpu_is_u8500v11();
+       /*
+        * U9540 has so much in common with U8500 that is is considered a
+        * U8500 variant.
+        */
+       return cpu_is_u9540() ||
+               (cpu_is_u8500() && !cpu_is_u8500v10() && !cpu_is_u8500v11());
 }
 
 static inline bool ux500_is_svp(void)
index c23a6b5f0c4eefd58220620043316d999b3d651d..7da9ec58a531a517bb5dd5dc0348bb7cd3c54949 100644 (file)
@@ -24,7 +24,7 @@
  */
 #define IRQ_MTU0               (IRQ_SHPI_START + 4)
 
-#define DBX500_NR_INTERNAL_IRQS                160
+#define DBX500_NR_INTERNAL_IRQS                166
 
 /* After chip-specific IRQ numbers we have the GPIO ones */
 #define NOMADIK_NR_GPIO                        288
index eff5842f6232a8f7d0af9e29a87477508ce9f455..f499a0703928fb14db701f2b424442e4996e33bd 100644 (file)
@@ -50,7 +50,7 @@ static void __iomem *scu_base_addr(void)
 {
        if (cpu_is_u5500())
                return __io_address(U5500_SCU_BASE);
-       else if (cpu_is_u8500())
+       else if (cpu_is_u8500_family())
                return __io_address(U8500_SCU_BASE);
        else
                ux500_unknown_soc();
@@ -122,7 +122,7 @@ static void __init wakeup_secondary(void)
 
        if (cpu_is_u5500())
                backupram = __io_address(U5500_BACKUPRAM0_BASE);
-       else if (cpu_is_u8500())
+       else if (cpu_is_u8500_family())
                backupram = __io_address(U8500_BACKUPRAM0_BASE);
        else
                ux500_unknown_soc();
index d37df98b5c32588d65450867900e7d87a6f4aec9..3bfbfdf833c6b2ae6acb9d12da0952fb34f550cd 100644 (file)
@@ -51,7 +51,7 @@ static void __init ux500_timer_init(void)
        if (cpu_is_u5500()) {
                mtu_timer_base = __io_address(U5500_MTU0_BASE);
                prcmu_timer_base = __io_address(U5500_PRCMU_TIMER_3_BASE);
-       } else if (cpu_is_u8500()) {
+       } else if (cpu_is_u8500_family()) {
                mtu_timer_base = __io_address(U8500_MTU0_BASE);
                prcmu_timer_base = __io_address(U8500_PRCMU_TIMER_4_BASE);
        } else {
index 0bf1b8910eebe74a6e86a32b3338ddf0a6d1ef1a..74b830b635a65d48260e4b5e9ff4a9aa889dbf97 100644 (file)
@@ -161,7 +161,7 @@ static struct cpufreq_driver db8500_cpufreq_driver = {
 
 static int __init db8500_cpufreq_register(void)
 {
-       if (!cpu_is_u8500v20_or_later())
+       if (!cpu_is_u8500_family())
                return -ENODEV;
 
        pr_info("cpufreq for DB8500 started\n");