Path: blob/master/arch/arm/mach-integrator/integrator_ap.c
10817 views
/*1* linux/arch/arm/mach-integrator/integrator_ap.c2*3* Copyright (C) 2000-2003 Deep Blue Solutions Ltd4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* (at your option) any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*15* You should have received a copy of the GNU General Public License16* along with this program; if not, write to the Free Software17* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA18*/19#include <linux/types.h>20#include <linux/kernel.h>21#include <linux/init.h>22#include <linux/list.h>23#include <linux/platform_device.h>24#include <linux/slab.h>25#include <linux/string.h>26#include <linux/syscore_ops.h>27#include <linux/amba/bus.h>28#include <linux/amba/kmi.h>29#include <linux/clocksource.h>30#include <linux/clockchips.h>31#include <linux/interrupt.h>32#include <linux/io.h>33#include <linux/mtd/physmap.h>3435#include <mach/hardware.h>36#include <mach/platform.h>37#include <asm/hardware/arm_timer.h>38#include <asm/irq.h>39#include <asm/setup.h>40#include <asm/param.h> /* HZ */41#include <asm/mach-types.h>4243#include <mach/lm.h>4445#include <asm/mach/arch.h>46#include <asm/mach/irq.h>47#include <asm/mach/map.h>48#include <asm/mach/time.h>4950#include <plat/fpga-irq.h>5152#include "common.h"5354/*55* All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx56* is the (PA >> 12).57*58* Setup a VA for the Integrator interrupt controller (for header #0,59* just for now).60*/61#define VA_IC_BASE __io_address(INTEGRATOR_IC_BASE)62#define VA_SC_BASE __io_address(INTEGRATOR_SC_BASE)63#define VA_EBI_BASE __io_address(INTEGRATOR_EBI_BASE)64#define VA_CMIC_BASE __io_address(INTEGRATOR_HDR_IC)6566/*67* Logical Physical68* e8000000 40000000 PCI memory PHYS_PCI_MEM_BASE (max 512M)69* ec000000 61000000 PCI config space PHYS_PCI_CONFIG_BASE (max 16M)70* ed000000 62000000 PCI V3 regs PHYS_PCI_V3_BASE (max 64k)71* ee000000 60000000 PCI IO PHYS_PCI_IO_BASE (max 16M)72* ef000000 Cache flush73* f1000000 10000000 Core module registers74* f1100000 11000000 System controller registers75* f1200000 12000000 EBI registers76* f1300000 13000000 Counter/Timer77* f1400000 14000000 Interrupt controller78* f1600000 16000000 UART 079* f1700000 17000000 UART 180* f1a00000 1a000000 Debug LEDs81* f1b00000 1b000000 GPIO82*/8384static struct map_desc ap_io_desc[] __initdata = {85{86.virtual = IO_ADDRESS(INTEGRATOR_HDR_BASE),87.pfn = __phys_to_pfn(INTEGRATOR_HDR_BASE),88.length = SZ_4K,89.type = MT_DEVICE90}, {91.virtual = IO_ADDRESS(INTEGRATOR_SC_BASE),92.pfn = __phys_to_pfn(INTEGRATOR_SC_BASE),93.length = SZ_4K,94.type = MT_DEVICE95}, {96.virtual = IO_ADDRESS(INTEGRATOR_EBI_BASE),97.pfn = __phys_to_pfn(INTEGRATOR_EBI_BASE),98.length = SZ_4K,99.type = MT_DEVICE100}, {101.virtual = IO_ADDRESS(INTEGRATOR_CT_BASE),102.pfn = __phys_to_pfn(INTEGRATOR_CT_BASE),103.length = SZ_4K,104.type = MT_DEVICE105}, {106.virtual = IO_ADDRESS(INTEGRATOR_IC_BASE),107.pfn = __phys_to_pfn(INTEGRATOR_IC_BASE),108.length = SZ_4K,109.type = MT_DEVICE110}, {111.virtual = IO_ADDRESS(INTEGRATOR_UART0_BASE),112.pfn = __phys_to_pfn(INTEGRATOR_UART0_BASE),113.length = SZ_4K,114.type = MT_DEVICE115}, {116.virtual = IO_ADDRESS(INTEGRATOR_UART1_BASE),117.pfn = __phys_to_pfn(INTEGRATOR_UART1_BASE),118.length = SZ_4K,119.type = MT_DEVICE120}, {121.virtual = IO_ADDRESS(INTEGRATOR_DBG_BASE),122.pfn = __phys_to_pfn(INTEGRATOR_DBG_BASE),123.length = SZ_4K,124.type = MT_DEVICE125}, {126.virtual = IO_ADDRESS(INTEGRATOR_AP_GPIO_BASE),127.pfn = __phys_to_pfn(INTEGRATOR_AP_GPIO_BASE),128.length = SZ_4K,129.type = MT_DEVICE130}, {131.virtual = PCI_MEMORY_VADDR,132.pfn = __phys_to_pfn(PHYS_PCI_MEM_BASE),133.length = SZ_16M,134.type = MT_DEVICE135}, {136.virtual = PCI_CONFIG_VADDR,137.pfn = __phys_to_pfn(PHYS_PCI_CONFIG_BASE),138.length = SZ_16M,139.type = MT_DEVICE140}, {141.virtual = PCI_V3_VADDR,142.pfn = __phys_to_pfn(PHYS_PCI_V3_BASE),143.length = SZ_64K,144.type = MT_DEVICE145}, {146.virtual = PCI_IO_VADDR,147.pfn = __phys_to_pfn(PHYS_PCI_IO_BASE),148.length = SZ_64K,149.type = MT_DEVICE150}151};152153static void __init ap_map_io(void)154{155iotable_init(ap_io_desc, ARRAY_SIZE(ap_io_desc));156}157158#define INTEGRATOR_SC_VALID_INT 0x003fffff159160static struct fpga_irq_data sc_irq_data = {161.base = VA_IC_BASE,162.irq_start = 0,163.chip.name = "SC",164};165166static void __init ap_init_irq(void)167{168/* Disable all interrupts initially. */169/* Do the core module ones */170writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR);171172/* do the header card stuff next */173writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR);174writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR);175176fpga_irq_init(-1, INTEGRATOR_SC_VALID_INT, &sc_irq_data);177}178179#ifdef CONFIG_PM180static unsigned long ic_irq_enable;181182static int irq_suspend(void)183{184ic_irq_enable = readl(VA_IC_BASE + IRQ_ENABLE);185return 0;186}187188static void irq_resume(void)189{190/* disable all irq sources */191writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR);192writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR);193writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR);194195writel(ic_irq_enable, VA_IC_BASE + IRQ_ENABLE_SET);196}197#else198#define irq_suspend NULL199#define irq_resume NULL200#endif201202static struct syscore_ops irq_syscore_ops = {203.suspend = irq_suspend,204.resume = irq_resume,205};206207static int __init irq_syscore_init(void)208{209register_syscore_ops(&irq_syscore_ops);210211return 0;212}213214device_initcall(irq_syscore_init);215216/*217* Flash handling.218*/219#define SC_CTRLC (VA_SC_BASE + INTEGRATOR_SC_CTRLC_OFFSET)220#define SC_CTRLS (VA_SC_BASE + INTEGRATOR_SC_CTRLS_OFFSET)221#define EBI_CSR1 (VA_EBI_BASE + INTEGRATOR_EBI_CSR1_OFFSET)222#define EBI_LOCK (VA_EBI_BASE + INTEGRATOR_EBI_LOCK_OFFSET)223224static int ap_flash_init(struct platform_device *dev)225{226u32 tmp;227228writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC);229230tmp = readl(EBI_CSR1) | INTEGRATOR_EBI_WRITE_ENABLE;231writel(tmp, EBI_CSR1);232233if (!(readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE)) {234writel(0xa05f, EBI_LOCK);235writel(tmp, EBI_CSR1);236writel(0, EBI_LOCK);237}238return 0;239}240241static void ap_flash_exit(struct platform_device *dev)242{243u32 tmp;244245writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC);246247tmp = readl(EBI_CSR1) & ~INTEGRATOR_EBI_WRITE_ENABLE;248writel(tmp, EBI_CSR1);249250if (readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE) {251writel(0xa05f, EBI_LOCK);252writel(tmp, EBI_CSR1);253writel(0, EBI_LOCK);254}255}256257static void ap_flash_set_vpp(struct platform_device *pdev, int on)258{259void __iomem *reg = on ? SC_CTRLS : SC_CTRLC;260261writel(INTEGRATOR_SC_CTRL_nFLVPPEN, reg);262}263264static struct physmap_flash_data ap_flash_data = {265.width = 4,266.init = ap_flash_init,267.exit = ap_flash_exit,268.set_vpp = ap_flash_set_vpp,269};270271static struct resource cfi_flash_resource = {272.start = INTEGRATOR_FLASH_BASE,273.end = INTEGRATOR_FLASH_BASE + INTEGRATOR_FLASH_SIZE - 1,274.flags = IORESOURCE_MEM,275};276277static struct platform_device cfi_flash_device = {278.name = "physmap-flash",279.id = 0,280.dev = {281.platform_data = &ap_flash_data,282},283.num_resources = 1,284.resource = &cfi_flash_resource,285};286287static void __init ap_init(void)288{289unsigned long sc_dec;290int i;291292platform_device_register(&cfi_flash_device);293294sc_dec = readl(VA_SC_BASE + INTEGRATOR_SC_DEC_OFFSET);295for (i = 0; i < 4; i++) {296struct lm_device *lmdev;297298if ((sc_dec & (16 << i)) == 0)299continue;300301lmdev = kzalloc(sizeof(struct lm_device), GFP_KERNEL);302if (!lmdev)303continue;304305lmdev->resource.start = 0xc0000000 + 0x10000000 * i;306lmdev->resource.end = lmdev->resource.start + 0x0fffffff;307lmdev->resource.flags = IORESOURCE_MEM;308lmdev->irq = IRQ_AP_EXPINT0 + i;309lmdev->id = i;310311lm_device_register(lmdev);312}313}314315/*316* Where is the timer (VA)?317*/318#define TIMER0_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER0_BASE)319#define TIMER1_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER1_BASE)320#define TIMER2_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER2_BASE)321322/*323* How long is the timer interval?324*/325#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10)326#if TIMER_INTERVAL >= 0x100000327#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC)328#elif TIMER_INTERVAL >= 0x10000329#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC)330#else331#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC)332#endif333334static unsigned long timer_reload;335336static void integrator_clocksource_init(u32 khz)337{338void __iomem *base = (void __iomem *)TIMER2_VA_BASE;339u32 ctrl = TIMER_CTRL_ENABLE;340341if (khz >= 1500) {342khz /= 16;343ctrl = TIMER_CTRL_DIV16;344}345346writel(ctrl, base + TIMER_CTRL);347writel(0xffff, base + TIMER_LOAD);348349clocksource_mmio_init(base + TIMER_VALUE, "timer2",350khz * 1000, 200, 16, clocksource_mmio_readl_down);351}352353static void __iomem * const clkevt_base = (void __iomem *)TIMER1_VA_BASE;354355/*356* IRQ handler for the timer357*/358static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id)359{360struct clock_event_device *evt = dev_id;361362/* clear the interrupt */363writel(1, clkevt_base + TIMER_INTCLR);364365evt->event_handler(evt);366367return IRQ_HANDLED;368}369370static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)371{372u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;373374BUG_ON(mode == CLOCK_EVT_MODE_ONESHOT);375376if (mode == CLOCK_EVT_MODE_PERIODIC) {377writel(ctrl, clkevt_base + TIMER_CTRL);378writel(timer_reload, clkevt_base + TIMER_LOAD);379ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;380}381382writel(ctrl, clkevt_base + TIMER_CTRL);383}384385static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt)386{387unsigned long ctrl = readl(clkevt_base + TIMER_CTRL);388389writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);390writel(next, clkevt_base + TIMER_LOAD);391writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);392393return 0;394}395396static struct clock_event_device integrator_clockevent = {397.name = "timer1",398.shift = 34,399.features = CLOCK_EVT_FEAT_PERIODIC,400.set_mode = clkevt_set_mode,401.set_next_event = clkevt_set_next_event,402.rating = 300,403.cpumask = cpu_all_mask,404};405406static struct irqaction integrator_timer_irq = {407.name = "timer",408.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,409.handler = integrator_timer_interrupt,410.dev_id = &integrator_clockevent,411};412413static void integrator_clockevent_init(u32 khz)414{415struct clock_event_device *evt = &integrator_clockevent;416unsigned int ctrl = 0;417418if (khz * 1000 > 0x100000 * HZ) {419khz /= 256;420ctrl |= TIMER_CTRL_DIV256;421} else if (khz * 1000 > 0x10000 * HZ) {422khz /= 16;423ctrl |= TIMER_CTRL_DIV16;424}425426timer_reload = khz * 1000 / HZ;427writel(ctrl, clkevt_base + TIMER_CTRL);428429evt->irq = IRQ_TIMERINT1;430evt->mult = div_sc(khz, NSEC_PER_MSEC, evt->shift);431evt->max_delta_ns = clockevent_delta2ns(0xffff, evt);432evt->min_delta_ns = clockevent_delta2ns(0xf, evt);433434setup_irq(IRQ_TIMERINT1, &integrator_timer_irq);435clockevents_register_device(evt);436}437438/*439* Set up timer(s).440*/441static void __init ap_init_timer(void)442{443u32 khz = TICKS_PER_uSEC * 1000;444445writel(0, TIMER0_VA_BASE + TIMER_CTRL);446writel(0, TIMER1_VA_BASE + TIMER_CTRL);447writel(0, TIMER2_VA_BASE + TIMER_CTRL);448449integrator_clocksource_init(khz);450integrator_clockevent_init(khz);451}452453static struct sys_timer ap_timer = {454.init = ap_init_timer,455};456457MACHINE_START(INTEGRATOR, "ARM-Integrator")458/* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */459.boot_params = 0x00000100,460.reserve = integrator_reserve,461.map_io = ap_map_io,462.init_early = integrator_init_early,463.init_irq = ap_init_irq,464.timer = &ap_timer,465.init_machine = ap_init,466MACHINE_END467468469