diff options
Diffstat (limited to 'arch/arm/mach-mmp')
32 files changed, 1194 insertions, 0 deletions
diff --git a/arch/arm/mach-mmp/Kconfig b/arch/arm/mach-mmp/Kconfig new file mode 100644 index 00000000000..b5232676355 --- /dev/null +++ b/arch/arm/mach-mmp/Kconfig @@ -0,0 +1,27 @@ +if ARCH_MMP + +menu "Marvell PXA168 Implmentations" + +config MACH_ASPENITE + bool "Marvell's PXA168 Aspenite Development Board" + select CPU_PXA168 + help + Say 'Y' here if you want to support the Marvell PXA168-based + Aspenite Development Board. + +config MACH_ZYLONITE2 + bool "Marvell's PXA168 Zylonite2 Development Board" + select CPU_PXA168 + help + Say 'Y' here if you want to support the Marvell PXA168-based + Zylonite2 Development Board. + +endmenu + +config CPU_PXA168 + bool + select CPU_MOHAWK + help + Select code specific to PXA168 + +endif diff --git a/arch/arm/mach-mmp/Makefile b/arch/arm/mach-mmp/Makefile new file mode 100644 index 00000000000..0ac7644ec99 --- /dev/null +++ b/arch/arm/mach-mmp/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for Marvell's PXA168 processors line +# + +obj-y += common.o clock.o devices.o irq.o time.o + +# SoC support +obj-$(CONFIG_CPU_PXA168) += pxa168.o + +# board support +obj-$(CONFIG_MACH_ASPENITE) += aspenite.o +obj-$(CONFIG_MACH_ZYLONITE2) += aspenite.o diff --git a/arch/arm/mach-mmp/Makefile.boot b/arch/arm/mach-mmp/Makefile.boot new file mode 100644 index 00000000000..574a4aa8321 --- /dev/null +++ b/arch/arm/mach-mmp/Makefile.boot @@ -0,0 +1 @@ + zreladdr-y := 0x00008000 diff --git a/arch/arm/mach-mmp/aspenite.c b/arch/arm/mach-mmp/aspenite.c new file mode 100644 index 00000000000..e8caf58e004 --- /dev/null +++ b/arch/arm/mach-mmp/aspenite.c @@ -0,0 +1,42 @@ +/* + * linux/arch/arm/mach-mmp/aspenite.c + * + * Support for the Marvell PXA168-based Aspenite and Zylonite2 + * Development 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 + * publishhed by the Free Software Foundation. + */ + +#include <linux/init.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <mach/addr-map.h> + +#include "common.h" + +static void __init common_init(void) +{ +} + +MACHINE_START(ASPENITE, "PXA168-based Aspenite Development Platform") + .phys_io = APB_PHYS_BASE, + .boot_params = 0x00000100, + .io_pg_offst = (APB_VIRT_BASE >> 18) & 0xfffc, + .map_io = pxa_map_io, + .init_irq = pxa168_init_irq, + .timer = &pxa168_timer, + .init_machine = common_init, +MACHINE_END + +MACHINE_START(ZYLONITE2, "PXA168-based Zylonite2 Development Platform") + .phys_io = APB_PHYS_BASE, + .boot_params = 0x00000100, + .io_pg_offst = (APB_VIRT_BASE >> 18) & 0xfffc, + .map_io = pxa_map_io, + .init_irq = pxa168_init_irq, + .timer = &pxa168_timer, + .init_machine = common_init, +MACHINE_END diff --git a/arch/arm/mach-mmp/clock.c b/arch/arm/mach-mmp/clock.c new file mode 100644 index 00000000000..2d9cc5a7122 --- /dev/null +++ b/arch/arm/mach-mmp/clock.c @@ -0,0 +1,83 @@ +/* + * linux/arch/arm/mach-mmp/clock.c + * + * 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/module.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/spinlock.h> +#include <linux/clk.h> +#include <linux/io.h> + +#include <mach/regs-apbc.h> +#include "clock.h" + +static void apbc_clk_enable(struct clk *clk) +{ + uint32_t clk_rst; + + clk_rst = APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(clk->fnclksel); + __raw_writel(clk_rst, clk->clk_rst); +} + +static void apbc_clk_disable(struct clk *clk) +{ + __raw_writel(0, clk->clk_rst); +} + +struct clkops apbc_clk_ops = { + .enable = apbc_clk_enable, + .disable = apbc_clk_disable, +}; + +static DEFINE_SPINLOCK(clocks_lock); + +int clk_enable(struct clk *clk) +{ + unsigned long flags; + + spin_lock_irqsave(&clocks_lock, flags); + if (clk->enabled++ == 0) + clk->ops->enable(clk); + spin_unlock_irqrestore(&clocks_lock, flags); + return 0; +} +EXPORT_SYMBOL(clk_enable); + +void clk_disable(struct clk *clk) +{ + unsigned long flags; + + WARN_ON(clk->enabled == 0); + + spin_lock_irqsave(&clocks_lock, flags); + if (--clk->enabled == 0) + clk->ops->disable(clk); + spin_unlock_irqrestore(&clocks_lock, flags); +} +EXPORT_SYMBOL(clk_disable); + +unsigned long clk_get_rate(struct clk *clk) +{ + unsigned long rate; + + if (clk->ops->getrate) + rate = clk->ops->getrate(clk); + else + rate = clk->rate; + + return rate; +} +EXPORT_SYMBOL(clk_get_rate); + +void clks_register(struct clk_lookup *clks, size_t num) +{ + int i; + + for (i = 0; i < num; i++) + clkdev_add(&clks[i]); +} diff --git a/arch/arm/mach-mmp/clock.h b/arch/arm/mach-mmp/clock.h new file mode 100644 index 00000000000..ed967e78e6a --- /dev/null +++ b/arch/arm/mach-mmp/clock.h @@ -0,0 +1,71 @@ +/* + * linux/arch/arm/mach-mmp/clock.h + * + * 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 <asm/clkdev.h> + +struct clkops { + void (*enable)(struct clk *); + void (*disable)(struct clk *); + unsigned long (*getrate)(struct clk *); +}; + +struct clk { + const struct clkops *ops; + + void __iomem *clk_rst; /* clock reset control register */ + int fnclksel; /* functional clock select (APBC) */ + uint32_t enable_val; /* value for clock enable (APMU) */ + unsigned long rate; + int enabled; +}; + +extern struct clkops apbc_clk_ops; + +#define APBC_CLK(_name, _reg, _fnclksel, _rate) \ +struct clk clk_##_name = { \ + .clk_rst = (void __iomem *)APBC_##_reg, \ + .fnclksel = _fnclksel, \ + .rate = _rate, \ + .ops = &apbc_clk_ops, \ +} + +#define APBC_CLK_OPS(_name, _reg, _fnclksel, _rate, _ops) \ +struct clk clk_##_name = { \ + .clk_rst = (void __iomem *)APBC_##_reg, \ + .fnclksel = _fnclksel, \ + .rate = _rate, \ + .ops = _ops, \ +} + +#define APMU_CLK(_name, _reg, _eval, _rate) \ +struct clk clk_##_name = { \ + .clk_rst = (void __iomem *)APMU_##_reg, \ + .enable_val = _eval, \ + .rate = _rate, \ + .ops = &apmu_clk_ops, \ +} + +#define APMU_CLK_OPS(_name, _reg, _eval, _rate, _ops) \ +struct clk clk_##_name = { \ + .clk_rst = (void __iomem *)APMU_##_reg, \ + .enable_val = _eval, \ + .rate = _rate, \ + .ops = _ops, \ +} + +#define INIT_CLKREG(_clk, _devname, _conname) \ + { \ + .clk = _clk, \ + .dev_id = _devname, \ + .con_id = _conname, \ + } + +extern struct clk clk_pxa168_gpio; +extern struct clk clk_pxa168_timers; + +extern void clks_register(struct clk_lookup *, size_t); diff --git a/arch/arm/mach-mmp/common.c b/arch/arm/mach-mmp/common.c new file mode 100644 index 00000000000..e1e66c18b44 --- /dev/null +++ b/arch/arm/mach-mmp/common.c @@ -0,0 +1,37 @@ +/* + * linux/arch/arm/mach-mmp/common.c + * + * Code common to PXA168 processor lines + * + * 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/kernel.h> + +#include <asm/page.h> +#include <asm/mach/map.h> +#include <mach/addr-map.h> + +#include "common.h" + +static struct map_desc standard_io_desc[] __initdata = { + { + .pfn = __phys_to_pfn(APB_PHYS_BASE), + .virtual = APB_VIRT_BASE, + .length = APB_PHYS_SIZE, + .type = MT_DEVICE, + }, { + .pfn = __phys_to_pfn(AXI_PHYS_BASE), + .virtual = AXI_VIRT_BASE, + .length = AXI_PHYS_SIZE, + .type = MT_DEVICE, + }, +}; + +void __init pxa_map_io(void) +{ + iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc)); +} diff --git a/arch/arm/mach-mmp/common.h b/arch/arm/mach-mmp/common.h new file mode 100644 index 00000000000..bf7a6a492de --- /dev/null +++ b/arch/arm/mach-mmp/common.h @@ -0,0 +1,11 @@ +#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x) + +struct sys_timer; + +extern void timer_init(int irq); + +extern struct sys_timer pxa168_timer; +extern void __init pxa168_init_irq(void); + +extern void __init icu_init_irq(void); +extern void __init pxa_map_io(void); diff --git a/arch/arm/mach-mmp/devices.c b/arch/arm/mach-mmp/devices.c new file mode 100644 index 00000000000..191d9dea873 --- /dev/null +++ b/arch/arm/mach-mmp/devices.c @@ -0,0 +1,69 @@ +/* + * linux/arch/arm/mach-mmp/devices.c + * + * 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/platform_device.h> +#include <linux/dma-mapping.h> + +#include <asm/irq.h> +#include <mach/devices.h> + +int __init pxa_register_device(struct pxa_device_desc *desc, + void *data, size_t size) +{ + struct platform_device *pdev; + struct resource res[2 + MAX_RESOURCE_DMA]; + int i, ret = 0, nres = 0; + + pdev = platform_device_alloc(desc->drv_name, desc->id); + if (pdev == NULL) + return -ENOMEM; + + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + + memset(res, 0, sizeof(res)); + + if (desc->start != -1ul && desc->size > 0) { + res[nres].start = desc->start; + res[nres].end = desc->start + desc->size - 1; + res[nres].flags = IORESOURCE_MEM; + nres++; + } + + if (desc->irq != NO_IRQ) { + res[nres].start = desc->irq; + res[nres].end = desc->irq; + res[nres].flags = IORESOURCE_IRQ; + nres++; + } + + for (i = 0; i < MAX_RESOURCE_DMA; i++, nres++) { + if (desc->dma[i] == 0) + break; + + res[nres].start = desc->dma[i]; + res[nres].end = desc->dma[i]; + res[nres].flags = IORESOURCE_DMA; + } + + ret = platform_device_add_resources(pdev, res, nres); + if (ret) { + platform_device_put(pdev); + return ret; + } + + if (data && size) { + ret = platform_device_add_data(pdev, data, size); + if (ret) { + platform_device_put(pdev); + return ret; + } + } + + return platform_device_add(pdev); +} diff --git a/arch/arm/mach-mmp/include/mach/addr-map.h b/arch/arm/mach-mmp/include/mach/addr-map.h new file mode 100644 index 00000000000..3254089a644 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/addr-map.h @@ -0,0 +1,34 @@ +/* + * linux/arch/arm/mach-mmp/include/mach/addr-map.h + * + * Common address map definitions + * + * 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. + */ + +#ifndef __ASM_MACH_ADDR_MAP_H +#define __ASM_MACH_ADDR_MAP_H + +/* APB - Application Subsystem Peripheral Bus + * + * NOTE: the DMA controller registers are actually on the AXI fabric #1 + * slave port to AHB/APB bridge, due to its close relationship to those + * peripherals on APB, let's count it into the ABP mapping area. + */ +#define APB_PHYS_BASE 0xd4000000 +#define APB_VIRT_BASE 0xfe000000 +#define APB_PHYS_SIZE 0x00200000 + +#define AXI_PHYS_BASE 0xd4200000 +#define AXI_VIRT_BASE 0xfe200000 +#define AXI_PHYS_SIZE 0x00200000 + +/* Static Memory Controller - Chip Select 0 and 1 */ +#define SMC_CS0_PHYS_BASE 0x80000000 +#define SMC_CS0_PHYS_SIZE 0x10000000 +#define SMC_CS1_PHYS_BASE 0x90000000 +#define SMC_CS1_PHYS_SIZE 0x10000000 + +#endif /* __ASM_MACH_ADDR_MAP_H */ diff --git a/arch/arm/mach-mmp/include/mach/clkdev.h b/arch/arm/mach-mmp/include/mach/clkdev.h new file mode 100644 index 00000000000..2fb354e54e0 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/clkdev.h @@ -0,0 +1,7 @@ +#ifndef __ASM_MACH_CLKDEV_H +#define __ASM_MACH_CLKDEV_H + +#define __clk_get(clk) ({ 1; }) +#define __clk_put(clk) do { } while (0) + +#endif /* __ASM_MACH_CLKDEV_H */ diff --git a/arch/arm/mach-mmp/include/mach/cputype.h b/arch/arm/mach-mmp/include/mach/cputype.h new file mode 100644 index 00000000000..4ceed7a5075 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/cputype.h @@ -0,0 +1,21 @@ +#ifndef __ASM_MACH_CPUTYPE_H +#define __ASM_MACH_CPUTYPE_H + +#include <asm/cputype.h> + +/* + * CPU Stepping OLD_ID CPU_ID CHIP_ID + * + * PXA168 A0 0x41159263 0x56158400 0x00A0A333 + */ + +#ifdef CONFIG_CPU_PXA168 +# define __cpu_is_pxa168(id) \ + ({ unsigned int _id = ((id) >> 8) & 0xff; _id == 0x84; }) +#else +# define __cpu_is_pxa168(id) (0) +#endif + +#define cpu_is_pxa168() ({ __cpu_is_pxa168(read_cpuid_id()); }) + +#endif /* __ASM_MACH_CPUTYPE_H */ diff --git a/arch/arm/mach-mmp/include/mach/debug-macro.S b/arch/arm/mach-mmp/include/mach/debug-macro.S new file mode 100644 index 00000000000..a850f87de51 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/debug-macro.S @@ -0,0 +1,23 @@ +/* arch/arm/mach-mmp/include/mach/debug-macro.S + * + * Debugging macro include header + * + * Copied from arch/arm/mach-pxa/include/mach/debug.S + * + * 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 <mach/addr-map.h> + + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + ldreq \rx, =APB_PHYS_BASE @ physical + ldrne \rx, =APB_VIRT_BASE @ virtual + orr \rx, \rx, #0x00017000 + .endm + +#define UART_SHIFT 2 +#include <asm/hardware/debug-8250.S> diff --git a/arch/arm/mach-mmp/include/mach/devices.h b/arch/arm/mach-mmp/include/mach/devices.h new file mode 100644 index 00000000000..bc03388d5fd --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/devices.h @@ -0,0 +1,27 @@ +#include <linux/types.h> + +#define MAX_RESOURCE_DMA 2 + +/* structure for describing the on-chip devices */ +struct pxa_device_desc { + const char *dev_name; + const char *drv_name; + int id; + int irq; + unsigned long start; + unsigned long size; + int dma[MAX_RESOURCE_DMA]; +}; + +#define PXA168_DEVICE(_name, _drv, _id, _irq, _start, _size, _dma...) \ +struct pxa_device_desc pxa168_device_##_name __initdata = { \ + .dev_name = "pxa168-" #_name, \ + .drv_name = _drv, \ + .id = _id, \ + .irq = IRQ_PXA168_##_irq, \ + .start = _start, \ + .size = _size, \ + .dma = { _dma }, \ +}; + +extern int pxa_register_device(struct pxa_device_desc *, void *, size_t); diff --git a/arch/arm/mach-mmp/include/mach/dma.h b/arch/arm/mach-mmp/include/mach/dma.h new file mode 100644 index 00000000000..1d6914544da --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/dma.h @@ -0,0 +1,13 @@ +/* + * linux/arch/arm/mach-mmp/include/mach/dma.h + */ + +#ifndef __ASM_MACH_DMA_H +#define __ASM_MACH_DMA_H + +#include <mach/addr-map.h> + +#define DMAC_REGS_VIRT (APB_VIRT_BASE + 0x00000) + +#include <plat/dma.h> +#endif /* __ASM_MACH_DMA_H */ diff --git a/arch/arm/mach-mmp/include/mach/entry-macro.S b/arch/arm/mach-mmp/include/mach/entry-macro.S new file mode 100644 index 00000000000..6d3cd35478b --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/entry-macro.S @@ -0,0 +1,25 @@ +/* + * linux/arch/arm/mach-mmp/include/mach/entry-macro.S + * + * 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 <mach/regs-icu.h> + + .macro disable_fiq + .endm + + .macro arch_ret_to_user, tmp1, tmp2 + .endm + + .macro get_irqnr_preamble, base, tmp + ldr \base, =ICU_AP_IRQ_SEL_INT_NUM + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + ldr \tmp, [\base, #0] + and \irqnr, \tmp, #0x3f + tst \tmp, #(1 << 6) + .endm diff --git a/arch/arm/mach-mmp/include/mach/hardware.h b/arch/arm/mach-mmp/include/mach/hardware.h new file mode 100644 index 00000000000..99264a5ce5e --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/hardware.h @@ -0,0 +1,4 @@ +#ifndef __ASM_MACH_HARDWARE_H +#define __ASM_MACH_HARDWARE_H + +#endif /* __ASM_MACH_HARDWARE_H */ diff --git a/arch/arm/mach-mmp/include/mach/io.h b/arch/arm/mach-mmp/include/mach/io.h new file mode 100644 index 00000000000..e7adf3d012c --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/io.h @@ -0,0 +1,21 @@ +/* + * linux/arch/arm/mach-mmp/include/mach/io.h + * + * 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. + */ + +#ifndef __ASM_MACH_IO_H +#define __ASM_MACH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +/* + * We don't actually have real ISA nor PCI buses, but there is so many + * drivers out there that might just work if we fake them... + */ +#define __io(a) __typesafe_io(a) +#define __mem_pci(a) (a) + +#endif /* __ASM_MACH_IO_H */ diff --git a/arch/arm/mach-mmp/include/mach/irqs.h b/arch/arm/mach-mmp/include/mach/irqs.h new file mode 100644 index 00000000000..91ecb3fbca0 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/irqs.h @@ -0,0 +1,58 @@ +#ifndef __ASM_MACH_IRQS_H +#define __ASM_MACH_IRQS_H + +/* + * Interrupt numbers for PXA168 + */ +#define IRQ_PXA168_NONE (-1) +#define IRQ_PXA168_SSP3 0 +#define IRQ_PXA168_SSP2 1 +#define IRQ_PXA168_SSP1 2 +#define IRQ_PXA168_SSP0 3 +#define IRQ_PXA168_PMIC_INT 4 +#define IRQ_PXA168_RTC_INT 5 +#define IRQ_PXA168_RTC_ALARM 6 +#define IRQ_PXA168_TWSI0 7 +#define IRQ_PXA168_GPU 8 +#define IRQ_PXA168_KEYPAD 9 +#define IRQ_PXA168_ONEWIRE 12 +#define IRQ_PXA168_TIMER1 13 +#define IRQ_PXA168_TIMER2 14 +#define IRQ_PXA168_TIMER3 15 +#define IRQ_PXA168_CMU 16 +#define IRQ_PXA168_SSP4 17 +#define IRQ_PXA168_MSP_WAKEUP 19 +#define IRQ_PXA168_CF_WAKEUP 20 +#define IRQ_PXA168_XD_WAKEUP 21 +#define IRQ_PXA168_MFU 22 +#define IRQ_PXA168_MSP 23 +#define IRQ_PXA168_CF 24 +#define IRQ_PXA168_XD 25 +#define IRQ_PXA168_DDR_INT 26 +#define IRQ_PXA168_UART1 27 +#define IRQ_PXA168_UART2 28 +#define IRQ_PXA168_WDT 35 +#define IRQ_PXA168_FRQ_CHANGE 38 +#define IRQ_PXA168_SDH1 39 +#define IRQ_PXA168_SDH2 40 +#define IRQ_PXA168_LCD 41 +#define IRQ_PXA168_CI 42 +#define IRQ_PXA168_USB1 44 +#define IRQ_PXA168_NAND 45 +#define IRQ_PXA168_HIFI_DMA 46 +#define IRQ_PXA168_DMA_INT0 47 +#define IRQ_PXA168_DMA_INT1 48 +#define IRQ_PXA168_GPIOX 49 +#define IRQ_PXA168_USB2 51 +#define IRQ_PXA168_AC97 57 +#define IRQ_PXA168_TWSI1 58 +#define IRQ_PXA168_PMU 60 +#define IRQ_PXA168_SM_INT 63 + +#define IRQ_GPIO_START 64 +#define IRQ_GPIO_NUM 128 +#define IRQ_GPIO(x) (IRQ_GPIO_START + (x)) + +#define NR_IRQS (IRQ_GPIO_START + IRQ_GPIO_NUM) + +#endif /* __ASM_MACH_IRQS_H */ diff --git a/arch/arm/mach-mmp/include/mach/memory.h b/arch/arm/mach-mmp/include/mach/memory.h new file mode 100644 index 00000000000..bdb21d70714 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/memory.h @@ -0,0 +1,14 @@ +/* + * linux/arch/arm/mach-mmp/include/mach/memory.h + * + * 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. + */ + +#ifndef __ASM_MACH_MEMORY_H +#define __ASM_MACH_MEMORY_H + +#define PHYS_OFFSET UL(0x00000000) + +#endif /* __ASM_MACH_MEMORY_H */ diff --git a/arch/arm/mach-mmp/include/mach/pxa168.h b/arch/arm/mach-mmp/include/mach/pxa168.h new file mode 100644 index 00000000000..ef0a8a2076e --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/pxa168.h @@ -0,0 +1,23 @@ +#ifndef __ASM_MACH_PXA168_H +#define __ASM_MACH_PXA168_H + +#include <mach/devices.h> + +extern struct pxa_device_desc pxa168_device_uart1; +extern struct pxa_device_desc pxa168_device_uart2; + +static inline int pxa168_add_uart(int id) +{ + struct pxa_device_desc *d = NULL; + + switch (id) { + case 1: d = &pxa168_device_uart1; break; + case 2: d = &pxa168_device_uart2; break; + } + + if (d == NULL) + return -EINVAL; + + return pxa_register_device(d, NULL, 0); +} +#endif /* __ASM_MACH_PXA168_H */ diff --git a/arch/arm/mach-mmp/include/mach/regs-apbc.h b/arch/arm/mach-mmp/include/mach/regs-apbc.h new file mode 100644 index 00000000000..e0ffae59487 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/regs-apbc.h @@ -0,0 +1,53 @@ +/* + * linux/arch/arm/mach-mmp/include/mach/regs-apbc.h + * + * Application Peripheral Bus Clock Unit + * + * 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. + */ + +#ifndef __ASM_MACH_REGS_APBC_H +#define __ASM_MACH_REGS_APBC_H + +#include <mach/addr-map.h> + +#define APBC_VIRT_BASE (APB_VIRT_BASE + 0x015000) +#define APBC_REG(x) (APBC_VIRT_BASE + (x)) + +/* + * APB clock register offsets for PXA168 + */ +#define APBC_PXA168_UART1 APBC_REG(0x000) +#define APBC_PXA168_UART2 APBC_REG(0x004) +#define APBC_PXA168_GPIO APBC_REG(0x008) +#define APBC_PXA168_PWM0 APBC_REG(0x00c) +#define APBC_PXA168_PWM1 APBC_REG(0x010) +#define APBC_PXA168_SSP1 APBC_REG(0x01c) +#define APBC_PXA168_SSP2 APBC_REG(0x020) +#define APBC_PXA168_RTC APBC_REG(0x028) +#define APBC_PXA168_TWSI0 APBC_REG(0x02c) +#define APBC_PXA168_KPC APBC_REG(0x030) +#define APBC_PXA168_TIMERS APBC_REG(0x034) +#define APBC_PXA168_AIB APBC_REG(0x03c) +#define APBC_PXA168_SW_JTAG APBC_REG(0x040) +#define APBC_PXA168_ONEWIRE APBC_REG(0x048) +#define APBC_PXA168_SSP3 APBC_REG(0x04c) +#define APBC_PXA168_ASFAR APBC_REG(0x050) +#define APBC_PXA168_ASSAR APBC_REG(0x054) +#define APBC_PXA168_SSP4 APBC_REG(0x058) +#define APBC_PXA168_SSP5 APBC_REG(0x05c) +#define APBC_PXA168_TWSI1 APBC_REG(0x06c) +#define APBC_PXA168_UART3 APBC_REG(0x070) +#define APBC_PXA168_AC97 APBC_REG(0x084) + +/* Common APB clock register bit definitions */ +#define APBC_APBCLK (1 << 0) /* APB Bus Clock Enable */ +#define APBC_FNCLK (1 << 1) /* Functional Clock Enable */ +#define APBC_RST (1 << 2) /* Reset Generation */ + +/* Functional Clock Selection Mask */ +#define APBC_FNCLKSEL(x) (((x) & 0xf) << 4) + +#endif /* __ASM_MACH_REGS_APBC_H */ diff --git a/arch/arm/mach-mmp/include/mach/regs-apmu.h b/arch/arm/mach-mmp/include/mach/regs-apmu.h new file mode 100644 index 00000000000..91903051412 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/regs-apmu.h @@ -0,0 +1,36 @@ +/* + * linux/arch/arm/mach-mmp/include/mach/regs-apmu.h + * + * Application Subsystem Power Management Unit + * + * 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. + */ + +#ifndef __ASM_MACH_REGS_APMU_H +#define __ASM_MACH_REGS_APMU_H + +#include <mach/addr-map.h> + +#define APMU_VIRT_BASE (AXI_VIRT_BASE + 0x82800) +#define APMU_REG(x) (APMU_VIRT_BASE + (x)) + +/* Clock Reset Control */ +#define APMU_IRE APMU_REG(0x048) +#define APMU_LCD APMU_REG(0x04c) +#define APMU_CCIC APMU_REG(0x050) +#define APMU_SDH0 APMU_REG(0x054) +#define APMU_SDH1 APMU_REG(0x058) +#define APMU_USB APMU_REG(0x05c) +#define APMU_NAND APMU_REG(0x060) +#define APMU_DMA APMU_REG(0x064) +#define APMU_GEU APMU_REG(0x068) +#define APMU_BUS APMU_REG(0x06c) + +#define APMU_FNCLK_EN (1 << 4) +#define APMU_AXICLK_EN (1 << 3) +#define APMU_FNRST_DIS (1 << 1) +#define APMU_AXIRST_DIS (1 << 0) + +#endif /* __ASM_MACH_REGS_APMU_H */ diff --git a/arch/arm/mach-mmp/include/mach/regs-icu.h b/arch/arm/mach-mmp/include/mach/regs-icu.h new file mode 100644 index 00000000000..e5f08723e0c --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/regs-icu.h @@ -0,0 +1,31 @@ +/* + * linux/arch/arm/mach-mmp/include/mach/regs-icu.h + * + * Interrupt Control Unit + * + * 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. + */ + +#ifndef __ASM_MACH_ICU_H +#define __ASM_MACH_ICU_H + +#include <mach/addr-map.h> + +#define ICU_VIRT_BASE (AXI_VIRT_BASE + 0x82000) +#define ICU_REG(x) (ICU_VIRT_BASE + (x)) + +#define ICU_INT_CONF(n) ICU_REG((n) << 2) +#define ICU_INT_CONF_AP_INT (1 << 6) +#define ICU_INT_CONF_CP_INT (1 << 5) +#define ICU_INT_CONF_IRQ (1 << 4) +#define ICU_INT_CONF_MASK (0xf) + +#define ICU_AP_FIQ_SEL_INT_NUM ICU_REG(0x108) /* AP FIQ Selected Interrupt */ +#define ICU_AP_IRQ_SEL_INT_NUM ICU_REG(0x10C) /* AP IRQ Selected Interrupt */ +#define ICU_AP_GBL_IRQ_MSK ICU_REG(0x114) /* AP Global Interrupt Mask */ +#define ICU_INT_STATUS_0 ICU_REG(0x128) /* Interrupt Stuats 0 */ +#define ICU_INT_STATUS_1 ICU_REG(0x12C) /* Interrupt Status 1 */ + +#endif /* __ASM_MACH_ICU_H */ diff --git a/arch/arm/mach-mmp/include/mach/regs-timers.h b/arch/arm/mach-mmp/include/mach/regs-timers.h new file mode 100644 index 00000000000..45589fec9fc --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/regs-timers.h @@ -0,0 +1,44 @@ +/* + * linux/arch/arm/mach-mmp/include/mach/regs-timers.h + * + * Timers Module + * + * 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. + */ + +#ifndef __ASM_MACH_REGS_TIMERS_H +#define __ASM_MACH_REGS_TIMERS_H + +#include <mach/addr-map.h> + +#define TIMERS1_VIRT_BASE (APB_VIRT_BASE + 0x14000) +#define TIMERS2_VIRT_BASE (APB_VIRT_BASE + 0x16000) + +#define TMR_CCR (0x0000) +#define TMR_TN_MM(n, m) (0x0004 + ((n) << 3) + (((n) + (m)) << 2)) +#define TMR_CR(n) (0x0028 + ((n) << 2)) +#define TMR_SR(n) (0x0034 + ((n) << 2)) +#define TMR_IER(n) (0x0040 + ((n) << 2)) +#define TMR_PLVR(n) (0x004c + ((n) << 2)) +#define TMR_PLCR(n) (0x0058 + ((n) << 2)) +#define TMR_WMER (0x0064) +#define TMR_WMR (0x0068) +#define TMR_WVR (0x006c) +#define TMR_WSR (0x0070) +#define TMR_ICR(n) (0x0074 + ((n) << 2)) +#define TMR_WICR (0x0080) +#define TMR_CER (0x0084) +#define TMR_CMR (0x0088) +#define TMR_ILR(n) (0x008c + ((n) << 2)) +#define TMR_WCR (0x0098) +#define TMR_WFAR (0x009c) +#define TMR_WSAR (0x00A0) +#define TMR_CVWR(n) (0x00A4 + ((n) << 2)) + +#define TMR_CCR_CS_0(x) (((x) & 0x3) << 0) +#define TMR_CCR_CS_1(x) (((x) & 0x7) << 2) +#define TMR_CCR_CS_2(x) (((x) & 0x3) << 5) + +#endif /* __ASM_MACH_REGS_TIMERS_H */ diff --git a/arch/arm/mach-mmp/include/mach/system.h b/arch/arm/mach-mmp/include/mach/system.h new file mode 100644 index 00000000000..001edfefec1 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/system.h @@ -0,0 +1,21 @@ +/* + * linux/arch/arm/mach-mmp/include/mach/system.h + * + * 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. + */ + +#ifndef __ASM_MACH_SYSTEM_H +#define __ASM_MACH_SYSTEM_H + +static inline void arch_idle(void) +{ + cpu_do_idle(); +} + +static inline void arch_reset(char mode) +{ + cpu_reset(0); +} +#endif /* __ASM_MACH_SYSTEM_H */ diff --git a/arch/arm/mach-mmp/include/mach/timex.h b/arch/arm/mach-mmp/include/mach/timex.h new file mode 100644 index 00000000000..6cebbd0ca8f --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/timex.h @@ -0,0 +1,9 @@ +/* + * linux/arch/arm/mach-mmp/include/mach/timex.h + * + * 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. + */ + +#define CLOCK_TICK_RATE 3250000 diff --git a/arch/arm/mach-mmp/include/mach/uncompress.h b/arch/arm/mach-mmp/include/mach/uncompress.h new file mode 100644 index 00000000000..c93d5fa5865 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/uncompress.h @@ -0,0 +1,41 @@ +/* + * arch/arm/mach-mmp/include/mach/uncompress.h + * + * 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/serial_reg.h> +#include <mach/addr-map.h> + +#define UART1_BASE (APB_PHYS_BASE + 0x36000) +#define UART2_BASE (APB_PHYS_BASE + 0x17000) +#define UART3_BASE (APB_PHYS_BASE + 0x18000) + +static inline void putc(char c) +{ + volatile unsigned long *UART = (unsigned long *)UART2_BASE; + + /* UART enabled? */ + if (!(UART[UART_IER] & UART_IER_UUE)) + return; + + while (!(UART[UART_LSR] & UART_LSR_THRE)) + barrier(); + + UART[UART_TX] = c; +} + +/* + * This does not append a newline + */ +static inline void flush(void) +{ +} + +/* + * nothing to do + */ +#define arch_decomp_setup() +#define arch_decomp_wdog() diff --git a/arch/arm/mach-mmp/include/mach/vmalloc.h b/arch/arm/mach-mmp/include/mach/vmalloc.h new file mode 100644 index 00000000000..b60ccaf9fee --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/vmalloc.h @@ -0,0 +1,5 @@ +/* + * linux/arch/arm/mach-mmp/include/mach/vmalloc.h + */ + +#define VMALLOC_END 0xfe000000 diff --git a/arch/arm/mach-mmp/irq.c b/arch/arm/mach-mmp/irq.c new file mode 100644 index 00000000000..52ff2f065eb --- /dev/null +++ b/arch/arm/mach-mmp/irq.c @@ -0,0 +1,55 @@ +/* + * linux/arch/arm/mach-mmp/irq.c + * + * Generic IRQ handling, GPIO IRQ demultiplexing, etc. + * + * Author: Bin Yang <bin.yang@marvell.com> + * Created: Sep 30, 2008 + * Copyright: Marvell International 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/irq.h> +#include <linux/io.h> + +#include <mach/regs-icu.h> + +#include "common.h" + +#define IRQ_ROUTE_TO_AP (ICU_INT_CONF_AP_INT | ICU_INT_CONF_IRQ) + +#define PRIORITY_DEFAULT 0x1 +#define PRIORITY_NONE 0x0 /* means IRQ disabled */ + +static void icu_mask_irq(unsigned int irq) +{ + __raw_writel(PRIORITY_NONE, ICU_INT_CONF(irq)); +} + +static void icu_unmask_irq(unsigned int irq) +{ + __raw_writel(IRQ_ROUTE_TO_AP | PRIORITY_DEFAULT, ICU_INT_CONF(irq)); +} + +static struct irq_chip icu_irq_chip = { + .name = "icu_irq", + .ack = icu_mask_irq, + .mask = icu_mask_irq, + .unmask = icu_unmask_irq, +}; + +void __init icu_init_irq(void) +{ + int irq; + + for (irq = 0; irq < 64; irq++) { + icu_mask_irq(irq); + set_irq_chip(irq, &icu_irq_chip); + set_irq_handler(irq, handle_level_irq); + set_irq_flags(irq, IRQF_VALID); + } +} diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c new file mode 100644 index 00000000000..1935c754511 --- /dev/null +++ b/arch/arm/mach-mmp/pxa168.c @@ -0,0 +1,77 @@ +/* + * linux/arch/arm/mach-mmp/pxa168.c + * + * Code specific to PXA168 + * + * 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/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/clk.h> + +#include <asm/mach/time.h> +#include <mach/addr-map.h> +#include <mach/cputype.h> +#include <mach/regs-apbc.h> +#include <mach/irqs.h> +#include <mach/dma.h> +#include <mach/devices.h> + +#include "common.h" +#include "clock.h" + +void __init pxa168_init_irq(void) +{ + icu_init_irq(); +} + +/* APB peripheral clocks */ +static APBC_CLK(uart1, PXA168_UART1, 1, 14745600); +static APBC_CLK(uart2, PXA168_UART2, 1, 14745600); + +/* device and clock bindings */ +static struct clk_lookup pxa168_clkregs[] = { + INIT_CLKREG(&clk_uart1, "pxa2xx-uart.0", NULL), + INIT_CLKREG(&clk_uart2, "pxa2xx-uart.1", NULL), +}; + +static int __init pxa168_init(void) +{ + if (cpu_is_pxa168()) { + pxa_init_dma(IRQ_PXA168_DMA_INT0, 32); + clks_register(ARRAY_AND_SIZE(pxa168_clkregs)); + } + + return 0; +} +postcore_initcall(pxa168_init); + +/* system timer - clock enabled, 3.25MHz */ +#define TIMER_CLK_RST (APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(3)) + +static void __init pxa168_timer_init(void) +{ + /* this is early, we have to initialize the CCU registers by + * ourselves instead of using clk_* API. Clock rate is defined + * by APBC_TIMERS_CLK_RST (3.25MHz) and enabled free-running + */ + __raw_writel(APBC_APBCLK | APBC_RST, APBC_PXA168_TIMERS); + + /* 3.25MHz, bus/functional clock enabled, release reset */ + __raw_writel(TIMER_CLK_RST, APBC_PXA168_TIMERS); + + timer_init(IRQ_PXA168_TIMER1); +} + +struct sys_timer pxa168_timer = { + .init = pxa168_timer_init, +}; + +/* on-chip devices */ +PXA168_DEVICE(uart1, "pxa2xx-uart", 0, UART1, 0xd4017000, 0x30, 21, 22); +PXA168_DEVICE(uart2, "pxa2xx-uart", 1, UART2, 0xd4018000, 0x30, 23, 24); diff --git a/arch/arm/mach-mmp/time.c b/arch/arm/mach-mmp/time.c new file mode 100644 index 00000000000..b03a6eda741 --- /dev/null +++ b/arch/arm/mach-mmp/time.c @@ -0,0 +1,199 @@ +/* + * linux/arch/arm/mach-mmp/time.c + * + * Support for clocksource and clockevents + * + * Copyright (C) 2008 Marvell International Ltd. + * All rights reserved. + * + * 2008-04-11: Jason Chagas <Jason.chagas@marvell.com> + * 2008-10-08: Bin Yang <bin.yang@marvell.com> + * + * The timers module actually includes three timers, each timer with upto + * three match comparators. Timer #0 is used here in free-running mode as + * the clock source, and match comparator #1 used as clock event device. + * + * 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/kernel.h> +#include <linux/interrupt.h> +#include <linux/clockchips.h> + +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/sched.h> +#include <linux/cnt32_to_63.h> + +#include <mach/addr-map.h> +#include <mach/regs-timers.h> +#include <mach/irqs.h> + +#include "clock.h" + +#define TIMERS_VIRT_BASE TIMERS1_VIRT_BASE + +#define MAX_DELTA (0xfffffffe) +#define MIN_DELTA (16) + +#define TCR2NS_SCALE_FACTOR 10 + +static unsigned long tcr2ns_scale; + +static void __init set_tcr2ns_scale(unsigned long tcr_rate) +{ + unsigned long long v = 1000000000ULL << TCR2NS_SCALE_FACTOR; + do_div(v, tcr_rate); + tcr2ns_scale = v; + /* + * We want an even value to automatically clear the top bit + * returned by cnt32_to_63() without an additional run time + * instruction. So if the LSB is 1 then round it up. + */ + if (tcr2ns_scale & 1) + tcr2ns_scale++; +} + +/* + * FIXME: the timer needs some delay to stablize the counter capture + */ +static inline uint32_t timer_read(void) +{ + int delay = 100; + + __raw_writel(1, TIMERS_VIRT_BASE + TMR_CVWR(0)); + + while (delay--) + cpu_relax(); + + return __raw_readl(TIMERS_VIRT_BASE + TMR_CVWR(0)); +} + +unsigned long long sched_clock(void) +{ + unsigned long long v = cnt32_to_63(timer_read()); + return (v * tcr2ns_scale) >> TCR2NS_SCALE_FACTOR; +} + +static irqreturn_t timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *c = dev_id; + + /* disable and clear pending interrupt status */ + __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_IER(0)); + __raw_writel(0x1, TIMERS_VIRT_BASE + TMR_ICR(0)); + c->event_handler(c); + return IRQ_HANDLED; +} + +static int timer_set_next_event(unsigned long delta, + struct clock_event_device *dev) +{ + unsigned long flags, next; + + local_irq_save(flags); + + /* clear pending interrupt status and enable */ + __raw_writel(0x01, TIMERS_VIRT_BASE + TMR_ICR(0)); + __raw_writel(0x01, TIMERS_VIRT_BASE + TMR_IER(0)); + + next = timer_read() + delta; + __raw_writel(next, TIMERS_VIRT_BASE + TMR_TN_MM(0, 0)); + + local_irq_restore(flags); + return 0; +} + +static void timer_set_mode(enum clock_event_mode mode, + struct clock_event_device *dev) +{ + unsigned long flags; + + local_irq_save(flags); + switch (mode) { + case CLOCK_EVT_MODE_ONESHOT: + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + /* disable the matching interrupt */ + __raw_writel(0x00, TIMERS_VIRT_BASE + TMR_IER(0)); + break; + case CLOCK_EVT_MODE_RESUME: + case CLOCK_EVT_MODE_PERIODIC: + break; + } + local_irq_restore(flags); +} + +static struct clock_event_device ckevt = { + .name = "clockevent", + .features = CLOCK_EVT_FEAT_ONESHOT, + .shift = 32, + .rating = 200, + .set_next_event = timer_set_next_event, + .set_mode = timer_set_mode, +}; + +static cycle_t clksrc_read(void) +{ + return timer_read(); +} + +static struct clocksource cksrc = { + .name = "clocksource", + .shift = 20, + .rating = 200, + .read = clksrc_read, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static void __init timer_config(void) +{ + uint32_t ccr = __raw_readl(TIMERS_VIRT_BASE + TMR_CCR); + uint32_t cer = __raw_readl(TIMERS_VIRT_BASE + TMR_CER); + uint32_t cmr = __raw_readl(TIMERS_VIRT_BASE + TMR_CMR); + + __raw_writel(cer & ~0x1, TIMERS_VIRT_BASE + TMR_CER); /* disable */ + + ccr &= TMR_CCR_CS_0(0x3); + __raw_writel(ccr, TIMERS_VIRT_BASE + TMR_CCR); + + /* free-running mode */ + __raw_writel(cmr | 0x01, TIMERS_VIRT_BASE + TMR_CMR); + + __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_PLCR(0)); /* free-running */ + __raw_writel(0x7, TIMERS_VIRT_BASE + TMR_ICR(0)); /* clear status */ + __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_IER(0)); + + /* enable timer counter */ + __raw_writel(cer | 0x01, TIMERS_VIRT_BASE + TMR_CER); +} + +static struct irqaction timer_irq = { + .name = "timer", + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .handler = timer_interrupt, + .dev_id = &ckevt, +}; + +void __init timer_init(int irq) +{ + timer_config(); + + set_tcr2ns_scale(CLOCK_TICK_RATE); + + ckevt.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, ckevt.shift); + ckevt.max_delta_ns = clockevent_delta2ns(MAX_DELTA, &ckevt); + ckevt.min_delta_ns = clockevent_delta2ns(MIN_DELTA, &ckevt); + ckevt.cpumask = cpumask_of(0); + + cksrc.mult = clocksource_hz2mult(CLOCK_TICK_RATE, cksrc.shift); + + setup_irq(irq, &timer_irq); + + clocksource_register(&cksrc); + clockevents_register_device(&ckevt); +} |