From patchwork Fri Aug 31 10:35:12 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Barry Song X-Patchwork-Id: 1392611 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork2.kernel.org (Postfix) with ESMTP id 68F3CE0000 for ; Fri, 31 Aug 2012 10:40:50 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1T7ObP-0000oJ-MW; Fri, 31 Aug 2012 10:37:27 +0000 Received: from cluster-d.mailcontrol.com ([85.115.60.190]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1T7ObJ-0000mU-1u for linux-arm-kernel@lists.infradead.org; Fri, 31 Aug 2012 10:37:24 +0000 Received: from rly38d.srv.mailcontrol.com (localhost.localdomain [127.0.0.1]) by rly38d.srv.mailcontrol.com (MailControl) with ESMTP id q7VAaEqF029984 for ; Fri, 31 Aug 2012 11:37:10 +0100 Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by rly38d.srv.mailcontrol.com (MailControl) id q7VAZhXv017780 for ; Fri, 31 Aug 2012 11:35:43 +0100 Received: from banasiexc01.ASIA.ROOT.PRI ([202.80.51.114]) by rly38d-eth0.srv.mailcontrol.com (envelope-sender ) (MIMEDefang) with ESMTP id q7VAZbtI015932 (TLS bits=128 verify=FAIL); Fri, 31 Aug 2012 11:35:43 +0100 (BST) Received: from SHAASIEXC02.ASIA.ROOT.PRI (10.125.12.85) by banasiexc01.ASIA.ROOT.PRI (10.190.12.21) with Microsoft SMTP Server (TLS) id 14.1.355.2; Fri, 31 Aug 2012 16:05:36 +0530 Received: from localhost.localdomain (10.125.36.195) by asimail.csr.com (10.125.12.88) with Microsoft SMTP Server (TLS) id 14.1.355.2; Fri, 31 Aug 2012 18:35:28 +0800 From: Barry Song To: , Subject: [RFC/PATCH] ARM: PRIMA2: initial support for SiRFmarco dual-core SoC Date: Fri, 31 Aug 2012 18:35:12 +0800 Message-ID: <1346409312-16778-1-git-send-email-Barry.Song@csr.com> X-Mailer: git-send-email 1.7.1 MIME-Version: 1.0 X-Originating-IP: [10.125.36.195] X-Scanned-By: MailControl 8316.0 (www.mailcontrol.com) on 10.68.1.148 X-Spam-Note: CRM114 invocation failed X-Spam-Score: -2.6 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.6 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [85.115.60.190 listed in list.dnswl.org] -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: linux-arm-kernel@lists.infradead.org, workgroup.linux@csr.com, Barry Song X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org From: Barry Song SiRFmarco is a dual-core cortex-A9 SoC. This patch adds initial support for it. It is only a RFC for early review from community. I'd like to split it into multiple patches later. change list: 1. Marco has different OS timer hardware with Prima2, so add a new timer-marco 2. add platsmp.c, headsmp.S and hotplug.c for MPcore support 3. some hardwares have changed, like rstc, so use of_compatible to branch Prima2 and Marco 4. add initial .dtsi for Marco SoC and initial .dts for the EVB 5. some hardware support both Prima2 and Marco, add marco stuff to of_match tables 6. use GIC for Marco instead of Prima2's IRQ controller 7. add DEBUG_LL uart ports for Prima2 and Marco debug ports Signed-off-by: Barry Song --- arch/arm/Kconfig | 3 +- arch/arm/Kconfig.debug | 14 + arch/arm/Makefile | 2 +- arch/arm/boot/dts/marco-evb.dts | 20 + arch/arm/boot/dts/marco.dtsi | 497 ++++++++++++++++++++++ arch/arm/configs/marcocb_defconfig | 86 ++++ arch/arm/mach-prima2/Kconfig | 14 + arch/arm/mach-prima2/Makefile | 5 +- arch/arm/mach-prima2/common.c | 44 ++- arch/arm/mach-prima2/common.h | 6 +- arch/arm/mach-prima2/headsmp.S | 79 ++++ arch/arm/mach-prima2/hotplug.c | 57 +++ arch/arm/mach-prima2/include/mach/uart.h | 4 + arch/arm/mach-prima2/l2x0.c | 19 +- arch/arm/mach-prima2/platsmp.c | 154 +++++++ arch/arm/mach-prima2/pm.c | 1 + arch/arm/mach-prima2/rstc.c | 47 ++- arch/arm/mach-prima2/rtciobrg.c | 1 + arch/arm/mach-prima2/timer-marco.c | 295 +++++++++++++ arch/arm/mach-prima2/{timer.c => timer-prima2.c} | 4 +- drivers/pinctrl/Kconfig | 2 +- 21 files changed, 1326 insertions(+), 28 deletions(-) create mode 100644 arch/arm/boot/dts/marco-evb.dts create mode 100644 arch/arm/boot/dts/marco.dtsi create mode 100644 arch/arm/configs/marcocb_defconfig create mode 100644 arch/arm/mach-prima2/headsmp.S create mode 100644 arch/arm/mach-prima2/hotplug.c create mode 100644 arch/arm/mach-prima2/platsmp.c create mode 100644 arch/arm/mach-prima2/timer-marco.c rename arch/arm/mach-prima2/{timer.c => timer-prima2.c} (98%) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 00ef0e0..8f2fe64 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -418,8 +418,9 @@ config ARCH_SIRF select PINCTRL select PINCTRL_SIRF select USE_OF + select AUTO_ZRELADDR help - Support for CSR SiRFprimaII/Marco/Polo platforms + Support for CSR SiRFprimaII/Marco/Polo platforms config ARCH_EBSA110 bool "EBSA-110" diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index f15f82b..2e63c78 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -310,6 +310,20 @@ choice The uncompressor code port configuration is now handled by CONFIG_S3C_LOWLEVEL_UART_PORT. + config DEBUG_SIRFPRIMA2_UART1 + bool "Kernel low-level debugging messages via SiRFprimaII UART1" + depends on ARCH_PRIMA2 + help + Say Y here if you want the debug print routines to direct + their output to the uart1 port on SiRFprimaII devices. + + config DEBUG_SIRFMARCO_UART1 + bool "Kernel low-level debugging messages via SiRFmarco UART1" + depends on ARCH_MARCO + help + Say Y here if you want the debug print routines to direct + their output to the uart1 port on SiRFmarco devices. + config DEBUG_VEXPRESS_UART0_DETECT bool "Autodetect UART0 on Versatile Express Cortex-A core tiles" depends on ARCH_VEXPRESS && CPU_CP15_MMU diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 30eae87..6fbec07 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -168,7 +168,6 @@ machine-$(CONFIG_ARCH_OMAP2PLUS) := omap2 machine-$(CONFIG_ARCH_ORION5X) := orion5x machine-$(CONFIG_ARCH_PICOXCELL) := picoxcell 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 @@ -182,6 +181,7 @@ machine-$(CONFIG_ARCH_EXYNOS5) := exynos machine-$(CONFIG_ARCH_SA1100) := sa1100 machine-$(CONFIG_ARCH_SHARK) := shark machine-$(CONFIG_ARCH_SHMOBILE) := shmobile +machine-$(CONFIG_ARCH_SIRF) := prima2 machine-$(CONFIG_ARCH_TEGRA) := tegra machine-$(CONFIG_ARCH_U300) := u300 machine-$(CONFIG_ARCH_U8500) := ux500 diff --git a/arch/arm/boot/dts/marco-evb.dts b/arch/arm/boot/dts/marco-evb.dts new file mode 100644 index 0000000..8b2dc61 --- /dev/null +++ b/arch/arm/boot/dts/marco-evb.dts @@ -0,0 +1,20 @@ +/* + * DTS file for CSR SiRFmarco Evaluation Board + * + * Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +/dts-v1/; + +/include/ "marco.dtsi" + +/ { + model = "CSR SiRFmarco Evaluation Board"; + compatible = "sirf,marco", "sirf,marco-cb"; + + memory { + reg = <0x40000000 0x60000000>; + }; +}; diff --git a/arch/arm/boot/dts/marco.dtsi b/arch/arm/boot/dts/marco.dtsi new file mode 100644 index 0000000..34aad72 --- /dev/null +++ b/arch/arm/boot/dts/marco.dtsi @@ -0,0 +1,497 @@ +/* + * DTS file for CSR SiRFmarco SoC + * + * Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +/include/ "skeleton.dtsi" +/ { + compatible = "sirf,marco"; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&gic>; + + cpus { + cpu@0 { + compatible = "arm,cortex-a9"; + }; + cpu@1 { + compatible = "arm,cortex-a9"; + }; + }; + + axi { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x40000000 0x40000000 0xa0000000>; + + l2-cache-controller@c0030000 { + compatible = "arm,pl310-cache", "sirf,marco-pl310-cache"; + reg = <0xc0030000 0x1000>; + interrupts = <0 59 0>; + arm,tag-latency = <1 1 1>; + arm,data-latency = <1 1 1>; + arm,filter-ranges = <0x40000000 0xc0000000>; + }; + + gic: interrupt-controller@c0011000 { + compatible = "arm,cortex-a9-gic"; + interrupt-controller; + #interrupt-cells = <3>; + reg = <0xc0011000 0x1000>, + <0xc0010100 0x0100>; + }; + + rstc-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xc2000000 0xc2000000 0x10000>; + + reset-controller@c2000000 { + compatible = "sirf,marco-rstc"; + reg = <0xc2000000 0x10000>; + }; + }; + + sys-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xc3000000 0xc3000000 0x30000>; + + clock-controller@c3000000 { + compatible = "sirf,marco-clkc"; + reg = <0xc3000000 0x1000>; + interrupts = <0 3 0>; + }; + + rsc-controller@c3010000 { + compatible = "sirf,marco-rsc"; + reg = <0xc3010000 0x1000>; + }; + }; + + mem-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xc4000000 0xc4000000 0x10000>; + + memory-controller@c4000000 { + compatible = "sirf,marco-memc"; + reg = <0xc4000000 0x10000>; + interrupts = <0 27 0>; + }; + }; + + disp-iobg0 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xc5000000 0xc5000000 0x20000>; + + display0@c5000000 { + compatible = "sirf,marco-lcd"; + reg = <0xc5000000 0x10000>; + interrupts = <0 30 0>; + }; + + vpp0@c5010000 { + compatible = "sirf,marco-vpp"; + reg = <0xc5010000 0x10000>; + interrupts = <0 31 0>; + }; + }; + + disp-iobg1 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xc6000000 0xc6000000 0x20000>; + + display1@c6000000 { + compatible = "sirf,marco-lcd"; + reg = <0xc6000000 0x10000>; + interrupts = <0 62 0>; + }; + + vpp1@c6010000 { + compatible = "sirf,marco-vpp"; + reg = <0xc6010000 0x10000>; + interrupts = <0 63 0>; + }; + }; + + graphics-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xc8000000 0xc8000000 0x1000000>; + + graphics@c8000000 { + compatible = "powervr,sgx540"; + reg = <0xc8000000 0x1000000>; + interrupts = <0 6 0>; + }; + }; + + multimedia-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xc9000000 0xc9000000 0x1000000>; + + multimedia@a0000000 { + compatible = "sirf,marco-video-codec"; + reg = <0xc9000000 0x1000000>; + interrupts = <0 5 0>; + }; + }; + + dsp-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xca000000 0xca000000 0x2000000>; + + dspif@ca000000 { + compatible = "sirf,marco-dspif"; + reg = <0xca000000 0x10000>; + interrupts = <0 9 0>; + }; + + gps@ca010000 { + compatible = "sirf,marco-gps"; + reg = <0xca010000 0x10000>; + interrupts = <0 7 0>; + }; + + dsp@cb000000 { + compatible = "sirf,marco-dsp"; + reg = <0xcb000000 0x1000000>; + interrupts = <0 8 0>; + }; + }; + + peri-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xcc000000 0xcc000000 0x1b0000>; + + timer@cc020000 { + compatible = "sirf,marco-tick"; + reg = <0xcc020000 0x1000>; + interrupts = <0 0 0>; + }; + + nand@cc030000 { + compatible = "sirf,marco-nand"; + reg = <0xcc030000 0x10000>; + interrupts = <0 41 0>; + }; + + audio@cc040000 { + compatible = "sirf,marco-audio"; + reg = <0xcc040000 0x10000>; + interrupts = <0 35 0>; + }; + + uart0: uart@cc050000 { + cell-index = <0>; + compatible = "sirf,marco-uart"; + reg = <0xcc050000 0x1000>; + interrupts = <0 17 0>; + fifosize = <128>; + }; + + uart1: uart@cc060000 { + cell-index = <1>; + compatible = "sirf,marco-uart"; + reg = <0xcc060000 0x1000>; + interrupts = <0 18 0>; + fifosize = <32>; + }; + + uart2: uart@cc070000 { + cell-index = <2>; + compatible = "sirf,marco-uart"; + reg = <0xcc070000 0x1000>; + interrupts = <0 19 0>; + fifosize = <128>; + }; + + uart3: uart@cc190000 { + cell-index = <3>; + compatible = "sirf,marco-uart"; + reg = <0xcc190000 0x1000>; + interrupts = <0 66 0>; + fifosize = <128>; + }; + + uart4: uart@cc1a0000 { + cell-index = <4>; + compatible = "sirf,marco-uart"; + reg = <0xcc1a0000 0x1000>; + interrupts = <0 69 0>; + fifosize = <128>; + }; + + usp0: usp@cc080000 { + cell-index = <0>; + compatible = "sirf,marco-usp"; + reg = <0xcc080000 0x10000>; + interrupts = <0 20 0>; + }; + + usp1: usp@cc090000 { + cell-index = <1>; + compatible = "sirf,marco-usp"; + reg = <0xcc090000 0x10000>; + interrupts = <0 21 0>; + }; + + usp2: usp@cc0a0000 { + cell-index = <2>; + compatible = "sirf,marco-usp"; + reg = <0xcc0a0000 0x10000>; + interrupts = <0 22 0>; + }; + + dmac0: dma-controller@cc0b0000 { + cell-index = <0>; + compatible = "sirf,marco-dmac"; + reg = <0xcc0b0000 0x10000>; + interrupts = <0 12 0>; + }; + + dmac1: dma-controller@cc160000 { + cell-index = <1>; + compatible = "sirf,marco-dmac"; + reg = <0xcc160000 0x10000>; + interrupts = <0 13 0>; + }; + + vip@cc0c0000 { + compatible = "sirf,marco-vip"; + reg = <0xcc0c0000 0x10000>; + }; + + spi0: spi@cc0D0000 { + cell-index = <0>; + compatible = "sirf,marco-spi"; + reg = <0xcc0D0000 0x10000>; + interrupts = <0 15 0>; + sirf,spi-num-chipselects = <1>; + cs-gpios = <&gpio 0 0>; + }; + + spi1: spi@cc170000 { + cell-index = <1>; + compatible = "sirf,marco-spi"; + reg = <0xcc170000 0x10000>; + interrupts = <0 16 0>; + sirf,spi-num-chipselects = <1>; + cs-gpios = <&gpio 0 0>; + }; + + i2c0: i2c@cc0e0000 { + cell-index = <0>; + compatible = "sirf,marco-i2c"; + reg = <0xcc0e0000 0x10000>; + interrupts = <0 24 0>; + }; + + i2c1: i2c@cc0f0000 { + cell-index = <1>; + compatible = "sirf,marco-i2c"; + reg = <0xcc0f0000 0x10000>; + interrupts = <0 25 0>; + }; + + tsc@cc110000 { + compatible = "sirf,marco-tsc"; + reg = <0xcc110000 0x10000>; + interrupts = <0 33 0>; + }; + + gpio: gpio-controller@cc120000 { + #gpio-cells = <2>; + #interrupt-cells = <2>; + compatible = "sirf,marco-gpio-pinmux"; + reg = <0xcc120000 0x10000>; + interrupts = <0 43 0>, + <0 44 0>, + <0 45 0>, + <0 46 0>, + <0 47 0>; + gpio-controller; + interrupt-controller; + }; + + pwm@cc130000 { + compatible = "sirf,marco-pwm"; + reg = <0xcc130000 0x10000>; + }; + + efusesys@cc140000 { + compatible = "sirf,marco-efuse"; + reg = <0xcc140000 0x10000>; + }; + + pulsec@cc150000 { + compatible = "sirf,marco-pulsec"; + reg = <0xcc150000 0x10000>; + interrupts = <0 48 0>; + }; + + pci-iobg { + compatible = "sirf,marco-pciiobg", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xcD000000 0xcD000000 0x1000000>; + + sd0: sdhci@cD000000 { + cell-index = <0>; + compatible = "sirf,marco-sdhc"; + reg = <0xcD000000 0x100000>; + interrupts = <0 38 0>; + }; + + sd1: sdhci@cD100000 { + cell-index = <1>; + compatible = "sirf,marco-sdhc"; + reg = <0xcD100000 0x100000>; + interrupts = <0 38 0>; + }; + + sd2: sdhci@cD200000 { + cell-index = <2>; + compatible = "sirf,marco-sdhc"; + reg = <0xcD200000 0x100000>; + interrupts = <0 23 0>; + }; + + sd3: sdhci@cD300000 { + cell-index = <3>; + compatible = "sirf,marco-sdhc"; + reg = <0xcD300000 0x100000>; + interrupts = <0 23 0>; + }; + + sd4: sdhci@cD400000 { + cell-index = <4>; + compatible = "sirf,marco-sdhc"; + reg = <0xcD400000 0x100000>; + interrupts = <0 39 0>; + }; + + sd5: sdhci@cD500000 { + cell-index = <5>; + compatible = "sirf,marco-sdhc"; + reg = <0xcD500000 0x100000>; + interrupts = <0 39 0>; + }; + + pci-copy@cD900000 { + compatible = "sirf,marco-pcicp"; + reg = <0xcD900000 0x100000>; + interrupts = <0 40 0>; + }; + + rom-interface@cDa00000 { + compatible = "sirf,marco-romif"; + reg = <0xcDa00000 0x100000>; + }; + }; + }; + + rtc-iobg { + compatible = "sirf,marco-rtciobg", "sirf-marco-rtciobg-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xc1000000 0x10000>; + + gpsrtc@1000 { + compatible = "sirf,marco-gpsrtc"; + reg = <0x1000 0x1000>; + interrupts = <0 55 0>, + <0 56 0>, + <0 57 0>; + }; + + sysrtc@2000 { + compatible = "sirf,marco-sysrtc"; + reg = <0x2000 0x1000>; + interrupts = <0 52 0>, + <0 53 0>, + <0 54 0>; + }; + + pwrc@3000 { + compatible = "sirf,marco-pwrc"; + reg = <0x3000 0x1000>; + interrupts = <0 32 0>; + }; + }; + + uus-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xce000000 0xce000000 0x40000>; + + usb0: usb@ce000000 { + compatible = "chipidea,ci13611a-marco"; + reg = <0xce000000 0x10000>; + interrupts = <0 10 0>; + }; + + usb1: usb@ce010000 { + compatible = "chipidea,ci13611a-marco"; + reg = <0xce010000 0x10000>; + interrupts = <0 11 0>; + }; + + security@ce020000 { + compatible = "sirf,marco-security"; + reg = <0xce020000 0x10000>; + interrupts = <0 42 0>; + }; + }; + + can-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xD0000000 0xD0000000 0x20000>; + + can0: can@D0000000 { + compatible = "sirf,marco-can"; + reg = <0xD0000000 0x10000>; + }; + + can1: can@D0010000 { + compatible = "sirf,marco-can"; + reg = <0xD0010000 0x10000>; + }; + }; + + lvds-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xD1000000 0xD1000000 0x10000>; + + lvds@D1000000 { + compatible = "sirf,marco-lvds"; + reg = <0xD1000000 0x10000>; + interrupts = <0 64 0>; + }; + }; + }; +}; diff --git a/arch/arm/configs/marcocb_defconfig b/arch/arm/configs/marcocb_defconfig new file mode 100644 index 0000000..1a9829d --- /dev/null +++ b/arch/arm/configs/marcocb_defconfig @@ -0,0 +1,86 @@ +CONFIG_EXPERIMENTAL=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_KALLSYMS_ALL=y +CONFIG_PERF_EVENTS=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_LBDAF is not set +# CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_BSD_DISKLABEL=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_ARCH_SIRF=y +# CONFIG_ARCH_PRIMA2 is not set +# CONFIG_SWP_EMULATE is not set +CONFIG_SMP=y +CONFIG_NR_CPUS=2 +# CONFIG_LOCAL_TIMERS is not set +CONFIG_PREEMPT=y +CONFIG_AEABI=y +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_KEXEC=y +CONFIG_CPU_IDLE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_MISC=y +CONFIG_PM_RUNTIME=y +CONFIG_PM_DEBUG=y +CONFIG_PM_ADVANCED_DEBUG=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_HW_RANDOM=y +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_SPI=y +CONFIG_SPI_BITBANG=y +CONFIG_SPI_SPIDEV=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_GENERIC_PLATFORM=y +CONFIG_POWER_SUPPLY=y +# CONFIG_HWMON is not set +CONFIG_THERMAL=y +CONFIG_USB_GADGET=y +CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m +CONFIG_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_DMADEVICES=y +CONFIG_DMADEVICES_DEBUG=y +CONFIG_DMADEVICES_VDEBUG=y +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_EXT2_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_CRAMFS=y +CONFIG_ROMFS_FS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_SECTION_MISMATCH=y +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEBUG_RT_MUTEXES=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_LL=y +CONFIG_EARLY_PRINTK=y +CONFIG_CRC_CCITT=y diff --git a/arch/arm/mach-prima2/Kconfig b/arch/arm/mach-prima2/Kconfig index 41fc853..1ad4dd3 100644 --- a/arch/arm/mach-prima2/Kconfig +++ b/arch/arm/mach-prima2/Kconfig @@ -11,9 +11,23 @@ config ARCH_PRIMA2 help Support for CSR SiRFSoC ARM Cortex A9 Platform +config ARCH_MARCO + bool "CSR SiRFSoC MARCO ARM Cortex A9 Platform" + default y + select CPU_V7 + select HAVE_SMP + select SMP_ON_UP + select ARM_GIC + select SIRFMARCO_FPGA + help + Support for CSR SiRFSoC ARM Cortex A9 Platform + endmenu config SIRF_IRQ bool +config SIRFMARCO_FPGA + bool "CSR SiRFmarco FPGA with 26Mhz io clock" + endif diff --git a/arch/arm/mach-prima2/Makefile b/arch/arm/mach-prima2/Makefile index fc9ce22..bfe360c 100644 --- a/arch/arm/mach-prima2/Makefile +++ b/arch/arm/mach-prima2/Makefile @@ -1,4 +1,3 @@ -obj-y := timer.o obj-y += rstc.o obj-y += common.o obj-y += rtciobrg.o @@ -6,3 +5,7 @@ obj-$(CONFIG_DEBUG_LL) += lluart.o obj-$(CONFIG_CACHE_L2X0) += l2x0.o obj-$(CONFIG_SUSPEND) += pm.o sleep.o obj-$(CONFIG_SIRF_IRQ) += irq.o +obj-$(CONFIG_SMP) += platsmp.o headsmp.o +obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o +obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o +obj-$(CONFIG_ARCH_MARCO) += timer-marco.o diff --git a/arch/arm/mach-prima2/common.c b/arch/arm/mach-prima2/common.c index f25a541..3ee1457 100644 --- a/arch/arm/mach-prima2/common.c +++ b/arch/arm/mach-prima2/common.c @@ -8,9 +8,11 @@ #include #include +#include #include #include #include +#include #include #include #include "common.h" @@ -32,15 +34,15 @@ void __init sirfsoc_init_late(void) #ifdef CONFIG_ARCH_PRIMA2 static const char *prima2_dt_match[] __initdata = { - "sirf,prima2", - NULL + "sirf,prima2", + NULL }; DT_MACHINE_START(PRIMA2_DT, "Generic PRIMA2 (Flattened Device Tree)") /* Maintainer: Barry Song */ .map_io = sirfsoc_map_lluart, .init_irq = sirfsoc_of_irq_init, - .timer = &sirfsoc_timer, + .timer = &sirfsoc_prima2_timer, .dma_zone_size = SZ_256M, .init_machine = sirfsoc_mach_init, .init_late = sirfsoc_init_late, @@ -48,3 +50,39 @@ DT_MACHINE_START(PRIMA2_DT, "Generic PRIMA2 (Flattened Device Tree)") .restart = sirfsoc_restart, MACHINE_END #endif + +#ifdef CONFIG_ARCH_MARCO +static __init void sirfsoc_map_io(void) +{ + sirfsoc_map_lluart(); + sirfsoc_map_scu(); +} + +static const struct of_device_id marco_irq_match[] __initconst = { + { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, + { /* sentinel */ } +}; + +static void __init marco_init_irq(void) +{ + of_irq_init(marco_irq_match); +} + +static const char *marco_dt_match[] __initdata = { + "sirf,marco", + NULL +}; + +DT_MACHINE_START(MARCO_DT, "Generic MARCO (Flattened Device Tree)") + /* Maintainer: Barry Song */ + .map_io = sirfsoc_map_io, + .init_irq = marco_init_irq, + .handle_irq = gic_handle_irq, + .timer = &sirfsoc_marco_timer, + .init_machine = sirfsoc_mach_init, + .init_late = sirfsoc_init_late, + .dt_compat = marco_dt_match, + .restart = sirfsoc_restart, +MACHINE_END +#endif + diff --git a/arch/arm/mach-prima2/common.h b/arch/arm/mach-prima2/common.h index 60d826f..2e82e41 100644 --- a/arch/arm/mach-prima2/common.h +++ b/arch/arm/mach-prima2/common.h @@ -12,11 +12,13 @@ #include #include -extern struct sys_timer sirfsoc_timer; +extern struct sys_timer sirfsoc_prima2_timer; +extern struct sys_timer sirfsoc_marco_timer; extern void __init sirfsoc_of_irq_init(void); extern void __init sirfsoc_of_clk_init(void); extern void sirfsoc_restart(char, const char *); +extern void sirfsoc_secondary_startup(void); #ifndef CONFIG_DEBUG_LL static inline void sirfsoc_map_lluart(void) {} @@ -24,6 +26,8 @@ static inline void sirfsoc_map_lluart(void) {} extern void __init sirfsoc_map_lluart(void); #endif +extern void sirfsoc_map_scu(void); + #ifdef CONFIG_SUSPEND extern int sirfsoc_pm_init(void); #else diff --git a/arch/arm/mach-prima2/headsmp.S b/arch/arm/mach-prima2/headsmp.S new file mode 100644 index 0000000..6ec19d5 --- /dev/null +++ b/arch/arm/mach-prima2/headsmp.S @@ -0,0 +1,79 @@ +/* + * Entry of the second core for CSR Marco dual-core SMP SoCs + * + * Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include +#include + + __INIT +/* + * Cold boot and hardware reset show different behaviour, + * system will be always panic if we warm-reset the board + * Here we invalidate L1 of CPU1 to make sure there isn't + * uninitialized data written into memory later + */ +ENTRY(v7_invalidate_l1) + mov r0, #0 + mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache + mcr p15, 2, r0, c0, c0, 0 + mrc p15, 1, r0, c0, c0, 0 + + ldr r1, =0x7fff + and r2, r1, r0, lsr #13 + + ldr r1, =0x3ff + + and r3, r1, r0, lsr #3 @ NumWays - 1 + add r2, r2, #1 @ NumSets + + and r0, r0, #0x7 + add r0, r0, #4 @ SetShift + + clz r1, r3 @ WayShift + add r4, r3, #1 @ NumWays +1: sub r2, r2, #1 @ NumSets-- + mov r3, r4 @ Temp = NumWays +2: subs r3, r3, #1 @ Temp-- + mov r5, r3, lsl r1 + mov r6, r2, lsl r0 + orr r5, r5, r6 @ Reg = (Temp< +#include +#include + +#include +#include + +extern volatile int pen_release; + +static inline void platform_do_lowpower(unsigned int cpu) +{ + flush_cache_all(); + + /* we put the platform to just WFI */ + for (;;) { + __asm__ __volatile__("dsb\n\t" "wfi\n\t" + : : : "memory"); + if (pen_release == cpu_logical_map(cpu)) { + /* + * OK, proper wakeup, we're done + */ + break; + } + } +} + +int platform_cpu_kill(unsigned int cpu) +{ + return 1; +} + +/* + * platform-specific code to shutdown a CPU + * + * Called with IRQs disabled + */ +void platform_cpu_die(unsigned int cpu) +{ + platform_do_lowpower(cpu); +} + +int platform_cpu_disable(unsigned int cpu) +{ + /* + * we don't allow CPU 0 to be shutdown (it is still too special + * e.g. clock tick interrupts) + */ + return cpu == 0 ? -EPERM : 0; +} diff --git a/arch/arm/mach-prima2/include/mach/uart.h b/arch/arm/mach-prima2/include/mach/uart.h index c98b4d5..e5953d2 100644 --- a/arch/arm/mach-prima2/include/mach/uart.h +++ b/arch/arm/mach-prima2/include/mach/uart.h @@ -10,7 +10,11 @@ #define __MACH_PRIMA2_SIRFSOC_UART_H /* UART-1: used as serial debug port */ +#if defined(CONFIG_DEBUG_SIRFPRIMA2_UART1) #define SIRFSOC_UART1_PA_BASE 0xb0060000 +#elif defined(CONFIG_DEBUG_SIRFMARCO_UART1) +#define SIRFSOC_UART1_PA_BASE 0xcc060000 +#endif #define SIRFSOC_UART1_VA_BASE SIRFSOC_VA(0x060000) #define SIRFSOC_UART1_SIZE SZ_4K diff --git a/arch/arm/mach-prima2/l2x0.c b/arch/arm/mach-prima2/l2x0.c index c998377..35a2973 100644 --- a/arch/arm/mach-prima2/l2x0.c +++ b/arch/arm/mach-prima2/l2x0.c @@ -11,21 +11,38 @@ #include #include +/* + * fixme: make aux_val and aux_mask the private data + * of of_device_id after we get right aux_val/mask + */ static struct of_device_id prima2_l2x0_ids[] = { { .compatible = "sirf,prima2-pl310-cache" }, {}, }; +static struct of_device_id marco_l2x0_ids[] = { + { .compatible = "sirf,marco-pl310-cache" }, + {}, +}; + static int __init sirfsoc_l2x0_init(void) { struct device_node *np; - np = of_find_matching_node(NULL, prima2_l2x0_ids); if (np) { pr_info("Initializing prima2 L2 cache\n"); return l2x0_of_init(0x40000, 0); } + np = of_find_matching_node(NULL, marco_l2x0_ids); + if (np) { + pr_info("Initializing marco L2 cache\n"); + /* + * fixme: set the right aux_val and aux_mask + * return l2x0_of_init(0x10000, 0); + */ + } + return 0; } early_initcall(sirfsoc_l2x0_init); diff --git a/arch/arm/mach-prima2/platsmp.c b/arch/arm/mach-prima2/platsmp.c new file mode 100644 index 0000000..e990a79 --- /dev/null +++ b/arch/arm/mach-prima2/platsmp.c @@ -0,0 +1,154 @@ +/* + * plat smp support for CSR Marco dual-core SMP SoCs + * + * Copyright (c) 2012 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 "common.h" + +static void __iomem *scu_base; +/* + * control for which core is the next to come out of the secondary + * boot "holding pen". + */ +volatile int pen_release = -1; + +static DEFINE_SPINLOCK(boot_lock); + +static struct map_desc scu_io_desc __initdata = { + .length = SZ_4K, + .type = MT_DEVICE, +}; + +void __init sirfsoc_map_scu(void) +{ + unsigned long base; + + /* Get SCU base */ + asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base)); + + scu_io_desc.virtual = SIRFSOC_VA(base); + scu_io_desc.pfn = __phys_to_pfn(base); + iotable_init(&scu_io_desc, 1); + + scu_base = (void __iomem *)SIRFSOC_VA(base); +} + +void __cpuinit platform_secondary_init(unsigned int cpu) +{ + /* + * if any interrupts are already enabled for the primary + * core (e.g. timer irq), then they will not have been enabled + * for us: do so + */ + gic_secondary_init(0); + + /* + * let the primary processor know we're out of the + * pen, then head off into the C entry point + */ + pen_release = -1; + smp_wmb(); + + /* + * Synchronise with the boot thread. + */ + spin_lock(&boot_lock); + spin_unlock(&boot_lock); +} + +int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + unsigned long timeout; + static void __iomem *sram_base; + + /* for the moment in FPGA we use DSP SRAM */ +#define SIRFSOC_DSP_SRAM_BASE 0xCA008000UL + sram_base = ioremap_nocache(SIRFSOC_DSP_SRAM_BASE, SZ_4K); + + /* + * write the address of secondary startup into the sram register + * at offset 0x34, then write the magic number 0x12345678 to the + * sram register at offset 0x30, which is what boot rom code is + * waiting for. This would wake up the secondary core from WFI + */ +#define SIRFSOC_CPU1_JUMPADDR_OFFSET 0x34 + __raw_writel(virt_to_phys(sirfsoc_secondary_startup), + sram_base + SIRFSOC_CPU1_JUMPADDR_OFFSET); + +#define SIRFSOC_CPU1_WAKEMAGIC_OFFSET 0x30 + __raw_writel(0x12345678, + sram_base + SIRFSOC_CPU1_WAKEMAGIC_OFFSET); + + /* make sure write buffer is drained */ + mb(); + + spin_lock(&boot_lock); + + /* + * The secondary processor is waiting to be released from + * the holding pen - release it, then wait for it to flag + * that it has been released by resetting pen_release. + * + * Note that "pen_release" is the hardware CPU ID, whereas + * "cpu" is Linux's internal ID. + */ + pen_release = cpu_logical_map(cpu); + __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); + outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); + + /* + * Send the secondary CPU a soft interrupt ID15, thereby causing + * the boot monitor to read the JUMPADDR and WAKEMAGIC, and branch + * to the address found there. + */ + gic_raise_softirq(cpumask_of(cpu), 15); + + timeout = jiffies + (1 * HZ); + while (time_before(jiffies, timeout)) { + smp_rmb(); + if (pen_release == -1) + break; + + udelay(10); + } + + /* + * now the secondary core is starting up let it run its + * calibrations, then wait for it to finish + */ + spin_unlock(&boot_lock); + + return pen_release != -1 ? -ENOSYS : 0; +} + +void __init smp_init_cpus(void) +{ + int i, ncores; + + ncores = scu_get_core_count(scu_base); + + for (i = 0; i < ncores; i++) + set_cpu_possible(i, true); + + set_smp_cross_call(gic_raise_softirq); +} + +void __init platform_smp_prepare_cpus(unsigned int max_cpus) +{ + scu_enable(scu_base); +} diff --git a/arch/arm/mach-prima2/pm.c b/arch/arm/mach-prima2/pm.c index fb5a791..a16dec7 100644 --- a/arch/arm/mach-prima2/pm.c +++ b/arch/arm/mach-prima2/pm.c @@ -93,6 +93,7 @@ int __init sirfsoc_pm_init(void) static const struct of_device_id pwrc_ids[] = { { .compatible = "sirf,prima2-pwrc" }, + { .compatible = "sirf,marco-pwrc" }, {} }; diff --git a/arch/arm/mach-prima2/rstc.c b/arch/arm/mach-prima2/rstc.c index 762adb7..b8b002a 100644 --- a/arch/arm/mach-prima2/rstc.c +++ b/arch/arm/mach-prima2/rstc.c @@ -19,6 +19,7 @@ static DEFINE_MUTEX(rstc_lock); static struct of_device_id rstc_ids[] = { { .compatible = "sirf,prima2-rstc" }, + { .compatible = "sirf,marco-rstc" }, {}, }; @@ -42,27 +43,39 @@ 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; + u32 reset_bit; - if (!prop) - return -ENODEV; - - reset_bit = be32_to_cpup(prop); + if (of_property_read_u32(dev->of_node, "reset-bit", &reset_bit)) + return -EINVAL; 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); + if (of_device_is_compatible(dev->of_node, "sirf,prima2-rstc")) { + /* + * 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); + } else { + /* + * For MARCO and POLO + * Writing 1 to SET register resets corresponding block. Writing 1 to CLEAR + * register 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) * 8) | reset_bit, + sirfsoc_rstc_base + (reset_bit / 32) * 8); + msleep(10); + writel(readl(sirfsoc_rstc_base + (reset_bit / 32) * 8) | reset_bit, + sirfsoc_rstc_base + (reset_bit / 32) * 8 + 4); + } mutex_unlock(&rstc_lock); diff --git a/arch/arm/mach-prima2/rtciobrg.c b/arch/arm/mach-prima2/rtciobrg.c index 9d80f1e..fc6c4ab 100644 --- a/arch/arm/mach-prima2/rtciobrg.c +++ b/arch/arm/mach-prima2/rtciobrg.c @@ -104,6 +104,7 @@ EXPORT_SYMBOL_GPL(sirfsoc_rtc_iobrg_writel); static const struct of_device_id rtciobrg_ids[] = { { .compatible = "sirf,prima2-rtciobg" }, + { .compatible = "sirf,marco-rtciobg" }, {} }; diff --git a/arch/arm/mach-prima2/timer-marco.c b/arch/arm/mach-prima2/timer-marco.c new file mode 100644 index 0000000..eb5adad --- /dev/null +++ b/arch/arm/mach-prima2/timer-marco.c @@ -0,0 +1,295 @@ +/* + * 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 +#include +#include + +#include "common.h" + +#define SIRFSOC_TIMER_32COUNTER_0_CTRL 0x0000 +#define SIRFSOC_TIMER_32COUNTER_1_CTRL 0x0004 +#define SIRFSOC_TIMER_32COUNTER_2_CTRL 0x0008 +#define SIRFSOC_TIMER_32COUNTER_3_CTRL 0x000c +#define SIRFSOC_TIMER_32COUNTER_4_CTRL 0x0010 +#define SIRFSOC_TIMER_32COUNTER_5_CTRL 0x0014 +#define SIRFSOC_TIMER_MATCH_0 0x0018 +#define SIRFSOC_TIMER_MATCH_1 0x001c +#define SIRFSOC_TIMER_MATCH_2 0x0020 +#define SIRFSOC_TIMER_MATCH_3 0x0024 +#define SIRFSOC_TIMER_MATCH_4 0x0028 +#define SIRFSOC_TIMER_MATCH_5 0x002c +#define SIRFSOC_TIMER_32COUNTER_0_MATCH_NUM 0x0030 +#define SIRFSOC_TIMER_32COUNTER_1_MATCH_NUM 0x0034 +#define SIRFSOC_TIMER_32COUNTER_2_MATCH_NUM 0x0038 +#define SIRFSOC_TIMER_32COUNTER_3_MATCH_NUM 0x003c +#define SIRFSOC_TIMER_32COUNTER_4_MATCH_NUM 0x0040 +#define SIRFSOC_TIMER_32COUNTER_5_MATCH_NUM 0x0044 +#define SIRFSOC_TIMER_COUNTER_0 0x0048 +#define SIRFSOC_TIMER_COUNTER_1 0x004c +#define SIRFSOC_TIMER_COUNTER_2 0x0050 +#define SIRFSOC_TIMER_COUNTER_3 0x0054 +#define SIRFSOC_TIMER_COUNTER_4 0x0058 +#define SIRFSOC_TIMER_COUNTER_5 0x005c +#define SIRFSOC_TIMER_INTR_STATUS 0x0060 +#define SIRFSOC_TIMER_WATCHDOG_EN 0x0064 +#define SIRFSOC_TIMER_64COUNTER_CTRL 0x0068 +#define SIRFSOC_TIMER_64COUNTER_LO 0x006c +#define SIRFSOC_TIMER_64COUNTER_HI 0x0070 +#define SIRFSOC_TIMER_64COUNTER_LOAD_LO 0x0074 +#define SIRFSOC_TIMER_64COUNTER_LOAD_HI 0x0078 +#define SIRFSOC_TIMER_64COUNTER_RLATCHED_LO 0x007c +#define SIRFSOC_TIMER_64COUNTER_RLATCHED_HI 0x0080 + +#define SIRFSOC_TIMER_REG_CNT 5 + +static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = { + SIRFSOC_TIMER_WATCHDOG_EN, + SIRFSOC_TIMER_32COUNTER_0_CTRL, + SIRFSOC_TIMER_64COUNTER_CTRL, + SIRFSOC_TIMER_64COUNTER_RLATCHED_LO, + SIRFSOC_TIMER_64COUNTER_RLATCHED_HI, +}; + +static u32 sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT]; + +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; + u32 val; + + WARN_ON(!(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS) & BIT(0))); + + /* Stop the timer tick */ + val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL); + val &= ~(BIT(0) | BIT(1) | BIT(2)); + writel_relaxed(val, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL); + + writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0); + + /* clear timer0 interrupt */ + writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS); + + ce->event_handler(ce); + + return IRQ_HANDLED; +} + +/* read 64-bit timer counter */ +static cycle_t sirfsoc_timer_read(struct clocksource *cs) +{ + u64 cycles; + + writel_relaxed((readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) | + BIT(0)) & ~BIT(1), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); + + cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_HI); + cycles = (cycles << 32) | readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_LO); + + return cycles; +} + +static int sirfsoc_timer_set_next_event(unsigned long delta, + struct clock_event_device *ce) +{ + u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL); + val |= BIT(0) | BIT(1) | BIT(2); + + writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0); +#if 0 + writel_relaxed(delta, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0); +#else + /* Fix FPGA: divider of 32counter_0 doesn't work */ + writel_relaxed(delta * 13, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0); +#endif + + /* enable the tick */ + writel_relaxed(val, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL); + return 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_32COUNTER_0_CTRL); + val &= ~(BIT(0) | BIT(1) | BIT(2)); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + WARN_ON(1); + break; + case CLOCK_EVT_MODE_ONESHOT: + /* enable in set_next_event */ + break; + case CLOCK_EVT_MODE_SHUTDOWN: + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_RESUME: + break; + } + + writel_relaxed(val, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL); +} + +static void sirfsoc_clocksource_suspend(struct clocksource *cs) +{ + int i; + + for (i = 0; i < SIRFSOC_TIMER_REG_CNT; i++) + sirfsoc_timer_reg_val[i] = readl_relaxed(sirfsoc_timer_base + sirfsoc_timer_reg_list[i]); +} + +static void sirfsoc_clocksource_resume(struct clocksource *cs) +{ + int i; + + for (i = 0; i < SIRFSOC_TIMER_REG_CNT - 2; i++) + writel_relaxed(sirfsoc_timer_reg_val[i], sirfsoc_timer_base + sirfsoc_timer_reg_list[i]); + + writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 2], + sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO); + writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 1], + sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI); + + writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) | + BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); +} + +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, + .suspend = sirfsoc_clocksource_suspend, + .resume = sirfsoc_clocksource_resume, +}; + +static struct irqaction sirfsoc_timer_irq = { + .name = "sirfsoc_timer0", + .flags = IRQF_TIMER, + .handler = sirfsoc_timer_interrupt, + .dev_id = &sirfsoc_clockevent, +}; + +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; + u32 timer_div; + struct clk *clk; + + /* initialize clocking early, we want to set the OS timer */ + sirfsoc_of_clk_init(); + + /* timer's input clock is io clock */ + clk = clk_get_sys("io", NULL); + + BUG_ON(IS_ERR(clk)); +#if defined(CONFIG_SIRFMARCO_FPGA) + /* For FPGA, the io clk is fixed to 26Mhz */ + rate = 26000000; +#else + rate = clk_get_rate(clk); +#endif + + BUG_ON(rate < CLOCK_TICK_RATE); + BUG_ON(rate % CLOCK_TICK_RATE); + + sirfsoc_of_timer_map(); + + /* Initialize the timer divider */ + timer_div = rate / CLOCK_TICK_RATE / 2 - 1; + writel_relaxed((timer_div << 16) | readl_relaxed(sirfsoc_timer_base + + SIRFSOC_TIMER_64COUNTER_CTRL), + sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); + + writel_relaxed((timer_div << 16) | readl_relaxed(sirfsoc_timer_base + + SIRFSOC_TIMER_32COUNTER_0_CTRL) | BIT(0), + sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL); + + /* Initialize the timer counter to 0 */ + + writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO); + writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI); + writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) | + BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); + writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0); + + writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INTR_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,marco-tick" }, + {}, +}; + +static void __init sirfsoc_of_timer_map(void) +{ + struct device_node *np; + + np = of_find_matching_node(NULL, timer_ids); + if (!np) + return; + sirfsoc_timer_base = of_iomap(np, 0); + if (!sirfsoc_timer_base) + panic("unable to map timer cpu registers\n"); + + sirfsoc_timer_irq.irq = irq_of_parse_and_map(np, 0); + if (!sirfsoc_timer_irq.irq) + panic("No irq passed for timer via DT\n"); + + of_node_put(np); +} + +struct sys_timer sirfsoc_marco_timer = { + .init = sirfsoc_timer_init, +}; diff --git a/arch/arm/mach-prima2/timer.c b/arch/arm/mach-prima2/timer-prima2.c similarity index 98% rename from arch/arm/mach-prima2/timer.c rename to arch/arm/mach-prima2/timer-prima2.c index d95bf25..305cbcc 100644 --- a/arch/arm/mach-prima2/timer.c +++ b/arch/arm/mach-prima2/timer-prima2.c @@ -233,7 +233,7 @@ static void __init sirfsoc_of_timer_map(void) np = of_find_matching_node(NULL, timer_ids); if (!np) - panic("unable to find compatible timer node in dtb\n"); + return; sirfsoc_timer_base = of_iomap(np, 0); if (!sirfsoc_timer_base) panic("unable to map timer cpu registers\n"); @@ -246,6 +246,6 @@ static void __init sirfsoc_of_timer_map(void) of_node_put(np); } -struct sys_timer sirfsoc_timer = { +struct sys_timer sirfsoc_prima2_timer = { .init = sirfsoc_timer_init, }; diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 54e3588..e5db829 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -112,7 +112,7 @@ config PINCTRL_SINGLE config PINCTRL_SIRF bool "CSR SiRFprimaII pin controller driver" - depends on ARCH_PRIMA2 + depends on ARCH_SIRF select PINMUX config PINCTRL_TEGRA