diff options
Diffstat (limited to 'arch')
22 files changed, 1050 insertions, 136 deletions
diff --git a/arch/arm/cpu/armv7/sunxi/psci.c b/arch/arm/cpu/armv7/sunxi/psci.c index 104dc909bc..b3a34de1aa 100644 --- a/arch/arm/cpu/armv7/sunxi/psci.c +++ b/arch/arm/cpu/armv7/sunxi/psci.c @@ -27,6 +27,17 @@ #define GICD_BASE (SUNXI_GIC400_BASE + GIC_DIST_OFFSET) #define GICC_BASE (SUNXI_GIC400_BASE + GIC_CPU_OFFSET_A15) +/* + * R40 is different from other single cluster SoCs. + * + * The power clamps are located in the unused space after the per-core + * reset controls for core 3. The secondary core entry address register + * is in the SRAM controller address range. + */ +#define SUN8I_R40_PWROFF (0x110) +#define SUN8I_R40_PWR_CLAMP(cpu) (0x120 + (cpu) * 0x4) +#define SUN8I_R40_SRAMC_SOFT_ENTRY_REG0 (0xbc) + static void __secure cp15_write_cntp_tval(u32 tval) { asm volatile ("mcr p15, 0, %0, c14, c2, 0" : : "r" (tval)); @@ -68,7 +79,8 @@ static void __secure __mdelay(u32 ms) static void __secure clamp_release(u32 __maybe_unused *clamp) { #if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN7I) || \ - defined(CONFIG_MACH_SUN8I_H3) + defined(CONFIG_MACH_SUN8I_H3) || \ + defined(CONFIG_MACH_SUN8I_R40) u32 tmp = 0x1ff; do { tmp >>= 1; @@ -82,7 +94,8 @@ static void __secure clamp_release(u32 __maybe_unused *clamp) static void __secure clamp_set(u32 __maybe_unused *clamp) { #if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN7I) || \ - defined(CONFIG_MACH_SUN8I_H3) + defined(CONFIG_MACH_SUN8I_H3) || \ + defined(CONFIG_MACH_SUN8I_R40) writel(0xff, clamp); #endif } @@ -115,7 +128,17 @@ static void __secure sunxi_cpu_set_power(int __always_unused cpu, bool on) sunxi_power_switch(&cpucfg->cpu1_pwr_clamp, &cpucfg->cpu1_pwroff, on, 0); } -#else /* ! CONFIG_MACH_SUN7I */ +#elif defined CONFIG_MACH_SUN8I_R40 +static void __secure sunxi_cpu_set_power(int cpu, bool on) +{ + struct sunxi_cpucfg_reg *cpucfg = + (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE; + + sunxi_power_switch((void *)cpucfg + SUN8I_R40_PWR_CLAMP(cpu), + (void *)cpucfg + SUN8I_R40_PWROFF, + on, 0); +} +#else /* ! CONFIG_MACH_SUN7I && ! CONFIG_MACH_SUN8I_R40 */ static void __secure sunxi_cpu_set_power(int cpu, bool on) { struct sunxi_prcm_reg *prcm = @@ -213,7 +236,13 @@ int __secure psci_cpu_on(u32 __always_unused unused, u32 mpidr, u32 pc) psci_save_target_pc(cpu, pc); /* Set secondary core power on PC */ +#ifdef CONFIG_MACH_SUN8I_R40 + /* secondary core entry address is programmed differently */ + writel((u32)&psci_cpu_entry, + SUNXI_SRAMC_BASE + SUN8I_R40_SRAMC_SOFT_ENTRY_REG0); +#else writel((u32)&psci_cpu_entry, &cpucfg->priv0); +#endif /* Assert reset on target CPU */ writel(0, &cpucfg->cpu[cpu].rst); diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 5656e0d10e..f3f53f3e29 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -305,6 +305,10 @@ dtb-$(CONFIG_MACH_SUN8I_H3) += \ sun8i-h3-orangepi-plus2e.dtb \ sun8i-h3-nanopi-neo.dtb \ sun8i-h3-nanopi-neo-air.dtb +dtb-$(CONFIG_MACH_SUN8I_R40) += \ + sun8i-r40-bananapi-m2-ultra.dtb +dtb-$(CONFIG_MACH_SUN8I_V3S) += \ + sun8i-v3s-licheepi-zero.dtb dtb-$(CONFIG_MACH_SUN50I_H5) += \ sun50i-h5-orangepi-pc2.dtb dtb-$(CONFIG_MACH_SUN50I) += \ diff --git a/arch/arm/dts/sun8i-r40-bananapi-m2-ultra.dts b/arch/arm/dts/sun8i-r40-bananapi-m2-ultra.dts new file mode 100644 index 0000000000..ab471ab0bf --- /dev/null +++ b/arch/arm/dts/sun8i-r40-bananapi-m2-ultra.dts @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2016 Chen-Yu Tsai <wens@csie.org> + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; +#include "sun8i-r40.dtsi" + +/ { + model = "Banana Pi BPI-M2-Ultra"; + compatible = "sinovoip,bpi-m2-ultra", "allwinner,sun8i-r40"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; +}; + +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pb_pins>; + status = "okay"; +}; diff --git a/arch/arm/dts/sun8i-r40.dtsi b/arch/arm/dts/sun8i-r40.dtsi new file mode 100644 index 0000000000..48ec2e855a --- /dev/null +++ b/arch/arm/dts/sun8i-r40.dtsi @@ -0,0 +1,183 @@ +/* + * Copyright 2016 Chen-Yu Tsai + * + * Chen-Yu Tsai <wens@csie.org> + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <dt-bindings/interrupt-controller/arm-gic.h> + +/ { + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&gic>; + + aliases { + }; + + chosen { + }; + + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + osc24M: osc24M_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + }; + + osc32k: osc32k_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + clock-output-names = "osc32k"; + }; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "arm,cortex-a7"; + device_type = "cpu"; + reg = <0>; + }; + + cpu@1 { + compatible = "arm,cortex-a7"; + device_type = "cpu"; + reg = <1>; + }; + + cpu@2 { + compatible = "arm,cortex-a7"; + device_type = "cpu"; + reg = <2>; + }; + + cpu@3 { + compatible = "arm,cortex-a7"; + device_type = "cpu"; + reg = <3>; + }; + }; + + memory@40000000 { + device_type = "memory"; + reg = <0x40000000 0x80000000>; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + pio: pinctrl@1c20800 { + compatible = "allwinner,sun8i-r40-pinctrl"; + reg = <0x01c20800 0x400>; + interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>; + /* apb should be replaced once CCU is implemented */ + clocks = <&osc24M>, <&osc24M>, <&osc32k>; + clock-names = "apb", "hosc", "losc"; + gpio-controller; + interrupt-controller; + #interrupt-cells = <3>; + #gpio-cells = <3>; + + i2c0_pins: i2c0_pins { + pins = "PB0", "PB1"; + function = "i2c0"; + bias-pull-up; + }; + + uart0_pb_pins: uart0_pb_pins { + pins = "PB22", "PB23"; + function = "uart0"; + bias-pull-up; + }; + }; + + uart0: serial@1c28000 { + compatible = "snps,dw-apb-uart"; + reg = <0x01c28000 0x400>; + interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&osc24M>; + status = "disabled"; + }; + + i2c0: i2c@1c2ac00 { + compatible = "allwinner,sun6i-a31-i2c"; + reg = <0x01c2ac00 0x400>; + interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&osc24M>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + gic: interrupt-controller@1c81000 { + compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic"; + reg = <0x01c81000 0x1000>, + <0x01c82000 0x1000>, + <0x01c84000 0x2000>, + <0x01c86000 0x2000>; + interrupt-controller; + #interrupt-cells = <3>; + interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; + }; + }; + + timer { + compatible = "arm,armv7-timer"; + interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>; + clock-frequency = <24000000>; + arm,cpu-registers-not-fw-configured; + }; +}; diff --git a/arch/arm/dts/sun8i-v3s-licheepi-zero.dts b/arch/arm/dts/sun8i-v3s-licheepi-zero.dts new file mode 100644 index 0000000000..3d9168cbae --- /dev/null +++ b/arch/arm/dts/sun8i-v3s-licheepi-zero.dts @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2016 Icenowy Zheng <icenowy@aosc.xyz> + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; +#include "sun8i-v3s.dtsi" +#include "sunxi-common-regulators.dtsi" + +/ { + model = "Lichee Pi Zero"; + compatible = "licheepi,licheepi-zero", "allwinner,sun8i-v3s"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; +}; + +&mmc0 { + pinctrl-0 = <&mmc0_pins_a>; + pinctrl-names = "default"; + broken-cd; + bus-width = <4>; + vmmc-supply = <®_vcc3v3>; + status = "okay"; +}; + +&uart0 { + pinctrl-0 = <&uart0_pins_a>; + pinctrl-names = "default"; + status = "okay"; +}; + +&usb_otg { + dr_mode = "otg"; + status = "okay"; +}; + +&usbphy { + usb0_id_det-gpio = <&pio 5 6 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; diff --git a/arch/arm/dts/sun8i-v3s.dtsi b/arch/arm/dts/sun8i-v3s.dtsi new file mode 100644 index 0000000000..ebefc0fefe --- /dev/null +++ b/arch/arm/dts/sun8i-v3s.dtsi @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2016 Icenowy Zheng <icenowy@aosc.xyz> + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <dt-bindings/clock/sun8i-v3s-ccu.h> +#include <dt-bindings/reset/sun8i-v3s-ccu.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> +#include <dt-bindings/pinctrl/sun4i-a10.h> + +/ { + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&gic>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a7"; + device_type = "cpu"; + reg = <0>; + clocks = <&ccu CLK_CPU>; + }; + }; + + timer { + compatible = "arm,armv7-timer"; + interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>; + }; + + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + osc24M: osc24M_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + clock-output-names = "osc24M"; + }; + + osc32k: osc32k_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + clock-output-names = "osc32k"; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mmc0: mmc@01c0f000 { + compatible = "allwinner,sun7i-a20-mmc"; + reg = <0x01c0f000 0x1000>; + clocks = <&ccu CLK_BUS_MMC0>, + <&ccu CLK_MMC0>, + <&ccu CLK_MMC0_OUTPUT>, + <&ccu CLK_MMC0_SAMPLE>; + clock-names = "ahb", + "mmc", + "output", + "sample"; + resets = <&ccu RST_BUS_MMC0>; + reset-names = "ahb"; + interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + mmc1: mmc@01c10000 { + compatible = "allwinner,sun7i-a20-mmc"; + reg = <0x01c10000 0x1000>; + clocks = <&ccu CLK_BUS_MMC1>, + <&ccu CLK_MMC1>, + <&ccu CLK_MMC1_OUTPUT>, + <&ccu CLK_MMC1_SAMPLE>; + clock-names = "ahb", + "mmc", + "output", + "sample"; + resets = <&ccu RST_BUS_MMC1>; + reset-names = "ahb"; + interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + mmc2: mmc@01c11000 { + compatible = "allwinner,sun7i-a20-mmc"; + reg = <0x01c11000 0x1000>; + clocks = <&ccu CLK_BUS_MMC2>, + <&ccu CLK_MMC2>, + <&ccu CLK_MMC2_OUTPUT>, + <&ccu CLK_MMC2_SAMPLE>; + clock-names = "ahb", + "mmc", + "output", + "sample"; + resets = <&ccu RST_BUS_MMC2>; + reset-names = "ahb"; + interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + usb_otg: usb@01c19000 { + compatible = "allwinner,sun8i-h3-musb"; + reg = <0x01c19000 0x0400>; + clocks = <&ccu CLK_BUS_OTG>; + resets = <&ccu RST_BUS_OTG>; + interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "mc"; + phys = <&usbphy 0>; + phy-names = "usb"; + extcon = <&usbphy 0>; + status = "disabled"; + }; + + usbphy: phy@01c19400 { + compatible = "allwinner,sun8i-v3s-usb-phy"; + reg = <0x01c19400 0x2c>, + <0x01c1a800 0x4>; + reg-names = "phy_ctrl", + "pmu0"; + clocks = <&ccu CLK_USB_PHY0>; + clock-names = "usb0_phy"; + resets = <&ccu RST_USB_PHY0>; + reset-names = "usb0_reset"; + status = "disabled"; + #phy-cells = <1>; + }; + + ccu: clock@01c20000 { + compatible = "allwinner,sun8i-v3s-ccu"; + reg = <0x01c20000 0x400>; + clocks = <&osc24M>, <&osc32k>; + clock-names = "hosc", "losc"; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + rtc: rtc@01c20400 { + compatible = "allwinner,sun6i-a31-rtc"; + reg = <0x01c20400 0x54>; + interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>; + }; + + pio: pinctrl@01c20800 { + compatible = "allwinner,sun8i-v3s-pinctrl"; + reg = <0x01c20800 0x400>; + interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&osc32k>; + clock-names = "apb", "hosc", "losc"; + gpio-controller; + #gpio-cells = <3>; + interrupt-controller; + #interrupt-cells = <3>; + + uart0_pins_a: uart0@0 { + pins = "PB8", "PB9"; + function = "uart0"; + bias-pull-up; + }; + + mmc0_pins_a: mmc0@0 { + pins = "PF0", "PF1", "PF2", "PF3", + "PF4", "PF5"; + function = "mmc0"; + drive-strength = <30>; + bias-pull-up; + }; + }; + + timer@01c20c00 { + compatible = "allwinner,sun4i-a10-timer"; + reg = <0x01c20c00 0xa0>; + interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&osc24M>; + }; + + wdt0: watchdog@01c20ca0 { + compatible = "allwinner,sun6i-a31-wdt"; + reg = <0x01c20ca0 0x20>; + interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>; + }; + + uart0: serial@01c28000 { + compatible = "snps,dw-apb-uart"; + reg = <0x01c28000 0x400>; + interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&ccu CLK_BUS_UART0>; + resets = <&ccu RST_BUS_UART0>; + status = "disabled"; + }; + + uart1: serial@01c28400 { + compatible = "snps,dw-apb-uart"; + reg = <0x01c28400 0x400>; + interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&ccu CLK_BUS_UART1>; + resets = <&ccu RST_BUS_UART1>; + status = "disabled"; + }; + + uart2: serial@01c28800 { + compatible = "snps,dw-apb-uart"; + reg = <0x01c28800 0x400>; + interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&ccu CLK_BUS_UART2>; + resets = <&ccu RST_BUS_UART2>; + status = "disabled"; + }; + + gic: interrupt-controller@01c81000 { + compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic"; + reg = <0x01c81000 0x1000>, + <0x01c82000 0x1000>, + <0x01c84000 0x2000>, + <0x01c86000 0x2000>; + interrupt-controller; + #interrupt-cells = <3>; + interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; + }; + }; +}; diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h index 1bfb48bd52..a44ea77576 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h @@ -67,13 +67,22 @@ struct sunxi_ccm_reg { u32 dram_pll_cfg; /* 0xf8 PLL_DDR cfg register, A33 only */ u32 mbus_reset; /* 0xfc MBUS reset control, A33 only */ u32 dram_clk_gate; /* 0x100 DRAM module gating */ +#ifdef CONFIG_SUNXI_DE2 + u32 de_clk_cfg; /* 0x104 DE module clock */ +#else u32 be0_clk_cfg; /* 0x104 BE0 module clock */ +#endif u32 be1_clk_cfg; /* 0x108 BE1 module clock */ u32 fe0_clk_cfg; /* 0x10c FE0 module clock */ u32 fe1_clk_cfg; /* 0x110 FE1 module clock */ u32 mp_clk_cfg; /* 0x114 MP module clock */ +#ifdef CONFIG_SUNXI_DE2 + u32 lcd0_clk_cfg; /* 0x118 LCD0 module clock */ + u32 lcd1_clk_cfg; /* 0x11c LCD1 module clock */ +#else u32 lcd0_ch0_clk_cfg; /* 0x118 LCD0 CH0 module clock */ u32 lcd1_ch0_clk_cfg; /* 0x11c LCD1 CH0 module clock */ +#endif u32 reserved14[3]; u32 lcd0_ch1_clk_cfg; /* 0x12c LCD0 CH1 module clock */ u32 lcd1_ch1_clk_cfg; /* 0x130 LCD1 CH1 module clock */ @@ -85,7 +94,11 @@ struct sunxi_ccm_reg { u32 dmic_clk_cfg; /* 0x148 Digital Mic module clock*/ u32 reserved15; u32 hdmi_clk_cfg; /* 0x150 HDMI module clock */ +#ifdef CONFIG_SUNXI_DE2 + u32 hdmi_slow_clk_cfg; /* 0x154 HDMI slow module clock */ +#else u32 ps_clk_cfg; /* 0x154 PS module clock */ +#endif u32 mtc_clk_cfg; /* 0x158 MTC module clock */ u32 mbus0_clk_cfg; /* 0x15c MBUS0 module clock */ u32 mbus1_clk_cfg; /* 0x160 MBUS1 module clock */ @@ -142,6 +155,8 @@ struct sunxi_ccm_reg { u32 apb2_reset_cfg; /* 0x2d8 APB2 Reset config */ u32 reserved25[5]; u32 ccu_sec_switch; /* 0x2f0 CCU Security Switch, H3 only */ + u32 reserved26[11]; + u32 pll_lock_ctrl; /* 0x320 PLL lock control, R40 only */ }; /* apb2 bit field */ @@ -191,6 +206,7 @@ struct sunxi_ccm_reg { #define CCM_PLL3_CTRL_N_MASK (0x7f << CCM_PLL3_CTRL_N_SHIFT) #define CCM_PLL3_CTRL_N(n) ((((n) - 1) & 0x7f) << 8) #define CCM_PLL3_CTRL_INTEGER_MODE (0x1 << 24) +#define CCM_PLL3_CTRL_LOCK (0x1 << 28) #define CCM_PLL3_CTRL_EN (0x1 << 31) #define CCM_PLL5_CTRL_M(n) ((((n) - 1) & 0x3) << 0) @@ -220,6 +236,16 @@ struct sunxi_ccm_reg { #define CCM_MIPI_PLL_CTRL_LDO_EN (0x3 << 22) #define CCM_MIPI_PLL_CTRL_EN (0x1 << 31) +#define CCM_PLL10_CTRL_M_SHIFT 0 +#define CCM_PLL10_CTRL_M_MASK (0xf << CCM_PLL10_CTRL_M_SHIFT) +#define CCM_PLL10_CTRL_M(n) ((((n) - 1) & 0xf) << 0) +#define CCM_PLL10_CTRL_N_SHIFT 8 +#define CCM_PLL10_CTRL_N_MASK (0x7f << CCM_PLL10_CTRL_N_SHIFT) +#define CCM_PLL10_CTRL_N(n) ((((n) - 1) & 0x7f) << 8) +#define CCM_PLL10_CTRL_INTEGER_MODE (0x1 << 24) +#define CCM_PLL10_CTRL_LOCK (0x1 << 28) +#define CCM_PLL10_CTRL_EN (0x1 << 31) + #define CCM_PLL11_CTRL_N(n) ((((n) - 1) & 0x3f) << 8) #define CCM_PLL11_CTRL_SIGMA_DELTA_EN (0x1 << 24) #define CCM_PLL11_CTRL_UPD (0x1 << 30) @@ -271,9 +297,15 @@ struct sunxi_ccm_reg { #define AHB_GATE_OFFSET_DRC0 25 #define AHB_GATE_OFFSET_DE_FE0 14 #define AHB_GATE_OFFSET_DE_BE0 12 +#define AHB_GATE_OFFSET_DE 12 #define AHB_GATE_OFFSET_HDMI 11 +#ifndef CONFIG_SUNXI_DE2 #define AHB_GATE_OFFSET_LCD1 5 #define AHB_GATE_OFFSET_LCD0 4 +#else +#define AHB_GATE_OFFSET_LCD1 4 +#define AHB_GATE_OFFSET_LCD0 3 +#endif #define CCM_MMC_CTRL_M(x) ((x) - 1) #define CCM_MMC_CTRL_OCLK_DLY(x) ((x) << 8) @@ -355,6 +387,12 @@ struct sunxi_ccm_reg { #define CCM_LCD_CH1_CTRL_PLL7_2X (3 << 24) #define CCM_LCD_CH1_CTRL_GATE (0x1 << 31) +#define CCM_LCD0_CTRL_GATE (0x1 << 31) +#define CCM_LCD0_CTRL_M(n) ((((n) - 1) & 0xf) << 0) + +#define CCM_LCD1_CTRL_GATE (0x1 << 31) +#define CCM_LCD1_CTRL_M(n) ((((n) - 1) & 0xf) << 0) + #define CCM_HDMI_CTRL_M(n) ((((n) - 1) & 0xf) << 0) #define CCM_HDMI_CTRL_PLL_MASK (3 << 24) #define CCM_HDMI_CTRL_PLL3 (0 << 24) @@ -364,6 +402,8 @@ struct sunxi_ccm_reg { #define CCM_HDMI_CTRL_DDC_GATE (0x1 << 30) #define CCM_HDMI_CTRL_GATE (0x1 << 31) +#define CCM_HDMI_SLOW_CTRL_DDC_GATE (1 << 31) + #if defined(CONFIG_MACH_SUN50I) #define MBUS_CLK_DEFAULT 0x81000002 /* PLL6x2 / 3 */ #elif defined(CONFIG_MACH_SUN8I) @@ -391,9 +431,16 @@ struct sunxi_ccm_reg { #define AHB_RESET_OFFSET_DRC0 25 #define AHB_RESET_OFFSET_DE_FE0 14 #define AHB_RESET_OFFSET_DE_BE0 12 +#define AHB_RESET_OFFSET_DE 12 #define AHB_RESET_OFFSET_HDMI 11 +#define AHB_RESET_OFFSET_HDMI2 10 +#ifndef CONFIG_SUNXI_DE2 #define AHB_RESET_OFFSET_LCD1 5 #define AHB_RESET_OFFSET_LCD0 4 +#else +#define AHB_RESET_OFFSET_LCD1 4 +#define AHB_RESET_OFFSET_LCD0 3 +#endif /* ahb_reset2 offsets */ #define AHB_RESET_OFFSET_EPHY 2 @@ -416,6 +463,13 @@ struct sunxi_ccm_reg { #define CCM_DE_CTRL_PLL10 (5 << 24) #define CCM_DE_CTRL_GATE (1 << 31) +/* CCM bits common to all Display Engine 2.0 clock ctrl regs */ +#define CCM_DE2_CTRL_M(n) ((((n) - 1) & 0xf) << 0) +#define CCM_DE2_CTRL_PLL_MASK (3 << 24) +#define CCM_DE2_CTRL_PLL6_2X (0 << 24) +#define CCM_DE2_CTRL_PLL10 (1 << 24) +#define CCM_DE2_CTRL_GATE (0x1 << 31) + /* CCU security switch, H3 only */ #define CCM_SEC_SWITCH_MBUS_NONSEC (1 << 2) #define CCM_SEC_SWITCH_BUS_NONSEC (1 << 1) @@ -424,7 +478,9 @@ struct sunxi_ccm_reg { #ifndef __ASSEMBLY__ void clock_set_pll1(unsigned int hz); void clock_set_pll3(unsigned int hz); +void clock_set_pll3_factors(int m, int n); void clock_set_pll5(unsigned int clk, bool sigma_delta_enable); +void clock_set_pll10(unsigned int hz); void clock_set_pll11(unsigned int clk, bool sigma_delta_enable); void clock_set_mipi_pll(unsigned int hz); unsigned int clock_get_pll3(void); diff --git a/arch/arm/include/asm/arch-sunxi/cpu.h b/arch/arm/include/asm/arch-sunxi/cpu.h index e8e670e7e9..caec865264 100644 --- a/arch/arm/include/asm/arch-sunxi/cpu.h +++ b/arch/arm/include/asm/arch-sunxi/cpu.h @@ -16,5 +16,6 @@ #define SOCID_A64 0x1689 #define SOCID_H3 0x1680 #define SOCID_H5 0x1718 +#define SOCID_R40 0x1701 #endif /* _SUNXI_CPU_H */ diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h b/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h index ea672fe844..88c3f13817 100644 --- a/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h +++ b/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h @@ -108,7 +108,7 @@ defined(CONFIG_MACH_SUN50I) #define SUNXI_TP_BASE 0x01c25000 #define SUNXI_PMU_BASE 0x01c25400 -#ifdef CONFIG_MACH_SUN7I +#if defined CONFIG_MACH_SUN7I || defined CONFIG_MACH_SUN8I_R40 #define SUNXI_CPUCFG_BASE 0x01c25c00 #endif @@ -167,7 +167,9 @@ defined(CONFIG_MACH_SUN50I) #define SUNXI_RTC_BASE 0x01f00000 #define SUNXI_PRCM_BASE 0x01f01400 -#if defined CONFIG_SUNXI_GEN_SUN6I && !defined CONFIG_MACH_SUN8I_A83T +#if defined CONFIG_SUNXI_GEN_SUN6I && \ + !defined CONFIG_MACH_SUN8I_A83T && \ + !defined CONFIG_MACH_SUN8I_R40 #define SUNXI_CPUCFG_BASE 0x01f01c00 #endif diff --git a/arch/arm/include/asm/arch-sunxi/display.h b/arch/arm/include/asm/arch-sunxi/display.h index b64f310b8b..93803addfb 100644 --- a/arch/arm/include/asm/arch-sunxi/display.h +++ b/arch/arm/include/asm/arch-sunxi/display.h @@ -157,52 +157,6 @@ struct sunxi_de_be_reg { u32 output_color_coef[12]; /* 0x9d0 */ }; -struct sunxi_lcdc_reg { - u32 ctrl; /* 0x00 */ - u32 int0; /* 0x04 */ - u32 int1; /* 0x08 */ - u8 res0[0x04]; /* 0x0c */ - u32 tcon0_frm_ctrl; /* 0x10 */ - u32 tcon0_frm_seed[6]; /* 0x14 */ - u32 tcon0_frm_table[4]; /* 0x2c */ - u8 res1[4]; /* 0x3c */ - u32 tcon0_ctrl; /* 0x40 */ - u32 tcon0_dclk; /* 0x44 */ - u32 tcon0_timing_active; /* 0x48 */ - u32 tcon0_timing_h; /* 0x4c */ - u32 tcon0_timing_v; /* 0x50 */ - u32 tcon0_timing_sync; /* 0x54 */ - u32 tcon0_hv_intf; /* 0x58 */ - u8 res2[0x04]; /* 0x5c */ - u32 tcon0_cpu_intf; /* 0x60 */ - u32 tcon0_cpu_wr_dat; /* 0x64 */ - u32 tcon0_cpu_rd_dat0; /* 0x68 */ - u32 tcon0_cpu_rd_dat1; /* 0x6c */ - u32 tcon0_ttl_timing0; /* 0x70 */ - u32 tcon0_ttl_timing1; /* 0x74 */ - u32 tcon0_ttl_timing2; /* 0x78 */ - u32 tcon0_ttl_timing3; /* 0x7c */ - u32 tcon0_ttl_timing4; /* 0x80 */ - u32 tcon0_lvds_intf; /* 0x84 */ - u32 tcon0_io_polarity; /* 0x88 */ - u32 tcon0_io_tristate; /* 0x8c */ - u32 tcon1_ctrl; /* 0x90 */ - u32 tcon1_timing_source; /* 0x94 */ - u32 tcon1_timing_scale; /* 0x98 */ - u32 tcon1_timing_out; /* 0x9c */ - u32 tcon1_timing_h; /* 0xa0 */ - u32 tcon1_timing_v; /* 0xa4 */ - u32 tcon1_timing_sync; /* 0xa8 */ - u8 res3[0x44]; /* 0xac */ - u32 tcon1_io_polarity; /* 0xf0 */ - u32 tcon1_io_tristate; /* 0xf4 */ - u8 res4[0x108]; /* 0xf8 */ - u32 mux_ctrl; /* 0x200 */ - u8 res5[0x1c]; /* 0x204 */ - u32 lvds_ana0; /* 0x220 */ - u32 lvds_ana1; /* 0x224 */ -}; - struct sunxi_hdmi_reg { u32 version_id; /* 0x000 */ u32 ctrl; /* 0x004 */ @@ -347,63 +301,6 @@ struct sunxi_tve_reg { #define SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE 1 /* - * LCDC register constants. - */ -#define SUNXI_LCDC_X(x) (((x) - 1) << 16) -#define SUNXI_LCDC_Y(y) (((y) - 1) << 0) -#define SUNXI_LCDC_TCON_VSYNC_MASK (1 << 24) -#define SUNXI_LCDC_TCON_HSYNC_MASK (1 << 25) -#define SUNXI_LCDC_CTRL_IO_MAP_MASK (1 << 0) -#define SUNXI_LCDC_CTRL_IO_MAP_TCON0 (0 << 0) -#define SUNXI_LCDC_CTRL_IO_MAP_TCON1 (1 << 0) -#define SUNXI_LCDC_CTRL_TCON_ENABLE (1 << 31) -#define SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 ((1 << 31) | (0 << 4)) -#define SUNXI_LCDC_TCON0_FRM_CTRL_RGB565 ((1 << 31) | (5 << 4)) -#define SUNXI_LCDC_TCON0_FRM_SEED 0x11111111 -#define SUNXI_LCDC_TCON0_FRM_TAB0 0x01010000 -#define SUNXI_LCDC_TCON0_FRM_TAB1 0x15151111 -#define SUNXI_LCDC_TCON0_FRM_TAB2 0x57575555 -#define SUNXI_LCDC_TCON0_FRM_TAB3 0x7f7f7777 -#define SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(n) (((n) & 0x1f) << 4) -#define SUNXI_LCDC_TCON0_CTRL_ENABLE (1 << 31) -#define SUNXI_LCDC_TCON0_DCLK_DIV(n) ((n) << 0) -#define SUNXI_LCDC_TCON0_DCLK_ENABLE (0xf << 28) -#define SUNXI_LCDC_TCON0_TIMING_H_BP(n) (((n) - 1) << 0) -#define SUNXI_LCDC_TCON0_TIMING_H_TOTAL(n) (((n) - 1) << 16) -#define SUNXI_LCDC_TCON0_TIMING_V_BP(n) (((n) - 1) << 0) -#define SUNXI_LCDC_TCON0_TIMING_V_TOTAL(n) (((n) * 2) << 16) -#ifdef CONFIG_SUNXI_GEN_SUN6I -#define SUNXI_LCDC_TCON0_LVDS_CLK_SEL_TCON0 (1 << 20) -#else -#define SUNXI_LCDC_TCON0_LVDS_CLK_SEL_TCON0 0 /* NA */ -#endif -#define SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(n) ((n) << 26) -#define SUNXI_LCDC_TCON0_LVDS_INTF_ENABLE (1 << 31) -#define SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(x) ((x) << 28) -#define SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(n) (((n) & 0x1f) << 4) -#define SUNXI_LCDC_TCON1_CTRL_INTERLACE_ENABLE (1 << 20) -#define SUNXI_LCDC_TCON1_CTRL_ENABLE (1 << 31) -#define SUNXI_LCDC_TCON1_TIMING_H_BP(n) (((n) - 1) << 0) -#define SUNXI_LCDC_TCON1_TIMING_H_TOTAL(n) (((n) - 1) << 16) -#define SUNXI_LCDC_TCON1_TIMING_V_BP(n) (((n) - 1) << 0) -#define SUNXI_LCDC_TCON1_TIMING_V_TOTAL(n) ((n) << 16) -#define SUNXI_LCDC_MUX_CTRL_SRC0_MASK (0xf << 0) -#define SUNXI_LCDC_MUX_CTRL_SRC0(x) ((x) << 0) -#define SUNXI_LCDC_MUX_CTRL_SRC1_MASK (0xf << 4) -#define SUNXI_LCDC_MUX_CTRL_SRC1(x) ((x) << 4) -#ifdef CONFIG_SUNXI_GEN_SUN6I -#define SUNXI_LCDC_LVDS_ANA0 0x40040320 -#define SUNXI_LCDC_LVDS_ANA0_EN_MB (1 << 31) -#define SUNXI_LCDC_LVDS_ANA0_DRVC (1 << 24) -#define SUNXI_LCDC_LVDS_ANA0_DRVD(x) ((x) << 20) -#else -#define SUNXI_LCDC_LVDS_ANA0 0x3f310000 -#define SUNXI_LCDC_LVDS_ANA0_UPDATE (1 << 22) -#endif -#define SUNXI_LCDC_LVDS_ANA1_INIT1 (0x1f << 26 | 0x1f << 10) -#define SUNXI_LCDC_LVDS_ANA1_INIT2 (0x1f << 16 | 0x1f << 00) - -/* * HDMI register constants. */ #define SUNXI_HDMI_X(x) (((x) - 1) << 0) diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h index 1dc82205b7..f452f889f9 100644 --- a/arch/arm/include/asm/arch-sunxi/dram.h +++ b/arch/arm/include/asm/arch-sunxi/dram.h @@ -24,7 +24,9 @@ #include <asm/arch/dram_sun8i_a33.h> #elif defined(CONFIG_MACH_SUN8I_A83T) #include <asm/arch/dram_sun8i_a83t.h> -#elif defined(CONFIG_MACH_SUNXI_H3_H5) || defined(CONFIG_MACH_SUN50I) +#elif defined(CONFIG_MACH_SUNXI_H3_H5) || \ + defined(CONFIG_MACH_SUN8I_R40) || \ + defined(CONFIG_MACH_SUN50I) #include <asm/arch/dram_sun8i_h3.h> #elif defined(CONFIG_MACH_SUN9I) #include <asm/arch/dram_sun9i.h> diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.h b/arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.h index 25d07d9863..2770986b61 100644 --- a/arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.h +++ b/arch/arm/include/asm/arch-sunxi/dram_sun8i_h3.h @@ -15,7 +15,8 @@ struct sunxi_mctl_com_reg { u32 cr; /* 0x00 control register */ - u8 res0[0x8]; /* 0x04 */ + u32 cr_r1; /* 0x04 rank 1 control register (R40 only) */ + u8 res0[0x4]; /* 0x08 */ u32 tmr; /* 0x0c (unused on H3) */ u32 mcr[16][2]; /* 0x10 */ u32 bwcr; /* 0x90 bandwidth control register */ @@ -63,6 +64,17 @@ struct sunxi_mctl_com_reg { #define MCTL_CR_DUAL_RANK (0x1 << 0) #define MCTL_CR_SINGLE_RANK (0x0 << 0) +/* + * CR_R1 is a register found in the R40's DRAM controller. It sets various + * parameters for rank 1. Bits [11:0] have the same meaning as the bits in + * MCTL_CR, but they apply to rank 1 only. This implies we can have + * different chips for rank 1 than rank 0. + * + * As address line A15 and CS1 chip select for rank 1 are muxed on the same + * pin, if single rank is used, A15 must be muxed in. + */ +#define MCTL_CR_R1_MUX_A15 (0x1 << 21) + #define PROTECT_MAGIC (0x94be6fa3) struct sunxi_mctl_ctl_reg { @@ -72,7 +84,8 @@ struct sunxi_mctl_ctl_reg { u32 clken; /* 0x0c */ u32 pgsr[2]; /* 0x10 PHY general status registers */ u32 statr; /* 0x18 */ - u8 res1[0x14]; /* 0x1c */ + u8 res1[0x10]; /* 0x1c */ + u32 lp3mr11; /* 0x2c */ u32 mr[4]; /* 0x30 mode registers */ u32 pllgcr; /* 0x40 */ u32 ptr[5]; /* 0x44 PHY timing registers */ @@ -120,7 +133,8 @@ struct sunxi_mctl_ctl_reg { struct { /* 0x300 DATX8 modules*/ u32 mdlr; /* 0x00 master delay line register */ u32 lcdlr[3]; /* 0x04 local calibrated delay line registers */ - u32 bdlr[12]; /* 0x10 bit delay line registers */ + u32 bdlr[11]; /* 0x10 bit delay line registers */ + u32 sdlr; /* 0x3c output enable bit delay registers */ u32 gtr; /* 0x40 general timing register */ u32 gcr; /* 0x44 general configuration register */ u32 gsr[3]; /* 0x48 general status registers */ diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h index 85a4ec3b0e..24f85206c8 100644 --- a/arch/arm/include/asm/arch-sunxi/gpio.h +++ b/arch/arm/include/asm/arch-sunxi/gpio.h @@ -161,6 +161,7 @@ enum sunxi_gpio_number { #define SUN8I_GPB_UART2 2 #define SUN8I_A33_GPB_UART0 3 #define SUN8I_A83T_GPB_UART0 2 +#define SUN8I_V3S_GPB_UART0 3 #define SUN50I_GPB_UART0 4 #define SUNXI_GPC_NAND 2 diff --git a/arch/arm/include/asm/arch-sunxi/lcdc.h b/arch/arm/include/asm/arch-sunxi/lcdc.h new file mode 100644 index 0000000000..a751698b4f --- /dev/null +++ b/arch/arm/include/asm/arch-sunxi/lcdc.h @@ -0,0 +1,128 @@ +/* + * Sunxi platform timing controller register and constant defines + * + * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com> + * (C) Copyright 2017 Jernej Skrabec <jernej.skrabec@siol.net> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _LCDC_H +#define _LCDC_H + +#include <fdtdec.h> + +struct sunxi_lcdc_reg { + u32 ctrl; /* 0x00 */ + u32 int0; /* 0x04 */ + u32 int1; /* 0x08 */ + u8 res0[0x04]; /* 0x0c */ + u32 tcon0_frm_ctrl; /* 0x10 */ + u32 tcon0_frm_seed[6]; /* 0x14 */ + u32 tcon0_frm_table[4]; /* 0x2c */ + u8 res1[4]; /* 0x3c */ + u32 tcon0_ctrl; /* 0x40 */ + u32 tcon0_dclk; /* 0x44 */ + u32 tcon0_timing_active; /* 0x48 */ + u32 tcon0_timing_h; /* 0x4c */ + u32 tcon0_timing_v; /* 0x50 */ + u32 tcon0_timing_sync; /* 0x54 */ + u32 tcon0_hv_intf; /* 0x58 */ + u8 res2[0x04]; /* 0x5c */ + u32 tcon0_cpu_intf; /* 0x60 */ + u32 tcon0_cpu_wr_dat; /* 0x64 */ + u32 tcon0_cpu_rd_dat0; /* 0x68 */ + u32 tcon0_cpu_rd_dat1; /* 0x6c */ + u32 tcon0_ttl_timing0; /* 0x70 */ + u32 tcon0_ttl_timing1; /* 0x74 */ + u32 tcon0_ttl_timing2; /* 0x78 */ + u32 tcon0_ttl_timing3; /* 0x7c */ + u32 tcon0_ttl_timing4; /* 0x80 */ + u32 tcon0_lvds_intf; /* 0x84 */ + u32 tcon0_io_polarity; /* 0x88 */ + u32 tcon0_io_tristate; /* 0x8c */ + u32 tcon1_ctrl; /* 0x90 */ + u32 tcon1_timing_source; /* 0x94 */ + u32 tcon1_timing_scale; /* 0x98 */ + u32 tcon1_timing_out; /* 0x9c */ + u32 tcon1_timing_h; /* 0xa0 */ + u32 tcon1_timing_v; /* 0xa4 */ + u32 tcon1_timing_sync; /* 0xa8 */ + u8 res3[0x44]; /* 0xac */ + u32 tcon1_io_polarity; /* 0xf0 */ + u32 tcon1_io_tristate; /* 0xf4 */ + u8 res4[0x108]; /* 0xf8 */ + u32 mux_ctrl; /* 0x200 */ + u8 res5[0x1c]; /* 0x204 */ + u32 lvds_ana0; /* 0x220 */ + u32 lvds_ana1; /* 0x224 */ +}; + +/* + * LCDC register constants. + */ +#define SUNXI_LCDC_X(x) (((x) - 1) << 16) +#define SUNXI_LCDC_Y(y) (((y) - 1) << 0) +#define SUNXI_LCDC_TCON_VSYNC_MASK (1 << 24) +#define SUNXI_LCDC_TCON_HSYNC_MASK (1 << 25) +#define SUNXI_LCDC_CTRL_IO_MAP_MASK (1 << 0) +#define SUNXI_LCDC_CTRL_IO_MAP_TCON0 (0 << 0) +#define SUNXI_LCDC_CTRL_IO_MAP_TCON1 (1 << 0) +#define SUNXI_LCDC_CTRL_TCON_ENABLE (1 << 31) +#define SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 ((1 << 31) | (0 << 4)) +#define SUNXI_LCDC_TCON0_FRM_CTRL_RGB565 ((1 << 31) | (5 << 4)) +#define SUNXI_LCDC_TCON0_FRM_SEED 0x11111111 +#define SUNXI_LCDC_TCON0_FRM_TAB0 0x01010000 +#define SUNXI_LCDC_TCON0_FRM_TAB1 0x15151111 +#define SUNXI_LCDC_TCON0_FRM_TAB2 0x57575555 +#define SUNXI_LCDC_TCON0_FRM_TAB3 0x7f7f7777 +#define SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(n) (((n) & 0x1f) << 4) +#define SUNXI_LCDC_TCON0_CTRL_ENABLE (1 << 31) +#define SUNXI_LCDC_TCON0_DCLK_DIV(n) ((n) << 0) +#define SUNXI_LCDC_TCON0_DCLK_ENABLE (0xf << 28) +#define SUNXI_LCDC_TCON0_TIMING_H_BP(n) (((n) - 1) << 0) +#define SUNXI_LCDC_TCON0_TIMING_H_TOTAL(n) (((n) - 1) << 16) +#define SUNXI_LCDC_TCON0_TIMING_V_BP(n) (((n) - 1) << 0) +#define SUNXI_LCDC_TCON0_TIMING_V_TOTAL(n) (((n) * 2) << 16) +#ifdef CONFIG_SUNXI_GEN_SUN6I +#define SUNXI_LCDC_TCON0_LVDS_CLK_SEL_TCON0 (1 << 20) +#else +#define SUNXI_LCDC_TCON0_LVDS_CLK_SEL_TCON0 0 /* NA */ +#endif +#define SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(n) ((n) << 26) +#define SUNXI_LCDC_TCON0_LVDS_INTF_ENABLE (1 << 31) +#define SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(x) ((x) << 28) +#define SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(n) (((n) & 0x1f) << 4) +#define SUNXI_LCDC_TCON1_CTRL_INTERLACE_ENABLE (1 << 20) +#define SUNXI_LCDC_TCON1_CTRL_ENABLE (1 << 31) +#define SUNXI_LCDC_TCON1_TIMING_H_BP(n) (((n) - 1) << 0) +#define SUNXI_LCDC_TCON1_TIMING_H_TOTAL(n) (((n) - 1) << 16) +#define SUNXI_LCDC_TCON1_TIMING_V_BP(n) (((n) - 1) << 0) +#define SUNXI_LCDC_TCON1_TIMING_V_TOTAL(n) ((n) << 16) +#define SUNXI_LCDC_MUX_CTRL_SRC0_MASK (0xf << 0) +#define SUNXI_LCDC_MUX_CTRL_SRC0(x) ((x) << 0) +#define SUNXI_LCDC_MUX_CTRL_SRC1_MASK (0xf << 4) +#define SUNXI_LCDC_MUX_CTRL_SRC1(x) ((x) << 4) +#ifdef CONFIG_SUNXI_GEN_SUN6I +#define SUNXI_LCDC_LVDS_ANA0 0x40040320 +#define SUNXI_LCDC_LVDS_ANA0_EN_MB (1 << 31) +#define SUNXI_LCDC_LVDS_ANA0_DRVC (1 << 24) +#define SUNXI_LCDC_LVDS_ANA0_DRVD(x) ((x) << 20) +#else +#define SUNXI_LCDC_LVDS_ANA0 0x3f310000 +#define SUNXI_LCDC_LVDS_ANA0_UPDATE (1 << 22) +#endif +#define SUNXI_LCDC_LVDS_ANA1_INIT1 (0x1f << 26 | 0x1f << 10) +#define SUNXI_LCDC_LVDS_ANA1_INIT2 (0x1f << 16 | 0x1f << 00) + +void lcdc_init(struct sunxi_lcdc_reg * const lcdc); +void lcdc_enable(struct sunxi_lcdc_reg * const lcdc, int depth); +void lcdc_tcon0_mode_set(struct sunxi_lcdc_reg * const lcdc, + const struct display_timing *mode, + int clk_div, bool for_ext_vga_dac, + int depth, int dclk_phase); +void lcdc_tcon1_mode_set(struct sunxi_lcdc_reg * const lcdc, + const struct display_timing *mode, + bool ext_hvsync, bool is_composite); + +#endif /* _LCDC_H */ diff --git a/arch/arm/include/asm/arch-sunxi/timer.h b/arch/arm/include/asm/arch-sunxi/timer.h index a665309803..ccdf942534 100644 --- a/arch/arm/include/asm/arch-sunxi/timer.h +++ b/arch/arm/include/asm/arch-sunxi/timer.h @@ -67,7 +67,7 @@ struct sunxi_timer_reg { struct sunxi_timer timer[6]; /* We have 6 timers */ u8 res2[16]; struct sunxi_avs avs; -#ifdef CONFIG_SUNXI_GEN_SUN4I +#if defined(CONFIG_SUNXI_GEN_SUN4I) || defined(CONFIG_MACH_SUN8I_R40) struct sunxi_wdog wdog; /* 0x90 */ /* XXX the following is not accurate for sun5i/sun7i */ struct sunxi_64cnt cnt64; /* 0xa0 */ @@ -77,8 +77,7 @@ struct sunxi_timer_reg { struct sunxi_tgp tgp[4]; u8 res5[8]; u32 cpu_cfg; -#endif -#ifdef CONFIG_SUNXI_GEN_SUN6I +#elif defined(CONFIG_SUNXI_GEN_SUN6I) u8 res3[16]; struct sunxi_wdog wdog[5]; /* We have 5 watchdogs */ #endif diff --git a/arch/arm/include/asm/arch-sunxi/watchdog.h b/arch/arm/include/asm/arch-sunxi/watchdog.h index 8108be97ba..ce6d664856 100644 --- a/arch/arm/include/asm/arch-sunxi/watchdog.h +++ b/arch/arm/include/asm/arch-sunxi/watchdog.h @@ -13,7 +13,10 @@ #define WDT_CTRL_RESTART (0x1 << 0) #define WDT_CTRL_KEY (0x0a57 << 1) -#if defined(CONFIG_MACH_SUN4I) || defined(CONFIG_MACH_SUN5I) || defined(CONFIG_MACH_SUN7I) +#if defined(CONFIG_MACH_SUN4I) || \ + defined(CONFIG_MACH_SUN5I) || \ + defined(CONFIG_MACH_SUN7I) || \ + defined(CONFIG_MACH_SUN8I_R40) #define WDT_MODE_EN (0x1 << 0) #define WDT_MODE_RESET_EN (0x1 << 1) diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile index efab4811ee..5510aa5435 100644 --- a/arch/arm/mach-sunxi/Makefile +++ b/arch/arm/mach-sunxi/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_MACH_SUN8I_A23) += dram_sun8i_a23.o obj-$(CONFIG_MACH_SUN8I_A33) += dram_sun8i_a33.o obj-$(CONFIG_MACH_SUN8I_A83T) += dram_sun8i_a83t.o obj-$(CONFIG_MACH_SUNXI_H3_H5) += dram_sun8i_h3.o +obj-$(CONFIG_MACH_SUN8I_R40) += dram_sun8i_h3.o obj-$(CONFIG_MACH_SUN9I) += dram_sun9i.o obj-$(CONFIG_MACH_SUN50I) += dram_sun8i_h3.o endif diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c index 5e03d03943..4507279cc5 100644 --- a/arch/arm/mach-sunxi/board.c +++ b/arch/arm/mach-sunxi/board.c @@ -69,12 +69,14 @@ struct mm_region *mem_map = sunxi_mem_map; static int gpio_init(void) { #if CONFIG_CONS_INDEX == 1 && defined(CONFIG_UART0_PORT_F) -#if defined(CONFIG_MACH_SUN4I) || defined(CONFIG_MACH_SUN7I) +#if defined(CONFIG_MACH_SUN4I) || \ + defined(CONFIG_MACH_SUN7I) || \ + defined(CONFIG_MACH_SUN8I_R40) /* disable GPB22,23 as uart0 tx,rx to avoid conflict */ sunxi_gpio_set_cfgpin(SUNXI_GPB(22), SUNXI_GPIO_INPUT); sunxi_gpio_set_cfgpin(SUNXI_GPB(23), SUNXI_GPIO_INPUT); #endif -#if defined(CONFIG_MACH_SUN8I) +#if defined(CONFIG_MACH_SUN8I) && !defined(CONFIG_MACH_SUN8I_R40) sunxi_gpio_set_cfgpin(SUNXI_GPF(2), SUN8I_GPF_UART0); sunxi_gpio_set_cfgpin(SUNXI_GPF(4), SUN8I_GPF_UART0); #else @@ -82,7 +84,9 @@ static int gpio_init(void) sunxi_gpio_set_cfgpin(SUNXI_GPF(4), SUNXI_GPF_UART0); #endif sunxi_gpio_set_pull(SUNXI_GPF(4), 1); -#elif CONFIG_CONS_INDEX == 1 && (defined(CONFIG_MACH_SUN4I) || defined(CONFIG_MACH_SUN7I)) +#elif CONFIG_CONS_INDEX == 1 && (defined(CONFIG_MACH_SUN4I) || \ + defined(CONFIG_MACH_SUN7I) || \ + defined(CONFIG_MACH_SUN8I_R40)) sunxi_gpio_set_cfgpin(SUNXI_GPB(22), SUN4I_GPB_UART0); sunxi_gpio_set_cfgpin(SUNXI_GPB(23), SUN4I_GPB_UART0); sunxi_gpio_set_pull(SUNXI_GPB(23), SUNXI_GPIO_PULL_UP); @@ -110,6 +114,10 @@ static int gpio_init(void) sunxi_gpio_set_cfgpin(SUNXI_GPB(9), SUN8I_A83T_GPB_UART0); sunxi_gpio_set_cfgpin(SUNXI_GPB(10), SUN8I_A83T_GPB_UART0); sunxi_gpio_set_pull(SUNXI_GPB(10), SUNXI_GPIO_PULL_UP); +#elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN8I_V3S) + sunxi_gpio_set_cfgpin(SUNXI_GPB(8), SUN8I_V3S_GPB_UART0); + sunxi_gpio_set_cfgpin(SUNXI_GPB(9), SUN8I_V3S_GPB_UART0); + sunxi_gpio_set_pull(SUNXI_GPB(9), SUNXI_GPIO_PULL_UP); #elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN9I) sunxi_gpio_set_cfgpin(SUNXI_GPH(12), SUN9I_GPH_UART0); sunxi_gpio_set_cfgpin(SUNXI_GPH(13), SUN9I_GPH_UART0); @@ -266,7 +274,7 @@ void board_init_f(ulong dummy) void reset_cpu(ulong addr) { -#ifdef CONFIG_SUNXI_GEN_SUN4I +#if defined(CONFIG_SUNXI_GEN_SUN4I) || defined(CONFIG_MACH_SUN8I_R40) static const struct sunxi_wdog *wdog = &((struct sunxi_timer_reg *)SUNXI_TIMER_BASE)->wdog; @@ -278,8 +286,7 @@ void reset_cpu(ulong addr) /* sun5i sometimes gets stuck without this */ writel(WDT_MODE_RESET_EN | WDT_MODE_EN, &wdog->mode); } -#endif -#ifdef CONFIG_SUNXI_GEN_SUN6I +#elif defined(CONFIG_SUNXI_GEN_SUN6I) static const struct sunxi_wdog *wdog = ((struct sunxi_timer_reg *)SUNXI_TIMER_BASE)->wdog; diff --git a/arch/arm/mach-sunxi/clock_sun6i.c b/arch/arm/mach-sunxi/clock_sun6i.c index 4762fbf0c3..631bc6e250 100644 --- a/arch/arm/mach-sunxi/clock_sun6i.c +++ b/arch/arm/mach-sunxi/clock_sun6i.c @@ -35,6 +35,11 @@ void clock_init_safe(void) clrbits_le32(&prcm->pll_ctrl1, PRCM_PLL_CTRL_LDO_KEY_MASK); #endif +#if defined(CONFIG_MACH_SUN8I_R40) || defined(CONFIG_MACH_SUN50I) + /* Set PLL lock enable bits and switch to old lock mode */ + writel(GENMASK(12, 0), &ccm->pll_lock_ctrl); +#endif + clock_set_pll1(408000000); writel(PLL6_CFG_DEFAULT, &ccm->pll6_cfg); @@ -145,6 +150,22 @@ void clock_set_pll3(unsigned int clk) &ccm->pll3_cfg); } +#ifdef CONFIG_SUNXI_DE2 +void clock_set_pll3_factors(int m, int n) +{ + struct sunxi_ccm_reg * const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + + /* PLL3 rate = 24000000 * n / m */ + writel(CCM_PLL3_CTRL_EN | CCM_PLL3_CTRL_INTEGER_MODE | + CCM_PLL3_CTRL_N(n) | CCM_PLL3_CTRL_M(m), + &ccm->pll3_cfg); + + while (!(readl(&ccm->pll3_cfg) & CCM_PLL3_CTRL_LOCK)) + ; +} +#endif + void clock_set_pll5(unsigned int clk, bool sigma_delta_enable) { struct sunxi_ccm_reg * const ccm = @@ -217,7 +238,31 @@ done: } #endif -#if defined(CONFIG_MACH_SUN8I_A33) || defined(CONFIG_MACH_SUN50I) +#ifdef CONFIG_SUNXI_DE2 +void clock_set_pll10(unsigned int clk) +{ + struct sunxi_ccm_reg * const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + const int m = 2; /* 12 MHz steps */ + + if (clk == 0) { + clrbits_le32(&ccm->pll10_cfg, CCM_PLL10_CTRL_EN); + return; + } + + /* PLL10 rate = 24000000 * n / m */ + writel(CCM_PLL10_CTRL_EN | CCM_PLL10_CTRL_INTEGER_MODE | + CCM_PLL10_CTRL_N(clk / (24000000 / m)) | CCM_PLL10_CTRL_M(m), + &ccm->pll10_cfg); + + while (!(readl(&ccm->pll10_cfg) & CCM_PLL10_CTRL_LOCK)) + ; +} +#endif + +#if defined(CONFIG_MACH_SUN8I_A33) || \ + defined(CONFIG_MACH_SUN8I_R40) || \ + defined(CONFIG_MACH_SUN50I) void clock_set_pll11(unsigned int clk, bool sigma_delta_enable) { struct sunxi_ccm_reg * const ccm = diff --git a/arch/arm/mach-sunxi/cpu_info.c b/arch/arm/mach-sunxi/cpu_info.c index 85633ccec2..25a5ec26a0 100644 --- a/arch/arm/mach-sunxi/cpu_info.c +++ b/arch/arm/mach-sunxi/cpu_info.c @@ -87,6 +87,10 @@ int print_cpuinfo(void) printf("CPU: Allwinner A83T (SUN8I %04x)\n", sunxi_get_sram_id()); #elif defined CONFIG_MACH_SUN8I_H3 printf("CPU: Allwinner H3 (SUN8I %04x)\n", sunxi_get_sram_id()); +#elif defined CONFIG_MACH_SUN8I_R40 + printf("CPU: Allwinner R40 (SUN8I %04x)\n", sunxi_get_sram_id()); +#elif defined CONFIG_MACH_SUN8I_V3S + printf("CPU: Allwinner V3s (SUN8I %04x)\n", sunxi_get_sram_id()); #elif defined CONFIG_MACH_SUN9I puts("CPU: Allwinner A80 (SUN9I)\n"); #elif defined CONFIG_MACH_SUN50I diff --git a/arch/arm/mach-sunxi/dram_sun8i_h3.c b/arch/arm/mach-sunxi/dram_sun8i_h3.c index d681a9df8b..2d12661a14 100644 --- a/arch/arm/mach-sunxi/dram_sun8i_h3.c +++ b/arch/arm/mach-sunxi/dram_sun8i_h3.c @@ -70,6 +70,12 @@ static void mctl_set_bit_delays(struct dram_para *para) writel(ACBDLR_WRITE_DELAY(para->ac_delays[i]), &mctl_ctl->acbdlr[i]); +#ifdef CONFIG_MACH_SUN8I_R40 + /* DQSn, DMn, DQn output enable bit delay */ + for (i = 0; i < 4; i++) + writel(0x6 << 24, &mctl_ctl->dx[i].sdlr); +#endif + setbits_le32(&mctl_ctl->pgcr[0], 1 << 26); } @@ -86,6 +92,9 @@ enum { MBUS_PORT_DI = 9, MBUS_PORT_DE = 10, MBUS_PORT_DE_CFD = 11, + MBUS_PORT_UNKNOWN1 = 12, + MBUS_PORT_UNKNOWN2 = 13, + MBUS_PORT_UNKNOWN3 = 14, }; enum { @@ -205,6 +214,42 @@ static void mctl_set_master_priority_h5(void) MBUS_CONF(DE_CFD, true, HIGHEST, 0, 600, 400, 200); } +static void mctl_set_master_priority_r40(void) +{ + struct sunxi_mctl_com_reg * const mctl_com = + (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; + + /* enable bandwidth limit windows and set windows size 1us */ + writel(399, &mctl_com->tmr); + writel((1 << 16), &mctl_com->bwcr); + + /* set cpu high priority */ + writel(0x00000001, &mctl_com->mapr); + + /* Port 2 is reserved per Allwinner's linux-3.10 source, yet + * they initialise it */ + MBUS_CONF( CPU, true, HIGHEST, 0, 300, 260, 150); + MBUS_CONF( GPU, true, HIGHEST, 0, 600, 400, 200); + MBUS_CONF( UNUSED, true, HIGHEST, 0, 512, 256, 96); + MBUS_CONF( DMA, true, HIGHEST, 0, 256, 128, 32); + MBUS_CONF( VE, true, HIGHEST, 0, 1900, 1500, 1000); + MBUS_CONF( CSI, true, HIGHEST, 0, 150, 120, 100); + MBUS_CONF( NAND, true, HIGH, 0, 256, 128, 64); + MBUS_CONF( SS, true, HIGHEST, 0, 256, 128, 64); + MBUS_CONF( TS, true, HIGHEST, 0, 256, 128, 64); + MBUS_CONF( DI, true, HIGH, 0, 1024, 256, 64); + + /* + * The port names are probably wrong, but no correct sources + * are available. + */ + MBUS_CONF( DE, true, HIGH, 0, 128, 48, 0); + MBUS_CONF( DE_CFD, true, HIGH, 0, 384, 256, 0); + MBUS_CONF(UNKNOWN1, true, HIGHEST, 0, 512, 384, 256); + MBUS_CONF(UNKNOWN2, true, HIGHEST, 2, 8192, 6144, 1024); + MBUS_CONF(UNKNOWN3, true, HIGH, 0, 1280, 144, 64); +} + static void mctl_set_master_priority(uint16_t socid) { switch (socid) { @@ -217,6 +262,9 @@ static void mctl_set_master_priority(uint16_t socid) case SOCID_H5: mctl_set_master_priority_h5(); return; + case SOCID_R40: + mctl_set_master_priority_r40(); + return; } } @@ -268,6 +316,9 @@ static void mctl_set_timing_params(uint16_t socid, struct dram_para *para) writel(0x18, &mctl_ctl->mr[2]); /* CWL=8 */ writel(0x0, &mctl_ctl->mr[3]); + if (socid == SOCID_R40) + writel(0x3, &mctl_ctl->lp3mr11); /* odt_en[7:4] */ + /* set DRAM timing */ writel(DRAMTMG0_TWTP(twtp) | DRAMTMG0_TFAW(tfaw) | DRAMTMG0_TRAS_MAX(trasmax) | DRAMTMG0_TRAS(tras), @@ -383,7 +434,7 @@ static void mctl_h3_zq_calibration_quirk(struct dram_para *para) } } -static void mctl_set_cr(struct dram_para *para) +static void mctl_set_cr(uint16_t socid, struct dram_para *para) { struct sunxi_mctl_com_reg * const mctl_com = (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE; @@ -393,6 +444,14 @@ static void mctl_set_cr(struct dram_para *para) (para->dual_rank ? MCTL_CR_DUAL_RANK : MCTL_CR_SINGLE_RANK) | MCTL_CR_PAGE_SIZE(para->page_size) | MCTL_CR_ROW_BITS(para->row_bits), &mctl_com->cr); + + if (socid == SOCID_R40) { + if (para->dual_rank) + panic("Dual rank memory not supported\n"); + + /* Mux pin to A15 address line for single rank memory. */ + setbits_le32(&mctl_com->cr_r1, MCTL_CR_R1_MUX_A15); + } } static void mctl_sys_init(uint16_t socid, struct dram_para *para) @@ -407,14 +466,14 @@ static void mctl_sys_init(uint16_t socid, struct dram_para *para) clrbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MCTL); clrbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MCTL); clrbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_EN); - if (socid == SOCID_A64) + if (socid == SOCID_A64 || socid == SOCID_R40) clrbits_le32(&ccm->pll11_cfg, CCM_PLL11_CTRL_EN); udelay(10); clrbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_RST); udelay(1000); - if (socid == SOCID_A64) { + if (socid == SOCID_A64 || socid == SOCID_R40) { clock_set_pll11(CONFIG_DRAM_CLK * 2 * 1000000, false); clrsetbits_le32(&ccm->dram_clk_cfg, CCM_DRAMCLK_CFG_DIV_MASK | @@ -459,7 +518,7 @@ static int mctl_channel_init(uint16_t socid, struct dram_para *para) unsigned int i; - mctl_set_cr(para); + mctl_set_cr(socid, para); mctl_set_timing_params(socid, para); mctl_set_master_priority(socid); @@ -509,6 +568,13 @@ static int mctl_channel_init(uint16_t socid, struct dram_para *para) /* dphy & aphy phase select ? */ clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8), (0x0 << 10) | (0x3 << 8)); + } else if (socid == SOCID_R40) { + /* dx ddr_clk & hdr_clk dynamic mode (tpr13[9] == 0) */ + clrbits_le32(&mctl_ctl->pgcr[0], (0x3 << 14) | (0x3 << 12)); + + /* dphy & aphy phase select ? */ + clrsetbits_le32(&mctl_ctl->pgcr[2], (0x3 << 10) | (0x3 << 8), + (0x0 << 10) | (0x3 << 8)); } /* set half DQ */ @@ -535,6 +601,11 @@ static int mctl_channel_init(uint16_t socid, struct dram_para *para) mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST | PIR_DRAMRST | PIR_DRAMINIT | PIR_QSGATE); /* no PIR_QSGATE for H5 ???? */ + } else if (socid == SOCID_R40) { + clrsetbits_le32(&mctl_ctl->zqcr, 0xffffff, CONFIG_DRAM_ZQ); + + mctl_phy_init(PIR_ZCAL | PIR_PLLINIT | PIR_DCAL | PIR_PHYRST | + PIR_DRAMRST | PIR_DRAMINIT); } /* detect ranks and bus width */ @@ -554,7 +625,7 @@ static int mctl_channel_init(uint16_t socid, struct dram_para *para) para->bus_width = 16; } - mctl_set_cr(para); + mctl_set_cr(socid, para); udelay(20); /* re-train */ @@ -575,7 +646,7 @@ static int mctl_channel_init(uint16_t socid, struct dram_para *para) /* set PGCR3, CKE polarity */ if (socid == SOCID_H3) writel(0x00aa0060, &mctl_ctl->pgcr[3]); - else if (socid == SOCID_A64 || socid == SOCID_H5) + else if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40) writel(0xc0aa0060, &mctl_ctl->pgcr[3]); /* power down zq calibration module for power save */ @@ -587,12 +658,12 @@ static int mctl_channel_init(uint16_t socid, struct dram_para *para) return 0; } -static void mctl_auto_detect_dram_size(struct dram_para *para) +static void mctl_auto_detect_dram_size(uint16_t socid, struct dram_para *para) { /* detect row address bits */ para->page_size = 512; para->row_bits = 16; - mctl_set_cr(para); + mctl_set_cr(socid, para); for (para->row_bits = 11; para->row_bits < 16; para->row_bits++) if (mctl_mem_matches((1 << (para->row_bits + 3)) * para->page_size)) @@ -600,7 +671,7 @@ static void mctl_auto_detect_dram_size(struct dram_para *para) /* detect page size */ para->page_size = 8192; - mctl_set_cr(para); + mctl_set_cr(socid, para); for (para->page_size = 512; para->page_size < 8192; para->page_size *= 2) if (mctl_mem_matches(para->page_size)) @@ -630,6 +701,22 @@ static void mctl_auto_detect_dram_size(struct dram_para *para) 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0 } +#define SUN8I_R40_DX_READ_DELAYS \ + {{ 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \ + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \ + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 }, \ + { 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0 } } +#define SUN8I_R40_DX_WRITE_DELAYS \ + {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 }, \ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 }, \ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 }, \ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 } } +#define SUN8I_R40_AC_DELAYS \ + { 0, 0, 3, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0 } + #define SUN50I_A64_DX_READ_DELAYS \ {{ 16, 16, 16, 16, 17, 16, 16, 17, 16, 1, 0 }, \ { 17, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0 }, \ @@ -679,6 +766,10 @@ unsigned long sunxi_dram_init(void) .dx_read_delays = SUN8I_H3_DX_READ_DELAYS, .dx_write_delays = SUN8I_H3_DX_WRITE_DELAYS, .ac_delays = SUN8I_H3_AC_DELAYS, +#elif defined(CONFIG_MACH_SUN8I_R40) + .dx_read_delays = SUN8I_R40_DX_READ_DELAYS, + .dx_write_delays = SUN8I_R40_DX_WRITE_DELAYS, + .ac_delays = SUN8I_R40_AC_DELAYS, #elif defined(CONFIG_MACH_SUN50I) .dx_read_delays = SUN50I_A64_DX_READ_DELAYS, .dx_write_delays = SUN50I_A64_DX_WRITE_DELAYS, @@ -696,6 +787,8 @@ unsigned long sunxi_dram_init(void) */ #if defined(CONFIG_MACH_SUN8I_H3) uint16_t socid = SOCID_H3; +#elif defined(CONFIG_MACH_SUN8I_R40) + uint16_t socid = SOCID_R40; #elif defined(CONFIG_MACH_SUN50I) uint16_t socid = SOCID_A64; #elif defined(CONFIG_MACH_SUN50I_H5) @@ -716,9 +809,11 @@ unsigned long sunxi_dram_init(void) if (socid == SOCID_H3) writel(0x0c000400, &mctl_ctl->odtcfg); - if (socid == SOCID_A64 || socid == SOCID_H5) { + if (socid == SOCID_A64 || socid == SOCID_H5 || socid == SOCID_R40) { + /* VTF enable (tpr13[8] == 1) */ setbits_le32(&mctl_ctl->vtfcr, - (socid == SOCID_H5 ? 3 : 2) << 8); + (socid != SOCID_A64 ? 3 : 2) << 8); + /* DQ hold disable (tpr13[26] == 1) */ clrbits_le32(&mctl_ctl->pgcr[2], (1 << 13)); } @@ -726,8 +821,8 @@ unsigned long sunxi_dram_init(void) setbits_le32(&mctl_com->cccr, 1 << 31); udelay(10); - mctl_auto_detect_dram_size(¶); - mctl_set_cr(¶); + mctl_auto_detect_dram_size(socid, ¶); + mctl_set_cr(socid, ¶); return (1UL << (para.row_bits + 3)) * para.page_size * (para.dual_rank ? 2 : 1); diff --git a/arch/arm/mach-sunxi/pmic_bus.c b/arch/arm/mach-sunxi/pmic_bus.c index 7c57f02792..f917c3e070 100644 --- a/arch/arm/mach-sunxi/pmic_bus.c +++ b/arch/arm/mach-sunxi/pmic_bus.c @@ -41,6 +41,9 @@ int pmic_bus_init(void) p2wi_init(); ret = p2wi_change_to_p2wi_mode(AXP221_CHIP_ADDR, AXP221_CTRL_ADDR, AXP221_INIT_DATA); +# elif defined CONFIG_MACH_SUN8I_R40 + /* Nothing. R40 uses the AXP221s in I2C mode */ + ret = 0; # else ret = rsb_init(); if (ret) @@ -65,6 +68,8 @@ int pmic_bus_read(u8 reg, u8 *data) #elif defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER # ifdef CONFIG_MACH_SUN6I return p2wi_read(reg, data); +# elif defined CONFIG_MACH_SUN8I_R40 + return i2c_read(AXP209_I2C_ADDR, reg, 1, data, 1); # else return rsb_read(AXP223_RUNTIME_ADDR, reg, data); # endif @@ -80,6 +85,8 @@ int pmic_bus_write(u8 reg, u8 data) #elif defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER # ifdef CONFIG_MACH_SUN6I return p2wi_write(reg, data); +# elif defined CONFIG_MACH_SUN8I_R40 + return i2c_write(AXP209_I2C_ADDR, reg, 1, &data, 1); # else return rsb_write(AXP223_RUNTIME_ADDR, reg, data); # endif |