mirror of https://gitee.com/openkylin/linux.git
ARM: 5831/1: ARM: U8500 core machine support
Adds core support for the ST-Ericsson U8500 platform. It supports memory mappings, binds to the existing modules like GIC, SCU, TWD and local timers and sets up the infrastructure for the secondary core. Reviewed-by: Alessandro Rubini <rubini@unipv.it> Reviewed-by: Linus Walleij <linus.walleij@stericsson.com> Signed-off-by: srinidhi kasagar <srinidhi.kasagar@stericsson.com> Acked-by: Andrea Gallo <andrea.gallo@stericsson.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
parent
c6b503caef
commit
aa44ef4d43
|
@ -0,0 +1,15 @@
|
|||
menu "ST-Ericsson platform type"
|
||||
depends on ARCH_U8500
|
||||
|
||||
comment "ST-Ericsson Multicore Mobile Platforms"
|
||||
|
||||
config MACH_U8500_MOP
|
||||
bool "U8500 Early Development platform"
|
||||
default y
|
||||
select ARM_GIC
|
||||
select HAS_MTU
|
||||
help
|
||||
Include support for mop500 development platform
|
||||
based on U8500 architecture. The platform is based
|
||||
on early drop silicon version of 8500.
|
||||
endmenu
|
|
@ -0,0 +1,8 @@
|
|||
#
|
||||
# Makefile for the linux kernel, U8500 machine.
|
||||
#
|
||||
|
||||
obj-y := clock.o
|
||||
obj-$(CONFIG_ARCH_U8500) += cpu-u8500.o
|
||||
obj-$(CONFIG_MACH_U8500_MOP) += board-mop500.o
|
||||
obj-$(CONFIG_SMP) += platsmp.o headsmp.o localtimer.o
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Copyright (C) 2008-2009 ST-Ericsson
|
||||
*
|
||||
* Author: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/amba/bus.h>
|
||||
#include <linux/amba/pl022.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <asm/localtimer.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/arch.h>
|
||||
|
||||
#include <plat/mtu.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/setup.h>
|
||||
|
||||
#define __MEM_4K_RESOURCE(x) \
|
||||
.res = {.start = (x), .end = (x) + SZ_4K - 1, .flags = IORESOURCE_MEM}
|
||||
|
||||
/* These are active devices on this board */
|
||||
static struct amba_device uart0_device = {
|
||||
.dev = { .init_name = "uart0" },
|
||||
__MEM_4K_RESOURCE(U8500_UART0_BASE),
|
||||
.irq = {IRQ_UART0, NO_IRQ},
|
||||
};
|
||||
|
||||
static struct amba_device uart1_device = {
|
||||
.dev = { .init_name = "uart1" },
|
||||
__MEM_4K_RESOURCE(U8500_UART1_BASE),
|
||||
.irq = {IRQ_UART1, NO_IRQ},
|
||||
};
|
||||
|
||||
static struct amba_device uart2_device = {
|
||||
.dev = { .init_name = "uart2" },
|
||||
__MEM_4K_RESOURCE(U8500_UART2_BASE),
|
||||
.irq = {IRQ_UART2, NO_IRQ},
|
||||
};
|
||||
|
||||
static void ab4500_spi_cs_control(u32 command)
|
||||
{
|
||||
/* set the FRM signal, which is CS - TODO */
|
||||
}
|
||||
|
||||
struct pl022_config_chip ab4500_chip_info = {
|
||||
.lbm = LOOPBACK_DISABLED,
|
||||
.com_mode = INTERRUPT_TRANSFER,
|
||||
.iface = SSP_INTERFACE_MOTOROLA_SPI,
|
||||
/* we can act as master only */
|
||||
.hierarchy = SSP_MASTER,
|
||||
.slave_tx_disable = 0,
|
||||
.endian_rx = SSP_RX_MSB,
|
||||
.endian_tx = SSP_TX_MSB,
|
||||
.data_size = SSP_DATA_BITS_24,
|
||||
.rx_lev_trig = SSP_RX_1_OR_MORE_ELEM,
|
||||
.tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC,
|
||||
.clk_phase = SSP_CLK_SECOND_EDGE,
|
||||
.clk_pol = SSP_CLK_POL_IDLE_HIGH,
|
||||
.cs_control = ab4500_spi_cs_control,
|
||||
};
|
||||
|
||||
static struct spi_board_info u8500_spi_devices[] = {
|
||||
{
|
||||
.modalias = "ab4500",
|
||||
.controller_data = &ab4500_chip_info,
|
||||
.max_speed_hz = 12000000,
|
||||
.bus_num = 0,
|
||||
.chip_select = 0,
|
||||
.mode = SPI_MODE_0,
|
||||
.irq = IRQ_AB4500,
|
||||
},
|
||||
};
|
||||
|
||||
static struct pl022_ssp_controller ssp0_platform_data = {
|
||||
.bus_id = 0,
|
||||
/* pl022 not yet supports dma */
|
||||
.enable_dma = 0,
|
||||
/* on this platform, gpio 31,142,144,214 &
|
||||
* 224 are connected as chip selects
|
||||
*/
|
||||
.num_chipselect = 5,
|
||||
};
|
||||
|
||||
static struct amba_device pl022_device = {
|
||||
.dev = {
|
||||
.coherent_dma_mask = ~0,
|
||||
.init_name = "pl022",
|
||||
.platform_data = &ssp0_platform_data,
|
||||
},
|
||||
.res = {
|
||||
.start = U8500_SSP0_BASE,
|
||||
.end = U8500_SSP0_BASE + SZ_4K - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
.irq = {IRQ_SSP0, NO_IRQ },
|
||||
/* ST-Ericsson modified id */
|
||||
.periphid = SSP_PER_ID,
|
||||
};
|
||||
|
||||
static struct amba_device *amba_devs[] __initdata = {
|
||||
&uart0_device,
|
||||
&uart1_device,
|
||||
&uart2_device,
|
||||
&pl022_device,
|
||||
};
|
||||
|
||||
static void __init u8500_timer_init(void)
|
||||
{
|
||||
#ifdef CONFIG_LOCAL_TIMERS
|
||||
/* Setup the local timer base */
|
||||
twd_base = __io_address(U8500_TWD_BASE);
|
||||
#endif
|
||||
/* Setup the MTU base */
|
||||
mtu_base = __io_address(U8500_MTU0_BASE);
|
||||
|
||||
nmdk_timer_init();
|
||||
}
|
||||
|
||||
static struct sys_timer u8500_timer = {
|
||||
.init = u8500_timer_init,
|
||||
};
|
||||
|
||||
static void __init u8500_init_machine(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Register the active AMBA devices on this board */
|
||||
for (i = 0; i < ARRAY_SIZE(amba_devs); i++)
|
||||
amba_device_register(amba_devs[i], &iomem_resource);
|
||||
|
||||
spi_register_board_info(u8500_spi_devices,
|
||||
ARRAY_SIZE(u8500_spi_devices));
|
||||
|
||||
u8500_init_devices();
|
||||
}
|
||||
|
||||
MACHINE_START(U8500, "ST-Ericsson MOP500 platform")
|
||||
/* Maintainer: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> */
|
||||
.phys_io = U8500_UART2_BASE,
|
||||
.io_pg_offst = (IO_ADDRESS(U8500_UART2_BASE) >> 18) & 0xfffc,
|
||||
.boot_params = 0x100,
|
||||
.map_io = u8500_map_io,
|
||||
.init_irq = u8500_init_irq,
|
||||
/* we re-use nomadik timer here */
|
||||
.timer = &u8500_timer,
|
||||
.init_machine = u8500_init_machine,
|
||||
MACHINE_END
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (C) 2008-2009 ST-Ericsson
|
||||
*
|
||||
* Author: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
#include <linux/types.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/amba/bus.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <asm/hardware/gic.h>
|
||||
#include <asm/mach/map.h>
|
||||
#include <mach/hardware.h>
|
||||
|
||||
/* add any platform devices here - TODO */
|
||||
static struct platform_device *platform_devs[] __initdata = {
|
||||
/* yet to be added, add i2c0, gpio.. */
|
||||
};
|
||||
|
||||
#define __IO_DEV_DESC(x, sz) { \
|
||||
.virtual = IO_ADDRESS(x), \
|
||||
.pfn = __phys_to_pfn(x), \
|
||||
.length = sz, \
|
||||
.type = MT_DEVICE, \
|
||||
}
|
||||
|
||||
/* minimum static i/o mapping required to boot U8500 platforms */
|
||||
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_MTU0_BASE, SZ_4K),
|
||||
__IO_DEV_DESC(U8500_TWD_BASE, SZ_4K),
|
||||
__IO_DEV_DESC(U8500_SCU_BASE, SZ_4K),
|
||||
__IO_DEV_DESC(U8500_BACKUPRAM0_BASE, SZ_8K),
|
||||
};
|
||||
|
||||
void __init u8500_map_io(void)
|
||||
{
|
||||
iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc));
|
||||
}
|
||||
|
||||
void __init u8500_init_irq(void)
|
||||
{
|
||||
gic_dist_init(0, __io_address(U8500_GIC_DIST_BASE), 29);
|
||||
gic_cpu_init(0, __io_address(U8500_GIC_CPU_BASE));
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called from the board init
|
||||
*/
|
||||
void __init u8500_init_devices(void)
|
||||
{
|
||||
/* Register the platform devices */
|
||||
platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
|
||||
|
||||
return ;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2009 ST-Ericsson
|
||||
* This file is based ARM Realview platform
|
||||
* Copyright (c) 2003 ARM Limited
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
__INIT
|
||||
|
||||
/*
|
||||
* U8500 specific entry point for secondary CPUs.
|
||||
*/
|
||||
ENTRY(u8500_secondary_startup)
|
||||
mrc p15, 0, r0, c0, c0, 5
|
||||
and r0, r0, #15
|
||||
adr r4, 1f
|
||||
ldmia r4, {r5, r6}
|
||||
sub r4, r4, r5
|
||||
add r6, r6, r4
|
||||
dsb
|
||||
pen: ldr r7, [r6]
|
||||
cmp r7, r0
|
||||
bne pen
|
||||
|
||||
/*
|
||||
* we've been released from the holding pen: secondary_stack
|
||||
* should now contain the SVC stack for this core
|
||||
*/
|
||||
b secondary_startup
|
||||
|
||||
1: .long .
|
||||
.long pen_release
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Debugging macro include header
|
||||
*
|
||||
* Copyright (C) 2009 ST-Ericsson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
.macro addruart,rx
|
||||
mrc p15, 0, \rx, c1, c0
|
||||
tst \rx, #1 @MMU enabled?
|
||||
moveq \rx, #0x80000000 @MMU off, Physical address
|
||||
movne \rx, #0xF0000000 @MMU on, Virtual address
|
||||
orr \rx, \rx, #0x7000
|
||||
.endm
|
||||
|
||||
#include <asm/hardware/debug-pl01x.S>
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Low-level IRQ helper macros for U8500 platforms
|
||||
*
|
||||
* Copyright (C) 2009 ST-Ericsson.
|
||||
*
|
||||
* This file is a copy of ARM Realview platform.
|
||||
* -just satisfied checkpatch script.
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/hardware/gic.h>
|
||||
|
||||
.macro disable_fiq
|
||||
.endm
|
||||
|
||||
.macro get_irqnr_preamble, base, tmp
|
||||
ldr \base, =IO_ADDRESS(U8500_GIC_CPU_BASE)
|
||||
.endm
|
||||
|
||||
.macro arch_ret_to_user, tmp1, tmp2
|
||||
.endm
|
||||
|
||||
/*
|
||||
* The interrupt numbering scheme is defined in the
|
||||
* interrupt controller spec. To wit:
|
||||
*
|
||||
* Interrupts 0-15 are IPI
|
||||
* 16-28 are reserved
|
||||
* 29-31 are local. We allow 30 to be used for the watchdog.
|
||||
* 32-1020 are global
|
||||
* 1021-1022 are reserved
|
||||
* 1023 is "spurious" (no interrupt)
|
||||
*
|
||||
* For now, we ignore all local interrupts so only return an
|
||||
* interrupt if it's between 30 and 1020. The test_for_ipi
|
||||
* routine below will pick up on IPIs.
|
||||
*
|
||||
* A simple read from the controller will tell us the number
|
||||
* of the highest priority enabled interrupt. We then just
|
||||
* need to check whether it is in the valid range for an
|
||||
* IRQ (30-1020 inclusive).
|
||||
*/
|
||||
|
||||
.macro get_irqnr_and_base, irqnr, irqstat, base, tmp
|
||||
|
||||
/* bits 12-10 = src CPU, 9-0 = int # */
|
||||
ldr \irqstat, [\base, #GIC_CPU_INTACK]
|
||||
|
||||
ldr \tmp, =1021
|
||||
|
||||
bic \irqnr, \irqstat, #0x1c00
|
||||
|
||||
cmp \irqnr, #29
|
||||
cmpcc \irqnr, \irqnr
|
||||
cmpne \irqnr, \tmp
|
||||
cmpcs \irqnr, \irqnr
|
||||
|
||||
.endm
|
||||
|
||||
/* We assume that irqstat (the raw value of the IRQ
|
||||
* acknowledge register) is preserved from the macro above.
|
||||
* If there is an IPI, we immediately signal end of
|
||||
* interrupt on the controller, since this requires the
|
||||
* original irqstat value which we won't easily be able
|
||||
* to recreate later.
|
||||
*/
|
||||
|
||||
.macro test_for_ipi, irqnr, irqstat, base, tmp
|
||||
bic \irqnr, \irqstat, #0x1c00
|
||||
cmp \irqnr, #16
|
||||
strcc \irqstat, [\base, #GIC_CPU_EOI]
|
||||
cmpcs \irqnr, \irqnr
|
||||
.endm
|
||||
|
||||
/* As above, this assumes that irqstat and base
|
||||
* are preserved..
|
||||
*/
|
||||
|
||||
.macro test_for_ltirq, irqnr, irqstat, base, tmp
|
||||
bic \irqnr, \irqstat, #0x1c00
|
||||
mov \tmp, #0
|
||||
cmp \irqnr, #29
|
||||
moveq \tmp, #1
|
||||
streq \irqstat, [\base, #GIC_CPU_EOI]
|
||||
cmp \tmp, #0
|
||||
.endm
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright (C) 2009 ST-Ericsson
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef __ASM_ARCH_MEMORY_H
|
||||
#define __ASM_ARCH_MEMORY_H
|
||||
|
||||
/*
|
||||
* Physical DRAM offset.
|
||||
*/
|
||||
#define PHYS_OFFSET UL(0x00000000)
|
||||
#define BUS_OFFSET UL(0x00000000)
|
||||
|
||||
#endif
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (C) 2009 ST-Ericsson.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* These symbols are needed for board-specific files to call their
|
||||
* own cpu-specific files
|
||||
*/
|
||||
#ifndef __ASM_ARCH_SETUP_H
|
||||
#define __ASM_ARCH_SETUP_H
|
||||
|
||||
#include <asm/mach/time.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
extern void u8500_map_io(void);
|
||||
extern void u8500_init_devices(void);
|
||||
extern void u8500_init_irq(void);
|
||||
/* We re-use nomadik_timer for this platform */
|
||||
extern void nmdk_timer_init(void);
|
||||
|
||||
#endif /* __ASM_ARCH_SETUP_H */
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* This file is based ARM realview platform.
|
||||
* Copyright (C) ARM Limited.
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
#ifndef ASMARM_ARCH_SMP_H
|
||||
#define ASMARM_ARCH_SMP_H
|
||||
|
||||
#include <asm/hardware/gic.h>
|
||||
|
||||
/* This is required to wakeup the secondary core */
|
||||
extern void u8500_secondary_startup(void);
|
||||
|
||||
#define hard_smp_processor_id() \
|
||||
({ \
|
||||
unsigned int cpunum; \
|
||||
__asm__("mrc p15, 0, %0, c0, c0, 5" \
|
||||
: "=r" (cpunum)); \
|
||||
cpunum &= 0x0F; \
|
||||
})
|
||||
|
||||
/*
|
||||
* We use IRQ1 as the IPI
|
||||
*/
|
||||
static inline void smp_cross_call(const struct cpumask *mask)
|
||||
{
|
||||
gic_raise_softirq(mask, 1);
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (C) 2009 ST-Ericsson.
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
#ifndef __ASM_ARCH_SYSTEM_H
|
||||
#define __ASM_ARCH_SYSTEM_H
|
||||
|
||||
static inline void arch_idle(void)
|
||||
{
|
||||
/*
|
||||
* This should do all the clock switching
|
||||
* and wait for interrupt tricks
|
||||
*/
|
||||
cpu_do_idle();
|
||||
}
|
||||
|
||||
static inline void arch_reset(char mode, const char *cmd)
|
||||
{
|
||||
/* yet to be implemented - TODO */
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef __ASM_ARCH_TIMEX_H
|
||||
#define __ASM_ARCH_TIMEX_H
|
||||
|
||||
#define CLOCK_TICK_RATE 110000000
|
||||
|
||||
#endif
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (C) 2009 ST-Ericsson
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#ifndef __ASM_ARCH_UNCOMPRESS_H
|
||||
#define __ASM_ARCH_UNCOMPRESS_H
|
||||
|
||||
#include <asm/setup.h>
|
||||
#include <linux/io.h>
|
||||
#include <mach/hardware.h>
|
||||
|
||||
#define U8500_UART_DR 0x80007000
|
||||
#define U8500_UART_LCRH 0x8000702c
|
||||
#define U8500_UART_CR 0x80007030
|
||||
#define U8500_UART_FR 0x80007018
|
||||
|
||||
static void putc(const char c)
|
||||
{
|
||||
/* Do nothing if the UART is not enabled. */
|
||||
if (!(readb(U8500_UART_CR) & 0x1))
|
||||
return;
|
||||
|
||||
if (c == '\n')
|
||||
putc('\r');
|
||||
|
||||
while (readb(U8500_UART_FR) & (1 << 5))
|
||||
barrier();
|
||||
writeb(c, U8500_UART_DR);
|
||||
}
|
||||
|
||||
static void flush(void)
|
||||
{
|
||||
if (!(readb(U8500_UART_CR) & 0x1))
|
||||
return;
|
||||
while (readb(U8500_UART_FR) & (1 << 3))
|
||||
barrier();
|
||||
}
|
||||
|
||||
static inline void arch_decomp_setup(void)
|
||||
{
|
||||
}
|
||||
|
||||
#define arch_decomp_wdog() /* nothing to do here */
|
||||
|
||||
#endif /* __ASM_ARCH_UNCOMPRESS_H */
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright (C) 2009 ST-Ericsson
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#define VMALLOC_END 0xf0000000
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (C) 2008-2009 ST-Ericsson
|
||||
* Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
|
||||
*
|
||||
* This file is heavily based on relaview platform, almost a copy.
|
||||
*
|
||||
* Copyright (C) 2002 ARM Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/clockchips.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/smp_twd.h>
|
||||
#include <asm/localtimer.h>
|
||||
|
||||
/*
|
||||
* Setup the local clock events for a CPU.
|
||||
*/
|
||||
void __cpuinit local_timer_setup(struct clock_event_device *evt)
|
||||
{
|
||||
evt->irq = IRQ_LOCALTIMER;
|
||||
twd_timer_setup(evt);
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* Copyright (C) 2002 ARM Ltd.
|
||||
* Copyright (C) 2008 STMicroelctronics.
|
||||
* Copyright (C) 2009 ST-Ericsson.
|
||||
* Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
|
||||
*
|
||||
* This file is based on arm realview platform
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/localtimer.h>
|
||||
#include <asm/smp_scu.h>
|
||||
#include <mach/hardware.h>
|
||||
|
||||
/*
|
||||
* control for which core is the next to come out of the secondary
|
||||
* boot "holding pen"
|
||||
*/
|
||||
volatile int __cpuinitdata pen_release = -1;
|
||||
|
||||
static unsigned int __init get_core_count(void)
|
||||
{
|
||||
return scu_get_core_count(__io_address(U8500_SCU_BASE));
|
||||
}
|
||||
|
||||
static DEFINE_SPINLOCK(boot_lock);
|
||||
|
||||
void __cpuinit platform_secondary_init(unsigned int cpu)
|
||||
{
|
||||
trace_hardirqs_off();
|
||||
|
||||
/*
|
||||
* if any interrupts are already enabled for the primary
|
||||
* core (e.g. timer irq), then they will not have been enabled
|
||||
* for us: do so
|
||||
*/
|
||||
gic_cpu_init(0, __io_address(U8500_GIC_CPU_BASE));
|
||||
|
||||
/*
|
||||
* let the primary processor know we're out of the
|
||||
* pen, then head off into the C entry point
|
||||
*/
|
||||
pen_release = -1;
|
||||
|
||||
/*
|
||||
* Synchronise with the boot thread.
|
||||
*/
|
||||
spin_lock(&boot_lock);
|
||||
spin_unlock(&boot_lock);
|
||||
}
|
||||
|
||||
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
|
||||
{
|
||||
unsigned long timeout;
|
||||
|
||||
/*
|
||||
* set synchronisation state between this boot processor
|
||||
* and the secondary one
|
||||
*/
|
||||
spin_lock(&boot_lock);
|
||||
|
||||
/*
|
||||
* The secondary processor is waiting to be released from
|
||||
* the holding pen - release it, then wait for it to flag
|
||||
* that it has been released by resetting pen_release.
|
||||
*/
|
||||
pen_release = cpu;
|
||||
flush_cache_all();
|
||||
|
||||
timeout = jiffies + (1 * HZ);
|
||||
while (time_before(jiffies, timeout)) {
|
||||
if (pen_release == -1)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* now the secondary core is starting up let it run its
|
||||
* calibrations, then wait for it to finish
|
||||
*/
|
||||
spin_unlock(&boot_lock);
|
||||
|
||||
return pen_release != -1 ? -ENOSYS : 0;
|
||||
}
|
||||
|
||||
static void __init wakeup_secondary(void)
|
||||
{
|
||||
/* nobody is to be released from the pen yet */
|
||||
pen_release = -1;
|
||||
|
||||
/*
|
||||
* write the address of secondary startup into the backup ram register
|
||||
* at offset 0x1FF4, then write the magic number 0xA1FEED01 to the
|
||||
* backup ram register at offset 0x1FF0, which is what boot rom code
|
||||
* is waiting for. This would wake up the secondary core from WFE
|
||||
*/
|
||||
#define U8500_CPU1_JUMPADDR_OFFSET 0x1FF4
|
||||
__raw_writel(virt_to_phys(u8500_secondary_startup),
|
||||
(void __iomem *)IO_ADDRESS(U8500_BACKUPRAM0_BASE) +
|
||||
U8500_CPU1_JUMPADDR_OFFSET);
|
||||
|
||||
#define U8500_CPU1_WAKEMAGIC_OFFSET 0x1FF0
|
||||
__raw_writel(0xA1FEED01,
|
||||
(void __iomem *)IO_ADDRESS(U8500_BACKUPRAM0_BASE) +
|
||||
U8500_CPU1_WAKEMAGIC_OFFSET);
|
||||
|
||||
/* make sure write buffer is drained */
|
||||
mb();
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise the CPU possible map early - this describes the CPUs
|
||||
* which may be present or become present in the system.
|
||||
*/
|
||||
void __init smp_init_cpus(void)
|
||||
{
|
||||
unsigned int i, ncores = get_core_count();
|
||||
|
||||
for (i = 0; i < ncores; i++)
|
||||
set_cpu_possible(i, true);
|
||||
}
|
||||
|
||||
void __init smp_prepare_cpus(unsigned int max_cpus)
|
||||
{
|
||||
unsigned int ncores = get_core_count();
|
||||
unsigned int cpu = smp_processor_id();
|
||||
int i;
|
||||
|
||||
/* sanity check */
|
||||
if (ncores == 0) {
|
||||
printk(KERN_ERR
|
||||
"U8500: strange CM count of 0? Default to 1\n");
|
||||
ncores = 1;
|
||||
}
|
||||
|
||||
if (ncores > num_possible_cpus()) {
|
||||
printk(KERN_WARNING
|
||||
"U8500: no. of cores (%d) greater than configured "
|
||||
"maximum of %d - clipping\n",
|
||||
ncores, num_possible_cpus());
|
||||
ncores = num_possible_cpus();
|
||||
}
|
||||
|
||||
smp_store_cpu_info(cpu);
|
||||
|
||||
/*
|
||||
* are we trying to boot more cores than exist?
|
||||
*/
|
||||
if (max_cpus > ncores)
|
||||
max_cpus = ncores;
|
||||
|
||||
/*
|
||||
* Initialise the present map, which describes the set of CPUs
|
||||
* actually populated at the present time.
|
||||
*/
|
||||
for (i = 0; i < max_cpus; i++)
|
||||
set_cpu_present(i, true);
|
||||
|
||||
if (max_cpus > 1) {
|
||||
/*
|
||||
* Enable the local timer or broadcast device for the
|
||||
* boot CPU, but only if we have more than one CPU.
|
||||
*/
|
||||
percpu_timer_setup();
|
||||
scu_enable(__io_address(U8500_SCU_BASE));
|
||||
wakeup_secondary();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue