diff options
42 files changed, 1996 insertions, 295 deletions
diff --git a/.travis.yml b/.travis.yml index 6cad65fd378..d83a5e63329 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,7 @@ install: - echo -e "[toolchain]\nroot = /usr" > ~/.buildman - echo -e "aarch64 = /tmp/gcc-linaro-6.3.1-2017.02-x86_64_aarch64-linux-gnu" >> ~/.buildman - echo -e "arm = /tmp/gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf" >> ~/.buildman - - echo -e "arc = /tmp/arc_gnu_2016.09_prebuilt_uclibc_le_archs_linux_install" >> ~/.buildman + - echo -e "arc = /tmp/arc_gnu_2017.09_prebuilt_uclibc_le_archs_linux_install" >> ~/.buildman - echo -e "\n[toolchain-alias]\nsh = sh4\nopenrisc = or32" >> ~/.buildman - cat ~/.buildman - virtualenv /tmp/venv @@ -70,8 +70,8 @@ before_script: echo -e "\n[toolchain-prefix]\nx86 = ${HOME}/.buildman-toolchains/gcc-4.9.0-nolibc/x86_64-linux/bin/x86_64-linux-" >> ~/.buildman; fi - if [[ "${TOOLCHAIN}" == arc ]]; then - wget https://github.com/foss-for-synopsys-dwc-arc-processors/toolchain/releases/download/arc-2016.09-release/arc_gnu_2016.09_prebuilt_uclibc_le_archs_linux_install.tar.gz && - tar -C /tmp -xf arc_gnu_2016.09_prebuilt_uclibc_le_archs_linux_install.tar.gz; + wget https://github.com/foss-for-synopsys-dwc-arc-processors/toolchain/releases/download/arc-2017.09-release/arc_gnu_2017.09_prebuilt_uclibc_le_archs_linux_install.tar.gz && + tar -C /tmp -xf arc_gnu_2017.09_prebuilt_uclibc_le_archs_linux_install.tar.gz; fi - if [[ "${TOOLCHAIN}" == *xtensa* ]]; then wget https://github.com/foss-xtensa/toolchain/releases/download/2018.02/x86_64-2018.02-${TOOLCHAIN}.tar.gz && @@ -600,9 +600,13 @@ KBUILD_CFLAGS += -g KBUILD_AFLAGS += -g # Report stack usage if supported +# ARC tools based on GCC 7.1 has an issue with stack usage +# with naked functions, see commit message for more details +ifndef CONFIG_ARC ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-stack-usage.sh $(CC)),y) KBUILD_CFLAGS += -fstack-usage endif +endif KBUILD_CFLAGS += $(call cc-option,-Wno-format-nonliteral) diff --git a/arch/arc/dts/axs10x_mb.dtsi b/arch/arc/dts/axs10x_mb.dtsi index b74d3c85459..17ef656483c 100644 --- a/arch/arc/dts/axs10x_mb.dtsi +++ b/arch/arc/dts/axs10x_mb.dtsi @@ -31,11 +31,8 @@ }; ethernet@18000 { - #interrupt-cells = <1>; compatible = "altr,socfpga-stmmac"; reg = < 0x18000 0x2000 >; - interrupts = < 25 >; - interrupt-names = "macirq"; phy-mode = "gmii"; snps,pbl = < 32 >; clocks = <&apbclk>; @@ -46,13 +43,11 @@ ehci@0x40000 { compatible = "generic-ehci"; reg = < 0x40000 0x100 >; - interrupts = < 8 >; }; ohci@0x60000 { compatible = "generic-ohci"; reg = < 0x60000 0x100 >; - interrupts = < 8 >; }; uart0: serial0@22000 { diff --git a/arch/arc/dts/hsdk.dts b/arch/arc/dts/hsdk.dts index 67dfb93ca8d..80b864af743 100644 --- a/arch/arc/dts/hsdk.dts +++ b/arch/arc/dts/hsdk.dts @@ -6,6 +6,7 @@ /dts-v1/; #include "skeleton.dtsi" +#include "dt-bindings/clock/snps,hsdk-cgu.h" / { #address-cells = <1>; @@ -13,6 +14,7 @@ aliases { console = &uart0; + spi0 = &spi0; }; cpu_card { @@ -24,6 +26,35 @@ }; }; + clk-fmeas { + clocks = <&cgu_clk CLK_ARC_PLL>, <&cgu_clk CLK_SYS_PLL>, + <&cgu_clk CLK_TUN_PLL>, <&cgu_clk CLK_DDR_PLL>, + <&cgu_clk CLK_ARC>, <&cgu_clk CLK_HDMI_PLL>, + <&cgu_clk CLK_TUN_TUN>, <&cgu_clk CLK_HDMI>, + <&cgu_clk CLK_SYS_APB>, <&cgu_clk CLK_SYS_AXI>, + <&cgu_clk CLK_SYS_ETH>, <&cgu_clk CLK_SYS_USB>, + <&cgu_clk CLK_SYS_SDIO>, <&cgu_clk CLK_SYS_HDMI>, + <&cgu_clk CLK_SYS_GFX_CORE>, <&cgu_clk CLK_SYS_GFX_DMA>, + <&cgu_clk CLK_SYS_GFX_CFG>, <&cgu_clk CLK_SYS_DMAC_CORE>, + <&cgu_clk CLK_SYS_DMAC_CFG>, <&cgu_clk CLK_SYS_SDIO_REF>, + <&cgu_clk CLK_SYS_SPI_REF>, <&cgu_clk CLK_SYS_I2C_REF>, + <&cgu_clk CLK_SYS_UART_REF>, <&cgu_clk CLK_SYS_EBI_REF>, + <&cgu_clk CLK_TUN_ROM>, <&cgu_clk CLK_TUN_PWM>; + clock-names = "cpu-pll", "sys-pll", + "tun-pll", "ddr-clk", + "cpu-clk", "hdmi-pll", + "tun-clk", "hdmi-clk", + "apb-clk", "axi-clk", + "eth-clk", "usb-clk", + "sdio-clk", "hdmi-sys-clk", + "gfx-core-clk", "gfx-dma-clk", + "gfx-cfg-clk", "dmac-core-clk", + "dmac-cfg-clk", "sdio-ref-clk", + "spi-clk", "i2c-clk", + "uart-clk", "ebi-clk", + "rom-clk", "pwm-clk"; + }; + cgu_clk: cgu-clk@f0000000 { compatible = "snps,hsdk-cgu-clock"; reg = <0xf0000000 0x10>, <0xf00014B8 0x4>; @@ -53,4 +84,29 @@ compatible = "generic-ohci"; reg = <0xf0060000 0x100>; }; + + spi0: spi@f0020000 { + compatible = "snps,dw-apb-ssi"; + reg = <0xf0020000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + spi-max-frequency = <4000000>; + clocks = <&cgu_clk CLK_SYS_SPI_REF>; + clock-names = "spi_clk"; + cs-gpio = <&cs_gpio 0>; + spi_flash@0 { + compatible = "spi-flash"; + reg = <0>; + spi-max-frequency = <4000000>; + }; + }; + + cs_gpio: gpio@f00014b0 { + compatible = "snps,hsdk-creg-gpio"; + reg = <0xf00014b0 0x4>; + gpio-controller; + #gpio-cells = <1>; + gpio-bank-name = "hsdk-spi-cs"; + gpio-count = <1>; + }; }; diff --git a/arch/arm/dts/sun50i-a64-pine64-plus-u-boot.dtsi b/arch/arm/dts/sun50i-a64-pine64-plus-u-boot.dtsi index 9c61beac011..32a263ce3d8 100644 --- a/arch/arm/dts/sun50i-a64-pine64-plus-u-boot.dtsi +++ b/arch/arm/dts/sun50i-a64-pine64-plus-u-boot.dtsi @@ -4,25 +4,38 @@ }; soc { - emac: ethernet@01c30000 { + syscon: syscon@1c00000 { + compatible = "allwinner,sun50i-a64-system-controller", + "syscon"; + reg = <0x01c00000 0x1000>; + }; + + emac: ethernet@1c30000 { compatible = "allwinner,sun50i-a64-emac"; - reg = <0x01c30000 0x2000>, <0x01c00030 0x4>; - reg-names = "emac", "syscon"; + syscon = <&syscon>; + reg = <0x01c30000 0x10000>; interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "macirq"; resets = <&ccu RST_BUS_EMAC>; - reset-names = "ahb"; + reset-names = "stmmaceth"; clocks = <&ccu CLK_BUS_EMAC>; - clock-names = "ahb"; + clock-names = "stmmaceth"; #address-cells = <1>; #size-cells = <0>; pinctrl-names = "default"; pinctrl-0 = <&rgmii_pins>; phy-mode = "rgmii"; - phy = <&phy1>; + phy-handle = <&ext_rgmii_phy>; status = "okay"; - phy1: ethernet-phy@1 { - reg = <1>; + mdio: mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + ext_rgmii_phy: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + }; }; }; }; @@ -30,21 +43,17 @@ &pio { rmii_pins: rmii_pins { - allwinner,pins = "PD10", "PD11", "PD13", "PD14", - "PD17", "PD18", "PD19", "PD20", - "PD22", "PD23"; - allwinner,function = "emac"; - allwinner,drive = <3>; - allwinner,pull = <0>; + pins = "PD10", "PD11", "PD13", "PD14", "PD17", + "PD18", "PD19", "PD20", "PD22", "PD23"; + function = "emac"; + drive-strength = <40>; }; rgmii_pins: rgmii_pins { - allwinner,pins = "PD8", "PD9", "PD10", "PD11", - "PD12", "PD13", "PD15", - "PD16", "PD17", "PD18", "PD19", - "PD20", "PD21", "PD22", "PD23"; - allwinner,function = "emac"; - allwinner,drive = <3>; - allwinner,pull = <0>; + pins = "PD8", "PD9", "PD10", "PD11", "PD12", + "PD13", "PD15", "PD16", "PD17", "PD18", + "PD19", "PD20", "PD21", "PD22", "PD23"; + function = "emac"; + drive-strength = <40>; }; }; diff --git a/arch/arm/dts/sun50i-h5-orangepi-pc2.dts b/arch/arm/dts/sun50i-h5-orangepi-pc2.dts index 780d59a0960..d1c347d2b86 100644 --- a/arch/arm/dts/sun50i-h5-orangepi-pc2.dts +++ b/arch/arm/dts/sun50i-h5-orangepi-pc2.dts @@ -108,10 +108,13 @@ pinctrl-names = "default"; pinctrl-0 = <&emac_rgmii_pins>; phy-mode = "rgmii"; - phy = <&phy1>; + phy-handle = <&ext_rgmii_phy>; status = "okay"; +}; - phy1: ethernet-phy@1 { +&external_mdio { + ext_rgmii_phy: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; reg = <1>; }; }; diff --git a/arch/arm/dts/sun8i-a23-a33.dtsi b/arch/arm/dts/sun8i-a23-a33.dtsi index ea50dda75ad..ffd21487dc0 100644 --- a/arch/arm/dts/sun8i-a23-a33.dtsi +++ b/arch/arm/dts/sun8i-a23-a33.dtsi @@ -289,6 +289,23 @@ function = "uart1"; }; + nand_pins_a: nand-base0@0 { + pins = "PC0", "PC1", "PC2", "PC5", + "PC8", "PC9", "PC10", "PC11", + "PC12", "PC13", "PC14", "PC15"; + function = "nand0"; + }; + + nand_cs0_pins_a: nand-cs@0 { + pins = "PC4"; + function = "nand0"; + }; + + nand_rb0_pins_a: nand-rb@0 { + pins = "PC6"; + function = "nand0"; + }; + mmc0_pins_a: mmc0@0 { pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5"; diff --git a/arch/arm/dts/sun8i-h2-plus-orangepi-zero.dts b/arch/arm/dts/sun8i-h2-plus-orangepi-zero.dts index 20d489cb2aa..e0efcb3ba3e 100644 --- a/arch/arm/dts/sun8i-h2-plus-orangepi-zero.dts +++ b/arch/arm/dts/sun8i-h2-plus-orangepi-zero.dts @@ -100,14 +100,10 @@ }; &emac { - phy = <&phy1>; + phy-handle = <&int_mii_phy>; phy-mode = "mii"; - allwinner,use-internal-phy; allwinner,leds-active-low; status = "okay"; - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &mmc0 { diff --git a/arch/arm/dts/sun8i-h3-libretech-all-h3-cc.dts b/arch/arm/dts/sun8i-h3-libretech-all-h3-cc.dts index 97b993f636f..c8fd69f0a4b 100644 --- a/arch/arm/dts/sun8i-h3-libretech-all-h3-cc.dts +++ b/arch/arm/dts/sun8i-h3-libretech-all-h3-cc.dts @@ -125,15 +125,10 @@ }; &emac { - phy = <&phy1>; + phy-handle = <&int_mii_phy>; phy-mode = "mii"; - allwinner,use-internal-phy; allwinner,leds-active-low; status = "okay"; - - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &ir { diff --git a/arch/arm/dts/sun8i-h3-nanopi-neo.dts b/arch/arm/dts/sun8i-h3-nanopi-neo.dts index 51130590989..78f6c24952d 100644 --- a/arch/arm/dts/sun8i-h3-nanopi-neo.dts +++ b/arch/arm/dts/sun8i-h3-nanopi-neo.dts @@ -48,12 +48,8 @@ }; &emac { - phy = <&phy1>; + phy-handle = <&int_mii_phy>; phy-mode = "mii"; - allwinner,use-internal-phy; allwinner,leds-active-low; status = "okay"; - phy1: ethernet-phy@1 { - reg = <1>; - }; }; diff --git a/arch/arm/dts/sun8i-h3-orangepi-2.dts b/arch/arm/dts/sun8i-h3-orangepi-2.dts index caa1a6959cf..d97fdacb35a 100644 --- a/arch/arm/dts/sun8i-h3-orangepi-2.dts +++ b/arch/arm/dts/sun8i-h3-orangepi-2.dts @@ -55,6 +55,7 @@ aliases { serial0 = &uart0; /* ethernet0 is the H3 emac, defined in sun8i-h3.dtsi */ + ethernet0 = &emac; ethernet1 = &rtl8189; }; @@ -110,14 +111,10 @@ }; &emac { - phy = <&phy1>; + phy-handle = <&int_mii_phy>; phy-mode = "mii"; - allwinner,use-internal-phy; allwinner,leds-active-low; status = "okay"; - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &ir { diff --git a/arch/arm/dts/sun8i-h3-orangepi-one.dts b/arch/arm/dts/sun8i-h3-orangepi-one.dts index 8df5c74f04c..adab1cbfc92 100644 --- a/arch/arm/dts/sun8i-h3-orangepi-one.dts +++ b/arch/arm/dts/sun8i-h3-orangepi-one.dts @@ -53,6 +53,7 @@ compatible = "xunlong,orangepi-one", "allwinner,sun8i-h3"; aliases { + ethernet0 = &emac; serial0 = &uart0; }; @@ -95,14 +96,10 @@ }; &emac { - phy = <&phy1>; + phy-handle = <&int_mii_phy>; phy-mode = "mii"; - allwinner,use-internal-phy; allwinner,leds-active-low; status = "okay"; - phy1: ethernet-phy@1 { - reg = <1>; - }; }; &mmc0 { diff --git a/arch/arm/dts/sun8i-h3-orangepi-pc.dts b/arch/arm/dts/sun8i-h3-orangepi-pc.dts index b8340f74e77..afba264ea53 100644 --- a/arch/arm/dts/sun8i-h3-orangepi-pc.dts +++ b/arch/arm/dts/sun8i-h3-orangepi-pc.dts @@ -53,6 +53,7 @@ compatible = "xunlong,orangepi-pc", "allwinner,sun8i-h3"; aliases { + ethernet0 = &emac; serial0 = &uart0; }; @@ -167,12 +168,8 @@ }; &emac { - phy = <&phy1>; + phy-handle = <&int_mii_phy>; phy-mode = "mii"; - allwinner,use-internal-phy; allwinner,leds-active-low; status = "okay"; - phy1: ethernet-phy@1 { - reg = <1>; - }; }; diff --git a/arch/arm/dts/sun8i-h3-orangepi-plus.dts b/arch/arm/dts/sun8i-h3-orangepi-plus.dts index e7079b26bc8..136e4414a4f 100644 --- a/arch/arm/dts/sun8i-h3-orangepi-plus.dts +++ b/arch/arm/dts/sun8i-h3-orangepi-plus.dts @@ -82,7 +82,13 @@ pinctrl-0 = <&emac_rgmii_pins>; phy-supply = <®_gmac_3v3>; phy-mode = "rgmii"; - /delete-property/allwinner,use-internal-phy; +}; + +&external_mdio { + ext_rgmii_phy: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0>; + }; }; &mmc2 { diff --git a/arch/arm/dts/sun8i-h3-orangepi-plus2e.dts b/arch/arm/dts/sun8i-h3-orangepi-plus2e.dts index f97b040b35a..51aaf49b6dc 100644 --- a/arch/arm/dts/sun8i-h3-orangepi-plus2e.dts +++ b/arch/arm/dts/sun8i-h3-orangepi-plus2e.dts @@ -69,8 +69,15 @@ pinctrl-names = "default"; pinctrl-0 = <&emac_rgmii_pins>; phy-supply = <®_gmac_3v3>; + phy-handle = <&ext_rgmii_phy>; phy-mode = "rgmii"; - /delete-property/allwinner,use-internal-phy; +}; + +&external_mdio { + ext_rgmii_phy: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + }; }; &pio { diff --git a/arch/arm/dts/sun8i-h3.dtsi b/arch/arm/dts/sun8i-h3.dtsi index afa60793a23..d9d31fa3f50 100644 --- a/arch/arm/dts/sun8i-h3.dtsi +++ b/arch/arm/dts/sun8i-h3.dtsi @@ -144,9 +144,10 @@ #size-cells = <1>; ranges; - syscon: syscon@01c00000 { - compatible = "allwinner,sun8i-h3-syscon","syscon"; - reg = <0x01c00000 0x34>; + syscon: syscon@1c00000 { + compatible = "allwinner,sun8i-h3-system-controller", + "syscon"; + reg = <0x01c00000 0x1000>; }; dma: dma-controller@01c02000 { @@ -339,15 +340,12 @@ interrupt-controller; #interrupt-cells = <3>; - emac_rgmii_pins: emac0@0 { - allwinner,pins = "PD0", "PD1", "PD2", "PD3", - "PD4", "PD5", "PD7", - "PD8", "PD9", "PD10", - "PD12", "PD13", "PD15", - "PD16", "PD17"; - allwinner,function = "emac"; - allwinner,drive = <SUN4I_PINCTRL_40_MA>; - allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; + emac_rgmii_pins: emac0 { + pins = "PD0", "PD1", "PD2", "PD3", "PD4", + "PD5", "PD7", "PD8", "PD9", "PD10", + "PD12", "PD13", "PD15", "PD16", "PD17"; + function = "emac"; + drive-strength = <40>; }; mmc0_pins_a: mmc0@0 { @@ -466,16 +464,51 @@ emac: ethernet@1c30000 { compatible = "allwinner,sun8i-h3-emac"; - reg = <0x01c30000 0x104>, <0x01c00030 0x4>; - reg-names = "emac", "syscon"; + syscon = <&syscon>; + reg = <0x01c30000 0x10000>; interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>; - resets = <&ccu RST_BUS_EMAC>, <&ccu RST_BUS_EPHY>; - reset-names = "ahb", "ephy"; - clocks = <&ccu CLK_BUS_EMAC>, <&ccu CLK_BUS_EPHY>; - clock-names = "ahb", "ephy"; + interrupt-names = "macirq"; + resets = <&ccu RST_BUS_EMAC>; + reset-names = "stmmaceth"; + clocks = <&ccu CLK_BUS_EMAC>; + clock-names = "stmmaceth"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; + + mdio: mdio { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,dwmac-mdio"; + }; + + mdio-mux { + compatible = "allwinner,sun8i-h3-mdio-mux"; + #address-cells = <1>; + #size-cells = <0>; + + mdio-parent-bus = <&mdio>; + /* Only one MDIO is usable at the time */ + internal_mdio: mdio@1 { + compatible = "allwinner,sun8i-h3-mdio-internal"; + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + int_mii_phy: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + clocks = <&ccu CLK_BUS_EPHY>; + resets = <&ccu RST_BUS_EPHY>; + }; + }; + + external_mdio: mdio@2 { + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; }; gic: interrupt-controller@01c81000 { diff --git a/arch/arm/dts/sun8i-r16-nintendo-nes-classic-edition.dts b/arch/arm/dts/sun8i-r16-nintendo-nes-classic-edition.dts index dce688ec8ee..72a8505d94b 100644 --- a/arch/arm/dts/sun8i-r16-nintendo-nes-classic-edition.dts +++ b/arch/arm/dts/sun8i-r16-nintendo-nes-classic-edition.dts @@ -61,3 +61,17 @@ pinctrl-0 = <&uart0_pins_a>; status = "okay"; }; + +&nfc { + pinctrl-names = "default"; + pinctrl-0 = <&nand_pins_a &nand_cs0_pins_a &nand_rb0_pins_a>; + status = "okay"; + + nand@0 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0>; + allwinner,rb = <0>; + nand-ecc-mode = "hw"; + }; +}; diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h index d328df9597d..d35aa479f7b 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h @@ -192,6 +192,7 @@ struct sunxi_ccm_reg { #define ATB_DIV_1 0 #define ATB_DIV_2 1 #define ATB_DIV_4 2 +#define AHB_DIV_1 0 #define CPU_CLK_SRC_OSC24M 1 #define CPU_CLK_SRC_PLL1 2 @@ -317,6 +318,11 @@ struct sunxi_ccm_reg { #define AHB_GATE_OFFSET_LCD0 3 #endif +#define CCM_NAND_CTRL_M(x) ((x) - 1) +#define CCM_NAND_CTRL_N(x) ((x) << 16) +#define CCM_NAND_CTRL_PLL6 (0x1 << 24) +#define CCM_NAND_CTRL_ENABLE (0x1 << 31) + #define CCM_MMC_CTRL_M(x) ((x) - 1) #define CCM_MMC_CTRL_OCLK_DLY(x) ((x) << 8) #define CCM_MMC_CTRL_N(x) ((x) << 16) diff --git a/board/sunxi/README.sunxi64 b/board/sunxi/README.sunxi64 index 5a363d27b8a..df1dbc818f7 100644 --- a/board/sunxi/README.sunxi64 +++ b/board/sunxi/README.sunxi64 @@ -38,6 +38,12 @@ the root of your U-Boot build directory (or create a symbolic link). $ export BL31=/src/arm-trusted-firmware/build/sun50iw1p1/debug/bl31.bin (adjust the actual path accordingly) +If you run into size issues with the resulting U-Boot image file, it might +help to use a release build, by using "DEBUG=0" when building bl31.bin. +As sometimes the ATF build process is a bit picky about the toolchain used, +or if you can't be bothered with building ATF, there are known working +binaries in the firmware repository[3], purely for convenience reasons. + SPL/U-Boot ------------ Both U-Boot proper and the SPL are using the 64-bit mode. As the boot ROM diff --git a/board/sunxi/board.c b/board/sunxi/board.c index e08e22f30c0..322dd9e23ac 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -286,10 +286,9 @@ static void nand_clock_setup(void) (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; setbits_le32(&ccm->ahb_gate0, (CLK_GATE_OPEN << AHB_GATE_OFFSET_NAND0)); -#ifdef CONFIG_MACH_SUN9I - setbits_le32(&ccm->ahb_gate1, (1 << AHB_GATE_OFFSET_DMA)); -#else - setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_DMA)); +#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I || \ + defined CONFIG_MACH_SUN9I || defined CONFIG_MACH_SUN50I + setbits_le32(&ccm->ahb_reset0_cfg, (1 << AHB_GATE_OFFSET_NAND0)); #endif setbits_le32(&ccm->nand0_clk_cfg, CCM_NAND_CTRL_ENABLE | AHB_DIV_1); } diff --git a/board/synopsys/hsdk/MAINTAINERS b/board/synopsys/hsdk/MAINTAINERS index d034bc479d0..e22bd1e40b2 100644 --- a/board/synopsys/hsdk/MAINTAINERS +++ b/board/synopsys/hsdk/MAINTAINERS @@ -1,5 +1,5 @@ -AXS10X BOARD -M: Alexey Brodkin <abrodkin@synopsys.com> +HSDK BOARD +M: Eugeniy Paltsev <paltsev@synopsys.com> S: Maintained F: board/synopsys/hsdk/ F: configs/hsdk_defconfig diff --git a/board/synopsys/hsdk/Makefile b/board/synopsys/hsdk/Makefile index d84dd032652..7ecff3d7400 100644 --- a/board/synopsys/hsdk/Makefile +++ b/board/synopsys/hsdk/Makefile @@ -5,3 +5,5 @@ # obj-y += hsdk.o +obj-y += env-lib.o +obj-y += clk-lib.o diff --git a/board/synopsys/hsdk/clk-lib.c b/board/synopsys/hsdk/clk-lib.c new file mode 100644 index 00000000000..1ce54afffeb --- /dev/null +++ b/board/synopsys/hsdk/clk-lib.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2018 Synopsys, Inc. All rights reserved. + * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <clk.h> +#include <dm/device.h> + +#include "clk-lib.h" + +#define HZ_IN_MHZ 1000000 +#define ceil(x, y) ({ ulong __x = (x), __y = (y); (__x + __y - 1) / __y; }) + +int soc_clk_ctl(const char *name, ulong *rate, enum clk_ctl_ops ctl) +{ + int ret; + ulong mhz_rate, priv_rate; + struct clk clk; + + /* Dummy fmeas device, just to be able to use standard clk_* api */ + struct udevice fmeas = { + .name = "clk-fmeas", + .node = ofnode_path("/clk-fmeas"), + }; + + ret = clk_get_by_name(&fmeas, name, &clk); + if (ret) { + pr_err("clock '%s' not found, err=%d\n", name, ret); + return ret; + } + + if (ctl & CLK_ON) { + ret = clk_enable(&clk); + if (ret && ret != -ENOSYS && ret != -ENOTSUPP) + return ret; + } + + if ((ctl & CLK_SET) && rate) { + priv_rate = ctl & CLK_MHZ ? (*rate) * HZ_IN_MHZ : *rate; + ret = clk_set_rate(&clk, priv_rate); + if (ret) + return ret; + } + + if (ctl & CLK_OFF) { + ret = clk_disable(&clk); + if (ret) { + pr_err("clock '%s' can't be disabled, err=%d\n", name, ret); + return ret; + } + } + + priv_rate = clk_get_rate(&clk); + + clk_free(&clk); + + mhz_rate = ceil(priv_rate, HZ_IN_MHZ); + + if (ctl & CLK_MHZ) + priv_rate = mhz_rate; + + if ((ctl & CLK_GET) && rate) + *rate = priv_rate; + + if ((ctl & CLK_PRINT) && (ctl & CLK_MHZ)) + printf("HSDK: clock '%s' rate %lu MHz\n", name, priv_rate); + else if (ctl & CLK_PRINT) + printf("HSDK: clock '%s' rate %lu Hz\n", name, priv_rate); + else + debug("HSDK: clock '%s' rate %lu MHz\n", name, mhz_rate); + + return 0; +} diff --git a/board/synopsys/hsdk/clk-lib.h b/board/synopsys/hsdk/clk-lib.h new file mode 100644 index 00000000000..3b7dbc58ae0 --- /dev/null +++ b/board/synopsys/hsdk/clk-lib.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2018 Synopsys, Inc. All rights reserved. + * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __BOARD_CLK_LIB_H +#define __BOARD_CLK_LIB_H + +#include <common.h> + +enum clk_ctl_ops { + CLK_SET = BIT(0), /* set frequency */ + CLK_GET = BIT(1), /* get frequency */ + CLK_ON = BIT(2), /* enable clock */ + CLK_OFF = BIT(3), /* disable clock */ + CLK_PRINT = BIT(4), /* print frequency */ + CLK_MHZ = BIT(5) /* all values in MHZ instead of HZ */ +}; + +/* + * Depending on the clk_ctl_ops enable / disable / + * set clock rate from 'rate' argument / read clock to 'rate' argument / + * print clock rate. If CLK_MHZ flag set in clk_ctl_ops 'rate' is in MHz, + * otherwise - in Hz. + * + * This function expects "clk-fmeas" node in device tree: + * / { + * clk-fmeas { + * clocks = <&cpu_pll>, <&sys_pll>; + * clock-names = "cpu-pll", "sys-pll"; + * }; + * }; + */ +int soc_clk_ctl(const char *name, ulong *rate, enum clk_ctl_ops ctl); + +#endif /* __BOARD_CLK_LIB_H */ diff --git a/board/synopsys/hsdk/env-lib.c b/board/synopsys/hsdk/env-lib.c new file mode 100644 index 00000000000..6b53d92c230 --- /dev/null +++ b/board/synopsys/hsdk/env-lib.c @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2018 Synopsys, Inc. All rights reserved. + * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "env-lib.h" + +#define MAX_CMD_LEN 25 + +static void env_clear_common(u32 index, const struct env_map_common *map) +{ + map[index].val->val = 0; + map[index].val->set = false; +} + +static int env_read_common(u32 index, const struct env_map_common *map) +{ + u32 val; + + if (!env_get_yesno(map[index].env_name)) { + if (map[index].type == ENV_HEX) { + val = (u32)env_get_hex(map[index].env_name, 0); + debug("ENV: %s: = %#x\n", map[index].env_name, val); + } else { + val = (u32)env_get_ulong(map[index].env_name, 10, 0); + debug("ENV: %s: = %d\n", map[index].env_name, val); + } + + map[index].val->val = val; + map[index].val->set = true; + } + + return 0; +} + +static void env_clear_core(u32 index, const struct env_map_percpu *map) +{ + for (u32 i = 0; i < NR_CPUS; i++) { + (*map[index].val)[i].val = 0; + (*map[index].val)[i].set = false; + } +} + +static int env_read_core(u32 index, const struct env_map_percpu *map) +{ + u32 val; + char command[MAX_CMD_LEN]; + + for (u32 i = 0; i < NR_CPUS; i++) { + sprintf(command, "%s_%u", map[index].env_name, i); + if (!env_get_yesno(command)) { + if (map[index].type == ENV_HEX) { + val = (u32)env_get_hex(command, 0); + debug("ENV: %s: = %#x\n", command, val); + } else { + val = (u32)env_get_ulong(command, 10, 0); + debug("ENV: %s: = %d\n", command, val); + } + + (*map[index].val)[i].val = val; + (*map[index].val)[i].set = true; + } + } + + return 0; +} + +static int env_validate_common(u32 index, const struct env_map_common *map) +{ + u32 value = map[index].val->val; + bool set = map[index].val->set; + u32 min = map[index].min; + u32 max = map[index].max; + + /* Check if environment is mandatory */ + if (map[index].mandatory && !set) { + pr_err("Variable \'%s\' is mandatory, but it is not defined\n", + map[index].env_name); + + return -EINVAL; + } + + /* Check environment boundary */ + if (set && (value < min || value > max)) { + if (map[index].type == ENV_HEX) + pr_err("Variable \'%s\' must be between %#x and %#x\n", + map[index].env_name, min, max); + else + pr_err("Variable \'%s\' must be between %u and %u\n", + map[index].env_name, min, max); + + return -EINVAL; + } + + return 0; +} + +static int env_validate_core(u32 index, const struct env_map_percpu *map, + bool (*cpu_used)(u32)) +{ + u32 value; + bool set; + bool mandatory = map[index].mandatory; + u32 min, max; + + for (u32 i = 0; i < NR_CPUS; i++) { + set = (*map[index].val)[i].set; + value = (*map[index].val)[i].val; + + /* Check if environment is mandatory */ + if (cpu_used(i) && mandatory && !set) { + pr_err("CPU %u is used, but \'%s_%u\' is not defined\n", + i, map[index].env_name, i); + + return -EINVAL; + } + + min = map[index].min[i]; + max = map[index].max[i]; + + /* Check environment boundary */ + if (set && (value < min || value > max)) { + if (map[index].type == ENV_HEX) + pr_err("Variable \'%s_%u\' must be between %#x and %#x\n", + map[index].env_name, i, min, max); + else + pr_err("Variable \'%s_%u\' must be between %d and %d\n", + map[index].env_name, i, min, max); + + return -EINVAL; + } + } + + return 0; +} + +void envs_cleanup_core(const struct env_map_percpu *map) +{ + /* Cleanup env struct first */ + for (u32 i = 0; map[i].env_name; i++) + env_clear_core(i, map); +} + +void envs_cleanup_common(const struct env_map_common *map) +{ + /* Cleanup env struct first */ + for (u32 i = 0; map[i].env_name; i++) + env_clear_common(i, map); +} + +int envs_read_common(const struct env_map_common *map) +{ + int ret; + + for (u32 i = 0; map[i].env_name; i++) { + ret = env_read_common(i, map); + if (ret) + return ret; + } + + return 0; +} + +int envs_validate_common(const struct env_map_common *map) +{ + int ret; + + for (u32 i = 0; map[i].env_name; i++) { + ret = env_validate_common(i, map); + if (ret) + return ret; + } + + return 0; +} + +int envs_read_validate_common(const struct env_map_common *map) +{ + int ret; + + envs_cleanup_common(map); + + ret = envs_read_common(map); + if (ret) + return ret; + + ret = envs_validate_common(map); + if (ret) + return ret; + + return 0; +} + +int envs_read_validate_core(const struct env_map_percpu *map, + bool (*cpu_used)(u32)) +{ + int ret; + + envs_cleanup_core(map); + + for (u32 i = 0; map[i].env_name; i++) { + ret = env_read_core(i, map); + if (ret) + return ret; + } + + for (u32 i = 0; map[i].env_name; i++) { + ret = env_validate_core(i, map, cpu_used); + if (ret) + return ret; + } + + return 0; +} + +int envs_process_and_validate(const struct env_map_common *common, + const struct env_map_percpu *core, + bool (*cpu_used)(u32)) +{ + int ret; + + ret = envs_read_validate_common(common); + if (ret) + return ret; + + ret = envs_read_validate_core(core, cpu_used); + if (ret) + return ret; + + return 0; +} + +static int args_envs_read_search(const struct env_map_common *map, + int argc, char *const argv[]) +{ + for (int i = 0; map[i].env_name; i++) { + if (!strcmp(argv[0], map[i].env_name)) + return i; + } + + pr_err("Unexpected argument '%s', can't parse\n", argv[0]); + + return -ENOENT; +} + +static int arg_read_set(const struct env_map_common *map, u32 i, int argc, + char *const argv[]) +{ + char *endp = argv[1]; + + if (map[i].type == ENV_HEX) + map[i].val->val = simple_strtoul(argv[1], &endp, 16); + else + map[i].val->val = simple_strtoul(argv[1], &endp, 10); + + map[i].val->set = true; + + if (*endp == '\0') + return 0; + + pr_err("Unexpected argument '%s', can't parse\n", argv[1]); + + map[i].val->set = false; + + return -EINVAL; +} + +int args_envs_enumerate(const struct env_map_common *map, int enum_by, + int argc, char *const argv[]) +{ + u32 i; + + if (argc % enum_by) { + pr_err("unexpected argument number: %d\n", argc); + return -EINVAL; + } + + while (argc > 0) { + i = args_envs_read_search(map, argc, argv); + if (i < 0) + return i; + + debug("ARG: found '%s' with index %d\n", map[i].env_name, i); + + if (i < 0) { + pr_err("unknown arg: %s\n", argv[0]); + return -EINVAL; + } + + if (arg_read_set(map, i, argc, argv)) + return -EINVAL; + + debug("ARG: value.s '%s' == %#x\n", argv[1], map[i].val->val); + + argc -= enum_by; + argv += enum_by; + } + + return 0; +} diff --git a/board/synopsys/hsdk/env-lib.h b/board/synopsys/hsdk/env-lib.h new file mode 100644 index 00000000000..606e802f0f7 --- /dev/null +++ b/board/synopsys/hsdk/env-lib.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2018 Synopsys, Inc. All rights reserved. + * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __BOARD_ENV_LIB_H +#define __BOARD_ENV_LIB_H + +#include <common.h> +#include <config.h> +#include <linux/kernel.h> + +enum env_type { + ENV_DEC, + ENV_HEX +}; + +typedef struct { + u32 val; + bool set; +} u32_env; + +struct env_map_common { + const char *const env_name; + enum env_type type; + bool mandatory; + u32 min; + u32 max; + u32_env *val; +}; + +struct env_map_percpu { + const char *const env_name; + enum env_type type; + bool mandatory; + u32 min[NR_CPUS]; + u32 max[NR_CPUS]; + u32_env (*val)[NR_CPUS]; +}; + +void envs_cleanup_common(const struct env_map_common *map); +int envs_read_common(const struct env_map_common *map); +int envs_validate_common(const struct env_map_common *map); +int envs_read_validate_common(const struct env_map_common *map); + +void envs_cleanup_core(const struct env_map_percpu *map); +int envs_read_validate_core(const struct env_map_percpu *map, + bool (*cpu_used)(u32)); +int envs_process_and_validate(const struct env_map_common *common, + const struct env_map_percpu *core, + bool (*cpu_used)(u32)); + +int args_envs_enumerate(const struct env_map_common *map, + int enum_by, int argc, char *const argv[]); + +#endif /* __BOARD_ENV_LIB_H */ diff --git a/board/synopsys/hsdk/hsdk.c b/board/synopsys/hsdk/hsdk.c index 5b3a063b690..65f937fd0fe 100644 --- a/board/synopsys/hsdk/hsdk.c +++ b/board/synopsys/hsdk/hsdk.c @@ -1,59 +1,713 @@ /* - * Copyright (C) 2017 Synopsys, Inc. All rights reserved. + * Copyright (C) 2018 Synopsys, Inc. All rights reserved. + * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com> * * SPDX-License-Identifier: GPL-2.0+ */ #include <common.h> +#include <config.h> +#include <linux/printk.h> +#include <linux/kernel.h> +#include <linux/io.h> +#include <asm/arcregs.h> +#include <fdt_support.h> #include <dwmmc.h> #include <malloc.h> +#include <usb.h> + +#include "clk-lib.h" +#include "env-lib.h" DECLARE_GLOBAL_DATA_PTR; -#define CREG_BASE (ARC_PERIPHERAL_BASE + 0x1000) -#define CREG_PAE (CREG_BASE + 0x180) -#define CREG_PAE_UPDATE (CREG_BASE + 0x194) -#define CREG_CPU_START (CREG_BASE + 0x400) +#define ALL_CPU_MASK GENMASK(NR_CPUS - 1, 0) +#define MASTER_CPU_ID 0 +#define APERTURE_SHIFT 28 +#define NO_CCM 0x10 +#define SLAVE_CPU_READY 0x12345678 +#define BOOTSTAGE_1 1 /* after SP, FP setup, before HW init */ +#define BOOTSTAGE_2 2 /* after HW init, before self halt */ +#define BOOTSTAGE_3 3 /* after self halt */ +#define BOOTSTAGE_4 4 /* before app launch */ +#define BOOTSTAGE_5 5 /* after app launch, unreachable */ -int board_early_init_f(void) +#define RESET_VECTOR_ADDR 0x0 + +#define CREG_BASE (ARC_PERIPHERAL_BASE + 0x1000) +#define CREG_CPU_START (CREG_BASE + 0x400) +#define CREG_CPU_START_MASK 0xF + +#define SDIO_BASE (ARC_PERIPHERAL_BASE + 0xA000) +#define SDIO_UHS_REG_EXT (SDIO_BASE + 0x108) +#define SDIO_UHS_REG_EXT_DIV_2 (2 << 30) + +/* Uncached access macros */ +#define arc_read_uncached_32(ptr) \ +({ \ + unsigned int __ret; \ + __asm__ __volatile__( \ + " ld.di %0, [%1] \n" \ + : "=r"(__ret) \ + : "r"(ptr)); \ + __ret; \ +}) + +#define arc_write_uncached_32(ptr, data)\ +({ \ + __asm__ __volatile__( \ + " st.di %0, [%1] \n" \ + : \ + : "r"(data), "r"(ptr)); \ +}) + +struct hsdk_env_core_ctl { + u32_env entry[NR_CPUS]; + u32_env iccm[NR_CPUS]; + u32_env dccm[NR_CPUS]; +}; + +struct hsdk_env_common_ctl { + bool halt_on_boot; + u32_env core_mask; + u32_env cpu_freq; + u32_env axi_freq; + u32_env tun_freq; + u32_env nvlim; + u32_env icache; + u32_env dcache; +}; + +/* + * Uncached cross-cpu structure. All CPUs must access to this structure fields + * only with arc_read_uncached_32() / arc_write_uncached_32() accessors (which + * implement ld.di / st.di instructions). Simultaneous cached and uncached + * access to this area will lead to data loss. + * We flush all data caches in board_early_init_r() as we don't want to have + * any dirty line in L1d$ or SL$ in this area. + */ +struct hsdk_cross_cpu { + /* slave CPU ready flag */ + u32 ready_flag; + /* address of the area, which can be used for stack by slave CPU */ + u32 stack_ptr; + /* slave CPU status - bootstage number */ + s32 status[NR_CPUS]; + + /* + * Slave CPU data - it is copy of corresponding fields in + * hsdk_env_core_ctl and hsdk_env_common_ctl structures which are + * required for slave CPUs initialization. + * This fields can be populated by copying from hsdk_env_core_ctl + * and hsdk_env_common_ctl structures with sync_cross_cpu_data() + * function. + */ + u32 entry[NR_CPUS]; + u32 iccm[NR_CPUS]; + u32 dccm[NR_CPUS]; + + u32 core_mask; + u32 icache; + u32 dcache; + + u8 cache_padding[ARCH_DMA_MINALIGN]; +} __aligned(ARCH_DMA_MINALIGN); + +/* Place for slave CPUs temporary stack */ +static u32 slave_stack[256 * NR_CPUS] __aligned(ARCH_DMA_MINALIGN); + +static struct hsdk_env_common_ctl env_common = {}; +static struct hsdk_env_core_ctl env_core = {}; +static struct hsdk_cross_cpu cross_cpu_data; + +static const struct env_map_common env_map_common[] = { + { "core_mask", ENV_HEX, true, 0x1, 0xF, &env_common.core_mask }, + { "non_volatile_limit", ENV_HEX, true, 0, 0xF, &env_common.nvlim }, + { "icache_ena", ENV_HEX, true, 0, 1, &env_common.icache }, + { "dcache_ena", ENV_HEX, true, 0, 1, &env_common.dcache }, + {} +}; + +static const struct env_map_common env_map_clock[] = { + { "cpu_freq", ENV_DEC, false, 100, 1000, &env_common.cpu_freq }, + { "axi_freq", ENV_DEC, false, 200, 800, &env_common.axi_freq }, + { "tun_freq", ENV_DEC, false, 0, 150, &env_common.tun_freq }, + {} +}; + +static const struct env_map_percpu env_map_core[] = { + { "core_iccm", ENV_HEX, true, {NO_CCM, 0, NO_CCM, 0}, {NO_CCM, 0xF, NO_CCM, 0xF}, &env_core.iccm }, + { "core_dccm", ENV_HEX, true, {NO_CCM, 0, NO_CCM, 0}, {NO_CCM, 0xF, NO_CCM, 0xF}, &env_core.dccm }, + {} +}; + +static const struct env_map_common env_map_mask[] = { + { "core_mask", ENV_HEX, false, 0x1, 0xF, &env_common.core_mask }, + {} +}; + +static const struct env_map_percpu env_map_go[] = { + { "core_entry", ENV_HEX, true, {0, 0, 0, 0}, {U32_MAX, U32_MAX, U32_MAX, U32_MAX}, &env_core.entry }, + {} +}; + +static void sync_cross_cpu_data(void) +{ + u32 value; + + for (u32 i = 0; i < NR_CPUS; i++) { + value = env_core.entry[i].val; + arc_write_uncached_32(&cross_cpu_data.entry[i], value); + } + + for (u32 i = 0; i < NR_CPUS; i++) { + value = env_core.iccm[i].val; + arc_write_uncached_32(&cross_cpu_data.iccm[i], value); + } + + for (u32 i = 0; i < NR_CPUS; i++) { + value = env_core.dccm[i].val; + arc_write_uncached_32(&cross_cpu_data.dccm[i], value); + } + + value = env_common.core_mask.val; + arc_write_uncached_32(&cross_cpu_data.core_mask, value); + + value = env_common.icache.val; + arc_write_uncached_32(&cross_cpu_data.icache, value); + + value = env_common.dcache.val; + arc_write_uncached_32(&cross_cpu_data.dcache, value); +} + +/* Can be used only on master CPU */ +static bool is_cpu_used(u32 cpu_id) { - /* In current chip PAE support for DMA is broken, disabling it. */ - writel(0, (void __iomem *) CREG_PAE); + return !!(env_common.core_mask.val & BIT(cpu_id)); +} - /* Really apply settings made above */ - writel(1, (void __iomem *) CREG_PAE_UPDATE); +/* TODO: add ICCM BCR and DCCM BCR runtime check */ +static void init_slave_cpu_func(u32 core) +{ + u32 val; + + /* Remap ICCM to another memory region if it exists */ + val = arc_read_uncached_32(&cross_cpu_data.iccm[core]); + if (val != NO_CCM) + write_aux_reg(ARC_AUX_ICCM_BASE, val << APERTURE_SHIFT); + + /* Remap DCCM to another memory region if it exists */ + val = arc_read_uncached_32(&cross_cpu_data.dccm[core]); + if (val != NO_CCM) + write_aux_reg(ARC_AUX_DCCM_BASE, val << APERTURE_SHIFT); + + if (arc_read_uncached_32(&cross_cpu_data.icache)) + icache_enable(); + else + icache_disable(); + + if (arc_read_uncached_32(&cross_cpu_data.dcache)) + dcache_enable(); + else + dcache_disable(); +} + +static void init_cluster_nvlim(void) +{ + u32 val = env_common.nvlim.val << APERTURE_SHIFT; + + flush_dcache_all(); + write_aux_reg(ARC_AUX_NON_VOLATILE_LIMIT, val); + write_aux_reg(AUX_AUX_CACHE_LIMIT, val); + flush_n_invalidate_dcache_all(); +} + +static void init_master_icache(void) +{ + if (icache_status()) { + /* I$ is enabled - we need to disable it */ + if (!env_common.icache.val) + icache_disable(); + } else { + /* I$ is disabled - we need to enable it */ + if (env_common.icache.val) { + icache_enable(); + + /* invalidate I$ right after enable */ + invalidate_icache_all(); + } + } +} + +static void init_master_dcache(void) +{ + if (dcache_status()) { + /* D$ is enabled - we need to disable it */ + if (!env_common.dcache.val) + dcache_disable(); + } else { + /* D$ is disabled - we need to enable it */ + if (env_common.dcache.val) + dcache_enable(); + + /* TODO: probably we need ti invalidate D$ right after enable */ + } +} + +static int cleanup_before_go(void) +{ + disable_interrupts(); + sync_n_cleanup_cache_all(); return 0; } -#define SDIO_BASE (ARC_PERIPHERAL_BASE + 0xA000) -#define SDIO_UHS_REG_EXT (SDIO_BASE + 0x108) -#define SDIO_UHS_REG_EXT_DIV_2 (2 << 30) +void slave_cpu_set_boot_addr(u32 addr) +{ + /* All cores have reset vector pointing to 0 */ + writel(addr, (void __iomem *)RESET_VECTOR_ADDR); -int board_mmc_init(bd_t *bis) + /* Make sure other cores see written value in memory */ + sync_n_cleanup_cache_all(); +} + +static inline void halt_this_cpu(void) { - struct dwmci_host *host = NULL; + __builtin_arc_flag(1); +} - host = malloc(sizeof(struct dwmci_host)); - if (!host) { - printf("dwmci_host malloc fail!\n"); - return 1; +static void smp_kick_cpu_x(u32 cpu_id) +{ + int cmd = readl((void __iomem *)CREG_CPU_START); + + if (cpu_id > NR_CPUS) + return; + + cmd &= ~CREG_CPU_START_MASK; + cmd |= (1 << cpu_id); + writel(cmd, (void __iomem *)CREG_CPU_START); +} + +static u32 prepare_cpu_ctart_reg(void) +{ + int cmd = readl((void __iomem *)CREG_CPU_START); + + cmd &= ~CREG_CPU_START_MASK; + + return cmd | env_common.core_mask.val; +} + +/* slave CPU entry for configuration */ +__attribute__((naked, noreturn, flatten)) noinline void hsdk_core_init_f(void) +{ + __asm__ __volatile__( + "ld.di r8, [%0]\n" + "mov %%sp, r8\n" + "mov %%fp, %%sp\n" + : /* no output */ + : "r" (&cross_cpu_data.stack_ptr)); + + invalidate_icache_all(); + + arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], BOOTSTAGE_1); + init_slave_cpu_func(CPU_ID_GET()); + + arc_write_uncached_32(&cross_cpu_data.ready_flag, SLAVE_CPU_READY); + arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], BOOTSTAGE_2); + + /* Halt the processor until the master kick us again */ + halt_this_cpu(); + + /* + * 3 NOPs after FLAG 1 instruction are no longer required for ARCv2 + * cores but we leave them for gebug purposes. + */ + __builtin_arc_nop(); + __builtin_arc_nop(); + __builtin_arc_nop(); + + arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], BOOTSTAGE_3); + + /* get the updated entry - invalidate i$ */ + invalidate_icache_all(); + + arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], BOOTSTAGE_4); + + /* Run our program */ + ((void (*)(void))(arc_read_uncached_32(&cross_cpu_data.entry[CPU_ID_GET()])))(); + + /* This bootstage is unreachable as we don't return from app we launch */ + arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], BOOTSTAGE_5); + + /* Something went terribly wrong */ + while (true) + halt_this_cpu(); +} + +static void clear_cross_cpu_data(void) +{ + arc_write_uncached_32(&cross_cpu_data.ready_flag, 0); + arc_write_uncached_32(&cross_cpu_data.stack_ptr, 0); + + for (u32 i = 0; i < NR_CPUS; i++) + arc_write_uncached_32(&cross_cpu_data.status[i], 0); +} + +static noinline void do_init_slave_cpu(u32 cpu_id) +{ + /* attempts number for check clave CPU ready_flag */ + u32 attempts = 100; + u32 stack_ptr = (u32)(slave_stack + (64 * cpu_id)); + + if (cpu_id >= NR_CPUS) + return; + + arc_write_uncached_32(&cross_cpu_data.ready_flag, 0); + + /* Use global unique place for each slave cpu stack */ + arc_write_uncached_32(&cross_cpu_data.stack_ptr, stack_ptr); + + debug("CPU %u: stack pool base: %p\n", cpu_id, slave_stack); + debug("CPU %u: current slave stack base: %x\n", cpu_id, stack_ptr); + slave_cpu_set_boot_addr((u32)hsdk_core_init_f); + + smp_kick_cpu_x(cpu_id); + + debug("CPU %u: cross-cpu flag: %x [before timeout]\n", cpu_id, + arc_read_uncached_32(&cross_cpu_data.ready_flag)); + + while (!arc_read_uncached_32(&cross_cpu_data.ready_flag) && attempts--) + mdelay(10); + + /* Just to be sure that slave cpu is halted after it set ready_flag */ + mdelay(20); + + /* + * Only print error here if we reach timeout as there is no option to + * halt slave cpu (or check that slave cpu is halted) + */ + if (!attempts) + pr_err("CPU %u is not responding after init!\n", cpu_id); + + /* Check current stage of slave cpu */ + if (arc_read_uncached_32(&cross_cpu_data.status[cpu_id]) != BOOTSTAGE_2) + pr_err("CPU %u status is unexpected: %d\n", cpu_id, + arc_read_uncached_32(&cross_cpu_data.status[cpu_id])); + + debug("CPU %u: cross-cpu flag: %x [after timeout]\n", cpu_id, + arc_read_uncached_32(&cross_cpu_data.ready_flag)); + debug("CPU %u: status: %d [after timeout]\n", cpu_id, + arc_read_uncached_32(&cross_cpu_data.status[cpu_id])); +} + +static void do_init_slave_cpus(void) +{ + clear_cross_cpu_data(); + sync_cross_cpu_data(); + + debug("cross_cpu_data location: %#x\n", (u32)&cross_cpu_data); + + for (u32 i = MASTER_CPU_ID + 1; i < NR_CPUS; i++) + if (is_cpu_used(i)) + do_init_slave_cpu(i); +} + +static void do_init_master_cpu(void) +{ + /* + * Setup master caches even if master isn't used as we want to use + * same cache configuration on all running CPUs + */ + init_master_icache(); + init_master_dcache(); +} + +enum hsdk_axi_masters { + M_HS_CORE = 0, + M_HS_RTT, + M_AXI_TUN, + M_HDMI_VIDEO, + M_HDMI_AUDIO, + M_USB_HOST, + M_ETHERNET, + M_SDIO, + M_GPU, + M_DMAC_0, + M_DMAC_1, + M_DVFS +}; + +#define UPDATE_VAL 1 + +/* + * m master AXI_M_m_SLV0 AXI_M_m_SLV1 AXI_M_m_OFFSET0 AXI_M_m_OFFSET1 + * 0 HS (CBU) 0x11111111 0x63111111 0xFEDCBA98 0x0E543210 + * 1 HS (RTT) 0x77777777 0x77777777 0xFEDCBA98 0x76543210 + * 2 AXI Tunnel 0x88888888 0x88888888 0xFEDCBA98 0x76543210 + * 3 HDMI-VIDEO 0x77777777 0x77777777 0xFEDCBA98 0x76543210 + * 4 HDMI-ADUIO 0x77777777 0x77777777 0xFEDCBA98 0x76543210 + * 5 USB-HOST 0x77777777 0x77999999 0xFEDCBA98 0x76DCBA98 + * 6 ETHERNET 0x77777777 0x77999999 0xFEDCBA98 0x76DCBA98 + * 7 SDIO 0x77777777 0x77999999 0xFEDCBA98 0x76DCBA98 + * 8 GPU 0x77777777 0x77777777 0xFEDCBA98 0x76543210 + * 9 DMAC (port #1) 0x77777777 0x77777777 0xFEDCBA98 0x76543210 + * 10 DMAC (port #2) 0x77777777 0x77777777 0xFEDCBA98 0x76543210 + * 11 DVFS 0x00000000 0x60000000 0x00000000 0x00000000 + * + * Please read ARC HS Development IC Specification, section 17.2 for more + * information about apertures configuration. + * NOTE: we intentionally modify default settings in U-boot. Default settings + * are specified in "Table 111 CREG Address Decoder register reset values". + */ + +#define CREG_AXI_M_SLV0(m) ((void __iomem *)(CREG_BASE + 0x020 * (m))) +#define CREG_AXI_M_SLV1(m) ((void __iomem *)(CREG_BASE + 0x020 * (m) + 0x004)) +#define CREG_AXI_M_OFT0(m) ((void __iomem *)(CREG_BASE + 0x020 * (m) + 0x008)) +#define CREG_AXI_M_OFT1(m) ((void __iomem *)(CREG_BASE + 0x020 * (m) + 0x00C)) +#define CREG_AXI_M_UPDT(m) ((void __iomem *)(CREG_BASE + 0x020 * (m) + 0x014)) + +#define CREG_AXI_M_HS_CORE_BOOT ((void __iomem *)(CREG_BASE + 0x010)) + +#define CREG_PAE ((void __iomem *)(CREG_BASE + 0x180)) +#define CREG_PAE_UPDT ((void __iomem *)(CREG_BASE + 0x194)) + +void init_memory_bridge(void) +{ + u32 reg; + + /* + * M_HS_CORE has one unic register - BOOT. + * We need to clean boot mirror (BOOT[1:0]) bits in them. + */ + reg = readl(CREG_AXI_M_HS_CORE_BOOT) & (~0x3); + writel(reg, CREG_AXI_M_HS_CORE_BOOT); + writel(0x11111111, CREG_AXI_M_SLV0(M_HS_CORE)); + writel(0x63111111, CREG_AXI_M_SLV1(M_HS_CORE)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HS_CORE)); + writel(0x0E543210, CREG_AXI_M_OFT1(M_HS_CORE)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HS_CORE)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_HS_RTT)); + writel(0x77777777, CREG_AXI_M_SLV1(M_HS_RTT)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HS_RTT)); + writel(0x76543210, CREG_AXI_M_OFT1(M_HS_RTT)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HS_RTT)); + + writel(0x88888888, CREG_AXI_M_SLV0(M_AXI_TUN)); + writel(0x88888888, CREG_AXI_M_SLV1(M_AXI_TUN)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_AXI_TUN)); + writel(0x76543210, CREG_AXI_M_OFT1(M_AXI_TUN)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_AXI_TUN)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_HDMI_VIDEO)); + writel(0x77777777, CREG_AXI_M_SLV1(M_HDMI_VIDEO)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HDMI_VIDEO)); + writel(0x76543210, CREG_AXI_M_OFT1(M_HDMI_VIDEO)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HDMI_VIDEO)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_HDMI_AUDIO)); + writel(0x77777777, CREG_AXI_M_SLV1(M_HDMI_AUDIO)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HDMI_AUDIO)); + writel(0x76543210, CREG_AXI_M_OFT1(M_HDMI_AUDIO)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HDMI_AUDIO)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_USB_HOST)); + writel(0x77999999, CREG_AXI_M_SLV1(M_USB_HOST)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_USB_HOST)); + writel(0x76DCBA98, CREG_AXI_M_OFT1(M_USB_HOST)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_USB_HOST)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_ETHERNET)); + writel(0x77999999, CREG_AXI_M_SLV1(M_ETHERNET)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_ETHERNET)); + writel(0x76DCBA98, CREG_AXI_M_OFT1(M_ETHERNET)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_ETHERNET)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_SDIO)); + writel(0x77999999, CREG_AXI_M_SLV1(M_SDIO)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_SDIO)); + writel(0x76DCBA98, CREG_AXI_M_OFT1(M_SDIO)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_SDIO)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_GPU)); + writel(0x77777777, CREG_AXI_M_SLV1(M_GPU)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_GPU)); + writel(0x76543210, CREG_AXI_M_OFT1(M_GPU)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_GPU)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_0)); + writel(0x77777777, CREG_AXI_M_SLV1(M_DMAC_0)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_0)); + writel(0x76543210, CREG_AXI_M_OFT1(M_DMAC_0)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_0)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_1)); + writel(0x77777777, CREG_AXI_M_SLV1(M_DMAC_1)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_1)); + writel(0x76543210, CREG_AXI_M_OFT1(M_DMAC_1)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_1)); + + writel(0x00000000, CREG_AXI_M_SLV0(M_DVFS)); + writel(0x60000000, CREG_AXI_M_SLV1(M_DVFS)); + writel(0x00000000, CREG_AXI_M_OFT0(M_DVFS)); + writel(0x00000000, CREG_AXI_M_OFT1(M_DVFS)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DVFS)); + + writel(0x00000000, CREG_PAE); + writel(UPDATE_VAL, CREG_PAE_UPDT); +} + +static void setup_clocks(void) +{ + ulong rate; + + /* Setup CPU clock */ + if (env_common.cpu_freq.set) { + rate = env_common.cpu_freq.val; + soc_clk_ctl("cpu-clk", &rate, CLK_ON | CLK_SET | CLK_MHZ); } + /* Setup TUN clock */ + if (env_common.tun_freq.set) { + rate = env_common.tun_freq.val; + if (rate) + soc_clk_ctl("tun-clk", &rate, CLK_ON | CLK_SET | CLK_MHZ); + else + soc_clk_ctl("tun-clk", NULL, CLK_OFF); + } + + if (env_common.axi_freq.set) { + rate = env_common.axi_freq.val; + soc_clk_ctl("axi-clk", &rate, CLK_SET | CLK_ON | CLK_MHZ); + } +} + +static void do_init_cluster(void) +{ /* - * Switch SDIO external ciu clock divider from default div-by-8 to - * minimum possible div-by-2. + * A multi-core ARC HS configuration always includes only one + * ARC_AUX_NON_VOLATILE_LIMIT register, which is shared by all the + * cores. */ - writel(SDIO_UHS_REG_EXT_DIV_2, (void __iomem *) SDIO_UHS_REG_EXT); + init_cluster_nvlim(); +} - memset(host, 0, sizeof(struct dwmci_host)); - host->name = "Synopsys Mobile storage"; - host->ioaddr = (void *)ARC_DWMMC_BASE; - host->buswidth = 4; - host->dev_index = 0; - host->bus_hz = 50000000; +static int check_master_cpu_id(void) +{ + if (CPU_ID_GET() == MASTER_CPU_ID) + return 0; - add_dwmci(host, host->bus_hz / 2, 400000); + pr_err("u-boot runs on non-master cpu with id: %lu\n", CPU_ID_GET()); + + return -ENOENT; +} + +static noinline int prepare_cpus(void) +{ + int ret; + + ret = check_master_cpu_id(); + if (ret) + return ret; + + ret = envs_process_and_validate(env_map_common, env_map_core, is_cpu_used); + if (ret) + return ret; + + printf("CPU start mask is %#x\n", env_common.core_mask.val); + + do_init_slave_cpus(); + do_init_master_cpu(); + do_init_cluster(); + + return 0; +} + +static int hsdk_go_run(u32 cpu_start_reg) +{ + /* Cleanup caches, disable interrupts */ + cleanup_before_go(); + + if (env_common.halt_on_boot) + halt_this_cpu(); + + /* + * 3 NOPs after FLAG 1 instruction are no longer required for ARCv2 + * cores but we leave them for gebug purposes. + */ + __builtin_arc_nop(); + __builtin_arc_nop(); + __builtin_arc_nop(); + + /* Kick chosen slave CPUs */ + writel(cpu_start_reg, (void __iomem *)CREG_CPU_START); + + if (is_cpu_used(MASTER_CPU_ID)) + ((void (*)(void))(env_core.entry[MASTER_CPU_ID].val))(); + else + halt_this_cpu(); + + pr_err("u-boot still runs on cpu [%ld]\n", CPU_ID_GET()); + + /* + * We will never return after executing our program if master cpu used + * otherwise halt master cpu manually. + */ + while (true) + halt_this_cpu(); + + return 0; +} + +int board_prep_linux(bootm_headers_t *images) +{ + int ret, ofst; + char mask[15]; + + ret = envs_read_validate_common(env_map_mask); + if (ret) + return ret; + + /* Rollback to default values */ + if (!env_common.core_mask.set) { + env_common.core_mask.val = ALL_CPU_MASK; + env_common.core_mask.set = true; + } + + printf("CPU start mask is %#x\n", env_common.core_mask.val); + + if (!is_cpu_used(MASTER_CPU_ID)) + pr_err("ERR: try to launch linux with CPU[0] disabled! It doesn't work for ARC.\n"); + + /* + * If we want to launch linux on all CPUs we don't need to patch + * linux DTB as it is default configuration + */ + if (env_common.core_mask.val == ALL_CPU_MASK) + return 0; + + if (!IMAGE_ENABLE_OF_LIBFDT || !images->ft_len) { + pr_err("WARN: core_mask setup will work properly only with external DTB!\n"); + return 0; + } + + /* patch '/possible-cpus' property according to cpu mask */ + ofst = fdt_path_offset(images->ft_addr, "/"); + sprintf(mask, "%s%s%s%s", + is_cpu_used(0) ? "0," : "", + is_cpu_used(1) ? "1," : "", + is_cpu_used(2) ? "2," : "", + is_cpu_used(3) ? "3," : ""); + ret = fdt_setprop_string(images->ft_addr, ofst, "possible-cpus", mask); + /* + * If we failed to patch '/possible-cpus' property we don't need break + * linux loading process: kernel will handle it but linux will print + * warning like "Timeout: CPU1 FAILED to comeup !!!". + * So warn here about error, but return 0 like no error had occurred. + */ + if (ret) + pr_err("WARN: failed to patch '/possible-cpus' property, ret=%d\n", + ret); return 0; } @@ -61,35 +715,335 @@ int board_mmc_init(bd_t *bis) void board_jump_and_run(ulong entry, int zero, int arch, uint params) { void (*kernel_entry)(int zero, int arch, uint params); + u32 cpu_start_reg; kernel_entry = (void (*)(int, int, uint))entry; - smp_set_core_boot_addr(entry, -1); - smp_kick_all_cpus(); - kernel_entry(zero, arch, params); + /* Prepare CREG_CPU_START for kicking chosen CPUs */ + cpu_start_reg = prepare_cpu_ctart_reg(); + + /* In case of run without hsdk_init */ + slave_cpu_set_boot_addr(entry); + + /* In case of run with hsdk_init */ + for (u32 i = 0; i < NR_CPUS; i++) { + env_core.entry[i].val = entry; + env_core.entry[i].set = true; + } + /* sync cross_cpu struct as we updated core-entry variables */ + sync_cross_cpu_data(); + + /* Kick chosen slave CPUs */ + writel(cpu_start_reg, (void __iomem *)CREG_CPU_START); + + if (is_cpu_used(0)) + kernel_entry(zero, arch, params); } -#define RESET_VECTOR_ADDR 0x0 +static int hsdk_go_prepare_and_run(void) +{ + /* Prepare CREG_CPU_START for kicking chosen CPUs */ + u32 reg = prepare_cpu_ctart_reg(); + + if (env_common.halt_on_boot) + printf("CPU will halt before application start, start application with debugger.\n"); -void smp_set_core_boot_addr(unsigned long addr, int corenr) + return hsdk_go_run(reg); +} + +static int do_hsdk_go(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { - /* All cores have reset vector pointing to 0 */ - writel(addr, (void __iomem *)RESET_VECTOR_ADDR); + int ret; - /* Make sure other cores see written value in memory */ + /* + * Check for 'halt' parameter. 'halt' = enter halt-mode just before + * starting the application; can be used for debug. + */ + if (argc > 1) { + env_common.halt_on_boot = !strcmp(argv[1], "halt"); + if (!env_common.halt_on_boot) { + pr_err("Unrecognised parameter: \'%s\'\n", argv[1]); + return CMD_RET_FAILURE; + } + } + + ret = check_master_cpu_id(); + if (ret) + return ret; + + ret = envs_process_and_validate(env_map_mask, env_map_go, is_cpu_used); + if (ret) + return ret; + + /* sync cross_cpu struct as we updated core-entry variables */ + sync_cross_cpu_data(); + + ret = hsdk_go_prepare_and_run(); + + return ret ? CMD_RET_FAILURE : CMD_RET_SUCCESS; +} + +U_BOOT_CMD( + hsdk_go, 3, 0, do_hsdk_go, + "Synopsys HSDK specific command", + " - Boot stand-alone application on HSDK\n" + "hsdk_go halt - Boot stand-alone application on HSDK, halt CPU just before application run\n" +); + +static int do_hsdk_init(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + static bool done = false; + int ret; + + /* hsdk_init can be run only once */ + if (done) { + printf("HSDK HW is already initialized! Please reset the board if you want to change the configuration.\n"); + return CMD_RET_FAILURE; + } + + ret = prepare_cpus(); + if (!ret) + done = true; + + return ret ? CMD_RET_FAILURE : CMD_RET_SUCCESS; +} + +U_BOOT_CMD( + hsdk_init, 1, 0, do_hsdk_init, + "Synopsys HSDK specific command", + "- Init HSDK HW\n" +); + +static int do_hsdk_clock_set(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + int ret = 0; + + /* Strip off leading subcommand argument */ + argc--; + argv++; + + envs_cleanup_common(env_map_clock); + + if (!argc) { + printf("Set clocks to values specified in environment\n"); + ret = envs_read_common(env_map_clock); + } else { + printf("Set clocks to values specified in args\n"); + ret = args_envs_enumerate(env_map_clock, 2, argc, argv); + } + + if (ret) + return CMD_RET_FAILURE; + + ret = envs_validate_common(env_map_clock); + if (ret) + return CMD_RET_FAILURE; + + /* Setup clock tree HW */ + setup_clocks(); + + return CMD_RET_SUCCESS; +} + +static int do_hsdk_clock_get(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + ulong rate; + + if (soc_clk_ctl("cpu-clk", &rate, CLK_GET | CLK_MHZ)) + return CMD_RET_FAILURE; + + if (env_set_ulong("cpu_freq", rate)) + return CMD_RET_FAILURE; + + if (soc_clk_ctl("tun-clk", &rate, CLK_GET | CLK_MHZ)) + return CMD_RET_FAILURE; + + if (env_set_ulong("tun_freq", rate)) + return CMD_RET_FAILURE; + + if (soc_clk_ctl("axi-clk", &rate, CLK_GET | CLK_MHZ)) + return CMD_RET_FAILURE; + + if (env_set_ulong("axi_freq", rate)) + return CMD_RET_FAILURE; + + printf("Clock values are saved to environment\n"); + + return CMD_RET_SUCCESS; +} + +static int do_hsdk_clock_print(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + /* Main clocks */ + soc_clk_ctl("cpu-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("tun-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("axi-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("ddr-clk", NULL, CLK_PRINT | CLK_MHZ); + + return CMD_RET_SUCCESS; +} + +static int do_hsdk_clock_print_all(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + /* + * NOTE: as of today we don't use some peripherals like HDMI / EBI + * so we don't want to print their clocks ("hdmi-sys-clk", "hdmi-pll", + * "hdmi-clk", "ebi-clk"). Nevertheless their clock subsystems is fully + * functional and we can print their clocks if it is required + */ + + /* CPU clock domain */ + soc_clk_ctl("cpu-pll", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("cpu-clk", NULL, CLK_PRINT | CLK_MHZ); + printf("\n"); + + /* SYS clock domain */ + soc_clk_ctl("sys-pll", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("apb-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("axi-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("eth-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("usb-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("sdio-clk", NULL, CLK_PRINT | CLK_MHZ); +/* soc_clk_ctl("hdmi-sys-clk", NULL, CLK_PRINT | CLK_MHZ); */ + soc_clk_ctl("gfx-core-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("gfx-dma-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("gfx-cfg-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("dmac-core-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("dmac-cfg-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("sdio-ref-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("spi-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("i2c-clk", NULL, CLK_PRINT | CLK_MHZ); +/* soc_clk_ctl("ebi-clk", NULL, CLK_PRINT | CLK_MHZ); */ + soc_clk_ctl("uart-clk", NULL, CLK_PRINT | CLK_MHZ); + printf("\n"); + + /* DDR clock domain */ + soc_clk_ctl("ddr-clk", NULL, CLK_PRINT | CLK_MHZ); + printf("\n"); + + /* HDMI clock domain */ +/* soc_clk_ctl("hdmi-pll", NULL, CLK_PRINT | CLK_MHZ); */ +/* soc_clk_ctl("hdmi-clk", NULL, CLK_PRINT | CLK_MHZ); */ +/* printf("\n"); */ + + /* TUN clock domain */ + soc_clk_ctl("tun-pll", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("tun-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("rom-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("pwm-clk", NULL, CLK_PRINT | CLK_MHZ); + printf("\n"); + + return CMD_RET_SUCCESS; +} + +cmd_tbl_t cmd_hsdk_clock[] = { + U_BOOT_CMD_MKENT(set, 3, 0, do_hsdk_clock_set, "", ""), + U_BOOT_CMD_MKENT(get, 3, 0, do_hsdk_clock_get, "", ""), + U_BOOT_CMD_MKENT(print, 4, 0, do_hsdk_clock_print, "", ""), + U_BOOT_CMD_MKENT(print_all, 4, 0, do_hsdk_clock_print_all, "", ""), +}; + +static int do_hsdk_clock(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + cmd_tbl_t *c; + + if (argc < 2) + return CMD_RET_USAGE; + + /* Strip off leading 'hsdk_clock' command argument */ + argc--; + argv++; + + c = find_cmd_tbl(argv[0], cmd_hsdk_clock, ARRAY_SIZE(cmd_hsdk_clock)); + if (!c) + return CMD_RET_USAGE; + + return c->cmd(cmdtp, flag, argc, argv); +} + +U_BOOT_CMD( + hsdk_clock, CONFIG_SYS_MAXARGS, 0, do_hsdk_clock, + "Synopsys HSDK specific clock command", + "set - Set clock to values specified in environment / command line arguments\n" + "hsdk_clock get - Save clock values to environment\n" + "hsdk_clock print - Print main clock values to console\n" + "hsdk_clock print_all - Print all clock values to console\n" +); + +/* init calls */ +int board_early_init_f(void) +{ + /* + * Setup AXI apertures unconditionally as we want to have DDR + * in 0x00000000 region when we are kicking slave cpus. + */ + init_memory_bridge(); + + return 0; +} + +int board_early_init_r(void) +{ + /* + * TODO: Init USB here to be able read environment from USB MSD. + * It can be done with usb_init() call. We can't do it right now + * due to brocken USB IP SW reset and lack of USB IP HW reset in + * linux kernel (if we init USB here we will break USB in linux) + */ + + /* + * Flush all d$ as we want to use uncached area with st.di / ld.di + * instructions and we don't want to have any dirty line in L1d$ or SL$ + * in this area. It is enough to flush all d$ once here as we access to + * uncached area with regular st (non .di) instruction only when we copy + * data during u-boot relocation. + */ flush_dcache_all(); + + printf("Relocation Offset is: %08lx\n", gd->reloc_off); + + return 0; } -void smp_kick_all_cpus(void) +int board_late_init(void) { -#define BITS_START_CORE1 1 -#define BITS_START_CORE2 2 -#define BITS_START_CORE3 3 + /* + * Populate environment with clock frequency values - + * run hsdk_clock get callback without uboot command run. + */ + do_hsdk_clock_get(NULL, 0, 0, NULL); - int cmd = readl((void __iomem *)CREG_CPU_START); + return 0; +} - cmd |= (1 << BITS_START_CORE1) | - (1 << BITS_START_CORE2) | - (1 << BITS_START_CORE3); - writel(cmd, (void __iomem *)CREG_CPU_START); +int board_mmc_init(bd_t *bis) +{ + struct dwmci_host *host = NULL; + + host = malloc(sizeof(struct dwmci_host)); + if (!host) { + printf("dwmci_host malloc fail!\n"); + return 1; + } + + /* + * Switch SDIO external ciu clock divider from default div-by-8 to + * minimum possible div-by-2. + */ + writel(SDIO_UHS_REG_EXT_DIV_2, (void __iomem *)SDIO_UHS_REG_EXT); + + memset(host, 0, sizeof(struct dwmci_host)); + host->name = "Synopsys Mobile storage"; + host->ioaddr = (void *)ARC_DWMMC_BASE; + host->buswidth = 4; + host->dev_index = 0; + host->bus_hz = 50000000; + + add_dwmci(host, host->bus_hz / 2, 400000); + + return 0; } diff --git a/cmd/Kconfig b/cmd/Kconfig index 136836d1465..27086df09b4 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -426,7 +426,6 @@ menu "Memory commands" config CMD_CRC32 bool "crc32" select HASH - default n if ARCH_SUNXI default y help Compute CRC32. @@ -568,7 +567,6 @@ config CMD_LZMADEC config CMD_UNZIP bool "unzip" - default n if ARCH_SUNXI default y if CMD_BOOTI help Uncompress a zip-compressed memory region. @@ -780,14 +778,12 @@ config CMD_I2C config CMD_LOADB bool "loadb" - default n if ARCH_SUNXI default y help Load a binary file over serial line. config CMD_LOADS bool "loads" - default n if ARCH_SUNXI default y help Load an S-Record file over serial line @@ -1187,7 +1183,6 @@ config CMD_GETTIME # TODO: rename to CMD_SLEEP config CMD_MISC bool "sleep" - default n if ARCH_SUNXI default y help Delay execution for some time diff --git a/common/spl/spl.c b/common/spl/spl.c index b1ce56d0d07..61d3071324b 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -127,8 +127,14 @@ void spl_set_header_raw_uboot(struct spl_image_info *spl_image) ulong u_boot_pos = binman_sym(ulong, u_boot_any, pos); spl_image->size = CONFIG_SYS_MONITOR_LEN; - if (u_boot_pos != BINMAN_SYM_MISSING) { - /* biman does not support separate entry addresses at present */ + + /* + * Binman error cases: address of the end of the previous region or the + * start of the image's entry area (usually 0) if there is no previous + * region. + */ + if (u_boot_pos && u_boot_pos != BINMAN_SYM_MISSING) { + /* Binman does not support separated entry addresses */ spl_image->entry_point = u_boot_pos; spl_image->load_addr = u_boot_pos; } else { diff --git a/configs/CHIP_pro_defconfig b/configs/CHIP_pro_defconfig index 60dcaa76db1..2e204d53939 100644 --- a/configs/CHIP_pro_defconfig +++ b/configs/CHIP_pro_defconfig @@ -1,11 +1,12 @@ CONFIG_ARM=y CONFIG_ARCH_SUNXI=y -CONFIG_SPL_NAND_SUPPORT=y CONFIG_MACH_SUN5I=y CONFIG_DRAM_TIMINGS_DDR3_800E_1066G_1333J=y CONFIG_USB0_VBUS_PIN="PB10" CONFIG_DEFAULT_DEVICE_TREE="sun5i-gr8-chip-pro" -CONFIG_SYS_EXTRA_OPTIONS="SYS_NAND_BLOCK_SIZE=0x40000,SYS_NAND_PAGE_SIZE=4096,SYS_NAND_OOBSIZE=256" +CONFIG_SYS_NAND_BLOCK_SIZE=0x40000 +CONFIG_SYS_NAND_PAGE_SIZE=0x1000 +CONFIG_SYS_NAND_OOBSIZE=0x100 CONFIG_SPL=y CONFIG_SPL_I2C_SUPPORT=y # CONFIG_CMD_FLASH is not set @@ -16,7 +17,6 @@ CONFIG_ENV_UBI_PART="UBI" CONFIG_ENV_UBI_VOLUME="uboot-env" # CONFIG_MMC is not set CONFIG_NAND=y -CONFIG_NAND_SUNXI=y CONFIG_AXP_ALDO3_VOLT=3300 CONFIG_AXP_ALDO4_VOLT=3300 CONFIG_CONS_INDEX=2 diff --git a/configs/Nintendo_NES_Classic_Edition_defconfig b/configs/Nintendo_NES_Classic_Edition_defconfig index 31d38afe212..62bee970694 100644 --- a/configs/Nintendo_NES_Classic_Edition_defconfig +++ b/configs/Nintendo_NES_Classic_Edition_defconfig @@ -9,6 +9,10 @@ CONFIG_AXP_GPIO=y CONFIG_DEFAULT_DEVICE_TREE="sun8i-r16-nintendo-nes-classic-edition" # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set CONFIG_SPL=y +CONFIG_NAND=y +CONFIG_SYS_NAND_BLOCK_SIZE=0x20000 +CONFIG_SYS_NAND_PAGE_SIZE=0x800 +CONFIG_SYS_NAND_OOBSIZE=0x40 # CONFIG_CMD_FLASH is not set # CONFIG_SPL_DOS_PARTITION is not set # CONFIG_SPL_ISO_PARTITION is not set diff --git a/configs/hsdk_defconfig b/configs/hsdk_defconfig index 11cb7e03a65..476ce6a9741 100644 --- a/configs/hsdk_defconfig +++ b/configs/hsdk_defconfig @@ -7,13 +7,18 @@ CONFIG_DEFAULT_DEVICE_TREE="hsdk" CONFIG_USE_BOOTARGS=y CONFIG_BOOTARGS="console=ttyS0,115200n8" CONFIG_BOARD_EARLY_INIT_F=y +CONFIG_HUSH_PARSER=y CONFIG_SYS_PROMPT="hsdk# " +CONFIG_CMD_ENV_FLAGS=y # CONFIG_CMD_FLASH is not set CONFIG_CMD_MMC=y +CONFIG_CMD_SF=y +CONFIG_CMD_SPI=y CONFIG_CMD_USB=y # CONFIG_CMD_SETEXPR is not set CONFIG_CMD_DHCP=y CONFIG_CMD_PING=y +CONFIG_CMD_CACHE=y CONFIG_CMD_EXT2=y CONFIG_CMD_EXT4=y CONFIG_CMD_EXT4_WRITE=y @@ -25,12 +30,20 @@ CONFIG_ENV_FAT_INTERFACE="mmc" CONFIG_ENV_FAT_DEVICE_AND_PART="0:1" CONFIG_NET_RANDOM_ETHADDR=y CONFIG_DM=y +CONFIG_CLK_HSDK=y +CONFIG_DM_GPIO=y +CONFIG_HSDK_CREG_GPIO=y CONFIG_MMC=y CONFIG_MMC_DW=y +CONFIG_DM_SPI_FLASH=y +CONFIG_SPI_FLASH=y +CONFIG_SPI_FLASH_SST=y CONFIG_DM_ETH=y CONFIG_ETH_DESIGNWARE=y CONFIG_DM_SERIAL=y CONFIG_SYS_NS16550=y +CONFIG_DM_SPI=y +CONFIG_DESIGNWARE_SPI=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_EHCI_HCD=y diff --git a/configs/pine64_plus_defconfig b/configs/pine64_plus_defconfig index e98740aec01..c512c1846d2 100644 --- a/configs/pine64_plus_defconfig +++ b/configs/pine64_plus_defconfig @@ -9,6 +9,7 @@ CONFIG_SPL=y # CONFIG_SPL_DOS_PARTITION is not set # CONFIG_SPL_ISO_PARTITION is not set # CONFIG_SPL_EFI_PARTITION is not set +CONFIG_OF_LIST="sun50i-a64-pine64 sun50i-a64-pine64-plus" CONFIG_SUN8I_EMAC=y CONFIG_USB_EHCI_HCD=y CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE=y diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c index 3cf01b6e369..ea6f3593b9e 100644 --- a/drivers/gpio/sunxi_gpio.c +++ b/drivers/gpio/sunxi_gpio.c @@ -354,12 +354,15 @@ static const struct udevice_id sunxi_gpio_ids[] = { ID("allwinner,sun8i-a83t-pinctrl", a_all), ID("allwinner,sun8i-h3-pinctrl", a_all), ID("allwinner,sun8i-r40-pinctrl", a_all), + ID("allwinner,sun8i-v3s-pinctrl", a_all), ID("allwinner,sun9i-a80-pinctrl", a_all), + ID("allwinner,sun50i-a64-pinctrl", a_all), ID("allwinner,sun6i-a31-r-pinctrl", l_2), ID("allwinner,sun8i-a23-r-pinctrl", l_1), ID("allwinner,sun8i-a83t-r-pinctrl", l_1), ID("allwinner,sun8i-h3-r-pinctrl", l_1), ID("allwinner,sun9i-a80-r-pinctrl", l_3), + ID("allwinner,sun50i-a64-r-pinctrl", l_1), { } }; diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index a820af61cee..94fbf89e4b8 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -95,9 +95,11 @@ config NAND_PXA3XX config NAND_SUNXI bool "Support for NAND on Allwinner SoCs" - depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I + default ARCH_SUNXI + depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUN8I select SYS_NAND_SELF_INIT select SYS_NAND_U_BOOT_LOCATIONS + select SPL_NAND_SUPPORT imply CMD_NAND ---help--- Enable support for NAND. This option enables the standard and @@ -166,6 +168,28 @@ config NAND_ZYNQ_USE_BOOTLOADER1_TIMINGS comment "Generic NAND options" +config SYS_NAND_BLOCK_SIZE + hex "NAND chip eraseblock size" + depends on ARCH_SUNXI + help + Number of data bytes in one eraseblock for the NAND chip on the + board. This is the multiple of NAND_PAGE_SIZE and the number of + pages. + +config SYS_NAND_PAGE_SIZE + hex "NAND chip page size" + depends on ARCH_SUNXI + help + Number of data bytes in one page for the NAND chip on the + board, not including the OOB area. + +config SYS_NAND_OOBSIZE + hex "NAND chip OOB size" + depends on ARCH_SUNXI + help + Number of bytes in the Out-Of-Band area for the NAND chip on + the board. + # Enhance depends when converting drivers to Kconfig which use this config # option (mxc_nand, ndfc, omap_gpmc). config SYS_NAND_BUSWIDTH_16BIT diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c index 532e03cd845..37160aaec2f 100644 --- a/drivers/mtd/nand/sunxi_nand.c +++ b/drivers/mtd/nand/sunxi_nand.c @@ -1407,8 +1407,14 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd, /* Add ECC info retrieval from DT */ for (i = 0; i < ARRAY_SIZE(strengths); i++) { - if (ecc->strength <= strengths[i]) + if (ecc->strength <= strengths[i]) { + /* + * Update ecc->strength value with the actual strength + * that will be used by the ECC engine. + */ + ecc->strength = strengths[i]; break; + } } if (i >= ARRAY_SIZE(strengths)) { diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c index eed4472bdc3..7241e9a374a 100644 --- a/drivers/mtd/nand/sunxi_nand_spl.c +++ b/drivers/mtd/nand/sunxi_nand_spl.c @@ -10,6 +10,7 @@ #include <common.h> #include <config.h> #include <nand.h> +#include <linux/ctype.h> /* registers */ #define NFC_CTL 0x00000000 @@ -55,7 +56,7 @@ #define NFC_ADDR_NUM_OFFSET 16 -#define NFC_SEND_ADR (1 << 19) +#define NFC_SEND_ADDR (1 << 19) #define NFC_ACCESS_DIR (1 << 20) #define NFC_DATA_TRANS (1 << 21) #define NFC_SEND_CMD1 (1 << 22) @@ -67,10 +68,12 @@ #define NFC_SEND_CMD3 (1 << 28) #define NFC_SEND_CMD4 (1 << 29) #define NFC_RAW_CMD (0 << 30) +#define NFC_ECC_CMD (1 << 30) #define NFC_PAGE_CMD (2 << 30) #define NFC_ST_CMD_INT_FLAG (1 << 1) #define NFC_ST_DMA_INT_FLAG (1 << 2) +#define NFC_ST_CMD_FIFO_STAT (1 << 3) #define NFC_READ_CMD_OFFSET 0 #define NFC_RANDOM_READ_CMD0_OFFSET 8 @@ -80,22 +83,6 @@ #define NFC_CMD_RNDOUT 0x05 #define NFC_CMD_READSTART 0x30 -#define SUNXI_DMA_CFG_REG0 0x300 -#define SUNXI_DMA_SRC_START_ADDR_REG0 0x304 -#define SUNXI_DMA_DEST_START_ADDRR_REG0 0x308 -#define SUNXI_DMA_DDMA_BC_REG0 0x30C -#define SUNXI_DMA_DDMA_PARA_REG0 0x318 - -#define SUNXI_DMA_DDMA_CFG_REG_LOADING (1 << 31) -#define SUNXI_DMA_DDMA_CFG_REG_DMA_DEST_DATA_WIDTH_32 (2 << 25) -#define SUNXI_DMA_DDMA_CFG_REG_DDMA_DST_DRQ_TYPE_DRAM (1 << 16) -#define SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_DATA_WIDTH_32 (2 << 9) -#define SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_ADDR_MODE_IO (1 << 5) -#define SUNXI_DMA_DDMA_CFG_REG_DDMA_SRC_DRQ_TYPE_NFC (3 << 0) - -#define SUNXI_DMA_DDMA_PARA_REG_SRC_WAIT_CYC (0x0F << 0) -#define SUNXI_DMA_DDMA_PARA_REG_SRC_BLK_SIZE (0x7F << 8) - struct nfc_config { int page_size; int ecc_strength; @@ -155,6 +142,42 @@ static inline int check_value_negated(int offset, int unexpected_bits, return check_value_inner(offset, unexpected_bits, timeout_us, 1); } +static int nand_wait_cmd_fifo_empty(void) +{ + if (!check_value_negated(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_FIFO_STAT, + DEFAULT_TIMEOUT_US)) { + printf("nand: timeout waiting for empty cmd FIFO\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int nand_wait_int(void) +{ + if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG, + DEFAULT_TIMEOUT_US)) { + printf("nand: timeout waiting for interruption\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int nand_exec_cmd(u32 cmd) +{ + int ret; + + ret = nand_wait_cmd_fifo_empty(); + if (ret) + return ret; + + writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST); + writel(cmd, SUNXI_NFC_BASE + NFC_CMD); + + return nand_wait_int(); +} + void nand_init(void) { uint32_t val; @@ -172,22 +195,15 @@ void nand_init(void) } /* reset NAND */ - writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST); - writel(NFC_SEND_CMD1 | NFC_WAIT_FLAG | NAND_CMD_RESET, - SUNXI_NFC_BASE + NFC_CMD); - - if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG, - DEFAULT_TIMEOUT_US)) { - printf("Error timeout waiting for nand reset\n"); - return; - } - writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST); + nand_exec_cmd(NFC_SEND_CMD1 | NFC_WAIT_FLAG | NAND_CMD_RESET); } static void nand_apply_config(const struct nfc_config *conf) { u32 val; + nand_wait_cmd_fifo_empty(); + val = readl(SUNXI_NFC_BASE + NFC_CTL); val &= ~NFC_CTL_PAGE_SIZE_MASK; writel(val | NFC_CTL_RAM_METHOD | NFC_CTL_PAGE_SIZE(conf->page_size), @@ -206,128 +222,111 @@ static int nand_load_page(const struct nfc_config *conf, u32 offs) SUNXI_NFC_BASE + NFC_RCMD_SET); writel(((page & 0xFFFF) << 16), SUNXI_NFC_BASE + NFC_ADDR_LOW); writel((page >> 16) & 0xFF, SUNXI_NFC_BASE + NFC_ADDR_HIGH); - writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST); - writel(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD | NFC_WAIT_FLAG | - ((conf->addr_cycles - 1) << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADR, - SUNXI_NFC_BASE + NFC_CMD); - - if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG, - DEFAULT_TIMEOUT_US)) { - printf("Error while initializing dma interrupt\n"); - return -EIO; - } - return 0; + return nand_exec_cmd(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD | + NFC_SEND_ADDR | NFC_WAIT_FLAG | + ((conf->addr_cycles - 1) << NFC_ADDR_NUM_OFFSET)); } -static int nand_reset_column(void) +static int nand_change_column(u16 column) { + int ret; + writel((NFC_CMD_RNDOUTSTART << NFC_RANDOM_READ_CMD1_OFFSET) | (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET) | (NFC_CMD_RNDOUTSTART << NFC_READ_CMD_OFFSET), SUNXI_NFC_BASE + NFC_RCMD_SET); - writel(0, SUNXI_NFC_BASE + NFC_ADDR_LOW); - writel(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD | - (1 << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADR | NFC_CMD_RNDOUT, - SUNXI_NFC_BASE + NFC_CMD); + writel(column, SUNXI_NFC_BASE + NFC_ADDR_LOW); - if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG, - DEFAULT_TIMEOUT_US)) { - printf("Error while initializing dma interrupt\n"); - return -1; - } + ret = nand_exec_cmd(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD | + (1 << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADDR | + NFC_CMD_RNDOUT); + if (ret) + return ret; + + /* Ensure tCCS has passed before reading data */ + udelay(1); return 0; } +static const int ecc_bytes[] = {32, 46, 54, 60, 74, 88, 102, 110, 116}; + static int nand_read_page(const struct nfc_config *conf, u32 offs, void *dest, int len) { - dma_addr_t dst = (dma_addr_t)dest; int nsectors = len / conf->ecc_size; u16 rand_seed = 0; - u32 val; - int page; - - page = offs / conf->page_size; + int oob_chunk_sz = ecc_bytes[conf->ecc_strength]; + int page = offs / conf->page_size; + u32 ecc_st; + int i; if (offs % conf->page_size || len % conf->ecc_size || len > conf->page_size || len < 0) return -EINVAL; - /* clear ecc status */ - writel(0, SUNXI_NFC_BASE + NFC_ECC_ST); - /* Choose correct seed if randomized */ if (conf->randomize) rand_seed = random_seed[page % conf->nseeds]; - writel((rand_seed << 16) | (conf->ecc_strength << 12) | - (conf->randomize ? NFC_ECC_RANDOM_EN : 0) | - (conf->ecc_size == 512 ? NFC_ECC_BLOCK_SIZE : 0) | - NFC_ECC_EN | NFC_ECC_PIPELINE | NFC_ECC_EXCEPTION, - SUNXI_NFC_BASE + NFC_ECC_CTL); - - flush_dcache_range(dst, ALIGN(dst + conf->ecc_size, ARCH_DMA_MINALIGN)); - - /* SUNXI_DMA */ - writel(0x0, SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0); /* clr dma cmd */ - /* read from REG_IO_DATA */ - writel(SUNXI_NFC_BASE + NFC_IO_DATA, - SUNXI_DMA_BASE + SUNXI_DMA_SRC_START_ADDR_REG0); - /* read to RAM */ - writel(dst, SUNXI_DMA_BASE + SUNXI_DMA_DEST_START_ADDRR_REG0); - writel(SUNXI_DMA_DDMA_PARA_REG_SRC_WAIT_CYC | - SUNXI_DMA_DDMA_PARA_REG_SRC_BLK_SIZE, - SUNXI_DMA_BASE + SUNXI_DMA_DDMA_PARA_REG0); - writel(len, SUNXI_DMA_BASE + SUNXI_DMA_DDMA_BC_REG0); - writel(SUNXI_DMA_DDMA_CFG_REG_LOADING | - SUNXI_DMA_DDMA_CFG_REG_DMA_DEST_DATA_WIDTH_32 | - SUNXI_DMA_DDMA_CFG_REG_DDMA_DST_DRQ_TYPE_DRAM | - SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_DATA_WIDTH_32 | - SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_ADDR_MODE_IO | - SUNXI_DMA_DDMA_CFG_REG_DDMA_SRC_DRQ_TYPE_NFC, - SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0); - - writel(nsectors, SUNXI_NFC_BASE + NFC_SECTOR_NUM); - writel(NFC_ST_DMA_INT_FLAG, SUNXI_NFC_BASE + NFC_ST); - writel(NFC_DATA_TRANS | NFC_PAGE_CMD | NFC_DATA_SWAP_METHOD, - SUNXI_NFC_BASE + NFC_CMD); - - if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_DMA_INT_FLAG, - DEFAULT_TIMEOUT_US)) { - printf("Error while initializing dma interrupt\n"); - return -EIO; - } - writel(NFC_ST_DMA_INT_FLAG, SUNXI_NFC_BASE + NFC_ST); + /* Retrieve data from SRAM (PIO) */ + for (i = 0; i < nsectors; i++) { + int data_off = i * conf->ecc_size; + int oob_off = conf->page_size + (i * oob_chunk_sz); + u8 *data = dest + data_off; + + /* Clear ECC status and restart ECC engine */ + writel(0, SUNXI_NFC_BASE + NFC_ECC_ST); + writel((rand_seed << 16) | (conf->ecc_strength << 12) | + (conf->randomize ? NFC_ECC_RANDOM_EN : 0) | + (conf->ecc_size == 512 ? NFC_ECC_BLOCK_SIZE : 0) | + NFC_ECC_EN | NFC_ECC_EXCEPTION, + SUNXI_NFC_BASE + NFC_ECC_CTL); + + /* Move the data in SRAM */ + nand_change_column(data_off); + writel(conf->ecc_size, SUNXI_NFC_BASE + NFC_CNT); + nand_exec_cmd(NFC_DATA_TRANS); - if (!check_value_negated(SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0, - SUNXI_DMA_DDMA_CFG_REG_LOADING, - DEFAULT_TIMEOUT_US)) { - printf("Error while waiting for dma transfer to finish\n"); - return -EIO; - } + /* + * Let the ECC engine consume the ECC bytes and possibly correct + * the data. + */ + nand_change_column(oob_off); + nand_exec_cmd(NFC_DATA_TRANS | NFC_ECC_CMD); + + /* Get the ECC status */ + ecc_st = readl(SUNXI_NFC_BASE + NFC_ECC_ST); + + /* ECC error detected. */ + if (ecc_st & 0xffff) + return -EIO; + + /* + * Return 1 if the first chunk is empty (needed for + * configuration detection). + */ + if (!i && (ecc_st & 0x10000)) + return 1; - invalidate_dcache_range(dst, - ALIGN(dst + conf->ecc_size, ARCH_DMA_MINALIGN)); + /* Retrieve the data from SRAM */ + memcpy_fromio(data, SUNXI_NFC_BASE + NFC_RAM0_BASE, + conf->ecc_size); - val = readl(SUNXI_NFC_BASE + NFC_ECC_ST); + /* Stop the ECC engine */ + writel(readl(SUNXI_NFC_BASE + NFC_ECC_CTL) & ~NFC_ECC_EN, + SUNXI_NFC_BASE + NFC_ECC_CTL); - /* ECC error detected. */ - if (val & 0xffff) - return -EIO; + if (data_off + conf->ecc_size >= len) + break; + } - /* - * Return 1 if the page is empty. - * We consider the page as empty if the first ECC block is marked - * empty. - */ - return (val & 0x10000) ? 1 : 0; + return 0; } static int nand_max_ecc_strength(struct nfc_config *conf) { - static const int ecc_bytes[] = { 32, 46, 54, 60, 74, 88, 102, 110, 116 }; int max_oobsize, max_ecc_bytes; int nsectors = conf->page_size / conf->ecc_size; int i; @@ -393,7 +392,7 @@ static int nand_detect_ecc_config(struct nfc_config *conf, u32 offs, conf->ecc_strength >= 0; conf->ecc_strength--) { conf->randomize = false; - if (nand_reset_column()) + if (nand_change_column(0)) return -EIO; /* @@ -413,7 +412,7 @@ static int nand_detect_ecc_config(struct nfc_config *conf, u32 offs, conf->randomize = true; conf->nseeds = ARRAY_SIZE(random_seed); do { - if (nand_reset_column()) + if (nand_change_column(0)) return -EIO; if (!nand_read_page(conf, offs, dest, @@ -475,11 +474,12 @@ static int nand_detect_config(struct nfc_config *conf, u32 offs, void *dest) static int nand_read_buffer(struct nfc_config *conf, uint32_t offs, unsigned int size, void *dest) { - int first_seed, page, ret; + int first_seed = 0, page, ret; size = ALIGN(size, conf->page_size); page = offs / conf->page_size; - first_seed = page % conf->nseeds; + if (conf->randomize) + first_seed = page % conf->nseeds; for (; size; size -= conf->page_size) { if (nand_load_page(conf, offs)) @@ -504,7 +504,7 @@ static int nand_read_buffer(struct nfc_config *conf, uint32_t offs, /* Try to adjust ->nseeds and read the page again... */ conf->nseeds = cur_seed; - if (nand_reset_column()) + if (nand_change_column(0)) return -EIO; /* ... it still fails => it's a real corruption. */ diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c index be43472b1aa..b6e5dafe83e 100644 --- a/drivers/net/sun8i_emac.c +++ b/drivers/net/sun8i_emac.c @@ -21,6 +21,7 @@ #include <malloc.h> #include <miiphy.h> #include <net.h> +#include <dt-bindings/pinctrl/sun4i-a10.h> #ifdef CONFIG_DM_GPIO #include <asm-generic/gpio.h> #endif @@ -278,7 +279,7 @@ static int sun8i_emac_set_syscon(struct emac_eth_dev *priv) int ret; u32 reg; - reg = readl(priv->sysctl_reg); + reg = readl(priv->sysctl_reg + 0x30); if (priv->variant == H3_EMAC) { ret = sun8i_emac_set_syscon_ephy(priv, ®); @@ -309,7 +310,7 @@ static int sun8i_emac_set_syscon(struct emac_eth_dev *priv) return -EINVAL; } - writel(reg, priv->sysctl_reg); + writel(reg, priv->sysctl_reg + 0x30); return 0; } @@ -455,7 +456,7 @@ static int parse_phy_pins(struct udevice *dev) { int offset; const char *pin_name; - int drive, pull, i; + int drive, pull = SUN4I_PINCTRL_NO_PULL, i; offset = fdtdec_lookup_phandle(gd->fdt_blob, dev_of_offset(dev), "pinctrl-0"); @@ -465,30 +466,44 @@ static int parse_phy_pins(struct udevice *dev) } drive = fdt_getprop_u32_default_node(gd->fdt_blob, offset, 0, - "allwinner,drive", 4); - pull = fdt_getprop_u32_default_node(gd->fdt_blob, offset, 0, - "allwinner,pull", 0); + "drive-strength", ~0); + if (drive != ~0) { + if (drive <= 10) + drive = SUN4I_PINCTRL_10_MA; + else if (drive <= 20) + drive = SUN4I_PINCTRL_20_MA; + else if (drive <= 30) + drive = SUN4I_PINCTRL_30_MA; + else + drive = SUN4I_PINCTRL_40_MA; + } + + if (fdt_get_property(gd->fdt_blob, offset, "bias-pull-up", NULL)) + pull = SUN4I_PINCTRL_PULL_UP; + else if (fdt_get_property(gd->fdt_blob, offset, "bias-pull-down", NULL)) + pull = SUN4I_PINCTRL_PULL_DOWN; + for (i = 0; ; i++) { int pin; pin_name = fdt_stringlist_get(gd->fdt_blob, offset, - "allwinner,pins", i, NULL); + "pins", i, NULL); if (!pin_name) break; - if (pin_name[0] != 'P') - continue; - pin = (pin_name[1] - 'A') << 5; - if (pin >= 26 << 5) + + pin = sunxi_name_to_gpio(pin_name); + if (pin < 0) continue; - pin += simple_strtol(&pin_name[2], NULL, 10); sunxi_gpio_set_cfgpin(pin, SUN8I_GPD8_GMAC); - sunxi_gpio_set_drv(pin, drive); - sunxi_gpio_set_pull(pin, pull); + if (drive != ~0) + sunxi_gpio_set_drv(pin, drive); + if (pull != ~0) + sunxi_gpio_set_pull(pin, pull); } if (!i) { - printf("WARNING: emac: cannot find allwinner,pins property\n"); + printf("WARNING: emac: cannot find pins property\n"); return -2; } @@ -772,6 +787,7 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev) struct eth_pdata *pdata = &sun8i_pdata->eth_pdata; struct emac_eth_dev *priv = dev_get_priv(dev); const char *phy_mode; + const fdt32_t *reg; int node = dev_of_offset(dev); int offset = 0; #ifdef CONFIG_DM_GPIO @@ -779,18 +795,40 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev) int ret = 0; #endif - pdata->iobase = devfdt_get_addr_name(dev, "emac"); - priv->sysctl_reg = devfdt_get_addr_name(dev, "syscon"); + pdata->iobase = devfdt_get_addr(dev); + if (pdata->iobase == FDT_ADDR_T_NONE) { + debug("%s: Cannot find MAC base address\n", __func__); + return -EINVAL; + } + + offset = fdtdec_lookup_phandle(gd->fdt_blob, node, "syscon"); + if (offset < 0) { + debug("%s: cannot find syscon node\n", __func__); + return -EINVAL; + } + reg = fdt_getprop(gd->fdt_blob, offset, "reg", NULL); + if (!reg) { + debug("%s: cannot find reg property in syscon node\n", + __func__); + return -EINVAL; + } + priv->sysctl_reg = fdt_translate_address((void *)gd->fdt_blob, + offset, reg); + if (priv->sysctl_reg == FDT_ADDR_T_NONE) { + debug("%s: Cannot find syscon base address\n", __func__); + return -EINVAL; + } pdata->phy_interface = -1; priv->phyaddr = -1; priv->use_internal_phy = false; - offset = fdtdec_lookup_phandle(gd->fdt_blob, node, - "phy"); - if (offset > 0) - priv->phyaddr = fdtdec_get_int(gd->fdt_blob, offset, "reg", - -1); + offset = fdtdec_lookup_phandle(gd->fdt_blob, node, "phy-handle"); + if (offset < 0) { + debug("%s: Cannot find PHY address\n", __func__); + return -EINVAL; + } + priv->phyaddr = fdtdec_get_int(gd->fdt_blob, offset, "reg", -1); phy_mode = fdt_getprop(gd->fdt_blob, node, "phy-mode", NULL); @@ -812,8 +850,11 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev) } if (priv->variant == H3_EMAC) { - if (fdt_getprop(gd->fdt_blob, node, - "allwinner,use-internal-phy", NULL)) + int parent = fdt_parent_offset(gd->fdt_blob, offset); + + if (parent >= 0 && + !fdt_node_check_compatible(gd->fdt_blob, parent, + "allwinner,sun8i-h3-mdio-internal")) priv->use_internal_phy = true; } diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 2fc0defcd0d..45a105db06a 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -38,7 +38,6 @@ config BACKLIGHT_GPIO config VIDEO_BPP8 bool "Support 8-bit-per-pixel displays" depends on DM_VIDEO - default n if ARCH_SUNXI default y if DM_VIDEO help Support drawing text and bitmaps onto a 8-bit-per-pixel display. @@ -49,7 +48,6 @@ config VIDEO_BPP8 config VIDEO_BPP16 bool "Support 16-bit-per-pixel displays" depends on DM_VIDEO - default n if ARCH_SUNXI default y if DM_VIDEO help Support drawing text and bitmaps onto a 16-bit-per-pixel display. diff --git a/env/Kconfig b/env/Kconfig index 35548721bdd..3bc1a35f658 100644 --- a/env/Kconfig +++ b/env/Kconfig @@ -152,7 +152,6 @@ config ENV_IS_IN_MMC bool "Environment in an MMC device" depends on !CHAIN_OF_TRUST depends on MMC - default y if ARCH_SUNXI default y if ARCH_EXYNOS4 default y if MX6SX || MX7D default y if TEGRA30 || TEGRA124 diff --git a/include/configs/hsdk.h b/include/configs/hsdk.h index fb4829ab468..ac86f311425 100644 --- a/include/configs/hsdk.h +++ b/include/configs/hsdk.h @@ -12,6 +12,7 @@ /* * CPU configuration */ +#define NR_CPUS 4 #define ARC_PERIPHERAL_BASE 0xF0000000 #define ARC_DWMMC_BASE (ARC_PERIPHERAL_BASE + 0xA000) #define ARC_DWGMAC_BASE (ARC_PERIPHERAL_BASE + 0x18000) @@ -61,6 +62,50 @@ */ #define CONFIG_ENV_SIZE SZ_16K +#define CONFIG_EXTRA_ENV_SETTINGS \ + "core_dccm_0=0x10\0" \ + "core_dccm_1=0x6\0" \ + "core_dccm_2=0x10\0" \ + "core_dccm_3=0x6\0" \ + "core_iccm_0=0x10\0" \ + "core_iccm_1=0x6\0" \ + "core_iccm_2=0x10\0" \ + "core_iccm_3=0x6\0" \ + "core_mask=0xF\0" \ + "dcache_ena=0x1\0" \ + "icache_ena=0x1\0" \ + "non_volatile_limit=0xE\0" \ + "hsdk_hs34=setenv core_mask 0x2; setenv icache_ena 0x0; \ +setenv dcache_ena 0x0; setenv core_iccm_1 0x7; \ +setenv core_dccm_1 0x8; setenv non_volatile_limit 0x0;\0" \ + "hsdk_hs36=setenv core_mask 0x1; setenv icache_ena 0x1; \ +setenv dcache_ena 0x1; setenv core_iccm_0 0x10; \ +setenv core_dccm_0 0x10; setenv non_volatile_limit 0xE;\0" \ + "hsdk_hs36_ccm=setenv core_mask 0x2; setenv icache_ena 0x1; \ +setenv dcache_ena 0x1; setenv core_iccm_1 0x7; \ +setenv core_dccm_1 0x8; setenv non_volatile_limit 0xE;\0" \ + "hsdk_hs38=setenv core_mask 0x1; setenv icache_ena 0x1; \ +setenv dcache_ena 0x1; setenv core_iccm_0 0x10; \ +setenv core_dccm_0 0x10; setenv non_volatile_limit 0xE;\0" \ + "hsdk_hs38_ccm=setenv core_mask 0x2; setenv icache_ena 0x1; \ +setenv dcache_ena 0x1; setenv core_iccm_1 0x7; \ +setenv core_dccm_1 0x8; setenv non_volatile_limit 0xE;\0" \ + "hsdk_hs38x2=setenv core_mask 0x3; setenv icache_ena 0x1; \ +setenv dcache_ena 0x1; setenv core_iccm_0 0x10; \ +setenv core_dccm_0 0x10; setenv non_volatile_limit 0xE; \ +setenv core_iccm_1 0x6; setenv core_dccm_1 0x6;\0" \ + "hsdk_hs38x3=setenv core_mask 0x7; setenv icache_ena 0x1; \ +setenv dcache_ena 0x1; setenv core_iccm_0 0x10; \ +setenv core_dccm_0 0x10; setenv non_volatile_limit 0xE; \ +setenv core_iccm_1 0x6; setenv core_dccm_1 0x6; \ +setenv core_iccm_2 0x10; setenv core_dccm_2 0x10;\0" \ + "hsdk_hs38x4=setenv core_mask 0xF; setenv icache_ena 0x1; \ +setenv dcache_ena 0x1; setenv core_iccm_0 0x10; \ +setenv core_dccm_0 0x10; setenv non_volatile_limit 0xE; \ +setenv core_iccm_1 0x6; setenv core_dccm_1 0x6; \ +setenv core_iccm_2 0x10; setenv core_dccm_2 0x10; \ +setenv core_iccm_3 0x6; setenv core_dccm_3 0x6;\0" + /* * Environment configuration */ @@ -68,12 +113,17 @@ #define CONFIG_LOADADDR CONFIG_SYS_LOAD_ADDR /* - * Console configuration + * Misc utility configuration */ +#define CONFIG_BOUNCE_BUFFER + +/* Cli configuration */ +#define CONFIG_SYS_CBSIZE SZ_2K /* - * Misc utility configuration + * Callback configuration */ -#define CONFIG_BOUNCE_BUFFER +#define CONFIG_BOARD_EARLY_INIT_R +#define CONFIG_BOARD_LATE_INIT #endif /* _CONFIG_HSDK_H_ */ diff --git a/lib/Kconfig b/lib/Kconfig index a4029a67dd6..436b90fa85c 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -66,7 +66,6 @@ config PANIC_HANG config REGEX bool "Enable regular expression support" - default n if ARCH_SUNXI default y if NET help If this variable is defined, U-Boot is linked against the |