From b85a3ef4ac65169b65fd2fe9bec7912bbf475ba4 Mon Sep 17 00:00:00 2001 From: John Linn Date: Mon, 20 Jun 2011 11:47:27 -0600 Subject: [PATCH 01/10] ARM: Xilinx: Adding Xilinx board support The 1st board support is minimal to get a system up and running on the Xilinx platform. This platform reuses the clock implementation from plat-versatile, and it depends entirely on CONFIG_OF support. There is only one board support file which obtains all device information from a device tree dtb file which is passed to the kernel at boot time. Signed-off-by: John Linn --- .../devicetree/bindings/arm/xilinx.txt | 7 + arch/arm/Kconfig | 14 + arch/arm/Makefile | 2 + arch/arm/boot/dts/zynq-ep107.dts | 52 +++ arch/arm/mach-zynq/Makefile | 6 + arch/arm/mach-zynq/Makefile.boot | 3 + arch/arm/mach-zynq/board_dt.c | 37 +++ arch/arm/mach-zynq/common.c | 102 ++++++ arch/arm/mach-zynq/common.h | 29 ++ arch/arm/mach-zynq/include/mach/clkdev.h | 32 ++ arch/arm/mach-zynq/include/mach/debug-macro.S | 36 +++ arch/arm/mach-zynq/include/mach/entry-macro.S | 30 ++ arch/arm/mach-zynq/include/mach/hardware.h | 18 ++ arch/arm/mach-zynq/include/mach/io.h | 33 ++ arch/arm/mach-zynq/include/mach/irqs.h | 21 ++ arch/arm/mach-zynq/include/mach/memory.h | 22 ++ arch/arm/mach-zynq/include/mach/system.h | 28 ++ arch/arm/mach-zynq/include/mach/timex.h | 23 ++ arch/arm/mach-zynq/include/mach/uart.h | 25 ++ arch/arm/mach-zynq/include/mach/uncompress.h | 51 +++ arch/arm/mach-zynq/include/mach/vmalloc.h | 20 ++ arch/arm/mach-zynq/include/mach/zynq_soc.h | 48 +++ arch/arm/mach-zynq/timer.c | 298 ++++++++++++++++++ arch/arm/mm/Kconfig | 2 +- 24 files changed, 938 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/arm/xilinx.txt create mode 100644 arch/arm/boot/dts/zynq-ep107.dts create mode 100644 arch/arm/mach-zynq/Makefile create mode 100644 arch/arm/mach-zynq/Makefile.boot create mode 100644 arch/arm/mach-zynq/board_dt.c create mode 100644 arch/arm/mach-zynq/common.c create mode 100644 arch/arm/mach-zynq/common.h create mode 100644 arch/arm/mach-zynq/include/mach/clkdev.h create mode 100644 arch/arm/mach-zynq/include/mach/debug-macro.S create mode 100644 arch/arm/mach-zynq/include/mach/entry-macro.S create mode 100644 arch/arm/mach-zynq/include/mach/hardware.h create mode 100644 arch/arm/mach-zynq/include/mach/io.h create mode 100644 arch/arm/mach-zynq/include/mach/irqs.h create mode 100644 arch/arm/mach-zynq/include/mach/memory.h create mode 100644 arch/arm/mach-zynq/include/mach/system.h create mode 100644 arch/arm/mach-zynq/include/mach/timex.h create mode 100644 arch/arm/mach-zynq/include/mach/uart.h create mode 100644 arch/arm/mach-zynq/include/mach/uncompress.h create mode 100644 arch/arm/mach-zynq/include/mach/vmalloc.h create mode 100644 arch/arm/mach-zynq/include/mach/zynq_soc.h create mode 100644 arch/arm/mach-zynq/timer.c diff --git a/Documentation/devicetree/bindings/arm/xilinx.txt b/Documentation/devicetree/bindings/arm/xilinx.txt new file mode 100644 index 000000000000..6f1ed830b4f7 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/xilinx.txt @@ -0,0 +1,7 @@ +Xilinx Zynq EP107 Emulation Platform board + +This board is an emulation platform for the Zynq product which is +based on an ARM Cortex A9 processor. + +Required root node properties: + - compatible = "xlnx,zynq-ep107"; diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9adc278a22ab..9e76a75a490b 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -879,6 +879,20 @@ config ARCH_VT8500 select HAVE_PWM help Support for VIA/WonderMedia VT8500/WM85xx System-on-Chip. + +config ARCH_ZYNQ + bool "Xilinx Zynq ARM Cortex A9 Platform" + select CPU_V7 + select GENERIC_TIME + select GENERIC_CLOCKEVENTS + select CLKDEV_LOOKUP + select ARM_GIC + select ARM_AMBA + select ICST + select USE_OF + help + Support for Xilinx Zynq ARM Cortex A9 Platform + endchoice # diff --git a/arch/arm/Makefile b/arch/arm/Makefile index f5b2b390c8f2..999c17aa8571 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -196,6 +196,7 @@ machine-$(CONFIG_MACH_SPEAR300) := spear3xx machine-$(CONFIG_MACH_SPEAR310) := spear3xx machine-$(CONFIG_MACH_SPEAR320) := spear3xx machine-$(CONFIG_MACH_SPEAR600) := spear6xx +machine-$(CONFIG_ARCH_ZYNQ) := zynq # Platform directory name. This list is sorted alphanumerically # by CONFIG_* macro name. @@ -203,6 +204,7 @@ plat-$(CONFIG_ARCH_MXC) := mxc plat-$(CONFIG_ARCH_OMAP) := omap plat-$(CONFIG_ARCH_S3C64XX) := samsung plat-$(CONFIG_ARCH_TCC_926) := tcc +plat-$(CONFIG_ARCH_ZYNQ) := versatile plat-$(CONFIG_PLAT_IOP) := iop plat-$(CONFIG_PLAT_NOMADIK) := nomadik plat-$(CONFIG_PLAT_ORION) := orion diff --git a/arch/arm/boot/dts/zynq-ep107.dts b/arch/arm/boot/dts/zynq-ep107.dts new file mode 100644 index 000000000000..37ca192fb193 --- /dev/null +++ b/arch/arm/boot/dts/zynq-ep107.dts @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2011 Xilinx + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +/dts-v1/; +/ { + model = "Xilinx Zynq EP107"; + compatible = "xlnx,zynq-ep107"; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&intc>; + + memory { + device_type = "memory"; + reg = <0x0 0x10000000>; + }; + + chosen { + bootargs = "console=ttyPS0,9600 root=/dev/ram rw initrd=0x800000,8M earlyprintk"; + linux,stdout-path = &uart0; + }; + + amba { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + intc: interrupt-controller@f8f01000 { + interrupt-controller; + compatible = "arm,gic"; + reg = <0xF8F01000 0x1000>; + #interrupt-cells = <2>; + }; + + uart0: uart@e0000000 { + compatible = "xlnx,xuartps"; + reg = <0xE0000000 0x1000>; + interrupts = <59 0>; + clock = <50000000>; + }; + }; +}; diff --git a/arch/arm/mach-zynq/Makefile b/arch/arm/mach-zynq/Makefile new file mode 100644 index 000000000000..c550c67aa893 --- /dev/null +++ b/arch/arm/mach-zynq/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the linux kernel. +# + +# Common support +obj-y := common.o timer.o board_dt.o diff --git a/arch/arm/mach-zynq/Makefile.boot b/arch/arm/mach-zynq/Makefile.boot new file mode 100644 index 000000000000..67039c3e0c48 --- /dev/null +++ b/arch/arm/mach-zynq/Makefile.boot @@ -0,0 +1,3 @@ + zreladdr-y := 0x00008000 +params_phys-y := 0x00000100 +initrd_phys-y := 0x00800000 diff --git a/arch/arm/mach-zynq/board_dt.c b/arch/arm/mach-zynq/board_dt.c new file mode 100644 index 000000000000..5b4710d09258 --- /dev/null +++ b/arch/arm/mach-zynq/board_dt.c @@ -0,0 +1,37 @@ +/* + * This file contains code for boards with device tree support. + * + * Copyright (C) 2011 Xilinx + * + * based on arch/arm/mach-realview/core.c + * + * Copyright (C) 1999 - 2003 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include +#include +#include +#include "common.h" + +static const char *xilinx_dt_match[] = { + "xlnx,zynq-ep107", + NULL +}; + +MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform") + .map_io = xilinx_map_io, + .init_irq = xilinx_irq_init, + .init_machine = xilinx_init_machine, + .timer = &xttcpss_sys_timer, + .dt_compat = xilinx_dt_match, +MACHINE_END diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c new file mode 100644 index 000000000000..b3ac5c2e12dc --- /dev/null +++ b/arch/arm/mach-zynq/common.c @@ -0,0 +1,102 @@ +/* + * This file contains common code that is intended to be used across + * boards so that it's not replicated. + * + * Copyright (C) 2011 Xilinx + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include "common.h" + +static struct of_device_id zynq_of_bus_ids[] __initdata = { + { .compatible = "simple-bus", }, + {} +}; + +/** + * xilinx_init_machine() - System specific initialization, intended to be + * called from board specific initialization. + */ +void __init xilinx_init_machine(void) +{ +#ifdef CONFIG_CACHE_L2X0 + /* + * 64KB way size, 8-way associativity, parity disabled + */ + l2x0_init(PL310_L2CC_BASE, 0x02060000, 0xF0F0FFFF); +#endif + + of_platform_bus_probe(NULL, zynq_of_bus_ids, NULL); +} + +/** + * xilinx_irq_init() - Interrupt controller initialization for the GIC. + */ +void __init xilinx_irq_init(void) +{ + gic_init(0, 29, SCU_GIC_DIST_BASE, SCU_GIC_CPU_BASE); +} + +/* The minimum devices needed to be mapped before the VM system is up and + * running include the GIC, UART and Timer Counter. + */ + +static struct map_desc io_desc[] __initdata = { + { + .virtual = TTC0_VIRT, + .pfn = __phys_to_pfn(TTC0_PHYS), + .length = SZ_4K, + .type = MT_DEVICE, + }, { + .virtual = SCU_PERIPH_VIRT, + .pfn = __phys_to_pfn(SCU_PERIPH_PHYS), + .length = SZ_8K, + .type = MT_DEVICE, + }, { + .virtual = PL310_L2CC_VIRT, + .pfn = __phys_to_pfn(PL310_L2CC_PHYS), + .length = SZ_4K, + .type = MT_DEVICE, + }, + +#ifdef CONFIG_DEBUG_LL + { + .virtual = UART0_VIRT, + .pfn = __phys_to_pfn(UART0_PHYS), + .length = SZ_4K, + .type = MT_DEVICE, + }, +#endif + +}; + +/** + * xilinx_map_io() - Create memory mappings needed for early I/O. + */ +void __init xilinx_map_io(void) +{ + iotable_init(io_desc, ARRAY_SIZE(io_desc)); +} diff --git a/arch/arm/mach-zynq/common.h b/arch/arm/mach-zynq/common.h new file mode 100644 index 000000000000..bca21968f80b --- /dev/null +++ b/arch/arm/mach-zynq/common.h @@ -0,0 +1,29 @@ +/* + * This file contains common function prototypes to avoid externs + * in the c files. + * + * Copyright (C) 2011 Xilinx + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#ifndef __MACH_ZYNQ_COMMON_H__ +#define __MACH_ZYNQ_COMMON_H__ + +#include +#include + +extern void xilinx_init_machine(void); +extern void xilinx_irq_init(void); +extern void xilinx_map_io(void); + +extern struct sys_timer xttcpss_sys_timer; + +#endif diff --git a/arch/arm/mach-zynq/include/mach/clkdev.h b/arch/arm/mach-zynq/include/mach/clkdev.h new file mode 100644 index 000000000000..c6e73d81a459 --- /dev/null +++ b/arch/arm/mach-zynq/include/mach/clkdev.h @@ -0,0 +1,32 @@ +/* + * arch/arm/mach-zynq/include/mach/clkdev.h + * + * Copyright (C) 2011 Xilinx, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __MACH_CLKDEV_H__ +#define __MACH_CLKDEV_H__ + +#include + +struct clk { + unsigned long rate; + const struct clk_ops *ops; + const struct icst_params *params; + void __iomem *vcoreg; +}; + +#define __clk_get(clk) ({ 1; }) +#define __clk_put(clk) do { } while (0) + +#endif diff --git a/arch/arm/mach-zynq/include/mach/debug-macro.S b/arch/arm/mach-zynq/include/mach/debug-macro.S new file mode 100644 index 000000000000..9f664d5eb81d --- /dev/null +++ b/arch/arm/mach-zynq/include/mach/debug-macro.S @@ -0,0 +1,36 @@ +/* arch/arm/mach-zynq/include/mach/debug-macro.S + * + * Debugging macro include header + * + * Copyright (C) 2011 Xilinx + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include +#include + + .macro addruart, rp, rv + ldr \rp, =LL_UART_PADDR @ physical + ldr \rv, =LL_UART_VADDR @ virtual + .endm + + .macro senduart,rd,rx + str \rd, [\rx, #UART_FIFO_OFFSET] @ TXDATA + .endm + + .macro waituart,rd,rx + .endm + + .macro busyuart,rd,rx +1002: ldr \rd, [\rx, #UART_SR_OFFSET] @ get status register + tst \rd, #UART_SR_TXFULL @ + bne 1002b @ wait if FIFO is full + .endm diff --git a/arch/arm/mach-zynq/include/mach/entry-macro.S b/arch/arm/mach-zynq/include/mach/entry-macro.S new file mode 100644 index 000000000000..3cfc01b37461 --- /dev/null +++ b/arch/arm/mach-zynq/include/mach/entry-macro.S @@ -0,0 +1,30 @@ +/* + * arch/arm/mach-zynq/include/mach/entry-macro.S + * + * Low-level IRQ helper macros + * + * Copyright (C) 2011 Xilinx + * + * based on arch/plat-mxc/include/mach/entry-macro.S + * + * Copyright (C) 2007 Lennert Buytenhek + * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include +#include + + .macro disable_fiq + .endm + + .macro arch_ret_to_user, tmp1, tmp2 + .endm diff --git a/arch/arm/mach-zynq/include/mach/hardware.h b/arch/arm/mach-zynq/include/mach/hardware.h new file mode 100644 index 000000000000..d558d8a94be7 --- /dev/null +++ b/arch/arm/mach-zynq/include/mach/hardware.h @@ -0,0 +1,18 @@ +/* arch/arm/mach-zynq/include/mach/hardware.h + * + * Copyright (C) 2011 Xilinx + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#ifndef __MACH_HARDWARE_H__ +#define __MACH_HARDWARE_H__ + +#endif diff --git a/arch/arm/mach-zynq/include/mach/io.h b/arch/arm/mach-zynq/include/mach/io.h new file mode 100644 index 000000000000..39d9885e0e9a --- /dev/null +++ b/arch/arm/mach-zynq/include/mach/io.h @@ -0,0 +1,33 @@ +/* arch/arm/mach-zynq/include/mach/io.h + * + * Copyright (C) 2011 Xilinx + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#ifndef __MACH_IO_H__ +#define __MACH_IO_H__ + +/* Allow IO space to be anywhere in the memory */ + +#define IO_SPACE_LIMIT 0xffff + +/* IO address mapping macros, nothing special at this time but required */ + +#ifdef __ASSEMBLER__ +#define IOMEM(x) (x) +#else +#define IOMEM(x) ((void __force __iomem *)(x)) +#endif + +#define __io(a) __typesafe_io(a) +#define __mem_pci(a) (a) + +#endif diff --git a/arch/arm/mach-zynq/include/mach/irqs.h b/arch/arm/mach-zynq/include/mach/irqs.h new file mode 100644 index 000000000000..5fb04fd3bac8 --- /dev/null +++ b/arch/arm/mach-zynq/include/mach/irqs.h @@ -0,0 +1,21 @@ +/* arch/arm/mach-zynq/include/mach/irqs.h + * + * Copyright (C) 2011 Xilinx + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#ifndef __MACH_IRQS_H +#define __MACH_IRQS_H + +#define ARCH_NR_GPIOS 118 +#define NR_IRQS (128 + ARCH_NR_GPIOS) + +#endif diff --git a/arch/arm/mach-zynq/include/mach/memory.h b/arch/arm/mach-zynq/include/mach/memory.h new file mode 100644 index 000000000000..35a92634dcc1 --- /dev/null +++ b/arch/arm/mach-zynq/include/mach/memory.h @@ -0,0 +1,22 @@ +/* arch/arm/mach-zynq/include/mach/memory.h + * + * Copyright (C) 2011 Xilinx + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#ifndef __MACH_MEMORY_H__ +#define __MACH_MEMORY_H__ + +#include + +#define PLAT_PHYS_OFFSET UL(0x0) + +#endif diff --git a/arch/arm/mach-zynq/include/mach/system.h b/arch/arm/mach-zynq/include/mach/system.h new file mode 100644 index 000000000000..1b84d705c675 --- /dev/null +++ b/arch/arm/mach-zynq/include/mach/system.h @@ -0,0 +1,28 @@ +/* arch/arm/mach-zynq/include/mach/system.h + * + * Copyright (C) 2011 Xilinx + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#ifndef __MACH_SYSTEM_H__ +#define __MACH_SYSTEM_H__ + +static inline void arch_idle(void) +{ + cpu_do_idle(); +} + +static inline void arch_reset(char mode, const char *cmd) +{ + /* Add architecture specific reset processing here */ +} + +#endif diff --git a/arch/arm/mach-zynq/include/mach/timex.h b/arch/arm/mach-zynq/include/mach/timex.h new file mode 100644 index 000000000000..6c0245e42a5e --- /dev/null +++ b/arch/arm/mach-zynq/include/mach/timex.h @@ -0,0 +1,23 @@ +/* arch/arm/mach-zynq/include/mach/timex.h + * + * Copyright (C) 2011 Xilinx + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#ifndef __MACH_TIMEX_H__ +#define __MACH_TIMEX_H__ + +/* the following is needed for the system to build but will be removed + in the future, the value is not important but won't hurt +*/ +#define CLOCK_TICK_RATE (100 * HZ) + +#endif diff --git a/arch/arm/mach-zynq/include/mach/uart.h b/arch/arm/mach-zynq/include/mach/uart.h new file mode 100644 index 000000000000..5c47c97156f3 --- /dev/null +++ b/arch/arm/mach-zynq/include/mach/uart.h @@ -0,0 +1,25 @@ +/* arch/arm/mach-zynq/include/mach/uart.h + * + * Copyright (C) 2011 Xilinx + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#ifndef __MACH_UART_H__ +#define __MACH_UART_H__ + +#define UART_CR_OFFSET 0x00 /* Control Register [8:0] */ +#define UART_SR_OFFSET 0x2C /* Channel Status [11:0] */ +#define UART_FIFO_OFFSET 0x30 /* FIFO [15:0] or [7:0] */ + +#define UART_SR_TXFULL 0x00000010 /* TX FIFO full */ +#define UART_SR_TXEMPTY 0x00000008 /* TX FIFO empty */ + +#endif diff --git a/arch/arm/mach-zynq/include/mach/uncompress.h b/arch/arm/mach-zynq/include/mach/uncompress.h new file mode 100644 index 000000000000..af4e8447bfa3 --- /dev/null +++ b/arch/arm/mach-zynq/include/mach/uncompress.h @@ -0,0 +1,51 @@ +/* arch/arm/mach-zynq/include/mach/uncompress.h + * + * Copyright (C) 2011 Xilinx + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#ifndef __MACH_UNCOMPRESS_H__ +#define __MACH_UNCOMPRESS_H__ + +#include +#include +#include +#include + +void arch_decomp_setup(void) +{ +} + +static inline void flush(void) +{ + /* + * Wait while the FIFO is not empty + */ + while (!(__raw_readl(IOMEM(LL_UART_PADDR + UART_SR_OFFSET)) & + UART_SR_TXEMPTY)) + cpu_relax(); +} + +#define arch_decomp_wdog() + +static void putc(char ch) +{ + /* + * Wait for room in the FIFO, then write the char into the FIFO + */ + while (__raw_readl(IOMEM(LL_UART_PADDR + UART_SR_OFFSET)) & + UART_SR_TXFULL) + cpu_relax(); + + __raw_writel(ch, IOMEM(LL_UART_PADDR + UART_FIFO_OFFSET)); +} + +#endif diff --git a/arch/arm/mach-zynq/include/mach/vmalloc.h b/arch/arm/mach-zynq/include/mach/vmalloc.h new file mode 100644 index 000000000000..2398eff1e8b8 --- /dev/null +++ b/arch/arm/mach-zynq/include/mach/vmalloc.h @@ -0,0 +1,20 @@ +/* arch/arm/mach-zynq/include/mach/vmalloc.h + * + * Copyright (C) 2011 Xilinx + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#ifndef __MACH_VMALLOC_H__ +#define __MACH_VMALLOC_H__ + +#define VMALLOC_END 0xE0000000UL + +#endif diff --git a/arch/arm/mach-zynq/include/mach/zynq_soc.h b/arch/arm/mach-zynq/include/mach/zynq_soc.h new file mode 100644 index 000000000000..d0d3f8fb06dd --- /dev/null +++ b/arch/arm/mach-zynq/include/mach/zynq_soc.h @@ -0,0 +1,48 @@ +/* arch/arm/mach-zynq/include/mach/zynq_soc.h + * + * Copyright (C) 2011 Xilinx + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#ifndef __MACH_XILINX_SOC_H__ +#define __MACH_XILINX_SOC_H__ + +#define PERIPHERAL_CLOCK_RATE 2500000 + +/* For now, all mappings are flat (physical = virtual) + */ +#define UART0_PHYS 0xE0000000 +#define UART0_VIRT UART0_PHYS + +#define TTC0_PHYS 0xF8001000 +#define TTC0_VIRT TTC0_PHYS + +#define PL310_L2CC_PHYS 0xF8F02000 +#define PL310_L2CC_VIRT PL310_L2CC_PHYS + +#define SCU_PERIPH_PHYS 0xF8F00000 +#define SCU_PERIPH_VIRT SCU_PERIPH_PHYS + +/* The following are intended for the devices that are mapped early */ + +#define TTC0_BASE IOMEM(TTC0_VIRT) +#define SCU_PERIPH_BASE IOMEM(SCU_PERIPH_VIRT) +#define SCU_GIC_CPU_BASE (SCU_PERIPH_BASE + 0x100) +#define SCU_GIC_DIST_BASE (SCU_PERIPH_BASE + 0x1000) +#define PL310_L2CC_BASE IOMEM(PL310_L2CC_VIRT) + +/* + * Mandatory for CONFIG_LL_DEBUG, UART is mapped virtual = physical + */ +#define LL_UART_PADDR UART0_PHYS +#define LL_UART_VADDR UART0_VIRT + +#endif diff --git a/arch/arm/mach-zynq/timer.c b/arch/arm/mach-zynq/timer.c new file mode 100644 index 000000000000..c2c96cc7d6e7 --- /dev/null +++ b/arch/arm/mach-zynq/timer.c @@ -0,0 +1,298 @@ +/* + * This file contains driver for the Xilinx PS Timer Counter IP. + * + * Copyright (C) 2011 Xilinx + * + * based on arch/mips/kernel/time.c timer driver + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "common.h" + +#define IRQ_TIMERCOUNTER0 42 + +/* + * This driver configures the 2 16-bit count-up timers as follows: + * + * T1: Timer 1, clocksource for generic timekeeping + * T2: Timer 2, clockevent source for hrtimers + * T3: Timer 3, + * + * The input frequency to the timer module for emulation is 2.5MHz which is + * common to all the timer channels (T1, T2, and T3). With a pre-scaler of 32, + * the timers are clocked at 78.125KHz (12.8 us resolution). + * + * The input frequency to the timer module in silicon will be 200MHz. With the + * pre-scaler of 32, the timers are clocked at 6.25MHz (160ns resolution). + */ +#define XTTCPSS_CLOCKSOURCE 0 /* Timer 1 as a generic timekeeping */ +#define XTTCPSS_CLOCKEVENT 1 /* Timer 2 as a clock event */ + +#define XTTCPSS_TIMER_BASE TTC0_BASE +#define XTTCPCC_EVENT_TIMER_IRQ (IRQ_TIMERCOUNTER0 + 1) +/* + * Timer Register Offset Definitions of Timer 1, Increment base address by 4 + * and use same offsets for Timer 2 + */ +#define XTTCPSS_CLK_CNTRL_OFFSET 0x00 /* Clock Control Reg, RW */ +#define XTTCPSS_CNT_CNTRL_OFFSET 0x0C /* Counter Control Reg, RW */ +#define XTTCPSS_COUNT_VAL_OFFSET 0x18 /* Counter Value Reg, RO */ +#define XTTCPSS_INTR_VAL_OFFSET 0x24 /* Interval Count Reg, RW */ +#define XTTCPSS_MATCH_1_OFFSET 0x30 /* Match 1 Value Reg, RW */ +#define XTTCPSS_MATCH_2_OFFSET 0x3C /* Match 2 Value Reg, RW */ +#define XTTCPSS_MATCH_3_OFFSET 0x48 /* Match 3 Value Reg, RW */ +#define XTTCPSS_ISR_OFFSET 0x54 /* Interrupt Status Reg, RO */ +#define XTTCPSS_IER_OFFSET 0x60 /* Interrupt Enable Reg, RW */ + +#define XTTCPSS_CNT_CNTRL_DISABLE_MASK 0x1 + +/* Setup the timers to use pre-scaling */ + +#define TIMER_RATE (PERIPHERAL_CLOCK_RATE / 32) + +/** + * struct xttcpss_timer - This definition defines local timer structure + * + * @base_addr: Base address of timer + **/ +struct xttcpss_timer { + void __iomem *base_addr; +}; + +static struct xttcpss_timer timers[2]; +static struct clock_event_device xttcpss_clockevent; + +/** + * xttcpss_set_interval - Set the timer interval value + * + * @timer: Pointer to the timer instance + * @cycles: Timer interval ticks + **/ +static void xttcpss_set_interval(struct xttcpss_timer *timer, + unsigned long cycles) +{ + u32 ctrl_reg; + + /* Disable the counter, set the counter value and re-enable counter */ + ctrl_reg = __raw_readl(timer->base_addr + XTTCPSS_CNT_CNTRL_OFFSET); + ctrl_reg |= XTTCPSS_CNT_CNTRL_DISABLE_MASK; + __raw_writel(ctrl_reg, timer->base_addr + XTTCPSS_CNT_CNTRL_OFFSET); + + __raw_writel(cycles, timer->base_addr + XTTCPSS_INTR_VAL_OFFSET); + + /* Reset the counter (0x10) so that it starts from 0, one-shot + mode makes this needed for timing to be right. */ + ctrl_reg |= 0x10; + ctrl_reg &= ~XTTCPSS_CNT_CNTRL_DISABLE_MASK; + __raw_writel(ctrl_reg, timer->base_addr + XTTCPSS_CNT_CNTRL_OFFSET); +} + +/** + * xttcpss_clock_event_interrupt - Clock event timer interrupt handler + * + * @irq: IRQ number of the Timer + * @dev_id: void pointer to the xttcpss_timer instance + * + * returns: Always IRQ_HANDLED - success + **/ +static irqreturn_t xttcpss_clock_event_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *evt = &xttcpss_clockevent; + struct xttcpss_timer *timer = dev_id; + + /* Acknowledge the interrupt and call event handler */ + __raw_writel(__raw_readl(timer->base_addr + XTTCPSS_ISR_OFFSET), + timer->base_addr + XTTCPSS_ISR_OFFSET); + + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static struct irqaction event_timer_irq = { + .name = "xttcpss clockevent", + .flags = IRQF_DISABLED | IRQF_TIMER, + .handler = xttcpss_clock_event_interrupt, +}; + +/** + * xttcpss_timer_hardware_init - Initialize the timer hardware + * + * Initialize the hardware to start the clock source, get the clock + * event timer ready to use, and hook up the interrupt. + **/ +static void __init xttcpss_timer_hardware_init(void) +{ + /* Setup the clock source counter to be an incrementing counter + * with no interrupt and it rolls over at 0xFFFF. Pre-scale + it by 32 also. Let it start running now. + */ + timers[XTTCPSS_CLOCKSOURCE].base_addr = XTTCPSS_TIMER_BASE; + + __raw_writel(0x0, timers[XTTCPSS_CLOCKSOURCE].base_addr + + XTTCPSS_IER_OFFSET); + __raw_writel(0x9, timers[XTTCPSS_CLOCKSOURCE].base_addr + + XTTCPSS_CLK_CNTRL_OFFSET); + __raw_writel(0x10, timers[XTTCPSS_CLOCKSOURCE].base_addr + + XTTCPSS_CNT_CNTRL_OFFSET); + + /* Setup the clock event timer to be an interval timer which + * is prescaled by 32 using the interval interrupt. Leave it + * disabled for now. + */ + + timers[XTTCPSS_CLOCKEVENT].base_addr = XTTCPSS_TIMER_BASE + 4; + + __raw_writel(0x23, timers[XTTCPSS_CLOCKEVENT].base_addr + + XTTCPSS_CNT_CNTRL_OFFSET); + __raw_writel(0x9, timers[XTTCPSS_CLOCKEVENT].base_addr + + XTTCPSS_CLK_CNTRL_OFFSET); + __raw_writel(0x1, timers[XTTCPSS_CLOCKEVENT].base_addr + + XTTCPSS_IER_OFFSET); + + /* Setup IRQ the clock event timer */ + event_timer_irq.dev_id = &timers[XTTCPSS_CLOCKEVENT]; + setup_irq(XTTCPCC_EVENT_TIMER_IRQ, &event_timer_irq); +} + +/** + * __raw_readl_cycles - Reads the timer counter register + * + * returns: Current timer counter register value + **/ +static cycle_t __raw_readl_cycles(struct clocksource *cs) +{ + struct xttcpss_timer *timer = &timers[XTTCPSS_CLOCKSOURCE]; + + return (cycle_t)__raw_readl(timer->base_addr + + XTTCPSS_COUNT_VAL_OFFSET); +} + + +/* + * Instantiate and initialize the clock source structure + */ +static struct clocksource clocksource_xttcpss = { + .name = "xttcpss_timer1", + .rating = 200, /* Reasonable clock source */ + .read = __raw_readl_cycles, + .mask = CLOCKSOURCE_MASK(16), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + + +/** + * xttcpss_set_next_event - Sets the time interval for next event + * + * @cycles: Timer interval ticks + * @evt: Address of clock event instance + * + * returns: Always 0 - success + **/ +static int xttcpss_set_next_event(unsigned long cycles, + struct clock_event_device *evt) +{ + struct xttcpss_timer *timer = &timers[XTTCPSS_CLOCKEVENT]; + + xttcpss_set_interval(timer, cycles); + return 0; +} + +/** + * xttcpss_set_mode - Sets the mode of timer + * + * @mode: Mode to be set + * @evt: Address of clock event instance + **/ +static void xttcpss_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + struct xttcpss_timer *timer = &timers[XTTCPSS_CLOCKEVENT]; + u32 ctrl_reg; + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + xttcpss_set_interval(timer, TIMER_RATE / HZ); + break; + case CLOCK_EVT_MODE_ONESHOT: + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + ctrl_reg = __raw_readl(timer->base_addr + + XTTCPSS_CNT_CNTRL_OFFSET); + ctrl_reg |= XTTCPSS_CNT_CNTRL_DISABLE_MASK; + __raw_writel(ctrl_reg, + timer->base_addr + XTTCPSS_CNT_CNTRL_OFFSET); + break; + case CLOCK_EVT_MODE_RESUME: + ctrl_reg = __raw_readl(timer->base_addr + + XTTCPSS_CNT_CNTRL_OFFSET); + ctrl_reg &= ~XTTCPSS_CNT_CNTRL_DISABLE_MASK; + __raw_writel(ctrl_reg, + timer->base_addr + XTTCPSS_CNT_CNTRL_OFFSET); + break; + } +} + +/* + * Instantiate and initialize the clock event structure + */ +static struct clock_event_device xttcpss_clockevent = { + .name = "xttcpss_timer2", + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_next_event = xttcpss_set_next_event, + .set_mode = xttcpss_set_mode, + .rating = 200, +}; + +/** + * xttcpss_timer_init - Initialize the timer + * + * Initializes the timer hardware and register the clock source and clock event + * timers with Linux kernal timer framework + **/ +static void __init xttcpss_timer_init(void) +{ + xttcpss_timer_hardware_init(); + clocksource_register_hz(&clocksource_xttcpss, TIMER_RATE); + + /* Calculate the parameters to allow the clockevent to operate using + integer math + */ + clockevents_calc_mult_shift(&xttcpss_clockevent, TIMER_RATE, 4); + + xttcpss_clockevent.max_delta_ns = + clockevent_delta2ns(0xfffe, &xttcpss_clockevent); + xttcpss_clockevent.min_delta_ns = + clockevent_delta2ns(1, &xttcpss_clockevent); + + /* Indicate that clock event is on 1st CPU as SMP boot needs it */ + + xttcpss_clockevent.cpumask = cpumask_of(0); + clockevents_register_device(&xttcpss_clockevent); +} + +/* + * Instantiate and initialize the system timer structure + */ +struct sys_timer xttcpss_sys_timer = { + .init = xttcpss_timer_init, +}; diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 0074b8dba793..f0469823faaa 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -821,7 +821,7 @@ config CACHE_L2X0 depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || \ REALVIEW_EB_A9MP || SOC_IMX35 || SOC_IMX31 || MACH_REALVIEW_PBX || \ ARCH_NOMADIK || ARCH_OMAP4 || ARCH_EXYNOS4 || ARCH_TEGRA || \ - ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || ARCH_SHMOBILE + ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || ARCH_SHMOBILE || ARCH_ZYNQ default y select OUTER_CACHE select OUTER_CACHE_SYNC From 3d64b4496f5fd90618106555344205a522178c0c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 7 Jul 2011 11:35:20 +0000 Subject: [PATCH 02/10] ARM: Xilinx: merge board file into main platform code The zynq platform will never have board files other than the device tree one, so there is no point splitting it from common.c. This makes the code more compact. Signed-off-by: Arnd Bergmann Acked-by: John Linn --- arch/arm/mach-zynq/board_dt.c | 37 ----------------------------------- arch/arm/mach-zynq/common.c | 22 ++++++++++++++++++--- arch/arm/mach-zynq/common.h | 5 ----- 3 files changed, 19 insertions(+), 45 deletions(-) diff --git a/arch/arm/mach-zynq/board_dt.c b/arch/arm/mach-zynq/board_dt.c index 5b4710d09258..e69de29bb2d1 100644 --- a/arch/arm/mach-zynq/board_dt.c +++ b/arch/arm/mach-zynq/board_dt.c @@ -1,37 +0,0 @@ -/* - * This file contains code for boards with device tree support. - * - * Copyright (C) 2011 Xilinx - * - * based on arch/arm/mach-realview/core.c - * - * Copyright (C) 1999 - 2003 ARM Limited - * Copyright (C) 2000 Deep Blue Solutions Ltd - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - */ - -#include -#include -#include -#include "common.h" - -static const char *xilinx_dt_match[] = { - "xlnx,zynq-ep107", - NULL -}; - -MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform") - .map_io = xilinx_map_io, - .init_irq = xilinx_irq_init, - .init_machine = xilinx_init_machine, - .timer = &xttcpss_sys_timer, - .dt_compat = xilinx_dt_match, -MACHINE_END diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c index b3ac5c2e12dc..73e93687b81a 100644 --- a/arch/arm/mach-zynq/common.c +++ b/arch/arm/mach-zynq/common.c @@ -21,8 +21,11 @@ #include #include #include +#include +#include #include +#include #include #include #include @@ -40,7 +43,7 @@ static struct of_device_id zynq_of_bus_ids[] __initdata = { * xilinx_init_machine() - System specific initialization, intended to be * called from board specific initialization. */ -void __init xilinx_init_machine(void) +static void __init xilinx_init_machine(void) { #ifdef CONFIG_CACHE_L2X0 /* @@ -55,7 +58,7 @@ void __init xilinx_init_machine(void) /** * xilinx_irq_init() - Interrupt controller initialization for the GIC. */ -void __init xilinx_irq_init(void) +static void __init xilinx_irq_init(void) { gic_init(0, 29, SCU_GIC_DIST_BASE, SCU_GIC_CPU_BASE); } @@ -96,7 +99,20 @@ static struct map_desc io_desc[] __initdata = { /** * xilinx_map_io() - Create memory mappings needed for early I/O. */ -void __init xilinx_map_io(void) +static void __init xilinx_map_io(void) { iotable_init(io_desc, ARRAY_SIZE(io_desc)); } + +static const char *xilinx_dt_match[] = { + "xlnx,zynq-ep107", + NULL +}; + +MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform") + .map_io = xilinx_map_io, + .init_irq = xilinx_irq_init, + .init_machine = xilinx_init_machine, + .timer = &xttcpss_sys_timer, + .dt_compat = xilinx_dt_match, +MACHINE_END diff --git a/arch/arm/mach-zynq/common.h b/arch/arm/mach-zynq/common.h index bca21968f80b..a009644a1555 100644 --- a/arch/arm/mach-zynq/common.h +++ b/arch/arm/mach-zynq/common.h @@ -17,13 +17,8 @@ #ifndef __MACH_ZYNQ_COMMON_H__ #define __MACH_ZYNQ_COMMON_H__ -#include #include -extern void xilinx_init_machine(void); -extern void xilinx_irq_init(void); -extern void xilinx_map_io(void); - extern struct sys_timer xttcpss_sys_timer; #endif From fa54dccddc8f4a53c223d53c56c54c61ea7d2623 Mon Sep 17 00:00:00 2001 From: Aneesh V Date: Sat, 2 Jul 2011 08:00:21 +0530 Subject: [PATCH 03/10] OMAP: ID: introduce chip detection for OMAP4460 Add support for detecting the latest in the OMAP4 family: OMAP4460 Among other changes, the new chip also can support 1.5GHz A9s, 1080p stereoscopic 3D and 12 MP stereo (dual camera). In addition, we have changes to OPPs supported, clock tree etc, hence having a chip detection is required. For more details on OMAP4460, see Highlights: http://focus.ti.com/general/docs/wtbu/wtbuproductcontent.tsp?contentId=53243&navigationId=12843&templateId=6123 Public TRM is available here as usual: http://focus.ti.com/general/docs/wtbu/wtbudocumentcenter.tsp?templateId=6123&navigationId=12667 [nm@ti.com: cleanups and introduction of ramp system] Signed-off-by: Nishanth Menon Signed-off-by: Aneesh V Signed-off-by: Rajendra Nayak Reviewed-by: Kevin Hilman Reviewed-by: Paul Walmsley [tony@atomide.com: updated to not use CHIP_IS_OMAP44XX] Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/id.c | 13 +++++++++++-- arch/arm/plat-omap/include/plat/cpu.h | 12 +++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c index 2537090aa33a..743889a25e4b 100644 --- a/arch/arm/mach-omap2/id.c +++ b/arch/arm/mach-omap2/id.c @@ -344,10 +344,10 @@ static void __init omap4_check_revision(void) rev = (idcode >> 28) & 0xf; /* - * Few initial ES2.0 samples IDCODE is same as ES1.0 + * Few initial 4430 ES2.0 samples IDCODE is same as ES1.0 * Use ARM register to detect the correct ES version */ - if (!rev) { + if (!rev && (hawkeye != 0xb94e)) { idcode = read_cpuid(CPUID_ID); rev = (idcode & 0xf) - 1; } @@ -377,6 +377,15 @@ static void __init omap4_check_revision(void) omap_chip.oc |= CHIP_IS_OMAP4430ES2_2; } break; + case 0xb94e: + switch (rev) { + case 0: + default: + omap_revision = OMAP4460_REV_ES1_0; + omap_chip.oc |= CHIP_IS_OMAP4460ES1_0; + break; + } + break; default: /* Unknown default to latest silicon rev as default */ omap_revision = OMAP4430_REV_ES2_2; diff --git a/arch/arm/plat-omap/include/plat/cpu.h b/arch/arm/plat-omap/include/plat/cpu.h index 8198bb6cdb5e..a2cec9970fda 100644 --- a/arch/arm/plat-omap/include/plat/cpu.h +++ b/arch/arm/plat-omap/include/plat/cpu.h @@ -88,6 +88,7 @@ unsigned int omap_rev(void); * cpu_is_omap243x(): True for OMAP2430 * cpu_is_omap343x(): True for OMAP3430 * cpu_is_omap443x(): True for OMAP4430 + * cpu_is_omap446x(): True for OMAP4460 */ #define GET_OMAP_CLASS (omap_rev() & 0xff) @@ -123,6 +124,7 @@ IS_OMAP_SUBCLASS(243x, 0x243) IS_OMAP_SUBCLASS(343x, 0x343) IS_OMAP_SUBCLASS(363x, 0x363) IS_OMAP_SUBCLASS(443x, 0x443) +IS_OMAP_SUBCLASS(446x, 0x446) IS_TI_SUBCLASS(816x, 0x816) @@ -137,6 +139,7 @@ IS_TI_SUBCLASS(816x, 0x816) #define cpu_is_ti816x() 0 #define cpu_is_omap44xx() 0 #define cpu_is_omap443x() 0 +#define cpu_is_omap446x() 0 #if defined(MULTI_OMAP1) # if defined(CONFIG_ARCH_OMAP730) @@ -361,8 +364,10 @@ IS_OMAP_TYPE(3517, 0x3517) # if defined(CONFIG_ARCH_OMAP4) # undef cpu_is_omap44xx # undef cpu_is_omap443x +# undef cpu_is_omap446x # define cpu_is_omap44xx() is_omap44xx() # define cpu_is_omap443x() is_omap443x() +# define cpu_is_omap446x() is_omap446x() # endif /* Macros to detect if we have OMAP1 or OMAP2 */ @@ -410,6 +415,9 @@ IS_OMAP_TYPE(3517, 0x3517) #define OMAP4430_REV_ES2_1 (OMAP443X_CLASS | (0x21 << 8)) #define OMAP4430_REV_ES2_2 (OMAP443X_CLASS | (0x22 << 8)) +#define OMAP446X_CLASS 0x44600044 +#define OMAP4460_REV_ES1_0 (OMAP446X_CLASS | (0x10 << 8)) + /* * omap_chip bits * @@ -439,13 +447,15 @@ IS_OMAP_TYPE(3517, 0x3517) #define CHIP_IS_OMAP4430ES2_1 (1 << 12) #define CHIP_IS_OMAP4430ES2_2 (1 << 13) #define CHIP_IS_TI816X (1 << 14) +#define CHIP_IS_OMAP4460ES1_0 (1 << 15) #define CHIP_IS_OMAP24XX (CHIP_IS_OMAP2420 | CHIP_IS_OMAP2430) #define CHIP_IS_OMAP4430 (CHIP_IS_OMAP4430ES1 | \ CHIP_IS_OMAP4430ES2 | \ CHIP_IS_OMAP4430ES2_1 | \ - CHIP_IS_OMAP4430ES2_2) + CHIP_IS_OMAP4430ES2_2 | \ + CHIP_IS_OMAP4460ES1_0) /* * "GE" here represents "greater than or equal to" in terms of ES From cc0170b2d929b8a31fec3da66a132822a99f550b Mon Sep 17 00:00:00 2001 From: Aneesh V Date: Sat, 2 Jul 2011 08:00:22 +0530 Subject: [PATCH 04/10] OMAP4: ID: add omap_has_feature for max freq supported Macros for identifying the max frequency supported by various OMAP4 variants - Expanding along the lines of OMAP3's feature handling. [nm@ti.com: minor fixes for checks that should only for 443x|446x] Signed-off-by: Nishanth Menon Signed-off-by: Aneesh V Signed-off-by: Rajendra Nayak Reviewed-by: Kevin Hilman Reviewed-by: Paul Walmsley Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/id.c | 40 ++++++++++++++++++++++----- arch/arm/plat-omap/include/plat/cpu.h | 23 +++++++++++++-- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c index 743889a25e4b..37efb8696927 100644 --- a/arch/arm/mach-omap2/id.c +++ b/arch/arm/mach-omap2/id.c @@ -31,7 +31,7 @@ static struct omap_chip_id omap_chip; static unsigned int omap_revision; -u32 omap3_features; +u32 omap_features; unsigned int omap_rev(void) { @@ -183,14 +183,14 @@ static void __init omap24xx_check_revision(void) #define OMAP3_CHECK_FEATURE(status,feat) \ if (((status & OMAP3_ ##feat## _MASK) \ >> OMAP3_ ##feat## _SHIFT) != FEAT_ ##feat## _NONE) { \ - omap3_features |= OMAP3_HAS_ ##feat; \ + omap_features |= OMAP3_HAS_ ##feat; \ } static void __init omap3_check_features(void) { u32 status; - omap3_features = 0; + omap_features = 0; status = omap_ctrl_readl(OMAP3_CONTROL_OMAP_STATUS); @@ -200,11 +200,11 @@ static void __init omap3_check_features(void) OMAP3_CHECK_FEATURE(status, NEON); OMAP3_CHECK_FEATURE(status, ISP); if (cpu_is_omap3630()) - omap3_features |= OMAP3_HAS_192MHZ_CLK; + omap_features |= OMAP3_HAS_192MHZ_CLK; if (!cpu_is_omap3505() && !cpu_is_omap3517()) - omap3_features |= OMAP3_HAS_IO_WAKEUP; + omap_features |= OMAP3_HAS_IO_WAKEUP; - omap3_features |= OMAP3_HAS_SDRC; + omap_features |= OMAP3_HAS_SDRC; /* * TODO: Get additional info (where applicable) @@ -212,9 +212,34 @@ static void __init omap3_check_features(void) */ } +static void __init omap4_check_features(void) +{ + u32 si_type; + + if (cpu_is_omap443x()) + omap_features |= OMAP4_HAS_MPU_1GHZ; + + + if (cpu_is_omap446x()) { + si_type = + read_tap_reg(OMAP4_CTRL_MODULE_CORE_STD_FUSE_PROD_ID_1); + switch ((si_type & (3 << 16)) >> 16) { + case 2: + /* High performance device */ + omap_features |= OMAP4_HAS_MPU_1_5GHZ; + break; + case 1: + default: + /* Standard device */ + omap_features |= OMAP4_HAS_MPU_1_2GHZ; + break; + } + } +} + static void __init ti816x_check_features(void) { - omap3_features = OMAP3_HAS_NEON; + omap_features = OMAP3_HAS_NEON; } static void __init omap3_check_revision(void) @@ -527,6 +552,7 @@ void __init omap2_check_revision(void) return; } else if (cpu_is_omap44xx()) { omap4_check_revision(); + omap4_check_features(); return; } else { pr_err("OMAP revision unknown, please fix!\n"); diff --git a/arch/arm/plat-omap/include/plat/cpu.h b/arch/arm/plat-omap/include/plat/cpu.h index a2cec9970fda..67b3d75884cd 100644 --- a/arch/arm/plat-omap/include/plat/cpu.h +++ b/arch/arm/plat-omap/include/plat/cpu.h @@ -478,7 +478,7 @@ void omap2_check_revision(void); /* * Runtime detection of OMAP3 features */ -extern u32 omap3_features; +extern u32 omap_features; #define OMAP3_HAS_L2CACHE BIT(0) #define OMAP3_HAS_IVA BIT(1) @@ -488,11 +488,15 @@ extern u32 omap3_features; #define OMAP3_HAS_192MHZ_CLK BIT(5) #define OMAP3_HAS_IO_WAKEUP BIT(6) #define OMAP3_HAS_SDRC BIT(7) +#define OMAP4_HAS_MPU_1GHZ BIT(8) +#define OMAP4_HAS_MPU_1_2GHZ BIT(9) +#define OMAP4_HAS_MPU_1_5GHZ BIT(10) + #define OMAP3_HAS_FEATURE(feat,flag) \ static inline unsigned int omap3_has_ ##feat(void) \ { \ - return (omap3_features & OMAP3_HAS_ ##flag); \ + return omap_features & OMAP3_HAS_ ##flag; \ } \ OMAP3_HAS_FEATURE(l2cache, L2CACHE) @@ -504,4 +508,19 @@ OMAP3_HAS_FEATURE(192mhz_clk, 192MHZ_CLK) OMAP3_HAS_FEATURE(io_wakeup, IO_WAKEUP) OMAP3_HAS_FEATURE(sdrc, SDRC) +/* + * Runtime detection of OMAP4 features + */ +extern u32 omap_features; + +#define OMAP4_HAS_FEATURE(feat, flag) \ +static inline unsigned int omap4_has_ ##feat(void) \ +{ \ + return omap_features & OMAP4_HAS_ ##flag; \ +} \ + +OMAP4_HAS_FEATURE(mpu_1ghz, MPU_1GHZ) +OMAP4_HAS_FEATURE(mpu_1_2ghz, MPU_1_2GHZ) +OMAP4_HAS_FEATURE(mpu_1_5ghz, MPU_1_5GHZ) + #endif From 6b54b4991289762887a572785e296d15adbc1550 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Sat, 2 Jul 2011 08:00:23 +0530 Subject: [PATCH 05/10] OMAP4: PRCM: OMAP4460 specific PRM and CM register bitshifts This patch adds additional register bitshifts for registers added in OMAP4460 platform. Signed-off-by: Rajendra Nayak Signed-off-by: Nishanth Menon Signed-off-by: Benoit Cousson Reviewed-by: Kevin Hilman Acked-by: Paul Walmsley [tony@atomide.com: updated to apply on cleanup patches] Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/cm-regbits-44xx.h | 36 ++++++++++++++++++++++++++ arch/arm/mach-omap2/prm-regbits-44xx.h | 8 ++++++ 2 files changed, 44 insertions(+) diff --git a/arch/arm/mach-omap2/cm-regbits-44xx.h b/arch/arm/mach-omap2/cm-regbits-44xx.h index 9d47a05b17b4..28e20d3a9f77 100644 --- a/arch/arm/mach-omap2/cm-regbits-44xx.h +++ b/arch/arm/mach-omap2/cm-regbits-44xx.h @@ -106,6 +106,10 @@ #define OMAP4430_CLKACTIVITY_CORE_DPLL_EMU_CLK_SHIFT 9 #define OMAP4430_CLKACTIVITY_CORE_DPLL_EMU_CLK_MASK (1 << 9) +/* Used by CM_L4CFG_CLKSTCTRL */ +#define OMAP4460_CLKACTIVITY_CORE_TS_GFCLK_SHIFT 9 +#define OMAP4460_CLKACTIVITY_CORE_TS_GFCLK_MASK (1 << 9) + /* Used by CM_CEFUSE_CLKSTCTRL */ #define OMAP4430_CLKACTIVITY_CUST_EFUSE_SYS_CLK_SHIFT 9 #define OMAP4430_CLKACTIVITY_CUST_EFUSE_SYS_CLK_MASK (1 << 9) @@ -418,6 +422,10 @@ #define OMAP4430_CLKACTIVITY_WKUP_32K_GFCLK_SHIFT 11 #define OMAP4430_CLKACTIVITY_WKUP_32K_GFCLK_MASK (1 << 11) +/* Used by CM_WKUP_CLKSTCTRL */ +#define OMAP4460_CLKACTIVITY_WKUP_TS_GFCLK_SHIFT 13 +#define OMAP4460_CLKACTIVITY_WKUP_TS_GFCLK_MASK (1 << 13) + /* * Used by CM1_ABE_TIMER5_CLKCTRL, CM1_ABE_TIMER6_CLKCTRL, * CM1_ABE_TIMER7_CLKCTRL, CM1_ABE_TIMER8_CLKCTRL, CM_L3INIT_MMC1_CLKCTRL, @@ -449,6 +457,10 @@ #define OMAP4430_CLKSEL_60M_SHIFT 24 #define OMAP4430_CLKSEL_60M_MASK (1 << 24) +/* Used by CM_MPU_MPU_CLKCTRL */ +#define OMAP4460_CLKSEL_ABE_DIV_MODE_SHIFT 25 +#define OMAP4460_CLKSEL_ABE_DIV_MODE_MASK (1 << 25) + /* Used by CM1_ABE_AESS_CLKCTRL */ #define OMAP4430_CLKSEL_AESS_FCLK_SHIFT 24 #define OMAP4430_CLKSEL_AESS_FCLK_MASK (1 << 24) @@ -468,6 +480,10 @@ #define OMAP4430_CLKSEL_DIV_SHIFT 24 #define OMAP4430_CLKSEL_DIV_MASK (1 << 24) +/* Used by CM_MPU_MPU_CLKCTRL */ +#define OMAP4460_CLKSEL_EMIF_DIV_MODE_SHIFT 24 +#define OMAP4460_CLKSEL_EMIF_DIV_MODE_MASK (1 << 24) + /* Used by CM_CAM_FDIF_CLKCTRL */ #define OMAP4430_CLKSEL_FCLK_SHIFT 24 #define OMAP4430_CLKSEL_FCLK_MASK (0x3 << 24) @@ -572,6 +588,14 @@ #define OMAP4430_D2D_STATDEP_SHIFT 18 #define OMAP4430_D2D_STATDEP_MASK (1 << 18) +/* Used by CM_CLKSEL_DPLL_MPU */ +#define OMAP4460_DCC_COUNT_MAX_SHIFT 24 +#define OMAP4460_DCC_COUNT_MAX_MASK (0xff << 24) + +/* Used by CM_CLKSEL_DPLL_MPU */ +#define OMAP4460_DCC_EN_SHIFT 22 +#define OMAP4460_DCC_EN_MASK (1 << 22) + /* * Used by CM_SSC_DELTAMSTEP_DPLL_ABE, CM_SSC_DELTAMSTEP_DPLL_CORE, * CM_SSC_DELTAMSTEP_DPLL_CORE_RESTORE, CM_SSC_DELTAMSTEP_DPLL_DDRPHY, @@ -582,6 +606,10 @@ #define OMAP4430_DELTAMSTEP_SHIFT 0 #define OMAP4430_DELTAMSTEP_MASK (0xfffff << 0) +/* Renamed from DELTAMSTEP Used by CM_SSC_DELTAMSTEP_DPLL_USB */ +#define OMAP4460_DELTAMSTEP_0_20_SHIFT 0 +#define OMAP4460_DELTAMSTEP_0_20_MASK (0x1fffff << 0) + /* Used by CM_SHADOW_FREQ_CONFIG1, CM_SHADOW_FREQ_CONFIG1_RESTORE */ #define OMAP4430_DLL_OVERRIDE_SHIFT 2 #define OMAP4430_DLL_OVERRIDE_MASK (1 << 2) @@ -1204,6 +1232,10 @@ #define OMAP4430_MODULEMODE_SHIFT 0 #define OMAP4430_MODULEMODE_MASK (0x3 << 0) +/* Used by CM_L4CFG_DYNAMICDEP */ +#define OMAP4460_MPU_DYNDEP_SHIFT 19 +#define OMAP4460_MPU_DYNDEP_MASK (1 << 19) + /* Used by CM_DSS_DSS_CLKCTRL */ #define OMAP4430_OPTFCLKEN_48MHZ_CLK_SHIFT 9 #define OMAP4430_OPTFCLKEN_48MHZ_CLK_MASK (1 << 9) @@ -1298,6 +1330,10 @@ #define OMAP4430_OPTFCLKEN_SYS_CLK_SHIFT 10 #define OMAP4430_OPTFCLKEN_SYS_CLK_MASK (1 << 10) +/* Used by CM_WKUP_BANDGAP_CLKCTRL */ +#define OMAP4460_OPTFCLKEN_TS_FCLK_SHIFT 8 +#define OMAP4460_OPTFCLKEN_TS_FCLK_MASK (1 << 8) + /* Used by CM_DSS_DSS_CLKCTRL */ #define OMAP4430_OPTFCLKEN_TV_CLK_SHIFT 11 #define OMAP4430_OPTFCLKEN_TV_CLK_MASK (1 << 11) diff --git a/arch/arm/mach-omap2/prm-regbits-44xx.h b/arch/arm/mach-omap2/prm-regbits-44xx.h index 6d2776f6fc08..3cb247bebdaa 100644 --- a/arch/arm/mach-omap2/prm-regbits-44xx.h +++ b/arch/arm/mach-omap2/prm-regbits-44xx.h @@ -283,6 +283,14 @@ #define OMAP4430_DUCATI_UNICACHE_STATEST_SHIFT 10 #define OMAP4430_DUCATI_UNICACHE_STATEST_MASK (0x3 << 10) +/* Used by PRM_DEVICE_OFF_CTRL */ +#define OMAP4460_EMIF1_OFFWKUP_DISABLE_SHIFT 8 +#define OMAP4460_EMIF1_OFFWKUP_DISABLE_MASK (1 << 8) + +/* Used by PRM_DEVICE_OFF_CTRL */ +#define OMAP4460_EMIF2_OFFWKUP_DISABLE_SHIFT 9 +#define OMAP4460_EMIF2_OFFWKUP_DISABLE_MASK (1 << 9) + /* Used by RM_MPU_RSTST */ #define OMAP4430_EMULATION_RST_SHIFT 0 #define OMAP4430_EMULATION_RST_MASK (1 << 0) From 257d643d7d7cd81075b6dee88cfba14f773805c7 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Sat, 2 Jul 2011 08:00:24 +0530 Subject: [PATCH 06/10] OMAP4: clocks: Update the clock tree with 4460 clock nodes Add the new clock nodes (bandgap_ts_fclk, div_ts_ck) for omap4460. Handle these nodes using the clock flags (CK_*). Signed-off-by: Rajendra Nayak Signed-off-by: Nishanth Menon Signed-off-by: Benoit Cousson Reviewed-by: Kevin Hilman Acked-by: Paul Walmsley Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/clock44xx_data.c | 39 +++++++++++++++++++ arch/arm/plat-omap/include/plat/clkdev_omap.h | 1 + arch/arm/plat-omap/include/plat/clock.h | 2 + 3 files changed, 42 insertions(+) diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c index 8c965671b4d4..639e00e0eac2 100644 --- a/arch/arm/mach-omap2/clock44xx_data.c +++ b/arch/arm/mach-omap2/clock44xx_data.c @@ -1486,6 +1486,40 @@ static struct clk dss_dss_clk = { .recalc = &followparent_recalc, }; +static const struct clksel_rate div3_8to32_rates[] = { + { .div = 8, .val = 0, .flags = RATE_IN_44XX }, + { .div = 16, .val = 1, .flags = RATE_IN_44XX }, + { .div = 32, .val = 2, .flags = RATE_IN_44XX }, + { .div = 0 }, +}; + +static const struct clksel div_ts_div[] = { + { .parent = &l4_wkup_clk_mux_ck, .rates = div3_8to32_rates }, + { .parent = NULL }, +}; + +static struct clk div_ts_ck = { + .name = "div_ts_ck", + .parent = &l4_wkup_clk_mux_ck, + .clksel = div_ts_div, + .clksel_reg = OMAP4430_CM_WKUP_BANDGAP_CLKCTRL, + .clksel_mask = OMAP4430_CLKSEL_24_25_MASK, + .ops = &clkops_null, + .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate, + .set_rate = &omap2_clksel_set_rate, +}; + +static struct clk bandgap_ts_fclk = { + .name = "bandgap_ts_fclk", + .ops = &clkops_omap2_dflt, + .enable_reg = OMAP4430_CM_WKUP_BANDGAP_CLKCTRL, + .enable_bit = OMAP4460_OPTFCLKEN_TS_FCLK_SHIFT, + .clkdm_name = "l4_wkup_clkdm", + .parent = &div_ts_ck, + .recalc = &followparent_recalc, +}; + static struct clk dss_48mhz_clk = { .name = "dss_48mhz_clk", .ops = &clkops_omap2_dflt, @@ -3110,7 +3144,9 @@ static struct omap_clk omap44xx_clks[] = { CLK(NULL, "aes2_fck", &aes2_fck, CK_443X), CLK(NULL, "aess_fck", &aess_fck, CK_443X), CLK(NULL, "bandgap_fclk", &bandgap_fclk, CK_443X), + CLK(NULL, "bandgap_ts_fclk", &bandgap_ts_fclk, CK_446X), CLK(NULL, "des3des_fck", &des3des_fck, CK_443X), + CLK(NULL, "div_ts_ck", &div_ts_ck, CK_446X), CLK(NULL, "dmic_sync_mux_ck", &dmic_sync_mux_ck, CK_443X), CLK(NULL, "dmic_fck", &dmic_fck, CK_443X), CLK(NULL, "dsp_fck", &dsp_fck, CK_443X), @@ -3293,6 +3329,9 @@ int __init omap4xxx_clk_init(void) if (cpu_is_omap44xx()) { cpu_mask = RATE_IN_4430; cpu_clkflg = CK_443X; + } else if (cpu_is_omap446x()) { + cpu_mask = RATE_IN_4460; + cpu_clkflg = CK_446X; } clk_init(&omap2_clk_functions); diff --git a/arch/arm/plat-omap/include/plat/clkdev_omap.h b/arch/arm/plat-omap/include/plat/clkdev_omap.h index f1899a3e4174..387a9638991b 100644 --- a/arch/arm/plat-omap/include/plat/clkdev_omap.h +++ b/arch/arm/plat-omap/include/plat/clkdev_omap.h @@ -39,6 +39,7 @@ struct omap_clk { #define CK_36XX (1 << 10) /* 36xx/37xx-specific clocks */ #define CK_443X (1 << 11) #define CK_TI816X (1 << 12) +#define CK_446X (1 << 13) #define CK_34XX (CK_3430ES1 | CK_3430ES2PLUS) diff --git a/arch/arm/plat-omap/include/plat/clock.h b/arch/arm/plat-omap/include/plat/clock.h index 006e599c6613..21b1beb23e5e 100644 --- a/arch/arm/plat-omap/include/plat/clock.h +++ b/arch/arm/plat-omap/include/plat/clock.h @@ -58,10 +58,12 @@ struct clkops { #define RATE_IN_36XX (1 << 4) #define RATE_IN_4430 (1 << 5) #define RATE_IN_TI816X (1 << 6) +#define RATE_IN_4460 (1 << 7) #define RATE_IN_24XX (RATE_IN_242X | RATE_IN_243X) #define RATE_IN_34XX (RATE_IN_3430ES1 | RATE_IN_3430ES2PLUS) #define RATE_IN_3XXX (RATE_IN_34XX | RATE_IN_36XX) +#define RATE_IN_44XX (RATE_IN_4430 | RATE_IN_4460) /* RATE_IN_3430ES2PLUS_36XX includes 34xx/35xx with ES >=2, and all 36xx/37xx */ #define RATE_IN_3430ES2PLUS_36XX (RATE_IN_3430ES2PLUS | RATE_IN_36XX) From 02c981c07bc95ac1e42ec6c817f0c28cf3fe993a Mon Sep 17 00:00:00 2001 From: Binghua Duan Date: Fri, 8 Jul 2011 17:40:12 +0800 Subject: [PATCH 07/10] ARM: CSR: Adding CSR SiRFprimaII board support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SiRFprimaII is the latest generation application processor from CSR’s Multifunction SoC product family. Designed around an ARM cortex A9 core, high-speed memory bus, advanced 3D accelerator and full-HD multi-format video decoder, SiRFprimaII is able to meet the needs of complicated applications for modern multifunction devices that require heavy concurrent applications and fluid user experience. Integrated with GPS baseband, analog and PMU, this new platform is designed to provide a cost effective solution for Automotive and Consumer markets. This patch adds the basic support for this SoC and EVB board based on device tree. It is following the ZYNQ of Xilinx in some degree. Signed-off-by: Binghua Duan Signed-off-by: Rongjun Ying Signed-off-by: Zhiwu Song Signed-off-by: Yuping Luo Signed-off-by: Bin Shi Signed-off-by: Huayi Li Signed-off-by: Barry Song Reviewed-by: Arnd Bergmann --- .../devicetree/bindings/arm/sirf.txt | 3 + arch/arm/Kconfig | 14 + arch/arm/Makefile | 1 + arch/arm/boot/dts/prima2-cb.dts | 416 ++++++++++++++ arch/arm/mach-prima2/Makefile | 5 + arch/arm/mach-prima2/Makefile.boot | 3 + arch/arm/mach-prima2/clock.c | 509 ++++++++++++++++++ arch/arm/mach-prima2/common.h | 20 + arch/arm/mach-prima2/include/mach/clkdev.h | 15 + .../mach-prima2/include/mach/debug-macro.S | 29 + .../mach-prima2/include/mach/entry-macro.S | 29 + arch/arm/mach-prima2/include/mach/hardware.h | 15 + arch/arm/mach-prima2/include/mach/io.h | 16 + arch/arm/mach-prima2/include/mach/irqs.h | 17 + arch/arm/mach-prima2/include/mach/map.h | 16 + arch/arm/mach-prima2/include/mach/memory.h | 21 + arch/arm/mach-prima2/include/mach/system.h | 29 + arch/arm/mach-prima2/include/mach/timex.h | 14 + arch/arm/mach-prima2/include/mach/uart.h | 23 + .../arm/mach-prima2/include/mach/uncompress.h | 40 ++ arch/arm/mach-prima2/include/mach/vmalloc.h | 16 + arch/arm/mach-prima2/irq.c | 71 +++ arch/arm/mach-prima2/prima2.c | 40 ++ arch/arm/mach-prima2/rstc.c | 69 +++ arch/arm/mach-prima2/timer.c | 217 ++++++++ arch/arm/mm/Kconfig | 2 +- 26 files changed, 1649 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/arm/sirf.txt create mode 100644 arch/arm/boot/dts/prima2-cb.dts create mode 100644 arch/arm/mach-prima2/Makefile create mode 100644 arch/arm/mach-prima2/Makefile.boot create mode 100644 arch/arm/mach-prima2/clock.c create mode 100644 arch/arm/mach-prima2/common.h create mode 100644 arch/arm/mach-prima2/include/mach/clkdev.h create mode 100644 arch/arm/mach-prima2/include/mach/debug-macro.S create mode 100644 arch/arm/mach-prima2/include/mach/entry-macro.S create mode 100644 arch/arm/mach-prima2/include/mach/hardware.h create mode 100644 arch/arm/mach-prima2/include/mach/io.h create mode 100644 arch/arm/mach-prima2/include/mach/irqs.h create mode 100644 arch/arm/mach-prima2/include/mach/map.h create mode 100644 arch/arm/mach-prima2/include/mach/memory.h create mode 100644 arch/arm/mach-prima2/include/mach/system.h create mode 100644 arch/arm/mach-prima2/include/mach/timex.h create mode 100644 arch/arm/mach-prima2/include/mach/uart.h create mode 100644 arch/arm/mach-prima2/include/mach/uncompress.h create mode 100644 arch/arm/mach-prima2/include/mach/vmalloc.h create mode 100644 arch/arm/mach-prima2/irq.c create mode 100644 arch/arm/mach-prima2/prima2.c create mode 100644 arch/arm/mach-prima2/rstc.c create mode 100644 arch/arm/mach-prima2/timer.c diff --git a/Documentation/devicetree/bindings/arm/sirf.txt b/Documentation/devicetree/bindings/arm/sirf.txt new file mode 100644 index 000000000000..6b07f65b32de --- /dev/null +++ b/Documentation/devicetree/bindings/arm/sirf.txt @@ -0,0 +1,3 @@ +prima2 "cb" evalutation board +Required root node properties: + - compatible = "sirf,prima2-cb", "sirf,prima2"; diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9adc278a22ab..aa6c91d0d794 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -879,6 +879,20 @@ config ARCH_VT8500 select HAVE_PWM help Support for VIA/WonderMedia VT8500/WM85xx System-on-Chip. + +config ARCH_PRIMA2 + bool "CSR SiRFSoC PRIMA2 ARM Cortex A9 Platform" + select CPU_V7 + select GENERIC_TIME + select NO_IOPORT + select GENERIC_CLOCKEVENTS + select CLKDEV_LOOKUP + select GENERIC_IRQ_CHIP + select USE_OF + select ZONE_DMA + help + Support for CSR SiRFSoC ARM Cortex A9 Platform + endchoice # diff --git a/arch/arm/Makefile b/arch/arm/Makefile index f5b2b390c8f2..1d693d06257e 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -169,6 +169,7 @@ machine-$(CONFIG_ARCH_OMAP3) := omap2 machine-$(CONFIG_ARCH_OMAP4) := omap2 machine-$(CONFIG_ARCH_ORION5X) := orion5x machine-$(CONFIG_ARCH_PNX4008) := pnx4008 +machine-$(CONFIG_ARCH_PRIMA2) := prima2 machine-$(CONFIG_ARCH_PXA) := pxa machine-$(CONFIG_ARCH_REALVIEW) := realview machine-$(CONFIG_ARCH_RPC) := rpc diff --git a/arch/arm/boot/dts/prima2-cb.dts b/arch/arm/boot/dts/prima2-cb.dts new file mode 100644 index 000000000000..6fecc88065b2 --- /dev/null +++ b/arch/arm/boot/dts/prima2-cb.dts @@ -0,0 +1,416 @@ +/dts-v1/; +/ { + model = "SiRF Prima2 eVB"; + compatible = "sirf,prima2-cb", "sirf,prima2"; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&intc>; + + memory { + reg = <0x00000000 0x20000000>; + }; + + chosen { + bootargs = "mem=512M real_root=/dev/mmcblk0p2 console=ttyS0 panel=1 bootsplash=true bpp=16 androidboot.console=ttyS1"; + linux,stdout-path = &uart1; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + reg = <0x0>; + d-cache-line-size = <32>; + i-cache-line-size = <32>; + d-cache-size = <32768>; + i-cache-size = <32768>; + /* from bootloader */ + timebase-frequency = <0>; + bus-frequency = <0>; + clock-frequency = <0>; + }; + }; + + axi { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x40000000 0x40000000 0x80000000>; + + l2-cache-controller@80040000 { + compatible = "arm,pl310-cache"; + reg = <0x80040000 0x1000>; + interrupts = <59>; + }; + + intc: interrupt-controller@80020000 { + #interrupt-cells = <1>; + interrupt-controller; + compatible = "sirf,prima2-intc"; + reg = <0x80020000 0x1000>; + }; + + sys-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x88000000 0x88000000 0x40000>; + + clock-controller@88000000 { + compatible = "sirf,prima2-clkc"; + reg = <0x88000000 0x1000>; + interrupts = <3>; + }; + + reset-controller@88010000 { + compatible = "sirf,prima2-rstc"; + reg = <0x88010000 0x1000>; + }; + }; + + mem-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x90000000 0x90000000 0x10000>; + + memory-controller@90000000 { + compatible = "sirf,prima2-memc"; + reg = <0x90000000 0x10000>; + interrupts = <27>; + }; + }; + + disp-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x90010000 0x90010000 0x30000>; + + display@90010000 { + compatible = "sirf,prima2-lcd"; + reg = <0x90010000 0x20000>; + interrupts = <30>; + }; + + vpp@90020000 { + compatible = "sirf,prima2-vpp"; + reg = <0x90020000 0x10000>; + interrupts = <31>; + }; + }; + + graphics-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x98000000 0x98000000 0x8000000>; + + graphics@98000000 { + compatible = "powervr,sgx531"; + reg = <0x98000000 0x8000000>; + interrupts = <6>; + }; + }; + + multimedia-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xa0000000 0xa0000000 0x8000000>; + + multimedia@a0000000 { + compatible = "sirf,prima2-video-codec"; + reg = <0xa0000000 0x8000000>; + interrupts = <5>; + }; + }; + + dsp-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xa8000000 0xa8000000 0x2000000>; + + dspif@a8000000 { + compatible = "sirf,prima2-dspif"; + reg = <0xa8000000 0x10000>; + interrupts = <9>; + }; + + gps@a8010000 { + compatible = "sirf,prima2-gps"; + reg = <0xa8010000 0x10000>; + interrupts = <7>; + }; + + dsp@a9000000 { + compatible = "sirf,prima2-dsp"; + reg = <0xa9000000 0x1000000>; + interrupts = <8>; + }; + }; + + peri-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xb0000000 0xb0000000 0x180000>; + + timer@b0020000 { + compatible = "sirf,prima2-tick"; + reg = <0xb0020000 0x1000>; + interrupts = <0>; + }; + + nand@b0030000 { + compatible = "sirf,prima2-nand"; + reg = <0xb0030000 0x10000>; + interrupts = <41>; + }; + + audio@b0040000 { + compatible = "sirf,prima2-audio"; + reg = <0xb0040000 0x10000>; + interrupts = <35>; + }; + + uart0: uart@b0050000 { + cell-index = <0>; + compatible = "sirf,prima2-uart"; + reg = <0xb0050000 0x10000>; + interrupts = <17>; + }; + + uart1: uart@b0060000 { + cell-index = <1>; + compatible = "sirf,prima2-uart"; + reg = <0xb0060000 0x10000>; + interrupts = <18>; + }; + + uart2: uart@b0070000 { + cell-index = <2>; + compatible = "sirf,prima2-uart"; + reg = <0xb0070000 0x10000>; + interrupts = <19>; + }; + + usp0: usp@b0080000 { + cell-index = <0>; + compatible = "sirf,prima2-usp"; + reg = <0xb0080000 0x10000>; + interrupts = <20>; + }; + + usp1: usp@b0090000 { + cell-index = <1>; + compatible = "sirf,prima2-usp"; + reg = <0xb0090000 0x10000>; + interrupts = <21>; + }; + + usp2: usp@b00a0000 { + cell-index = <2>; + compatible = "sirf,prima2-usp"; + reg = <0xb00a0000 0x10000>; + interrupts = <22>; + }; + + dmac0: dma-controller@b00b0000 { + cell-index = <0>; + compatible = "sirf,prima2-dmac"; + reg = <0xb00b0000 0x10000>; + interrupts = <12>; + }; + + dmac1: dma-controller@b0160000 { + cell-index = <1>; + compatible = "sirf,prima2-dmac"; + reg = <0xb0160000 0x10000>; + interrupts = <13>; + }; + + vip@b00C0000 { + compatible = "sirf,prima2-vip"; + reg = <0xb00C0000 0x10000>; + }; + + spi0: spi@b00d0000 { + cell-index = <0>; + compatible = "sirf,prima2-spi"; + reg = <0xb00d0000 0x10000>; + interrupts = <15>; + }; + + spi1: spi@b0170000 { + cell-index = <1>; + compatible = "sirf,prima2-spi"; + reg = <0xb0170000 0x10000>; + interrupts = <16>; + }; + + i2c0: i2c@b00e0000 { + cell-index = <0>; + compatible = "sirf,prima2-i2c"; + reg = <0xb00e0000 0x10000>; + interrupts = <24>; + }; + + i2c1: i2c@b00f0000 { + cell-index = <1>; + compatible = "sirf,prima2-i2c"; + reg = <0xb00f0000 0x10000>; + interrupts = <25>; + }; + + tsc@b0110000 { + compatible = "sirf,prima2-tsc"; + reg = <0xb0110000 0x10000>; + interrupts = <33>; + }; + + gpio: gpio-controller@b0120000 { + #gpio-cells = <2>; + #interrupt-cells = <2>; + compatible = "sirf,prima2-gpio"; + reg = <0xb0120000 0x10000>; + gpio-controller; + interrupt-controller; + }; + + pwm@b0130000 { + compatible = "sirf,prima2-pwm"; + reg = <0xb0130000 0x10000>; + }; + + efusesys@b0140000 { + compatible = "sirf,prima2-efuse"; + reg = <0xb0140000 0x10000>; + }; + + pulsec@b0150000 { + compatible = "sirf,prima2-pulsec"; + reg = <0xb0150000 0x10000>; + interrupts = <48>; + }; + + pci-iobg { + compatible = "sirf,prima2-pciiobg", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x56000000 0x56000000 0x1b00000>; + + sd0: sdhci@56000000 { + cell-index = <0>; + compatible = "sirf,prima2-sdhc"; + reg = <0x56000000 0x100000>; + interrupts = <38>; + }; + + sd1: sdhci@56100000 { + cell-index = <1>; + compatible = "sirf,prima2-sdhc"; + reg = <0x56100000 0x100000>; + interrupts = <38>; + }; + + sd2: sdhci@56200000 { + cell-index = <2>; + compatible = "sirf,prima2-sdhc"; + reg = <0x56200000 0x100000>; + interrupts = <23>; + }; + + sd3: sdhci@56300000 { + cell-index = <3>; + compatible = "sirf,prima2-sdhc"; + reg = <0x56300000 0x100000>; + interrupts = <23>; + }; + + sd4: sdhci@56400000 { + cell-index = <4>; + compatible = "sirf,prima2-sdhc"; + reg = <0x56400000 0x100000>; + interrupts = <39>; + }; + + sd5: sdhci@56500000 { + cell-index = <5>; + compatible = "sirf,prima2-sdhc"; + reg = <0x56500000 0x100000>; + interrupts = <39>; + }; + + pci-copy@57900000 { + compatible = "sirf,prima2-pcicp"; + reg = <0x57900000 0x100000>; + interrupts = <40>; + }; + + rom-interface@57a00000 { + compatible = "sirf,prima2-romif"; + reg = <0x57a00000 0x100000>; + }; + }; + }; + + rtc-iobg { + compatible = "sirf,prima2-rtciobg", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x80030000 0x10000>; + + gpsrtc@1000 { + compatible = "sirf,prima2-gpsrtc"; + reg = <0x1000 0x1000>; + interrupts = <55 56 57>; + }; + + sysrtc@2000 { + compatible = "sirf,prima2-sysrtc"; + reg = <0x2000 0x1000>; + interrupts = <52 53 54>; + }; + + pwrc@3000 { + compatible = "sirf,prima2-pwrc"; + reg = <0x3000 0x1000>; + interrupts = <32>; + }; + }; + + uus-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xb8000000 0xb8000000 0x40000>; + + usb0: usb@b00e0000 { + compatible = "chipidea,ci13611a-prima2"; + reg = <0xb8000000 0x10000>; + interrupts = <10>; + }; + + usb1: usb@b00f0000 { + compatible = "chipidea,ci13611a-prima2"; + reg = <0xb8010000 0x10000>; + interrupts = <11>; + }; + + sata@b00f0000 { + compatible = "synopsys,dwc-ahsata"; + reg = <0xb8020000 0x10000>; + interrupts = <37>; + }; + + security@b00f0000 { + compatible = "sirf,prima2-security"; + reg = <0xb8030000 0x10000>; + interrupts = <42>; + }; + }; + }; +}; diff --git a/arch/arm/mach-prima2/Makefile b/arch/arm/mach-prima2/Makefile new file mode 100644 index 000000000000..d44f7aedda87 --- /dev/null +++ b/arch/arm/mach-prima2/Makefile @@ -0,0 +1,5 @@ +obj-y := timer.o +obj-y += irq.o +obj-y += clock.o +obj-y += rstc.o +obj-y += prima2.o diff --git a/arch/arm/mach-prima2/Makefile.boot b/arch/arm/mach-prima2/Makefile.boot new file mode 100644 index 000000000000..d023db3ae4ff --- /dev/null +++ b/arch/arm/mach-prima2/Makefile.boot @@ -0,0 +1,3 @@ +zreladdr-y := 0x00008000 +params_phys-y := 0x00000100 +initrd_phys-y := 0x00800000 diff --git a/arch/arm/mach-prima2/clock.c b/arch/arm/mach-prima2/clock.c new file mode 100644 index 000000000000..f9a2aaf63f71 --- /dev/null +++ b/arch/arm/mach-prima2/clock.c @@ -0,0 +1,509 @@ +/* + * Clock tree for CSR SiRFprimaII + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SIRFSOC_CLKC_CLK_EN0 0x0000 +#define SIRFSOC_CLKC_CLK_EN1 0x0004 +#define SIRFSOC_CLKC_REF_CFG 0x0014 +#define SIRFSOC_CLKC_CPU_CFG 0x0018 +#define SIRFSOC_CLKC_MEM_CFG 0x001c +#define SIRFSOC_CLKC_SYS_CFG 0x0020 +#define SIRFSOC_CLKC_IO_CFG 0x0024 +#define SIRFSOC_CLKC_DSP_CFG 0x0028 +#define SIRFSOC_CLKC_GFX_CFG 0x002c +#define SIRFSOC_CLKC_MM_CFG 0x0030 +#define SIRFSOC_LKC_LCD_CFG 0x0034 +#define SIRFSOC_CLKC_MMC_CFG 0x0038 +#define SIRFSOC_CLKC_PLL1_CFG0 0x0040 +#define SIRFSOC_CLKC_PLL2_CFG0 0x0044 +#define SIRFSOC_CLKC_PLL3_CFG0 0x0048 +#define SIRFSOC_CLKC_PLL1_CFG1 0x004c +#define SIRFSOC_CLKC_PLL2_CFG1 0x0050 +#define SIRFSOC_CLKC_PLL3_CFG1 0x0054 +#define SIRFSOC_CLKC_PLL1_CFG2 0x0058 +#define SIRFSOC_CLKC_PLL2_CFG2 0x005c +#define SIRFSOC_CLKC_PLL3_CFG2 0x0060 + +#define SIRFSOC_CLOCK_VA_BASE SIRFSOC_VA(0x005000) + +#define KHZ 1000 +#define MHZ (KHZ * KHZ) + +struct clk_ops { + unsigned long (*get_rate)(struct clk *clk); + long (*round_rate)(struct clk *clk, unsigned long rate); + int (*set_rate)(struct clk *clk, unsigned long rate); + int (*enable)(struct clk *clk); + int (*disable)(struct clk *clk); + struct clk *(*get_parent)(struct clk *clk); + int (*set_parent)(struct clk *clk, struct clk *parent); +}; + +struct clk { + struct clk *parent; /* parent clk */ + unsigned long rate; /* clock rate in Hz */ + signed char usage; /* clock enable count */ + signed char enable_bit; /* enable bit: 0 ~ 63 */ + unsigned short regofs; /* register offset */ + struct clk_ops *ops; /* clock operation */ +}; + +static DEFINE_SPINLOCK(clocks_lock); + +static inline unsigned long clkc_readl(unsigned reg) +{ + return readl(SIRFSOC_CLOCK_VA_BASE + reg); +} + +static inline void clkc_writel(u32 val, unsigned reg) +{ + writel(val, SIRFSOC_CLOCK_VA_BASE + reg); +} + +/* + * osc_rtc - real time oscillator - 32.768KHz + * osc_sys - high speed oscillator - 26MHz + */ + +static struct clk clk_rtc = { + .rate = 32768, +}; + +static struct clk clk_osc = { + .rate = 26 * MHZ, +}; + +/* + * std pll + */ +static unsigned long std_pll_get_rate(struct clk *clk) +{ + unsigned long fin = clk_get_rate(clk->parent); + u32 regcfg2 = clk->regofs + SIRFSOC_CLKC_PLL1_CFG2 - + SIRFSOC_CLKC_PLL1_CFG0; + + if (clkc_readl(regcfg2) & BIT(2)) { + /* pll bypass mode */ + clk->rate = fin; + } else { + /* fout = fin * nf / nr / od */ + u32 cfg0 = clkc_readl(clk->regofs); + u32 nf = (cfg0 & (BIT(13) - 1)) + 1; + u32 nr = ((cfg0 >> 13) & (BIT(6) - 1)) + 1; + u32 od = ((cfg0 >> 19) & (BIT(4) - 1)) + 1; + WARN_ON(fin % MHZ); + clk->rate = fin / MHZ * nf / nr / od * MHZ; + } + + return clk->rate; +} + +static int std_pll_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long fin, nf, nr, od, reg; + + /* + * fout = fin * nf / (nr * od); + * set od = 1, nr = fin/MHz, so fout = nf * MHz + */ + + nf = rate / MHZ; + if (unlikely((rate % MHZ) || nf > BIT(13) || nf < 1)) + return -EINVAL; + + fin = clk_get_rate(clk->parent); + BUG_ON(fin < MHZ); + + nr = fin / MHZ; + BUG_ON((fin % MHZ) || nr > BIT(6)); + + od = 1; + + reg = (nf - 1) | ((nr - 1) << 13) | ((od - 1) << 19); + clkc_writel(reg, clk->regofs); + + reg = clk->regofs + SIRFSOC_CLKC_PLL1_CFG1 - SIRFSOC_CLKC_PLL1_CFG0; + clkc_writel((nf >> 1) - 1, reg); + + reg = clk->regofs + SIRFSOC_CLKC_PLL1_CFG2 - SIRFSOC_CLKC_PLL1_CFG0; + while (!(clkc_readl(reg) & BIT(6))) + cpu_relax(); + + clk->rate = 0; /* set to zero will force recalculation */ + return 0; +} + +static struct clk_ops std_pll_ops = { + .get_rate = std_pll_get_rate, + .set_rate = std_pll_set_rate, +}; + +static struct clk clk_pll1 = { + .parent = &clk_osc, + .regofs = SIRFSOC_CLKC_PLL1_CFG0, + .ops = &std_pll_ops, +}; + +static struct clk clk_pll2 = { + .parent = &clk_osc, + .regofs = SIRFSOC_CLKC_PLL2_CFG0, + .ops = &std_pll_ops, +}; + +static struct clk clk_pll3 = { + .parent = &clk_osc, + .regofs = SIRFSOC_CLKC_PLL3_CFG0, + .ops = &std_pll_ops, +}; + +/* + * clock domains - cpu, mem, sys/io + */ + +static struct clk clk_mem; + +static struct clk *dmn_get_parent(struct clk *clk) +{ + struct clk *clks[] = { + &clk_osc, &clk_rtc, &clk_pll1, &clk_pll2, &clk_pll3 + }; + u32 cfg = clkc_readl(clk->regofs); + WARN_ON((cfg & (BIT(3) - 1)) > 4); + return clks[cfg & (BIT(3) - 1)]; +} + +static int dmn_set_parent(struct clk *clk, struct clk *parent) +{ + const struct clk *clks[] = { + &clk_osc, &clk_rtc, &clk_pll1, &clk_pll2, &clk_pll3 + }; + u32 cfg = clkc_readl(clk->regofs); + int i; + for (i = 0; i < ARRAY_SIZE(clks); i++) { + if (clks[i] == parent) { + cfg &= ~(BIT(3) - 1); + clkc_writel(cfg | i, clk->regofs); + /* BIT(3) - switching status: 1 - busy, 0 - done */ + while (clkc_readl(clk->regofs) & BIT(3)) + cpu_relax(); + return 0; + } + } + return -EINVAL; +} + +static unsigned long dmn_get_rate(struct clk *clk) +{ + unsigned long fin = clk_get_rate(clk->parent); + u32 cfg = clkc_readl(clk->regofs); + if (cfg & BIT(24)) { + /* fcd bypass mode */ + clk->rate = fin; + } else { + /* + * wait count: bit[19:16], hold count: bit[23:20] + */ + u32 wait = (cfg >> 16) & (BIT(4) - 1); + u32 hold = (cfg >> 20) & (BIT(4) - 1); + + clk->rate = fin / (wait + hold + 2); + } + + return clk->rate; +} + +static int dmn_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long fin; + unsigned ratio, wait, hold, reg; + unsigned bits = (clk == &clk_mem) ? 3 : 4; + + fin = clk_get_rate(clk->parent); + ratio = fin / rate; + + if (unlikely(ratio < 2 || ratio > BIT(bits + 1))) + return -EINVAL; + + WARN_ON(fin % rate); + + wait = (ratio >> 1) - 1; + hold = ratio - wait - 2; + + reg = clkc_readl(clk->regofs); + reg &= ~(((BIT(bits) - 1) << 16) | ((BIT(bits) - 1) << 20)); + reg |= (wait << 16) | (hold << 20) | BIT(25); + clkc_writel(reg, clk->regofs); + + /* waiting FCD been effective */ + while (clkc_readl(clk->regofs) & BIT(25)) + cpu_relax(); + + clk->rate = 0; /* set to zero will force recalculation */ + + return 0; +} + +/* + * cpu clock has no FCD register in Prima2, can only change pll + */ +static int cpu_set_rate(struct clk *clk, unsigned long rate) +{ + int ret1, ret2; + struct clk *cur_parent, *tmp_parent; + + cur_parent = dmn_get_parent(clk); + BUG_ON(cur_parent == NULL || cur_parent->usage > 1); + + /* switch to tmp pll before setting parent clock's rate */ + tmp_parent = cur_parent == &clk_pll1 ? &clk_pll2 : &clk_pll1; + ret1 = dmn_set_parent(clk, tmp_parent); + BUG_ON(ret1); + + ret2 = clk_set_rate(cur_parent, rate); + + ret1 = dmn_set_parent(clk, cur_parent); + + clk->rate = 0; /* set to zero will force recalculation */ + + return ret2 ? ret2 : ret1; +} + +static struct clk_ops cpu_ops = { + .get_parent = dmn_get_parent, + .set_parent = dmn_set_parent, + .set_rate = cpu_set_rate, +}; + +static struct clk clk_cpu = { + .parent = &clk_pll1, + .regofs = SIRFSOC_CLKC_CPU_CFG, + .ops = &cpu_ops, +}; + + +static struct clk_ops msi_ops = { + .set_rate = dmn_set_rate, + .get_rate = dmn_get_rate, + .set_parent = dmn_set_parent, + .get_parent = dmn_get_parent, +}; + +static struct clk clk_mem = { + .parent = &clk_pll2, + .regofs = SIRFSOC_CLKC_MEM_CFG, + .ops = &msi_ops, +}; + +static struct clk clk_sys = { + .parent = &clk_pll3, + .regofs = SIRFSOC_CLKC_SYS_CFG, + .ops = &msi_ops, +}; + +static struct clk clk_io = { + .parent = &clk_pll3, + .regofs = SIRFSOC_CLKC_IO_CFG, + .ops = &msi_ops, +}; + +/* + * on-chip clock sets + */ +static struct clk_lookup onchip_clks[] = { + { + .dev_id = "rtc", + .clk = &clk_rtc, + }, { + .dev_id = "osc", + .clk = &clk_osc, + }, { + .dev_id = "pll1", + .clk = &clk_pll1, + }, { + .dev_id = "pll2", + .clk = &clk_pll2, + }, { + .dev_id = "pll3", + .clk = &clk_pll3, + }, { + .dev_id = "cpu", + .clk = &clk_cpu, + }, { + .dev_id = "mem", + .clk = &clk_mem, + }, { + .dev_id = "sys", + .clk = &clk_sys, + }, { + .dev_id = "io", + .clk = &clk_io, + }, +}; + +int clk_enable(struct clk *clk) +{ + unsigned long flags; + + if (unlikely(IS_ERR_OR_NULL(clk))) + return -EINVAL; + + if (clk->parent) + clk_enable(clk->parent); + + spin_lock_irqsave(&clocks_lock, flags); + if (!clk->usage++ && clk->ops && clk->ops->enable) + 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; + + if (unlikely(IS_ERR_OR_NULL(clk))) + return; + + WARN_ON(!clk->usage); + + spin_lock_irqsave(&clocks_lock, flags); + if (--clk->usage == 0 && clk->ops && clk->ops->disable) + clk->ops->disable(clk); + spin_unlock_irqrestore(&clocks_lock, flags); + + if (clk->parent) + clk_disable(clk->parent); +} +EXPORT_SYMBOL(clk_disable); + +unsigned long clk_get_rate(struct clk *clk) +{ + if (unlikely(IS_ERR_OR_NULL(clk))) + return 0; + + if (clk->rate) + return clk->rate; + + if (clk->ops && clk->ops->get_rate) + return clk->ops->get_rate(clk); + + return clk_get_rate(clk->parent); +} +EXPORT_SYMBOL(clk_get_rate); + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + if (unlikely(IS_ERR_OR_NULL(clk))) + return 0; + + if (clk->ops && clk->ops->round_rate) + return clk->ops->round_rate(clk, rate); + + return 0; +} +EXPORT_SYMBOL(clk_round_rate); + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + if (unlikely(IS_ERR_OR_NULL(clk))) + return -EINVAL; + + if (!clk->ops || !clk->ops->set_rate) + return -EINVAL; + + return clk->ops->set_rate(clk, rate); +} +EXPORT_SYMBOL(clk_set_rate); + +int clk_set_parent(struct clk *clk, struct clk *parent) +{ + int ret; + unsigned long flags; + + if (unlikely(IS_ERR_OR_NULL(clk))) + return -EINVAL; + + if (!clk->ops || !clk->ops->set_parent) + return -EINVAL; + + spin_lock_irqsave(&clocks_lock, flags); + ret = clk->ops->set_parent(clk, parent); + if (!ret) { + parent->usage += clk->usage; + clk->parent->usage -= clk->usage; + BUG_ON(clk->parent->usage < 0); + clk->parent = parent; + } + spin_unlock_irqrestore(&clocks_lock, flags); + return ret; +} +EXPORT_SYMBOL(clk_set_parent); + +struct clk *clk_get_parent(struct clk *clk) +{ + unsigned long flags; + + if (unlikely(IS_ERR_OR_NULL(clk))) + return NULL; + + if (!clk->ops || !clk->ops->get_parent) + return clk->parent; + + spin_lock_irqsave(&clocks_lock, flags); + clk->parent = clk->ops->get_parent(clk); + spin_unlock_irqrestore(&clocks_lock, flags); + return clk->parent; +} +EXPORT_SYMBOL(clk_get_parent); + +static void __init sirfsoc_clk_init(void) +{ + clkdev_add_table(onchip_clks, ARRAY_SIZE(onchip_clks)); +} + +static struct of_device_id clkc_ids[] = { + { .compatible = "sirf,prima2-clkc" }, +}; + +void __init sirfsoc_of_clk_init(void) +{ + struct device_node *np; + struct resource res; + struct map_desc sirfsoc_clkc_iodesc = { + .virtual = SIRFSOC_CLOCK_VA_BASE, + .type = MT_DEVICE, + }; + + np = of_find_matching_node(NULL, clkc_ids); + if (!np) + panic("unable to find compatible clkc node in dtb\n"); + + if (of_address_to_resource(np, 0, &res)) + panic("unable to find clkc range in dtb"); + of_node_put(np); + + sirfsoc_clkc_iodesc.pfn = __phys_to_pfn(res.start); + sirfsoc_clkc_iodesc.length = 1 + res.end - res.start; + + iotable_init(&sirfsoc_clkc_iodesc, 1); + + sirfsoc_clk_init(); +} diff --git a/arch/arm/mach-prima2/common.h b/arch/arm/mach-prima2/common.h new file mode 100644 index 000000000000..fa4a3b5c674a --- /dev/null +++ b/arch/arm/mach-prima2/common.h @@ -0,0 +1,20 @@ +/* + * This file contains common function prototypes to avoid externs in the c files. + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef __MACH_PRIMA2_COMMON_H__ +#define __MACH_PRIMA2_COMMON_H__ + +#include +#include + +extern struct sys_timer sirfsoc_timer; + +extern void __init sirfsoc_of_irq_init(void); +extern void __init sirfsoc_of_clk_init(void); + +#endif diff --git a/arch/arm/mach-prima2/include/mach/clkdev.h b/arch/arm/mach-prima2/include/mach/clkdev.h new file mode 100644 index 000000000000..66932518b1b7 --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/clkdev.h @@ -0,0 +1,15 @@ +/* + * arch/arm/mach-prima2/include/mach/clkdev.h + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef __MACH_CLKDEV_H +#define __MACH_CLKDEV_H + +#define __clk_get(clk) ({ 1; }) +#define __clk_put(clk) do { } while (0) + +#endif diff --git a/arch/arm/mach-prima2/include/mach/debug-macro.S b/arch/arm/mach-prima2/include/mach/debug-macro.S new file mode 100644 index 000000000000..bf75106333ff --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/debug-macro.S @@ -0,0 +1,29 @@ +/* + * arch/arm/mach-prima2/include/mach/debug-macro.S + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include +#include + + .macro addruart, rp, rv + ldr \rp, =SIRFSOC_UART1_PA_BASE @ physical + ldr \rv, =SIRFSOC_UART1_VA_BASE @ virtual + .endm + + .macro senduart,rd,rx + str \rd, [\rx, #SIRFSOC_UART_TXFIFO_DATA] + .endm + + .macro busyuart,rd,rx + .endm + + .macro waituart,rd,rx +1001: ldr \rd, [\rx, #SIRFSOC_UART_TXFIFO_STATUS] + tst \rd, #SIRFSOC_UART1_TXFIFO_EMPTY + beq 1001b + .endm + diff --git a/arch/arm/mach-prima2/include/mach/entry-macro.S b/arch/arm/mach-prima2/include/mach/entry-macro.S new file mode 100644 index 000000000000..1c8a50f102a7 --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/entry-macro.S @@ -0,0 +1,29 @@ +/* + * arch/arm/mach-prima2/include/mach/entry-macro.S + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include + +#define SIRFSOC_INT_ID 0x38 + + .macro get_irqnr_preamble, base, tmp + ldr \base, =sirfsoc_intc_base + ldr \base, [\base] + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + ldr \irqnr, [\base, #SIRFSOC_INT_ID] @ Get the highest priority irq + cmp \irqnr, #0x40 @ the irq num can't be larger than 0x3f + movges \irqnr, #0 + .endm + + .macro disable_fiq + .endm + + .macro arch_ret_to_user, tmp1, tmp2 + .endm + diff --git a/arch/arm/mach-prima2/include/mach/hardware.h b/arch/arm/mach-prima2/include/mach/hardware.h new file mode 100644 index 000000000000..105b96964f25 --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/hardware.h @@ -0,0 +1,15 @@ +/* + * arch/arm/mach-prima2/include/mach/hardware.h + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef __MACH_HARDWARE_H__ +#define __MACH_HARDWARE_H__ + +#include +#include + +#endif diff --git a/arch/arm/mach-prima2/include/mach/io.h b/arch/arm/mach-prima2/include/mach/io.h new file mode 100644 index 000000000000..6c31e9ec279e --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/io.h @@ -0,0 +1,16 @@ +/* + * arch/arm/mach-prima2/include/mach/io.h + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef __MACH_PRIMA2_IO_H +#define __MACH_PRIMA2_IO_H + +#define IO_SPACE_LIMIT ((resource_size_t)0) + +#define __mem_pci(a) (a) + +#endif diff --git a/arch/arm/mach-prima2/include/mach/irqs.h b/arch/arm/mach-prima2/include/mach/irqs.h new file mode 100644 index 000000000000..bb354f952fd6 --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/irqs.h @@ -0,0 +1,17 @@ +/* + * arch/arm/mach-prima2/include/mach/irqs.h + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef __ASM_ARCH_IRQS_H +#define __ASM_ARCH_IRQS_H + +#define SIRFSOC_INTENAL_IRQ_START 0 +#define SIRFSOC_INTENAL_IRQ_END 59 + +#define NR_IRQS 220 + +#endif diff --git a/arch/arm/mach-prima2/include/mach/map.h b/arch/arm/mach-prima2/include/mach/map.h new file mode 100644 index 000000000000..66b1ae2e553f --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/map.h @@ -0,0 +1,16 @@ +/* + * memory & I/O static mapping definitions for CSR SiRFprimaII + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef __MACH_PRIMA2_MAP_H__ +#define __MACH_PRIMA2_MAP_H__ + +#include + +#define SIRFSOC_VA(x) (VMALLOC_END + ((x) & 0x00FFF000)) + +#endif diff --git a/arch/arm/mach-prima2/include/mach/memory.h b/arch/arm/mach-prima2/include/mach/memory.h new file mode 100644 index 000000000000..368cd5a0601a --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/memory.h @@ -0,0 +1,21 @@ +/* + * arch/arm/mach-prima2/include/mach/memory.h + * + * Copyright (c) 2010 – 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +#define PLAT_PHYS_OFFSET UL(0x00000000) + +/* + * Restrict DMA-able region to workaround silicon limitation. + * The limitation restricts buffers available for DMA to SD/MMC + * hardware to be below 256MB + */ +#define ARM_DMA_ZONE_SIZE (SZ_256M) + +#endif diff --git a/arch/arm/mach-prima2/include/mach/system.h b/arch/arm/mach-prima2/include/mach/system.h new file mode 100644 index 000000000000..0dbd257ad16d --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/system.h @@ -0,0 +1,29 @@ +/* + * arch/arm/mach-prima2/include/mach/system.h + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef __MACH_SYSTEM_H__ +#define __MACH_SYSTEM_H__ + +#include +#include + +#define SIRFSOC_SYS_RST_BIT BIT(31) + +extern void __iomem *sirfsoc_rstc_base; + +static inline void arch_idle(void) +{ + cpu_do_idle(); +} + +static inline void arch_reset(char mode, const char *cmd) +{ + writel(SIRFSOC_SYS_RST_BIT, sirfsoc_rstc_base); +} + +#endif diff --git a/arch/arm/mach-prima2/include/mach/timex.h b/arch/arm/mach-prima2/include/mach/timex.h new file mode 100644 index 000000000000..d6f98a75e562 --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/timex.h @@ -0,0 +1,14 @@ +/* + * arch/arm/mach-prima2/include/mach/timex.h + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef __MACH_TIMEX_H__ +#define __MACH_TIMEX_H__ + +#define CLOCK_TICK_RATE 1000000 + +#endif diff --git a/arch/arm/mach-prima2/include/mach/uart.h b/arch/arm/mach-prima2/include/mach/uart.h new file mode 100644 index 000000000000..c98b4d5ac24a --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/uart.h @@ -0,0 +1,23 @@ +/* + * arch/arm/mach-prima2/include/mach/uart.h + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef __MACH_PRIMA2_SIRFSOC_UART_H +#define __MACH_PRIMA2_SIRFSOC_UART_H + +/* UART-1: used as serial debug port */ +#define SIRFSOC_UART1_PA_BASE 0xb0060000 +#define SIRFSOC_UART1_VA_BASE SIRFSOC_VA(0x060000) +#define SIRFSOC_UART1_SIZE SZ_4K + +#define SIRFSOC_UART_TXFIFO_STATUS 0x0114 +#define SIRFSOC_UART_TXFIFO_DATA 0x0118 + +#define SIRFSOC_UART1_TXFIFO_FULL (1 << 5) +#define SIRFSOC_UART1_TXFIFO_EMPTY (1 << 6) + +#endif diff --git a/arch/arm/mach-prima2/include/mach/uncompress.h b/arch/arm/mach-prima2/include/mach/uncompress.h new file mode 100644 index 000000000000..83125c6a30b3 --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/uncompress.h @@ -0,0 +1,40 @@ +/* + * arch/arm/mach-prima2/include/mach/uncompress.h + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef __ASM_ARCH_UNCOMPRESS_H +#define __ASM_ARCH_UNCOMPRESS_H + +#include +#include +#include + +void arch_decomp_setup(void) +{ +} + +#define arch_decomp_wdog() + +static __inline__ void putc(char c) +{ + /* + * during kernel decompression, all mappings are flat: + * virt_addr == phys_addr + */ + while (__raw_readl(SIRFSOC_UART1_PA_BASE + SIRFSOC_UART_TXFIFO_STATUS) + & SIRFSOC_UART1_TXFIFO_FULL) + barrier(); + + __raw_writel(c, SIRFSOC_UART1_PA_BASE + SIRFSOC_UART_TXFIFO_DATA); +} + +static inline void flush(void) +{ +} + +#endif + diff --git a/arch/arm/mach-prima2/include/mach/vmalloc.h b/arch/arm/mach-prima2/include/mach/vmalloc.h new file mode 100644 index 000000000000..c9f90fec78e3 --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/vmalloc.h @@ -0,0 +1,16 @@ +/* + * arch/arm/ach-prima2/include/mach/vmalloc.h + * + * Copyright (c) 2010 – 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef __MACH_VMALLOC_H +#define __MACH_VMALLOC_H + +#include + +#define VMALLOC_END _AC(0xFEC00000, UL) + +#endif diff --git a/arch/arm/mach-prima2/irq.c b/arch/arm/mach-prima2/irq.c new file mode 100644 index 000000000000..c3404cbb6ff7 --- /dev/null +++ b/arch/arm/mach-prima2/irq.c @@ -0,0 +1,71 @@ +/* + * interrupt controller support for CSR SiRFprimaII + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define SIRFSOC_INT_RISC_MASK0 0x0018 +#define SIRFSOC_INT_RISC_MASK1 0x001C +#define SIRFSOC_INT_RISC_LEVEL0 0x0020 +#define SIRFSOC_INT_RISC_LEVEL1 0x0024 + +void __iomem *sirfsoc_intc_base; + +static __init void +sirfsoc_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num) +{ + struct irq_chip_generic *gc; + struct irq_chip_type *ct; + + gc = irq_alloc_generic_chip("SIRFINTC", 1, irq_start, base, handle_level_irq); + ct = gc->chip_types; + + ct->chip.irq_mask = irq_gc_mask_clr_bit; + ct->chip.irq_unmask = irq_gc_mask_set_bit; + ct->regs.mask = SIRFSOC_INT_RISC_MASK0; + + irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST, 0); +} + +static __init void sirfsoc_irq_init(void) +{ + sirfsoc_alloc_gc(sirfsoc_intc_base, 0, 32); + sirfsoc_alloc_gc(sirfsoc_intc_base + 4, 32, SIRFSOC_INTENAL_IRQ_END - 32); + + writel_relaxed(0, sirfsoc_intc_base + SIRFSOC_INT_RISC_LEVEL0); + writel_relaxed(0, sirfsoc_intc_base + SIRFSOC_INT_RISC_LEVEL1); + + writel_relaxed(0, sirfsoc_intc_base + SIRFSOC_INT_RISC_MASK0); + writel_relaxed(0, sirfsoc_intc_base + SIRFSOC_INT_RISC_MASK1); +} + +static struct of_device_id intc_ids[] = { + { .compatible = "sirf,prima2-intc" }, +}; + +void __init sirfsoc_of_irq_init(void) +{ + struct device_node *np; + + np = of_find_matching_node(NULL, intc_ids); + if (!np) + panic("unable to find compatible intc node in dtb\n"); + + sirfsoc_intc_base = of_iomap(np, 0); + if (!sirfsoc_intc_base) + panic("unable to map intc cpu registers\n"); + + of_node_put(np); + + sirfsoc_irq_init(); +} diff --git a/arch/arm/mach-prima2/prima2.c b/arch/arm/mach-prima2/prima2.c new file mode 100644 index 000000000000..c26947d76e12 --- /dev/null +++ b/arch/arm/mach-prima2/prima2.c @@ -0,0 +1,40 @@ +/* + * Defines machines for CSR SiRFprimaII + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include "common.h" + +static struct of_device_id sirfsoc_of_bus_ids[] __initdata = { + { .compatible = "simple-bus", }, + {}, +}; + +void __init sirfsoc_mach_init(void) +{ + of_platform_bus_probe(NULL, sirfsoc_of_bus_ids, NULL); +} + +static const char *prima2cb_dt_match[] __initdata = { + "sirf,prima2-cb", + NULL +}; + +MACHINE_START(PRIMA2_EVB, "prima2cb") + /* Maintainer: Barry Song */ + .boot_params = 0x00000100, + .init_early = sirfsoc_of_clk_init, + .init_irq = sirfsoc_of_irq_init, + .timer = &sirfsoc_timer, + .init_machine = sirfsoc_mach_init, + .dt_compat = prima2cb_dt_match, +MACHINE_END diff --git a/arch/arm/mach-prima2/rstc.c b/arch/arm/mach-prima2/rstc.c new file mode 100644 index 000000000000..d074786e83d4 --- /dev/null +++ b/arch/arm/mach-prima2/rstc.c @@ -0,0 +1,69 @@ +/* + * reset controller for CSR SiRFprimaII + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include + +void __iomem *sirfsoc_rstc_base; +static DEFINE_MUTEX(rstc_lock); + +static struct of_device_id rstc_ids[] = { + { .compatible = "sirf,prima2-rstc" }, +}; + +static int __init sirfsoc_of_rstc_init(void) +{ + struct device_node *np; + + np = of_find_matching_node(NULL, rstc_ids); + if (!np) + panic("unable to find compatible rstc node in dtb\n"); + + sirfsoc_rstc_base = of_iomap(np, 0); + if (!sirfsoc_rstc_base) + panic("unable to map rstc cpu registers\n"); + + of_node_put(np); + + return 0; +} +early_initcall(sirfsoc_of_rstc_init); + +int sirfsoc_reset_device(struct device *dev) +{ + const unsigned int *prop = of_get_property(dev->of_node, "reset-bit", NULL); + unsigned int reset_bit; + + if (!prop) + return -ENODEV; + + reset_bit = be32_to_cpup(prop); + + mutex_lock(&rstc_lock); + + /* + * Writing 1 to this bit resets corresponding block. Writing 0 to this + * bit de-asserts reset signal of the corresponding block. + * datasheet doesn't require explicit delay between the set and clear + * of reset bit. it could be shorter if tests pass. + */ + writel(readl(sirfsoc_rstc_base + (reset_bit / 32) * 4) | reset_bit, + sirfsoc_rstc_base + (reset_bit / 32) * 4); + msleep(10); + writel(readl(sirfsoc_rstc_base + (reset_bit / 32) * 4) & ~reset_bit, + sirfsoc_rstc_base + (reset_bit / 32) * 4); + + mutex_unlock(&rstc_lock); + + return 0; +} diff --git a/arch/arm/mach-prima2/timer.c b/arch/arm/mach-prima2/timer.c new file mode 100644 index 000000000000..44027f34a88a --- /dev/null +++ b/arch/arm/mach-prima2/timer.c @@ -0,0 +1,217 @@ +/* + * System timer for CSR SiRFprimaII + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SIRFSOC_TIMER_COUNTER_LO 0x0000 +#define SIRFSOC_TIMER_COUNTER_HI 0x0004 +#define SIRFSOC_TIMER_MATCH_0 0x0008 +#define SIRFSOC_TIMER_MATCH_1 0x000C +#define SIRFSOC_TIMER_MATCH_2 0x0010 +#define SIRFSOC_TIMER_MATCH_3 0x0014 +#define SIRFSOC_TIMER_MATCH_4 0x0018 +#define SIRFSOC_TIMER_MATCH_5 0x001C +#define SIRFSOC_TIMER_STATUS 0x0020 +#define SIRFSOC_TIMER_INT_EN 0x0024 +#define SIRFSOC_TIMER_WATCHDOG_EN 0x0028 +#define SIRFSOC_TIMER_DIV 0x002C +#define SIRFSOC_TIMER_LATCH 0x0030 +#define SIRFSOC_TIMER_LATCHED_LO 0x0034 +#define SIRFSOC_TIMER_LATCHED_HI 0x0038 + +#define SIRFSOC_TIMER_WDT_INDEX 5 + +#define SIRFSOC_TIMER_LATCH_BIT BIT(0) + +static void __iomem *sirfsoc_timer_base; +static void __init sirfsoc_of_timer_map(void); + +/* timer0 interrupt handler */ +static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *ce = dev_id; + + WARN_ON(!(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_STATUS) & BIT(0))); + + /* clear timer0 interrupt */ + writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS); + + ce->event_handler(ce); + + return IRQ_HANDLED; +} + +/* read 64-bit timer counter */ +static cycle_t sirfsoc_timer_read(struct clocksource *cs) +{ + u64 cycles; + + /* latch the 64-bit timer counter */ + writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH); + cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_HI); + cycles = (cycles << 32) | readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO); + + return cycles; +} + +static int sirfsoc_timer_set_next_event(unsigned long delta, + struct clock_event_device *ce) +{ + unsigned long now, next; + + writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH); + now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO); + next = now + delta; + writel_relaxed(next, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0); + writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH); + now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO); + + return next - now > delta ? -ETIME : 0; +} + +static void sirfsoc_timer_set_mode(enum clock_event_mode mode, + struct clock_event_device *ce) +{ + u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + WARN_ON(1); + break; + case CLOCK_EVT_MODE_ONESHOT: + writel_relaxed(val | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); + break; + case CLOCK_EVT_MODE_SHUTDOWN: + writel_relaxed(val & ~BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_RESUME: + break; + } +} + +static struct clock_event_device sirfsoc_clockevent = { + .name = "sirfsoc_clockevent", + .rating = 200, + .features = CLOCK_EVT_FEAT_ONESHOT, + .set_mode = sirfsoc_timer_set_mode, + .set_next_event = sirfsoc_timer_set_next_event, +}; + +static struct clocksource sirfsoc_clocksource = { + .name = "sirfsoc_clocksource", + .rating = 200, + .mask = CLOCKSOURCE_MASK(64), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .read = sirfsoc_timer_read, +}; + +static struct irqaction sirfsoc_timer_irq = { + .name = "sirfsoc_timer0", + .flags = IRQF_TIMER, + .irq = 0, + .handler = sirfsoc_timer_interrupt, + .dev_id = &sirfsoc_clockevent, +}; + +/* Overwrite weak default sched_clock with more precise one */ +unsigned long long notrace sched_clock(void) +{ + static int is_mapped = 0; + + /* + * sched_clock is called earlier than .init of sys_timer + * if we map timer memory in .init of sys_timer, system + * will panic due to illegal memory access + */ + if(!is_mapped) { + sirfsoc_of_timer_map(); + is_mapped = 1; + } + + return sirfsoc_timer_read(NULL) * (NSEC_PER_SEC / CLOCK_TICK_RATE); +} + +static void __init sirfsoc_clockevent_init(void) +{ + clockevents_calc_mult_shift(&sirfsoc_clockevent, CLOCK_TICK_RATE, 60); + + sirfsoc_clockevent.max_delta_ns = + clockevent_delta2ns(-2, &sirfsoc_clockevent); + sirfsoc_clockevent.min_delta_ns = + clockevent_delta2ns(2, &sirfsoc_clockevent); + + sirfsoc_clockevent.cpumask = cpumask_of(0); + clockevents_register_device(&sirfsoc_clockevent); +} + +/* initialize the kernel jiffy timer source */ +static void __init sirfsoc_timer_init(void) +{ + unsigned long rate; + + /* timer's input clock is io clock */ + struct clk *clk = clk_get_sys("io", NULL); + + BUG_ON(IS_ERR(clk)); + + rate = clk_get_rate(clk); + + BUG_ON(rate < CLOCK_TICK_RATE); + BUG_ON(rate % CLOCK_TICK_RATE); + + writel_relaxed(rate / CLOCK_TICK_RATE / 2 - 1, sirfsoc_timer_base + SIRFSOC_TIMER_DIV); + writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO); + writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI); + writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS); + + BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE)); + + BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq)); + + sirfsoc_clockevent_init(); +} + +static struct of_device_id timer_ids[] = { + { .compatible = "sirf,prima2-tick" }, +}; + +static void __init sirfsoc_of_timer_map(void) +{ + struct device_node *np; + const unsigned int *intspec; + + np = of_find_matching_node(NULL, timer_ids); + if (!np) + panic("unable to find compatible timer node in dtb\n"); + sirfsoc_timer_base = of_iomap(np, 0); + if (!sirfsoc_timer_base) + panic("unable to map timer cpu registers\n"); + + /* Get the interrupts property */ + intspec = of_get_property(np, "interrupts", NULL); + BUG_ON(!intspec); + sirfsoc_timer_irq.irq = be32_to_cpup(intspec); + + of_node_put(np); +} + +struct sys_timer sirfsoc_timer = { + .init = sirfsoc_timer_init, +}; diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 0074b8dba793..edf0681c0e29 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -821,7 +821,7 @@ config CACHE_L2X0 depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || \ REALVIEW_EB_A9MP || SOC_IMX35 || SOC_IMX31 || MACH_REALVIEW_PBX || \ ARCH_NOMADIK || ARCH_OMAP4 || ARCH_EXYNOS4 || ARCH_TEGRA || \ - ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || ARCH_SHMOBILE + ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || ARCH_SHMOBILE || ARCH_PRIMA2 default y select OUTER_CACHE select OUTER_CACHE_SYNC From 31adb06f9d68f9d033284c9ab0e264b2d581bceb Mon Sep 17 00:00:00 2001 From: Barry Song Date: Fri, 8 Jul 2011 02:40:13 -0700 Subject: [PATCH 08/10] ARM: CSR: mapping early DEBUG_LL uart Signed-off-by: Barry Song Reviewed-by: Arnd Bergmann --- arch/arm/mach-prima2/Makefile | 1 + arch/arm/mach-prima2/common.h | 6 ++++++ arch/arm/mach-prima2/lluart.c | 25 +++++++++++++++++++++++++ arch/arm/mach-prima2/prima2.c | 1 + 4 files changed, 33 insertions(+) create mode 100644 arch/arm/mach-prima2/lluart.c diff --git a/arch/arm/mach-prima2/Makefile b/arch/arm/mach-prima2/Makefile index d44f7aedda87..f2fba666c109 100644 --- a/arch/arm/mach-prima2/Makefile +++ b/arch/arm/mach-prima2/Makefile @@ -3,3 +3,4 @@ obj-y += irq.o obj-y += clock.o obj-y += rstc.o obj-y += prima2.o +obj-$(CONFIG_DEBUG_LL) += lluart.o diff --git a/arch/arm/mach-prima2/common.h b/arch/arm/mach-prima2/common.h index fa4a3b5c674a..83e5d2128118 100644 --- a/arch/arm/mach-prima2/common.h +++ b/arch/arm/mach-prima2/common.h @@ -17,4 +17,10 @@ extern struct sys_timer sirfsoc_timer; extern void __init sirfsoc_of_irq_init(void); extern void __init sirfsoc_of_clk_init(void); +#ifndef CONFIG_DEBUG_LL +static inline void sirfsoc_map_lluart(void) {} +#else +extern void __init sirfsoc_map_lluart(void); +#endif + #endif diff --git a/arch/arm/mach-prima2/lluart.c b/arch/arm/mach-prima2/lluart.c new file mode 100644 index 000000000000..a89f9b3c8cc5 --- /dev/null +++ b/arch/arm/mach-prima2/lluart.c @@ -0,0 +1,25 @@ +/* + * Static memory mapping for DEBUG_LL + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include +#include +#include +#include +#include + +void __init sirfsoc_map_lluart(void) +{ + struct map_desc sirfsoc_lluart_map = { + .virtual = SIRFSOC_UART1_VA_BASE, + .pfn = __phys_to_pfn(SIRFSOC_UART1_PA_BASE), + .length = SIRFSOC_UART1_SIZE, + .type = MT_DEVICE, + }; + + iotable_init(&sirfsoc_lluart_map, 1); +} diff --git a/arch/arm/mach-prima2/prima2.c b/arch/arm/mach-prima2/prima2.c index c26947d76e12..f57124bdd143 100644 --- a/arch/arm/mach-prima2/prima2.c +++ b/arch/arm/mach-prima2/prima2.c @@ -33,6 +33,7 @@ MACHINE_START(PRIMA2_EVB, "prima2cb") /* Maintainer: Barry Song */ .boot_params = 0x00000100, .init_early = sirfsoc_of_clk_init, + .map_io = sirfsoc_map_lluart, .init_irq = sirfsoc_of_irq_init, .timer = &sirfsoc_timer, .init_machine = sirfsoc_mach_init, From 89e162afd37caa6acab4e05b6e9e9fad6235381e Mon Sep 17 00:00:00 2001 From: Rongjun Ying Date: Fri, 8 Jul 2011 02:40:14 -0700 Subject: [PATCH 09/10] ARM: CSR: initializing L2 cache Signed-off-by: Rongjun Ying Signed-off-by: Barry Song Reviewed-by: Arnd Bergmann --- arch/arm/mach-prima2/Makefile | 1 + arch/arm/mach-prima2/l2x0.c | 59 +++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 arch/arm/mach-prima2/l2x0.c diff --git a/arch/arm/mach-prima2/Makefile b/arch/arm/mach-prima2/Makefile index f2fba666c109..7af7fc05d565 100644 --- a/arch/arm/mach-prima2/Makefile +++ b/arch/arm/mach-prima2/Makefile @@ -4,3 +4,4 @@ obj-y += clock.o obj-y += rstc.o obj-y += prima2.o obj-$(CONFIG_DEBUG_LL) += lluart.o +obj-$(CONFIG_CACHE_L2X0) += l2x0.o diff --git a/arch/arm/mach-prima2/l2x0.c b/arch/arm/mach-prima2/l2x0.c new file mode 100644 index 000000000000..9cda2057bcfb --- /dev/null +++ b/arch/arm/mach-prima2/l2x0.c @@ -0,0 +1,59 @@ +/* + * l2 cache initialization for CSR SiRFprimaII + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define L2X0_ADDR_FILTERING_START 0xC00 +#define L2X0_ADDR_FILTERING_END 0xC04 + +static struct of_device_id l2x_ids[] = { + { .compatible = "arm,pl310-cache" }, +}; + +static int __init sirfsoc_of_l2x_init(void) +{ + struct device_node *np; + void __iomem *sirfsoc_l2x_base; + + np = of_find_matching_node(NULL, l2x_ids); + if (!np) + panic("unable to find compatible l2x node in dtb\n"); + + sirfsoc_l2x_base = of_iomap(np, 0); + if (!sirfsoc_l2x_base) + panic("unable to map l2x cpu registers\n"); + + of_node_put(np); + + if (!(readl_relaxed(sirfsoc_l2x_base + L2X0_CTRL) & 1)) { + /* + * set the physical memory windows L2 cache will cover + */ + writel_relaxed(PLAT_PHYS_OFFSET + 1024 * 1024 * 1024, + sirfsoc_l2x_base + L2X0_ADDR_FILTERING_END); + writel_relaxed(PLAT_PHYS_OFFSET | 0x1, + sirfsoc_l2x_base + L2X0_ADDR_FILTERING_START); + + writel_relaxed(0, + sirfsoc_l2x_base + L2X0_TAG_LATENCY_CTRL); + writel_relaxed(0, + sirfsoc_l2x_base + L2X0_DATA_LATENCY_CTRL); + } + l2x0_init((void __iomem *)sirfsoc_l2x_base, 0x00040000, + 0x00000000); + + return 0; +} +early_initcall(sirfsoc_of_l2x_init); From a990cbd887585a1056b927b3b20de325f14fdf96 Mon Sep 17 00:00:00 2001 From: Barry Song <21cnbao@gmail.com> Date: Tue, 12 Jul 2011 21:44:10 +0800 Subject: [PATCH 10/10] MAINTAINERS: add maintainer of CSR SiRFprimaII machine Signed-off-by: Barry Song Signed-off-by: Arnd Bergmann --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 9820e89c827c..09cbbbb40cd1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -721,6 +721,12 @@ T: git git://git.berlios.de/gemini-board S: Maintained F: arch/arm/mach-gemini/ +ARM/CSR SIRFPRIMA2 MACHINE SUPPORT +M: Barry Song +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +S: Maintained +F: arch/arm/mach-prima2/ + ARM/EBSA110 MACHINE SUPPORT M: Russell King L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)