[ARM] 5473/1: U300 core machine support

This adds core support for the ST-Ericsson U300 series
platforms: U300, U330, U335 and U365. Supports memory
mappings, interrupt controller, system timer (clocksource
and clockevents), and binds to the existing drivers for
the PrimeCells used in this design: PL190 (VIC), PL180
(MMC/SD host) and PL011 (UART). This is intented to serve
as starting point for our mainling work, more patches to
follow.

Signed-off-by: Linus Walleij <linus.walleij@stericsson.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
Linus Walleij 2009-04-23 10:22:13 +01:00 committed by Russell King
parent cd27e48541
commit bb3cee2b35
15 changed files with 1716 additions and 0 deletions

105
arch/arm/mach-u300/Kconfig Normal file
View File

@ -0,0 +1,105 @@
if ARCH_U300
menu "ST-Ericsson AB U300/U330/U335/U365 Platform"
comment "ST-Ericsson Mobile Platform Products"
config MACH_U300
bool "U300"
comment "ST-Ericsson U300/U330/U335/U365 Feature Selections"
choice
prompt "U300/U330/U335/U365 system type"
default MACH_U300_BS2X
---help---
You need to select the target system, i.e. the
U300/U330/U335/U365 board that you want to compile your kernel
for.
config MACH_U300_BS2X
bool "S26/S26/B25/B26 Test Products"
depends on MACH_U300
help
Select this if you're developing on the
S26/S25 test products. (Also works on
B26/B25 big boards.)
config MACH_U300_BS330
bool "S330/B330 Test Products"
depends on MACH_U300
help
Select this if you're developing on the
S330/B330 test products.
config MACH_U300_BS335
bool "S335/B335 Test Products"
depends on MACH_U300
help
Select this if you're developing on the
S335/B335 test products.
config MACH_U300_BS365
bool "S365/B365 Test Products"
depends on MACH_U300
help
Select this if you're developing on the
S365/B365 test products.
endchoice
choice
prompt "Memory configuration"
default MACH_U300_SINGLE_RAM
---help---
You have to config the kernel according to the physical memory
configuration.
config MACH_U300_SINGLE_RAM
bool "Single RAM"
help
Select this if you want support for Single RAM phones.
config MACH_U300_DUAL_RAM
bool "Dual RAM"
help
Select this if you want support for Dual RAM phones.
This is two RAM memorys on different EMIFs.
endchoice
config U300_DEBUG
bool "Debug support for U300"
depends on PM
help
Debug support for U300 in sysfs, procfs etc.
config MACH_U300_SEMI_IS_SHARED
bool "The SEMI is used by both the access and application side"
depends on MACH_U300
help
This makes it possible to use the SEMI (Shared External
Memory Interface) from both from access and application
side.
comment "All the settings below must match the bootloader's settings"
config MACH_U300_ACCESS_MEM_SIZE
int "Access CPU memory allocation"
range 7 25
depends on MACH_U300_SINGLE_RAM
default 13
help
How much memory in MiB that the Access side CPU has allocated
config MACH_U300_2MB_ALIGNMENT_FIX
bool "2MiB alignment fix"
depends on MACH_U300_SINGLE_RAM
default y
help
If yes and the Access side CPU has allocated an odd size in
MiB, this fix gives you one MiB extra that would otherwise be
lost due to Linux 2 MiB alignment policy.
endmenu
endif

View File

@ -0,0 +1,11 @@
#
# Makefile for the linux kernel, U300 machine.
#
obj-y := core.o clock.o timer.o gpio.o padmux.o
obj-m :=
obj-n :=
obj- :=
obj-$(CONFIG_ARCH_U300) += u300.o
obj-$(CONFIG_MMC) += mmc.o

649
arch/arm/mach-u300/core.c Normal file
View File

