summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--arch/arm/Kconfig7
-rw-r--r--arch/arm/cpu/armv7/am33xx/ddr.c24
-rw-r--r--arch/arm/dts/Makefile4
-rw-r--r--arch/arm/dts/rk3288-evb.dts59
-rw-r--r--arch/arm/dts/rk3288-evb.dtsi379
-rw-r--r--arch/arm/dts/rk3288.dtsi1
-rw-r--r--arch/arm/dts/rk3399-evb.dts104
-rw-r--r--arch/arm/dts/rk3399.dtsi1028
-rw-r--r--arch/arm/dts/sun5i-a10s.dtsi14
-rw-r--r--arch/arm/dts/sun5i-a13-olinuxino.dts15
-rw-r--r--arch/arm/dts/sun5i-r8-chip.dts15
-rw-r--r--arch/arm/dts/sun5i.dtsi49
-rw-r--r--arch/arm/include/asm/arch-omap4/i2c.h6
-rw-r--r--arch/arm/include/asm/arch-omap5/i2c.h6
-rw-r--r--arch/arm/include/asm/arch-rockchip/clock.h4
-rw-r--r--arch/arm/include/asm/arch-sunxi/clock_sun4i.h5
-rw-r--r--arch/arm/mach-keystone/init.c2
-rw-r--r--arch/arm/mach-rockchip/Kconfig38
-rw-r--r--arch/arm/mach-rockchip/Makefile8
-rw-r--r--arch/arm/mach-rockchip/board.c107
-rw-r--r--arch/arm/mach-rockchip/rk3036/Kconfig4
-rw-r--r--arch/arm/mach-rockchip/rk3036/Makefile1
-rw-r--r--arch/arm/mach-rockchip/rk3288-board-spl.c10
-rw-r--r--arch/arm/mach-rockchip/rk3288/Kconfig10
-rw-r--r--arch/arm/mach-rockchip/rk3288/Makefile1
-rw-r--r--arch/arm/mach-rockchip/rk3288/clk_rk3288.c17
-rw-r--r--arch/arm/mach-rockchip/rk3288/sdram_rk3288.c18
-rw-r--r--arch/arm/mach-rockchip/rk3399/Kconfig23
-rw-r--r--arch/arm/mach-rockchip/rk3399/Makefile7
-rw-r--r--arch/arm/mach-rockchip/rk3399/rk3399.c30
-rw-r--r--arch/arm/mach-rockchip/save_boot_param.S (renamed from arch/arm/mach-rockchip/rk3036/save_boot_param.S)2
-rw-r--r--board/evb-rk3288/evb-rk3288/Kconfig15
-rw-r--r--board/evb-rk3288/evb-rk3288/MAINTAINERS6
-rw-r--r--board/evb-rk3288/evb-rk3288/Makefile7
-rw-r--r--board/evb-rk3288/evb-rk3288/evb-rk3288.c15
-rw-r--r--board/rockchip/evb_rk3036/Kconfig (renamed from board/evb_rk3036/evb_rk3036/Kconfig)2
-rw-r--r--board/rockchip/evb_rk3036/MAINTAINERS (renamed from board/evb_rk3036/evb_rk3036/MAINTAINERS)0
-rw-r--r--board/rockchip/evb_rk3036/Makefile (renamed from board/evb_rk3036/evb_rk3036/Makefile)0
-rw-r--r--board/rockchip/evb_rk3036/evb_rk3036.c (renamed from board/evb_rk3036/evb_rk3036/evb_rk3036.c)0
-rw-r--r--board/rockchip/evb_rk3399/Kconfig15
-rw-r--r--board/rockchip/evb_rk3399/MAINTAINERS0
-rw-r--r--board/rockchip/evb_rk3399/Makefile7
-rw-r--r--board/rockchip/evb_rk3399/README73
-rw-r--r--board/rockchip/evb_rk3399/evb-rk3399.c26
-rw-r--r--board/rockchip/kylin_rk3036/Kconfig (renamed from board/kylin/kylin_rk3036/Kconfig)2
-rw-r--r--board/rockchip/kylin_rk3036/MAINTAINERS (renamed from board/kylin/kylin_rk3036/MAINTAINERS)0
-rw-r--r--board/rockchip/kylin_rk3036/Makefile (renamed from board/kylin/kylin_rk3036/Makefile)0
-rw-r--r--board/rockchip/kylin_rk3036/kylin_rk3036.c (renamed from board/kylin/kylin_rk3036/kylin_rk3036.c)0
-rw-r--r--board/sandbox/README.sandbox3
-rw-r--r--board/sunxi/board.c5
-rw-r--r--cmd/bootefi.c7
-rw-r--r--cmd/lzmadec.c5
-rw-r--r--cmd/misc.c21
-rw-r--r--cmd/mtdparts.c4
-rw-r--r--cmd/nand.c15
-rw-r--r--common/image-fit.c7
-rw-r--r--configs/am335x_boneblack_vboot_defconfig1
-rw-r--r--configs/am335x_evm_defconfig1
-rw-r--r--configs/am43xx_evm_defconfig1
-rw-r--r--configs/am43xx_hs_evm_defconfig1
-rw-r--r--configs/am57xx_evm_defconfig1
-rw-r--r--configs/am57xx_hs_evm_defconfig1
-rw-r--r--configs/chromebook_jerry_defconfig2
-rw-r--r--configs/dra7xx_evm_defconfig1
-rw-r--r--configs/dra7xx_hs_evm_defconfig1
-rw-r--r--configs/evb-rk3036_defconfig2
-rw-r--r--configs/evb-rk3288_defconfig67
-rw-r--r--configs/evb-rk3399_defconfig33
-rw-r--r--configs/firefly-rk3288_defconfig2
-rw-r--r--configs/kylin-rk3036_defconfig2
-rw-r--r--configs/rock2_defconfig2
-rw-r--r--configs/sandbox_defconfig5
-rw-r--r--configs/sandbox_noblk_defconfig4
-rw-r--r--configs/thunderx_88xx_defconfig1
-rw-r--r--disk/part_efi.c10
-rw-r--r--doc/README.rockchip43
-rw-r--r--drivers/clk/clk_rk3288.c6
-rw-r--r--drivers/core/uclass.c20
-rw-r--r--drivers/i2c/Kconfig7
-rw-r--r--drivers/i2c/i2c-uclass.c14
-rw-r--r--drivers/i2c/mvtwsi.c777
-rw-r--r--drivers/i2c/omap24xx_i2c.c407
-rw-r--r--drivers/mmc/Kconfig6
-rw-r--r--drivers/mmc/Makefile1
-rw-r--r--drivers/mmc/rockchip_sdhci.c93
-rw-r--r--drivers/mtd/nand/Kconfig8
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/nand_base.c72
-rw-r--r--drivers/mtd/nand/nand_ids.c4
-rw-r--r--drivers/mtd/nand/sunxi_nand.c1845
-rw-r--r--drivers/pinctrl/Kconfig14
-rw-r--r--drivers/pinctrl/rockchip/Makefile4
-rw-r--r--drivers/usb/gadget/dwc2_udc_otg.c22
-rw-r--r--drivers/usb/gadget/dwc2_udc_otg_regs.h6
-rw-r--r--drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c3
-rw-r--r--drivers/usb/phy/Makefile1
-rw-r--r--drivers/usb/phy/rockchip_usb2_phy.c107
-rw-r--r--drivers/video/rockchip/rk_vop.c2
-rw-r--r--include/configs/evb-rk3288.h26
-rw-r--r--include/configs/evb_rk3399.h26
-rw-r--r--include/configs/rk3288_common.h31
-rw-r--r--include/configs/rk3399_common.h73
-rw-r--r--include/configs/sandbox.h6
-rw-r--r--include/configs/sunxi-common.h3
-rw-r--r--include/configs/ti_armv7_common.h16
-rw-r--r--include/dm/device.h4
-rw-r--r--include/dm/uclass.h18
-rw-r--r--include/dt-bindings/clock/rk3399-cru.h746
-rw-r--r--include/fdtdec.h1
-rw-r--r--include/linux/mtd/mtd.h5
-rw-r--r--include/linux/mtd/nand.h5
-rw-r--r--include/nand.h3
-rw-r--r--include/usb/dwc2_udc.h5
-rw-r--r--lib/fdtdec.c1
-rw-r--r--lib/hashtable.c10
-rw-r--r--lib/rsa/rsa-sign.c6
-rw-r--r--tools/dtoc/fdt_fallback.py6
-rw-r--r--tools/env/fw_env.c17
-rw-r--r--tools/image-host.c11
-rw-r--r--tools/rkcommon.c1
121 files changed, 6377 insertions, 481 deletions
diff --git a/Makefile b/Makefile
index 7ce933c..bccfbaa 100644
--- a/Makefile
+++ b/Makefile
@@ -3,9 +3,9 @@
#
VERSION = 2016
-PATCHLEVEL = 07
+PATCHLEVEL = 09
SUBLEVEL =
-EXTRAVERSION =
+EXTRAVERSION = -rc1
NAME =
# *DOCUMENTATION*
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 397981a..4a62d4b 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -840,15 +840,12 @@ config STM32
config ARCH_ROCKCHIP
bool "Support Rockchip SoCs"
- select SUPPORT_SPL
- select SPL
select OF_CONTROL
- select CPU_V7
select BLK
select DM
- select SPL_DM
+ select SPL_DM if SPL
select SYS_MALLOC_F
- select SPL_SYS_MALLOC_SIMPLE
+ select SPL_SYS_MALLOC_SIMPLE if SPL
select DM_GPIO
select DM_I2C
select DM_MMC
diff --git a/arch/arm/cpu/armv7/am33xx/ddr.c b/arch/arm/cpu/armv7/am33xx/ddr.c
index 888cf1f..6acf30c 100644
--- a/arch/arm/cpu/armv7/am33xx/ddr.c
+++ b/arch/arm/cpu/armv7/am33xx/ddr.c
@@ -120,12 +120,15 @@ void config_sdram_emif4d5(const struct emif_regs *regs, int nr)
writel(regs->sdram_config, &emif_reg[nr]->emif_sdram_config);
writel(regs->sdram_config, &cstat->secure_emif_sdram_config);
+
+ /* Wait 1ms because of L3 timeout error */
+ udelay(1000);
+
writel(regs->ref_ctrl, &emif_reg[nr]->emif_sdram_ref_ctrl);
writel(regs->ref_ctrl, &emif_reg[nr]->emif_sdram_ref_ctrl_shdw);
/* Perform hardware leveling for DDR3 */
if (emif_sdram_type(regs->sdram_config) == EMIF_SDRAM_TYPE_DDR3) {
- udelay(1000);
writel(readl(&emif_reg[nr]->emif_ddr_ext_phy_ctrl_36) |
0x100, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_36);
writel(readl(&emif_reg[nr]->emif_ddr_ext_phy_ctrl_36_shdw) |
@@ -289,19 +292,14 @@ static void ext_phy_settings_hwlvl(const struct emif_regs *regs, int nr)
void config_ddr_phy(const struct emif_regs *regs, int nr)
{
/*
- * Disable initialization and refreshes for now until we
- * finish programming EMIF regs.
- * Also set time between rising edge of DDR_RESET to rising
- * edge of DDR_CKE to > 500us per memory spec.
+ * Disable initialization and refreshes for now until we finish
+ * programming EMIF regs and set time between rising edge of
+ * DDR_RESET to rising edge of DDR_CKE to > 500us per memory spec.
+ * We currently hardcode a value based on a max expected frequency
+ * of 400MHz.
*/
-#ifndef CONFIG_AM43XX
- setbits_le32(&emif_reg[nr]->emif_sdram_ref_ctrl,
- EMIF_REG_INITREF_DIS_MASK);
-#endif
- if (regs->zq_config)
- /* Set time between rising edge of DDR_RESET to rising
- * edge of DDR_CKE to > 500us per memory spec. */
- writel(0x00003100, &emif_reg[nr]->emif_sdram_ref_ctrl);
+ writel(EMIF_REG_INITREF_DIS_MASK | 0x3100,
+ &emif_reg[nr]->emif_sdram_ref_ctrl);
writel(regs->emif_ddr_phy_ctlr_1,
&emif_reg[nr]->emif_ddr_phy_ctrl_1);
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index ca8712a..c97e3f6 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -31,7 +31,9 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \
rk3288-firefly.dtb \
rk3288-jerry.dtb \
rk3288-rock2-square.dtb \
- rk3036-sdk.dtb
+ rk3288-evb.dtb \
+ rk3036-sdk.dtb \
+ rk3399-evb.dtb
dtb-$(CONFIG_ARCH_MESON) += \
meson-gxbb-odroidc2.dtb
dtb-$(CONFIG_TEGRA) += tegra20-harmony.dtb \
diff --git a/arch/arm/dts/rk3288-evb.dts b/arch/arm/dts/rk3288-evb.dts
new file mode 100644
index 0000000..caf24ee
--- /dev/null
+++ b/arch/arm/dts/rk3288-evb.dts
@@ -0,0 +1,59 @@
+/*
+ * (C) Copyright 2016 Rockchip Electronics Co., Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0+ X11
+ */
+
+/dts-v1/;
+#include "rk3288-evb.dtsi"
+
+/ {
+ model = "Evb-RK3288";
+ compatible = "evb-rk3288,evb-rk3288", "rockchip,rk3288";
+
+ chosen {
+ stdout-path = &uart2;
+ };
+};
+
+&dmc {
+ rockchip,num-channels = <2>;
+ rockchip,pctl-timing = <0x215 0xc8 0x0 0x35 0x26 0x2 0x70 0x2000d
+ 0x6 0x0 0x8 0x4 0x17 0x24 0xd 0x6
+ 0x4 0x8 0x4 0x76 0x4 0x0 0x30 0x0
+ 0x1 0x2 0x2 0x4 0x0 0x0 0xc0 0x4
+ 0x8 0x1f4>;
+ rockchip,phy-timing = <0x48d7dd93 0x187008d8 0x121076
+ 0x0 0xc3 0x6 0x2>;
+ rockchip,sdram-channel = /bits/ 8 <0x2 0xa 0x3 0x2 0x2 0x0 0xe 0xe>;
+ rockchip,sdram-params = <0x20d266a4 0x5b6 2 533000000 6 9 0>;
+};
+
+&pinctrl {
+ u-boot,dm-pre-reloc;
+};
+
+&pwm1 {
+ status = "okay";
+};
+
+&uart2 {
+ u-boot,dm-pre-reloc;
+ reg-shift = <2>;
+};
+
+&sdmmc {
+ u-boot,dm-pre-reloc;
+};
+
+&emmc {
+ u-boot,dm-pre-reloc;
+};
+
+&gpio3 {
+ u-boot,dm-pre-reloc;
+};
+
+&gpio8 {
+ u-boot,dm-pre-reloc;
+};
diff --git a/arch/arm/dts/rk3288-evb.dtsi b/arch/arm/dts/rk3288-evb.dtsi
new file mode 100644
index 0000000..cb7d03e
--- /dev/null
+++ b/arch/arm/dts/rk3288-evb.dtsi
@@ -0,0 +1,379 @@
+/*
+ * (C) Copyright 2016 Rockchip Electronics Co., Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0+ X11
+ */
+
+#include "rk3288.dtsi"
+
+/ {
+ memory {
+ reg = <0 0x80000000>;
+ };
+
+ keys: gpio-keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ button@0 {
+ gpio-key,wakeup = <1>;
+ gpios = <&gpio0 5 GPIO_ACTIVE_LOW>;
+ label = "GPIO Power";
+ linux,code = <116>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwr_key>;
+ };
+ };
+
+ vcc_sys: vsys-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc_sys";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ vcc_flash: flash-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc_flash";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ vin-supply = <&vcc_io>;
+ };
+
+ vcc_5v: usb-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc_5v";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ vin-supply = <&vcc_sys>;
+ };
+
+ vcc_host_5v: usb-host-regulator {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio0 14 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&host_vbus_drv>;
+ regulator-name = "vcc_host_5v";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ vin-supply = <&vcc_5v>;
+ };
+
+ vcc_otg_5v: usb-otg-regulator {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio0 12 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&otg_vbus_drv>;
+ regulator-name = "vcc_otg_5v";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ vin-supply = <&vcc_5v>;
+ };
+};
+
+&cpu0 {
+ cpu0-supply = <&vdd_cpu>;
+};
+
+&emmc {
+ broken-cd;
+ bus-width = <8>;
+ cap-mmc-highspeed;
+ disable-wp;
+ non-removable;
+ num-slots = <1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&emmc_clk>, <&emmc_cmd>, <&emmc_pwr>, <&emmc_bus8>;
+ vmmc-supply = <&vcc_io>;
+ vqmmc-supply = <&vcc_flash>;
+ status = "okay";
+};
+
+&hdmi {
+ ddc-i2c-bus = <&i2c5>;
+ status = "okay";
+};
+
+&i2c0 {
+ clock-frequency = <400000>;
+ status = "okay";
+
+ vdd_cpu: syr827@40 {
+ compatible = "silergy,syr827";
+ fcs,suspend-voltage-selector = <1>;
+ reg = <0x40>;
+ regulator-name = "vdd_cpu";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ vin-supply = <&vcc_sys>;
+ };
+
+ vdd_gpu: syr828@41 {
+ compatible = "silergy,syr828";
+ fcs,suspend-voltage-selector = <1>;
+ reg = <0x41>;
+ regulator-name = "vdd_gpu";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ vin-supply = <&vcc_sys>;
+ };
+
+ hym8563: hym8563@51 {
+ compatible = "haoyu,hym8563";
+ reg = <0x51>;
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ clock-output-names = "xin32k";
+ interrupt-parent = <&gpio7>;
+ interrupts = <4 IRQ_TYPE_EDGE_FALLING>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&rtc_int>;
+ };
+
+ act8846: act8846@5a {
+ compatible = "active-semi,act8846";
+ reg = <0x5a>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwr_hold>;
+ system-power-controller;
+
+ regulators {
+ vcc_ddr: REG1 {
+ regulator-name = "vcc_ddr";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ };
+
+ vcc_io: REG2 {
+ regulator-name = "vcc_io";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vdd_log: REG3 {
+ regulator-name = "vdd_log";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ };
+
+ vcc_20: REG4 {
+ regulator-name = "vcc_20";
+ regulator-min-microvolt = <2000000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-always-on;
+ };
+
+ vccio_sd: REG5 {
+ regulator-name = "vccio_sd";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vdd10_lcd: REG6 {
+ regulator-name = "vdd10_lcd";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ vcca_codec: REG7 {
+ regulator-name = "vcca_codec";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ vcc_tp: REG8 {
+ regulator-name = "vcca_33";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ vccio_pmu: REG9 {
+ regulator-name = "vccio_pmu";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ vdd_10: REG10 {
+ regulator-name = "vdd_10";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ vcc_18: REG11 {
+ regulator-name = "vcc_18";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ vcc18_lcd: REG12 {
+ regulator-name = "vcc18_lcd";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+ };
+ };
+};
+
+&i2c1 {
+ status = "okay";
+};
+
+&i2c2 {
+ status = "okay";
+};
+
+&i2c4 {
+ status = "okay";
+};
+
+&i2c5 {
+ status = "okay";
+};
+
+&pinctrl {
+ pcfg_output_high: pcfg-output-high {
+ output-high;
+ };
+
+ pcfg_output_low: pcfg-output-low {
+ output-low;
+ };
+
+ act8846 {
+ pwr_hold: pwr-hold {
+ rockchip,pins = <0 9 RK_FUNC_GPIO &pcfg_output_high>;
+ };
+ };
+
+ hym8563 {
+ rtc_int: rtc-int {
+ rockchip,pins = <0 4 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+
+ keys {
+ pwr_key: pwr-key {
+ rockchip,pins = <0 5 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+
+ sdmmc {
+ sdmmc_pwr: sdmmc-pwr {
+ rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ usb_host {
+ host_vbus_drv: host-vbus-drv {
+ rockchip,pins = <0 14 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ usb_otg {
+ otg_vbus_drv: otg-vbus-drv {
+ rockchip,pins = <0 12 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+};
+
+&saradc {
+ vref-supply = <&vcc_18>;
+ status = "okay";
+};
+
+&sdio0 {
+ broken-cd;
+ bus-width = <4>;
+ disable-wp;
+ non-removable;
+ num-slots = <1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdio0_bus4>, <&sdio0_cmd>, <&sdio0_clk>;
+ vmmc-supply = <&vcc_18>;
+ status = "disabled";
+};
+
+&sdmmc {
+ bus-width = <4>;
+ cap-mmc-highspeed;
+ cap-sd-highspeed;
+ card-detect-delay = <200>;
+ disable-wp;
+ num-slots = <1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc_clk>, <&sdmmc_cmd>, <&sdmmc_cd>, <&sdmmc_bus4>;
+ vmmc-supply = <&vccio_sd>;
+ status = "okay";
+};
+
+&spi0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi0_clk>, <&spi0_cs0>, <&spi0_tx>, <&spi0_rx>, <&spi0_cs1>;
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_xfer>, <&uart0_cts>, <&uart0_rts>;
+ status = "okay";
+};
+
+&uart1 {
+ status = "okay";
+};
+
+&uart2 {
+ status = "okay";
+};
+
+&uart3 {
+ status = "okay";
+};
+
+&usb_host1 {
+ status = "okay";
+};
+
+&usb_otg {
+ status = "okay";
+};
+
+&vopb {
+ status = "okay";
+};
+
+&vopb_mmu {
+ status = "okay";
+};
+
+&vopl {
+ status = "okay";
+};
+
+&vopl_mmu {
+ status = "okay";
+};
+
+&wdt {
+ status = "okay";
+};
diff --git a/arch/arm/dts/rk3288.dtsi b/arch/arm/dts/rk3288.dtsi
index 3dab0fc..bcf051a 100644
--- a/arch/arm/dts/rk3288.dtsi
+++ b/arch/arm/dts/rk3288.dtsi
@@ -454,6 +454,7 @@
interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru HCLK_OTG0>;
clock-names = "otg";
+ dr_mode = "otg";
phys = <&usbphy0>;
phy-names = "usb2-phy";
status = "disabled";
diff --git a/arch/arm/dts/rk3399-evb.dts b/arch/arm/dts/rk3399-evb.dts
new file mode 100644
index 0000000..bbcfcd0
--- /dev/null
+++ b/arch/arm/dts/rk3399-evb.dts
@@ -0,0 +1,104 @@
+/*
+ * (C) Copyright 2016 Rockchip Electronics Co., Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/dts-v1/;
+#include <dt-bindings/pwm/pwm.h>
+#include "rk3399.dtsi"
+
+/ {
+ model = "Rockchip RK3399 Evaluation Board";
+ compatible = "rockchip,rk3399-evb", "rockchip,rk3399",
+ "google,rk3399evb-rev2";
+
+ chosen {
+ stdout-path = &uart2;
+ };
+
+ vdd_center: vdd-center {
+ compatible = "pwm-regulator";
+ pwms = <&pwm3 0 25000 0>;
+ regulator-name = "vdd_center";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-always-on;
+ regulator-boot-on;
+ status = "okay";
+ };
+
+ vcc3v3_sys: vcc3v3-sys {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3_sys";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ vcc_phy: vcc-phy-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc_phy";
+ regulator-always-on;
+ regulator-boot-on;
+ };
+};
+
+&emmc_phy {
+ status = "okay";
+};
+
+&pwm0 {
+ status = "okay";
+};
+
+&pwm2 {
+ status = "okay";
+};
+
+&pwm3 {
+ status = "okay";
+};
+
+&sdhci {
+ bus-width = <8>;
+ mmc-hs400-1_8v;
+ mmc-hs400-enhanced-strobe;
+ non-removable;
+ status = "okay";
+};
+
+&uart2 {
+ status = "okay";
+};
+
+&usb_host0_ehci {
+ status = "okay";
+};
+
+&usb_host0_ohci {
+ status = "okay";
+};
+
+&usb_host1_ehci {
+ status = "okay";
+};
+
+&usb_host1_ohci {
+ status = "okay";
+};
+
+&pinctrl {
+ pmic {
+ pmic_int_l: pmic-int-l {
+ rockchip,pins =
+ <1 21 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+
+ pmic_dvs2: pmic-dvs2 {
+ rockchip,pins =
+ <1 18 RK_FUNC_GPIO &pcfg_pull_down>;
+ };
+ };
+};
diff --git a/arch/arm/dts/rk3399.dtsi b/arch/arm/dts/rk3399.dtsi
new file mode 100644
index 0000000..fb5af54
--- /dev/null
+++ b/arch/arm/dts/rk3399.dtsi
@@ -0,0 +1,1028 @@
+/*
+ * (C) Copyright 2016 Rockchip Electronics Co., Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <dt-bindings/clock/rk3399-cru.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+
+/ {
+ compatible = "rockchip,rk3399";
+
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ aliases {
+ serial0 = &uart0;
+ serial1 = &uart1;
+ serial2 = &uart2;
+ serial3 = &uart3;
+ serial4 = &uart4;
+ };
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&cpu_l0>;
+ };
+ core1 {
+ cpu = <&cpu_l1>;
+ };
+ core2 {
+ cpu = <&cpu_l2>;
+ };
+ core3 {
+ cpu = <&cpu_l3>;
+ };
+ };
+
+ cluster1 {
+ core0 {
+ cpu = <&cpu_b0>;
+ };
+ core1 {
+ cpu = <&cpu_b1>;
+ };
+ };
+ };
+
+ cpu_l0: cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53", "arm,armv8";
+ reg = <0x0 0x0>;
+ enable-method = "psci";
+ #cooling-cells = <2>; /* min followed by max */
+ clocks = <&cru ARMCLKL>;
+ };
+
+ cpu_l1: cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53", "arm,armv8";
+ reg = <0x0 0x1>;
+ enable-method = "psci";
+ clocks = <&cru ARMCLKL>;
+ };
+
+ cpu_l2: cpu@2 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53", "arm,armv8";
+ reg = <0x0 0x2>;
+ enable-method = "psci";
+ clocks = <&cru ARMCLKL>;
+ };
+
+ cpu_l3: cpu@3 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53", "arm,armv8";
+ reg = <0x0 0x3>;
+ enable-method = "psci";
+ clocks = <&cru ARMCLKL>;
+ };
+
+ cpu_b0: cpu@100 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x0 0x100>;
+ enable-method = "psci";
+ #cooling-cells = <2>; /* min followed by max */
+ clocks = <&cru ARMCLKB>;
+ };
+
+ cpu_b1: cpu@101 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x0 0x101>;
+ enable-method = "psci";
+ clocks = <&cru ARMCLKB>;
+ };
+ };
+
+ psci {
+ compatible = "arm,psci-1.0";
+ method = "smc";
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+ };
+
+ xin24m: xin24m {
+ compatible = "fixed-clock";
+ clock-frequency = <24000000>;
+ clock-output-names = "xin24m";
+ #clock-cells = <0>;
+ };
+
+ amba {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ dmac_bus: dma-controller@ff6d0000 {
+ compatible = "arm,pl330", "arm,primecell";
+ reg = <0x0 0xff6d0000 0x0 0x4000>;
+ interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+ #dma-cells = <1>;
+ clocks = <&cru ACLK_DMAC0_PERILP>;
+ clock-names = "apb_pclk";
+ };
+
+ dmac_peri: dma-controller@ff6e0000 {
+ compatible = "arm,pl330", "arm,primecell";
+ reg = <0x0 0xff6e0000 0x0 0x4000>;
+ interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+ #dma-cells = <1>;
+ clocks = <&cru ACLK_DMAC1_PERILP>;
+ clock-names = "apb_pclk";
+ };
+ };
+
+ sdio0: dwmmc@fe310000 {
+ compatible = "rockchip,rk3399-dw-mshc",
+ "rockchip,rk3288-dw-mshc";
+ reg = <0x0 0xfe310000 0x0 0x4000>;
+ interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
+ clock-freq-min-max = <400000 150000000>;
+ clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>,
+ <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>;
+ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
+ fifo-depth = <0x100>;
+ status = "disabled";
+ };
+
+ sdmmc: dwmmc@fe320000 {
+ compatible = "rockchip,rk3399-dw-mshc",
+ "rockchip,rk3288-dw-mshc";
+ reg = <0x0 0xfe320000 0x0 0x4000>;
+ interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
+ clock-freq-min-max = <400000 150000000>;
+ clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>,
+ <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>;
+ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
+ fifo-depth = <0x100>;
+ status = "disabled";
+ };
+
+ sdhci: sdhci@fe330000 {
+ compatible = "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1";
+ reg = <0x0 0xfe330000 0x0 0x10000>;
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ assigned-clocks = <&cru SCLK_EMMC>;
+ assigned-clock-rates = <200000000>;
+ clocks = <&cru SCLK_EMMC>, <&cru ACLK_EMMC>;
+ clock-names = "clk_xin", "clk_ahb";
+ phys = <&emmc_phy>;
+ phy-names = "phy_arasan";
+ status = "disabled";
+ };
+
+ usb_host0_ehci: usb@fe380000 {
+ compatible = "generic-ehci";
+ reg = <0x0 0xfe380000 0x0 0x20000>;
+ interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru HCLK_HOST0>, <&cru HCLK_HOST0_ARB>;
+ clock-names = "hclk_host0", "hclk_host0_arb";
+ status = "disabled";
+ };
+
+ usb_host0_ohci: usb@fe3a0000 {
+ compatible = "generic-ohci";
+ reg = <0x0 0xfe3a0000 0x0 0x20000>;
+ interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru HCLK_HOST0>, <&cru HCLK_HOST0_ARB>;
+ clock-names = "hclk_host0", "hclk_host0_arb";
+ status = "disabled";
+ };
+
+ usb_host1_ehci: usb@fe3c0000 {
+ compatible = "generic-ehci";
+ reg = <0x0 0xfe3c0000 0x0 0x20000>;
+ interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru HCLK_HOST1>, <&cru HCLK_HOST1_ARB>;
+ clock-names = "hclk_host1", "hclk_host1_arb";
+ status = "disabled";
+ };
+
+ usb_host1_ohci: usb@fe3e0000 {
+ compatible = "generic-ohci";
+ reg = <0x0 0xfe3e0000 0x0 0x20000>;
+ interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru HCLK_HOST1>, <&cru HCLK_HOST1_ARB>;
+ clock-names = "hclk_host1", "hclk_host1_arb";
+ status = "disabled";
+ };
+
+ gic: interrupt-controller@fee00000 {
+ compatible = "arm,gic-v3";
+ #interrupt-cells = <3>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ interrupt-controller;
+
+ reg = <0x0 0xfee00000 0 0x10000>, /* GICD */
+ <0x0 0xfef00000 0 0xc0000>, /* GICR */
+ <0x0 0xfff00000 0 0x10000>, /* GICC */
+ <0x0 0xfff10000 0 0x10000>, /* GICH */
+ <0x0 0xfff20000 0 0x10000>; /* GICV */
+ interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ its: interrupt-controller@fee20000 {
+ compatible = "arm,gic-v3-its";
+ msi-controller;
+ reg = <0x0 0xfee20000 0x0 0x20000>;
+ };
+ };
+
+ uart0: serial@ff180000 {
+ compatible = "rockchip,rk3399-uart", "snps,dw-apb-uart";
+ reg = <0x0 0xff180000 0x0 0x100>;
+ clocks = <&cru SCLK_UART0>, <&cru PCLK_UART0>;
+ clock-names = "baudclk", "apb_pclk";
+ interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_xfer>;
+ status = "disabled";
+ };
+
+ uart1: serial@ff190000 {
+ compatible = "rockchip,rk3399-uart", "snps,dw-apb-uart";
+ reg = <0x0 0xff190000 0x0 0x100>;
+ clocks = <&cru SCLK_UART1>, <&cru PCLK_UART1>;
+ clock-names = "baudclk", "apb_pclk";
+ interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_xfer>;
+ status = "disabled";
+ };
+
+ uart2: serial@ff1a0000 {
+ compatible = "rockchip,rk3399-uart", "snps,dw-apb-uart";
+ reg = <0x0 0xff1a0000 0x0 0x100>;
+ clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>;
+ clock-names = "baudclk", "apb_pclk";
+ interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
+ clock-frequency = <24000000>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2c_xfer>;
+ status = "disabled";
+ };
+
+ uart3: serial@ff1b0000 {
+ compatible = "rockchip,rk3399-uart", "snps,dw-apb-uart";
+ reg = <0x0 0xff1b0000 0x0 0x100>;
+ clocks = <&cru SCLK_UART3>, <&cru PCLK_UART3>;
+ clock-names = "baudclk", "apb_pclk";
+ interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_xfer>;
+ status = "disabled";
+ };
+
+ spi0: spi@ff1c0000 {
+ compatible = "rockchip,rk3399-spi", "rockchip,rk3066-spi";
+ reg = <0x0 0xff1c0000 0x0 0x1000>;
+ clocks = <&cru SCLK_SPI0>, <&cru PCLK_SPI0>;
+ clock-names = "spiclk", "apb_pclk";
+ interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi0_clk &spi0_tx &spi0_rx &spi0_cs0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi1: spi@ff1d0000 {
+ compatible = "rockchip,rk3399-spi", "rockchip,rk3066-spi";
+ reg = <0x0 0xff1d0000 0x0 0x1000>;
+ clocks = <&cru SCLK_SPI1>, <&cru PCLK_SPI1>;
+ clock-names = "spiclk", "apb_pclk";
+ interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi1_clk &spi1_tx &spi1_rx &spi1_cs0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi2: spi@ff1e0000 {
+ compatible = "rockchip,rk3399-spi", "rockchip,rk3066-spi";
+ reg = <0x0 0xff1e0000 0x0 0x1000>;
+ clocks = <&cru SCLK_SPI2>, <&cru PCLK_SPI2>;
+ clock-names = "spiclk", "apb_pclk";
+ interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi2_clk &spi2_tx &spi2_rx &spi2_cs0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi4: spi@ff1f0000 {
+ compatible = "rockchip,rk3399-spi", "rockchip,rk3066-spi";
+ reg = <0x0 0xff1f0000 0x0 0x1000>;
+ clocks = <&cru SCLK_SPI4>, <&cru PCLK_SPI4>;
+ clock-names = "spiclk", "apb_pclk";
+ interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi4_clk &spi4_tx &spi4_rx &spi4_cs0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi5: spi@ff200000 {
+ compatible = "rockchip,rk3399-spi", "rockchip,rk3066-spi";
+ reg = <0x0 0xff200000 0x0 0x1000>;
+ clocks = <&cru SCLK_SPI5>, <&cru PCLK_SPI5>;
+ clock-names = "spiclk", "apb_pclk";
+ interrupts = <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi5_clk &spi5_tx &spi5_rx &spi5_cs0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ pmugrf: syscon@ff320000 {
+ compatible = "rockchip,rk3399-pmugrf", "syscon", "simple-mfd";
+ reg = <0x0 0xff320000 0x0 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ pmu_io_domains: io-domains {
+ compatible = "rockchip,rk3399-pmu-io-voltage-domain";
+ status = "disabled";
+ };
+ };
+
+ spi3: spi@ff350000 {
+ compatible = "rockchip,rk3399-spi", "rockchip,rk3066-spi";
+ reg = <0x0 0xff350000 0x0 0x1000>;
+ clocks = <&pmucru SCLK_SPI3_PMU>, <&pmucru PCLK_SPI3_PMU>;
+ clock-names = "spiclk", "apb_pclk";
+ interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi3_clk &spi3_tx &spi3_rx &spi3_cs0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ uart4: serial@ff370000 {
+ compatible = "rockchip,rk3399-uart", "snps,dw-apb-uart";
+ reg = <0x0 0xff370000 0x0 0x100>;
+ clocks = <&pmucru SCLK_UART4_PMU>, <&pmucru PCLK_UART4_PMU>;
+ clock-names = "baudclk", "apb_pclk";
+ interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart4_xfer>;
+ status = "disabled";
+ };
+
+ pwm0: pwm@ff420000 {
+ compatible = "rockchip,rk3399-pwm", "rockchip,rk3288-pwm";
+ reg = <0x0 0xff420000 0x0 0x10>;
+ #pwm-cells = <3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm0_pin>;
+ clocks = <&pmucru PCLK_RKPWM_PMU>;
+ clock-names = "pwm";
+ status = "disabled";
+ };
+
+ pwm1: pwm@ff420010 {
+ compatible = "rockchip,rk3399-pwm", "rockchip,rk3288-pwm";
+ reg = <0x0 0xff420010 0x0 0x10>;
+ #pwm-cells = <3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm1_pin>;
+ clocks = <&pmucru PCLK_RKPWM_PMU>;
+ clock-names = "pwm";
+ status = "disabled";
+ };
+
+ pwm2: pwm@ff420020 {
+ compatible = "rockchip,rk3399-pwm", "rockchip,rk3288-pwm";
+ reg = <0x0 0xff420020 0x0 0x10>;
+ #pwm-cells = <3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm2_pin>;
+ clocks = <&pmucru PCLK_RKPWM_PMU>;
+ clock-names = "pwm";
+ status = "disabled";
+ };
+
+ pwm3: pwm@ff420030 {
+ compatible = "rockchip,rk3399-pwm", "rockchip,rk3288-pwm";
+ reg = <0x0 0xff420030 0x0 0x10>;
+ #pwm-cells = <3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm3a_pin>;
+ clocks = <&pmucru PCLK_RKPWM_PMU>;
+ clock-names = "pwm";
+ status = "disabled";
+ };
+
+ pmucru: pmu-clock-controller@ff750000 {
+ compatible = "rockchip,rk3399-pmucru";
+ reg = <0x0 0xff750000 0x0 0x1000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ assigned-clocks = <&pmucru PLL_PPLL>;
+ assigned-clock-rates = <676000000>;
+ };
+
+ cru: clock-controller@ff760000 {
+ compatible = "rockchip,rk3399-cru";
+ reg = <0x0 0xff760000 0x0 0x1000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ assigned-clocks =
+ <&cru PLL_GPLL>, <&cru PLL_CPLL>,
+ <&cru PLL_NPLL>,
+ <&cru ACLK_PERIHP>, <&cru HCLK_PERIHP>,
+ <&cru PCLK_PERIHP>,
+ <&cru ACLK_PERILP0>, <&cru HCLK_PERILP0>,
+ <&cru PCLK_PERILP0>,
+ <&cru HCLK_PERILP1>, <&cru PCLK_PERILP1>;
+ assigned-clock-rates =
+ <594000000>, <800000000>,
+ <1000000000>,
+ <150000000>, <75000000>,
+ <37500000>,
+ <100000000>, <100000000>,
+ <50000000>,
+ <100000000>, <50000000>;
+ };
+
+ grf: syscon@ff770000 {
+ compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd";
+ reg = <0x0 0xff770000 0x0 0x10000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ io_domains: io-domains {
+ compatible = "rockchip,rk3399-io-voltage-domain";
+ status = "disabled";
+ };
+
+ emmc_phy: phy@f780 {
+ compatible = "rockchip,rk3399-emmc-phy";
+ reg = <0xf780 0x24>;
+ #phy-cells = <0>;
+ status = "disabled";
+ };
+ };
+
+ watchdog@ff840000 {
+ compatible = "snps,dw-wdt";
+ reg = <0x0 0xff840000 0x0 0x100>;
+ clocks = <&cru PCLK_WDT>;
+ interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ spdif: spdif@ff870000 {
+ compatible = "rockchip,rk3399-spdif";
+ reg = <0x0 0xff870000 0x0 0x1000>;
+ interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&dmac_bus 7>;
+ dma-names = "tx";
+ clock-names = "mclk", "hclk";
+ clocks = <&cru SCLK_SPDIF_8CH>, <&cru HCLK_SPDIF>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&spdif_bus>;
+ status = "disabled";
+ };
+
+ i2s0: i2s@ff880000 {
+ compatible = "rockchip,rk3399-i2s", "rockchip,rk3066-i2s";
+ reg = <0x0 0xff880000 0x0 0x1000>;
+ rockchip,grf = <&grf>;
+ interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&dmac_bus 0>, <&dmac_bus 1>;
+ dma-names = "tx", "rx";
+ clock-names = "i2s_clk", "i2s_hclk";
+ clocks = <&cru SCLK_I2S0_8CH>, <&cru HCLK_I2S0_8CH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2s0_8ch_bus>;
+ status = "disabled";
+ };
+
+ i2s1: i2s@ff890000 {
+ compatible = "rockchip,rk3399-i2s", "rockchip,rk3066-i2s";
+ reg = <0x0 0xff890000 0x0 0x1000>;
+ interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&dmac_bus 2>, <&dmac_bus 3>;
+ dma-names = "tx", "rx";
+ clock-names = "i2s_clk", "i2s_hclk";
+ clocks = <&cru SCLK_I2S1_8CH>, <&cru HCLK_I2S1_8CH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2s1_2ch_bus>;
+ status = "disabled";
+ };
+
+ i2s2: i2s@ff8a0000 {
+ compatible = "rockchip,rk3399-i2s", "rockchip,rk3066-i2s";
+ reg = <0x0 0xff8a0000 0x0 0x1000>;
+ interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&dmac_bus 4>, <&dmac_bus 5>;
+ dma-names = "tx", "rx";
+ clock-names = "i2s_clk", "i2s_hclk";
+ clocks = <&cru SCLK_I2S2_8CH>, <&cru HCLK_I2S2_8CH>;
+ status = "disabled";
+ };
+
+ pinctrl: pinctrl {
+ compatible = "rockchip,rk3399-pinctrl";
+ rockchip,grf = <&grf>;
+ rockchip,pmu = <&pmugrf>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ gpio0: gpio0@ff720000 {
+ compatible = "rockchip,gpio-bank";
+ reg = <0x0 0xff720000 0x0 0x100>;
+ clocks = <&pmucru PCLK_GPIO0_PMU>;
+ interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+
+ gpio-controller;
+ #gpio-cells = <0x2>;
+
+ interrupt-controller;
+ #interrupt-cells = <0x2>;
+ };
+
+ gpio1: gpio1@ff730000 {
+ compatible = "rockchip,gpio-bank";
+ reg = <0x0 0xff730000 0x0 0x100>;
+ clocks = <&pmucru PCLK_GPIO1_PMU>;
+ interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+
+ gpio-controller;
+ #gpio-cells = <0x2>;
+
+ interrupt-controller;
+ #interrupt-cells = <0x2>;
+ };
+
+ gpio2: gpio2@ff780000 {
+ compatible = "rockchip,gpio-bank";
+ reg = <0x0 0xff780000 0x0 0x100>;
+ clocks = <&cru PCLK_GPIO2>;
+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+
+ gpio-controller;
+ #gpio-cells = <0x2>;
+
+ interrupt-controller;
+ #interrupt-cells = <0x2>;
+ };
+
+ gpio3: gpio3@ff788000 {
+ compatible = "rockchip,gpio-bank";
+ reg = <0x0 0xff788000 0x0 0x100>;
+ clocks = <&cru PCLK_GPIO3>;
+ interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+
+ gpio-controller;
+ #gpio-cells = <0x2>;
+
+ interrupt-controller;
+ #interrupt-cells = <0x2>;
+ };
+
+ gpio4: gpio4@ff790000 {
+ compatible = "rockchip,gpio-bank";
+ reg = <0x0 0xff790000 0x0 0x100>;
+ clocks = <&cru PCLK_GPIO4>;
+ interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
+
+ gpio-controller;
+ #gpio-cells = <0x2>;
+
+ interrupt-controller;
+ #interrupt-cells = <0x2>;
+ };
+
+ pcfg_pull_up: pcfg-pull-up {
+ bias-pull-up;
+ };
+
+ pcfg_pull_down: pcfg-pull-down {
+ bias-pull-down;
+ };
+
+ pcfg_pull_none: pcfg-pull-none {
+ bias-disable;
+ };
+
+ pcfg_pull_none_12ma: pcfg-pull-none-12ma {
+ bias-disable;
+ drive-strength = <12>;
+ };
+
+ pcfg_pull_up_8ma: pcfg-pull-up-8ma {
+ bias-pull-up;
+ drive-strength = <8>;
+ };
+
+ pcfg_pull_down_4ma: pcfg-pull-down-4ma {
+ bias-pull-down;
+ drive-strength = <4>;
+ };
+
+ pcfg_pull_up_2ma: pcfg-pull-up-2ma {
+ bias-pull-up;
+ drive-strength = <2>;
+ };
+
+ pcfg_pull_down_12ma: pcfg-pull-down-12ma {
+ bias-pull-down;
+ drive-strength = <12>;
+ };
+
+ pcfg_pull_none_13ma: pcfg-pull-none-13ma {
+ bias-disable;
+ drive-strength = <13>;
+ };
+
+ i2c0 {
+ i2c0_xfer: i2c0-xfer {
+ rockchip,pins =
+ <1 15 RK_FUNC_2 &pcfg_pull_none>,
+ <1 16 RK_FUNC_2 &pcfg_pull_none>;
+ };
+ };
+
+ i2c1 {
+ i2c1_xfer: i2c1-xfer {
+ rockchip,pins =
+ <4 2 RK_FUNC_1 &pcfg_pull_none>,
+ <4 1 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+
+ i2c2 {
+ i2c2_xfer: i2c2-xfer {
+ rockchip,pins =
+ <2 1 RK_FUNC_2 &pcfg_pull_none_12ma>,
+ <2 0 RK_FUNC_2 &pcfg_pull_none_12ma>;
+ };
+ };
+
+ i2c3 {
+ i2c3_xfer: i2c3-xfer {
+ rockchip,pins =
+ <4 17 RK_FUNC_1 &pcfg_pull_none>,
+ <4 16 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+
+ i2c4 {
+ i2c4_xfer: i2c4-xfer {
+ rockchip,pins =
+ <1 12 RK_FUNC_1 &pcfg_pull_none>,
+ <1 11 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+
+ i2c5 {
+ i2c5_xfer: i2c5-xfer {
+ rockchip,pins =
+ <3 11 RK_FUNC_2 &pcfg_pull_none>,
+ <3 10 RK_FUNC_2 &pcfg_pull_none>;
+ };
+ };
+
+ i2c6 {
+ i2c6_xfer: i2c6-xfer {
+ rockchip,pins =
+ <2 10 RK_FUNC_2 &pcfg_pull_none>,
+ <2 9 RK_FUNC_2 &pcfg_pull_none>;
+ };
+ };
+
+ i2c7 {
+ i2c7_xfer: i2c7-xfer {
+ rockchip,pins =
+ <2 8 RK_FUNC_2 &pcfg_pull_none>,
+ <2 7 RK_FUNC_2 &pcfg_pull_none>;
+ };
+ };
+
+ i2c8 {
+ i2c8_xfer: i2c8-xfer {
+ rockchip,pins =
+ <1 21 RK_FUNC_1 &pcfg_pull_none>,
+ <1 20 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+
+ i2s0 {
+ i2s0_8ch_bus: i2s0-8ch-bus {
+ rockchip,pins =
+ <3 24 RK_FUNC_1 &pcfg_pull_none>,
+ <3 25 RK_FUNC_1 &pcfg_pull_none>,
+ <3 26 RK_FUNC_1 &pcfg_pull_none>,
+ <3 27 RK_FUNC_1 &pcfg_pull_none>,
+ <3 28 RK_FUNC_1 &pcfg_pull_none>,
+ <3 29 RK_FUNC_1 &pcfg_pull_none>,
+ <3 30 RK_FUNC_1 &pcfg_pull_none>,
+ <3 31 RK_FUNC_1 &pcfg_pull_none>,
+ <4 0 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+
+ i2s1 {
+ i2s1_2ch_bus: i2s1-2ch-bus {
+ rockchip,pins =
+ <4 3 RK_FUNC_1 &pcfg_pull_none>,
+ <4 4 RK_FUNC_1 &pcfg_pull_none>,
+ <4 5 RK_FUNC_1 &pcfg_pull_none>,
+ <4 6 RK_FUNC_1 &pcfg_pull_none>,
+ <4 7 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+
+ spdif {
+ spdif_bus: spdif-bus {
+ rockchip,pins =
+ <4 21 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+
+ spi0 {
+ spi0_clk: spi0-clk {
+ rockchip,pins =
+ <3 6 RK_FUNC_2 &pcfg_pull_up>;
+ };
+ spi0_cs0: spi0-cs0 {
+ rockchip,pins =
+ <3 7 RK_FUNC_2 &pcfg_pull_up>;
+ };
+ spi0_cs1: spi0-cs1 {
+ rockchip,pins =
+ <3 8 RK_FUNC_2 &pcfg_pull_up>;
+ };
+ spi0_tx: spi0-tx {
+ rockchip,pins =
+ <3 5 RK_FUNC_2 &pcfg_pull_up>;
+ };
+ spi0_rx: spi0-rx {
+ rockchip,pins =
+ <3 4 RK_FUNC_2 &pcfg_pull_up>;
+ };
+ };
+
+ spi1 {
+ spi1_clk: spi1-clk {
+ rockchip,pins =
+ <1 9 RK_FUNC_2 &pcfg_pull_up>;
+ };
+ spi1_cs0: spi1-cs0 {
+ rockchip,pins =
+ <1 10 RK_FUNC_2 &pcfg_pull_up>;
+ };
+ spi1_rx: spi1-rx {
+ rockchip,pins =
+ <1 7 RK_FUNC_2 &pcfg_pull_up>;
+ };
+ spi1_tx: spi1-tx {
+ rockchip,pins =
+ <1 8 RK_FUNC_2 &pcfg_pull_up>;
+ };
+ };
+
+ spi2 {
+ spi2_clk: spi2-clk {
+ rockchip,pins =
+ <2 11 RK_FUNC_1 &pcfg_pull_up>;
+ };
+ spi2_cs0: spi2-cs0 {
+ rockchip,pins =
+ <2 12 RK_FUNC_1 &pcfg_pull_up>;
+ };
+ spi2_rx: spi2-rx {
+ rockchip,pins =
+ <2 9 RK_FUNC_1 &pcfg_pull_up>;
+ };
+ spi2_tx: spi2-tx {
+ rockchip,pins =
+ <2 10 RK_FUNC_1 &pcfg_pull_up>;
+ };
+ };
+
+ spi3 {
+ spi3_clk: spi3-clk {
+ rockchip,pins =
+ <1 17 RK_FUNC_1 &pcfg_pull_up>;
+ };
+ spi3_cs0: spi3-cs0 {
+ rockchip,pins =
+ <1 18 RK_FUNC_1 &pcfg_pull_up>;
+ };
+ spi3_rx: spi3-rx {
+ rockchip,pins =
+ <1 15 RK_FUNC_1 &pcfg_pull_up>;
+ };
+ spi3_tx: spi3-tx {
+ rockchip,pins =
+ <1 16 RK_FUNC_1 &pcfg_pull_up>;
+ };
+ };
+
+ spi4 {
+ spi4_clk: spi4-clk {
+ rockchip,pins =
+ <3 2 RK_FUNC_2 &pcfg_pull_up>;
+ };
+ spi4_cs0: spi4-cs0 {
+ rockchip,pins =
+ <3 3 RK_FUNC_2 &pcfg_pull_up>;
+ };
+ spi4_rx: spi4-rx {
+ rockchip,pins =
+ <3 0 RK_FUNC_2 &pcfg_pull_up>;
+ };
+ spi4_tx: spi4-tx {
+ rockchip,pins =
+ <3 1 RK_FUNC_2 &pcfg_pull_up>;
+ };
+ };
+
+ spi5 {
+ spi5_clk: spi5-clk {
+ rockchip,pins =
+ <2 22 RK_FUNC_2 &pcfg_pull_up>;
+ };
+ spi5_cs0: spi5-cs0 {
+ rockchip,pins =
+ <2 23 RK_FUNC_2 &pcfg_pull_up>;
+ };
+ spi5_rx: spi5-rx {
+ rockchip,pins =
+ <2 20 RK_FUNC_2 &pcfg_pull_up>;
+ };
+ spi5_tx: spi5-tx {
+ rockchip,pins =
+ <2 21 RK_FUNC_2 &pcfg_pull_up>;
+ };
+ };
+
+ uart0 {
+ uart0_xfer: uart0-xfer {
+ rockchip,pins =
+ <2 16 RK_FUNC_1 &pcfg_pull_up>,
+ <2 17 RK_FUNC_1 &pcfg_pull_none>;
+ };
+
+ uart0_cts: uart0-cts {
+ rockchip,pins =
+ <2 18 RK_FUNC_1 &pcfg_pull_none>;
+ };
+
+ uart0_rts: uart0-rts {
+ rockchip,pins =
+ <2 19 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+
+ uart1 {
+ uart1_xfer: uart1-xfer {
+ rockchip,pins =
+ <3 12 RK_FUNC_2 &pcfg_pull_up>,
+ <3 13 RK_FUNC_2 &pcfg_pull_none>;
+ };
+ };
+
+ uart2a {
+ uart2a_xfer: uart2a-xfer {
+ rockchip,pins =
+ <4 8 RK_FUNC_2 &pcfg_pull_up>,
+ <4 9 RK_FUNC_2 &pcfg_pull_none>;
+ };
+ };
+
+ uart2b {
+ uart2b_xfer: uart2b-xfer {
+ rockchip,pins =
+ <4 16 RK_FUNC_2 &pcfg_pull_up>,
+ <4 17 RK_FUNC_2 &pcfg_pull_none>;
+ };
+ };
+
+ uart2c {
+ uart2c_xfer: uart2c-xfer {
+ rockchip,pins =
+ <4 19 RK_FUNC_1 &pcfg_pull_up>,
+ <4 20 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+
+ uart3 {
+ uart3_xfer: uart3-xfer {
+ rockchip,pins =
+ <3 14 RK_FUNC_2 &pcfg_pull_up>,
+ <3 15 RK_FUNC_2 &pcfg_pull_none>;
+ };
+
+ uart3_cts: uart3-cts {
+ rockchip,pins =
+ <3 18 RK_FUNC_2 &pcfg_pull_none>;
+ };
+
+ uart3_rts: uart3-rts {
+ rockchip,pins =
+ <3 19 RK_FUNC_2 &pcfg_pull_none>;
+ };
+ };
+
+ uart4 {
+ uart4_xfer: uart4-xfer {
+ rockchip,pins =
+ <1 7 RK_FUNC_1 &pcfg_pull_up>,
+ <1 8 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+
+ uarthdcp {
+ uarthdcp_xfer: uarthdcp-xfer {
+ rockchip,pins =
+ <4 21 RK_FUNC_2 &pcfg_pull_up>,
+ <4 22 RK_FUNC_2 &pcfg_pull_none>;
+ };
+ };
+
+ pwm0 {
+ pwm0_pin: pwm0-pin {
+ rockchip,pins =
+ <4 18 RK_FUNC_1 &pcfg_pull_none>;
+ };
+
+ vop0_pwm_pin: vop0-pwm-pin {
+ rockchip,pins =
+ <4 18 RK_FUNC_2 &pcfg_pull_none>;
+ };
+ };
+
+ pwm1 {
+ pwm1_pin: pwm1-pin {
+ rockchip,pins =
+ <4 22 RK_FUNC_1 &pcfg_pull_none>;
+ };
+
+ vop1_pwm_pin: vop1-pwm-pin {
+ rockchip,pins =
+ <4 18 RK_FUNC_3 &pcfg_pull_none>;
+ };
+ };
+
+ pwm2 {
+ pwm2_pin: pwm2-pin {
+ rockchip,pins =
+ <1 19 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+
+ pwm3a {
+ pwm3a_pin: pwm3a-pin {
+ rockchip,pins =
+ <0 6 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+
+ pwm3b {
+ pwm3b_pin: pwm3b-pin {
+ rockchip,pins =
+ <1 14 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+ };
+};
diff --git a/arch/arm/dts/sun5i-a10s.dtsi b/arch/arm/dts/sun5i-a10s.dtsi
index bddd0de..a5f8855 100644
--- a/arch/arm/dts/sun5i-a10s.dtsi
+++ b/arch/arm/dts/sun5i-a10s.dtsi
@@ -241,6 +241,20 @@
allwinner,drive = <SUN4I_PINCTRL_30_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+
+ nand_cs2_pins_a: nand_cs@2 {
+ allwinner,pins = "PC17";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_cs3_pins_a: nand_cs@3 {
+ allwinner,pins = "PC18";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
};
&sram_a {
diff --git a/arch/arm/dts/sun5i-a13-olinuxino.dts b/arch/arm/dts/sun5i-a13-olinuxino.dts
index b3c234c..30e069a 100644
--- a/arch/arm/dts/sun5i-a13-olinuxino.dts
+++ b/arch/arm/dts/sun5i-a13-olinuxino.dts
@@ -155,6 +155,21 @@
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 = <2>;
+ #size-cells = <2>;
+ reg = <0>;
+ allwinner,rb = <0>;
+ nand-ecc-mode = "hw";
+ allwinner,randomize;
+ };
+};
+
&ohci0 {
status = "okay";
};
diff --git a/arch/arm/dts/sun5i-r8-chip.dts b/arch/arm/dts/sun5i-r8-chip.dts
index 6ad19e2..b1b62d5 100644
--- a/arch/arm/dts/sun5i-r8-chip.dts
+++ b/arch/arm/dts/sun5i-r8-chip.dts
@@ -142,6 +142,21 @@
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 = <2>;
+ #size-cells = <2>;
+ reg = <0>;
+ allwinner,rb = <0>;
+ nand-ecc-mode = "hw";
+ nand-on-flash-bbt;
+ };
+};
+
&ohci0 {
status = "okay";
};
diff --git a/arch/arm/dts/sun5i.dtsi b/arch/arm/dts/sun5i.dtsi
index 59a9426..87e5353 100644
--- a/arch/arm/dts/sun5i.dtsi
+++ b/arch/arm/dts/sun5i.dtsi
@@ -356,6 +356,17 @@
#dma-cells = <2>;
};
+ nfc: nand@01c03000 {
+ compatible = "allwinner,sun4i-a10-nand";
+ reg = <0x01c03000 0x1000>;
+ interrupts = <37>;
+ clocks = <&ahb_gates 13>, <&nand_clk>;
+ clock-names = "ahb", "mod";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
spi0: spi@01c05000 {
compatible = "allwinner,sun4i-a10-spi";
reg = <0x01c05000 0x1000>;
@@ -548,6 +559,44 @@
allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
};
+ nand_pins_a: nand_base0@0 {
+ allwinner,pins = "PC0", "PC1", "PC2",
+ "PC5", "PC8", "PC9", "PC10",
+ "PC11", "PC12", "PC13", "PC14",
+ "PC15";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_cs0_pins_a: nand_cs@0 {
+ allwinner,pins = "PC4";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_cs1_pins_a: nand_cs@1 {
+ allwinner,pins = "PC3";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_rb0_pins_a: nand_rb@0 {
+ allwinner,pins = "PC6";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_rb1_pins_a: nand_rb@1 {
+ allwinner,pins = "PC7";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
uart3_pins_a: uart3@0 {
allwinner,pins = "PG9", "PG10";
allwinner,function = "uart3";
diff --git a/arch/arm/include/asm/arch-omap4/i2c.h b/arch/arm/include/asm/arch-omap4/i2c.h
index adc8eb2..463e979 100644
--- a/arch/arm/include/asm/arch-omap4/i2c.h
+++ b/arch/arm/include/asm/arch-omap4/i2c.h
@@ -14,9 +14,9 @@ struct i2c {
unsigned short revnb_lo; /* 0x00 */
unsigned short res1;
unsigned short revnb_hi; /* 0x04 */
- unsigned short res2[13];
- unsigned short sysc; /* 0x20 */
- unsigned short res3;
+ unsigned short res2[5];
+ unsigned short sysc; /* 0x10 */
+ unsigned short res3[9];
unsigned short irqstatus_raw; /* 0x24 */
unsigned short res4;
unsigned short stat; /* 0x28 */
diff --git a/arch/arm/include/asm/arch-omap5/i2c.h b/arch/arm/include/asm/arch-omap5/i2c.h
index d875cfe..2b55edf 100644
--- a/arch/arm/include/asm/arch-omap5/i2c.h
+++ b/arch/arm/include/asm/arch-omap5/i2c.h
@@ -14,9 +14,9 @@ struct i2c {
unsigned short revnb_lo; /* 0x00 */
unsigned short res1;
unsigned short revnb_hi; /* 0x04 */
- unsigned short res2[13];
- unsigned short sysc; /* 0x20 */
- unsigned short res3;
+ unsigned short res2[5];
+ unsigned short sysc; /* 0x10 */
+ unsigned short res3[9];
unsigned short irqstatus_raw; /* 0x24 */
unsigned short res4;
unsigned short stat; /* 0x28 */
diff --git a/arch/arm/include/asm/arch-rockchip/clock.h b/arch/arm/include/asm/arch-rockchip/clock.h
index 317e512..21edbc2 100644
--- a/arch/arm/include/asm/arch-rockchip/clock.h
+++ b/arch/arm/include/asm/arch-rockchip/clock.h
@@ -65,6 +65,8 @@ void *rockchip_get_cru(void);
struct rk3288_cru;
struct rk3288_grf;
-void rkclk_configure_cpu(struct rk3288_cru *cru, struct rk3288_grf *grf);
+void rk3288_clk_configure_cpu(struct rk3288_cru *cru, struct rk3288_grf *grf);
+
+int rockchip_get_clk(struct udevice **devp);
#endif
diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun4i.h b/arch/arm/include/asm/arch-sunxi/clock_sun4i.h
index 0088bb9..d1c5ad0 100644
--- a/arch/arm/include/asm/arch-sunxi/clock_sun4i.h
+++ b/arch/arm/include/asm/arch-sunxi/clock_sun4i.h
@@ -269,6 +269,11 @@ struct sunxi_ccm_reg {
#define CCM_MBUS_CTRL_CLK_SRC_PLL5 0x2
#define CCM_MBUS_CTRL_GATE (0x1 << 31)
+#define CCM_NAND_CTRL_M(x) ((x) - 1)
+#define CCM_NAND_CTRL_N(x) ((x) << 16)
+#define CCM_NAND_CTRL_OSCM24 (0x0 << 24)
+#define CCM_NAND_CTRL_PLL6 (0x1 << 24)
+#define CCM_NAND_CTRL_PLL5 (0x2 << 24)
#define CCM_NAND_CTRL_ENABLE (0x1 << 31)
#define CCM_MMC_CTRL_M(x) ((x) - 1)
diff --git a/arch/arm/mach-keystone/init.c b/arch/arm/mach-keystone/init.c
index 3b6d5ef..6e5a1e1 100644
--- a/arch/arm/mach-keystone/init.c
+++ b/arch/arm/mach-keystone/init.c
@@ -101,9 +101,7 @@ static void msmc_k2hkle_common_setup(void)
msmc_share_all_segments(KS2_MSMC_SEGMENT_C6X_0);
msmc_share_all_segments(K2HKLE_MSMC_SEGMENT_ARM);
msmc_share_all_segments(K2HKLE_MSMC_SEGMENT_NETCP);
-#ifdef KS2_MSMC_SEGMENT_QM_PDSP
msmc_share_all_segments(K2HKLE_MSMC_SEGMENT_QM_PDSP);
-#endif
msmc_share_all_segments(K2HKLE_MSMC_SEGMENT_PCIE0);
msmc_share_all_segments(KS2_MSMC_SEGMENT_DEBUG);
}
diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
index c49cc19..1aac3c8 100644
--- a/arch/arm/mach-rockchip/Kconfig
+++ b/arch/arm/mach-rockchip/Kconfig
@@ -1,7 +1,21 @@
if ARCH_ROCKCHIP
+config ROCKCHIP_RK3036
+ bool "Support Rockchip RK3036"
+ select CPU_V7
+ select SUPPORT_SPL
+ select SPL
+ help
+ The Rockchip RK3036 is a ARM-based SoC with a dual-core Cortex-A7
+ including NEON and GPU, Mali-400 graphics, several DDR3 options
+ and video codec support. Peripherals include Gigabit Ethernet,
+ USB2 host and OTG, SDIO, I2S, UART, SPI, I2C and PWMs.
+
config ROCKCHIP_RK3288
bool "Support Rockchip RK3288"
+ select CPU_V7
+ select SUPPORT_SPL
+ select SPL
help
The Rockchip RK3288 is a ARM-based SoC with a quad-core Cortex-A17
including NEON and GPU, 1MB L2 cache, Mali-T7 graphics, two
@@ -9,14 +23,26 @@ config ROCKCHIP_RK3288
and video codec support. Peripherals include Gigabit Ethernet,
USB2 host and OTG, SDIO, I2S, UART,s, SPI, I2C and PWMs.
-config ROCKCHIP_RK3036
- bool "Support Rockchip RK3036"
+config ROCKCHIP_RK3399
+ bool "Support Rockchip RK3399"
+ select ARM64
help
- The Rockchip RK3036 is a ARM-based SoC with a dual-core Cortex-A7
- including NEON and GPU, Mali-400 graphics, several DDR3 options
+ The Rockchip RK3399 is a ARM-based SoC with a dual-core Cortex-A72
+ and quad-core Cortex-A53.
+ including NEON and GPU, 1MB L2 cache, Mali-T7 graphics, two
+ video interfaces supporting HDMI and eDP, several DDR3 options
and video codec support. Peripherals include Gigabit Ethernet,
- USB2 host and OTG, SDIO, I2S, UART, SPI, I2C and PWMs.
+ USB2 host and OTG, SDIO, I2S, UARTs, SPI, I2C and PWMs.
+
+config ROCKCHIP_SPL_BACK_TO_BROM
+ bool "SPL returns to bootrom"
+ default y if ROCKCHIP_RK3036
+ help
+ Rockchip SoCs have ability to load SPL & U-Boot binary. If enabled,
+ SPL will return to the boot rom, which will then load the U-Boot
+ binary to keep going on.
-source "arch/arm/mach-rockchip/rk3288/Kconfig"
source "arch/arm/mach-rockchip/rk3036/Kconfig"
+source "arch/arm/mach-rockchip/rk3288/Kconfig"
+source "arch/arm/mach-rockchip/rk3399/Kconfig"
endif
diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile
index 55567cb..157d42f 100644
--- a/arch/arm/mach-rockchip/Makefile
+++ b/arch/arm/mach-rockchip/Makefile
@@ -5,11 +5,15 @@
#
ifdef CONFIG_SPL_BUILD
-obj-$(CONFIG_ROCKCHIP_RK3288) += rk3288-board-spl.o
obj-$(CONFIG_ROCKCHIP_RK3036) += rk3036-board-spl.o
+obj-$(CONFIG_ROCKCHIP_RK3288) += rk3288-board-spl.o
+obj-$(CONFIG_ROCKCHIP_SPL_BACK_TO_BROM) += save_boot_param.o
else
obj-$(CONFIG_ROCKCHIP_RK3288) += board.o
endif
+ifndef CONFIG_ARM64
obj-y += rk_timer.o
-obj-$(CONFIG_ROCKCHIP_RK3288) += rk3288/
+endif
obj-$(CONFIG_ROCKCHIP_RK3036) += rk3036/
+obj-$(CONFIG_ROCKCHIP_RK3288) += rk3288/
+obj-$(CONFIG_ROCKCHIP_RK3399) += rk3399/
diff --git a/arch/arm/mach-rockchip/board.c b/arch/arm/mach-rockchip/board.c
index 816540e..bec756d 100644
--- a/arch/arm/mach-rockchip/board.c
+++ b/arch/arm/mach-rockchip/board.c
@@ -10,12 +10,45 @@
#include <ram.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
+#include <asm/arch/periph.h>
+#include <asm/gpio.h>
+#include <dm/pinctrl.h>
DECLARE_GLOBAL_DATA_PTR;
int board_init(void)
{
+#ifdef CONFIG_ROCKCHIP_SPL_BACK_TO_BROM
+ struct udevice *pinctrl;
+ int ret;
+
+ /*
+ * We need to implement sdcard iomux here for the further
+ * initlization, otherwise, it'll hit sdcard command sending
+ * timeout exception.
+ */
+ ret = uclass_get_device(UCLASS_PINCTRL, 0, &pinctrl);
+ if (ret) {
+ debug("%s: Cannot find pinctrl device\n", __func__);
+ goto err;
+ }
+ ret = pinctrl_request_noflags(pinctrl, PERIPH_ID_SDCARD);
+ if (ret) {
+ debug("%s: Failed to set up SD card\n", __func__);
+ goto err;
+ }
+
+ return 0;
+err:
+ printf("board_init: Error %d\n", ret);
+
+ /* No way to report error here */
+ hang();
+
+ return -1;
+#else
return 0;
+#endif
}
int dram_init(void)
@@ -52,6 +85,78 @@ void lowlevel_init(void)
{
}
+#if defined(CONFIG_USB_GADGET) && defined(CONFIG_USB_GADGET_DWC2_OTG)
+#include <usb.h>
+#include <usb/dwc2_udc.h>
+
+static struct dwc2_plat_otg_data rk3288_otg_data = {
+ .rx_fifo_sz = 512,
+ .np_tx_fifo_sz = 16,
+ .tx_fifo_sz = 128,
+};
+
+int board_usb_init(int index, enum usb_init_type init)
+{
+ int node, phy_node;
+ const char *mode;
+ bool matched = false;
+ const void *blob = gd->fdt_blob;
+ u32 grf_phy_offset;
+
+ /* find the usb_otg node */
+ node = fdt_node_offset_by_compatible(blob, -1,
+ "rockchip,rk3288-usb");
+
+ while (node > 0) {
+ mode = fdt_getprop(blob, node, "dr_mode", NULL);
+ if (mode && strcmp(mode, "otg") == 0) {
+ matched = true;
+ break;
+ }
+
+ node = fdt_node_offset_by_compatible(blob, node,
+ "rockchip,rk3288-usb");
+ }
+ if (!matched) {
+ debug("Not found usb_otg device\n");
+ return -ENODEV;
+ }
+ rk3288_otg_data.regs_otg = fdtdec_get_addr(blob, node, "reg");
+
+ node = fdtdec_lookup_phandle(blob, node, "phys");
+ if (node <= 0) {
+ debug("Not found usb phy device\n");
+ return -ENODEV;
+ }
+
+ phy_node = fdt_parent_offset(blob, node);
+ if (phy_node <= 0) {
+ debug("Not found usb phy device\n");
+ return -ENODEV;
+ }
+
+ rk3288_otg_data.phy_of_node = phy_node;
+ grf_phy_offset = fdtdec_get_addr(blob, node, "reg");
+
+ /* find the grf node */
+ node = fdt_node_offset_by_compatible(blob, -1,
+ "rockchip,rk3288-grf");
+ if (node <= 0) {
+ debug("Not found grf device\n");
+ return -ENODEV;
+ }
+ rk3288_otg_data.regs_phy = grf_phy_offset +
+ fdtdec_get_addr(blob, node, "reg");
+
+ return dwc2_udc_probe(&rk3288_otg_data);
+}
+
+int board_usb_cleanup(int index, enum usb_init_type init)
+{
+ return 0;
+}
+#endif
+
static int do_clock(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{
@@ -73,7 +178,7 @@ static int do_clock(cmd_tbl_t *cmdtp, int flag, int argc,
int ret, i;
struct udevice *dev;
- ret = uclass_get_device(UCLASS_CLK, 0, &dev);
+ ret = rockchip_get_clk(&dev);
if (ret) {
printf("clk-uclass not found\n");
return 0;
diff --git a/arch/arm/mach-rockchip/rk3036/Kconfig b/arch/arm/mach-rockchip/rk3036/Kconfig
index cc03808..f7562bd 100644
--- a/arch/arm/mach-rockchip/rk3036/Kconfig
+++ b/arch/arm/mach-rockchip/rk3036/Kconfig
@@ -15,7 +15,7 @@ config SYS_MALLOC_F_LEN
config ROCKCHIP_COMMON
bool "Support rk common fuction"
-source "board/evb_rk3036/evb_rk3036/Kconfig"
-source "board/kylin/kylin_rk3036/Kconfig"
+source "board/rockchip/evb_rk3036/Kconfig"
+source "board/rockchip/kylin_rk3036/Kconfig"
endif
diff --git a/arch/arm/mach-rockchip/rk3036/Makefile b/arch/arm/mach-rockchip/rk3036/Makefile
index 97d299d..6095777 100644
--- a/arch/arm/mach-rockchip/rk3036/Makefile
+++ b/arch/arm/mach-rockchip/rk3036/Makefile
@@ -10,4 +10,3 @@ obj-y += syscon_rk3036.o
endif
obj-y += sdram_rk3036.o
-obj-y += save_boot_param.o
diff --git a/arch/arm/mach-rockchip/rk3288-board-spl.c b/arch/arm/mach-rockchip/rk3288-board-spl.c
index 123f58b..ed14023 100644
--- a/arch/arm/mach-rockchip/rk3288-board-spl.c
+++ b/arch/arm/mach-rockchip/rk3288-board-spl.c
@@ -149,7 +149,7 @@ static int configure_emmc(struct udevice *pinctrl)
return 0;
}
#endif
-
+extern void back_to_bootrom(void);
void board_init_f(ulong dummy)
{
struct udevice *pinctrl;
@@ -187,7 +187,7 @@ void board_init_f(ulong dummy)
rockchip_timer_init();
configure_l2ctlr();
- ret = uclass_get_device(UCLASS_CLK, 0, &dev);
+ ret = rockchip_get_clk(&dev);
if (ret) {
debug("CLK init failed: %d\n", ret);
return;
@@ -204,6 +204,9 @@ void board_init_f(ulong dummy)
debug("DRAM init failed: %d\n", ret);
return;
}
+#ifdef CONFIG_ROCKCHIP_SPL_BACK_TO_BROM
+ back_to_bootrom();
+#endif
}
static int setup_led(void)
@@ -248,7 +251,8 @@ void spl_board_init(void)
}
#ifdef CONFIG_SPL_MMC_SUPPORT
if (!IS_ENABLED(CONFIG_TARGET_ROCK2) &&
- !IS_ENABLED(CONFIG_TARGET_FIREFLY_RK3288)) {
+ !IS_ENABLED(CONFIG_TARGET_FIREFLY_RK3288) &&
+ !IS_ENABLED(CONFIG_TARGET_EVB_RK3288)) {
ret = pinctrl_request_noflags(pinctrl, PERIPH_ID_SDCARD);
if (ret) {
debug("%s: Failed to set up SD card\n", __func__);
diff --git a/arch/arm/mach-rockchip/rk3288/Kconfig b/arch/arm/mach-rockchip/rk3288/Kconfig
index 7215624..031dbfc 100644
--- a/arch/arm/mach-rockchip/rk3288/Kconfig
+++ b/arch/arm/mach-rockchip/rk3288/Kconfig
@@ -8,6 +8,14 @@ config TARGET_FIREFLY_RK3288
also includes on-board eMMC and 1GB of SDRAM. Expansion connectors
provide access to display pins, I2C, SPI, UART and GPIOs.
+config TARGET_EVB_RK3288
+ bool "Evb-RK3288"
+ help
+ EVB-RK3288 is a RK3288-based development board with 2 USB ports,
+ HDMI, VGA, micro-SD card, audio, WiFi and Gigabit Ethernet, It
+ also includes on-board eMMC and 2GB of SDRAM. Expansion connectors
+ provide access to display pins, I2C, SPI, UART and GPIOs.
+
config TARGET_CHROMEBOOK_JERRY
bool "Google/Rockchip Veyron-Jerry Chromebook"
help
@@ -45,4 +53,6 @@ source "board/firefly/firefly-rk3288/Kconfig"
source "board/radxa/rock2/Kconfig"
+source "board/evb-rk3288/evb-rk3288/Kconfig"
+
endif
diff --git a/arch/arm/mach-rockchip/rk3288/Makefile b/arch/arm/mach-rockchip/rk3288/Makefile
index 6f62375..82b00a1 100644
--- a/arch/arm/mach-rockchip/rk3288/Makefile
+++ b/arch/arm/mach-rockchip/rk3288/Makefile
@@ -4,6 +4,7 @@
# SPDX-License-Identifier: GPL-2.0+
#
+obj-y += clk_rk3288.o
obj-y += reset_rk3288.o
obj-y += sdram_rk3288.o
obj-y += syscon_rk3288.o
diff --git a/arch/arm/mach-rockchip/rk3288/clk_rk3288.c b/arch/arm/mach-rockchip/rk3288/clk_rk3288.c
new file mode 100644
index 0000000..2099e34
--- /dev/null
+++ b/arch/arm/mach-rockchip/rk3288/clk_rk3288.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <syscon.h>
+#include <asm/arch/clock.h>
+
+int rockchip_get_clk(struct udevice **devp)
+{
+ return uclass_get_device_by_driver(UCLASS_CLK,
+ DM_GET_DRIVER(rockchip_rk3288_cru), devp);
+}
diff --git a/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c b/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c
index b36b6af..cf9ef2e 100644
--- a/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c
+++ b/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c
@@ -575,14 +575,14 @@ static void dram_all_config(const struct dram_info *dram,
&sdram_params->ch[chan];
sys_reg |= info->row_3_4 << SYS_REG_ROW_3_4_SHIFT(chan);
- sys_reg |= chan << SYS_REG_CHINFO_SHIFT(chan);
+ sys_reg |= 1 << SYS_REG_CHINFO_SHIFT(chan);
sys_reg |= (info->rank - 1) << SYS_REG_RANK_SHIFT(chan);
sys_reg |= (info->col - 9) << SYS_REG_COL_SHIFT(chan);
- sys_reg |= info->bk == 3 ? 1 << SYS_REG_BK_SHIFT(chan) : 0;
+ sys_reg |= info->bk == 3 ? 0 : 1 << SYS_REG_BK_SHIFT(chan);
sys_reg |= (info->cs0_row - 13) << SYS_REG_CS0_ROW_SHIFT(chan);
sys_reg |= (info->cs1_row - 13) << SYS_REG_CS1_ROW_SHIFT(chan);
- sys_reg |= info->bw << SYS_REG_BW_SHIFT(chan);
- sys_reg |= info->dbw << SYS_REG_DBW_SHIFT(chan);
+ sys_reg |= (2 >> info->bw) << SYS_REG_BW_SHIFT(chan);
+ sys_reg |= (2 >> info->dbw) << SYS_REG_DBW_SHIFT(chan);
dram_cfg_rbc(&dram->chan[chan], chan, sdram_params);
}
@@ -734,13 +734,13 @@ size_t sdram_size_mb(struct rk3288_pmu *pmu)
rank = 1 + (sys_reg >> SYS_REG_RANK_SHIFT(ch) &
SYS_REG_RANK_MASK);
col = 9 + (sys_reg >> SYS_REG_COL_SHIFT(ch) & SYS_REG_COL_MASK);
- bk = sys_reg & (1 << SYS_REG_BK_SHIFT(ch)) ? 3 : 0;
+ bk = 3 - ((sys_reg >> SYS_REG_BK_SHIFT(ch)) & SYS_REG_BK_MASK);
cs0_row = 13 + (sys_reg >> SYS_REG_CS0_ROW_SHIFT(ch) &
SYS_REG_CS0_ROW_MASK);
cs1_row = 13 + (sys_reg >> SYS_REG_CS1_ROW_SHIFT(ch) &
SYS_REG_CS1_ROW_MASK);
- bw = (sys_reg >> SYS_REG_BW_SHIFT(ch)) &
- SYS_REG_BW_MASK;
+ bw = (2 >> ((sys_reg >> SYS_REG_BW_SHIFT(ch)) &
+ SYS_REG_BW_MASK));
row_3_4 = sys_reg >> SYS_REG_ROW_3_4_SHIFT(ch) &
SYS_REG_ROW_3_4_MASK;
@@ -784,7 +784,7 @@ static int veyron_init(struct dram_info *priv)
return ret;
udelay(100);/* Must wait for voltage to stabilize, 2mV/us */
- rkclk_configure_cpu(priv->cru, priv->grf);
+ rk3288_clk_configure_cpu(priv->cru, priv->grf);
return 0;
}
@@ -923,7 +923,7 @@ static int rk3288_dmc_probe(struct udevice *dev)
priv->chan[1].pctl = regmap_get_range(plat->map, 2);
priv->chan[1].publ = regmap_get_range(plat->map, 3);
#endif
- ret = uclass_get_device(UCLASS_CLK, 0, &dev_clk);
+ ret = rockchip_get_clk(&dev_clk);
if (ret)
return ret;
priv->ddr_clk.id = CLK_DDR;
diff --git a/arch/arm/mach-rockchip/rk3399/Kconfig b/arch/arm/mach-rockchip/rk3399/Kconfig
new file mode 100644
index 0000000..83bd04a
--- /dev/null
+++ b/arch/arm/mach-rockchip/rk3399/Kconfig
@@ -0,0 +1,23 @@
+if ROCKCHIP_RK3399
+
+choice
+ prompt "RK3399 board select"
+
+config TARGET_EVB_RK3399
+ bool "RK3399 evaluation board"
+ help
+ RK3399evb is a evaluation board for Rockchp rk3399,
+ with full function and phisical connectors support like type-C ports,
+ usb2.0 host ports, LVDS, JTAG, MAC, SDcard, HDMI, USB-2-serial...
+
+endchoice
+
+config SYS_SOC
+ default "rockchip"
+
+config SYS_MALLOC_F_LEN
+ default 0x0800
+
+source "board/rockchip/evb_rk3399/Kconfig"
+
+endif
diff --git a/arch/arm/mach-rockchip/rk3399/Makefile b/arch/arm/mach-rockchip/rk3399/Makefile
new file mode 100644
index 0000000..3f219ac
--- /dev/null
+++ b/arch/arm/mach-rockchip/rk3399/Makefile
@@ -0,0 +1,7 @@
+#
+# (C) Copyright 2016 Rockchip Electronics Co., Ltd
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-y += rk3399.o
diff --git a/arch/arm/mach-rockchip/rk3399/rk3399.c b/arch/arm/mach-rockchip/rk3399/rk3399.c
new file mode 100644
index 0000000..b9d7629
--- /dev/null
+++ b/arch/arm/mach-rockchip/rk3399/rk3399.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2016 Rockchip Electronics Co., Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/armv8/mmu.h>
+
+static struct mm_region rk3399_mem_map[] = {
+ {
+ .virt = 0x0UL,
+ .phys = 0x0UL,
+ .size = 0x80000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+ PTE_BLOCK_INNER_SHARE
+ }, {
+ .virt = 0xf0000000UL,
+ .phys = 0xf0000000UL,
+ .size = 0x10000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+ PTE_BLOCK_NON_SHARE |
+ PTE_BLOCK_PXN | PTE_BLOCK_UXN
+ }, {
+ /* List terminator */
+ 0,
+ }
+};
+
+struct mm_region *mem_map = rk3399_mem_map;
diff --git a/arch/arm/mach-rockchip/rk3036/save_boot_param.S b/arch/arm/mach-rockchip/save_boot_param.S
index 778ec83..85b407b 100644
--- a/arch/arm/mach-rockchip/rk3036/save_boot_param.S
+++ b/arch/arm/mach-rockchip/save_boot_param.S
@@ -1,5 +1,5 @@
/*
- * (C) Copyright 2015 Google, Inc
+ * (C) Copyright 2016 Rockchip Electronics Co., Ltd
*
* SPDX-License-Identifier: GPL-2.0+
*/
diff --git a/board/evb-rk3288/evb-rk3288/Kconfig b/board/evb-rk3288/evb-rk3288/Kconfig
new file mode 100644
index 0000000..b201acb
--- /dev/null
+++ b/board/evb-rk3288/evb-rk3288/Kconfig
@@ -0,0 +1,15 @@
+if TARGET_EVB_RK3288
+
+config SYS_BOARD
+ default "evb-rk3288"
+
+config SYS_VENDOR
+ default "evb-rk3288"
+
+config SYS_CONFIG_NAME
+ default "evb-rk3288"
+
+config BOARD_SPECIFIC_OPTIONS # dummy
+ def_bool y
+
+endif
diff --git a/board/evb-rk3288/evb-rk3288/MAINTAINERS b/board/evb-rk3288/evb-rk3288/MAINTAINERS
new file mode 100644
index 0000000..222c254
--- /dev/null
+++ b/board/evb-rk3288/evb-rk3288/MAINTAINERS
@@ -0,0 +1,6 @@
+EVB-RK3288
+M: Lin Huang <hl@rock-chips.com>
+S: Maintained
+F: board/evb-rk3288/evb-rk3288
+F: include/configs/evb-rk3288.h
+F: configs/evb-rk3288_defconfig
diff --git a/board/evb-rk3288/evb-rk3288/Makefile b/board/evb-rk3288/evb-rk3288/Makefile
new file mode 100644
index 0000000..c11b657
--- /dev/null
+++ b/board/evb-rk3288/evb-rk3288/Makefile
@@ -0,0 +1,7 @@
+#
+# (C) Copyright 2016 Rockchip Electronics Co., Ltd
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-y += evb-rk3288.o
diff --git a/board/evb-rk3288/evb-rk3288/evb-rk3288.c b/board/evb-rk3288/evb-rk3288/evb-rk3288.c
new file mode 100644
index 0000000..a82f0ae
--- /dev/null
+++ b/board/evb-rk3288/evb-rk3288/evb-rk3288.c
@@ -0,0 +1,15 @@
+/*
+ * (C) Copyright 2016 Rockchip Electronics Co., Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <spl.h>
+
+void board_boot_order(u32 *spl_boot_list)
+{
+ /* eMMC prior to sdcard. */
+ spl_boot_list[0] = BOOT_DEVICE_MMC2;
+ spl_boot_list[1] = BOOT_DEVICE_MMC1;
+}
diff --git a/board/evb_rk3036/evb_rk3036/Kconfig b/board/rockchip/evb_rk3036/Kconfig
index ae2a9eb..ef45f62 100644
--- a/board/evb_rk3036/evb_rk3036/Kconfig
+++ b/board/rockchip/evb_rk3036/Kconfig
@@ -4,7 +4,7 @@ config SYS_BOARD
default "evb_rk3036"
config SYS_VENDOR
- default "evb_rk3036"
+ default "rockchip"
config SYS_CONFIG_NAME
default "evb_rk3036"
diff --git a/board/evb_rk3036/evb_rk3036/MAINTAINERS b/board/rockchip/evb_rk3036/MAINTAINERS
index 152d31c..152d31c 100644
--- a/board/evb_rk3036/evb_rk3036/MAINTAINERS
+++ b/board/rockchip/evb_rk3036/MAINTAINERS
diff --git a/board/evb_rk3036/evb_rk3036/Makefile b/board/rockchip/evb_rk3036/Makefile
index 0403836..0403836 100644
--- a/board/evb_rk3036/evb_rk3036/Makefile
+++ b/board/rockchip/evb_rk3036/Makefile
diff --git a/board/evb_rk3036/evb_rk3036/evb_rk3036.c b/board/rockchip/evb_rk3036/evb_rk3036.c
index f5758b1..f5758b1 100644
--- a/board/evb_rk3036/evb_rk3036/evb_rk3036.c
+++ b/board/rockchip/evb_rk3036/evb_rk3036.c
diff --git a/board/rockchip/evb_rk3399/Kconfig b/board/rockchip/evb_rk3399/Kconfig
new file mode 100644
index 0000000..412b81c
--- /dev/null
+++ b/board/rockchip/evb_rk3399/Kconfig
@@ -0,0 +1,15 @@
+if TARGET_EVB_RK3399
+
+config SYS_BOARD
+ default "evb_rk3399"
+
+config SYS_VENDOR
+ default "rockchip"
+
+config SYS_CONFIG_NAME
+ default "evb_rk3399"
+
+config BOARD_SPECIFIC_OPTIONS # dummy
+ def_bool y
+
+endif
diff --git a/board/rockchip/evb_rk3399/MAINTAINERS b/board/rockchip/evb_rk3399/MAINTAINERS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/board/rockchip/evb_rk3399/MAINTAINERS
diff --git a/board/rockchip/evb_rk3399/Makefile b/board/rockchip/evb_rk3399/Makefile
new file mode 100644
index 0000000..aaa51c2
--- /dev/null
+++ b/board/rockchip/evb_rk3399/Makefile
@@ -0,0 +1,7 @@
+#
+# (C) Copyright 2016 Rockchip Electronics Co., Ltd
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-y += evb-rk3399.o
diff --git a/board/rockchip/evb_rk3399/README b/board/rockchip/evb_rk3399/README
new file mode 100644
index 0000000..fb8bb19
--- /dev/null
+++ b/board/rockchip/evb_rk3399/README
@@ -0,0 +1,73 @@
+Introduction
+============
+
+RK3399 key features we might use in U-Boot:
+* CPU: ARMv8 64bit Big-Little architecture,
+* Big: dual-core Cortex-A72
+* Little: quad-core Cortex-A53
+* IRAM: 200KB
+* DRAM: 4GB-128MB dual-channel
+* eMMC: support eMMC 5.0/5.1, suport HS400, HS200, DDR50
+* SD/MMC: support SD 3.0, MMC 4.51
+* USB: USB3.0 typc-C port *2 with dwc3 controller
+* USB2.0 EHCI host port *2
+* Display: RGB/HDMI/DP/MIPI/EDP
+
+evb key features:
+* regulator: pwm regulator for CPU B/L
+* PMIC: rk808
+* debug console: UART2
+
+In order to support Arm Trust Firmware(ATF), we need to use the
+miniloader from rockchip which:
+* do DRAM init
+* load and verify ATF image
+* load and verify U-Boot image
+
+Here is the step-by-step to boot to U-Boot on rk3399.
+
+Get the Source and prebuild binary
+==================================
+
+ > mkdir ~/evb_rk3399
+ > cd ~/evb_rk3399
+ > git clone https://github.com/ARM-software/arm-trusted-firmware.git
+ > git clone https://github.com/rockchip-linux/rkbin
+ > git clone https://github.com/rockchip-linux/rkflashtool
+
+Compile the ATF
+===============
+
+ > cd arm-trusted-firmware
+ > make realclean
+ > make CROSS_COMPILE=aarch64-linux-gnu- PLAT=rk3399 bl31
+
+Compile the U-Boot
+==================
+
+ > cd ../u-boot
+ > make CROSS_COMPILE=aarch64-linux-gnu- evb-rk3399_defconfig all
+
+Compile the rkflashtool
+=======================
+
+ > cd ../rkflashtool
+ > make
+
+Package the image for miniloader
+================================
+ > cd ..
+ > cp arm-trusted-firmware/build/rk3399/release/bl31.bin rkbin/rk33
+ > ./rkbin/tools/trust_merger rkbin/tools/RK3399TRUST.ini
+ > ./rkbin/tools/loaderimage --pack --uboot u-boot/u-boot-dtb.bin uboot.img
+ > mkdir image
+ > mv trust.img ./image/
+ > mv uboot.img ./image/rk3399evb-uboot.bin
+
+Flash the image
+===============
+Power on(or reset with RESET KEY) with MASKROM KEY preesed, and then:
+
+ > ./rkflashtool/rkflashloader rk3399evb
+
+You should be able to get U-Boot log message in console/UART2 now.
diff --git a/board/rockchip/evb_rk3399/evb-rk3399.c b/board/rockchip/evb_rk3399/evb-rk3399.c
new file mode 100644
index 0000000..dffacd0
--- /dev/null
+++ b/board/rockchip/evb_rk3399/evb-rk3399.c
@@ -0,0 +1,26 @@
+/*
+ * (C) Copyright 2016 Rockchip Electronics Co., Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <asm/armv8/mmu.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int board_init(void)
+{
+ return 0;
+}
+
+int dram_init(void)
+{
+ gd->ram_size = 0x80000000;
+ return 0;
+}
+
+void dram_init_banksize(void)
+{
+ gd->bd->bi_dram[0].start = 0;
+ gd->bd->bi_dram[0].size = 0x80000000;
+}
diff --git a/board/kylin/kylin_rk3036/Kconfig b/board/rockchip/kylin_rk3036/Kconfig
index 5d75c1f..8d35b4e 100644
--- a/board/kylin/kylin_rk3036/Kconfig
+++ b/board/rockchip/kylin_rk3036/Kconfig
@@ -4,7 +4,7 @@ config SYS_BOARD
default "kylin_rk3036"
config SYS_VENDOR
- default "kylin"
+ default "rockchip"
config SYS_CONFIG_NAME
default "kylin_rk3036"
diff --git a/board/kylin/kylin_rk3036/MAINTAINERS b/board/rockchip/kylin_rk3036/MAINTAINERS
index f8ee834..f8ee834 100644
--- a/board/kylin/kylin_rk3036/MAINTAINERS
+++ b/board/rockchip/kylin_rk3036/MAINTAINERS
diff --git a/board/kylin/kylin_rk3036/Makefile b/board/rockchip/kylin_rk3036/Makefile
index 0663270..0663270 100644
--- a/board/kylin/kylin_rk3036/Makefile
+++ b/board/rockchip/kylin_rk3036/Makefile
diff --git a/board/kylin/kylin_rk3036/kylin_rk3036.c b/board/rockchip/kylin_rk3036/kylin_rk3036.c
index 2a25871..2a25871 100644
--- a/board/kylin/kylin_rk3036/kylin_rk3036.c
+++ b/board/rockchip/kylin_rk3036/kylin_rk3036.c
diff --git a/board/sandbox/README.sandbox b/board/sandbox/README.sandbox
index 9fe3bf1..ed820d3 100644
--- a/board/sandbox/README.sandbox
+++ b/board/sandbox/README.sandbox
@@ -44,6 +44,9 @@ Note:
make sandbox_defconfig all NO_SDL=1
./u-boot
+ If you are building on a 32-bit machine you may get errors from __ffs.h
+ about shifting more than the machine word size. Edit the config file
+ include/configs/sandbox.h and change CONFIG_SANDBOX_BITS_PER_LONG to 32.
U-Boot will start on your computer, showing a sandbox emulation of the serial
console:
diff --git a/board/sunxi/board.c b/board/sunxi/board.c
index f6e28b0..36cf963 100644
--- a/board/sunxi/board.c
+++ b/board/sunxi/board.c
@@ -136,7 +136,7 @@ int dram_init(void)
return 0;
}
-#if defined(CONFIG_NAND_SUNXI) && defined(CONFIG_SPL_BUILD)
+#if defined(CONFIG_NAND_SUNXI)
static void nand_pinmux_setup(void)
{
unsigned int pin;
@@ -173,6 +173,9 @@ void board_nand_init(void)
{
nand_pinmux_setup();
nand_clock_setup();
+#ifndef CONFIG_SPL_BUILD
+ sunxi_nand_init();
+#endif
}
#endif
diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index 011f62c..d66892e 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -290,6 +290,11 @@ void efi_set_bootdev(const char *dev, const char *devnr, const char *path)
/* Patch bootefi_image_path to the target file path */
memset(bootefi_image_path[0].str, 0, sizeof(bootefi_image_path[0].str));
- snprintf(devname, sizeof(devname), "%s", path);
+ if (strcmp(dev, "Net")) {
+ /* Add leading / to fs paths, because they're absolute */
+ snprintf(devname, sizeof(devname), "/%s", path);
+ } else {
+ snprintf(devname, sizeof(devname), "%s", path);
+ }
ascii2unicode(bootefi_image_path[0].str, devname);
}
diff --git a/cmd/lzmadec.c b/cmd/lzmadec.c
index 1ad9ed6..c78df82 100644
--- a/cmd/lzmadec.c
+++ b/cmd/lzmadec.c
@@ -20,7 +20,7 @@
static int do_lzmadec(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
unsigned long src, dst;
- unsigned long src_len = ~0UL, dst_len = ~0UL;
+ SizeT src_len = ~0UL, dst_len = ~0UL;
int ret;
switch (argc) {
@@ -40,7 +40,8 @@ static int do_lzmadec(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
if (ret != SZ_OK)
return 1;
- printf("Uncompressed size: %ld = 0x%lX\n", src_len, src_len);
+ printf("Uncompressed size: %ld = %#lX\n", (ulong)src_len,
+ (ulong)src_len);
setenv_hex("filesize", src_len);
return 0;
diff --git a/cmd/misc.c b/cmd/misc.c
index 39d8683..efcbb90 100644
--- a/cmd/misc.c
+++ b/cmd/misc.c
@@ -15,13 +15,31 @@
static int do_sleep(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
ulong start = get_timer(0);
+ ulong mdelay = 0;
ulong delay;
+ char *frpart;
if (argc != 2)
return CMD_RET_USAGE;
delay = simple_strtoul(argv[1], NULL, 10) * CONFIG_SYS_HZ;
+ frpart = strchr(argv[1], '.');
+
+ if (frpart) {
+ uint mult = CONFIG_SYS_HZ / 10;
+ for (frpart++; *frpart != '\0' && mult > 0; frpart++) {
+ if (*frpart < '0' || *frpart > '9') {
+ mdelay = 0;
+ break;
+ }
+ mdelay += (*frpart - '0') * mult;
+ mult /= 10;
+ }
+ }
+
+ delay += mdelay;
+
while (get_timer(start) < delay) {
if (ctrlc())
return (-1);
@@ -36,7 +54,8 @@ U_BOOT_CMD(
sleep , 2, 1, do_sleep,
"delay execution for some time",
"N\n"
- " - delay execution for N seconds (N is _decimal_ !!!)"
+ " - delay execution for N seconds (N is _decimal_ and can be\n"
+ " fractional)"
);
#ifdef CONFIG_CMD_TIMER
diff --git a/cmd/mtdparts.c b/cmd/mtdparts.c
index 3f4f334..b9b160d 100644
--- a/cmd/mtdparts.c
+++ b/cmd/mtdparts.c
@@ -1493,7 +1493,7 @@ static int spread_partitions(void)
part = list_entry(pentry, struct part_info, link);
debug("spread_partitions: device = %s%d, partition %d ="
- " (%s) 0x%08x@0x%08x\n",
+ " (%s) 0x%08llx@0x%08llx\n",
MTD_DEV_TYPE(dev->id->type), dev->id->num,
part_num, part->name, part->size,
part->offset);
@@ -2025,7 +2025,7 @@ static int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc,
if (!strcmp(&argv[1][3], ".spread")) {
spread_partition(mtd, p, &next_offset);
- debug("increased %s to %d bytes\n", p->name, p->size);
+ debug("increased %s to %llu bytes\n", p->name, p->size);
}
#endif
diff --git a/cmd/nand.c b/cmd/nand.c
index ffdeea4..e10349a 100644
--- a/cmd/nand.c
+++ b/cmd/nand.c
@@ -306,7 +306,7 @@ static void nand_print_and_set_info(int idx)
}
static int raw_access(struct mtd_info *mtd, ulong addr, loff_t off,
- ulong count, int read)
+ ulong count, int read, int no_verify)
{
int ret = 0;
@@ -324,7 +324,7 @@ static int raw_access(struct mtd_info *mtd, ulong addr, loff_t off,
ret = mtd_read_oob(mtd, off, &ops);
} else {
ret = mtd_write_oob(mtd, off, &ops);
- if (!ret)
+ if (!ret && !no_verify)
ret = nand_verify_page_oob(mtd, &ops, off);
}
@@ -546,6 +546,7 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
ulong pagecount = 1;
int read;
int raw = 0;
+ int no_verify = 0;
if (argc < 4)
goto usage;
@@ -557,9 +558,12 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
s = strchr(cmd, '.');
- if (s && !strcmp(s, ".raw")) {
+ if (s && !strncmp(s, ".raw", 4)) {
raw = 1;
+ if (!strcmp(s, ".raw.noverify"))
+ no_verify = 1;
+
if (mtd_arg_off(argv[3], &dev, &off, &size, &maxsize,
MTD_DEV_TYPE_NAND,
nand_info[dev]->size))
@@ -633,7 +637,8 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
else
ret = mtd_write_oob(mtd, off, &ops);
} else if (raw) {
- ret = raw_access(mtd, addr, off, pagecount, read);
+ ret = raw_access(mtd, addr, off, pagecount, read,
+ no_verify);
} else {
printf("Unknown nand command suffix '%s'.\n", s);
return 1;
@@ -786,7 +791,7 @@ static char nand_help_text[] =
" read/write 'size' bytes starting at offset 'off'\n"
" to/from memory address 'addr', skipping bad blocks.\n"
"nand read.raw - addr off|partition [count]\n"
- "nand write.raw - addr off|partition [count]\n"
+ "nand write.raw[.noverify] - addr off|partition [count]\n"
" Use read.raw/write.raw to avoid ECC and access the flash as-is.\n"
#ifdef CONFIG_CMD_NAND_TRIMFFS
"nand write.trimffs - addr off|partition size\n"
diff --git a/common/image-fit.c b/common/image-fit.c
index 6f920da..73ad34e 100644
--- a/common/image-fit.c
+++ b/common/image-fit.c
@@ -1684,12 +1684,13 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL);
type_ok = fit_image_check_type(fit, noffset, image_type) ||
- (image_type == IH_TYPE_KERNEL &&
- fit_image_check_type(fit, noffset,
- IH_TYPE_KERNEL_NOLOAD));
+ fit_image_check_type(fit, noffset, IH_TYPE_FIRMWARE) ||
+ (image_type == IH_TYPE_KERNEL &&
+ fit_image_check_type(fit, noffset, IH_TYPE_KERNEL_NOLOAD));
os_ok = image_type == IH_TYPE_FLATDT || IH_TYPE_FPGA ||
fit_image_check_os(fit, noffset, IH_OS_LINUX) ||
+ fit_image_check_os(fit, noffset, IH_OS_U_BOOT) ||
fit_image_check_os(fit, noffset, IH_OS_OPENRTOS);
/*
diff --git a/configs/am335x_boneblack_vboot_defconfig b/configs/am335x_boneblack_vboot_defconfig
index 903f518..c2f09cb 100644
--- a/configs/am335x_boneblack_vboot_defconfig
+++ b/configs/am335x_boneblack_vboot_defconfig
@@ -49,3 +49,4 @@ CONFIG_USB_GADGET_DOWNLOAD=y
CONFIG_G_DNL_MANUFACTURER="Texas Instruments"
CONFIG_G_DNL_VENDOR_NUM=0x0451
CONFIG_G_DNL_PRODUCT_NUM=0xd022
+CONFIG_DM_I2C=y
diff --git a/configs/am335x_evm_defconfig b/configs/am335x_evm_defconfig
index 696024c..6885230 100644
--- a/configs/am335x_evm_defconfig
+++ b/configs/am335x_evm_defconfig
@@ -49,3 +49,4 @@ CONFIG_FIT=y
CONFIG_SPL_OF_LIBFDT=y
CONFIG_SPL_LOAD_FIT=y
CONFIG_OF_LIST="am335x-evm am335x-bone am335x-boneblack am335x-evmsk am335x-bonegreen am335x-icev2"
+CONFIG_DM_I2C=y
diff --git a/configs/am43xx_evm_defconfig b/configs/am43xx_evm_defconfig
index cb3de11..0eab4ad 100644
--- a/configs/am43xx_evm_defconfig
+++ b/configs/am43xx_evm_defconfig
@@ -54,3 +54,4 @@ CONFIG_G_DNL_MANUFACTURER="Texas Instruments"
CONFIG_G_DNL_VENDOR_NUM=0x0403
CONFIG_G_DNL_PRODUCT_NUM=0xbd00
CONFIG_SPL_OF_LIBFDT=y
+CONFIG_DM_I2C=y
diff --git a/configs/am43xx_hs_evm_defconfig b/configs/am43xx_hs_evm_defconfig
index 68dfb6c..c8ce723 100644
--- a/configs/am43xx_hs_evm_defconfig
+++ b/configs/am43xx_hs_evm_defconfig
@@ -58,3 +58,4 @@ CONFIG_G_DNL_MANUFACTURER="Texas Instruments"
CONFIG_G_DNL_VENDOR_NUM=0x0403
CONFIG_G_DNL_PRODUCT_NUM=0xbd00
CONFIG_SPL_OF_LIBFDT=y
+CONFIG_DM_I2C=y
diff --git a/configs/am57xx_evm_defconfig b/configs/am57xx_evm_defconfig
index c29a05a..8a8a4c9 100644
--- a/configs/am57xx_evm_defconfig
+++ b/configs/am57xx_evm_defconfig
@@ -40,3 +40,4 @@ CONFIG_FIT=y
CONFIG_SPL_OF_LIBFDT=y
CONFIG_SPL_LOAD_FIT=y
CONFIG_OF_LIST="am57xx-beagle-x15 am572x-idk"
+CONFIG_DM_I2C=y
diff --git a/configs/am57xx_hs_evm_defconfig b/configs/am57xx_hs_evm_defconfig
index 01a4701..2ccb332 100644
--- a/configs/am57xx_hs_evm_defconfig
+++ b/configs/am57xx_hs_evm_defconfig
@@ -42,3 +42,4 @@ CONFIG_SPL_OF_LIBFDT=y
CONFIG_SPL_LOAD_FIT=y
CONFIG_SPL_FIT_IMAGE_POST_PROCESS=y
CONFIG_OF_LIST="am57xx-beagle-x15"
+CONFIG_DM_I2C=y
diff --git a/configs/chromebook_jerry_defconfig b/configs/chromebook_jerry_defconfig
index d5bc515..fd5314a 100644
--- a/configs/chromebook_jerry_defconfig
+++ b/configs/chromebook_jerry_defconfig
@@ -53,7 +53,7 @@ CONFIG_ROCKCHIP_DWMMC=y
CONFIG_PINCTRL=y
CONFIG_SPL_PINCTRL=y
# CONFIG_SPL_PINCTRL_FULL is not set
-CONFIG_ROCKCHIP_PINCTRL=y
+CONFIG_ROCKCHIP_RK3288_PINCTRL=y
CONFIG_DM_PMIC=y
# CONFIG_SPL_PMIC_CHILDREN is not set
CONFIG_PMIC_RK808=y
diff --git a/configs/dra7xx_evm_defconfig b/configs/dra7xx_evm_defconfig
index 756af63..1d27e52 100644
--- a/configs/dra7xx_evm_defconfig
+++ b/configs/dra7xx_evm_defconfig
@@ -57,3 +57,4 @@ CONFIG_FIT=y
CONFIG_SPL_OF_LIBFDT=y
CONFIG_SPL_LOAD_FIT=y
CONFIG_OF_LIST="dra7-evm dra72-evm"
+CONFIG_DM_I2C=y
diff --git a/configs/dra7xx_hs_evm_defconfig b/configs/dra7xx_hs_evm_defconfig
index eb01f41..faf9cd5 100644
--- a/configs/dra7xx_hs_evm_defconfig
+++ b/configs/dra7xx_hs_evm_defconfig
@@ -60,3 +60,4 @@ CONFIG_SPL_OF_LIBFDT=y
CONFIG_SPL_LOAD_FIT=y
CONFIG_SPL_FIT_IMAGE_POST_PROCESS=y
CONFIG_OF_LIST="dra7-evm dra72-evm"
+CONFIG_DM_I2C=y
diff --git a/configs/evb-rk3036_defconfig b/configs/evb-rk3036_defconfig
index 9894fff..2d5e5e0 100644
--- a/configs/evb-rk3036_defconfig
+++ b/configs/evb-rk3036_defconfig
@@ -32,7 +32,7 @@ CONFIG_SYSRESET=y
CONFIG_DM_MMC=y
CONFIG_ROCKCHIP_DWMMC=y
CONFIG_PINCTRL=y
-CONFIG_ROCKCHIP_3036_PINCTRL=y
+CONFIG_ROCKCHIP_RK3036_PINCTRL=y
CONFIG_RAM=y
# CONFIG_SPL_SERIAL_PRESENT is not set
CONFIG_DEBUG_UART=y
diff --git a/configs/evb-rk3288_defconfig b/configs/evb-rk3288_defconfig
new file mode 100644
index 0000000..41cfedd
--- /dev/null
+++ b/configs/evb-rk3288_defconfig
@@ -0,0 +1,67 @@
+CONFIG_ARM=y
+CONFIG_ARCH_ROCKCHIP=y
+CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_ROCKCHIP_RK3288=y
+CONFIG_TARGET_EVB_RK3288=y
+CONFIG_SPL_STACK_R_ADDR=0x80000
+CONFIG_DEFAULT_DEVICE_TREE="rk3288-evb"
+CONFIG_SPL_STACK_R=y
+CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN=0x2000
+CONFIG_HUSH_PARSER=y
+CONFIG_CMD_BOOTZ=y
+# CONFIG_CMD_IMLS is not set
+CONFIG_CMD_MMC=y
+CONFIG_CMD_SF=y
+CONFIG_CMD_SPI=y
+CONFIG_CMD_I2C=y
+CONFIG_CMD_GPIO=y
+# CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
+CONFIG_CMD_CACHE=y
+CONFIG_CMD_TIME=y
+CONFIG_CMD_PMIC=y
+CONFIG_CMD_REGULATOR=y
+CONFIG_CMD_EXT2=y
+CONFIG_CMD_EXT4=y
+CONFIG_CMD_FAT=y
+CONFIG_CMD_FS_GENERIC=y
+CONFIG_SPL_OF_CONTROL=y
+CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names clock-names interrupt-parent assigned-clocks assigned-clock-rates assigned-clock-parents"
+CONFIG_REGMAP=y
+CONFIG_SPL_REGMAP=y
+CONFIG_SYSCON=y
+CONFIG_SPL_SYSCON=y
+CONFIG_CLK=y
+CONFIG_SPL_CLK=y
+CONFIG_ROCKCHIP_GPIO=y
+CONFIG_SYS_I2C_ROCKCHIP=y
+CONFIG_LED=y
+CONFIG_LED_GPIO=y
+CONFIG_SYSRESET=y
+CONFIG_DM_MMC=y
+CONFIG_ROCKCHIP_DWMMC=y
+CONFIG_PINCTRL=y
+# CONFIG_PINCTRL_FULL is not set
+CONFIG_SPL_PINCTRL=y
+# CONFIG_SPL_PINCTRL_FULL is not set
+CONFIG_ROCKCHIP_PINCTRL=y
+CONFIG_DM_PMIC=y
+CONFIG_PMIC_ACT8846=y
+CONFIG_DM_REGULATOR=y
+CONFIG_REGULATOR_ACT8846=y
+CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_DM_PWM=y
+CONFIG_PWM_ROCKCHIP=y
+CONFIG_RAM=y
+CONFIG_SPL_RAM=y
+CONFIG_DEBUG_UART=y
+CONFIG_DEBUG_UART_BASE=0xff690000
+CONFIG_DEBUG_UART_CLOCK=24000000
+CONFIG_DEBUG_UART_SHIFT=2
+CONFIG_SYS_NS16550=y
+CONFIG_USE_PRIVATE_LIBGCC=y
+CONFIG_USE_TINY_PRINTF=y
+CONFIG_CMD_DHRYSTONE=y
+CONFIG_ERRNO_STR=y
diff --git a/configs/evb-rk3399_defconfig b/configs/evb-rk3399_defconfig
new file mode 100644
index 0000000..3f9b47e
--- /dev/null
+++ b/configs/evb-rk3399_defconfig
@@ -0,0 +1,33 @@
+CONFIG_ARM=y
+CONFIG_ARCH_ROCKCHIP=y
+CONFIG_ROCKCHIP_RK3399=y
+CONFIG_TARGET_EVB_RK3399=y
+CONFIG_DEFAULT_DEVICE_TREE="rk3399-evb"
+CONFIG_HUSH_PARSER=y
+CONFIG_CMD_BOOTZ=y
+# CONFIG_CMD_IMLS is not set
+CONFIG_CMD_MMC=y
+CONFIG_CMD_SF=y
+# CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_TIME=y
+CONFIG_CMD_GPT=y
+CONFIG_CMD_EXT2=y
+CONFIG_CMD_EXT4=y
+CONFIG_CMD_FAT=y
+CONFIG_CMD_FS_GENERIC=y
+CONFIG_REGMAP=y
+CONFIG_SYSCON=y
+CONFIG_CLK=y
+CONFIG_FIT=y
+CONFIG_SYSRESET=y
+CONFIG_DM_MMC=y
+CONFIG_ROCKCHIP_SDHCI=y
+CONFIG_PINCTRL=y
+CONFIG_RAM=y
+CONFIG_SYS_NS16550=y
+CONFIG_DEBUG_UART=y
+CONFIG_DEBUG_UART_BASE=0xFF1A0000
+CONFIG_DEBUG_UART_CLOCK=24000000
+CONFIG_DEBUG_UART_SHIFT=2
+CONFIG_USE_TINY_PRINTF=y
+CONFIG_ERRNO_STR=y
diff --git a/configs/firefly-rk3288_defconfig b/configs/firefly-rk3288_defconfig
index bdafc71..4122000 100644
--- a/configs/firefly-rk3288_defconfig
+++ b/configs/firefly-rk3288_defconfig
@@ -46,7 +46,7 @@ CONFIG_ROCKCHIP_DWMMC=y
CONFIG_PINCTRL=y
CONFIG_SPL_PINCTRL=y
# CONFIG_SPL_PINCTRL_FULL is not set
-CONFIG_ROCKCHIP_PINCTRL=y
+CONFIG_ROCKCHIP_RK3288_PINCTRL=y
CONFIG_DM_PMIC=y
# CONFIG_SPL_PMIC_CHILDREN is not set
CONFIG_PMIC_ACT8846=y
diff --git a/configs/kylin-rk3036_defconfig b/configs/kylin-rk3036_defconfig
index 0ff6c6b..51196aa 100644
--- a/configs/kylin-rk3036_defconfig
+++ b/configs/kylin-rk3036_defconfig
@@ -32,7 +32,7 @@ CONFIG_SYSRESET=y
CONFIG_DM_MMC=y
CONFIG_ROCKCHIP_DWMMC=y
CONFIG_PINCTRL=y
-CONFIG_ROCKCHIP_3036_PINCTRL=y
+CONFIG_ROCKCHIP_RK3036_PINCTRL=y
CONFIG_RAM=y
CONFIG_USE_PRIVATE_LIBGCC=y
CONFIG_CMD_DHRYSTONE=y
diff --git a/configs/rock2_defconfig b/configs/rock2_defconfig
index 3e16b80..3b6d7d9 100644
--- a/configs/rock2_defconfig
+++ b/configs/rock2_defconfig
@@ -44,7 +44,7 @@ CONFIG_ROCKCHIP_DWMMC=y
CONFIG_PINCTRL=y
CONFIG_SPL_PINCTRL=y
# CONFIG_SPL_PINCTRL_FULL is not set
-CONFIG_ROCKCHIP_PINCTRL=y
+CONFIG_ROCKCHIP_RK3288_PINCTRL=y
CONFIG_DM_PMIC=y
# CONFIG_SPL_PMIC_CHILDREN is not set
CONFIG_PMIC_ACT8846=y
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 6a1874a..29e6d85 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -101,6 +101,7 @@ CONFIG_CROS_EC_SPI=y
CONFIG_PWRSEQ=y
CONFIG_SPL_PWRSEQ=y
CONFIG_SYSRESET=y
+CONFIG_I2C_EEPROM=y
CONFIG_DM_MMC_OPS=y
CONFIG_SANDBOX_MMC=y
CONFIG_SPI_FLASH_SANDBOX=y
@@ -119,8 +120,8 @@ CONFIG_DM_PCI_COMPAT=y
CONFIG_PCI_SANDBOX=y
CONFIG_PINCTRL=y
CONFIG_PINCONF=y
-CONFIG_ROCKCHIP_PINCTRL=y
-CONFIG_ROCKCHIP_3036_PINCTRL=y
+CONFIG_ROCKCHIP_RK3288_PINCTRL=y
+CONFIG_ROCKCHIP_RK3036_PINCTRL=y
CONFIG_PINCTRL_SANDBOX=y
CONFIG_DM_PMIC=y
CONFIG_PMIC_ACT8846=y
diff --git a/configs/sandbox_noblk_defconfig b/configs/sandbox_noblk_defconfig
index 60c7339..503845b 100644
--- a/configs/sandbox_noblk_defconfig
+++ b/configs/sandbox_noblk_defconfig
@@ -112,8 +112,8 @@ CONFIG_DM_PCI_COMPAT=y
CONFIG_PCI_SANDBOX=y
CONFIG_PINCTRL=y
CONFIG_PINCONF=y
-CONFIG_ROCKCHIP_PINCTRL=y
-CONFIG_ROCKCHIP_3036_PINCTRL=y
+CONFIG_ROCKCHIP_RK3288_PINCTRL=y
+CONFIG_ROCKCHIP_RK3036_PINCTRL=y
CONFIG_PINCTRL_SANDBOX=y
CONFIG_DM_PMIC=y
CONFIG_PMIC_ACT8846=y
diff --git a/configs/thunderx_88xx_defconfig b/configs/thunderx_88xx_defconfig
index 4a8655f..28797f9 100644
--- a/configs/thunderx_88xx_defconfig
+++ b/configs/thunderx_88xx_defconfig
@@ -2,7 +2,6 @@ CONFIG_ARM=y
CONFIG_TARGET_THUNDERX_88XX=y
CONFIG_DM_SERIAL=y
CONFIG_DEFAULT_DEVICE_TREE="thunderx-88xx"
-CONFIG_SYS_EXTRA_OPTIONS="ARM64"
CONFIG_BOOTDELAY=5
CONFIG_HUSH_PARSER=y
CONFIG_SYS_PROMPT="ThunderX_88XX> "
diff --git a/disk/part_efi.c b/disk/part_efi.c
index 0af1e92..01f71be 100644
--- a/disk/part_efi.c
+++ b/disk/part_efi.c
@@ -886,9 +886,10 @@ static gpt_entry *alloc_read_gpt_entries(struct blk_desc *dev_desc,
count = le32_to_cpu(pgpt_head->num_partition_entries) *
le32_to_cpu(pgpt_head->sizeof_partition_entry);
- debug("%s: count = %u * %u = %zu\n", __func__,
+ debug("%s: count = %u * %u = %lu\n", __func__,
(u32) le32_to_cpu(pgpt_head->num_partition_entries),
- (u32) le32_to_cpu(pgpt_head->sizeof_partition_entry), count);
+ (u32) le32_to_cpu(pgpt_head->sizeof_partition_entry),
+ (ulong)count);
/* Allocate memory for PTE, remember to FREE */
if (count != 0) {
@@ -897,9 +898,8 @@ static gpt_entry *alloc_read_gpt_entries(struct blk_desc *dev_desc,
}
if (count == 0 || pte == NULL) {
- printf("%s: ERROR: Can't allocate 0x%zX "
- "bytes for GPT Entries\n",
- __func__, count);
+ printf("%s: ERROR: Can't allocate %#lX bytes for GPT Entries\n",
+ __func__, (ulong)count);
return NULL;
}
diff --git a/doc/README.rockchip b/doc/README.rockchip
index e0572c8..c218a8b 100644
--- a/doc/README.rockchip
+++ b/doc/README.rockchip
@@ -36,11 +36,12 @@ You will need:
Building
========
-At present three RK3288 boards are supported:
+At present four RK3288 boards are supported:
- Firefly RK3288 - use firefly-rk3288 configuration
- Radxa Rock 2 - use rock2 configuration
- Hisense Chromebook - use chromebook_jerry configuration
+ - EVB RK3288 - use evb-rk3288 configuration
Two RK3036 board are supported:
@@ -119,6 +120,20 @@ something like:
Hit any key to stop autoboot: 0
=>
+The rockchip bootrom can load and boot an initial spl, then continue to
+load a second-level bootloader(ie. U-BOOT) as soon as it returns to bootrom.
+Therefore RK3288 has another loading sequence like RK3036. The option of
+U-Boot is controlled with this setting in U-Boot:
+
+ #define CONFIG_ROCKCHIP_SPL_BACK_TO_BROM
+
+You can create the image via the following operations:
+
+ ./firefly-rk3288/tools/mkimage -n rk3288 -T rksd -d \
+ firefly-rk3288/spl/u-boot-spl-dtb.bin out && \
+ cat firefly-rk3288/u-boot-dtb.bin >> out && \
+ sudo dd if=out of=/dev/sdc seek=64
+
If you have an HDMI cable attached you should see a video console.
For evb_rk3036 board:
@@ -129,6 +144,32 @@ For evb_rk3036 board:
Note: rk3036 SDMMC and debug uart use the same iomux, so if you boot from SD, the
debug uart must be disabled
+Using fastboot on rk3288
+========================
+- Define GPT partition layout like kylin_rk3036(see include/configs/kylin_rk3036.h)
+- Write GPT partition layout to mmc device which fastboot want to use it to
+store the image
+
+ => gpt write mmc 1 $partitions
+
+- Invoke fastboot command to prepare
+
+ => fastboot 1
+
+- Start fastboot request on PC
+
+ fastboot -i 0x2207 flash loader evb-rk3288/spl/u-boot-spl-dtb.bin
+
+You should see something like:
+
+ => fastboot 1
+ WARNING: unknown variable: partition-type:loader
+ Starting download of 357796 bytes
+ ..
+ downloading of 357796 bytes finished
+ Flashing Raw Image
+ ........ wrote 357888 bytes to 'loader'
+
Booting from SPI
================
diff --git a/drivers/clk/clk_rk3288.c b/drivers/clk/clk_rk3288.c
index 679f010..e00feb0 100644
--- a/drivers/clk/clk_rk3288.c
+++ b/drivers/clk/clk_rk3288.c
@@ -47,7 +47,7 @@ enum {
OUTPUT_MAX_HZ = 2200U * 1000000,
OUTPUT_MIN_HZ = 27500000,
FREF_MAX_HZ = 2200U * 1000000,
- FREF_MIN_HZ = 269 * 1000000,
+ FREF_MIN_HZ = 269 * 1000,
};
enum {
@@ -145,7 +145,7 @@ void *rockchip_get_cru(void)
struct udevice *dev;
int ret;
- ret = uclass_get_device(UCLASS_CLK, 0, &dev);
+ ret = rockchip_get_clk(&dev);
if (ret)
return ERR_PTR(ret);
@@ -447,7 +447,7 @@ static void rkclk_init(struct rk3288_cru *cru, struct rk3288_grf *grf)
}
#endif
-void rkclk_configure_cpu(struct rk3288_cru *cru, struct rk3288_grf *grf)
+void rk3288_clk_configure_cpu(struct rk3288_cru *cru, struct rk3288_grf *grf)
{
/* pll enter slow-mode */
rk_clrsetreg(&cru->cru_mode_con,
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index 1141ce1..de602ae 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -311,6 +311,26 @@ static int uclass_find_device_by_phandle(enum uclass_id id,
}
#endif
+int uclass_get_device_by_driver(enum uclass_id id,
+ const struct driver *find_drv,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+ struct uclass *uc;
+ int ret;
+
+ ret = uclass_get(id, &uc);
+ if (ret)
+ return ret;
+
+ list_for_each_entry(dev, &uc->dev_head, uclass_node) {
+ if (dev->driver == find_drv)
+ return uclass_get_device_tail(dev, 0, devp);
+ }
+
+ return -ENODEV;
+}
+
int uclass_get_device_tail(struct udevice *dev, int ret,
struct udevice **devp)
{
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 6e22bba..b3e8405 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -154,6 +154,13 @@ config SYS_I2C_UNIPHIER_F
Support for UniPhier FIFO-builtin I2C controller driver.
This I2C controller is used on PH1-Pro4 or newer UniPhier SoCs.
+config SYS_I2C_MVTWSI
+ bool "Marvell I2C driver"
+ depends on DM_I2C
+ help
+ Support for Marvell I2C controllers as used on the orion5x and
+ kirkwood SoC families.
+
source "drivers/i2c/muxes/Kconfig"
endmenu
diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c
index 50b99ea..20b30ff 100644
--- a/drivers/i2c/i2c-uclass.c
+++ b/drivers/i2c/i2c-uclass.c
@@ -467,6 +467,7 @@ int i2c_deblock(struct udevice *bus)
return ops->deblock(bus);
}
+#if CONFIG_IS_ENABLED(OF_CONTROL)
int i2c_chip_ofdata_to_platdata(const void *blob, int node,
struct dm_i2c_chip *chip)
{
@@ -482,31 +483,44 @@ int i2c_chip_ofdata_to_platdata(const void *blob, int node,
return 0;
}
+#endif
static int i2c_post_probe(struct udevice *dev)
{
+#if CONFIG_IS_ENABLED(OF_CONTROL)
struct dm_i2c_bus *i2c = dev_get_uclass_priv(dev);
i2c->speed_hz = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
"clock-frequency", 100000);
return dm_i2c_set_bus_speed(dev, i2c->speed_hz);
+#else
+ return 0;
+#endif
}
static int i2c_post_bind(struct udevice *dev)
{
+#if CONFIG_IS_ENABLED(OF_CONTROL)
/* Scan the bus for devices */
return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
+#else
+ return 0;
+#endif
}
static int i2c_child_post_bind(struct udevice *dev)
{
+#if CONFIG_IS_ENABLED(OF_CONTROL)
struct dm_i2c_chip *plat = dev_get_parent_platdata(dev);
if (dev->of_offset == -1)
return 0;
return i2c_chip_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, plat);
+#else
+ return 0;
+#endif
}
UCLASS_DRIVER(i2c) = {
diff --git a/drivers/i2c/mvtwsi.c b/drivers/i2c/mvtwsi.c
index bf44432..ab7481a 100644
--- a/drivers/i2c/mvtwsi.c
+++ b/drivers/i2c/mvtwsi.c
@@ -12,12 +12,19 @@
#include <i2c.h>
#include <asm/errno.h>
#include <asm/io.h>
+#include <linux/compat.h>
+#ifdef CONFIG_DM_I2C
+#include <dm.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
/*
- * include a file that will provide CONFIG_I2C_MVTWSI_BASE*
- * and possibly other settings
+ * Include a file that will provide CONFIG_I2C_MVTWSI_BASE*, and possibly other
+ * settings
*/
+#ifndef CONFIG_DM_I2C
#if defined(CONFIG_ORION5X)
#include <asm/arch/orion5x.h>
#elif (defined(CONFIG_KIRKWOOD) || defined(CONFIG_ARCH_MVEBU))
@@ -27,6 +34,7 @@
#else
#error Driver mvtwsi not supported by SoC or board
#endif
+#endif /* CONFIG_DM_I2C */
/*
* TWSI register structure
@@ -51,8 +59,8 @@ struct mvtwsi_registers {
u32 data;
u32 control;
union {
- u32 status; /* when reading */
- u32 baudrate; /* when writing */
+ u32 status; /* When reading */
+ u32 baudrate; /* When writing */
};
u32 xtnd_slave_addr;
u32 reserved[2];
@@ -61,20 +69,43 @@ struct mvtwsi_registers {
#endif
+#ifdef CONFIG_DM_I2C
+struct mvtwsi_i2c_dev {
+ /* TWSI Register base for the device */
+ struct mvtwsi_registers *base;
+ /* Number of the device (determined from cell-index property) */
+ int index;
+ /* The I2C slave address for the device */
+ u8 slaveadd;
+ /* The configured I2C speed in Hz */
+ uint speed;
+ /* The current length of a clock period (depending on speed) */
+ uint tick;
+};
+#endif /* CONFIG_DM_I2C */
+
/*
- * Control register fields
+ * enum mvtwsi_ctrl_register_fields - Bit masks for flags in the control
+ * register
*/
-
-#define MVTWSI_CONTROL_ACK 0x00000004
-#define MVTWSI_CONTROL_IFLG 0x00000008
-#define MVTWSI_CONTROL_STOP 0x00000010
-#define MVTWSI_CONTROL_START 0x00000020
-#define MVTWSI_CONTROL_TWSIEN 0x00000040
-#define MVTWSI_CONTROL_INTEN 0x00000080
+enum mvtwsi_ctrl_register_fields {
+ /* Acknowledge bit */
+ MVTWSI_CONTROL_ACK = 0x00000004,
+ /* Interrupt flag */
+ MVTWSI_CONTROL_IFLG = 0x00000008,
+ /* Stop bit */
+ MVTWSI_CONTROL_STOP = 0x00000010,
+ /* Start bit */
+ MVTWSI_CONTROL_START = 0x00000020,
+ /* I2C enable */
+ MVTWSI_CONTROL_TWSIEN = 0x00000040,
+ /* Interrupt enable */
+ MVTWSI_CONTROL_INTEN = 0x00000080,
+};
/*
- * On sun6i and newer IFLG is a write-clear bit which is cleared by writing 1,
- * on other platforms it is a normal r/w bit which is cleared by writing 0.
+ * On sun6i and newer, IFLG is a write-clear bit, which is cleared by writing 1;
+ * on other platforms, it is a normal r/w bit, which is cleared by writing 0.
*/
#ifdef CONFIG_SUNXI_GEN_SUN6I
@@ -84,53 +115,95 @@ struct mvtwsi_registers {
#endif
/*
- * Status register values -- only those expected in normal master
- * operation on non-10-bit-address devices; whatever status we don't
- * expect in nominal conditions (bus errors, arbitration losses,
- * missing ACKs...) we just pass back to the caller as an error
+ * enum mvstwsi_status_values - Possible values of I2C controller's status
+ * register
+ *
+ * Only those statuses expected in normal master operation on
+ * non-10-bit-address devices are specified.
+ *
+ * Every status that's unexpected during normal operation (bus errors,
+ * arbitration losses, missing ACKs...) is passed back to the caller as an error
* code.
*/
+enum mvstwsi_status_values {
+ /* START condition transmitted */
+ MVTWSI_STATUS_START = 0x08,
+ /* Repeated START condition transmitted */
+ MVTWSI_STATUS_REPEATED_START = 0x10,
+ /* Address + write bit transmitted, ACK received */
+ MVTWSI_STATUS_ADDR_W_ACK = 0x18,
+ /* Data transmitted, ACK received */
+ MVTWSI_STATUS_DATA_W_ACK = 0x28,
+ /* Address + read bit transmitted, ACK received */
+ MVTWSI_STATUS_ADDR_R_ACK = 0x40,
+ /* Address + read bit transmitted, ACK not received */
+ MVTWSI_STATUS_ADDR_R_NAK = 0x48,
+ /* Data received, ACK transmitted */
+ MVTWSI_STATUS_DATA_R_ACK = 0x50,
+ /* Data received, ACK not transmitted */
+ MVTWSI_STATUS_DATA_R_NAK = 0x58,
+ /* No relevant status */
+ MVTWSI_STATUS_IDLE = 0xF8,
+};
-#define MVTWSI_STATUS_START 0x08
-#define MVTWSI_STATUS_REPEATED_START 0x10
-#define MVTWSI_STATUS_ADDR_W_ACK 0x18
-#define MVTWSI_STATUS_DATA_W_ACK 0x28
-#define MVTWSI_STATUS_ADDR_R_ACK 0x40
-#define MVTWSI_STATUS_ADDR_R_NAK 0x48
-#define MVTWSI_STATUS_DATA_R_ACK 0x50
-#define MVTWSI_STATUS_DATA_R_NAK 0x58
-#define MVTWSI_STATUS_IDLE 0xF8
+/*
+ * enum mvstwsi_ack_flags - Determine whether a read byte should be
+ * acknowledged or not.
+ */
+enum mvtwsi_ack_flags {
+ /* Send NAK after received byte */
+ MVTWSI_READ_NAK = 0,
+ /* Send ACK after received byte */
+ MVTWSI_READ_ACK = 1,
+};
/*
- * MVTWSI controller base
+ * calc_tick() - Calculate the duration of a clock cycle from the I2C speed
+ *
+ * @speed: The speed in Hz to calculate the clock cycle duration for.
+ * @return The duration of a clock cycle in ns.
*/
+inline uint calc_tick(uint speed)
+{
+ /* One tick = the duration of a period at the specified speed in ns (we
+ * add 100 ns to be on the safe side) */
+ return (1000000000u / speed) + 100;
+}
+#ifndef CONFIG_DM_I2C
+
+/*
+ * twsi_get_base() - Get controller register base for specified adapter
+ *
+ * @adap: Adapter to get the register base for.
+ * @return Register base for the specified adapter.
+ */
static struct mvtwsi_registers *twsi_get_base(struct i2c_adapter *adap)
{
switch (adap->hwadapnr) {
#ifdef CONFIG_I2C_MVTWSI_BASE0
case 0:
- return (struct mvtwsi_registers *) CONFIG_I2C_MVTWSI_BASE0;
+ return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE0;
#endif
#ifdef CONFIG_I2C_MVTWSI_BASE1
case 1:
- return (struct mvtwsi_registers *) CONFIG_I2C_MVTWSI_BASE1;
+ return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE1;
#endif
#ifdef CONFIG_I2C_MVTWSI_BASE2
case 2:
- return (struct mvtwsi_registers *) CONFIG_I2C_MVTWSI_BASE2;
+ return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE2;
#endif
#ifdef CONFIG_I2C_MVTWSI_BASE3
case 3:
- return (struct mvtwsi_registers *) CONFIG_I2C_MVTWSI_BASE3;
+ return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE3;
#endif
#ifdef CONFIG_I2C_MVTWSI_BASE4
case 4:
- return (struct mvtwsi_registers *) CONFIG_I2C_MVTWSI_BASE4;
+ return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE4;
#endif
#ifdef CONFIG_I2C_MVTWSI_BASE5
case 5:
- return (struct mvtwsi_registers *) CONFIG_I2C_MVTWSI_BASE5;
+ return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE5;
#endif
default:
printf("Missing mvtwsi controller %d base\n", adap->hwadapnr);
@@ -139,30 +212,48 @@ static struct mvtwsi_registers *twsi_get_base(struct i2c_adapter *adap)
return NULL;
}
+#endif
/*
- * Returned statuses are 0 for success and nonzero otherwise.
- * Currently, cmd_i2c and cmd_eeprom do not interpret an error status.
- * Thus to ease debugging, the return status contains some debug info:
- * - bits 31..24 are error class: 1 is timeout, 2 is 'status mismatch'.
- * - bits 23..16 are the last value of the control register.
- * - bits 15..8 are the last value of the status register.
- * - bits 7..0 are the expected value of the status register.
+ * enum mvtwsi_error_class - types of I2C errors
*/
+enum mvtwsi_error_class {
+ /* The controller returned a different status than expected */
+ MVTWSI_ERROR_WRONG_STATUS = 0x01,
+ /* The controller timed out */
+ MVTWSI_ERROR_TIMEOUT = 0x02,
+};
-#define MVTWSI_ERROR_WRONG_STATUS 0x01
-#define MVTWSI_ERROR_TIMEOUT 0x02
-
-#define MVTWSI_ERROR(ec, lc, ls, es) (((ec << 24) & 0xFF000000) | \
- ((lc << 16) & 0x00FF0000) | ((ls<<8) & 0x0000FF00) | (es & 0xFF))
+/*
+ * mvtwsi_error() - Build I2C return code from error information
+ *
+ * For debugging purposes, this function packs some information of an occurred
+ * error into a return code. These error codes are returned from I2C API
+ * functions (i2c_{read,write}, dm_i2c_{read,write}, etc.).
+ *
+ * @ec: The error class of the error (enum mvtwsi_error_class).
+ * @lc: The last value of the control register.
+ * @ls: The last value of the status register.
+ * @es: The expected value of the status register.
+ * @return The generated error code.
+ */
+inline uint mvtwsi_error(uint ec, uint lc, uint ls, uint es)
+{
+ return ((ec << 24) & 0xFF000000)
+ | ((lc << 16) & 0x00FF0000)
+ | ((ls << 8) & 0x0000FF00)
+ | (es & 0xFF);
+}
/*
- * Wait for IFLG to raise, or return 'timeout'; then if status is as expected,
- * return 0 (ok) or return 'wrong status'.
+ * twsi_wait() - Wait for I2C bus interrupt flag and check status, or time out.
+ *
+ * @return Zero if status is as expected, or a non-zero code if either a time
+ * out occurred, or the status was not the expected one.
*/
-static int twsi_wait(struct i2c_adapter *adap, int expected_status)
+static int twsi_wait(struct mvtwsi_registers *twsi, int expected_status,
+ uint tick)
{
- struct mvtwsi_registers *twsi = twsi_get_base(adap);
int control, status;
int timeout = 1000;
@@ -173,105 +264,140 @@ static int twsi_wait(struct i2c_adapter *adap, int expected_status)
if (status == expected_status)
return 0;
else
- return MVTWSI_ERROR(
+ return mvtwsi_error(
MVTWSI_ERROR_WRONG_STATUS,
control, status, expected_status);
}
- udelay(10); /* one clock cycle at 100 kHz */
+ ndelay(tick); /* One clock cycle */
} while (timeout--);
status = readl(&twsi->status);
- return MVTWSI_ERROR(
- MVTWSI_ERROR_TIMEOUT, control, status, expected_status);
+ return mvtwsi_error(MVTWSI_ERROR_TIMEOUT, control, status,
+ expected_status);
}
/*
- * Assert the START condition, either in a single I2C transaction
- * or inside back-to-back ones (repeated starts).
+ * twsi_start() - Assert a START condition on the bus.
+ *
+ * This function is used in both single I2C transactions and inside
+ * back-to-back transactions (repeated starts).
+ *
+ * @twsi: The MVTWSI register structure to use.
+ * @expected_status: The I2C bus status expected to be asserted after the
+ * operation completion.
+ * @tick: The duration of a clock cycle at the current I2C speed.
+ * @return Zero if status is as expected, or a non-zero code if either a time
+ * out occurred or the status was not the expected one.
*/
-static int twsi_start(struct i2c_adapter *adap, int expected_status, u8 *flags)
+static int twsi_start(struct mvtwsi_registers *twsi, int expected_status,
+ uint tick)
{
- struct mvtwsi_registers *twsi = twsi_get_base(adap);
-
- /* globally set TWSIEN in case it was not */
- *flags |= MVTWSI_CONTROL_TWSIEN;
- /* assert START */
- writel(*flags | MVTWSI_CONTROL_START |
- MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
- /* wait for controller to process START */
- return twsi_wait(adap, expected_status);
+ /* Assert START */
+ writel(MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_START |
+ MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
+ /* Wait for controller to process START */
+ return twsi_wait(twsi, expected_status, tick);
}
/*
- * Send a byte (i2c address or data).
+ * twsi_send() - Send a byte on the I2C bus.
+ *
+ * The byte may be part of an address byte or data.
+ *
+ * @twsi: The MVTWSI register structure to use.
+ * @byte: The byte to send.
+ * @expected_status: The I2C bus status expected to be asserted after the
+ * operation completion.
+ * @tick: The duration of a clock cycle at the current I2C speed.
+ * @return Zero if status is as expected, or a non-zero code if either a time
+ * out occurred or the status was not the expected one.
*/
-static int twsi_send(struct i2c_adapter *adap, u8 byte, int expected_status,
- u8 *flags)
+static int twsi_send(struct mvtwsi_registers *twsi, u8 byte,
+ int expected_status, uint tick)
{
- struct mvtwsi_registers *twsi = twsi_get_base(adap);
-
- /* put byte in data register for sending */
+ /* Write byte to data register for sending */
writel(byte, &twsi->data);
- /* clear any pending interrupt -- that'll cause sending */
- writel(*flags | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
- /* wait for controller to receive byte and check ACK */
- return twsi_wait(adap, expected_status);
+ /* Clear any pending interrupt -- that will cause sending */
+ writel(MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_CLEAR_IFLG,
+ &twsi->control);
+ /* Wait for controller to receive byte, and check ACK */
+ return twsi_wait(twsi, expected_status, tick);
}
/*
- * Receive a byte.
- * Global mvtwsi_control_flags variable says if we should ack or nak.
+ * twsi_recv() - Receive a byte on the I2C bus.
+ *
+ * The static variable mvtwsi_control_flags controls whether we ack or nak.
+ *
+ * @twsi: The MVTWSI register structure to use.
+ * @byte: The byte to send.
+ * @ack_flag: Flag that determines whether the received byte should
+ * be acknowledged by the controller or not (sent ACK/NAK).
+ * @tick: The duration of a clock cycle at the current I2C speed.
+ * @return Zero if status is as expected, or a non-zero code if either a time
+ * out occurred or the status was not the expected one.
*/
-static int twsi_recv(struct i2c_adapter *adap, u8 *byte, u8 *flags)
+static int twsi_recv(struct mvtwsi_registers *twsi, u8 *byte, int ack_flag,
+ uint tick)
{
- struct mvtwsi_registers *twsi = twsi_get_base(adap);
- int expected_status, status;
-
- /* compute expected status based on ACK bit in global control flags */
- if (*flags & MVTWSI_CONTROL_ACK)
- expected_status = MVTWSI_STATUS_DATA_R_ACK;
- else
- expected_status = MVTWSI_STATUS_DATA_R_NAK;
- /* acknowledge *previous state* and launch receive */
- writel(*flags | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
- /* wait for controller to receive byte and assert ACK or NAK */
- status = twsi_wait(adap, expected_status);
- /* if we did receive expected byte then store it */
+ int expected_status, status, control;
+
+ /* Compute expected status based on passed ACK flag */
+ expected_status = ack_flag ? MVTWSI_STATUS_DATA_R_ACK :
+ MVTWSI_STATUS_DATA_R_NAK;
+ /* Acknowledge *previous state*, and launch receive */
+ control = MVTWSI_CONTROL_TWSIEN;
+ control |= ack_flag == MVTWSI_READ_ACK ? MVTWSI_CONTROL_ACK : 0;
+ writel(control | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
+ /* Wait for controller to receive byte, and assert ACK or NAK */
+ status = twsi_wait(twsi, expected_status, tick);
+ /* If we did receive the expected byte, store it */
if (status == 0)
*byte = readl(&twsi->data);
- /* return status */
return status;
}
/*
- * Assert the STOP condition.
- * This is also used to force the bus back in idle (SDA=SCL=1).
+ * twsi_stop() - Assert a STOP condition on the bus.
+ *
+ * This function is also used to force the bus back to idle state (SDA =
+ * SCL = 1).
+ *
+ * @twsi: The MVTWSI register structure to use.
+ * @tick: The duration of a clock cycle at the current I2C speed.
+ * @return Zero if the operation succeeded, or a non-zero code if a time out
+ * occurred.
*/
-static int twsi_stop(struct i2c_adapter *adap, int status)
+static int twsi_stop(struct mvtwsi_registers *twsi, uint tick)
{
- struct mvtwsi_registers *twsi = twsi_get_base(adap);
int control, stop_status;
+ int status = 0;
int timeout = 1000;
- /* assert STOP */
+ /* Assert STOP */
control = MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_STOP;
writel(control | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
- /* wait for IDLE; IFLG won't rise so twsi_wait() is no use. */
+ /* Wait for IDLE; IFLG won't rise, so we can't use twsi_wait() */
do {
stop_status = readl(&twsi->status);
if (stop_status == MVTWSI_STATUS_IDLE)
break;
- udelay(10); /* one clock cycle at 100 kHz */
+ ndelay(tick); /* One clock cycle */
} while (timeout--);
control = readl(&twsi->control);
if (stop_status != MVTWSI_STATUS_IDLE)
- if (status == 0)
- status = MVTWSI_ERROR(
- MVTWSI_ERROR_TIMEOUT,
- control, status, MVTWSI_STATUS_IDLE);
+ status = mvtwsi_error(MVTWSI_ERROR_TIMEOUT,
+ control, status, MVTWSI_STATUS_IDLE);
return status;
}
-static unsigned int twsi_calc_freq(const int n, const int m)
+/*
+ * twsi_calc_freq() - Compute I2C frequency depending on m and n parameters.
+ *
+ * @n: Parameter 'n' for the frequency calculation algorithm.
+ * @m: Parameter 'm' for the frequency calculation algorithm.
+ * @return The I2C frequency corresponding to the passed m and n parameters.
+ */
+static uint twsi_calc_freq(const int n, const int m)
{
#ifdef CONFIG_SUNXI
return CONFIG_SYS_TCLK / (10 * (m + 1) * (1 << n));
@@ -281,176 +407,303 @@ static unsigned int twsi_calc_freq(const int n, const int m)
}
/*
- * Reset controller.
- * Controller reset also resets the baud rate and slave address, so
- * they must be re-established afterwards.
+ * twsi_reset() - Reset the I2C controller.
+ *
+ * Resetting the controller also resets the baud rate and slave address, hence
+ * they must be re-established after the reset.
+ *
+ * @twsi: The MVTWSI register structure to use.
*/
-static void twsi_reset(struct i2c_adapter *adap)
+static void twsi_reset(struct mvtwsi_registers *twsi)
{
- struct mvtwsi_registers *twsi = twsi_get_base(adap);
-
- /* reset controller */
+ /* Reset controller */
writel(0, &twsi->soft_reset);
- /* wait 2 ms -- this is what the Marvell LSP does */
+ /* Wait 2 ms -- this is what the Marvell LSP does */
udelay(20000);
}
/*
- * I2C init called by cmd_i2c when doing 'i2c reset'.
- * Sets baud to the highest possible value not exceeding requested one.
+ * __twsi_i2c_set_bus_speed() - Set the speed of the I2C controller.
+ *
+ * This function sets baud rate to the highest possible value that does not
+ * exceed the requested rate.
+ *
+ * @twsi: The MVTWSI register structure to use.
+ * @requested_speed: The desired frequency the controller should run at
+ * in Hz.
+ * @return The actual frequency the controller was configured to.
*/
-static unsigned int twsi_i2c_set_bus_speed(struct i2c_adapter *adap,
- unsigned int requested_speed)
+static uint __twsi_i2c_set_bus_speed(struct mvtwsi_registers *twsi,
+ uint requested_speed)
{
- struct mvtwsi_registers *twsi = twsi_get_base(adap);
- unsigned int tmp_speed, highest_speed, n, m;
- unsigned int baud = 0x44; /* baudrate at controller reset */
+ uint tmp_speed, highest_speed, n, m;
+ uint baud = 0x44; /* Baud rate after controller reset */
- /* use actual speed to collect progressively higher values */
highest_speed = 0;
- /* compute m, n setting for highest speed not above requested speed */
+ /* Successively try m, n combinations, and use the combination
+ * resulting in the largest speed that's not above the requested
+ * speed */
for (n = 0; n < 8; n++) {
for (m = 0; m < 16; m++) {
tmp_speed = twsi_calc_freq(n, m);
- if ((tmp_speed <= requested_speed)
- && (tmp_speed > highest_speed)) {
+ if ((tmp_speed <= requested_speed) &&
+ (tmp_speed > highest_speed)) {
highest_speed = tmp_speed;
baud = (m << 3) | n;
}
}
}
writel(baud, &twsi->baudrate);
- return 0;
+
+ /* Wait for controller for one tick */
+#ifdef CONFIG_DM_I2C
+ ndelay(calc_tick(highest_speed));
+#else
+ ndelay(10000);
+#endif
+ return highest_speed;
}
-static void twsi_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
+/*
+ * __twsi_i2c_init() - Initialize the I2C controller.
+ *
+ * @twsi: The MVTWSI register structure to use.
+ * @speed: The initial frequency the controller should run at
+ * in Hz.
+ * @slaveadd: The I2C address to be set for the I2C master.
+ * @actual_speed: A output parameter that receives the actual frequency
+ * in Hz the controller was set to by the function.
+ * @return Zero if the operation succeeded, or a non-zero code if a time out
+ * occurred.
+ */
+static void __twsi_i2c_init(struct mvtwsi_registers *twsi, int speed,
+ int slaveadd, uint *actual_speed)
{
- struct mvtwsi_registers *twsi = twsi_get_base(adap);
-
- /* reset controller */
- twsi_reset(adap);
- /* set speed */
- twsi_i2c_set_bus_speed(adap, speed);
- /* set slave address even though we don't use it */
+ /* Reset controller */
+ twsi_reset(twsi);
+ /* Set speed */
+ *actual_speed = __twsi_i2c_set_bus_speed(twsi, speed);
+ /* Set slave address; even though we don't use it */
writel(slaveadd, &twsi->slave_address);
writel(0, &twsi->xtnd_slave_addr);
- /* assert STOP but don't care for the result */
- (void) twsi_stop(adap, 0);
+ /* Assert STOP, but don't care for the result */
+#ifdef CONFIG_DM_I2C
+ (void) twsi_stop(twsi, calc_tick(*actual_speed));
+#else
+ (void) twsi_stop(twsi, 10000);
+#endif
}
/*
- * Begin I2C transaction with expected start status, at given address.
- * Common to i2c_probe, i2c_read and i2c_write.
- * Expected address status will derive from direction bit (bit 0) in addr.
+ * i2c_begin() - Start a I2C transaction.
+ *
+ * Begin a I2C transaction with a given expected start status and chip address.
+ * A START is asserted, and the address byte is sent to the I2C controller. The
+ * expected address status will be derived from the direction bit (bit 0) of
+ * the address byte.
+ *
+ * @twsi: The MVTWSI register structure to use.
+ * @expected_start_status: The I2C status the controller is expected to
+ * assert after the address byte was sent.
+ * @addr: The address byte to be sent.
+ * @tick: The duration of a clock cycle at the current
+ * I2C speed.
+ * @return Zero if the operation succeeded, or a non-zero code if a time out or
+ * unexpected I2C status occurred.
*/
-static int i2c_begin(struct i2c_adapter *adap, int expected_start_status,
- u8 addr, u8 *flags)
+static int i2c_begin(struct mvtwsi_registers *twsi, int expected_start_status,
+ u8 addr, uint tick)
{
int status, expected_addr_status;
- /* compute expected address status from direction bit in addr */
- if (addr & 1) /* reading */
+ /* Compute the expected address status from the direction bit in
+ * the address byte */
+ if (addr & 1) /* Reading */
expected_addr_status = MVTWSI_STATUS_ADDR_R_ACK;
- else /* writing */
+ else /* Writing */
expected_addr_status = MVTWSI_STATUS_ADDR_W_ACK;
- /* assert START */
- status = twsi_start(adap, expected_start_status, flags);
- /* send out the address if the start went well */
+ /* Assert START */
+ status = twsi_start(twsi, expected_start_status, tick);
+ /* Send out the address if the start went well */
if (status == 0)
- status = twsi_send(adap, addr, expected_addr_status,
- flags);
- /* return ok or status of first failure to caller */
+ status = twsi_send(twsi, addr, expected_addr_status, tick);
+ /* Return 0, or the status of the first failure */
return status;
}
/*
- * I2C probe called by cmd_i2c when doing 'i2c probe'.
- * Begin read, nak data byte, end.
+ * __twsi_i2c_probe_chip() - Probe the given I2C chip address.
+ *
+ * This function begins a I2C read transaction, does a dummy read and NAKs; if
+ * the procedure succeeds, the chip is considered to be present.
+ *
+ * @twsi: The MVTWSI register structure to use.
+ * @chip: The chip address to probe.
+ * @tick: The duration of a clock cycle at the current I2C speed.
+ * @return Zero if the operation succeeded, or a non-zero code if a time out or
+ * unexpected I2C status occurred.
*/
-static int twsi_i2c_probe(struct i2c_adapter *adap, uchar chip)
+static int __twsi_i2c_probe_chip(struct mvtwsi_registers *twsi, uchar chip,
+ uint tick)
{
u8 dummy_byte;
- u8 flags = 0;
int status;
- /* begin i2c read */
- status = i2c_begin(adap, MVTWSI_STATUS_START, (chip << 1) | 1, &flags);
- /* dummy read was accepted: receive byte but NAK it. */
+ /* Begin i2c read */
+ status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1) | 1, tick);
+ /* Dummy read was accepted: receive byte, but NAK it. */
if (status == 0)
- status = twsi_recv(adap, &dummy_byte, &flags);
+ status = twsi_recv(twsi, &dummy_byte, MVTWSI_READ_NAK, tick);
/* Stop transaction */
- twsi_stop(adap, 0);
- /* return 0 or status of first failure */
+ twsi_stop(twsi, tick);
+ /* Return 0, or the status of the first failure */
return status;
}
/*
- * I2C read called by cmd_i2c when doing 'i2c read' and by cmd_eeprom.c
- * Begin write, send address byte(s), begin read, receive data bytes, end.
- *
- * NOTE: some EEPROMS want a stop right before the second start, while
- * some will choke if it is there. Deciding which we should do is eeprom
- * stuff, not i2c, but at the moment the APIs won't let us put it in
- * cmd_eeprom, so we have to choose here, and for the moment that'll be
- * a repeated start without a preceding stop.
+ * __twsi_i2c_read() - Read data from a I2C chip.
+ *
+ * This function begins a I2C write transaction, and transmits the address
+ * bytes; then begins a I2C read transaction, and receives the data bytes.
+ *
+ * NOTE: Some devices want a stop right before the second start, while some
+ * will choke if it is there. Since deciding this is not yet supported in
+ * higher level APIs, we need to make a decision here, and for the moment that
+ * will be a repeated start without a preceding stop.
+ *
+ * @twsi: The MVTWSI register structure to use.
+ * @chip: The chip address to read from.
+ * @addr: The address bytes to send.
+ * @alen: The length of the address bytes in bytes.
+ * @data: The buffer to receive the data read from the chip (has to have
+ * a size of at least 'length' bytes).
+ * @length: The amount of data to be read from the chip in bytes.
+ * @tick: The duration of a clock cycle at the current I2C speed.
+ * @return Zero if the operation succeeded, or a non-zero code if a time out or
+ * unexpected I2C status occurred.
*/
-static int twsi_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
- int alen, uchar *data, int length)
+static int __twsi_i2c_read(struct mvtwsi_registers *twsi, uchar chip,
+ u8 *addr, int alen, uchar *data, int length,
+ uint tick)
{
- int status;
- u8 flags = 0;
-
- /* begin i2c write to send the address bytes */
- status = i2c_begin(adap, MVTWSI_STATUS_START, (chip << 1), &flags);
- /* send addr bytes */
- while ((status == 0) && alen--)
- status = twsi_send(adap, addr >> (8*alen),
- MVTWSI_STATUS_DATA_W_ACK, &flags);
- /* begin i2c read to receive eeprom data bytes */
- if (status == 0)
- status = i2c_begin(adap, MVTWSI_STATUS_REPEATED_START,
- (chip << 1) | 1, &flags);
- /* prepare ACK if at least one byte must be received */
- if (length > 0)
- flags |= MVTWSI_CONTROL_ACK;
- /* now receive actual bytes */
- while ((status == 0) && length--) {
- /* reset NAK if we if no more to read now */
- if (length == 0)
- flags &= ~MVTWSI_CONTROL_ACK;
- /* read current byte */
- status = twsi_recv(adap, data++, &flags);
+ int status = 0;
+ int stop_status;
+ int expected_start = MVTWSI_STATUS_START;
+
+ if (alen > 0) {
+ /* Begin i2c write to send the address bytes */
+ status = i2c_begin(twsi, expected_start, (chip << 1), tick);
+ /* Send address bytes */
+ while ((status == 0) && alen--)
+ status = twsi_send(twsi, *(addr++),
+ MVTWSI_STATUS_DATA_W_ACK, tick);
+ /* Send repeated STARTs after the initial START */
+ expected_start = MVTWSI_STATUS_REPEATED_START;
}
+ /* Begin i2c read to receive data bytes */
+ if (status == 0)
+ status = i2c_begin(twsi, expected_start, (chip << 1) | 1, tick);
+ /* Receive actual data bytes; set NAK if we if we have nothing more to
+ * read */
+ while ((status == 0) && length--)
+ status = twsi_recv(twsi, data++,
+ length > 0 ?
+ MVTWSI_READ_ACK : MVTWSI_READ_NAK, tick);
/* Stop transaction */
- status = twsi_stop(adap, status);
- /* return 0 or status of first failure */
- return status;
+ stop_status = twsi_stop(twsi, tick);
+ /* Return 0, or the status of the first failure */
+ return status != 0 ? status : stop_status;
}
/*
- * I2C write called by cmd_i2c when doing 'i2c write' and by cmd_eeprom.c
- * Begin write, send address byte(s), send data bytes, end.
+ * __twsi_i2c_write() - Send data to a I2C chip.
+ *
+ * This function begins a I2C write transaction, and transmits the address
+ * bytes; then begins a new I2C write transaction, and sends the data bytes.
+ *
+ * @twsi: The MVTWSI register structure to use.
+ * @chip: The chip address to read from.
+ * @addr: The address bytes to send.
+ * @alen: The length of the address bytes in bytes.
+ * @data: The buffer containing the data to be sent to the chip.
+ * @length: The length of data to be sent to the chip in bytes.
+ * @tick: The duration of a clock cycle at the current I2C speed.
+ * @return Zero if the operation succeeded, or a non-zero code if a time out or
+ * unexpected I2C status occurred.
*/
-static int twsi_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
- int alen, uchar *data, int length)
+static int __twsi_i2c_write(struct mvtwsi_registers *twsi, uchar chip,
+ u8 *addr, int alen, uchar *data, int length,
+ uint tick)
{
- int status;
- u8 flags = 0;
-
- /* begin i2c write to send the eeprom adress bytes then data bytes */
- status = i2c_begin(adap, MVTWSI_STATUS_START, (chip << 1), &flags);
- /* send addr bytes */
- while ((status == 0) && alen--)
- status = twsi_send(adap, addr >> (8*alen),
- MVTWSI_STATUS_DATA_W_ACK, &flags);
- /* send data bytes */
+ int status, stop_status;
+
+ /* Begin i2c write to send first the address bytes, then the
+ * data bytes */
+ status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1), tick);
+ /* Send address bytes */
+ while ((status == 0) && (alen-- > 0))
+ status = twsi_send(twsi, *(addr++), MVTWSI_STATUS_DATA_W_ACK,
+ tick);
+ /* Send data bytes */
while ((status == 0) && (length-- > 0))
- status = twsi_send(adap, *(data++), MVTWSI_STATUS_DATA_W_ACK,
- &flags);
+ status = twsi_send(twsi, *(data++), MVTWSI_STATUS_DATA_W_ACK,
+ tick);
/* Stop transaction */
- status = twsi_stop(adap, status);
- /* return 0 or status of first failure */
- return status;
+ stop_status = twsi_stop(twsi, tick);
+ /* Return 0, or the status of the first failure */
+ return status != 0 ? status : stop_status;
+}
+
+#ifndef CONFIG_DM_I2C
+static void twsi_i2c_init(struct i2c_adapter *adap, int speed,
+ int slaveadd)
+{
+ struct mvtwsi_registers *twsi = twsi_get_base(adap);
+ __twsi_i2c_init(twsi, speed, slaveadd, NULL);
+}
+
+static uint twsi_i2c_set_bus_speed(struct i2c_adapter *adap,
+ uint requested_speed)
+{
+ struct mvtwsi_registers *twsi = twsi_get_base(adap);
+ __twsi_i2c_set_bus_speed(twsi, requested_speed);
+ return 0;
+}
+
+static int twsi_i2c_probe(struct i2c_adapter *adap, uchar chip)
+{
+ struct mvtwsi_registers *twsi = twsi_get_base(adap);
+ return __twsi_i2c_probe_chip(twsi, chip, 10000);
+}
+
+static int twsi_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
+ int alen, uchar *data, int length)
+{
+ struct mvtwsi_registers *twsi = twsi_get_base(adap);
+ u8 addr_bytes[4];
+
+ addr_bytes[0] = (addr >> 0) & 0xFF;
+ addr_bytes[1] = (addr >> 8) & 0xFF;
+ addr_bytes[2] = (addr >> 16) & 0xFF;
+ addr_bytes[3] = (addr >> 24) & 0xFF;
+
+ return __twsi_i2c_read(twsi, chip, addr_bytes, alen, data, length,
+ 10000);
+}
+
+static int twsi_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
+ int alen, uchar *data, int length)
+{
+ struct mvtwsi_registers *twsi = twsi_get_base(adap);
+ u8 addr_bytes[4];
+
+ addr_bytes[0] = (addr >> 0) & 0xFF;
+ addr_bytes[1] = (addr >> 8) & 0xFF;
+ addr_bytes[2] = (addr >> 16) & 0xFF;
+ addr_bytes[3] = (addr >> 24) & 0xFF;
+
+ return __twsi_i2c_write(twsi, chip, addr_bytes, alen, data, length,
+ 10000);
}
#ifdef CONFIG_I2C_MVTWSI_BASE0
@@ -494,3 +747,99 @@ U_BOOT_I2C_ADAP_COMPLETE(twsi5, twsi_i2c_init, twsi_i2c_probe,
CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 5)
#endif
+#else /* CONFIG_DM_I2C */
+
+static int mvtwsi_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
+ u32 chip_flags)
+{
+ struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
+ return __twsi_i2c_probe_chip(dev->base, chip_addr, dev->tick);
+}
+
+static int mvtwsi_i2c_set_bus_speed(struct udevice *bus, uint speed)
+{
+ struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
+
+ dev->speed = __twsi_i2c_set_bus_speed(dev->base, speed);
+ dev->tick = calc_tick(dev->speed);
+
+ return 0;
+}
+
+static int mvtwsi_i2c_ofdata_to_platdata(struct udevice *bus)
+{
+ struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
+
+ dev->base = dev_get_addr_ptr(bus);
+
+ if (!dev->base)
+ return -ENOMEM;
+
+ dev->index = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
+ "cell-index", -1);
+ dev->slaveadd = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
+ "u-boot,i2c-slave-addr", 0x0);
+ dev->speed = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
+ "clock-frequency", 100000);
+ return 0;
+}
+
+static int mvtwsi_i2c_probe(struct udevice *bus)
+{
+ struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
+ uint actual_speed;
+
+ __twsi_i2c_init(dev->base, dev->speed, dev->slaveadd, &actual_speed);
+ dev->speed = actual_speed;
+ dev->tick = calc_tick(dev->speed);
+ return 0;
+}
+
+static int mvtwsi_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
+{
+ struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
+ struct i2c_msg *dmsg, *omsg, dummy;
+
+ memset(&dummy, 0, sizeof(struct i2c_msg));
+
+ /* We expect either two messages (one with an offset and one with the
+ * actual data) or one message (just data or offset/data combined) */
+ if (nmsgs > 2 || nmsgs == 0) {
+ debug("%s: Only one or two messages are supported.", __func__);
+ return -1;
+ }
+
+ omsg = nmsgs == 1 ? &dummy : msg;
+ dmsg = nmsgs == 1 ? msg : msg + 1;
+
+ if (dmsg->flags & I2C_M_RD)
+ return __twsi_i2c_read(dev->base, dmsg->addr, omsg->buf,
+ omsg->len, dmsg->buf, dmsg->len,
+ dev->tick);
+ else
+ return __twsi_i2c_write(dev->base, dmsg->addr, omsg->buf,
+ omsg->len, dmsg->buf, dmsg->len,
+ dev->tick);
+}
+
+static const struct dm_i2c_ops mvtwsi_i2c_ops = {
+ .xfer = mvtwsi_i2c_xfer,
+ .probe_chip = mvtwsi_i2c_probe_chip,
+ .set_bus_speed = mvtwsi_i2c_set_bus_speed,
+};
+
+static const struct udevice_id mvtwsi_i2c_ids[] = {
+ { .compatible = "marvell,mv64xxx-i2c", },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(i2c_mvtwsi) = {
+ .name = "i2c_mvtwsi",
+ .id = UCLASS_I2C,
+ .of_match = mvtwsi_i2c_ids,
+ .probe = mvtwsi_i2c_probe,
+ .ofdata_to_platdata = mvtwsi_i2c_ofdata_to_platdata,
+ .priv_auto_alloc_size = sizeof(struct mvtwsi_i2c_dev),
+ .ops = &mvtwsi_i2c_ops,
+};
+#endif /* CONFIG_DM_I2C */
diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c
index a7f3fb4..0006343 100644
--- a/drivers/i2c/omap24xx_i2c.c
+++ b/drivers/i2c/omap24xx_i2c.c
@@ -39,6 +39,7 @@
*/
#include <common.h>
+#include <dm.h>
#include <i2c.h>
#include <asm/arch/i2c.h>
@@ -53,10 +54,14 @@ DECLARE_GLOBAL_DATA_PTR;
/* Absolutely safe for status update at 100 kHz I2C: */
#define I2C_WAIT 200
-static int wait_for_bb(struct i2c_adapter *adap);
-static struct i2c *omap24_get_base(struct i2c_adapter *adap);
-static u16 wait_for_event(struct i2c_adapter *adap);
-static void flush_fifo(struct i2c_adapter *adap);
+struct omap_i2c {
+ struct udevice *clk;
+ struct i2c *regs;
+ unsigned int speed;
+ int waitdelay;
+ int clk_id;
+};
+
static int omap24_i2c_findpsc(u32 *pscl, u32 *psch, uint speed)
{
unsigned int sampleclk, prescaler;
@@ -90,9 +95,96 @@ static int omap24_i2c_findpsc(u32 *pscl, u32 *psch, uint speed)
}
return -1;
}
-static uint omap24_i2c_setspeed(struct i2c_adapter *adap, uint speed)
+
+/*
+ * Wait for the bus to be free by checking the Bus Busy (BB)
+ * bit to become clear
+ */
+static int wait_for_bb(struct i2c *i2c_base, int waitdelay)
+{
+ int timeout = I2C_TIMEOUT;
+ u16 stat;
+
+ writew(0xFFFF, &i2c_base->stat); /* clear current interrupts...*/
+#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
+ while ((stat = readw(&i2c_base->stat) & I2C_STAT_BB) && timeout--) {
+#else
+ /* Read RAW status */
+ while ((stat = readw(&i2c_base->irqstatus_raw) &
+ I2C_STAT_BB) && timeout--) {
+#endif
+ writew(stat, &i2c_base->stat);
+ udelay(waitdelay);
+ }
+
+ if (timeout <= 0) {
+ printf("Timed out in wait_for_bb: status=%04x\n",
+ stat);
+ return 1;
+ }
+ writew(0xFFFF, &i2c_base->stat); /* clear delayed stuff*/
+ return 0;
+}
+
+/*
+ * Wait for the I2C controller to complete current action
+ * and update status
+ */
+static u16 wait_for_event(struct i2c *i2c_base, int waitdelay)
+{
+ u16 status;
+ int timeout = I2C_TIMEOUT;
+
+ do {
+ udelay(waitdelay);
+#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
+ status = readw(&i2c_base->stat);
+#else
+ /* Read RAW status */
+ status = readw(&i2c_base->irqstatus_raw);
+#endif
+ } while (!(status &
+ (I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY |
+ I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK |
+ I2C_STAT_AL)) && timeout--);
+
+ if (timeout <= 0) {
+ printf("Timed out in wait_for_event: status=%04x\n",
+ status);
+ /*
+ * If status is still 0 here, probably the bus pads have
+ * not been configured for I2C, and/or pull-ups are missing.
+ */
+ printf("Check if pads/pull-ups of bus are properly configured\n");
+ writew(0xFFFF, &i2c_base->stat);
+ status = 0;
+ }
+
+ return status;
+}
+
+static void flush_fifo(struct i2c *i2c_base)
+{
+ u16 stat;
+
+ /*
+ * note: if you try and read data when its not there or ready
+ * you get a bus error
+ */
+ while (1) {
+ stat = readw(&i2c_base->stat);
+ if (stat == I2C_STAT_RRDY) {
+ readb(&i2c_base->data);
+ writew(I2C_STAT_RRDY, &i2c_base->stat);
+ udelay(1000);
+ } else
+ break;
+ }
+}
+
+static int __omap24_i2c_setspeed(struct i2c *i2c_base, uint speed,
+ int *waitdelay)
{
- struct i2c *i2c_base = omap24_get_base(adap);
int psc, fsscll = 0, fssclh = 0;
int hsscll = 0, hssclh = 0;
u32 scll = 0, sclh = 0;
@@ -142,8 +234,7 @@ static uint omap24_i2c_setspeed(struct i2c_adapter *adap, uint speed)
}
}
- adap->speed = speed;
- adap->waitdelay = (10000000 / speed) * 2; /* wait for 20 clkperiods */
+ *waitdelay = (10000000 / speed) * 2; /* wait for 20 clkperiods */
writew(0, &i2c_base->con);
writew(psc, &i2c_base->psc);
writew(scll, &i2c_base->scll);
@@ -154,9 +245,8 @@ static uint omap24_i2c_setspeed(struct i2c_adapter *adap, uint speed)
return 0;
}
-static void omap24_i2c_deblock(struct i2c_adapter *adap)
+static void omap24_i2c_deblock(struct i2c *i2c_base)
{
- struct i2c *i2c_base = omap24_get_base(adap);
int i;
u16 systest;
u16 orgsystest;
@@ -200,9 +290,9 @@ static void omap24_i2c_deblock(struct i2c_adapter *adap)
writew(orgsystest, &i2c_base->systest);
}
-static void omap24_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
+static void __omap24_i2c_init(struct i2c *i2c_base, int speed, int slaveadd,
+ int *waitdelay)
{
- struct i2c *i2c_base = omap24_get_base(adap);
int timeout = I2C_TIMEOUT;
int deblock = 1;
@@ -224,7 +314,7 @@ retry:
udelay(1000);
}
- if (0 != omap24_i2c_setspeed(adap, speed)) {
+ if (0 != __omap24_i2c_setspeed(i2c_base, speed, waitdelay)) {
printf("ERROR: failed to setup I2C bus-speed!\n");
return;
}
@@ -241,45 +331,24 @@ retry:
I2C_IE_NACK_IE | I2C_IE_AL_IE, &i2c_base->ie);
#endif
udelay(1000);
- flush_fifo(adap);
+ flush_fifo(i2c_base);
writew(0xFFFF, &i2c_base->stat);
/* Handle possible failed I2C state */
- if (wait_for_bb(adap))
+ if (wait_for_bb(i2c_base, *waitdelay))
if (deblock == 1) {
- omap24_i2c_deblock(adap);
+ omap24_i2c_deblock(i2c_base);
deblock = 0;
goto retry;
}
}
-static void flush_fifo(struct i2c_adapter *adap)
-{
- struct i2c *i2c_base = omap24_get_base(adap);
- u16 stat;
-
- /*
- * note: if you try and read data when its not there or ready
- * you get a bus error
- */
- while (1) {
- stat = readw(&i2c_base->stat);
- if (stat == I2C_STAT_RRDY) {
- readb(&i2c_base->data);
- writew(I2C_STAT_RRDY, &i2c_base->stat);
- udelay(1000);
- } else
- break;
- }
-}
-
/*
* i2c_probe: Use write access. Allows to identify addresses that are
* write-only (like the config register of dual-port EEPROMs)
*/
-static int omap24_i2c_probe(struct i2c_adapter *adap, uchar chip)
+static int __omap24_i2c_probe(struct i2c *i2c_base, int waitdelay, uchar chip)
{
- struct i2c *i2c_base = omap24_get_base(adap);
u16 status;
int res = 1; /* default = fail */
@@ -287,7 +356,7 @@ static int omap24_i2c_probe(struct i2c_adapter *adap, uchar chip)
return res;
/* Wait until bus is free */
- if (wait_for_bb(adap))
+ if (wait_for_bb(i2c_base, waitdelay))
return res;
/* No data transfer, slave addr only */
@@ -296,7 +365,7 @@ static int omap24_i2c_probe(struct i2c_adapter *adap, uchar chip)
writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
I2C_CON_STP, &i2c_base->con);
- status = wait_for_event(adap);
+ status = wait_for_event(i2c_base, waitdelay);
if ((status & ~I2C_STAT_XRDY) == 0 || (status & I2C_STAT_AL)) {
/*
@@ -306,8 +375,8 @@ static int omap24_i2c_probe(struct i2c_adapter *adap, uchar chip)
* following 'if' section:
*/
if (status == I2C_STAT_XRDY)
- printf("i2c_probe: pads on bus %d probably not configured (status=0x%x)\n",
- adap->hwadapnr, status);
+ printf("i2c_probe: pads on bus probably not configured (status=0x%x)\n",
+ status);
goto pr_exit;
}
@@ -315,7 +384,7 @@ static int omap24_i2c_probe(struct i2c_adapter *adap, uchar chip)
/* Check for ACK (!NAK) */
if (!(status & I2C_STAT_NACK)) {
res = 0; /* Device found */
- udelay(adap->waitdelay);/* Required by AM335X in SPL */
+ udelay(waitdelay);/* Required by AM335X in SPL */
/* Abort transfer (force idle state) */
writew(I2C_CON_MST | I2C_CON_TRX, &i2c_base->con); /* Reset */
udelay(1000);
@@ -323,7 +392,7 @@ static int omap24_i2c_probe(struct i2c_adapter *adap, uchar chip)
I2C_CON_STP, &i2c_base->con); /* STP */
}
pr_exit:
- flush_fifo(adap);
+ flush_fifo(i2c_base);
writew(0xFFFF, &i2c_base->stat);
return res;
}
@@ -341,10 +410,9 @@ pr_exit:
* or that do not need a register address at all (such as some clock
* distributors).
*/
-static int omap24_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
- int alen, uchar *buffer, int len)
+static int __omap24_i2c_read(struct i2c *i2c_base, int waitdelay, uchar chip,
+ uint addr, int alen, uchar *buffer, int len)
{
- struct i2c *i2c_base = omap24_get_base(adap);
int i2c_error = 0;
u16 status;
@@ -389,7 +457,7 @@ static int omap24_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
#endif
/* Wait until bus not busy */
- if (wait_for_bb(adap))
+ if (wait_for_bb(i2c_base, waitdelay))
return 1;
/* Zero, one or two bytes reg address (offset) */
@@ -410,12 +478,12 @@ static int omap24_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
#endif
/* Send register offset */
while (1) {
- status = wait_for_event(adap);
+ status = wait_for_event(i2c_base, waitdelay);
/* Try to identify bus that is not padconf'd for I2C */
if (status == I2C_STAT_XRDY) {
i2c_error = 2;
- printf("i2c_read (addr phase): pads on bus %d probably not configured (status=0x%x)\n",
- adap->hwadapnr, status);
+ printf("i2c_read (addr phase): pads on bus probably not configured (status=0x%x)\n",
+ status);
goto rd_exit;
}
if (status == 0 || (status & I2C_STAT_NACK)) {
@@ -450,7 +518,7 @@ static int omap24_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
/* Receive data */
while (1) {
- status = wait_for_event(adap);
+ status = wait_for_event(i2c_base, waitdelay);
/*
* Try to identify bus that is not padconf'd for I2C. This
* state could be left over from previous transactions if
@@ -458,8 +526,8 @@ static int omap24_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
*/
if (status == I2C_STAT_XRDY) {
i2c_error = 2;
- printf("i2c_read (data phase): pads on bus %d probably not configured (status=0x%x)\n",
- adap->hwadapnr, status);
+ printf("i2c_read (data phase): pads on bus probably not configured (status=0x%x)\n",
+ status);
goto rd_exit;
}
if (status == 0 || (status & I2C_STAT_NACK)) {
@@ -477,16 +545,15 @@ static int omap24_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
}
rd_exit:
- flush_fifo(adap);
+ flush_fifo(i2c_base);
writew(0xFFFF, &i2c_base->stat);
return i2c_error;
}
/* i2c_write: Address (reg offset) may be 0, 1 or 2 bytes long. */
-static int omap24_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
- int alen, uchar *buffer, int len)
+static int __omap24_i2c_write(struct i2c *i2c_base, int waitdelay, uchar chip,
+ uint addr, int alen, uchar *buffer, int len)
{
- struct i2c *i2c_base = omap24_get_base(adap);
int i;
u16 status;
int i2c_error = 0;
@@ -536,7 +603,7 @@ static int omap24_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
#endif
/* Wait until bus not busy */
- if (wait_for_bb(adap))
+ if (wait_for_bb(i2c_base, waitdelay))
return 1;
/* Start address phase - will write regoffset + len bytes data */
@@ -549,12 +616,12 @@ static int omap24_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
while (alen) {
/* Must write reg offset (one or two bytes) */
- status = wait_for_event(adap);
+ status = wait_for_event(i2c_base, waitdelay);
/* Try to identify bus that is not padconf'd for I2C */
if (status == I2C_STAT_XRDY) {
i2c_error = 2;
- printf("i2c_write: pads on bus %d probably not configured (status=0x%x)\n",
- adap->hwadapnr, status);
+ printf("i2c_write: pads on bus probably not configured (status=0x%x)\n",
+ status);
goto wr_exit;
}
if (status == 0 || (status & I2C_STAT_NACK)) {
@@ -576,7 +643,7 @@ static int omap24_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
}
/* Address phase is over, now write data */
for (i = 0; i < len; i++) {
- status = wait_for_event(adap);
+ status = wait_for_event(i2c_base, waitdelay);
if (status == 0 || (status & I2C_STAT_NACK)) {
i2c_error = 1;
printf("i2c_write: error waiting for data ACK (status=0x%x)\n",
@@ -598,87 +665,22 @@ static int omap24_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
* transferred on the bus.
*/
do {
- status = wait_for_event(adap);
+ status = wait_for_event(i2c_base, waitdelay);
} while (!(status & I2C_STAT_ARDY) && timeout--);
if (timeout <= 0)
printf("i2c_write: timed out writig last byte!\n");
wr_exit:
- flush_fifo(adap);
+ flush_fifo(i2c_base);
writew(0xFFFF, &i2c_base->stat);
return i2c_error;
}
+#ifndef CONFIG_DM_I2C
/*
- * Wait for the bus to be free by checking the Bus Busy (BB)
- * bit to become clear
- */
-static int wait_for_bb(struct i2c_adapter *adap)
-{
- struct i2c *i2c_base = omap24_get_base(adap);
- int timeout = I2C_TIMEOUT;
- u16 stat;
-
- writew(0xFFFF, &i2c_base->stat); /* clear current interrupts...*/
-#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
- while ((stat = readw(&i2c_base->stat) & I2C_STAT_BB) && timeout--) {
-#else
- /* Read RAW status */
- while ((stat = readw(&i2c_base->irqstatus_raw) &
- I2C_STAT_BB) && timeout--) {
-#endif
- writew(stat, &i2c_base->stat);
- udelay(adap->waitdelay);
- }
-
- if (timeout <= 0) {
- printf("Timed out in wait_for_bb: status=%04x\n",
- stat);
- return 1;
- }
- writew(0xFFFF, &i2c_base->stat); /* clear delayed stuff*/
- return 0;
-}
-
-/*
- * Wait for the I2C controller to complete current action
- * and update status
+ * The legacy I2C functions. These need to get removed once
+ * all users of this driver are converted to DM.
*/
-static u16 wait_for_event(struct i2c_adapter *adap)
-{
- struct i2c *i2c_base = omap24_get_base(adap);
- u16 status;
- int timeout = I2C_TIMEOUT;
-
- do {
- udelay(adap->waitdelay);
-#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
- status = readw(&i2c_base->stat);
-#else
- /* Read RAW status */
- status = readw(&i2c_base->irqstatus_raw);
-#endif
- } while (!(status &
- (I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY |
- I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK |
- I2C_STAT_AL)) && timeout--);
-
- if (timeout <= 0) {
- printf("Timed out in wait_for_event: status=%04x\n",
- status);
- /*
- * If status is still 0 here, probably the bus pads have
- * not been configured for I2C, and/or pull-ups are missing.
- */
- printf("Check if pads/pull-ups of bus %d are properly configured\n",
- adap->hwadapnr);
- writew(0xFFFF, &i2c_base->stat);
- status = 0;
- }
-
- return status;
-}
-
static struct i2c *omap24_get_base(struct i2c_adapter *adap)
{
switch (adap->hwadapnr) {
@@ -710,6 +712,56 @@ static struct i2c *omap24_get_base(struct i2c_adapter *adap)
return NULL;
}
+
+static int omap24_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
+ int alen, uchar *buffer, int len)
+{
+ struct i2c *i2c_base = omap24_get_base(adap);
+
+ return __omap24_i2c_read(i2c_base, adap->waitdelay, chip, addr,
+ alen, buffer, len);
+}
+
+
+static int omap24_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
+ int alen, uchar *buffer, int len)
+{
+ struct i2c *i2c_base = omap24_get_base(adap);
+
+ return __omap24_i2c_write(i2c_base, adap->waitdelay, chip, addr,
+ alen, buffer, len);
+}
+
+static uint omap24_i2c_setspeed(struct i2c_adapter *adap, uint speed)
+{
+ struct i2c *i2c_base = omap24_get_base(adap);
+ int ret;
+
+ ret = __omap24_i2c_setspeed(i2c_base, speed, &adap->waitdelay);
+ if (ret) {
+ error("%s: set i2c speed failed\n", __func__);
+ return ret;
+ }
+
+ adap->speed = speed;
+
+ return 0;
+}
+
+static void omap24_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
+{
+ struct i2c *i2c_base = omap24_get_base(adap);
+
+ return __omap24_i2c_init(i2c_base, speed, slaveadd, &adap->waitdelay);
+}
+
+static int omap24_i2c_probe(struct i2c_adapter *adap, uchar chip)
+{
+ struct i2c *i2c_base = omap24_get_base(adap);
+
+ return __omap24_i2c_probe(i2c_base, adap->waitdelay, chip);
+}
+
#if !defined(CONFIG_SYS_OMAP24_I2C_SPEED1)
#define CONFIG_SYS_OMAP24_I2C_SPEED1 CONFIG_SYS_OMAP24_I2C_SPEED
#endif
@@ -769,3 +821,92 @@ U_BOOT_I2C_ADAP_COMPLETE(omap24_4, omap24_i2c_init, omap24_i2c_probe,
#endif
#endif
#endif
+
+#else /* CONFIG_DM_I2C */
+
+static int omap_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
+{
+ struct omap_i2c *priv = dev_get_priv(bus);
+ int ret;
+
+ debug("i2c_xfer: %d messages\n", nmsgs);
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
+ if (msg->flags & I2C_M_RD) {
+ ret = __omap24_i2c_read(priv->regs, priv->waitdelay,
+ msg->addr, 0, 0, msg->buf,
+ msg->len);
+ } else {
+ ret = __omap24_i2c_write(priv->regs, priv->waitdelay,
+ msg->addr, 0, 0, msg->buf,
+ msg->len);
+ }
+ if (ret) {
+ debug("i2c_write: error sending\n");
+ return -EREMOTEIO;
+ }
+ }
+
+ return 0;
+}
+
+static int omap_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+ struct omap_i2c *priv = dev_get_priv(bus);
+
+ priv->speed = speed;
+
+ return __omap24_i2c_setspeed(priv->regs, speed, &priv->waitdelay);
+}
+
+static int omap_i2c_probe_chip(struct udevice *bus, uint chip_addr,
+ uint chip_flags)
+{
+ struct omap_i2c *priv = dev_get_priv(bus);
+
+ return __omap24_i2c_probe(priv->regs, priv->waitdelay, chip_addr);
+}
+
+static int omap_i2c_probe(struct udevice *bus)
+{
+ struct omap_i2c *priv = dev_get_priv(bus);
+
+ __omap24_i2c_init(priv->regs, priv->speed, 0, &priv->waitdelay);
+
+ return 0;
+}
+
+static int omap_i2c_ofdata_to_platdata(struct udevice *bus)
+{
+ struct omap_i2c *priv = dev_get_priv(bus);
+
+ priv->regs = map_physmem(dev_get_addr(bus), sizeof(void *),
+ MAP_NOCACHE);
+ priv->speed = CONFIG_SYS_OMAP24_I2C_SPEED;
+
+ return 0;
+}
+
+static const struct dm_i2c_ops omap_i2c_ops = {
+ .xfer = omap_i2c_xfer,
+ .probe_chip = omap_i2c_probe_chip,
+ .set_bus_speed = omap_i2c_set_bus_speed,
+};
+
+static const struct udevice_id omap_i2c_ids[] = {
+ { .compatible = "ti,omap4-i2c" },
+ { }
+};
+
+U_BOOT_DRIVER(i2c_omap) = {
+ .name = "i2c_omap",
+ .id = UCLASS_I2C,
+ .of_match = omap_i2c_ids,
+ .ofdata_to_platdata = omap_i2c_ofdata_to_platdata,
+ .probe = omap_i2c_probe,
+ .priv_auto_alloc_size = sizeof(struct omap_i2c),
+ .ops = &omap_i2c_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+#endif /* CONFIG_DM_I2C */
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index e0adb9b..dc8f2b6 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -61,6 +61,12 @@ config ZYNQ_SDHCI
help
Support for Arasan SDHCI host controller on Zynq/ZynqMP ARM SoCs platform
+config ROCKCHIP_SDHCI
+ bool "Arasan SDHCI controller for Rockchip support"
+ depends on DM_MMC && BLK && DM_MMC_OPS
+ help
+ Support for Arasan SDHCI host controller on Rockchip ARM SoCs platform
+
config MMC_UNIPHIER
bool "UniPhier SD/MMC Host Controller support"
depends on ARCH_UNIPHIER
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index b44a12e..18351fb 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_SPEAR_SDHCI) += spear_sdhci.o
obj-$(CONFIG_TEGRA_MMC) += tegra_mmc.o
obj-$(CONFIG_MMC_UNIPHIER) += uniphier-sd.o
obj-$(CONFIG_ZYNQ_SDHCI) += zynq_sdhci.o
+obj-$(CONFIG_ROCKCHIP_SDHCI) += rockchip_sdhci.o
ifdef CONFIG_SPL_BUILD
obj-$(CONFIG_SPL_MMC_BOOT) += fsl_esdhc_spl.o
diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c
new file mode 100644
index 0000000..023c29b
--- /dev/null
+++ b/drivers/mmc/rockchip_sdhci.c
@@ -0,0 +1,93 @@
+/*
+ * (C) Copyright 2016 Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * Rockchip SD Host Controller Interface
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <libfdt.h>
+#include <malloc.h>
+#include <sdhci.h>
+
+/* 400KHz is max freq for card ID etc. Use that as min */
+#define EMMC_MIN_FREQ 400000
+
+struct rockchip_sdhc_plat {
+ struct mmc_config cfg;
+ struct mmc mmc;
+};
+
+struct rockchip_sdhc {
+ struct sdhci_host host;
+ void *base;
+};
+
+static int arasan_sdhci_probe(struct udevice *dev)
+{
+ struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+ struct rockchip_sdhc_plat *plat = dev_get_platdata(dev);
+ struct rockchip_sdhc *prv = dev_get_priv(dev);
+ struct sdhci_host *host = &prv->host;
+ int ret;
+ u32 caps;
+
+ host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
+ host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD;
+
+ caps = sdhci_readl(host, SDHCI_CAPABILITIES);
+ ret = sdhci_setup_cfg(&plat->cfg, dev->name, host->bus_width,
+ caps, CONFIG_ROCKCHIP_SDHCI_MAX_FREQ, EMMC_MIN_FREQ,
+ host->version, host->quirks, 0);
+
+ host->mmc = &plat->mmc;
+ if (ret)
+ return ret;
+ host->mmc->priv = &prv->host;
+ host->mmc->dev = dev;
+ upriv->mmc = host->mmc;
+
+ return sdhci_probe(dev);
+}
+
+static int arasan_sdhci_ofdata_to_platdata(struct udevice *dev)
+{
+ struct sdhci_host *host = dev_get_priv(dev);
+
+ host->name = dev->name;
+ host->ioaddr = dev_get_addr_ptr(dev);
+
+ return 0;
+}
+
+static int rockchip_sdhci_bind(struct udevice *dev)
+{
+ struct rockchip_sdhc_plat *plat = dev_get_platdata(dev);
+ int ret;
+
+ ret = sdhci_bind(dev, &plat->mmc, &plat->cfg);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static const struct udevice_id arasan_sdhci_ids[] = {
+ { .compatible = "arasan,sdhci-5.1" },
+ { }
+};
+
+U_BOOT_DRIVER(arasan_sdhci_drv) = {
+ .name = "arasan_sdhci",
+ .id = UCLASS_MMC,
+ .of_match = arasan_sdhci_ids,
+ .ofdata_to_platdata = arasan_sdhci_ofdata_to_platdata,
+ .ops = &sdhci_ops,
+ .bind = rockchip_sdhci_bind,
+ .probe = arasan_sdhci_probe,
+ .priv_auto_alloc_size = sizeof(struct rockchip_sdhc),
+ .platdata_auto_alloc_size = sizeof(struct rockchip_sdhc_plat),
+};
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 8c46a2f..5ce7d6d 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -64,12 +64,14 @@ config NAND_PXA3XX
PXA3xx processors (NFCv1) and also on Armada 370/XP (NFCv2).
config NAND_SUNXI
- bool "Support for NAND on Allwinner SoCs in SPL"
+ bool "Support for NAND on Allwinner SoCs"
depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I
select SYS_NAND_SELF_INIT
---help---
- Enable support for NAND. This option allows SPL to read from
- sunxi NAND using DMA transfers.
+ Enable support for NAND. This option enables the standard and
+ SPL drivers.
+ The SPL driver only supports reading from the NAND using DMA
+ transfers.
config NAND_ARASAN
bool "Configure Arasan Nand"
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 837d397..1df9273 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -66,6 +66,7 @@ obj-$(CONFIG_TEGRA_NAND) += tegra_nand.o
obj-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o
obj-$(CONFIG_NAND_OMAP_ELM) += omap_elm.o
obj-$(CONFIG_NAND_PLAT) += nand_plat.o
+obj-$(CONFIG_NAND_SUNXI) += sunxi_nand.o
else # minimal SPL drivers
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 6897167..d1287bc 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -29,6 +29,9 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <common.h>
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+#include <fdtdec.h>
+#endif
#include <malloc.h>
#include <watchdog.h>
#include <linux/err.h>
@@ -2411,7 +2414,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
int cached = writelen > bytes && page != blockmask;
uint8_t *wbuf = buf;
int use_bufpoi;
- int part_pagewr = (column || writelen < (mtd->writesize - 1));
+ int part_pagewr = (column || writelen < mtd->writesize);
if (part_pagewr)
use_bufpoi = 1;
@@ -3763,6 +3766,66 @@ ident_done:
return type;
}
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+DECLARE_GLOBAL_DATA_PTR;
+
+static int nand_dt_init(struct mtd_info *mtd, struct nand_chip *chip, int node)
+{
+ int ret, ecc_mode = -1, ecc_strength, ecc_step;
+ const void *blob = gd->fdt_blob;
+ const char *str;
+
+ ret = fdtdec_get_int(blob, node, "nand-bus-width", -1);
+ if (ret == 16)
+ chip->options |= NAND_BUSWIDTH_16;
+
+ if (fdtdec_get_bool(blob, node, "nand-on-flash-bbt"))
+ chip->bbt_options |= NAND_BBT_USE_FLASH;
+
+ str = fdt_getprop(blob, node, "nand-ecc-mode", NULL);
+ if (str) {
+ if (!strcmp(str, "none"))
+ ecc_mode = NAND_ECC_NONE;
+ else if (!strcmp(str, "soft"))
+ ecc_mode = NAND_ECC_SOFT;
+ else if (!strcmp(str, "hw"))
+ ecc_mode = NAND_ECC_HW;
+ else if (!strcmp(str, "hw_syndrome"))
+ ecc_mode = NAND_ECC_HW_SYNDROME;
+ else if (!strcmp(str, "hw_oob_first"))
+ ecc_mode = NAND_ECC_HW_OOB_FIRST;
+ else if (!strcmp(str, "soft_bch"))
+ ecc_mode = NAND_ECC_SOFT_BCH;
+ }
+
+
+ ecc_strength = fdtdec_get_int(blob, node, "nand-ecc-strength", -1);
+ ecc_step = fdtdec_get_int(blob, node, "nand-ecc-step-size", -1);
+
+ if ((ecc_step >= 0 && !(ecc_strength >= 0)) ||
+ (!(ecc_step >= 0) && ecc_strength >= 0)) {
+ pr_err("must set both strength and step size in DT\n");
+ return -EINVAL;
+ }
+
+ if (ecc_mode >= 0)
+ chip->ecc.mode = ecc_mode;
+
+ if (ecc_strength >= 0)
+ chip->ecc.strength = ecc_strength;
+
+ if (ecc_step > 0)
+ chip->ecc.size = ecc_step;
+
+ return 0;
+}
+#else
+static int nand_dt_init(struct mtd_info *mtd, struct nand_chip *chip, int node)
+{
+ return 0;
+}
+#endif /* CONFIG_IS_ENABLED(OF_CONTROL) */
+
/**
* nand_scan_ident - [NAND Interface] Scan for the NAND device
* @mtd: MTD device structure
@@ -3779,6 +3842,13 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
int i, nand_maf_id, nand_dev_id;
struct nand_chip *chip = mtd_to_nand(mtd);
struct nand_flash_dev *type;
+ int ret;
+
+ if (chip->flash_node) {
+ ret = nand_dt_init(mtd, chip, chip->flash_node);
+ if (ret)
+ return ret;
+ }
/* Set the default functions */
nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16);
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index 561d2cd..ce0a14e 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -62,6 +62,10 @@ struct nand_flash_dev nand_flash_ids[] = {
{ .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
NAND_ECC_INFO(40, SZ_1K), 4 },
+ {"H27QCG8T2E5R‐BCF 64G 3.3V 8-bit",
+ { .id = {0xad, 0xde, 0x14, 0xa7, 0x42, 0x4a} },
+ SZ_16K, SZ_8K, SZ_4M, NAND_NEED_SCRAMBLING, 6, 1664,
+ NAND_ECC_INFO(56, SZ_1K), 1 },
LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS),
LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
new file mode 100644
index 0000000..c4e2cd7
--- /dev/null
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -0,0 +1,1845 @@
+/*
+ * Copyright (C) 2013 Boris BREZILLON <b.brezillon.dev@gmail.com>
+ * Copyright (C) 2015 Roy Spliet <r.spliet@ultimaker.com>
+ *
+ * Derived from:
+ * https://github.com/yuq/sunxi-nfc-mtd
+ * Copyright (C) 2013 Qiang Yu <yuq825@gmail.com>
+ *
+ * https://github.com/hno/Allwinner-Info
+ * Copyright (C) 2013 Henrik Nordström <Henrik Nordström>
+ *
+ * Copyright (C) 2013 Dmitriy B. <rzk333@gmail.com>
+ * Copyright (C) 2013 Sergey Lapin <slapin@ossfans.org>
+ *
+ * This program 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <memalign.h>
+#include <nand.h>
+
+#include <linux/kernel.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/io.h>
+
+#include <asm/gpio.h>
+#include <asm/arch/clock.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define NFC_REG_CTL 0x0000
+#define NFC_REG_ST 0x0004
+#define NFC_REG_INT 0x0008
+#define NFC_REG_TIMING_CTL 0x000C
+#define NFC_REG_TIMING_CFG 0x0010
+#define NFC_REG_ADDR_LOW 0x0014
+#define NFC_REG_ADDR_HIGH 0x0018
+#define NFC_REG_SECTOR_NUM 0x001C
+#define NFC_REG_CNT 0x0020
+#define NFC_REG_CMD 0x0024
+#define NFC_REG_RCMD_SET 0x0028
+#define NFC_REG_WCMD_SET 0x002C
+#define NFC_REG_IO_DATA 0x0030
+#define NFC_REG_ECC_CTL 0x0034
+#define NFC_REG_ECC_ST 0x0038
+#define NFC_REG_DEBUG 0x003C
+#define NFC_REG_ECC_ERR_CNT(x) ((0x0040 + (x)) & ~0x3)
+#define NFC_REG_USER_DATA(x) (0x0050 + ((x) * 4))
+#define NFC_REG_SPARE_AREA 0x00A0
+#define NFC_REG_PAT_ID 0x00A4
+#define NFC_RAM0_BASE 0x0400
+#define NFC_RAM1_BASE 0x0800
+
+/* define bit use in NFC_CTL */
+#define NFC_EN BIT(0)
+#define NFC_RESET BIT(1)
+#define NFC_BUS_WIDTH_MSK BIT(2)
+#define NFC_BUS_WIDTH_8 (0 << 2)
+#define NFC_BUS_WIDTH_16 (1 << 2)
+#define NFC_RB_SEL_MSK BIT(3)
+#define NFC_RB_SEL(x) ((x) << 3)
+#define NFC_CE_SEL_MSK (0x7 << 24)
+#define NFC_CE_SEL(x) ((x) << 24)
+#define NFC_CE_CTL BIT(6)
+#define NFC_PAGE_SHIFT_MSK (0xf << 8)
+#define NFC_PAGE_SHIFT(x) (((x) < 10 ? 0 : (x) - 10) << 8)
+#define NFC_SAM BIT(12)
+#define NFC_RAM_METHOD BIT(14)
+#define NFC_DEBUG_CTL BIT(31)
+
+/* define bit use in NFC_ST */
+#define NFC_RB_B2R BIT(0)
+#define NFC_CMD_INT_FLAG BIT(1)
+#define NFC_DMA_INT_FLAG BIT(2)
+#define NFC_CMD_FIFO_STATUS BIT(3)
+#define NFC_STA BIT(4)
+#define NFC_NATCH_INT_FLAG BIT(5)
+#define NFC_RB_STATE(x) BIT(x + 8)
+
+/* define bit use in NFC_INT */
+#define NFC_B2R_INT_ENABLE BIT(0)
+#define NFC_CMD_INT_ENABLE BIT(1)
+#define NFC_DMA_INT_ENABLE BIT(2)
+#define NFC_INT_MASK (NFC_B2R_INT_ENABLE | \
+ NFC_CMD_INT_ENABLE | \
+ NFC_DMA_INT_ENABLE)
+
+/* define bit use in NFC_TIMING_CTL */
+#define NFC_TIMING_CTL_EDO BIT(8)
+
+/* define NFC_TIMING_CFG register layout */
+#define NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD) \
+ (((tWB) & 0x3) | (((tADL) & 0x3) << 2) | \
+ (((tWHR) & 0x3) << 4) | (((tRHW) & 0x3) << 6) | \
+ (((tCAD) & 0x7) << 8))
+
+/* define bit use in NFC_CMD */
+#define NFC_CMD_LOW_BYTE_MSK 0xff
+#define NFC_CMD_HIGH_BYTE_MSK (0xff << 8)
+#define NFC_CMD(x) (x)
+#define NFC_ADR_NUM_MSK (0x7 << 16)
+#define NFC_ADR_NUM(x) (((x) - 1) << 16)
+#define NFC_SEND_ADR BIT(19)
+#define NFC_ACCESS_DIR BIT(20)
+#define NFC_DATA_TRANS BIT(21)
+#define NFC_SEND_CMD1 BIT(22)
+#define NFC_WAIT_FLAG BIT(23)
+#define NFC_SEND_CMD2 BIT(24)
+#define NFC_SEQ BIT(25)
+#define NFC_DATA_SWAP_METHOD BIT(26)
+#define NFC_ROW_AUTO_INC BIT(27)
+#define NFC_SEND_CMD3 BIT(28)
+#define NFC_SEND_CMD4 BIT(29)
+#define NFC_CMD_TYPE_MSK (0x3 << 30)
+#define NFC_NORMAL_OP (0 << 30)
+#define NFC_ECC_OP (1 << 30)
+#define NFC_PAGE_OP (2 << 30)
+
+/* define bit use in NFC_RCMD_SET */
+#define NFC_READ_CMD_MSK 0xff
+#define NFC_RND_READ_CMD0_MSK (0xff << 8)
+#define NFC_RND_READ_CMD1_MSK (0xff << 16)
+
+/* define bit use in NFC_WCMD_SET */
+#define NFC_PROGRAM_CMD_MSK 0xff
+#define NFC_RND_WRITE_CMD_MSK (0xff << 8)
+#define NFC_READ_CMD0_MSK (0xff << 16)
+#define NFC_READ_CMD1_MSK (0xff << 24)
+
+/* define bit use in NFC_ECC_CTL */
+#define NFC_ECC_EN BIT(0)
+#define NFC_ECC_PIPELINE BIT(3)
+#define NFC_ECC_EXCEPTION BIT(4)
+#define NFC_ECC_BLOCK_SIZE_MSK BIT(5)
+#define NFC_ECC_BLOCK_512 (1 << 5)
+#define NFC_RANDOM_EN BIT(9)
+#define NFC_RANDOM_DIRECTION BIT(10)
+#define NFC_ECC_MODE_MSK (0xf << 12)
+#define NFC_ECC_MODE(x) ((x) << 12)
+#define NFC_RANDOM_SEED_MSK (0x7fff << 16)
+#define NFC_RANDOM_SEED(x) ((x) << 16)
+
+/* define bit use in NFC_ECC_ST */
+#define NFC_ECC_ERR(x) BIT(x)
+#define NFC_ECC_PAT_FOUND(x) BIT(x + 16)
+#define NFC_ECC_ERR_CNT(b, x) (((x) >> ((b) * 8)) & 0xff)
+
+#define NFC_DEFAULT_TIMEOUT_MS 1000
+
+#define NFC_SRAM_SIZE 1024
+
+#define NFC_MAX_CS 7
+
+/*
+ * Ready/Busy detection type: describes the Ready/Busy detection modes
+ *
+ * @RB_NONE: no external detection available, rely on STATUS command
+ * and software timeouts
+ * @RB_NATIVE: use sunxi NAND controller Ready/Busy support. The Ready/Busy
+ * pin of the NAND flash chip must be connected to one of the
+ * native NAND R/B pins (those which can be muxed to the NAND
+ * Controller)
+ * @RB_GPIO: use a simple GPIO to handle Ready/Busy status. The Ready/Busy
+ * pin of the NAND flash chip must be connected to a GPIO capable
+ * pin.
+ */
+enum sunxi_nand_rb_type {
+ RB_NONE,
+ RB_NATIVE,
+ RB_GPIO,
+};
+
+/*
+ * Ready/Busy structure: stores information related to Ready/Busy detection
+ *
+ * @type: the Ready/Busy detection mode
+ * @info: information related to the R/B detection mode. Either a gpio
+ * id or a native R/B id (those supported by the NAND controller).
+ */
+struct sunxi_nand_rb {
+ enum sunxi_nand_rb_type type;
+ union {
+ struct gpio_desc gpio;
+ int nativeid;
+ } info;
+};
+
+/*
+ * Chip Select structure: stores information related to NAND Chip Select
+ *
+ * @cs: the NAND CS id used to communicate with a NAND Chip
+ * @rb: the Ready/Busy description
+ */
+struct sunxi_nand_chip_sel {
+ u8 cs;
+ struct sunxi_nand_rb rb;
+};
+
+/*
+ * sunxi HW ECC infos: stores information related to HW ECC support
+ *
+ * @mode: the sunxi ECC mode field deduced from ECC requirements
+ * @layout: the OOB layout depending on the ECC requirements and the
+ * selected ECC mode
+ */
+struct sunxi_nand_hw_ecc {
+ int mode;
+ struct nand_ecclayout layout;
+};
+
+/*
+ * NAND chip structure: stores NAND chip device related information
+ *
+ * @node: used to store NAND chips into a list
+ * @nand: base NAND chip structure
+ * @mtd: base MTD structure
+ * @clk_rate: clk_rate required for this NAND chip
+ * @timing_cfg TIMING_CFG register value for this NAND chip
+ * @selected: current active CS
+ * @nsels: number of CS lines required by the NAND chip
+ * @sels: array of CS lines descriptions
+ */
+struct sunxi_nand_chip {
+ struct list_head node;
+ struct nand_chip nand;
+ unsigned long clk_rate;
+ u32 timing_cfg;
+ u32 timing_ctl;
+ int selected;
+ int addr_cycles;
+ u32 addr[2];
+ int cmd_cycles;
+ u8 cmd[2];
+ int nsels;
+ struct sunxi_nand_chip_sel sels[0];
+};
+
+static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand)
+{
+ return container_of(nand, struct sunxi_nand_chip, nand);
+}
+
+/*
+ * NAND Controller structure: stores sunxi NAND controller information
+ *
+ * @controller: base controller structure
+ * @dev: parent device (used to print error messages)
+ * @regs: NAND controller registers
+ * @ahb_clk: NAND Controller AHB clock
+ * @mod_clk: NAND Controller mod clock
+ * @assigned_cs: bitmask describing already assigned CS lines
+ * @clk_rate: NAND controller current clock rate
+ * @chips: a list containing all the NAND chips attached to
+ * this NAND controller
+ * @complete: a completion object used to wait for NAND
+ * controller events
+ */
+struct sunxi_nfc {
+ struct nand_hw_control controller;
+ struct device *dev;
+ void __iomem *regs;
+ struct clk *ahb_clk;
+ struct clk *mod_clk;
+ unsigned long assigned_cs;
+ unsigned long clk_rate;
+ struct list_head chips;
+};
+
+static inline struct sunxi_nfc *to_sunxi_nfc(struct nand_hw_control *ctrl)
+{
+ return container_of(ctrl, struct sunxi_nfc, controller);
+}
+
+static void sunxi_nfc_set_clk_rate(unsigned long hz)
+{
+ struct sunxi_ccm_reg *const ccm =
+ (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+ int div_m, div_n;
+
+ div_m = (clock_get_pll6() + hz - 1) / hz;
+ for (div_n = 0; div_n < 3 && div_m > 16; div_n++) {
+ if (div_m % 2)
+ div_m++;
+ div_m >>= 1;
+ }
+ if (div_m > 16)
+ div_m = 16;
+
+ /* config mod clock */
+ writel(CCM_NAND_CTRL_ENABLE | CCM_NAND_CTRL_PLL6 |
+ CCM_NAND_CTRL_N(div_n) | CCM_NAND_CTRL_M(div_m),
+ &ccm->nand0_clk_cfg);
+
+ /* gate on nand clock */
+ setbits_le32(&ccm->ahb_gate0, (1 << 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));
+#endif
+}
+
+static int sunxi_nfc_wait_int(struct sunxi_nfc *nfc, u32 flags,
+ unsigned int timeout_ms)
+{
+ unsigned int timeout_ticks;
+ u32 time_start, status;
+ int ret = -ETIMEDOUT;
+
+ if (!timeout_ms)
+ timeout_ms = NFC_DEFAULT_TIMEOUT_MS;
+
+ timeout_ticks = (timeout_ms * CONFIG_SYS_HZ) / 1000;
+
+ time_start = get_timer(0);
+
+ do {
+ status = readl(nfc->regs + NFC_REG_ST);
+ if ((status & flags) == flags) {
+ ret = 0;
+ break;
+ }
+
+ udelay(1);
+ } while (get_timer(time_start) < timeout_ticks);
+
+ writel(status & flags, nfc->regs + NFC_REG_ST);
+
+ return ret;
+}
+
+static int sunxi_nfc_wait_cmd_fifo_empty(struct sunxi_nfc *nfc)
+{
+ unsigned long timeout = (CONFIG_SYS_HZ *
+ NFC_DEFAULT_TIMEOUT_MS) / 1000;
+ u32 time_start;
+
+ time_start = get_timer(0);
+ do {
+ if (!(readl(nfc->regs + NFC_REG_ST) & NFC_CMD_FIFO_STATUS))
+ return 0;
+ } while (get_timer(time_start) < timeout);
+
+ dev_err(nfc->dev, "wait for empty cmd FIFO timedout\n");
+ return -ETIMEDOUT;
+}
+
+static int sunxi_nfc_rst(struct sunxi_nfc *nfc)
+{
+ unsigned long timeout = (CONFIG_SYS_HZ *
+ NFC_DEFAULT_TIMEOUT_MS) / 1000;
+ u32 time_start;
+
+ writel(0, nfc->regs + NFC_REG_ECC_CTL);
+ writel(NFC_RESET, nfc->regs + NFC_REG_CTL);
+
+ time_start = get_timer(0);
+ do {
+ if (!(readl(nfc->regs + NFC_REG_CTL) & NFC_RESET))
+ return 0;
+ } while (get_timer(time_start) < timeout);
+
+ dev_err(nfc->dev, "wait for NAND controller reset timedout\n");
+ return -ETIMEDOUT;
+}
+
+static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
+{
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
+ struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+ struct sunxi_nand_rb *rb;
+ unsigned long timeo = (sunxi_nand->nand.state == FL_ERASING ? 400 : 20);
+ int ret;
+
+ if (sunxi_nand->selected < 0)
+ return 0;
+
+ rb = &sunxi_nand->sels[sunxi_nand->selected].rb;
+
+ switch (rb->type) {
+ case RB_NATIVE:
+ ret = !!(readl(nfc->regs + NFC_REG_ST) &
+ NFC_RB_STATE(rb->info.nativeid));
+ if (ret)
+ break;
+
+ sunxi_nfc_wait_int(nfc, NFC_RB_B2R, timeo);
+ ret = !!(readl(nfc->regs + NFC_REG_ST) &
+ NFC_RB_STATE(rb->info.nativeid));
+ break;
+ case RB_GPIO:
+ ret = dm_gpio_get_value(&rb->info.gpio);
+ break;
+ case RB_NONE:
+ default:
+ ret = 0;
+ dev_err(nfc->dev, "cannot check R/B NAND status!\n");
+ break;
+ }
+
+ return ret;
+}
+
+static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
+{
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
+ struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+ struct sunxi_nand_chip_sel *sel;
+ u32 ctl;
+
+ if (chip > 0 && chip >= sunxi_nand->nsels)
+ return;
+
+ if (chip == sunxi_nand->selected)
+ return;
+
+ ctl = readl(nfc->regs + NFC_REG_CTL) &
+ ~(NFC_PAGE_SHIFT_MSK | NFC_CE_SEL_MSK | NFC_RB_SEL_MSK | NFC_EN);
+
+ if (chip >= 0) {
+ sel = &sunxi_nand->sels[chip];
+
+ ctl |= NFC_CE_SEL(sel->cs) | NFC_EN |
+ NFC_PAGE_SHIFT(nand->page_shift - 10);
+ if (sel->rb.type == RB_NONE) {
+ nand->dev_ready = NULL;
+ } else {
+ nand->dev_ready = sunxi_nfc_dev_ready;
+ if (sel->rb.type == RB_NATIVE)
+ ctl |= NFC_RB_SEL(sel->rb.info.nativeid);
+ }
+
+ writel(mtd->writesize, nfc->regs + NFC_REG_SPARE_AREA);
+
+ if (nfc->clk_rate != sunxi_nand->clk_rate) {
+ sunxi_nfc_set_clk_rate(sunxi_nand->clk_rate);
+ nfc->clk_rate = sunxi_nand->clk_rate;
+ }
+ }
+
+ writel(sunxi_nand->timing_ctl, nfc->regs + NFC_REG_TIMING_CTL);
+ writel(sunxi_nand->timing_cfg, nfc->regs + NFC_REG_TIMING_CFG);
+ writel(ctl, nfc->regs + NFC_REG_CTL);
+
+ sunxi_nand->selected = chip;
+}
+
+static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
+ struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+ int ret;
+ int cnt;
+ int offs = 0;
+ u32 tmp;
+
+ while (len > offs) {
+ cnt = min(len - offs, NFC_SRAM_SIZE);
+
+ ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
+ if (ret)
+ break;
+
+ writel(cnt, nfc->regs + NFC_REG_CNT);
+ tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD;
+ writel(tmp, nfc->regs + NFC_REG_CMD);
+
+ ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+ if (ret)
+ break;
+
+ if (buf)
+ memcpy_fromio(buf + offs, nfc->regs + NFC_RAM0_BASE,
+ cnt);
+ offs += cnt;
+ }
+}
+
+static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+ int len)
+{
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
+ struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+ int ret;
+ int cnt;
+ int offs = 0;
+ u32 tmp;
+
+ while (len > offs) {
+ cnt = min(len - offs, NFC_SRAM_SIZE);
+
+ ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
+ if (ret)
+ break;
+
+ writel(cnt, nfc->regs + NFC_REG_CNT);
+ memcpy_toio(nfc->regs + NFC_RAM0_BASE, buf + offs, cnt);
+ tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD |
+ NFC_ACCESS_DIR;
+ writel(tmp, nfc->regs + NFC_REG_CMD);
+
+ ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+ if (ret)
+ break;
+
+ offs += cnt;
+ }
+}
+
+static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd)
+{
+ uint8_t ret;
+
+ sunxi_nfc_read_buf(mtd, &ret, 1);
+
+ return ret;
+}
+
+static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
+ unsigned int ctrl)
+{
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
+ struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
+ int ret;
+ u32 tmp;
+
+ ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
+ if (ret)
+ return;
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ tmp = readl(nfc->regs + NFC_REG_CTL);
+ if (ctrl & NAND_NCE)
+ tmp |= NFC_CE_CTL;
+ else
+ tmp &= ~NFC_CE_CTL;
+ writel(tmp, nfc->regs + NFC_REG_CTL);
+ }
+
+ if (dat == NAND_CMD_NONE && (ctrl & NAND_NCE) &&
+ !(ctrl & (NAND_CLE | NAND_ALE))) {
+ u32 cmd = 0;
+
+ if (!sunxi_nand->addr_cycles && !sunxi_nand->cmd_cycles)
+ return;
+
+ if (sunxi_nand->cmd_cycles--)
+ cmd |= NFC_SEND_CMD1 | sunxi_nand->cmd[0];
+
+ if (sunxi_nand->cmd_cycles--) {
+ cmd |= NFC_SEND_CMD2;
+ writel(sunxi_nand->cmd[1],
+ nfc->regs + NFC_REG_RCMD_SET);
+ }
+
+ sunxi_nand->cmd_cycles = 0;
+
+ if (sunxi_nand->addr_cycles) {
+ cmd |= NFC_SEND_ADR |
+ NFC_ADR_NUM(sunxi_nand->addr_cycles);
+ writel(sunxi_nand->addr[0],
+ nfc->regs + NFC_REG_ADDR_LOW);
+ }
+
+ if (sunxi_nand->addr_cycles > 4)
+ writel(sunxi_nand->addr[1],
+ nfc->regs + NFC_REG_ADDR_HIGH);
+
+ writel(cmd, nfc->regs + NFC_REG_CMD);
+ sunxi_nand->addr[0] = 0;
+ sunxi_nand->addr[1] = 0;
+ sunxi_nand->addr_cycles = 0;
+ sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+ }
+
+ if (ctrl & NAND_CLE) {
+ sunxi_nand->cmd[sunxi_nand->cmd_cycles++] = dat;
+ } else if (ctrl & NAND_ALE) {
+ sunxi_nand->addr[sunxi_nand->addr_cycles / 4] |=
+ dat << ((sunxi_nand->addr_cycles % 4) * 8);
+ sunxi_nand->addr_cycles++;
+ }
+}
+
+/* These seed values have been extracted from Allwinner's BSP */
+static const u16 sunxi_nfc_randomizer_page_seeds[] = {
+ 0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72,
+ 0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436,
+ 0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d,
+ 0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130,
+ 0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56,
+ 0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55,
+ 0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb,
+ 0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17,
+ 0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62,
+ 0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064,
+ 0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126,
+ 0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e,
+ 0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3,
+ 0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b,
+ 0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d,
+ 0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db,
+};
+
+/*
+ * sunxi_nfc_randomizer_ecc512_seeds and sunxi_nfc_randomizer_ecc1024_seeds
+ * have been generated using
+ * sunxi_nfc_randomizer_step(seed, (step_size * 8) + 15), which is what
+ * the randomizer engine does internally before de/scrambling OOB data.
+ *
+ * Those tables are statically defined to avoid calculating randomizer state
+ * at runtime.
+ */
+static const u16 sunxi_nfc_randomizer_ecc512_seeds[] = {
+ 0x3346, 0x367f, 0x1f18, 0x769a, 0x4f64, 0x068c, 0x2ef1, 0x6b64,
+ 0x28a9, 0x15d7, 0x30f8, 0x3659, 0x53db, 0x7c5f, 0x71d4, 0x4409,
+ 0x26eb, 0x03cc, 0x655d, 0x47d4, 0x4daa, 0x0877, 0x712d, 0x3617,
+ 0x3264, 0x49aa, 0x7f9e, 0x588e, 0x4fbc, 0x7176, 0x7f91, 0x6c6d,
+ 0x4b95, 0x5fb7, 0x3844, 0x4037, 0x0184, 0x081b, 0x0ee8, 0x5b91,
+ 0x293d, 0x1f71, 0x0e6f, 0x402b, 0x5122, 0x1e52, 0x22be, 0x3d2d,
+ 0x75bc, 0x7c60, 0x6291, 0x1a2f, 0x61d4, 0x74aa, 0x4140, 0x29ab,
+ 0x472d, 0x2852, 0x017e, 0x15e8, 0x5ec2, 0x17cf, 0x7d0f, 0x06b8,
+ 0x117a, 0x6b94, 0x789b, 0x3126, 0x6ac5, 0x5be7, 0x150f, 0x51f8,
+ 0x7889, 0x0aa5, 0x663d, 0x77e8, 0x0b87, 0x3dcb, 0x360d, 0x218b,
+ 0x512f, 0x7dc9, 0x6a4d, 0x630a, 0x3547, 0x1dd2, 0x5aea, 0x69a5,
+ 0x7bfa, 0x5e4f, 0x1519, 0x6430, 0x3a0e, 0x5eb3, 0x5425, 0x0c7a,
+ 0x5540, 0x3670, 0x63c1, 0x31e9, 0x5a39, 0x2de7, 0x5979, 0x2891,
+ 0x1562, 0x014b, 0x5b05, 0x2756, 0x5a34, 0x13aa, 0x6cb5, 0x2c36,
+ 0x5e72, 0x1306, 0x0861, 0x15ef, 0x1ee8, 0x5a37, 0x7ac4, 0x45dd,
+ 0x44c4, 0x7266, 0x2f41, 0x3ccc, 0x045e, 0x7d40, 0x7c66, 0x0fa0,
+};
+
+static const u16 sunxi_nfc_randomizer_ecc1024_seeds[] = {
+ 0x2cf5, 0x35f1, 0x63a4, 0x5274, 0x2bd2, 0x778b, 0x7285, 0x32b6,
+ 0x6a5c, 0x70d6, 0x757d, 0x6769, 0x5375, 0x1e81, 0x0cf3, 0x3982,
+ 0x6787, 0x042a, 0x6c49, 0x1925, 0x56a8, 0x40a9, 0x063e, 0x7bd9,
+ 0x4dbf, 0x55ec, 0x672e, 0x7334, 0x5185, 0x4d00, 0x232a, 0x7e07,
+ 0x445d, 0x6b92, 0x528f, 0x4255, 0x53ba, 0x7d82, 0x2a2e, 0x3a4e,
+ 0x75eb, 0x450c, 0x6844, 0x1b5d, 0x581a, 0x4cc6, 0x0379, 0x37b2,
+ 0x419f, 0x0e92, 0x6b27, 0x5624, 0x01e3, 0x07c1, 0x44a5, 0x130c,
+ 0x13e8, 0x5910, 0x0876, 0x60c5, 0x54e3, 0x5b7f, 0x2269, 0x509f,
+ 0x7665, 0x36fd, 0x3e9a, 0x0579, 0x6295, 0x14ef, 0x0a81, 0x1bcc,
+ 0x4b16, 0x64db, 0x0514, 0x4f07, 0x0591, 0x3576, 0x6853, 0x0d9e,
+ 0x259f, 0x38b7, 0x64fb, 0x3094, 0x4693, 0x6ddd, 0x29bb, 0x0bc8,
+ 0x3f47, 0x490e, 0x0c0e, 0x7933, 0x3c9e, 0x5840, 0x398d, 0x3e68,
+ 0x4af1, 0x71f5, 0x57cf, 0x1121, 0x64eb, 0x3579, 0x15ac, 0x584d,
+ 0x5f2a, 0x47e2, 0x6528, 0x6eac, 0x196e, 0x6b96, 0x0450, 0x0179,
+ 0x609c, 0x06e1, 0x4626, 0x42c7, 0x273e, 0x486f, 0x0705, 0x1601,
+ 0x145b, 0x407e, 0x062b, 0x57a5, 0x53f9, 0x5659, 0x4410, 0x3ccd,
+};
+
+static u16 sunxi_nfc_randomizer_step(u16 state, int count)
+{
+ state &= 0x7fff;
+
+ /*
+ * This loop is just a simple implementation of a Fibonacci LFSR using
+ * the x16 + x15 + 1 polynomial.
+ */
+ while (count--)
+ state = ((state >> 1) |
+ (((state ^ (state >> 1)) & 1) << 14)) & 0x7fff;
+
+ return state;
+}
+
+static u16 sunxi_nfc_randomizer_state(struct mtd_info *mtd, int page, bool ecc)
+{
+ const u16 *seeds = sunxi_nfc_randomizer_page_seeds;
+ int mod = mtd->erasesize / mtd->writesize;
+
+ if (mod > ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds))
+ mod = ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds);
+
+ if (ecc) {
+ if (mtd->ecc_step_size == 512)
+ seeds = sunxi_nfc_randomizer_ecc512_seeds;
+ else
+ seeds = sunxi_nfc_randomizer_ecc1024_seeds;
+ }
+
+ return seeds[page % mod];
+}
+
+static void sunxi_nfc_randomizer_config(struct mtd_info *mtd,
+ int page, bool ecc)
+{
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+ u32 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
+ u16 state;
+
+ if (!(nand->options & NAND_NEED_SCRAMBLING))
+ return;
+
+ ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
+ state = sunxi_nfc_randomizer_state(mtd, page, ecc);
+ ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_SEED_MSK;
+ writel(ecc_ctl | NFC_RANDOM_SEED(state), nfc->regs + NFC_REG_ECC_CTL);
+}
+
+static void sunxi_nfc_randomizer_enable(struct mtd_info *mtd)
+{
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+
+ if (!(nand->options & NAND_NEED_SCRAMBLING))
+ return;
+
+ writel(readl(nfc->regs + NFC_REG_ECC_CTL) | NFC_RANDOM_EN,
+ nfc->regs + NFC_REG_ECC_CTL);
+}
+
+static void sunxi_nfc_randomizer_disable(struct mtd_info *mtd)
+{
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+
+ if (!(nand->options & NAND_NEED_SCRAMBLING))
+ return;
+
+ writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
+ nfc->regs + NFC_REG_ECC_CTL);
+}
+
+static void sunxi_nfc_randomize_bbm(struct mtd_info *mtd, int page, u8 *bbm)
+{
+ u16 state = sunxi_nfc_randomizer_state(mtd, page, true);
+
+ bbm[0] ^= state;
+ bbm[1] ^= sunxi_nfc_randomizer_step(state, 8);
+}
+
+static void sunxi_nfc_randomizer_write_buf(struct mtd_info *mtd,
+ const uint8_t *buf, int len,
+ bool ecc, int page)
+{
+ sunxi_nfc_randomizer_config(mtd, page, ecc);
+ sunxi_nfc_randomizer_enable(mtd);
+ sunxi_nfc_write_buf(mtd, buf, len);
+ sunxi_nfc_randomizer_disable(mtd);
+}
+
+static void sunxi_nfc_randomizer_read_buf(struct mtd_info *mtd, uint8_t *buf,
+ int len, bool ecc, int page)
+{
+ sunxi_nfc_randomizer_config(mtd, page, ecc);
+ sunxi_nfc_randomizer_enable(mtd);
+ sunxi_nfc_read_buf(mtd, buf, len);
+ sunxi_nfc_randomizer_disable(mtd);
+}
+
+static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd)
+{
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+ struct sunxi_nand_hw_ecc *data = nand->ecc.priv;
+ u32 ecc_ctl;
+
+ ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
+ ecc_ctl &= ~(NFC_ECC_MODE_MSK | NFC_ECC_PIPELINE |
+ NFC_ECC_BLOCK_SIZE_MSK);
+ ecc_ctl |= NFC_ECC_EN | NFC_ECC_MODE(data->mode) | NFC_ECC_EXCEPTION;
+
+ if (nand->ecc.size == 512)
+ ecc_ctl |= NFC_ECC_BLOCK_512;
+
+ writel(ecc_ctl, nfc->regs + NFC_REG_ECC_CTL);
+}
+
+static void sunxi_nfc_hw_ecc_disable(struct mtd_info *mtd)
+{
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+
+ writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN,
+ nfc->regs + NFC_REG_ECC_CTL);
+}
+
+static inline void sunxi_nfc_user_data_to_buf(u32 user_data, u8 *buf)
+{
+ buf[0] = user_data;
+ buf[1] = user_data >> 8;
+ buf[2] = user_data >> 16;
+ buf[3] = user_data >> 24;
+}
+
+static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
+ u8 *data, int data_off,
+ u8 *oob, int oob_off,
+ int *cur_off,
+ unsigned int *max_bitflips,
+ bool bbm, int page)
+{
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+ struct nand_ecc_ctrl *ecc = &nand->ecc;
+ int raw_mode = 0;
+ u32 status;
+ int ret;
+
+ if (*cur_off != data_off)
+ nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1);
+
+ sunxi_nfc_randomizer_read_buf(mtd, NULL, ecc->size, false, page);
+
+ if (data_off + ecc->size != oob_off)
+ nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
+
+ ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
+ if (ret)
+ return ret;
+
+ sunxi_nfc_randomizer_enable(mtd);
+ writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP,
+ nfc->regs + NFC_REG_CMD);
+
+ ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+ sunxi_nfc_randomizer_disable(mtd);
+ if (ret)
+ return ret;
+
+ *cur_off = oob_off + ecc->bytes + 4;
+
+ status = readl(nfc->regs + NFC_REG_ECC_ST);
+ if (status & NFC_ECC_PAT_FOUND(0)) {
+ u8 pattern = 0xff;
+
+ if (unlikely(!(readl(nfc->regs + NFC_REG_PAT_ID) & 0x1)))
+ pattern = 0x0;
+
+ memset(data, pattern, ecc->size);
+ memset(oob, pattern, ecc->bytes + 4);
+
+ return 1;
+ }
+
+ ret = NFC_ECC_ERR_CNT(0, readl(nfc->regs + NFC_REG_ECC_ERR_CNT(0)));
+
+ memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size);
+
+ nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
+ sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4, true, page);
+
+ if (status & NFC_ECC_ERR(0)) {
+ /*
+ * Re-read the data with the randomizer disabled to identify
+ * bitflips in erased pages.
+ */
+ if (nand->options & NAND_NEED_SCRAMBLING) {
+ nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1);
+ nand->read_buf(mtd, data, ecc->size);
+ nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
+ nand->read_buf(mtd, oob, ecc->bytes + 4);
+ }
+
+ ret = nand_check_erased_ecc_chunk(data, ecc->size,
+ oob, ecc->bytes + 4,
+ NULL, 0, ecc->strength);
+ if (ret >= 0)
+ raw_mode = 1;
+ } else {
+ /*
+ * The engine protects 4 bytes of OOB data per chunk.
+ * Retrieve the corrected OOB bytes.
+ */
+ sunxi_nfc_user_data_to_buf(readl(nfc->regs +
+ NFC_REG_USER_DATA(0)),
+ oob);
+
+ /* De-randomize the Bad Block Marker. */
+ if (bbm && nand->options & NAND_NEED_SCRAMBLING)
+ sunxi_nfc_randomize_bbm(mtd, page, oob);
+ }
+
+ if (ret < 0) {
+ mtd->ecc_stats.failed++;
+ } else {
+ mtd->ecc_stats.corrected += ret;
+ *max_bitflips = max_t(unsigned int, *max_bitflips, ret);
+ }
+
+ return raw_mode;
+}
+
+static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd,
+ u8 *oob, int *cur_off,
+ bool randomize, int page)
+{
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct nand_ecc_ctrl *ecc = &nand->ecc;
+ int offset = ((ecc->bytes + 4) * ecc->steps);
+ int len = mtd->oobsize - offset;
+
+ if (len <= 0)
+ return;
+
+ if (*cur_off != offset)
+ nand->cmdfunc(mtd, NAND_CMD_RNDOUT,
+ offset + mtd->writesize, -1);
+
+ if (!randomize)
+ sunxi_nfc_read_buf(mtd, oob + offset, len);
+ else
+ sunxi_nfc_randomizer_read_buf(mtd, oob + offset, len,
+ false, page);
+
+ *cur_off = mtd->oobsize + mtd->writesize;
+}
+
+static inline u32 sunxi_nfc_buf_to_user_data(const u8 *buf)
+{
+ return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+}
+
+static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
+ const u8 *data, int data_off,
+ const u8 *oob, int oob_off,
+ int *cur_off, bool bbm,
+ int page)
+{
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+ struct nand_ecc_ctrl *ecc = &nand->ecc;
+ int ret;
+
+ if (data_off != *cur_off)
+ nand->cmdfunc(mtd, NAND_CMD_RNDIN, data_off, -1);
+
+ sunxi_nfc_randomizer_write_buf(mtd, data, ecc->size, false, page);
+
+ /* Fill OOB data in */
+ if ((nand->options & NAND_NEED_SCRAMBLING) && bbm) {
+ u8 user_data[4];
+
+ memcpy(user_data, oob, 4);
+ sunxi_nfc_randomize_bbm(mtd, page, user_data);
+ writel(sunxi_nfc_buf_to_user_data(user_data),
+ nfc->regs + NFC_REG_USER_DATA(0));
+ } else {
+ writel(sunxi_nfc_buf_to_user_data(oob),
+ nfc->regs + NFC_REG_USER_DATA(0));
+ }
+
+ if (data_off + ecc->size != oob_off)
+ nand->cmdfunc(mtd, NAND_CMD_RNDIN, oob_off, -1);
+
+ ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
+ if (ret)
+ return ret;
+
+ sunxi_nfc_randomizer_enable(mtd);
+ writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD |
+ NFC_ACCESS_DIR | NFC_ECC_OP,
+ nfc->regs + NFC_REG_CMD);
+
+ ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+ sunxi_nfc_randomizer_disable(mtd);
+ if (ret)
+ return ret;
+
+ *cur_off = oob_off + ecc->bytes + 4;
+
+ return 0;
+}
+
+static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd,
+ u8 *oob, int *cur_off,
+ int page)
+{
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct nand_ecc_ctrl *ecc = &nand->ecc;
+ int offset = ((ecc->bytes + 4) * ecc->steps);
+ int len = mtd->oobsize - offset;
+
+ if (len <= 0)
+ return;
+
+ if (*cur_off != offset)
+ nand->cmdfunc(mtd, NAND_CMD_RNDIN,
+ offset + mtd->writesize, -1);
+
+ sunxi_nfc_randomizer_write_buf(mtd, oob + offset, len, false, page);
+
+ *cur_off = mtd->oobsize + mtd->writesize;
+}
+
+static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
+ struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
+{
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+ unsigned int max_bitflips = 0;
+ int ret, i, cur_off = 0;
+ bool raw_mode = false;
+
+ sunxi_nfc_hw_ecc_enable(mtd);
+
+ for (i = 0; i < ecc->steps; i++) {
+ int data_off = i * ecc->size;
+ int oob_off = i * (ecc->bytes + 4);
+ u8 *data = buf + data_off;
+ u8 *oob = chip->oob_poi + oob_off;
+
+ ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob,
+ oob_off + mtd->writesize,
+ &cur_off, &max_bitflips,
+ !i, page);
+ if (ret < 0)
+ return ret;
+ else if (ret)
+ raw_mode = true;
+ }
+
+ if (oob_required)
+ sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off,
+ !raw_mode, page);
+
+ sunxi_nfc_hw_ecc_disable(mtd);
+
+ return max_bitflips;
+}
+
+static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd,
+ struct nand_chip *chip,
+ uint32_t data_offs, uint32_t readlen,
+ uint8_t *bufpoi, int page)
+{
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+ int ret, i, cur_off = 0;
+ unsigned int max_bitflips = 0;
+
+ sunxi_nfc_hw_ecc_enable(mtd);
+
+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+ for (i = data_offs / ecc->size;
+ i < DIV_ROUND_UP(data_offs + readlen, ecc->size); i++) {
+ int data_off = i * ecc->size;
+ int oob_off = i * (ecc->bytes + 4);
+ u8 *data = bufpoi + data_off;
+ u8 *oob = chip->oob_poi + oob_off;
+
+ ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off,
+ oob, oob_off + mtd->writesize,
+ &cur_off, &max_bitflips, !i, page);
+ if (ret < 0)
+ return ret;
+ }
+
+ sunxi_nfc_hw_ecc_disable(mtd);
+
+ return max_bitflips;
+}
+
+static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
+ struct nand_chip *chip,
+ const uint8_t *buf, int oob_required,
+ int page)
+{
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+ int ret, i, cur_off = 0;
+
+ sunxi_nfc_hw_ecc_enable(mtd);
+
+ for (i = 0; i < ecc->steps; i++) {
+ int data_off = i * ecc->size;
+ int oob_off = i * (ecc->bytes + 4);
+ const u8 *data = buf + data_off;
+ const u8 *oob = chip->oob_poi + oob_off;
+
+ ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob,
+ oob_off + mtd->writesize,
+ &cur_off, !i, page);
+ if (ret)
+ return ret;
+ }
+
+ if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
+ sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
+ &cur_off, page);
+
+ sunxi_nfc_hw_ecc_disable(mtd);
+
+ return 0;
+}
+
+static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd,
+ struct nand_chip *chip,
+ u32 data_offs, u32 data_len,
+ const u8 *buf, int oob_required,
+ int page)
+{
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+ int ret, i, cur_off = 0;
+
+ sunxi_nfc_hw_ecc_enable(mtd);
+
+ for (i = data_offs / ecc->size;
+ i < DIV_ROUND_UP(data_offs + data_len, ecc->size); i++) {
+ int data_off = i * ecc->size;
+ int oob_off = i * (ecc->bytes + 4);
+ const u8 *data = buf + data_off;
+ const u8 *oob = chip->oob_poi + oob_off;
+
+ ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob,
+ oob_off + mtd->writesize,
+ &cur_off, !i, page);
+ if (ret)
+ return ret;
+ }
+
+ sunxi_nfc_hw_ecc_disable(mtd);
+
+ return 0;
+}
+
+static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
+ struct nand_chip *chip,
+ uint8_t *buf, int oob_required,
+ int page)
+{
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+ unsigned int max_bitflips = 0;
+ int ret, i, cur_off = 0;
+ bool raw_mode = false;
+
+ sunxi_nfc_hw_ecc_enable(mtd);
+
+ for (i = 0; i < ecc->steps; i++) {
+ int data_off = i * (ecc->size + ecc->bytes + 4);
+ int oob_off = data_off + ecc->size;
+ u8 *data = buf + (i * ecc->size);
+ u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4));
+
+ ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob,
+ oob_off, &cur_off,
+ &max_bitflips, !i, page);
+ if (ret < 0)
+ return ret;
+ else if (ret)
+ raw_mode = true;
+ }
+
+ if (oob_required)
+ sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off,
+ !raw_mode, page);
+
+ sunxi_nfc_hw_ecc_disable(mtd);
+
+ return max_bitflips;
+}
+
+static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd,
+ struct nand_chip *chip,
+ const uint8_t *buf,
+ int oob_required, int page)
+{
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+ int ret, i, cur_off = 0;
+
+ sunxi_nfc_hw_ecc_enable(mtd);
+
+ for (i = 0; i < ecc->steps; i++) {
+ int data_off = i * (ecc->size + ecc->bytes + 4);
+ int oob_off = data_off + ecc->size;
+ const u8 *data = buf + (i * ecc->size);
+ const u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4));
+
+ ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off,
+ oob, oob_off, &cur_off,
+ false, page);
+ if (ret)
+ return ret;
+ }
+
+ if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
+ sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
+ &cur_off, page);
+
+ sunxi_nfc_hw_ecc_disable(mtd);
+
+ return 0;
+}
+
+static const s32 tWB_lut[] = {6, 12, 16, 20};
+static const s32 tRHW_lut[] = {4, 8, 12, 20};
+
+static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration,
+ u32 clk_period)
+{
+ u32 clk_cycles = DIV_ROUND_UP(duration, clk_period);
+ int i;
+
+ for (i = 0; i < lut_size; i++) {
+ if (clk_cycles <= lut[i])
+ return i;
+ }
+
+ /* Doesn't fit */
+ return -EINVAL;
+}
+
+#define sunxi_nand_lookup_timing(l, p, c) \
+ _sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c)
+
+static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
+ const struct nand_sdr_timings *timings)
+{
+ u32 min_clk_period = 0;
+ s32 tWB, tADL, tWHR, tRHW, tCAD;
+
+ /* T1 <=> tCLS */
+ if (timings->tCLS_min > min_clk_period)
+ min_clk_period = timings->tCLS_min;
+
+ /* T2 <=> tCLH */
+ if (timings->tCLH_min > min_clk_period)
+ min_clk_period = timings->tCLH_min;
+
+ /* T3 <=> tCS */
+ if (timings->tCS_min > min_clk_period)
+ min_clk_period = timings->tCS_min;
+
+ /* T4 <=> tCH */
+ if (timings->tCH_min > min_clk_period)
+ min_clk_period = timings->tCH_min;
+
+ /* T5 <=> tWP */
+ if (timings->tWP_min > min_clk_period)
+ min_clk_period = timings->tWP_min;
+
+ /* T6 <=> tWH */
+ if (timings->tWH_min > min_clk_period)
+ min_clk_period = timings->tWH_min;
+
+ /* T7 <=> tALS */
+ if (timings->tALS_min > min_clk_period)
+ min_clk_period = timings->tALS_min;
+
+ /* T8 <=> tDS */
+ if (timings->tDS_min > min_clk_period)
+ min_clk_period = timings->tDS_min;
+
+ /* T9 <=> tDH */
+ if (timings->tDH_min > min_clk_period)
+ min_clk_period = timings->tDH_min;
+
+ /* T10 <=> tRR */
+ if (timings->tRR_min > (min_clk_period * 3))
+ min_clk_period = DIV_ROUND_UP(timings->tRR_min, 3);
+
+ /* T11 <=> tALH */
+ if (timings->tALH_min > min_clk_period)
+ min_clk_period = timings->tALH_min;
+
+ /* T12 <=> tRP */
+ if (timings->tRP_min > min_clk_period)
+ min_clk_period = timings->tRP_min;
+
+ /* T13 <=> tREH */
+ if (timings->tREH_min > min_clk_period)
+ min_clk_period = timings->tREH_min;
+
+ /* T14 <=> tRC */
+ if (timings->tRC_min > (min_clk_period * 2))
+ min_clk_period = DIV_ROUND_UP(timings->tRC_min, 2);
+
+ /* T15 <=> tWC */
+ if (timings->tWC_min > (min_clk_period * 2))
+ min_clk_period = DIV_ROUND_UP(timings->tWC_min, 2);
+
+ /* T16 - T19 + tCAD */
+ tWB = sunxi_nand_lookup_timing(tWB_lut, timings->tWB_max,
+ min_clk_period);
+ if (tWB < 0) {
+ dev_err(nfc->dev, "unsupported tWB\n");
+ return tWB;
+ }
+
+ tADL = DIV_ROUND_UP(timings->tADL_min, min_clk_period) >> 3;
+ if (tADL > 3) {
+ dev_err(nfc->dev, "unsupported tADL\n");
+ return -EINVAL;
+ }
+
+ tWHR = DIV_ROUND_UP(timings->tWHR_min, min_clk_period) >> 3;
+ if (tWHR > 3) {
+ dev_err(nfc->dev, "unsupported tWHR\n");
+ return -EINVAL;
+ }
+
+ tRHW = sunxi_nand_lookup_timing(tRHW_lut, timings->tRHW_min,
+ min_clk_period);
+ if (tRHW < 0) {
+ dev_err(nfc->dev, "unsupported tRHW\n");
+ return tRHW;
+ }
+
+ /*
+ * TODO: according to ONFI specs this value only applies for DDR NAND,
+ * but Allwinner seems to set this to 0x7. Mimic them for now.
+ */
+ tCAD = 0x7;
+
+ /* TODO: A83 has some more bits for CDQSS, CS, CLHZ, CCS, WC */
+ chip->timing_cfg = NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD);
+
+ /*
+ * ONFI specification 3.1, paragraph 4.15.2 dictates that EDO data
+ * output cycle timings shall be used if the host drives tRC less than
+ * 30 ns.
+ */
+ chip->timing_ctl = (timings->tRC_min < 30000) ? NFC_TIMING_CTL_EDO : 0;
+
+ /* Convert min_clk_period from picoseconds to nanoseconds */
+ min_clk_period = DIV_ROUND_UP(min_clk_period, 1000);
+
+ /*
+ * Convert min_clk_period into a clk frequency, then get the
+ * appropriate rate for the NAND controller IP given this formula
+ * (specified in the datasheet):
+ * nand clk_rate = min_clk_rate
+ */
+ chip->clk_rate = 1000000000L / min_clk_period;
+
+ return 0;
+}
+
+static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(&chip->nand);
+ const struct nand_sdr_timings *timings;
+ int ret;
+ int mode;
+
+ mode = onfi_get_async_timing_mode(&chip->nand);
+ if (mode == ONFI_TIMING_MODE_UNKNOWN) {
+ mode = chip->nand.onfi_timing_mode_default;
+ } else {
+ uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {};
+ int i;
+
+ mode = fls(mode) - 1;
+ if (mode < 0)
+ mode = 0;
+
+ feature[0] = mode;
+ for (i = 0; i < chip->nsels; i++) {
+ chip->nand.select_chip(mtd, i);
+ ret = chip->nand.onfi_set_features(mtd,
+ &chip->nand,
+ ONFI_FEATURE_ADDR_TIMING_MODE,
+ feature);
+ chip->nand.select_chip(mtd, -1);
+ if (ret)
+ return ret;
+ }
+ }
+
+ timings = onfi_async_timing_mode_to_sdr_timings(mode);
+ if (IS_ERR(timings))
+ return PTR_ERR(timings);
+
+ return sunxi_nand_chip_set_timings(chip, timings);
+}
+
+static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
+ struct nand_ecc_ctrl *ecc)
+{
+ static const u8 strengths[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 };
+ struct sunxi_nand_hw_ecc *data;
+ struct nand_ecclayout *layout;
+ int nsectors;
+ int ret;
+ int i;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ if (ecc->size != 512 && ecc->size != 1024)
+ return -EINVAL;
+
+ /* Prefer 1k ECC chunk over 512 ones */
+ if (ecc->size == 512 && mtd->writesize > 512) {
+ ecc->size = 1024;
+ ecc->strength *= 2;
+ }
+
+ /* Add ECC info retrieval from DT */
+ for (i = 0; i < ARRAY_SIZE(strengths); i++) {
+ if (ecc->strength <= strengths[i])
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(strengths)) {
+ dev_err(nfc->dev, "unsupported strength\n");
+ ret = -ENOTSUPP;
+ goto err;
+ }
+
+ data->mode = i;
+
+ /* HW ECC always request ECC bytes for 1024 bytes blocks */
+ ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * 1024), 8);
+
+ /* HW ECC always work with even numbers of ECC bytes */
+ ecc->bytes = ALIGN(ecc->bytes, 2);
+
+ layout = &data->layout;
+ nsectors = mtd->writesize / ecc->size;
+
+ if (mtd->oobsize < ((ecc->bytes + 4) * nsectors)) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ layout->eccbytes = (ecc->bytes * nsectors);
+
+ ecc->layout = layout;
+ ecc->priv = data;
+
+ return 0;
+
+err:
+ kfree(data);
+
+ return ret;
+}
+
+#ifndef __UBOOT__
+static void sunxi_nand_hw_common_ecc_ctrl_cleanup(struct nand_ecc_ctrl *ecc)
+{
+ kfree(ecc->priv);
+}
+#endif /* __UBOOT__ */
+
+static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
+ struct nand_ecc_ctrl *ecc)
+{
+ struct nand_ecclayout *layout;
+ int nsectors;
+ int i, j;
+ int ret;
+
+ ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc);
+ if (ret)
+ return ret;
+
+ ecc->read_page = sunxi_nfc_hw_ecc_read_page;
+ ecc->write_page = sunxi_nfc_hw_ecc_write_page;
+ ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage;
+ ecc->write_subpage = sunxi_nfc_hw_ecc_write_subpage;
+ layout = ecc->layout;
+ nsectors = mtd->writesize / ecc->size;
+
+ for (i = 0; i < nsectors; i++) {
+ if (i) {
+ layout->oobfree[i].offset =
+ layout->oobfree[i - 1].offset +
+ layout->oobfree[i - 1].length +
+ ecc->bytes;
+ layout->oobfree[i].length = 4;
+ } else {
+ /*
+ * The first 2 bytes are used for BB markers, hence we
+ * only have 2 bytes available in the first user data
+ * section.
+ */
+ layout->oobfree[i].length = 2;
+ layout->oobfree[i].offset = 2;
+ }
+
+ for (j = 0; j < ecc->bytes; j++)
+ layout->eccpos[(ecc->bytes * i) + j] =
+ layout->oobfree[i].offset +
+ layout->oobfree[i].length + j;
+ }
+
+ if (mtd->oobsize > (ecc->bytes + 4) * nsectors) {
+ layout->oobfree[nsectors].offset =
+ layout->oobfree[nsectors - 1].offset +
+ layout->oobfree[nsectors - 1].length +
+ ecc->bytes;
+ layout->oobfree[nsectors].length = mtd->oobsize -
+ ((ecc->bytes + 4) * nsectors);
+ }
+
+ return 0;
+}
+
+static int sunxi_nand_hw_syndrome_ecc_ctrl_init(struct mtd_info *mtd,
+ struct nand_ecc_ctrl *ecc)
+{
+ struct nand_ecclayout *layout;
+ int nsectors;
+ int i;
+ int ret;
+
+ ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc);
+ if (ret)
+ return ret;
+
+ ecc->prepad = 4;
+ ecc->read_page = sunxi_nfc_hw_syndrome_ecc_read_page;
+ ecc->write_page = sunxi_nfc_hw_syndrome_ecc_write_page;
+
+ layout = ecc->layout;
+ nsectors = mtd->writesize / ecc->size;
+
+ for (i = 0; i < (ecc->bytes * nsectors); i++)
+ layout->eccpos[i] = i;
+
+ layout->oobfree[0].length = mtd->oobsize - i;
+ layout->oobfree[0].offset = i;
+
+ return 0;
+}
+
+#ifndef __UBOOT__
+static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
+{
+ switch (ecc->mode) {
+ case NAND_ECC_HW:
+ case NAND_ECC_HW_SYNDROME:
+ sunxi_nand_hw_common_ecc_ctrl_cleanup(ecc);
+ break;
+ case NAND_ECC_NONE:
+ kfree(ecc->layout);
+ default:
+ break;
+ }
+}
+#endif /* __UBOOT__ */
+
+static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc)
+{
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ int ret;
+
+ if (!ecc->size) {
+ ecc->size = nand->ecc_step_ds;
+ ecc->strength = nand->ecc_strength_ds;
+ }
+
+ if (!ecc->size || !ecc->strength)
+ return -EINVAL;
+
+ switch (ecc->mode) {
+ case NAND_ECC_SOFT_BCH:
+ break;
+ case NAND_ECC_HW:
+ ret = sunxi_nand_hw_ecc_ctrl_init(mtd, ecc);
+ if (ret)
+ return ret;
+ break;
+ case NAND_ECC_HW_SYNDROME:
+ ret = sunxi_nand_hw_syndrome_ecc_ctrl_init(mtd, ecc);
+ if (ret)
+ return ret;
+ break;
+ case NAND_ECC_NONE:
+ ecc->layout = kzalloc(sizeof(*ecc->layout), GFP_KERNEL);
+ if (!ecc->layout)
+ return -ENOMEM;
+ ecc->layout->oobfree[0].length = mtd->oobsize;
+ case NAND_ECC_SOFT:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int sunxi_nand_chip_init(int node, struct sunxi_nfc *nfc, int devnum)
+{
+ const struct nand_sdr_timings *timings;
+ const void *blob = gd->fdt_blob;
+ struct sunxi_nand_chip *chip;
+ struct mtd_info *mtd;
+ struct nand_chip *nand;
+ int nsels;
+ int ret;
+ int i;
+ u32 cs[8], rb[8];
+
+ if (!fdt_getprop(blob, node, "reg", &nsels))
+ return -EINVAL;
+
+ nsels /= sizeof(u32);
+ if (!nsels || nsels > 8) {
+ dev_err(dev, "invalid reg property size\n");
+ return -EINVAL;
+ }
+
+ chip = kzalloc(sizeof(*chip) +
+ (nsels * sizeof(struct sunxi_nand_chip_sel)),
+ GFP_KERNEL);
+ if (!chip) {
+ dev_err(dev, "could not allocate chip\n");
+ return -ENOMEM;
+ }
+
+ chip->nsels = nsels;
+ chip->selected = -1;
+
+ for (i = 0; i < nsels; i++) {
+ cs[i] = -1;
+ rb[i] = -1;
+ }
+
+ ret = fdtdec_get_int_array(gd->fdt_blob, node, "reg", cs, nsels);
+ if (ret) {
+ dev_err(dev, "could not retrieve reg property: %d\n", ret);
+ return ret;
+ }
+
+ ret = fdtdec_get_int_array(gd->fdt_blob, node, "allwinner,rb", rb,
+ nsels);
+ if (ret) {
+ dev_err(dev, "could not retrieve reg property: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < nsels; i++) {
+ int tmp = cs[i];
+
+ if (tmp > NFC_MAX_CS) {
+ dev_err(dev,
+ "invalid reg value: %u (max CS = 7)\n",
+ tmp);
+ return -EINVAL;
+ }
+
+ if (test_and_set_bit(tmp, &nfc->assigned_cs)) {
+ dev_err(dev, "CS %d already assigned\n", tmp);
+ return -EINVAL;
+ }
+
+ chip->sels[i].cs = tmp;
+
+ tmp = rb[i];
+ if (tmp >= 0 && tmp < 2) {
+ chip->sels[i].rb.type = RB_NATIVE;
+ chip->sels[i].rb.info.nativeid = tmp;
+ } else {
+ ret = gpio_request_by_name_nodev(blob, node,
+ "rb-gpios", i,
+ &chip->sels[i].rb.info.gpio,
+ GPIOD_IS_IN);
+ if (ret)
+ chip->sels[i].rb.type = RB_GPIO;
+ else
+ chip->sels[i].rb.type = RB_NONE;
+ }
+ }
+
+ timings = onfi_async_timing_mode_to_sdr_timings(0);
+ if (IS_ERR(timings)) {
+ ret = PTR_ERR(timings);
+ dev_err(dev,
+ "could not retrieve timings for ONFI mode 0: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = sunxi_nand_chip_set_timings(chip, timings);
+ if (ret) {
+ dev_err(dev, "could not configure chip timings: %d\n", ret);
+ return ret;
+ }
+
+ nand = &chip->nand;
+ /* Default tR value specified in the ONFI spec (chapter 4.15.1) */
+ nand->chip_delay = 200;
+ nand->controller = &nfc->controller;
+ /*
+ * Set the ECC mode to the default value in case nothing is specified
+ * in the DT.
+ */
+ nand->ecc.mode = NAND_ECC_HW;
+ nand->flash_node = node;
+ nand->select_chip = sunxi_nfc_select_chip;
+ nand->cmd_ctrl = sunxi_nfc_cmd_ctrl;
+ nand->read_buf = sunxi_nfc_read_buf;
+ nand->write_buf = sunxi_nfc_write_buf;
+ nand->read_byte = sunxi_nfc_read_byte;
+
+ mtd = nand_to_mtd(nand);
+ ret = nand_scan_ident(mtd, nsels, NULL);
+ if (ret)
+ return ret;
+
+ if (nand->bbt_options & NAND_BBT_USE_FLASH)
+ nand->bbt_options |= NAND_BBT_NO_OOB;
+
+ if (nand->options & NAND_NEED_SCRAMBLING)
+ nand->options |= NAND_NO_SUBPAGE_WRITE;
+
+ nand->options |= NAND_SUBPAGE_READ;
+
+ ret = sunxi_nand_chip_init_timings(chip);
+ if (ret) {
+ dev_err(dev, "could not configure chip timings: %d\n", ret);
+ return ret;
+ }
+
+ ret = sunxi_nand_ecc_init(mtd, &nand->ecc);
+ if (ret) {
+ dev_err(dev, "ECC init failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = nand_scan_tail(mtd);
+ if (ret) {
+ dev_err(dev, "nand_scan_tail failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = nand_register(devnum, mtd);
+ if (ret) {
+ dev_err(dev, "failed to register mtd device: %d\n", ret);
+ return ret;
+ }
+
+ list_add_tail(&chip->node, &nfc->chips);
+
+ return 0;
+}
+
+static int sunxi_nand_chips_init(int node, struct sunxi_nfc *nfc)
+{
+ const void *blob = gd->fdt_blob;
+ int nand_node;
+ int ret, i = 0;
+
+ for (nand_node = fdt_first_subnode(blob, node); nand_node >= 0;
+ nand_node = fdt_next_subnode(blob, nand_node))
+ i++;
+
+ if (i > 8) {
+ dev_err(dev, "too many NAND chips: %d (max = 8)\n", i);
+ return -EINVAL;
+ }
+
+ i = 0;
+ for (nand_node = fdt_first_subnode(blob, node); nand_node >= 0;
+ nand_node = fdt_next_subnode(blob, nand_node)) {
+ ret = sunxi_nand_chip_init(nand_node, nfc, i++);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+#ifndef __UBOOT__
+static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc)
+{
+ struct sunxi_nand_chip *chip;
+
+ while (!list_empty(&nfc->chips)) {
+ chip = list_first_entry(&nfc->chips, struct sunxi_nand_chip,
+ node);
+ nand_release(&chip->mtd);
+ sunxi_nand_ecc_cleanup(&chip->nand.ecc);
+ list_del(&chip->node);
+ kfree(chip);
+ }
+}
+#endif /* __UBOOT__ */
+
+void sunxi_nand_init(void)
+{
+ const void *blob = gd->fdt_blob;
+ struct sunxi_nfc *nfc;
+ fdt_addr_t regs;
+ int node;
+ int ret;
+
+ nfc = kzalloc(sizeof(*nfc), GFP_KERNEL);
+ if (!nfc)
+ return;
+
+ spin_lock_init(&nfc->controller.lock);
+ init_waitqueue_head(&nfc->controller.wq);
+ INIT_LIST_HEAD(&nfc->chips);
+
+ node = fdtdec_next_compatible(blob, 0, COMPAT_SUNXI_NAND);
+ if (node < 0) {
+ pr_err("unable to find nfc node in device tree\n");
+ goto err;
+ }
+
+ if (!fdtdec_get_is_enabled(blob, node)) {
+ pr_err("nfc disabled in device tree\n");
+ goto err;
+ }
+
+ regs = fdtdec_get_addr(blob, node, "reg");
+ if (regs == FDT_ADDR_T_NONE) {
+ pr_err("unable to find nfc address in device tree\n");
+ goto err;
+ }
+
+ nfc->regs = (void *)regs;
+
+ ret = sunxi_nfc_rst(nfc);
+ if (ret)
+ goto err;
+
+ ret = sunxi_nand_chips_init(node, nfc);
+ if (ret) {
+ dev_err(dev, "failed to init nand chips\n");
+ goto err;
+ }
+
+ return;
+
+err:
+ kfree(nfc);
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Boris BREZILLON");
+MODULE_DESCRIPTION("Allwinner NAND Flash Controller driver");
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 1785e3b..2972dba 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -123,21 +123,21 @@ config QCA953X_PINCTRL
both the GPIO definitions and pin control functions for each
available multiplex function.
-config ROCKCHIP_PINCTRL
- bool "Rockchip pin control driver"
+config ROCKCHIP_RK3036_PINCTRL
+ bool "Rockchip rk3036 pin control driver"
depends on DM
help
- Support pin multiplexing control on Rockchip SoCs. The driver is
+ Support pin multiplexing control on Rockchip rk3036 SoCs. The driver is
controlled by a device tree node which contains both the GPIO
definitions and pin control functions for each available multiplex
function.
-config ROCKCHIP_3036_PINCTRL
- bool "Rockchip rk3036 pin control driver"
+config ROCKCHIP_RK3288_PINCTRL
+ bool "Rockchip pin control driver"
depends on DM
help
- Support pin multiplexing control on Rockchip rk3036 SoCs. The driver is
- controlled by a device tree node which contains both the GPIO
+ Support pin multiplexing control on Rockchip rk3288 SoCs. The driver
+ is controlled by a device tree node which contains both the GPIO
definitions and pin control functions for each available multiplex
function.
diff --git a/drivers/pinctrl/rockchip/Makefile b/drivers/pinctrl/rockchip/Makefile
index 6fa7d00..64e9587 100644
--- a/drivers/pinctrl/rockchip/Makefile
+++ b/drivers/pinctrl/rockchip/Makefile
@@ -5,5 +5,5 @@
# SPDX-License-Identifier: GPL-2.0+
#
-obj-$(CONFIG_ROCKCHIP_PINCTRL) += pinctrl_rk3288.o
-obj-$(CONFIG_ROCKCHIP_3036_PINCTRL) += pinctrl_rk3036.o
+obj-$(CONFIG_ROCKCHIP_RK3036_PINCTRL) += pinctrl_rk3036.o
+obj-$(CONFIG_ROCKCHIP_RK3288_PINCTRL) += pinctrl_rk3288.o
diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c
index a23278d..029927f 100644
--- a/drivers/usb/gadget/dwc2_udc_otg.c
+++ b/drivers/usb/gadget/dwc2_udc_otg.c
@@ -403,6 +403,7 @@ static void reconfig_usbd(struct dwc2_udc *dev)
int i;
unsigned int uTemp = writel(CORE_SOFT_RESET, &reg->grstctl);
uint32_t dflt_gusbcfg;
+ uint32_t rx_fifo_sz, tx_fifo_sz, np_tx_fifo_sz;
debug("Reseting OTG controller\n");
@@ -467,18 +468,27 @@ static void reconfig_usbd(struct dwc2_udc *dev)
/* 10. Unmask device IN EP common interrupts*/
writel(DIEPMSK_INIT, &reg->diepmsk);
+ rx_fifo_sz = RX_FIFO_SIZE;
+ np_tx_fifo_sz = NPTX_FIFO_SIZE;
+ tx_fifo_sz = PTX_FIFO_SIZE;
+
+ if (dev->pdata->rx_fifo_sz)
+ rx_fifo_sz = dev->pdata->rx_fifo_sz;
+ if (dev->pdata->np_tx_fifo_sz)
+ np_tx_fifo_sz = dev->pdata->np_tx_fifo_sz;
+ if (dev->pdata->tx_fifo_sz)
+ tx_fifo_sz = dev->pdata->tx_fifo_sz;
+
/* 11. Set Rx FIFO Size (in 32-bit words) */
- writel(RX_FIFO_SIZE >> 2, &reg->grxfsiz);
+ writel(rx_fifo_sz, &reg->grxfsiz);
/* 12. Set Non Periodic Tx FIFO Size */
- writel((NPTX_FIFO_SIZE >> 2) << 16 | ((RX_FIFO_SIZE >> 2)) << 0,
+ writel((np_tx_fifo_sz << 16) | rx_fifo_sz,
&reg->gnptxfsiz);
for (i = 1; i < DWC2_MAX_HW_ENDPOINTS; i++)
- writel((PTX_FIFO_SIZE >> 2) << 16 |
- ((RX_FIFO_SIZE + NPTX_FIFO_SIZE +
- PTX_FIFO_SIZE*(i-1)) >> 2) << 0,
- &reg->dieptxf[i-1]);
+ writel((rx_fifo_sz + np_tx_fifo_sz + tx_fifo_sz*(i-1)) |
+ tx_fifo_sz << 16, &reg->dieptxf[i-1]);
/* Flush the RX FIFO */
writel(RX_FIFO_FLUSH, &reg->grstctl);
diff --git a/drivers/usb/gadget/dwc2_udc_otg_regs.h b/drivers/usb/gadget/dwc2_udc_otg_regs.h
index 78ec90e..c94396a 100644
--- a/drivers/usb/gadget/dwc2_udc_otg_regs.h
+++ b/drivers/usb/gadget/dwc2_udc_otg_regs.h
@@ -130,9 +130,9 @@ struct dwc2_usbotg_reg {
#define HIGH_SPEED_CONTROL_PKT_SIZE 64
#define HIGH_SPEED_BULK_PKT_SIZE 512
-#define RX_FIFO_SIZE (1024*4)
-#define NPTX_FIFO_SIZE (1024*4)
-#define PTX_FIFO_SIZE (1536*1)
+#define RX_FIFO_SIZE (1024)
+#define NPTX_FIFO_SIZE (1024)
+#define PTX_FIFO_SIZE (384)
#define DEPCTL_TXFNUM_0 (0x0<<22)
#define DEPCTL_TXFNUM_1 (0x1<<22)
diff --git a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c
index 12f5c85..0d6d2fb 100644
--- a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c
+++ b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c
@@ -110,6 +110,9 @@ static int setdma_rx(struct dwc2_ep *ep, struct dwc2_request *req)
ctrl = readl(&reg->out_endp[ep_num].doepctl);
+ invalidate_dcache_range((unsigned long) ep->dma_buf,
+ (unsigned long) ep->dma_buf + ep->len);
+
writel((unsigned int) ep->dma_buf, &reg->out_endp[ep_num].doepdma);
writel(DOEPT_SIZ_PKT_CNT(pktcnt) | DOEPT_SIZ_XFER_SIZE(length),
&reg->out_endp[ep_num].doeptsiz);
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index 93d147e..4e548c2 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -7,3 +7,4 @@
obj-$(CONFIG_TWL4030_USB) += twl4030.o
obj-$(CONFIG_OMAP_USB_PHY) += omap_usb_phy.o
+obj-$(CONFIG_ROCKCHIP_USB2_PHY) += rockchip_usb2_phy.o
diff --git a/drivers/usb/phy/rockchip_usb2_phy.c b/drivers/usb/phy/rockchip_usb2_phy.c
new file mode 100644
index 0000000..1958478
--- /dev/null
+++ b/drivers/usb/phy/rockchip_usb2_phy.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2016 Rockchip Electronics Co., Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <libfdt.h>
+
+#include "../gadget/dwc2_udc_otg_priv.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define BIT_WRITEABLE_SHIFT 16
+
+struct usb2phy_reg {
+ unsigned int offset;
+ unsigned int bitend;
+ unsigned int bitstart;
+ unsigned int disable;
+ unsigned int enable;
+};
+
+/**
+ * struct rockchip_usb2_phy_cfg: usb-phy port configuration
+ * @port_reset: usb otg per-port reset register
+ * @soft_con: software control usb otg register
+ * @suspend: phy suspend register
+ */
+struct rockchip_usb2_phy_cfg {
+ struct usb2phy_reg port_reset;
+ struct usb2phy_reg soft_con;
+ struct usb2phy_reg suspend;
+};
+
+struct rockchip_usb2_phy_dt_id {
+ char compatible[128];
+ const void *data;
+};
+
+static const struct rockchip_usb2_phy_cfg rk3288_pdata = {
+ .port_reset = {0x00, 12, 12, 0, 1},
+ .soft_con = {0x08, 2, 2, 0, 1},
+ .suspend = {0x0c, 5, 0, 0x01, 0x2A},
+};
+
+static struct rockchip_usb2_phy_dt_id rockchip_usb2_phy_dt_ids[] = {
+ { .compatible = "rockchip,rk3288-usb-phy", .data = &rk3288_pdata },
+ {}
+};
+
+static void property_enable(struct dwc2_plat_otg_data *pdata,
+ const struct usb2phy_reg *reg, bool en)
+{
+ unsigned int val, mask, tmp;
+
+ tmp = en ? reg->enable : reg->disable;
+ mask = GENMASK(reg->bitend, reg->bitstart);
+ val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT);
+
+ writel(val, pdata->regs_phy + reg->offset);
+}
+
+
+void otg_phy_init(struct dwc2_udc *dev)
+{
+ struct dwc2_plat_otg_data *pdata = dev->pdata;
+ struct rockchip_usb2_phy_cfg *phy_cfg = NULL;
+ struct rockchip_usb2_phy_dt_id *of_id;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(rockchip_usb2_phy_dt_ids); i++) {
+ of_id = &rockchip_usb2_phy_dt_ids[i];
+ if (fdt_node_check_compatible(gd->fdt_blob, pdata->phy_of_node,
+ of_id->compatible) == 0) {
+ phy_cfg = (struct rockchip_usb2_phy_cfg *)of_id->data;
+ break;
+ }
+ }
+ if (!phy_cfg) {
+ debug("Can't find device platform data\n");
+
+ hang();
+ return;
+ }
+ pdata->priv = phy_cfg;
+ /* disable software control */
+ property_enable(pdata, &phy_cfg->soft_con, false);
+
+ /* reset otg port */
+ property_enable(pdata, &phy_cfg->port_reset, true);
+ mdelay(1);
+ property_enable(pdata, &phy_cfg->port_reset, false);
+ udelay(1);
+}
+
+void otg_phy_off(struct dwc2_udc *dev)
+{
+ struct dwc2_plat_otg_data *pdata = dev->pdata;
+ struct rockchip_usb2_phy_cfg *phy_cfg = pdata->priv;
+
+ /* enable software control */
+ property_enable(pdata, &phy_cfg->soft_con, true);
+ /* enter suspend */
+ property_enable(pdata, &phy_cfg->suspend, true);
+}
diff --git a/drivers/video/rockchip/rk_vop.c b/drivers/video/rockchip/rk_vop.c
index cc26f19..c6d88d9 100644
--- a/drivers/video/rockchip/rk_vop.c
+++ b/drivers/video/rockchip/rk_vop.c
@@ -238,7 +238,7 @@ int rk_display_init(struct udevice *dev, ulong fbbase,
return ret;
}
- ret = uclass_get_device(UCLASS_CLK, 0, &dev_clk);
+ ret = rockchip_get_clk(&dev_clk);
if (!ret) {
clk.id = DCLK_VOP0 + remote_vop_id;
ret = clk_request(dev_clk, &clk);
diff --git a/include/configs/evb-rk3288.h b/include/configs/evb-rk3288.h
new file mode 100644
index 0000000..342557f
--- /dev/null
+++ b/include/configs/evb-rk3288.h
@@ -0,0 +1,26 @@
+/*
+ * (C) Copyright 2016 Rockchip Electronics Co., Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define ROCKCHIP_DEVICE_SETTINGS
+#include <configs/rk3288_common.h>
+
+#define CONFIG_SPL_MMC_SUPPORT
+
+#define CONFIG_ENV_IS_IN_MMC
+#define CONFIG_SYS_MMC_ENV_DEV 1
+/* SPL @ 32k for ~36k
+ * ENV @ 96k
+ * u-boot @ 128K
+ */
+#define CONFIG_ENV_OFFSET (96 * 1024)
+
+#define CONFIG_SYS_WHITE_ON_BLACK
+#define CONFIG_CONSOLE_SCROLL_LINES 10
+
+#endif
diff --git a/include/configs/evb_rk3399.h b/include/configs/evb_rk3399.h
new file mode 100644
index 0000000..047850a
--- /dev/null
+++ b/include/configs/evb_rk3399.h
@@ -0,0 +1,26 @@
+/*
+ * (C) Copyright 2016 Rockchip Electronics Co., Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __EVB_RK3399_H
+#define __EVB_RK3399_H
+
+#include <configs/rk3399_common.h>
+
+#define CONFIG_ENV_IS_IN_MMC
+#define CONFIG_SYS_MMC_ENV_DEV 0
+/*
+ * SPL @ 32k for ~36k
+ * ENV @ 96k
+ * u-boot @ 128K
+ */
+#define CONFIG_ENV_OFFSET (96 * 1024)
+
+#define SDRAM_BANK_SIZE (2UL << 30)
+
+#define CONFIG_SYS_WHITE_ON_BLACK
+#define CONFIG_CONSOLE_SCROLL_LINES 10
+
+#endif
diff --git a/include/configs/rk3288_common.h b/include/configs/rk3288_common.h
index 8adc26f..2a36c17 100644
--- a/include/configs/rk3288_common.h
+++ b/include/configs/rk3288_common.h
@@ -33,7 +33,12 @@
#define CONFIG_SYS_NS16550_MEM32
#define CONFIG_SPL_BOARD_INIT
+#ifdef CONFIG_ROCKCHIP_SPL_BACK_TO_BROM
+/* Bootrom will load u-boot binary to 0x0 once return from SPL */
+#define CONFIG_SYS_TEXT_BASE 0x00000000
+#else
#define CONFIG_SYS_TEXT_BASE 0x00100000
+#endif
#define CONFIG_SYS_INIT_SP_ADDR 0x00100000
#define CONFIG_SYS_LOAD_ADDR 0x00800800
#define CONFIG_SPL_STACK 0xff718000
@@ -79,6 +84,32 @@
#define CONFIG_SPI
#define CONFIG_SF_DEFAULT_SPEED 20000000
+/* usb otg */
+#define CONFIG_USB_GADGET
+#define CONFIG_USB_GADGET_DUALSPEED
+#define CONFIG_USB_GADGET_DWC2_OTG
+#define CONFIG_ROCKCHIP_USB2_PHY
+#define CONFIG_USB_GADGET_VBUS_DRAW 0
+
+/* fastboot */
+#define CONFIG_CMD_FASTBOOT
+#define CONFIG_USB_FUNCTION_FASTBOOT
+#define CONFIG_FASTBOOT_FLASH
+#define CONFIG_FASTBOOT_FLASH_MMC_DEV 1 /* eMMC */
+/* stroe safely fastboot buffer data to the middle of bank */
+#define CONFIG_FASTBOOT_BUF_ADDR (CONFIG_SYS_SDRAM_BASE \
+ + SDRAM_BANK_SIZE / 2)
+#define CONFIG_FASTBOOT_BUF_SIZE 0x08000000
+
+#define CONFIG_USB_GADGET_DOWNLOAD
+#define CONFIG_G_DNL_MANUFACTURER "Rockchip"
+#define CONFIG_G_DNL_VENDOR_NUM 0x2207
+#define CONFIG_G_DNL_PRODUCT_NUM 0x320a
+
+/* Enable gpt partition table */
+#define CONFIG_CMD_GPT
+#define CONFIG_EFI_PARTITION
+
#ifndef CONFIG_SPL_BUILD
#include <config_distro_defaults.h>
diff --git a/include/configs/rk3399_common.h b/include/configs/rk3399_common.h
new file mode 100644
index 0000000..6ce1aa7
--- /dev/null
+++ b/include/configs/rk3399_common.h
@@ -0,0 +1,73 @@
+/*
+ * (C) Copyright 2016 Rockchip Electronics Co., Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __CONFIG_RK3399_COMMON_H
+#define __CONFIG_RK3399_COMMON_H
+
+#define CONFIG_SYS_CACHELINE_SIZE 64
+
+#define CONFIG_SYS_NO_FLASH
+#define CONFIG_NR_DRAM_BANKS 1
+#define CONFIG_ENV_SIZE 0x2000
+#define CONFIG_SYS_MAXARGS 16
+#define CONFIG_BAUDRATE 1500000
+#define CONFIG_SYS_MALLOC_LEN (32 << 20)
+#define CONFIG_SYS_CBSIZE 1024
+#define CONFIG_SKIP_LOWLEVEL_INIT
+#define CONFIG_DISPLAY_BOARDINFO
+
+#define CONFIG_SYS_NS16550_MEM32
+
+#define CONFIG_SYS_TEXT_BASE 0x00200000
+#define CONFIG_SYS_INIT_SP_ADDR 0x00300000
+#define CONFIG_SYS_LOAD_ADDR 0x00800800
+
+#define CONFIG_SYS_BOOTM_LEN (64 << 20) /* 64M */
+
+/* MMC/SD IP block */
+#define CONFIG_MMC
+#define CONFIG_GENERIC_MMC
+#define CONFIG_SDHCI
+#define CONFIG_BOUNCE_BUFFER
+#define CONFIG_ROCKCHIP_SDHCI_MAX_FREQ 200000000
+
+#define CONFIG_FAT_WRITE
+
+/* RAW SD card / eMMC locations. */
+#define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR 256
+#define CONFIG_SYS_SPI_U_BOOT_OFFS (128 << 10)
+
+/* FAT sd card locations. */
+#define CONFIG_SYS_MMCSD_FS_BOOT_PARTITION 1
+#define CONFIG_SYS_SDRAM_BASE 0
+#define CONFIG_NR_DRAM_BANKS 1
+
+#define CONFIG_SPI_FLASH
+#define CONFIG_SPI
+#define CONFIG_SF_DEFAULT_SPEED 20000000
+
+#ifndef CONFIG_SPL_BUILD
+#include <config_distro_defaults.h>
+
+#define ENV_MEM_LAYOUT_SETTINGS \
+ "scriptaddr=0x00000000\0" \
+ "pxefile_addr_r=0x00100000\0" \
+ "fdt_addr_r=0x01f00000\0" \
+ "kernel_addr_r=0x02000000\0" \
+ "ramdisk_addr_r=0x04000000\0"
+
+/* First try to boot from SD (index 0), then eMMC (index 1) */
+#define BOOT_TARGET_DEVICES(func) \
+ func(MMC, mmc, 0) \
+ func(MMC, mmc, 1)
+
+#include <config_distro_bootcmd.h>
+#define CONFIG_EXTRA_ENV_SETTINGS \
+ BOOTENV
+
+#endif
+
+#endif
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h
index 4de89f8..94e024b 100644
--- a/include/configs/sandbox.h
+++ b/include/configs/sandbox.h
@@ -27,7 +27,10 @@
#define CONFIG_SYS_STDIO_DEREGISTER
-/* Number of bits in a C 'long' on this architecture */
+/*
+ * Number of bits in a C 'long' on this architecture. Set this to 32 when
+ * building on a 32-bit machine.
+ */
#define CONFIG_SANDBOX_BITS_PER_LONG 64
#define CONFIG_LMB
@@ -82,7 +85,6 @@
#define CONFIG_CMD_SF_TEST
#define CONFIG_I2C_EDID
-#define CONFIG_I2C_EEPROM
/* Memory things - we don't really want a memory test */
#define CONFIG_SYS_LOAD_ADDR 0x00000000
diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
index 6358901..b9aa62b 100644
--- a/include/configs/sunxi-common.h
+++ b/include/configs/sunxi-common.h
@@ -134,7 +134,10 @@
#define CONFIG_SERIAL_TAG
#ifdef CONFIG_NAND_SUNXI
+#define CONFIG_SYS_NAND_MAX_ECCPOS 1664
#define CONFIG_SPL_NAND_SUPPORT 1
+#define CONFIG_SYS_NAND_ONFI_DETECTION
+#define CONFIG_SYS_MAX_NAND_DEVICE 8
#endif
#ifdef CONFIG_SPL_SPI_SUNXI
diff --git a/include/configs/ti_armv7_common.h b/include/configs/ti_armv7_common.h
index ba7cf15..9f947ee 100644
--- a/include/configs/ti_armv7_common.h
+++ b/include/configs/ti_armv7_common.h
@@ -108,9 +108,25 @@
/* Timer information. */
#define CONFIG_SYS_PTV 2 /* Divisor: 2^(PTV+1) => 8 */
+/*
+ * Disable DM_* for SPL build and can be re-enabled after adding
+ * DM support in SPL
+ */
+#ifdef CONFIG_SPL_BUILD
+#undef CONFIG_DM_I2C
+#endif
+
/* I2C IP block */
#define CONFIG_I2C
+#ifndef CONFIG_DM_I2C
#define CONFIG_SYS_I2C
+#else
+/*
+ * Enable CONFIG_DM_I2C_COMPAT temporarily until all the i2c client
+ * devices are adopted to DM
+ */
+#define CONFIG_DM_I2C_COMPAT
+#endif
/* MMC/SD IP block */
#define CONFIG_MMC
diff --git a/include/dm/device.h b/include/dm/device.h
index c825d47..705849b 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -207,6 +207,10 @@ struct driver {
#define U_BOOT_DRIVER(__name) \
ll_entry_declare(struct driver, __name, driver)
+/* Get a pointer to a given driver */
+#define DM_GET_DRIVER(__name) \
+ ll_entry_get(struct driver, __name, driver)
+
/**
* dev_get_platdata() - Get the platform data for a device
*
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index fd368b6..84f05bc 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -38,6 +38,7 @@ struct uclass {
struct list_head sibling_node;
};
+struct driver;
struct udevice;
/* Members of this uclass sequence themselves with aliases */
@@ -194,6 +195,23 @@ int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent,
const char *name, struct udevice **devp);
/**
+ * uclass_get_device_by_driver() - Get a uclass device for a driver
+ *
+ * This searches the devices in the uclass for one that uses the given
+ * driver. Use DM_GET_DRIVER(name) for the @drv argument, where 'name' is
+ * the driver name - as used in U_BOOT_DRIVER(name).
+ *
+ * The device is probed to activate it ready for use.
+ *
+ * @id: ID to look up
+ * @drv: Driver to look for
+ * @devp: Returns pointer to the first device with that driver
+ * @return 0 if OK, -ve on error
+ */
+int uclass_get_device_by_driver(enum uclass_id id, const struct driver *drv,
+ struct udevice **devp);
+
+/**
* uclass_first_device() - Get the first device in a uclass
*
* The device returned is probed if necessary, and ready for use
diff --git a/include/dt-bindings/clock/rk3399-cru.h b/include/dt-bindings/clock/rk3399-cru.h
new file mode 100644
index 0000000..0a86aec
--- /dev/null
+++ b/include/dt-bindings/clock/rk3399-cru.h
@@ -0,0 +1,746 @@
+/*
+ * Copyright (c) 2016 Rockchip Electronics Co. Ltd.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _DT_BINDINGS_CLK_ROCKCHIP_RK3399_H
+#define _DT_BINDINGS_CLK_ROCKCHIP_RK3399_H
+
+/* core clocks */
+#define PLL_APLLL 1
+#define PLL_APLLB 2
+#define PLL_DPLL 3
+#define PLL_CPLL 4
+#define PLL_GPLL 5
+#define PLL_NPLL 6
+#define PLL_VPLL 7
+#define ARMCLKL 8
+#define ARMCLKB 9
+
+/* sclk gates (special clocks) */
+#define SCLK_I2C1 65
+#define SCLK_I2C2 66
+#define SCLK_I2C3 67
+#define SCLK_I2C5 68
+#define SCLK_I2C6 69
+#define SCLK_I2C7 70
+#define SCLK_SPI0 71
+#define SCLK_SPI1 72
+#define SCLK_SPI2 73
+#define SCLK_SPI4 74
+#define SCLK_SPI5 75
+#define SCLK_SDMMC 76
+#define SCLK_SDIO 77
+#define SCLK_EMMC 78
+#define SCLK_TSADC 79
+#define SCLK_SARADC 80
+#define SCLK_UART0 81
+#define SCLK_UART1 82
+#define SCLK_UART2 83
+#define SCLK_UART3 84
+#define SCLK_SPDIF_8CH 85
+#define SCLK_I2S0_8CH 86
+#define SCLK_I2S1_8CH 87
+#define SCLK_I2S2_8CH 88
+#define SCLK_I2S_8CH_OUT 89
+#define SCLK_TIMER00 90
+#define SCLK_TIMER01 91
+#define SCLK_TIMER02 92
+#define SCLK_TIMER03 93
+#define SCLK_TIMER04 94
+#define SCLK_TIMER05 95
+#define SCLK_TIMER06 96
+#define SCLK_TIMER07 97
+#define SCLK_TIMER08 98
+#define SCLK_TIMER09 99
+#define SCLK_TIMER10 100
+#define SCLK_TIMER11 101
+#define SCLK_MACREF 102
+#define SCLK_MAC_RX 103
+#define SCLK_MAC_TX 104
+#define SCLK_MAC 105
+#define SCLK_MACREF_OUT 106
+#define SCLK_VOP0_PWM 107
+#define SCLK_VOP1_PWM 108
+#define SCLK_RGA_CORE 109
+#define SCLK_ISP0 110
+#define SCLK_ISP1 111
+#define SCLK_HDMI_CEC 112
+#define SCLK_HDMI_SFR 113
+#define SCLK_DP_CORE 114
+#define SCLK_PVTM_CORE_L 115
+#define SCLK_PVTM_CORE_B 116
+#define SCLK_PVTM_GPU 117
+#define SCLK_PVTM_DDR 118
+#define SCLK_MIPIDPHY_REF 119
+#define SCLK_MIPIDPHY_CFG 120
+#define SCLK_HSICPHY 121
+#define SCLK_USBPHY480M 122
+#define SCLK_USB2PHY0_REF 123
+#define SCLK_USB2PHY1_REF 124
+#define SCLK_UPHY0_TCPDPHY_REF 125
+#define SCLK_UPHY0_TCPDCORE 126
+#define SCLK_UPHY1_TCPDPHY_REF 127
+#define SCLK_UPHY1_TCPDCORE 128
+#define SCLK_USB3OTG0_REF 129
+#define SCLK_USB3OTG1_REF 130
+#define SCLK_USB3OTG0_SUSPEND 131
+#define SCLK_USB3OTG1_SUSPEND 132
+#define SCLK_CRYPTO0 133
+#define SCLK_CRYPTO1 134
+#define SCLK_CCI_TRACE 135
+#define SCLK_CS 136
+#define SCLK_CIF_OUT 137
+#define SCLK_PCIEPHY_REF 138
+#define SCLK_PCIE_CORE 139
+#define SCLK_M0_PERILP 140
+#define SCLK_M0_PERILP_DEC 141
+#define SCLK_CM0S 142
+#define SCLK_DBG_NOC 143
+#define SCLK_DBG_PD_CORE_B 144
+#define SCLK_DBG_PD_CORE_L 145
+#define SCLK_DFIMON0_TIMER 146
+#define SCLK_DFIMON1_TIMER 147
+#define SCLK_INTMEM0 148
+#define SCLK_INTMEM1 149
+#define SCLK_INTMEM2 150
+#define SCLK_INTMEM3 151
+#define SCLK_INTMEM4 152
+#define SCLK_INTMEM5 153
+#define SCLK_SDMMC_DRV 154
+#define SCLK_SDMMC_SAMPLE 155
+#define SCLK_SDIO_DRV 156
+#define SCLK_SDIO_SAMPLE 157
+#define SCLK_VDU_CORE 158
+#define SCLK_VDU_CA 159
+#define SCLK_PCIE_PM 160
+#define SCLK_SPDIF_REC_DPTX 161
+#define SCLK_DPHY_PLL 162
+#define SCLK_DPHY_TX0_CFG 163
+#define SCLK_DPHY_TX1RX1_CFG 164
+#define SCLK_DPHY_RX0_CFG 165
+#define SCLK_RMII_SRC 166
+#define SCLK_PCIEPHY_REF100M 167
+
+#define DCLK_VOP0 180
+#define DCLK_VOP1 181
+#define DCLK_VOP0_DIV 182
+#define DCLK_VOP1_DIV 183
+#define DCLK_M0_PERILP 184
+
+#define FCLK_CM0S 190
+
+/* aclk gates */
+#define ACLK_PERIHP 192
+#define ACLK_PERIHP_NOC 193
+#define ACLK_PERILP0 194
+#define ACLK_PERILP0_NOC 195
+#define ACLK_PERF_PCIE 196
+#define ACLK_PCIE 197
+#define ACLK_INTMEM 198
+#define ACLK_TZMA 199
+#define ACLK_DCF 200
+#define ACLK_CCI 201
+#define ACLK_CCI_NOC0 202
+#define ACLK_CCI_NOC1 203
+#define ACLK_CCI_GRF 204
+#define ACLK_CENTER 205
+#define ACLK_CENTER_MAIN_NOC 206
+#define ACLK_CENTER_PERI_NOC 207
+#define ACLK_GPU 208
+#define ACLK_PERF_GPU 209
+#define ACLK_GPU_GRF 210
+#define ACLK_DMAC0_PERILP 211
+#define ACLK_DMAC1_PERILP 212
+#define ACLK_GMAC 213
+#define ACLK_GMAC_NOC 214
+#define ACLK_PERF_GMAC 215
+#define ACLK_VOP0_NOC 216
+#define ACLK_VOP0 217
+#define ACLK_VOP1_NOC 218
+#define ACLK_VOP1 219
+#define ACLK_RGA 220
+#define ACLK_RGA_NOC 221
+#define ACLK_HDCP 222
+#define ACLK_HDCP_NOC 223
+#define ACLK_HDCP22 224
+#define ACLK_IEP 225
+#define ACLK_IEP_NOC 226
+#define ACLK_VIO 227
+#define ACLK_VIO_NOC 228
+#define ACLK_ISP0 229
+#define ACLK_ISP1 230
+#define ACLK_ISP0_NOC 231
+#define ACLK_ISP1_NOC 232
+#define ACLK_ISP0_WRAPPER 233
+#define ACLK_ISP1_WRAPPER 234
+#define ACLK_VCODEC 235
+#define ACLK_VCODEC_NOC 236
+#define ACLK_VDU 237
+#define ACLK_VDU_NOC 238
+#define ACLK_PERI 239
+#define ACLK_EMMC 240
+#define ACLK_EMMC_CORE 241
+#define ACLK_EMMC_NOC 242
+#define ACLK_EMMC_GRF 243
+#define ACLK_USB3 244
+#define ACLK_USB3_NOC 245
+#define ACLK_USB3OTG0 246
+#define ACLK_USB3OTG1 247
+#define ACLK_USB3_RKSOC_AXI_PERF 248
+#define ACLK_USB3_GRF 249
+#define ACLK_GIC 250
+#define ACLK_GIC_NOC 251
+#define ACLK_GIC_ADB400_CORE_L_2_GIC 252
+#define ACLK_GIC_ADB400_CORE_B_2_GIC 253
+#define ACLK_GIC_ADB400_GIC_2_CORE_L 254
+#define ACLK_GIC_ADB400_GIC_2_CORE_B 255
+#define ACLK_CORE_ADB400_CORE_L_2_CCI500 256
+#define ACLK_CORE_ADB400_CORE_B_2_CCI500 257
+#define ACLK_ADB400M_PD_CORE_L 258
+#define ACLK_ADB400M_PD_CORE_B 259
+#define ACLK_PERF_CORE_L 260
+#define ACLK_PERF_CORE_B 261
+#define ACLK_GIC_PRE 262
+#define ACLK_VOP0_PRE 263
+#define ACLK_VOP1_PRE 264
+
+/* pclk gates */
+#define PCLK_PERIHP 320
+#define PCLK_PERIHP_NOC 321
+#define PCLK_PERILP0 322
+#define PCLK_PERILP1 323
+#define PCLK_PERILP1_NOC 324
+#define PCLK_PERILP_SGRF 325
+#define PCLK_PERIHP_GRF 326
+#define PCLK_PCIE 327
+#define PCLK_SGRF 328
+#define PCLK_INTR_ARB 329
+#define PCLK_CENTER_MAIN_NOC 330
+#define PCLK_CIC 331
+#define PCLK_COREDBG_B 332
+#define PCLK_COREDBG_L 333
+#define PCLK_DBG_CXCS_PD_CORE_B 334
+#define PCLK_DCF 335
+#define PCLK_GPIO2 336
+#define PCLK_GPIO3 337
+#define PCLK_GPIO4 338
+#define PCLK_GRF 339
+#define PCLK_HSICPHY 340
+#define PCLK_I2C1 341
+#define PCLK_I2C2 342
+#define PCLK_I2C3 343
+#define PCLK_I2C5 344
+#define PCLK_I2C6 345
+#define PCLK_I2C7 346
+#define PCLK_SPI0 347
+#define PCLK_SPI1 348
+#define PCLK_SPI2 349
+#define PCLK_SPI4 350
+#define PCLK_SPI5 351
+#define PCLK_UART0 352
+#define PCLK_UART1 353
+#define PCLK_UART2 354
+#define PCLK_UART3 355
+#define PCLK_TSADC 356
+#define PCLK_SARADC 357
+#define PCLK_GMAC 358
+#define PCLK_GMAC_NOC 359
+#define PCLK_TIMER0 360
+#define PCLK_TIMER1 361
+#define PCLK_EDP 362
+#define PCLK_EDP_NOC 363
+#define PCLK_EDP_CTRL 364
+#define PCLK_VIO 365
+#define PCLK_VIO_NOC 366
+#define PCLK_VIO_GRF 367
+#define PCLK_MIPI_DSI0 368
+#define PCLK_MIPI_DSI1 369
+#define PCLK_HDCP 370
+#define PCLK_HDCP_NOC 371
+#define PCLK_HDMI_CTRL 372
+#define PCLK_DP_CTRL 373
+#define PCLK_HDCP22 374
+#define PCLK_GASKET 375
+#define PCLK_DDR 376
+#define PCLK_DDR_MON 377
+#define PCLK_DDR_SGRF 378
+#define PCLK_ISP1_WRAPPER 379
+#define PCLK_WDT 380
+#define PCLK_EFUSE1024NS 381
+#define PCLK_EFUSE1024S 382
+#define PCLK_PMU_INTR_ARB 383
+#define PCLK_MAILBOX0 384
+#define PCLK_USBPHY_MUX_G 385
+#define PCLK_UPHY0_TCPHY_G 386
+#define PCLK_UPHY0_TCPD_G 387
+#define PCLK_UPHY1_TCPHY_G 388
+#define PCLK_UPHY1_TCPD_G 389
+#define PCLK_ALIVE 390
+
+/* hclk gates */
+#define HCLK_PERIHP 448
+#define HCLK_PERILP0 449
+#define HCLK_PERILP1 450
+#define HCLK_PERILP0_NOC 451
+#define HCLK_PERILP1_NOC 452
+#define HCLK_M0_PERILP 453
+#define HCLK_M0_PERILP_NOC 454
+#define HCLK_AHB1TOM 455
+#define HCLK_HOST0 456
+#define HCLK_HOST0_ARB 457
+#define HCLK_HOST1 458
+#define HCLK_HOST1_ARB 459
+#define HCLK_HSIC 460
+#define HCLK_SD 461
+#define HCLK_SDMMC 462
+#define HCLK_SDMMC_NOC 463
+#define HCLK_M_CRYPTO0 464
+#define HCLK_M_CRYPTO1 465
+#define HCLK_S_CRYPTO0 466
+#define HCLK_S_CRYPTO1 467
+#define HCLK_I2S0_8CH 468
+#define HCLK_I2S1_8CH 469
+#define HCLK_I2S2_8CH 470
+#define HCLK_SPDIF 471
+#define HCLK_VOP0_NOC 472
+#define HCLK_VOP0 473
+#define HCLK_VOP1_NOC 474
+#define HCLK_VOP1 475
+#define HCLK_ROM 476
+#define HCLK_IEP 477
+#define HCLK_IEP_NOC 478
+#define HCLK_ISP0 479
+#define HCLK_ISP1 480
+#define HCLK_ISP0_NOC 481
+#define HCLK_ISP1_NOC 482
+#define HCLK_ISP0_WRAPPER 483
+#define HCLK_ISP1_WRAPPER 484
+#define HCLK_RGA 485
+#define HCLK_RGA_NOC 486
+#define HCLK_HDCP 487
+#define HCLK_HDCP_NOC 488
+#define HCLK_HDCP22 489
+#define HCLK_VCODEC 490
+#define HCLK_VCODEC_NOC 491
+#define HCLK_VDU 492
+#define HCLK_VDU_NOC 493
+#define HCLK_SDIO 494
+#define HCLK_SDIO_NOC 495
+#define HCLK_SDIOAUDIO_NOC 496
+
+#define CLK_NR_CLKS (HCLK_SDIOAUDIO_NOC + 1)
+
+/* pmu-clocks indices */
+
+#define PLL_PPLL 1
+
+#define SCLK_32K_SUSPEND_PMU 2
+#define SCLK_SPI3_PMU 3
+#define SCLK_TIMER12_PMU 4
+#define SCLK_TIMER13_PMU 5
+#define SCLK_UART4_PMU 6
+#define SCLK_PVTM_PMU 7
+#define SCLK_WIFI_PMU 8
+#define SCLK_I2C0_PMU 9
+#define SCLK_I2C4_PMU 10
+#define SCLK_I2C8_PMU 11
+
+#define PCLK_SRC_PMU 19
+#define PCLK_PMU 20
+#define PCLK_PMUGRF_PMU 21
+#define PCLK_INTMEM1_PMU 22
+#define PCLK_GPIO0_PMU 23
+#define PCLK_GPIO1_PMU 24
+#define PCLK_SGRF_PMU 25
+#define PCLK_NOC_PMU 26
+#define PCLK_I2C0_PMU 27
+#define PCLK_I2C4_PMU 28
+#define PCLK_I2C8_PMU 29
+#define PCLK_RKPWM_PMU 30
+#define PCLK_SPI3_PMU 31
+#define PCLK_TIMER_PMU 32
+#define PCLK_MAILBOX_PMU 33
+#define PCLK_UART4_PMU 34
+#define PCLK_WDT_M0_PMU 35
+
+#define FCLK_CM0S_SRC_PMU 44
+#define FCLK_CM0S_PMU 45
+#define SCLK_CM0S_PMU 46
+#define HCLK_CM0S_PMU 47
+#define DCLK_CM0S_PMU 48
+#define PCLK_INTR_ARB_PMU 49
+#define HCLK_NOC_PMU 50
+
+#define CLKPMU_NR_CLKS (HCLK_NOC_PMU + 1)
+
+/* soft-reset indices */
+
+/* cru_softrst_con0 */
+#define SRST_CORE_L0 0
+#define SRST_CORE_B0 1
+#define SRST_CORE_PO_L0 2
+#define SRST_CORE_PO_B0 3
+#define SRST_L2_L 4
+#define SRST_L2_B 5
+#define SRST_ADB_L 6
+#define SRST_ADB_B 7
+#define SRST_A_CCI 8
+#define SRST_A_CCIM0_NOC 9
+#define SRST_A_CCIM1_NOC 10
+#define SRST_DBG_NOC 11
+
+/* cru_softrst_con1 */
+#define SRST_CORE_L0_T 16
+#define SRST_CORE_L1 17
+#define SRST_CORE_L2 18
+#define SRST_CORE_L3 19
+#define SRST_CORE_PO_L0_T 20
+#define SRST_CORE_PO_L1 21
+#define SRST_CORE_PO_L2 22
+#define SRST_CORE_PO_L3 23
+#define SRST_A_ADB400_GIC2COREL 24
+#define SRST_A_ADB400_COREL2GIC 25
+#define SRST_P_DBG_L 26
+#define SRST_L2_L_T 28
+#define SRST_ADB_L_T 29
+#define SRST_A_RKPERF_L 30
+#define SRST_PVTM_CORE_L 31
+
+/* cru_softrst_con2 */
+#define SRST_CORE_B0_T 32
+#define SRST_CORE_B1 33
+#define SRST_CORE_PO_B0_T 36
+#define SRST_CORE_PO_B1 37
+#define SRST_A_ADB400_GIC2COREB 40
+#define SRST_A_ADB400_COREB2GIC 41
+#define SRST_P_DBG_B 42
+#define SRST_L2_B_T 43
+#define SRST_ADB_B_T 45
+#define SRST_A_RKPERF_B 46
+#define SRST_PVTM_CORE_B 47
+
+/* cru_softrst_con3 */
+#define SRST_A_CCI_T 50
+#define SRST_A_CCIM0_NOC_T 51
+#define SRST_A_CCIM1_NOC_T 52
+#define SRST_A_ADB400M_PD_CORE_B_T 53
+#define SRST_A_ADB400M_PD_CORE_L_T 54
+#define SRST_DBG_NOC_T 55
+#define SRST_DBG_CXCS 56
+#define SRST_CCI_TRACE 57
+#define SRST_P_CCI_GRF 58
+
+/* cru_softrst_con4 */
+#define SRST_A_CENTER_MAIN_NOC 64
+#define SRST_A_CENTER_PERI_NOC 65
+#define SRST_P_CENTER_MAIN 66
+#define SRST_P_DDRMON 67
+#define SRST_P_CIC 68
+#define SRST_P_CENTER_SGRF 69
+#define SRST_DDR0_MSCH 70
+#define SRST_DDRCFG0_MSCH 71
+#define SRST_DDR0 72
+#define SRST_DDRPHY0 73
+#define SRST_DDR1_MSCH 74
+#define SRST_DDRCFG1_MSCH 75
+#define SRST_DDR1 76
+#define SRST_DDRPHY1 77
+#define SRST_DDR_CIC 78
+#define SRST_PVTM_DDR 79
+
+/* cru_softrst_con5 */
+#define SRST_A_VCODEC_NOC 80
+#define SRST_A_VCODEC 81
+#define SRST_H_VCODEC_NOC 82
+#define SRST_H_VCODEC 83
+#define SRST_A_VDU_NOC 88
+#define SRST_A_VDU 89
+#define SRST_H_VDU_NOC 90
+#define SRST_H_VDU 91
+#define SRST_VDU_CORE 92
+#define SRST_VDU_CA 93
+
+/* cru_softrst_con6 */
+#define SRST_A_IEP_NOC 96
+#define SRST_A_VOP_IEP 97
+#define SRST_A_IEP 98
+#define SRST_H_IEP_NOC 99
+#define SRST_H_IEP 100
+#define SRST_A_RGA_NOC 102
+#define SRST_A_RGA 103
+#define SRST_H_RGA_NOC 104
+#define SRST_H_RGA 105
+#define SRST_RGA_CORE 106
+#define SRST_EMMC_NOC 108
+#define SRST_EMMC 109
+#define SRST_EMMC_GRF 110
+
+/* cru_softrst_con7 */
+#define SRST_A_PERIHP_NOC 112
+#define SRST_P_PERIHP_GRF 113
+#define SRST_H_PERIHP_NOC 114
+#define SRST_USBHOST0 115
+#define SRST_HOSTC0_AUX 116
+#define SRST_HOST0_ARB 117
+#define SRST_USBHOST1 118
+#define SRST_HOSTC1_AUX 119
+#define SRST_HOST1_ARB 120
+#define SRST_SDIO0 121
+#define SRST_SDMMC 122
+#define SRST_HSIC 123
+#define SRST_HSIC_AUX 124
+#define SRST_AHB1TOM 125
+#define SRST_P_PERIHP_NOC 126
+#define SRST_HSICPHY 127
+
+/* cru_softrst_con8 */
+#define SRST_A_PCIE 128
+#define SRST_P_PCIE 129
+#define SRST_PCIE_CORE 130
+#define SRST_PCIE_MGMT 131
+#define SRST_PCIE_MGMT_STICKY 132
+#define SRST_PCIE_PIPE 133
+#define SRST_PCIE_PM 134
+#define SRST_PCIEPHY 135
+#define SRST_A_GMAC_NOC 136
+#define SRST_A_GMAC 137
+#define SRST_P_GMAC_NOC 138
+#define SRST_P_GMAC_GRF 140
+#define SRST_HSICPHY_POR 142
+#define SRST_HSICPHY_UTMI 143
+
+/* cru_softrst_con9 */
+#define SRST_USB2PHY0_POR 144
+#define SRST_USB2PHY0_UTMI_PORT0 145
+#define SRST_USB2PHY0_UTMI_PORT1 146
+#define SRST_USB2PHY0_EHCIPHY 147
+#define SRST_UPHY0_PIPE_L00 148
+#define SRST_UPHY0 149
+#define SRST_UPHY0_TCPDPWRUP 150
+#define SRST_USB2PHY1_POR 152
+#define SRST_USB2PHY1_UTMI_PORT0 153
+#define SRST_USB2PHY1_UTMI_PORT1 154
+#define SRST_USB2PHY1_EHCIPHY 155
+#define SRST_UPHY1_PIPE_L00 156
+#define SRST_UPHY1 157
+#define SRST_UPHY1_TCPDPWRUP 158
+
+/* cru_softrst_con10 */
+#define SRST_A_PERILP0_NOC 160
+#define SRST_A_DCF 161
+#define SRST_GIC500 162
+#define SRST_DMAC0_PERILP0 163
+#define SRST_DMAC1_PERILP0 164
+#define SRST_TZMA 165
+#define SRST_INTMEM 166
+#define SRST_ADB400_MST0 167
+#define SRST_ADB400_MST1 168
+#define SRST_ADB400_SLV0 169
+#define SRST_ADB400_SLV1 170
+#define SRST_H_PERILP0 171
+#define SRST_H_PERILP0_NOC 172
+#define SRST_ROM 173
+#define SRST_CRYPTO_S 174
+#define SRST_CRYPTO_M 175
+
+/* cru_softrst_con11 */
+#define SRST_P_DCF 176
+#define SRST_CM0S_NOC 177
+#define SRST_CM0S 178
+#define SRST_CM0S_DBG 179
+#define SRST_CM0S_PO 180
+#define SRST_CRYPTO 181
+#define SRST_P_PERILP1_SGRF 182
+#define SRST_P_PERILP1_GRF 183
+#define SRST_CRYPTO1_S 184
+#define SRST_CRYPTO1_M 185
+#define SRST_CRYPTO1 186
+#define SRST_GIC_NOC 188
+#define SRST_SD_NOC 189
+#define SRST_SDIOAUDIO_BRG 190
+
+/* cru_softrst_con12 */
+#define SRST_H_PERILP1 192
+#define SRST_H_PERILP1_NOC 193
+#define SRST_H_I2S0_8CH 194
+#define SRST_H_I2S1_8CH 195
+#define SRST_H_I2S2_8CH 196
+#define SRST_H_SPDIF_8CH 197
+#define SRST_P_PERILP1_NOC 198
+#define SRST_P_EFUSE_1024 199
+#define SRST_P_EFUSE_1024S 200
+#define SRST_P_I2C0 201
+#define SRST_P_I2C1 202
+#define SRST_P_I2C2 203
+#define SRST_P_I2C3 204
+#define SRST_P_I2C4 205
+#define SRST_P_I2C5 206
+#define SRST_P_MAILBOX0 207
+
+/* cru_softrst_con13 */
+#define SRST_P_UART0 208
+#define SRST_P_UART1 209
+#define SRST_P_UART2 210
+#define SRST_P_UART3 211
+#define SRST_P_SARADC 212
+#define SRST_P_TSADC 213
+#define SRST_P_SPI0 214
+#define SRST_P_SPI1 215
+#define SRST_P_SPI2 216
+#define SRST_P_SPI3 217
+#define SRST_P_SPI4 218
+#define SRST_SPI0 219
+#define SRST_SPI1 220
+#define SRST_SPI2 221
+#define SRST_SPI3 222
+#define SRST_SPI4 223
+
+/* cru_softrst_con14 */
+#define SRST_I2S0_8CH 224
+#define SRST_I2S1_8CH 225
+#define SRST_I2S2_8CH 226
+#define SRST_SPDIF_8CH 227
+#define SRST_UART0 228
+#define SRST_UART1 229
+#define SRST_UART2 230
+#define SRST_UART3 231
+#define SRST_TSADC 232
+#define SRST_I2C0 233
+#define SRST_I2C1 234
+#define SRST_I2C2 235
+#define SRST_I2C3 236
+#define SRST_I2C4 237
+#define SRST_I2C5 238
+#define SRST_SDIOAUDIO_NOC 239
+
+/* cru_softrst_con15 */
+#define SRST_A_VIO_NOC 240
+#define SRST_A_HDCP_NOC 241
+#define SRST_A_HDCP 242
+#define SRST_H_HDCP_NOC 243
+#define SRST_H_HDCP 244
+#define SRST_P_HDCP_NOC 245
+#define SRST_P_HDCP 246
+#define SRST_P_HDMI_CTRL 247
+#define SRST_P_DP_CTRL 248
+#define SRST_S_DP_CTRL 249
+#define SRST_C_DP_CTRL 250
+#define SRST_P_MIPI_DSI0 251
+#define SRST_P_MIPI_DSI1 252
+#define SRST_DP_CORE 253
+#define SRST_DP_I2S 254
+
+/* cru_softrst_con16 */
+#define SRST_GASKET 256
+#define SRST_VIO_GRF 258
+#define SRST_DPTX_SPDIF_REC 259
+#define SRST_HDMI_CTRL 260
+#define SRST_HDCP_CTRL 261
+#define SRST_A_ISP0_NOC 262
+#define SRST_A_ISP1_NOC 263
+#define SRST_H_ISP0_NOC 266
+#define SRST_H_ISP1_NOC 267
+#define SRST_H_ISP0 268
+#define SRST_H_ISP1 269
+#define SRST_ISP0 270
+#define SRST_ISP1 271
+
+/* cru_softrst_con17 */
+#define SRST_A_VOP0_NOC 272
+#define SRST_A_VOP1_NOC 273
+#define SRST_A_VOP0 274
+#define SRST_A_VOP1 275
+#define SRST_H_VOP0_NOC 276
+#define SRST_H_VOP1_NOC 277
+#define SRST_H_VOP0 278
+#define SRST_H_VOP1 279
+#define SRST_D_VOP0 280
+#define SRST_D_VOP1 281
+#define SRST_VOP0_PWM 282
+#define SRST_VOP1_PWM 283
+#define SRST_P_EDP_NOC 284
+#define SRST_P_EDP_CTRL 285
+
+/* cru_softrst_con18 */
+#define SRST_A_GPU 288
+#define SRST_A_GPU_NOC 289
+#define SRST_A_GPU_GRF 290
+#define SRST_PVTM_GPU 291
+#define SRST_A_USB3_NOC 292
+#define SRST_A_USB3_OTG0 293
+#define SRST_A_USB3_OTG1 294
+#define SRST_A_USB3_GRF 295
+#define SRST_PMU 296
+
+/* cru_softrst_con19 */
+#define SRST_P_TIMER0_5 304
+#define SRST_TIMER0 305
+#define SRST_TIMER1 306
+#define SRST_TIMER2 307
+#define SRST_TIMER3 308
+#define SRST_TIMER4 309
+#define SRST_TIMER5 310
+#define SRST_P_TIMER6_11 311
+#define SRST_TIMER6 312
+#define SRST_TIMER7 313
+#define SRST_TIMER8 314
+#define SRST_TIMER9 315
+#define SRST_TIMER10 316
+#define SRST_TIMER11 317
+#define SRST_P_INTR_ARB_PMU 318
+#define SRST_P_ALIVE_SGRF 319
+
+/* cru_softrst_con20 */
+#define SRST_P_GPIO2 320
+#define SRST_P_GPIO3 321
+#define SRST_P_GPIO4 322
+#define SRST_P_GRF 323
+#define SRST_P_ALIVE_NOC 324
+#define SRST_P_WDT0 325
+#define SRST_P_WDT1 326
+#define SRST_P_INTR_ARB 327
+#define SRST_P_UPHY0_DPTX 328
+#define SRST_P_UPHY0_APB 330
+#define SRST_P_UPHY0_TCPHY 332
+#define SRST_P_UPHY1_TCPHY 333
+#define SRST_P_UPHY0_TCPDCTRL 334
+#define SRST_P_UPHY1_TCPDCTRL 335
+
+/* pmu soft-reset indices */
+
+/* pmu_cru_softrst_con0 */
+#define SRST_P_NOC 0
+#define SRST_P_INTMEM 1
+#define SRST_H_CM0S 2
+#define SRST_H_CM0S_NOC 3
+#define SRST_DBG_CM0S 4
+#define SRST_PO_CM0S 5
+#define SRST_P_SPI6 6
+#define SRST_SPI6 7
+#define SRST_P_TIMER_0_1 8
+#define SRST_P_TIMER_0 9
+#define SRST_P_TIMER_1 10
+#define SRST_P_UART4 11
+#define SRST_UART4 12
+#define SRST_P_WDT 13
+
+/* pmu_cru_softrst_con1 */
+#define SRST_P_I2C6 16
+#define SRST_P_I2C7 17
+#define SRST_P_I2C8 18
+#define SRST_P_MAILBOX 19
+#define SRST_P_RKPWM 20
+#define SRST_P_PMUGRF 21
+#define SRST_P_SGRF 22
+#define SRST_P_GPIO0 23
+#define SRST_P_GPIO1 24
+#define SRST_P_CRU 25
+#define SRST_P_INTR 26
+#define SRST_PVTM 27
+#define SRST_I2C6 28
+#define SRST_I2C7 29
+#define SRST_I2C8 30
+
+#endif
diff --git a/include/fdtdec.h b/include/fdtdec.h
index 151c590..70ea0bf 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -155,6 +155,7 @@ enum fdt_compat_id {
COMPAT_INTEL_BAYTRAIL_FSP, /* Intel Bay Trail FSP */
COMPAT_INTEL_BAYTRAIL_FSP_MDP, /* Intel FSP memory-down params */
COMPAT_INTEL_IVYBRIDGE_FSP, /* Intel Ivy Bridge FSP */
+ COMPAT_SUNXI_NAND, /* SUNXI NAND controller */
COMPAT_COUNT,
};
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index cf20674..779eea0 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -500,5 +500,10 @@ int mtd_arg_off(const char *arg, int *idx, loff_t *off, loff_t *size,
int mtd_arg_off_size(int argc, char *const argv[], int *idx, loff_t *off,
loff_t *size, loff_t *maxsize, int devtype,
uint64_t chipsize);
+
+/* drivers/mtd/mtdcore.c */
+void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset,
+ const uint64_t length, uint64_t *len_incl_bad,
+ int *truncated);
#endif
#endif /* __MTD_MTD_H__ */
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index b5a02c3..87d72db 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -48,7 +48,7 @@ extern void nand_wait_ready(struct mtd_info *mtd);
* is supported now. If you add a chip with bigger oobsize/page
* adjust this accordingly.
*/
-#define NAND_MAX_OOBSIZE 1216
+#define NAND_MAX_OOBSIZE 1664
#define NAND_MAX_PAGESIZE 16384
/*
@@ -590,6 +590,7 @@ struct nand_buffers {
* flash device
* @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the
* flash device.
+ * @flash_node: [BOARDSPECIFIC] device node describing this instance
* @read_byte: [REPLACEABLE] read one byte from the chip
* @read_word: [REPLACEABLE] read one word from the chip
* @write_byte: [REPLACEABLE] write a single byte to the chip on the
@@ -689,6 +690,8 @@ struct nand_chip {
void __iomem *IO_ADDR_R;
void __iomem *IO_ADDR_W;
+ int flash_node;
+
uint8_t (*read_byte)(struct mtd_info *mtd);
u16 (*read_word)(struct mtd_info *mtd);
void (*write_byte)(struct mtd_info *mtd, uint8_t byte);
diff --git a/include/nand.h b/include/nand.h
index 627b217..b6eb223 100644
--- a/include/nand.h
+++ b/include/nand.h
@@ -142,3 +142,6 @@ __attribute__((noreturn)) void nand_boot(void);
int get_nand_env_oob(struct mtd_info *mtd, unsigned long *result);
#endif
int spl_nand_erase_one(int block, int page);
+
+/* platform specific init functions */
+void sunxi_nand_init(void);
diff --git a/include/usb/dwc2_udc.h b/include/usb/dwc2_udc.h
index 302e9a3..7324d8a 100644
--- a/include/usb/dwc2_udc.h
+++ b/include/usb/dwc2_udc.h
@@ -12,12 +12,17 @@
#define PHY0_SLEEP (1 << 5)
struct dwc2_plat_otg_data {
+ void *priv;
+ int phy_of_node;
int (*phy_control)(int on);
unsigned int regs_phy;
unsigned int regs_otg;
unsigned int usb_phy_ctrl;
unsigned int usb_flags;
unsigned int usb_gusbcfg;
+ unsigned int rx_fifo_sz;
+ unsigned int np_tx_fifo_sz;
+ unsigned int tx_fifo_sz;
};
int dwc2_udc_probe(struct dwc2_plat_otg_data *pdata);
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index c2bcbde..462a24f 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -65,6 +65,7 @@ static const char * const compat_names[COMPAT_COUNT] = {
COMPAT(INTEL_BAYTRAIL_FSP, "intel,baytrail-fsp"),
COMPAT(INTEL_BAYTRAIL_FSP_MDP, "intel,baytrail-fsp-mdp"),
COMPAT(INTEL_IVYBRIDGE_FSP, "intel,ivybridge-fsp"),
+ COMPAT(COMPAT_SUNXI_NAND, "allwinner,sun4i-a10-nand"),
};
const char *fdtdec_get_compatible(enum fdt_compat_id id)
diff --git a/lib/hashtable.c b/lib/hashtable.c
index 435e2a6..4e52b36 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -602,8 +602,8 @@ ssize_t hexport_r(struct hsearch_data *htab, const char sep, int flag,
return (-1);
}
- debug("EXPORT table = %p, htab.size = %d, htab.filled = %d, "
- "size = %zu\n", htab, htab->size, htab->filled, size);
+ debug("EXPORT table = %p, htab.size = %d, htab.filled = %d, size = %lu\n",
+ htab, htab->size, htab->filled, (ulong)size);
/*
* Pass 1:
* search used entries,
@@ -657,8 +657,8 @@ ssize_t hexport_r(struct hsearch_data *htab, const char sep, int flag,
/* Check if the user supplied buffer size is sufficient */
if (size) {
if (size < totlen + 1) { /* provided buffer too small */
- printf("Env export buffer too small: %zu, "
- "but need %zu\n", size, totlen + 1);
+ printf("Env export buffer too small: %lu, but need %lu\n",
+ (ulong)size, (ulong)totlen + 1);
__set_errno(ENOMEM);
return (-1);
}
@@ -790,7 +790,7 @@ int himport_r(struct hsearch_data *htab,
/* we allocate new space to make sure we can write to the array */
if ((data = malloc(size + 1)) == NULL) {
- debug("himport_r: can't malloc %zu bytes\n", size + 1);
+ debug("himport_r: can't malloc %lu bytes\n", (ulong)size + 1);
__set_errno(ENOMEM);
return 0;
}
diff --git a/lib/rsa/rsa-sign.c b/lib/rsa/rsa-sign.c
index d4a1a5e..c26f741 100644
--- a/lib/rsa/rsa-sign.c
+++ b/lib/rsa/rsa-sign.c
@@ -420,8 +420,10 @@ static int fdt_add_bignum(void *blob, int noffset, const char *prop_name,
BN_rshift(num, num, 32); /* N = N/B */
}
- /* We try signing with successively increasing size values, so this
- * might fail several times */
+ /*
+ * We try signing with successively increasing size values, so this
+ * might fail several times
+ */
ret = fdt_setprop(blob, noffset, prop_name, buf, size);
if (ret)
return -FDT_ERR_NOSPACE;
diff --git a/tools/dtoc/fdt_fallback.py b/tools/dtoc/fdt_fallback.py
index 14decf3..9ed11e4 100644
--- a/tools/dtoc/fdt_fallback.py
+++ b/tools/dtoc/fdt_fallback.py
@@ -71,6 +71,12 @@ class Prop:
if type(newprop.value) == list and type(self.value) != list:
self.value = newprop.value
+ if type(self.value) == list and len(newprop.value) > len(self.value):
+ val = fdt_util.GetEmpty(self.type)
+ while len(self.value) < len(newprop.value):
+ self.value.append(val)
+
+
class Node:
"""A device tree node
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index 34ceebd..6b0dcaa 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -661,8 +661,8 @@ static int flash_bad_block (int fd, uint8_t mtd_type, loff_t *blockstart)
if (badblock) {
#ifdef DEBUG
- fprintf (stderr, "Bad block at 0x%llx, "
- "skipping\n", *blockstart);
+ fprintf (stderr, "Bad block at 0x%llx, skipping\n",
+ (unsigned long long) *blockstart);
#endif
return badblock;
}
@@ -749,7 +749,8 @@ static int flash_read_buf (int dev, int fd, void *buf, size_t count,
}
#ifdef DEBUG
fprintf(stderr, "Read 0x%x bytes at 0x%llx on %s\n",
- rc, blockstart + block_seek, DEVNAME(dev));
+ rc, (unsigned long long) blockstart + block_seek,
+ DEVNAME(dev));
#endif
processed += readlen;
readlen = min (blocklen, count - processed);
@@ -847,8 +848,9 @@ static int flash_write_buf (int dev, int fd, void *buf, size_t count,
if (block_seek + count != write_total) {
if (block_seek != 0)
fprintf(stderr, " and ");
- fprintf(stderr, "0x%lx - 0x%x",
- block_seek + count, write_total - 1);
+ fprintf(stderr, "0x%lx - 0x%lx",
+ (unsigned long) block_seek + count,
+ (unsigned long) write_total - 1);
}
fprintf(stderr, "\n");
#endif
@@ -911,8 +913,9 @@ static int flash_write_buf (int dev, int fd, void *buf, size_t count,
}
#ifdef DEBUG
- fprintf(stderr, "Write 0x%x bytes at 0x%llx\n", erasesize,
- blockstart);
+ fprintf(stderr, "Write 0x%llx bytes at 0x%llx\n",
+ (unsigned long long) erasesize,
+ (unsigned long long) blockstart);
#endif
if (write (fd, data + processed, erasesize) != erasesize) {
fprintf (stderr, "Write error on %s: %s\n",
diff --git a/tools/image-host.c b/tools/image-host.c
index 399ec94..1104695 100644
--- a/tools/image-host.c
+++ b/tools/image-host.c
@@ -238,11 +238,16 @@ static int fit_image_process_sig(const char *keydir, void *keydest,
/* Get keyname again, as FDT has changed and invalidated our pointer */
info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
- ret = info.algo->add_verify_data(&info, keydest);
+ if (keydest)
+ ret = info.algo->add_verify_data(&info, keydest);
+ else
+ return -1;
- /* Write the public key into the supplied FDT file; this might fail
+ /*
+ * Write the public key into the supplied FDT file; this might fail
* several times, since we try signing with successively increasing
- * size values */
+ * size values
+ */
if (keydest && ret)
return ret;
diff --git a/tools/rkcommon.c b/tools/rkcommon.c
index 72621fd..0a072aa 100644
--- a/tools/rkcommon.c
+++ b/tools/rkcommon.c
@@ -56,6 +56,7 @@ struct spl_info {
static struct spl_info spl_infos[] = {
{ "rk3036", "RK30", 0x1000 },
{ "rk3288", "RK32", 0x8000 },
+ { "rk3399", "RK33", 0x20000 },
};
static unsigned char rc4_key[16] = {