@ -0,0 +1,649 @@
/*
*
* arch/arm/mach-u300/core.c
*
*
* Copyright (C) 2007-2009 ST-Ericsson AB
* License terms: GNU General Public License (GPL) version 2
* Core platform support, IRQ handling and device definitions.
* Author: Linus Walleij <linus.walleij@stericsson.com>
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/mm.h>
#include <linux/termios.h>
#include <linux/amba/bus.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <asm/types.h>
#include <asm/setup.h>
#include <asm/memory.h>
#include <asm/hardware/vic.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
#include <mach/hardware.h>
#include <mach/syscon.h>
#include "clock.h"
#include "mmc.h"
/*
* Static I/O mappings that are needed for booting the U300 platforms. The
* only things we need are the areas where we find the timer, syscon and
* intcon, since the remaining device drivers will map their own memory
* physical to virtual as the need arise.
*/
static struct map_desc u300_io_desc[] __initdata = {
{
.virtual = U300_SLOW_PER_VIRT_BASE,
.pfn = __phys_to_pfn(U300_SLOW_PER_PHYS_BASE),
.length = SZ_64K,
.type = MT_DEVICE,
},
{
.virtual = U300_AHB_PER_VIRT_BASE,
.pfn = __phys_to_pfn(U300_AHB_PER_PHYS_BASE),
.length = SZ_32K,
.type = MT_DEVICE,
},
{
.virtual = U300_FAST_PER_VIRT_BASE,
.pfn = __phys_to_pfn(U300_FAST_PER_PHYS_BASE),
.length = SZ_32K,
.type = MT_DEVICE,
},
{
.virtual = 0xffff2000, /* TCM memory */
.pfn = __phys_to_pfn(0xffff2000),
.length = SZ_16K,
.type = MT_DEVICE,
},
/*
* This overlaps with the IRQ vectors etc at 0xffff0000, so these
* may have to be moved to 0x00000000 in order to use the ROM.
*/
/*
{
.virtual = U300_BOOTROM_VIRT_BASE,
.pfn = __phys_to_pfn(U300_BOOTROM_PHYS_BASE),
.length = SZ_64K,
.type = MT_ROM,
},
*/
};
void __init u300_map_io(void)
{
iotable_init(u300_io_desc, ARRAY_SIZE(u300_io_desc));
}
/*
* Declaration of devices found on the U300 board and
* their respective memory locations.
*/
static struct amba_device uart0_device = {
.dev = {
.init_name = "uart0", /* Slow device at 0x3000 offset */
.platform_data = NULL,
},
.res = {
.start = U300_UART0_BASE,
.end = U300_UART0_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
.irq = { IRQ_U300_UART0, NO_IRQ },
};
/* The U335 have an additional UART1 on the APP CPU */
#ifdef CONFIG_MACH_U300_BS335
static struct amba_device uart1_device = {
.dev = {
.init_name = "uart1", /* Fast device at 0x7000 offset */
.platform_data = NULL,
},
.res = {
.start = U300_UART1_BASE,
.end = U300_UART1_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
.irq = { IRQ_U300_UART1, NO_IRQ },
};
#endif
static struct amba_device pl172_device = {
.dev = {
.init_name = "pl172", /* AHB device at 0x4000 offset */
.platform_data = NULL,
},
.res = {
.start = U300_EMIF_CFG_BASE,
.end = U300_EMIF_CFG_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
};
/*
* Everything within this next ifdef deals with external devices connected to
* the APP SPI bus.
*/
static struct amba_device pl022_device = {
.dev = {
.coherent_dma_mask = ~0,
.init_name = "pl022", /* Fast device at 0x6000 offset */
},
.res = {
.start = U300_SPI_BASE,
.end = U300_SPI_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
.irq = {IRQ_U300_SPI, NO_IRQ },
/*
* This device has a DMA channel but the Linux driver does not use
* it currently.
*/
};
static struct amba_device mmcsd_device = {
.dev = {
.init_name = "mmci", /* Fast device at 0x1000 offset */
.platform_data = NULL, /* Added later */
},
.res = {
.start = U300_MMCSD_BASE,
.end = U300_MMCSD_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
.irq = {IRQ_U300_MMCSD_MCIINTR0, IRQ_U300_MMCSD_MCIINTR1 },
/*
* This device has a DMA channel but the Linux driver does not use
* it currently.
*/
};
/*
* The order of device declaration may be important, since some devices
* have dependencies on other devices being initialized first.
*/
static struct amba_device *amba_devs[] __initdata = {
&uart0_device,
#ifdef CONFIG_MACH_U300_BS335
&uart1_device,
#endif
&pl022_device,
&pl172_device,
&mmcsd_device,
};
/* Here follows a list of all hw resources that the platform devices
* allocate. Note, clock dependencies are not included
*/
static struct resource gpio_resources[] = {
{
.start = U300_GPIO_BASE,
.end = (U300_GPIO_BASE + SZ_4K - 1),
.flags = IORESOURCE_MEM,
},
{
.name = "gpio0",
.start = IRQ_U300_GPIO_PORT0,
.end = IRQ_U300_GPIO_PORT0,
.flags = IORESOURCE_IRQ,
},
{
.name = "gpio1",
.start = IRQ_U300_GPIO_PORT1,
.end = IRQ_U300_GPIO_PORT1,
.flags = IORESOURCE_IRQ,
},
{
.name = "gpio2",
.start = IRQ_U300_GPIO_PORT2,
.end = IRQ_U300_GPIO_PORT2,
.flags = IORESOURCE_IRQ,
},
#ifdef U300_COH901571_3
{
.name = "gpio3",
.start = IRQ_U300_GPIO_PORT3,
.end = IRQ_U300_GPIO_PORT3,
.flags = IORESOURCE_IRQ,
},
{
.name = "gpio4",
.start = IRQ_U300_GPIO_PORT4,
.end = IRQ_U300_GPIO_PORT4,
.flags = IORESOURCE_IRQ,
},
#ifdef CONFIG_MACH_U300_BS335
{
.name = "gpio5",
.start = IRQ_U300_GPIO_PORT5,
.end = IRQ_U300_GPIO_PORT5,
.flags = IORESOURCE_IRQ,
},
{
.name = "gpio6",
.start = IRQ_U300_GPIO_PORT6,
.end = IRQ_U300_GPIO_PORT6,
.flags = IORESOURCE_IRQ,
},
#endif /* CONFIG_MACH_U300_BS335 */
#endif /* U300_COH901571_3 */
};
static struct resource keypad_resources[] = {
{
.start = U300_KEYPAD_BASE,
.end = U300_KEYPAD_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "coh901461-press",
.start = IRQ_U300_KEYPAD_KEYBF,
.end = IRQ_U300_KEYPAD_KEYBF,
.flags = IORESOURCE_IRQ,
},
{
.name = "coh901461-release",
.start = IRQ_U300_KEYPAD_KEYBR,
.end = IRQ_U300_KEYPAD_KEYBR,
.flags = IORESOURCE_IRQ,
},
};
static struct resource rtc_resources[] = {
{
.start = U300_RTC_BASE,
.end = U300_RTC_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
{
.start = IRQ_U300_RTC,
.end = IRQ_U300_RTC,
.flags = IORESOURCE_IRQ,
},
};
/*
* Fsmc does have IRQs: #43 and #44 (NFIF and NFIF2)
* but these are not yet used by the driver.
*/
static struct resource fsmc_resources[] = {
{
.start = U300_NAND_IF_PHYS_BASE,
.end = U300_NAND_IF_PHYS_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
};
static struct resource i2c0_resources[] = {
{
.start = U300_I2C0_BASE,
.end = U300_I2C0_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
{
.start = IRQ_U300_I2C0,
.end = IRQ_U300_I2C0,
.flags = IORESOURCE_IRQ,
},
};
static struct resource i2c1_resources[] = {
{
.start = U300_I2C1_BASE,
.end = U300_I2C1_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
{
.start = IRQ_U300_I2C1,
.end = IRQ_U300_I2C1,
.flags = IORESOURCE_IRQ,
},
};
static struct resource wdog_resources[] = {
{
.start = U300_WDOG_BASE,
.end = U300_WDOG_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
{
.start = IRQ_U300_WDOG,
.end = IRQ_U300_WDOG,
.flags = IORESOURCE_IRQ,
}
};
/* TODO: These should be protected by suitable #ifdef's */
static struct resource ave_resources[] = {
{
.name = "AVE3e I/O Area",
.start = U300_VIDEOENC_BASE,
.end = U300_VIDEOENC_BASE + SZ_512K - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "AVE3e IRQ0",
.start = IRQ_U300_VIDEO_ENC_0,
.end = IRQ_U300_VIDEO_ENC_0,
.flags = IORESOURCE_IRQ,
},
{
.name = "AVE3e IRQ1",
.start = IRQ_U300_VIDEO_ENC_1,
.end = IRQ_U300_VIDEO_ENC_1,
.flags = IORESOURCE_IRQ,
},
{
.name = "AVE3e Physmem Area",
.start = 0, /* 0 will be remapped to reserved memory */
.end = SZ_1M - 1,
.flags = IORESOURCE_MEM,
},
/*
* The AVE3e requires two regions of 256MB that it considers
* "invisible". The hardware will not be able to access these
* adresses, so they should never point to system RAM.
*/
{
.name = "AVE3e Reserved 0",
.start = 0xd0000000,
.end = 0xd0000000 + SZ_256M - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "AVE3e Reserved 1",
.start = 0xe0000000,
.end = 0xe0000000 + SZ_256M - 1,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device wdog_device = {
.name = "wdog",
.id = -1,
.num_resources = ARRAY_SIZE(wdog_resources),
.resource = wdog_resources,
};
static struct platform_device i2c0_device = {
.name = "stddci2c",
.id = 0,
.num_resources = ARRAY_SIZE(i2c0_resources),
.resource = i2c0_resources,
};
static struct platform_device i2c1_device = {
.name = "stddci2c",
.id = 1,
.num_resources = ARRAY_SIZE(i2c1_resources),
.resource = i2c1_resources,
};
static struct platform_device gpio_device = {
.name = "u300-gpio",
.id = -1,
.num_resources = ARRAY_SIZE(gpio_resources),
.resource = gpio_resources,
};
static struct platform_device keypad_device = {
.name = "keypad",
.id = -1,
.num_resources = ARRAY_SIZE(keypad_resources),
.resource = keypad_resources,
};
static struct platform_device rtc_device = {
.name = "rtc0",
.id = -1,
.num_resources = ARRAY_SIZE(rtc_resources),
.resource = rtc_resources,
};
static struct platform_device fsmc_device = {
.name = "nandif",
.id = -1,
.num_resources = ARRAY_SIZE(fsmc_resources),
.resource = fsmc_resources,
};
static struct platform_device ave_device = {
.name = "video_enc",
.id = -1,
.num_resources = ARRAY_SIZE(ave_resources),
.resource = ave_resources,
};
/*
* Notice that AMBA devices are initialized before platform devices.
*
*/
static struct platform_device *platform_devs[] __initdata = {
&i2c0_device,
&i2c1_device,
&keypad_device,
&rtc_device,
&gpio_device,
&fsmc_device,
&wdog_device,
&ave_device
};
/*
* Interrupts: the U300 platforms have two pl190 ARM PrimeCells connected
* together so some interrupts are connected to the first one and some
* to the second one.
*/
void __init u300_init_irq(void)
{
u32 mask[2] = {0, 0};
int i;
for (i = 0; i < NR_IRQS; i++)
set_bit(i, (unsigned long *) &mask[0]);
u300_enable_intcon_clock();
vic_init((void __iomem *) U300_INTCON0_VBASE, 0, mask[0]);
vic_init((void __iomem *) U300_INTCON1_VBASE, 32, mask[1]);
}
/*
* U300 platforms peripheral handling
*/
struct db_chip {
u16 chipid;
const char *name;
};
/*
* This is a list of the Digital Baseband chips used in the U300 platform.
*/
static struct db_chip db_chips[] __initdata = {
{
.chipid = 0xb800,
.name = "DB3000",
},
{
.chipid = 0xc000,
.name = "DB3100",
},
{
.chipid = 0xc800,
.name = "DB3150",
},
{
.chipid = 0xd800,
.name = "DB3200",
},
{
.chipid = 0xe000,
.name = "DB3250",
},
{
.chipid = 0xe800,
.name = "DB3210",
},
{
.chipid = 0xf000,
.name = "DB3350 P1x",
},
{
.chipid = 0xf100,
.name = "DB3350 P2x",
},
{
.chipid = 0x0000, /* List terminator */
.name = NULL,
}
};
static void u300_init_check_chip(void)
{
u16 val;
struct db_chip *chip;
const char *chipname;
const char unknown[] = "UNKNOWN";
/* Read out and print chip ID */
val = readw(U300_SYSCON_VBASE + U300_SYSCON_CIDR);
/* This is in funky bigendian order... */
val = (val & 0xFFU) << 8 | (val >> 8);
chip = db_chips;
chipname = unknown;
for ( ; chip->chipid; chip++) {
if (chip->chipid == (val & 0xFF00U)) {
chipname = chip->name;
break;
}
}
printk(KERN_INFO "Initializing U300 system on %s baseband chip " \
"(chip ID 0x%04x)\n", chipname, val);
#ifdef CONFIG_MACH_U300_BS26
if ((val & 0xFF00U) != 0xc800) {
printk(KERN_ERR "Platform configured for BS25/BS26 " \
"with DB3150 but %s detected, expect problems!",
chipname);
}
#endif
#ifdef CONFIG_MACH_U300_BS330
if ((val & 0xFF00U) != 0xd800) {
printk(KERN_ERR "Platform configured for BS330 " \
"with DB3200 but %s detected, expect problems!",
chipname);
}
#endif
#ifdef CONFIG_MACH_U300_BS335
if ((val & 0xFF00U) != 0xf000 && (val & 0xFF00U) != 0xf100) {
printk(KERN_ERR "Platform configured for BS365 " \
" with DB3350 but %s detected, expect problems!",
chipname);
}
#endif
#ifdef CONFIG_MACH_U300_BS365
if ((val & 0xFF00U) != 0xe800) {
printk(KERN_ERR "Platform configured for BS365 " \
"with DB3210 but %s detected, expect problems!",
chipname);
}
#endif
}
/*
* Some devices and their resources require reserved physical memory from
* the end of the available RAM. This function traverses the list of devices
* and assigns actual adresses to these.
*/
static void __init u300_assign_physmem(void)
{
unsigned long curr_start = __pa(high_memory);
int i, j;
for (i = 0; i < ARRAY_SIZE(platform_devs); i++) {
for (j = 0; j < platform_devs[i]->num_resources; j++) {
struct resource *const res =
&platform_devs[i]->resource[j];
if (IORESOURCE_MEM == res->flags &&
0 == res->start) {
res->start = curr_start;
res->end += curr_start;
curr_start += (res->end - res->start + 1);
printk(KERN_INFO "core.c: Mapping RAM " \
"%#x-%#x to device %s:%s\n",
res->start, res->end,
platform_devs[i]->name, res->name);
}
}
}
}
void __init u300_init_devices(void)
{
int i;
u16 val;
/* Check what platform we run and print some status information */
u300_init_check_chip();
/* Set system to run at PLL208, max performance, a known state. */
val = readw(U300_SYSCON_VBASE + U300_SYSCON_CCR);
val &= ~U300_SYSCON_CCR_CLKING_PERFORMANCE_MASK;
writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
/* Wait for the PLL208 to lock if not locked in yet */
while (!(readw(U300_SYSCON_VBASE + U300_SYSCON_CSR) &
U300_SYSCON_CSR_PLL208_LOCK_IND));
/* Register the AMBA devices in the AMBA bus abstraction layer */
u300_clock_primecells();
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
struct amba_device *d = amba_devs[i];
amba_device_register(d, &iomem_resource);
}
u300_unclock_primecells();
u300_assign_physmem();
/* Register the platform devices */
platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
#ifndef CONFIG_MACH_U300_SEMI_IS_SHARED
/*
* Enable SEMI self refresh. Self-refresh of the SDRAM is entered when
* both subsystems are requesting this mode.
* If we not share the Acc SDRAM, this is never the case. Therefore
* enable it here from the App side.
*/
val = readw(U300_SYSCON_VBASE + U300_SYSCON_SMCR) |
U300_SYSCON_SMCR_SEMI_SREFREQ_ENABLE;
writew(val, U300_SYSCON_VBASE + U300_SYSCON_SMCR);
#endif /* CONFIG_MACH_U300_SEMI_IS_SHARED */
}
static int core_module_init(void)
{
/*
* This needs to be initialized later: it needs the input framework
* to be initialized first.
*/
return mmc_init(&mmcsd_device);
}
module_init(core_module_init);

View File

@ -0,0 +1,22 @@
/*
*
* arch-arm/mach-u300/include/mach/debug-macro.S
*
*
* Copyright (C) 2006-2009 ST-Ericsson AB
* License terms: GNU General Public License (GPL) version 2
* Debugging macro include header.
* Author: Linus Walleij <linus.walleij@stericsson.com>
*/
#include <mach/hardware.h>
.macro addruart,rx
/* If we move the adress using MMU, use this. */
mrc p15, 0, \rx, c1, c0
tst \rx, #1 @ MMU enabled?
ldreq \rx, = U300_SLOW_PER_PHYS_BASE @ MMU off, physical address
ldrne \rx, = U300_SLOW_PER_VIRT_BASE @ MMU on, virtual address
orr \rx, \rx, #0x00003000
.endm
#include <asm/hardware/debug-pl01x.S>

View File

@ -0,0 +1,40 @@
/*
*
* arch-arm/mach-u300/include/mach/entry-macro.S
*
*
* Copyright (C) 2006-2009 ST-Ericsson AB
* License terms: GNU General Public License (GPL) version 2
* Low-level IRQ helper macros for ST-Ericsson U300
* Author: Linus Walleij <linus.walleij@stericsson.com>
*/
#include <mach/hardware.h>
#include <asm/hardware/vic.h>
.macro disable_fiq
.endm
.macro get_irqnr_preamble, base, tmp
.endm
.macro arch_ret_to_user, tmp1, tmp2
.endm
.macro get_irqnr_and_base, irqnr, irqstat, base, tmp
ldr \base, = U300_AHB_PER_VIRT_BASE-U300_AHB_PER_PHYS_BASE+U300_INTCON0_BASE
ldr \irqstat, [\base, #VIC_IRQ_STATUS] @ get masked status
mov \irqnr, #0
teq \irqstat, #0
bne 1002f
1001: ldr \base, = U300_AHB_PER_VIRT_BASE-U300_AHB_PER_PHYS_BASE+U300_INTCON1_BASE
ldr \irqstat, [\base, #VIC_IRQ_STATUS] @ get masked status
mov \irqnr, #32
teq \irqstat, #0
beq 1003f
1002: tst \irqstat, #1
bne 1003f
add \irqnr, \irqnr, #1
movs \irqstat, \irqstat, lsr #1
bne 1002b
1003: /* EQ will be set if no irqs pending */
.endm

View File

@ -0,0 +1,42 @@
/*
*
* arch/arm/mach-u300/include/mach/memory.h
*
*
* Copyright (C) 2007-2009 ST-Ericsson AB
* License terms: GNU General Public License (GPL) version 2
* Memory virtual/physical mapping constants.
* Author: Linus Walleij <linus.walleij@stericsson.com>
* Author: Jonas Aaberg <jonas.aberg@stericsson.com>
*/
#ifndef __MACH_MEMORY_H
#define __MACH_MEMORY_H
#ifdef CONFIG_MACH_U300_DUAL_RAM
#define PHYS_OFFSET UL(0x48000000)
#define BOOT_PARAMS_OFFSET (PHYS_OFFSET + 0x100)
#else
#ifdef CONFIG_MACH_U300_2MB_ALIGNMENT_FIX
#define PHYS_OFFSET (0x28000000 + \
(CONFIG_MACH_U300_ACCESS_MEM_SIZE - \
(CONFIG_MACH_U300_ACCESS_MEM_SIZE & 1))*1024*1024)
#else
#define PHYS_OFFSET (0x28000000 + \
(CONFIG_MACH_U300_ACCESS_MEM_SIZE + \
(CONFIG_MACH_U300_ACCESS_MEM_SIZE & 1))*1024*1024)
#endif
#define BOOT_PARAMS_OFFSET (0x28000000 + \
(CONFIG_MACH_U300_ACCESS_MEM_SIZE + \
(CONFIG_MACH_U300_ACCESS_MEM_SIZE & 1))*1024*1024 + 0x100)
#endif
/*
* We enable a real big DMA buffer if need be.
*/
#define CONSISTENT_DMA_SIZE SZ_4M
#endif

View File

@ -0,0 +1,19 @@
/*
*
* arch/arm/mach-u300/include/mach/platform.h
*
*
* Copyright (C) 2006-2009 ST-Ericsson AB
* License terms: GNU General Public License (GPL) version 2
* Basic platform init and mapping functions.
* Author: Linus Walleij <linus.walleij@stericsson.com>
*/
#ifndef __ASSEMBLY__
void u300_map_io(void);
void u300_init_irq(void);
void u300_init_devices(void);
extern struct sys_timer u300_timer;
#endif

View File

@ -0,0 +1,42 @@
/*
*
* arch/arm/mach-u300/include/mach/system.h
*
*
* Copyright (C) 2007-2009 ST-Ericsson AB
* License terms: GNU General Public License (GPL) version 2
* System shutdown and reset functions.
* Author: Linus Walleij <linus.walleij@stericsson.com>
*/
#include <mach/hardware.h>
#include <asm/io.h>
#include <asm/hardware/vic.h>
#include <asm/irq.h>
/* Forward declare this function from the watchdog */
void coh901327_watchdog_reset(void);
static inline void arch_idle(void)
{
cpu_do_idle();
}
static void arch_reset(char mode, const char *cmd)
{
switch (mode) {
case 's':
case 'h':
printk(KERN_CRIT "RESET: shutting down/rebooting system\n");
/* Disable interrupts */
local_irq_disable();
#ifdef CONFIG_COH901327_WATCHDOG
coh901327_watchdog_reset();
#endif
break;
default:
/* Do nothing */
break;
}
/* Wait for system do die/reset. */
while (1);
}

View File

@ -0,0 +1,17 @@
/*
*
* arch/arm/mach-u300/include/mach/timex.h
*
*
* Copyright (C) 2006-2009 ST-Ericsson AB
* License terms: GNU General Public License (GPL) version 2
* Platform tick rate definition.
* Author: Linus Walleij <linus.walleij@stericsson.com>
*/
#ifndef __MACH_TIMEX_H
#define __MACH_TIMEX_H
/* This is for the APP OS GP1 (General Purpose 1) timer */
#define CLOCK_TICK_RATE 1000000
#endif

View File

@ -0,0 +1,46 @@
/*
* arch/arm/mach-u300/include/mach/uncompress.h
*
* Copyright (C) 2003 ARM Limited
*
* 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 AMBA_UART_DR (*(volatile unsigned char *)0xc0013000)
#define AMBA_UART_LCRH (*(volatile unsigned char *)0xc001302C)
#define AMBA_UART_CR (*(volatile unsigned char *)0xc0013030)
#define AMBA_UART_FR (*(volatile unsigned char *)0xc0013018)
/*
* This does not append a newline
*/
static inline void putc(int c)
{
while (AMBA_UART_FR & (1 << 5))
barrier();
AMBA_UART_DR = c;
}
static inline void flush(void)
{
while (AMBA_UART_FR & (1 << 3))
barrier();
}
/*
* nothing to do
*/
#define arch_decomp_setup()
#define arch_decomp_wdog()

View File

@ -0,0 +1,12 @@
/*
*
* arch/arm/mach-u300/include/mach/vmalloc.h
*
*
* Copyright (C) 2006-2009 ST-Ericsson AB
* License terms: GNU General Public License (GPL) version 2
* Virtual memory allocations
* End must be above the I/O registers and on an even 2MiB boundary.
* Author: Linus Walleij <linus.walleij@stericsson.com>
*/
#define VMALLOC_END 0xfe800000

216
arch/arm/mach-u300/mmc.c Normal file
View File

@ -0,0 +1,216 @@
/*
*
* arch/arm/mach-u300/mmc.c
*
*
* Copyright (C) 2009 ST-Ericsson AB
* License terms: GNU General Public License (GPL) version 2
*
* Author: Linus Walleij <linus.walleij@stericsson.com>
* Author: Johan Lundin <johan.lundin@stericsson.com>
* Author: Jonas Aaberg <jonas.aberg@stericsson.com>
*/
#include <linux/device.h>
#include <linux/amba/bus.h>
#include <linux/mmc/host.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/machine.h>
#include <linux/gpio.h>
#include <asm/mach/mmc.h>
#include "mmc.h"
struct mmci_card_event {
struct input_dev *mmc_input;
int mmc_inserted;
struct work_struct workq;
struct mmc_platform_data mmc0_plat_data;
};
static unsigned int mmc_status(struct device *dev)
{
struct mmci_card_event *mmci_card = container_of(
dev->platform_data,
struct mmci_card_event, mmc0_plat_data);
return mmci_card->mmc_inserted;
}
/*
* Here follows a large chunk of code which will only be enabled if you
* have both the AB3100 chip mounted and the MMC subsystem activated.
*/
static u32 mmc_translate_vdd(struct device *dev, unsigned int voltage)
{
int v;
/*
* MMC Spec:
* bit 7: 1.70 - 1.95V
* bit 8 - 14: 2.0 - 2.6V
* bit 15 - 23: 2.7 - 3.6V
*
* ab3100 voltages:
* 000 - 2.85V
* 001 - 2.75V
* 010 - 1.8V
* 011 - 1.5V
*/
switch (voltage) {
case 8:
v = 3;
break;
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
v = 1;
break;
case 16:
v = 1;
break;
case 17:
case 18:
case 19:
case 20:
case 21:
case 22:
case 23:
case 24:
v = 0;
break;
default:
v = 0;
break;
}
/* PL180 voltage register bits */
return v << 2;
}
static int mmci_callback(void *data)
{
struct mmci_card_event *mmci_card = data;
disable_irq_on_gpio_pin(U300_GPIO_PIN_MMC_CD);
schedule_work(&mmci_card->workq);
return 0;
}
static ssize_t gpio_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct mmci_card_event *mmci_card = container_of(
dev->platform_data,
struct mmci_card_event, mmc0_plat_data);
return sprintf(buf, "%d\n", !mmci_card->mmc_inserted);
}
static DEVICE_ATTR(mmc_inserted, S_IRUGO, gpio_show, NULL);
static void _mmci_callback(struct work_struct *ws)
{
struct mmci_card_event *mmci_card = container_of(
ws,
struct mmci_card_event, workq);
mdelay(20);
mmci_card->mmc_inserted = !!gpio_get_value(U300_GPIO_PIN_MMC_CD);
input_report_switch(mmci_card->mmc_input, KEY_INSERT,
!mmci_card->mmc_inserted);
input_sync(mmci_card->mmc_input);
pr_debug("MMC/SD card was %s\n",
mmci_card->mmc_inserted ? "removed" : "inserted");
enable_irq_on_gpio_pin(U300_GPIO_PIN_MMC_CD, !mmci_card->mmc_inserted);
}
int __devinit mmc_init(struct amba_device *adev)
{
struct mmci_card_event *mmci_card;
struct device *mmcsd_device = &adev->dev;
int ret = 0;
mmci_card = kzalloc(sizeof(struct mmci_card_event), GFP_KERNEL);
if (!mmci_card)
return -ENOMEM;
/* Nominally 2.85V on our platform */
mmci_card->mmc0_plat_data.ocr_mask = MMC_VDD_28_29;
mmci_card->mmc0_plat_data.translate_vdd = mmc_translate_vdd;
mmci_card->mmc0_plat_data.status = mmc_status;
mmcsd_device->platform_data = (void *) &mmci_card->mmc0_plat_data;
INIT_WORK(&mmci_card->workq, _mmci_callback);
ret = gpio_request(U300_GPIO_PIN_MMC_CD, "MMC card detection");
if (ret) {
printk(KERN_CRIT "Could not allocate MMC card detection " \
"GPIO pin\n");
goto out;
}
ret = gpio_direction_input(U300_GPIO_PIN_MMC_CD);
if (ret) {
printk(KERN_CRIT "Invalid GPIO pin requested\n");
goto out;
}
ret = sysfs_create_file(&mmcsd_device->kobj,
&dev_attr_mmc_inserted.attr);
if (ret)
goto out;
mmci_card->mmc_input = input_allocate_device();
if (!mmci_card->mmc_input) {
printk(KERN_CRIT "Could not allocate MMC input device\n");
return -ENOMEM;
}
mmci_card->mmc_input->name = "MMC insert notification";
mmci_card->mmc_input->id.bustype = BUS_HOST;
mmci_card->mmc_input->id.vendor = 0;
mmci_card->mmc_input->id.product = 0;
mmci_card->mmc_input->id.version = 0x0100;
mmci_card->mmc_input->dev.parent = mmcsd_device;
input_set_capability(mmci_card->mmc_input, EV_SW, KEY_INSERT);
/*
* Since this must always be compiled into the kernel, this input
* is never unregistered or free:ed.
*/
ret = input_register_device(mmci_card->mmc_input);
if (ret) {
input_free_device(mmci_card->mmc_input);
goto out;
}
input_set_drvdata(mmci_card->mmc_input, mmci_card);
ret = gpio_register_callback(U300_GPIO_PIN_MMC_CD, mmci_callback,
mmci_card);
schedule_work(&mmci_card->workq);
printk(KERN_INFO "Registered MMC insert/remove notification\n");
out:
return ret;
}

18
arch/arm/mach-u300/mmc.h Normal file
View File

@ -0,0 +1,18 @@
/*
*
* arch/arm/mach-u300/mmc.h
*
*
* Copyright (C) 2009 ST-Ericsson AB
* License terms: GNU General Public License (GPL) version 2
*
* Author: Jonas Aaberg <jonas.aberg@stericsson.com>
*/
#ifndef MMC_H
#define MMC_H
#include <linux/amba/bus.h>
int __devinit mmc_init(struct amba_device *adev);
#endif

422
arch/arm/mach-u300/timer.c Normal file
View File

@ -0,0 +1,422 @@
/*
*
* arch/arm/mach-u300/timer.c
*
*
* Copyright (C) 2007-2009 ST-Ericsson AB
* License terms: GNU General Public License (GPL) version 2
* Timer COH 901 328, runs the OS timer interrupt.
* Author: Linus Walleij <linus.walleij@stericsson.com>
*/
#include <linux/interrupt.h>
#include <linux/time.h>
#include <linux/timex.h>
#include <linux/clockchips.h>
#include <linux/clocksource.h>
#include <linux/types.h>
#include <linux/io.h>
#include <mach/hardware.h>
/* Generic stuff */
#include <asm/mach/map.h>
#include <asm/mach/time.h>
#include <asm/mach/irq.h>
#include "clock.h"
/*
* APP side special timer registers
* This timer contains four timers which can fire an interrupt each.
* OS (operating system) timer @ 32768 Hz
* DD (device driver) timer @ 1 kHz
* GP1 (general purpose 1) timer @ 1MHz
* GP2 (general purpose 2) timer @ 1MHz
*/
/* Reset OS Timer 32bit (-/W) */
#define U300_TIMER_APP_ROST (0x0000)
#define U300_TIMER_APP_ROST_TIMER_RESET (0x00000000)
/* Enable OS Timer 32bit (-/W) */
#define U300_TIMER_APP_EOST (0x0004)
#define U300_TIMER_APP_EOST_TIMER_ENABLE (0x00000000)
/* Disable OS Timer 32bit (-/W) */
#define U300_TIMER_APP_DOST (0x0008)
#define U300_TIMER_APP_DOST_TIMER_DISABLE (0x00000000)
/* OS Timer Mode Register 32bit (-/W) */
#define U300_TIMER_APP_SOSTM (0x000c)
#define U300_TIMER_APP_SOSTM_MODE_CONTINUOUS (0x00000000)
#define U300_TIMER_APP_SOSTM_MODE_ONE_SHOT (0x00000001)
/* OS Timer Status Register 32bit (R/-) */
#define U300_TIMER_APP_OSTS (0x0010)
#define U300_TIMER_APP_OSTS_TIMER_STATE_MASK (0x0000000F)
#define U300_TIMER_APP_OSTS_TIMER_STATE_IDLE (0x00000001)
#define U300_TIMER_APP_OSTS_TIMER_STATE_ACTIVE (0x00000002)
#define U300_TIMER_APP_OSTS_ENABLE_IND (0x00000010)
#define U300_TIMER_APP_OSTS_MODE_MASK (0x00000020)
#define U300_TIMER_APP_OSTS_MODE_CONTINUOUS (0x00000000)
#define U300_TIMER_APP_OSTS_MODE_ONE_SHOT (0x00000020)
#define U300_TIMER_APP_OSTS_IRQ_ENABLED_IND (0x00000040)
#define U300_TIMER_APP_OSTS_IRQ_PENDING_IND (0x00000080)
/* OS Timer Current Count Register 32bit (R/-) */
#define U300_TIMER_APP_OSTCC (0x0014)
/* OS Timer Terminal Count Register 32bit (R/W) */
#define U300_TIMER_APP_OSTTC (0x0018)
/* OS Timer Interrupt Enable Register 32bit (-/W) */
#define U300_TIMER_APP_OSTIE (0x001c)
#define U300_TIMER_APP_OSTIE_IRQ_DISABLE (0x00000000)
#define U300_TIMER_APP_OSTIE_IRQ_ENABLE (0x00000001)
/* OS Timer Interrupt Acknowledge Register 32bit (-/W) */
#define U300_TIMER_APP_OSTIA (0x0020)
#define U300_TIMER_APP_OSTIA_IRQ_ACK (0x00000080)
/* Reset DD Timer 32bit (-/W) */
#define U300_TIMER_APP_RDDT (0x0040)
#define U300_TIMER_APP_RDDT_TIMER_RESET (0x00000000)
/* Enable DD Timer 32bit (-/W) */
#define U300_TIMER_APP_EDDT (0x0044)
#define U300_TIMER_APP_EDDT_TIMER_ENABLE (0x00000000)
/* Disable DD Timer 32bit (-/W) */
#define U300_TIMER_APP_DDDT (0x0048)
#define U300_TIMER_APP_DDDT_TIMER_DISABLE (0x00000000)
/* DD Timer Mode Register 32bit (-/W) */
#define U300_TIMER_APP_SDDTM (0x004c)
#define U300_TIMER_APP_SDDTM_MODE_CONTINUOUS (0x00000000)
#define U300_TIMER_APP_SDDTM_MODE_ONE_SHOT (0x00000001)
/* DD Timer Status Register 32bit (R/-) */
#define U300_TIMER_APP_DDTS (0x0050)
#define U300_TIMER_APP_DDTS_TIMER_STATE_MASK (0x0000000F)
#define U300_TIMER_APP_DDTS_TIMER_STATE_IDLE (0x00000001)
#define U300_TIMER_APP_DDTS_TIMER_STATE_ACTIVE (0x00000002)
#define U300_TIMER_APP_DDTS_ENABLE_IND (0x00000010)
#define U300_TIMER_APP_DDTS_MODE_MASK (0x00000020)
#define U300_TIMER_APP_DDTS_MODE_CONTINUOUS (0x00000000)
#define U300_TIMER_APP_DDTS_MODE_ONE_SHOT (0x00000020)
#define U300_TIMER_APP_DDTS_IRQ_ENABLED_IND (0x00000040)
#define U300_TIMER_APP_DDTS_IRQ_PENDING_IND (0x00000080)
/* DD Timer Current Count Register 32bit (R/-) */
#define U300_TIMER_APP_DDTCC (0x0054)
/* DD Timer Terminal Count Register 32bit (R/W) */
#define U300_TIMER_APP_DDTTC (0x0058)
/* DD Timer Interrupt Enable Register 32bit (-/W) */
#define U300_TIMER_APP_DDTIE (0x005c)
#define U300_TIMER_APP_DDTIE_IRQ_DISABLE (0x00000000)
#define U300_TIMER_APP_DDTIE_IRQ_ENABLE (0x00000001)
/* DD Timer Interrupt Acknowledge Register 32bit (-/W) */
#define U300_TIMER_APP_DDTIA (0x0060)
#define U300_TIMER_APP_DDTIA_IRQ_ACK (0x00000080)
/* Reset GP1 Timer 32bit (-/W) */
#define U300_TIMER_APP_RGPT1 (0x0080)
#define U300_TIMER_APP_RGPT1_TIMER_RESET (0x00000000)
/* Enable GP1 Timer 32bit (-/W) */
#define U300_TIMER_APP_EGPT1 (0x0084)
#define U300_TIMER_APP_EGPT1_TIMER_ENABLE (0x00000000)
/* Disable GP1 Timer 32bit (-/W) */
#define U300_TIMER_APP_DGPT1 (0x0088)
#define U300_TIMER_APP_DGPT1_TIMER_DISABLE (0x00000000)
/* GP1 Timer Mode Register 32bit (-/W) */
#define U300_TIMER_APP_SGPT1M (0x008c)
#define U300_TIMER_APP_SGPT1M_MODE_CONTINUOUS (0x00000000)
#define U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT (0x00000001)
/* GP1 Timer Status Register 32bit (R/-) */
#define U300_TIMER_APP_GPT1S (0x0090)
#define U300_TIMER_APP_GPT1S_TIMER_STATE_MASK (0x0000000F)
#define U300_TIMER_APP_GPT1S_TIMER_STATE_IDLE (0x00000001)
#define U300_TIMER_APP_GPT1S_TIMER_STATE_ACTIVE (0x00000002)
#define U300_TIMER_APP_GPT1S_ENABLE_IND (0x00000010)
#define U300_TIMER_APP_GPT1S_MODE_MASK (0x00000020)
#define U300_TIMER_APP_GPT1S_MODE_CONTINUOUS (0x00000000)
#define U300_TIMER_APP_GPT1S_MODE_ONE_SHOT (0x00000020)
#define U300_TIMER_APP_GPT1S_IRQ_ENABLED_IND (0x00000040)
#define U300_TIMER_APP_GPT1S_IRQ_PENDING_IND (0x00000080)
/* GP1 Timer Current Count Register 32bit (R/-) */
#define U300_TIMER_APP_GPT1CC (0x0094)
/* GP1 Timer Terminal Count Register 32bit (R/W) */
#define U300_TIMER_APP_GPT1TC (0x0098)
/* GP1 Timer Interrupt Enable Register 32bit (-/W) */
#define U300_TIMER_APP_GPT1IE (0x009c)
#define U300_TIMER_APP_GPT1IE_IRQ_DISABLE (0x00000000)
#define U300_TIMER_APP_GPT1IE_IRQ_ENABLE (0x00000001)
/* GP1 Timer Interrupt Acknowledge Register 32bit (-/W) */
#define U300_TIMER_APP_GPT1IA (0x00a0)
#define U300_TIMER_APP_GPT1IA_IRQ_ACK (0x00000080)
/* Reset GP2 Timer 32bit (-/W) */
#define U300_TIMER_APP_RGPT2 (0x00c0)
#define U300_TIMER_APP_RGPT2_TIMER_RESET (0x00000000)
/* Enable GP2 Timer 32bit (-/W) */
#define U300_TIMER_APP_EGPT2 (0x00c4)
#define U300_TIMER_APP_EGPT2_TIMER_ENABLE (0x00000000)
/* Disable GP2 Timer 32bit (-/W) */
#define U300_TIMER_APP_DGPT2 (0x00c8)
#define U300_TIMER_APP_DGPT2_TIMER_DISABLE (0x00000000)
/* GP2 Timer Mode Register 32bit (-/W) */
#define U300_TIMER_APP_SGPT2M (0x00cc)
#define U300_TIMER_APP_SGPT2M_MODE_CONTINUOUS (0x00000000)
#define U300_TIMER_APP_SGPT2M_MODE_ONE_SHOT (0x00000001)
/* GP2 Timer Status Register 32bit (R/-) */
#define U300_TIMER_APP_GPT2S (0x00d0)
#define U300_TIMER_APP_GPT2S_TIMER_STATE_MASK (0x0000000F)
#define U300_TIMER_APP_GPT2S_TIMER_STATE_IDLE (0x00000001)
#define U300_TIMER_APP_GPT2S_TIMER_STATE_ACTIVE (0x00000002)
#define U300_TIMER_APP_GPT2S_ENABLE_IND (0x00000010)
#define U300_TIMER_APP_GPT2S_MODE_MASK (0x00000020)
#define U300_TIMER_APP_GPT2S_MODE_CONTINUOUS (0x00000000)
#define U300_TIMER_APP_GPT2S_MODE_ONE_SHOT (0x00000020)
#define U300_TIMER_APP_GPT2S_IRQ_ENABLED_IND (0x00000040)
#define U300_TIMER_APP_GPT2S_IRQ_PENDING_IND (0x00000080)
/* GP2 Timer Current Count Register 32bit (R/-) */
#define U300_TIMER_APP_GPT2CC (0x00d4)
/* GP2 Timer Terminal Count Register 32bit (R/W) */
#define U300_TIMER_APP_GPT2TC (0x00d8)
/* GP2 Timer Interrupt Enable Register 32bit (-/W) */
#define U300_TIMER_APP_GPT2IE (0x00dc)
#define U300_TIMER_APP_GPT2IE_IRQ_DISABLE (0x00000000)
#define U300_TIMER_APP_GPT2IE_IRQ_ENABLE (0x00000001)
/* GP2 Timer Interrupt Acknowledge Register 32bit (-/W) */
#define U300_TIMER_APP_GPT2IA (0x00e0)
#define U300_TIMER_APP_GPT2IA_IRQ_ACK (0x00000080)
/* Clock request control register - all four timers */
#define U300_TIMER_APP_CRC (0x100)
#define U300_TIMER_APP_CRC_CLOCK_REQUEST_ENABLE (0x00000001)
#define TICKS_PER_JIFFY ((CLOCK_TICK_RATE + (HZ/2)) / HZ)
#define US_PER_TICK ((1000000 + (HZ/2)) / HZ)
/*
* The u300_set_mode() function is always called first, if we
* have oneshot timer active, the oneshot scheduling function
* u300_set_next_event() is called immediately after.
*/
static void u300_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
/* Disable interrupts on GPT1 */
writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE);
/* Disable GP1 while we're reprogramming it. */
writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
U300_TIMER_APP_VBASE + U300_TIMER_APP_DGPT1);
/*
* Set the periodic mode to a certain number of ticks per
* jiffy.
*/
writel(TICKS_PER_JIFFY,
U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1TC);
/*
* Set continuous mode, so the timer keeps triggering
* interrupts.
*/
writel(U300_TIMER_APP_SGPT1M_MODE_CONTINUOUS,
U300_TIMER_APP_VBASE + U300_TIMER_APP_SGPT1M);
/* Enable timer interrupts */
writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE,
U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE);
/* Then enable the OS timer again */
writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE,
U300_TIMER_APP_VBASE + U300_TIMER_APP_EGPT1);
break;
case CLOCK_EVT_MODE_ONESHOT:
/* Just break; here? */
/*
* The actual event will be programmed by the next event hook,
* so we just set a dummy value somewhere at the end of the
* universe here.
*/
/* Disable interrupts on GPT1 */
writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE);
/* Disable GP1 while we're reprogramming it. */
writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
U300_TIMER_APP_VBASE + U300_TIMER_APP_DGPT1);
/*
* Expire far in the future, u300_set_next_event() will be
* called soon...
*/
writel(0xFFFFFFFF, U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1TC);
/* We run one shot per tick here! */
writel(U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT,
U300_TIMER_APP_VBASE + U300_TIMER_APP_SGPT1M);
/* Enable interrupts for this timer */
writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE,
U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE);
/* Enable timer */
writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE,
U300_TIMER_APP_VBASE + U300_TIMER_APP_EGPT1);
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
/* Disable interrupts on GP1 */
writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE);
/* Disable GP1 */
writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
U300_TIMER_APP_VBASE + U300_TIMER_APP_DGPT1);
break;
case CLOCK_EVT_MODE_RESUME:
/* Ignore this call */
break;
}
}
/*
* The app timer in one shot mode obviously has to be reprogrammed
* in EXACTLY this sequence to work properly. Do NOT try to e.g. replace
* the interrupt disable + timer disable commands with a reset command,
* it will fail miserably. Apparently (and I found this the hard way)
* the timer is very sensitive to the instruction order, though you don't
* get that impression from the data sheet.
*/
static int u300_set_next_event(unsigned long cycles,
struct clock_event_device *evt)
{
/* Disable interrupts on GPT1 */
writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE);
/* Disable GP1 while we're reprogramming it. */
writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
U300_TIMER_APP_VBASE + U300_TIMER_APP_DGPT1);
/* Reset the General Purpose timer 1. */
writel(U300_TIMER_APP_RGPT1_TIMER_RESET,
U300_TIMER_APP_VBASE + U300_TIMER_APP_RGPT1);
/* IRQ in n * cycles */
writel(cycles, U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1TC);
/*
* We run one shot per tick here! (This is necessary to reconfigure,
* the timer will tilt if you don't!)
*/
writel(U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT,
U300_TIMER_APP_VBASE + U300_TIMER_APP_SGPT1M);
/* Enable timer interrupts */
writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE,
U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IE);
/* Then enable the OS timer again */
writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE,
U300_TIMER_APP_VBASE + U300_TIMER_APP_EGPT1);
return 0;
}
/* Use general purpose timer 1 as clock event */
static struct clock_event_device clockevent_u300_1mhz = {
.name = "GPT1",
.rating = 300, /* Reasonably fast and accurate clock event */
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
/* 22 calculated using the algorithm in arch/mips/kernel/time.c */
.shift = 22,
.set_next_event = u300_set_next_event,
.set_mode = u300_set_mode,
};
/* Clock event timer interrupt handler */
static irqreturn_t u300_timer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *evt = &clockevent_u300_1mhz;
/* ACK/Clear timer IRQ for the APP GPT1 Timer */
writel(U300_TIMER_APP_GPT1IA_IRQ_ACK,
U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT1IA);
evt->event_handler(evt);
return IRQ_HANDLED;
}
static struct irqaction u300_timer_irq = {
.name = "U300 Timer Tick",
.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = u300_timer_interrupt,
};
/* Use general purpose timer 2 as clock source */
static cycle_t u300_get_cycles(void)
{
return (cycles_t) readl(U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT2CC);
}
static struct clocksource clocksource_u300_1mhz = {
.name = "GPT2",
.rating = 300, /* Reasonably fast and accurate clock source */
.read = u300_get_cycles,
.mask = CLOCKSOURCE_MASK(32), /* 32 bits */
/* 22 calculated using the algorithm in arch/mips/kernel/time.c */
.shift = 22,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
/*
* This sets up the system timers, clock source and clock event.
*/
static void __init u300_timer_init(void)
{
u300_enable_timer_clock();
/*
* Disable the "OS" and "DD" timers - these are designed for Symbian!
* Example usage in cnh1601578 cpu subsystem pd_timer_app.c
*/
writel(U300_TIMER_APP_CRC_CLOCK_REQUEST_ENABLE,
U300_TIMER_APP_VBASE + U300_TIMER_APP_CRC);
writel(U300_TIMER_APP_ROST_TIMER_RESET,
U300_TIMER_APP_VBASE + U300_TIMER_APP_ROST);
writel(U300_TIMER_APP_DOST_TIMER_DISABLE,
U300_TIMER_APP_VBASE + U300_TIMER_APP_DOST);
writel(U300_TIMER_APP_RDDT_TIMER_RESET,
U300_TIMER_APP_VBASE + U300_TIMER_APP_RDDT);
writel(U300_TIMER_APP_DDDT_TIMER_DISABLE,
U300_TIMER_APP_VBASE + U300_TIMER_APP_DDDT);
/* Reset the General Purpose timer 1. */
writel(U300_TIMER_APP_RGPT1_TIMER_RESET,
U300_TIMER_APP_VBASE + U300_TIMER_APP_RGPT1);
/* Set up the IRQ handler */
setup_irq(IRQ_U300_TIMER_APP_GP1, &u300_timer_irq);
/* Reset the General Purpose timer 2 */
writel(U300_TIMER_APP_RGPT2_TIMER_RESET,
U300_TIMER_APP_VBASE + U300_TIMER_APP_RGPT2);
/* Set this timer to run around forever */
writel(0xFFFFFFFFU, U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT2TC);
/* Set continuous mode so it wraps around */
writel(U300_TIMER_APP_SGPT2M_MODE_CONTINUOUS,
U300_TIMER_APP_VBASE + U300_TIMER_APP_SGPT2M);
/* Disable timer interrupts */
writel(U300_TIMER_APP_GPT2IE_IRQ_DISABLE,
U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT2IE);
/* Then enable the GP2 timer to use as a free running us counter */
writel(U300_TIMER_APP_EGPT2_TIMER_ENABLE,
U300_TIMER_APP_VBASE + U300_TIMER_APP_EGPT2);
/* This is a pure microsecond clock source */
clocksource_u300_1mhz.mult =
clocksource_khz2mult(1000, clocksource_u300_1mhz.shift);
if (clocksource_register(&clocksource_u300_1mhz))
printk(KERN_ERR "timer: failed to initialize clock "
"source %s\n", clocksource_u300_1mhz.name);
clockevent_u300_1mhz.mult =
div_sc(1000000, NSEC_PER_SEC, clockevent_u300_1mhz.shift);
/* 32bit counter, so 32bits delta is max */
clockevent_u300_1mhz.max_delta_ns =
clockevent_delta2ns(0xffffffff, &clockevent_u300_1mhz);
/* This timer is slow enough to set for 1 cycle == 1 MHz */
clockevent_u300_1mhz.min_delta_ns =
clockevent_delta2ns(1, &clockevent_u300_1mhz);
clockevent_u300_1mhz.cpumask = cpumask_of(0);
clockevents_register_device(&clockevent_u300_1mhz);
/*
* TODO: init and register the rest of the timers too, they can be
* used by hrtimers!
*/
}
/*
* Very simple system timer that only register the clock event and
* clock source.
*/
struct sys_timer u300_timer = {
.init = u300_timer_init,
};

55
arch/arm/mach-u300/u300.c Normal file
View File

@ -0,0 +1,55 @@
/*
*
* arch/arm/mach-u300/u300.c
*
*
* Copyright (C) 2006-2009 ST-Ericsson AB
* License terms: GNU General Public License (GPL) version 2
* Platform machine definition.
* Author: Linus Walleij <linus.walleij@stericsson.com>
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <mach/hardware.h>
#include <mach/platform.h>
#include <mach/memory.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
static void __init u300_init_machine(void)
{
u300_init_devices();
}
#ifdef CONFIG_MACH_U300_BS2X
#define MACH_U300_STRING "Ericsson AB U300 S25/S26/B25/B26 Prototype Board"
#endif
#ifdef CONFIG_MACH_U300_BS330
#define MACH_U300_STRING "Ericsson AB U330 S330/B330 Prototype Board"
#endif
#ifdef CONFIG_MACH_U300_BS335
#define MACH_U300_STRING "Ericsson AB U335 S335/B335 Prototype Board"
#endif
#ifdef CONFIG_MACH_U300_BS365
#define MACH_U300_STRING "Ericsson AB U365 S365/B365 Prototype Board"
#endif
MACHINE_START(U300, MACH_U300_STRING)
/* Maintainer: Linus Walleij <linus.walleij@stericsson.com> */
.phys_io = U300_AHB_PER_PHYS_BASE,
.io_pg_offst = ((U300_AHB_PER_VIRT_BASE) >> 18) & 0xfffc,
.boot_params = BOOT_PARAMS_OFFSET,
.map_io = u300_map_io,
.init_irq = u300_init_irq,
.timer = &u300_timer,
.init_machine = u300_init_machine,
MACHINE_END