All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 0/4] Add basic support for rk3066 platform.
@ 2021-07-13 18:58 Paweł Jarosz
  2021-07-13 18:58 ` [PATCH v6 1/4] rockchip: rk3066: add grf header file Paweł Jarosz
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Paweł Jarosz @ 2021-07-13 18:58 UTC (permalink / raw)
  To: kever.yang; +Cc: sjg, philipp.tomsich, lukma, u-boot

This patch serie adds basic support for Rockchip RK3066 processor.
For now it's clock, pinctrl and sdram driver.

Paweł Jarosz (4):
  rockchip: rk3066: add grf header file
  rockchip: rk3066: add clock driver for rk3066 soc
  rockchip: rk3066: add rk3066 pinctrl driver
  rockchip: rk3066: add sdram driver

 .../include/asm/arch-rockchip/cru_rk3066.h    | 203 ++++
 .../include/asm/arch-rockchip/grf_rk3066.h    | 211 ++++
 drivers/clk/rockchip/Makefile                 |   1 +
 drivers/clk/rockchip/clk_rk3066.c             | 704 +++++++++++++
 drivers/pinctrl/rockchip/Makefile             |   1 +
 drivers/pinctrl/rockchip/pinctrl-rk3066.c     | 113 +++
 drivers/ram/rockchip/Makefile                 |   1 +
 drivers/ram/rockchip/sdram_rk3066.c           | 942 ++++++++++++++++++
 8 files changed, 2176 insertions(+)
 create mode 100644 arch/arm/include/asm/arch-rockchip/cru_rk3066.h
 create mode 100644 arch/arm/include/asm/arch-rockchip/grf_rk3066.h
 create mode 100644 drivers/clk/rockchip/clk_rk3066.c
 create mode 100644 drivers/pinctrl/rockchip/pinctrl-rk3066.c
 create mode 100644 drivers/ram/rockchip/sdram_rk3066.c

--
2.32.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v6 1/4] rockchip: rk3066: add grf header file
  2021-07-13 18:58 [PATCH v6 0/4] Add basic support for rk3066 platform Paweł Jarosz
@ 2021-07-13 18:58 ` Paweł Jarosz
  2021-07-13 18:58 ` [PATCH v6 2/4] rockchip: rk3066: add clock driver for rk3066 soc Paweł Jarosz
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 8+ messages in thread
From: Paweł Jarosz @ 2021-07-13 18:58 UTC (permalink / raw)
  To: kever.yang; +Cc: sjg, philipp.tomsich, lukma, u-boot

grf is needed by various drivers for rk3066 soc.

Signed-off-by: Paweł Jarosz <paweljarosz3691@gmail.com>
Acked-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
---

Changes since v1:
- updated to shifted masks

Changes since v2:
- none

Changes since v3:
- none

Changes since v4:
- removed gpio iomux related constants

Changes since v5:
- removed unintentional tab
- updated maintainer email
- style related changes

 .../include/asm/arch-rockchip/grf_rk3066.h    | 211 ++++++++++++++++++
 1 file changed, 211 insertions(+)
 create mode 100644 arch/arm/include/asm/arch-rockchip/grf_rk3066.h

diff --git a/arch/arm/include/asm/arch-rockchip/grf_rk3066.h b/arch/arm/include/asm/arch-rockchip/grf_rk3066.h
new file mode 100644
index 0000000000..71fdcd0372
--- /dev/null
+++ b/arch/arm/include/asm/arch-rockchip/grf_rk3066.h
@@ -0,0 +1,211 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2021 Paweł Jarosz <paweljarosz3691@gmail.com>
+ */
+
+#ifndef _ASM_ARCH_GRF_RK3066_H
+#define _ASM_ARCH_GRF_RK3066_H
+
+struct rk3066_grf_gpio_lh {
+	u32 l;
+	u32 h;
+};
+
+struct rk3066_grf {
+	struct rk3066_grf_gpio_lh gpio_dir[7];
+	struct rk3066_grf_gpio_lh gpio_do[7];
+	struct rk3066_grf_gpio_lh gpio_en[7];
+
+	u32 gpio0a_iomux;
+	u32 gpio0b_iomux;
+	u32 gpio0c_iomux;
+	u32 gpio0d_iomux;
+
+	u32 gpio1a_iomux;
+	u32 gpio1b_iomux;
+	u32 gpio1c_iomux;
+	u32 gpio1d_iomux;
+
+	u32 gpio2a_iomux;
+	u32 gpio2b_iomux;
+	u32 gpio2c_iomux;
+	u32 gpio2d_iomux;
+
+	u32 gpio3a_iomux;
+	u32 gpio3b_iomux;
+	u32 gpio3c_iomux;
+	u32 gpio3d_iomux;
+
+	u32 gpio4a_iomux;
+	u32 gpio4b_iomux;
+	u32 gpio4c_iomux;
+	u32 gpio4d_iomux;
+
+	u32 reserved0[5];
+
+	u32 gpio6b_iomux;
+
+	u32 reserved1[2];
+
+	struct rk3066_grf_gpio_lh gpio_pull[7];
+
+	u32 soc_con0;
+	u32 soc_con1;
+	u32 soc_con2;
+
+	u32 soc_status0;
+
+	u32 dmac1_con[3];
+	u32 dmac2_con[4];
+
+	u32 uoc0_con[3];
+	u32 uoc1_con[4];
+	u32 ddrc_con;
+	u32 ddrc_stat;
+
+	u32 reserved2[10];
+
+	u32 os_reg[4];
+};
+
+check_member(rk3066_grf, os_reg[3], 0x01d4);
+
+/* GRF_GPIO1B_IOMUX */
+enum {
+	GPIO1B1_SHIFT		= 2,
+	GPIO1B1_MASK		= 1 << GPIO1B1_SHIFT,
+	GPIO1B1_GPIO		= 0,
+	GPIO1B1_UART2_SOUT,
+
+	GPIO1B0_SHIFT		= 0,
+	GPIO1B0_MASK		= 1 << GPIO1B0_SHIFT,
+	GPIO1B0_GPIO		= 0,
+	GPIO1B0_UART2_SIN
+};
+
+/* GRF_SOC_CON0 */
+enum {
+	SMC_MUX_CON_SHIFT	= 13,
+	SMC_MUX_CON_MASK	= 1 << SMC_MUX_CON_SHIFT,
+
+	NOC_REMAP_SHIFT		= 12,
+	NOC_REMAP_MASK		= 1 << NOC_REMAP_SHIFT,
+
+	EMMC_FLASH_SEL_SHIFT	= 11,
+	EMMC_FLASH_SEL_MASK	= 1 << EMMC_FLASH_SEL_SHIFT,
+
+	TZPC_REVISION_SHIFT	= 7,
+	TZPC_REVISION_MASK	= 0xf << TZPC_REVISION_SHIFT,
+
+	L2CACHE_ACC_SHIFT	= 5,
+	L2CACHE_ACC_MASK	= 3 << L2CACHE_ACC_SHIFT,
+
+	L2RD_WAIT_SHIFT		= 3,
+	L2RD_WAIT_MASK		= 3 << L2RD_WAIT_SHIFT,
+
+	IMEMRD_WAIT_SHIFT	= 1,
+	IMEMRD_WAIT_MASK	= 3 << IMEMRD_WAIT_SHIFT,
+
+	SOC_REMAP_SHIFT		= 0,
+	SOC_REMAP_MASK		= 1 << SOC_REMAP_SHIFT,
+};
+
+/* GRF_SOC_CON1 */
+enum {
+	RKI2C4_SEL_SHIFT	= 15,
+	RKI2C4_SEL_MASK		= 1 << RKI2C4_SEL_SHIFT,
+
+	RKI2C3_SEL_SHIFT	= 14,
+	RKI2C3_SEL_MASK		= 1 << RKI2C3_SEL_SHIFT,
+
+	RKI2C2_SEL_SHIFT	= 13,
+	RKI2C2_SEL_MASK		= 1 << RKI2C2_SEL_SHIFT,
+
+	RKI2C1_SEL_SHIFT	= 12,
+	RKI2C1_SEL_MASK		= 1 << RKI2C1_SEL_SHIFT,
+
+	RKI2C0_SEL_SHIFT	= 11,
+	RKI2C0_SEL_MASK		= 1 << RKI2C0_SEL_SHIFT,
+
+	VCODEC_SEL_SHIFT	= 10,
+	VCODEC_SEL_MASK		= 1 << VCODEC_SEL_SHIFT,
+
+	PERI_EMEM_PAUSE_SHIFT	= 9,
+	PERI_EMEM_PAUSE_MASK	= 1 << PERI_EMEM_PAUSE_SHIFT,
+
+	PERI_USB_PAUSE_SHIFT	= 8,
+	PERI_USB_PAUSE_MASK	= 1 << PERI_USB_PAUSE_SHIFT,
+
+	SMC_MUX_MODE_0_SHIFT	= 6,
+	SMC_MUX_MODE_0_MASK	= 1 << SMC_MUX_MODE_0_SHIFT,
+
+	SMC_SRAM_MW_0_SHIFT	= 4,
+	SMC_SRAM_MW_0_MASK	= 3 << SMC_SRAM_MW_0_SHIFT,
+
+	SMC_REMAP_0_SHIFT	= 3,
+	SMC_REMAP_0_MASK	= 1 << SMC_REMAP_0_SHIFT,
+
+	SMC_A_GT_M0_SYNC_SHIFT	= 2,
+	SMC_A_GT_M0_SYNC_MASK	= 1 << SMC_A_GT_M0_SYNC_SHIFT,
+
+	EMAC_SPEED_SHIFT	= 1,
+	EMAC_SPEEC_MASK		= 1 << EMAC_SPEED_SHIFT,
+
+	EMAC_MODE_SHIFT		= 0,
+	EMAC_MODE_MASK		= 1 << EMAC_MODE_SHIFT,
+};
+
+/* GRF_SOC_CON2 */
+enum {
+	MSCH4_MAINDDR3_SHIFT	= 7,
+	MSCH4_MAINDDR3_MASK	= 1 << MSCH4_MAINDDR3_SHIFT,
+	MSCH4_MAINDDR3_DDR3	= 1,
+
+	EMAC_NEWRCV_EN_SHIFT	= 6,
+	EMAC_NEWRCV_EN_MASK	= 1 << EMAC_NEWRCV_EN_SHIFT,
+
+	SW_ADDR15_EN_SHIFT	= 5,
+	SW_ADDR15_EN_MASK	= 1 << SW_ADDR15_EN_SHIFT,
+
+	SW_ADDR16_EN_SHIFT	= 4,
+	SW_ADDR16_EN_MASK	= 1 << SW_ADDR16_EN_SHIFT,
+
+	SW_ADDR17_EN_SHIFT	= 3,
+	SW_ADDR17_EN_MASK	= 1 << SW_ADDR17_EN_SHIFT,
+
+	BANK2_TO_RANK_EN_SHIFT	= 2,
+	BANK2_TO_RANK_EN_MASK	= 1 << BANK2_TO_RANK_EN_SHIFT,
+
+	RANK_TO_ROW15_EN_SHIFT	= 1,
+	RANK_TO_ROW15_EN_MASK	= 1 << RANK_TO_ROW15_EN_SHIFT,
+
+	UPCTL_C_ACTIVE_IN_SHIFT = 0,
+	UPCTL_C_ACTIVE_IN_MASK	= 1 << UPCTL_C_ACTIVE_IN_SHIFT,
+	UPCTL_C_ACTIVE_IN_MAY	= 0,
+	UPCTL_C_ACTIVE_IN_WILL,
+};
+
+/* GRF_DDRC_CON0 */
+enum {
+	DTO_LB_SHIFT		= 11,
+	DTO_LB_MASK		= 3 << DTO_LB_SHIFT,
+
+	DTO_TE_SHIFT		= 9,
+	DTO_TE_MASK		= 3 << DTO_TE_SHIFT,
+
+	DTO_PDR_SHIFT		= 7,
+	DTO_PDR_MASK		= 3 << DTO_PDR_SHIFT,
+
+	DTO_PDD_SHIFT		= 5,
+	DTO_PDD_MASK		= 3 << DTO_PDD_SHIFT,
+
+	DTO_IOM_SHIFT		= 3,
+	DTO_IOM_MASK		= 3 << DTO_IOM_SHIFT,
+
+	DTO_OE_SHIFT		= 1,
+	DTO_OE_MASK		= 3 << DTO_OE_SHIFT,
+
+	ATO_AE_SHIFT		= 0,
+	ATO_AE_MASK		= 1 << ATO_AE_SHIFT,
+};
+#endif
--
2.32.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v6 2/4] rockchip: rk3066: add clock driver for rk3066 soc
  2021-07-13 18:58 [PATCH v6 0/4] Add basic support for rk3066 platform Paweł Jarosz
  2021-07-13 18:58 ` [PATCH v6 1/4] rockchip: rk3066: add grf header file Paweł Jarosz
@ 2021-07-13 18:58 ` Paweł Jarosz
  2021-07-13 20:17   ` Simon Glass
  2021-07-13 18:58 ` [PATCH v6 3/4] rockchip: rk3066: add rk3066 pinctrl driver Paweł Jarosz
  2021-07-13 18:59 ` [PATCH v6 4/4] rockchip: rk3066: add sdram driver Paweł Jarosz
  3 siblings, 1 reply; 8+ messages in thread
From: Paweł Jarosz @ 2021-07-13 18:58 UTC (permalink / raw)
  To: kever.yang; +Cc: sjg, philipp.tomsich, lukma, u-boot

Add clock driver for rk3066 platform.

Signed-off-by: Paweł Jarosz <paweljarosz3691@gmail.com>
Acked-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
---

Changes since v1:
- updated to shifted masks
- moved clk init to tpl

Changes since v2:
- none

Changes since v3:
- none

Changes since v4:
- updated to current codebase
- fixed compilation errors

Changes since v5:
- various style changes
- added clk_enable/clk_disable support for nand and mmc clocks
- updated maintainer email
- renamed uint32_t to u32
- used #if IS_ENABLED macro instead #ifdef



 .../include/asm/arch-rockchip/cru_rk3066.h    | 203 +++++
 drivers/clk/rockchip/Makefile                 |   1 +
 drivers/clk/rockchip/clk_rk3066.c             | 704 ++++++++++++++++++
 3 files changed, 908 insertions(+)
 create mode 100644 arch/arm/include/asm/arch-rockchip/cru_rk3066.h
 create mode 100644 drivers/clk/rockchip/clk_rk3066.c

diff --git a/arch/arm/include/asm/arch-rockchip/cru_rk3066.h b/arch/arm/include/asm/arch-rockchip/cru_rk3066.h
new file mode 100644
index 0000000000..711366d530
--- /dev/null
+++ b/arch/arm/include/asm/arch-rockchip/cru_rk3066.h
@@ -0,0 +1,203 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2021 Paweł Jarosz <paweljarosz3691@gmail.com>
+ */
+
+#ifndef _ASM_ARCH_CRU_RK3066_H
+#define _ASM_ARCH_CRU_RK3066_H
+
+#define OSC_HZ		(24 * 1000 * 1000)
+
+#define APLL_HZ	(1416 * 1000000)
+#define APLL_SAFE_HZ	(600 * 1000000)
+#define GPLL_HZ	(594 * 1000000)
+#define CPLL_HZ	(384 * 1000000)
+
+/* The SRAM is clocked off aclk_cpu, so we want to max it out for boot speed */
+#define CPU_ACLK_HZ	297000000
+#define CPU_HCLK_HZ	148500000
+#define CPU_PCLK_HZ	74250000
+#define CPU_H2P_HZ	74250000
+
+#define PERI_ACLK_HZ	148500000
+#define PERI_HCLK_HZ	148500000
+#define PERI_PCLK_HZ	74250000
+
+/* Private data for the clock driver - used by rockchip_get_cru() */
+struct rk3066_clk_priv {
+	struct rk3066_grf *grf;
+	struct rk3066_cru *cru;
+	ulong rate;
+	bool has_bwadj;
+};
+
+struct rk3066_cru {
+	struct rk3066_pll {
+		u32 con0;
+		u32 con1;
+		u32 con2;
+		u32 con3;
+	} pll[4];
+	u32 cru_mode_con;
+	u32 cru_clksel_con[35];
+	u32 cru_clkgate_con[10];
+	u32 reserved1[2];
+	u32 cru_glb_srst_fst_value;
+	u32 cru_glb_srst_snd_value;
+	u32 reserved2[2];
+	u32 cru_softrst_con[9];
+	u32 cru_misc_con;
+	u32 reserved3[2];
+	u32 cru_glb_cnt_th;
+};
+
+check_member(rk3066_cru, cru_glb_cnt_th, 0x0140);
+
+/* CRU_CLKSEL0_CON */
+enum {
+	/* a9_core_div: core = core_src / (a9_core_div + 1) */
+	A9_CORE_DIV_SHIFT	= 9,
+	A9_CORE_DIV_MASK	= 0x1f << A9_CORE_DIV_SHIFT,
+	CORE_PLL_SHIFT		= 8,
+	CORE_PLL_MASK		= 1 << CORE_PLL_SHIFT,
+	CORE_PLL_SELECT_APLL	= 0,
+	CORE_PLL_SELECT_GPLL,
+
+	/* core peri div: core:core_peri = 2:1, 4:1, 8:1 or 16:1 */
+	CORE_PERI_DIV_SHIFT	= 6,
+	CORE_PERI_DIV_MASK	= 3 << CORE_PERI_DIV_SHIFT,
+
+	/* aclk_cpu pll selection */
+	CPU_ACLK_PLL_SHIFT	= 5,
+	CPU_ACLK_PLL_MASK	= 1 << CPU_ACLK_PLL_SHIFT,
+	CPU_ACLK_PLL_SELECT_APLL	= 0,
+	CPU_ACLK_PLL_SELECT_GPLL,
+
+	/* a9_cpu_div: aclk_cpu = cpu_src / (a9_cpu_div + 1) */
+	A9_CPU_DIV_SHIFT	= 0,
+	A9_CPU_DIV_MASK	= 0x1f << A9_CPU_DIV_SHIFT,
+};
+
+/* CRU_CLKSEL1_CON */
+enum {
+	/* ahb2apb_pclk_div: hclk_cpu:pclk_cpu = 1:1, 2:1 or 4:1 */
+	AHB2APB_DIV_SHIFT	= 14,
+	AHB2APB_DIV_MASK	= 3 << AHB2APB_DIV_SHIFT,
+
+	/* cpu_pclk_div: aclk_cpu:pclk_cpu = 1:1, 2:1, 4:1 or 8:1 */
+	CPU_PCLK_DIV_SHIFT	= 12,
+	CPU_PCLK_DIV_MASK	= 3 << CPU_PCLK_DIV_SHIFT,
+
+	/* cpu_hclk_div: aclk_cpu:hclk_cpu = 1:1, 2:1 or 4:1 */
+	CPU_HCLK_DIV_SHIFT	= 8,
+	CPU_HCLK_DIV_MASK	= 3 << CPU_HCLK_DIV_SHIFT,
+
+	/* core_aclk_div: cire:aclk_core = 1:1, 2:1, 3:1, 4:1 or 8:1 */
+	CORE_ACLK_DIV_SHIFT	= 3,
+	CORE_ACLK_DIV_MASK	= 7 << CORE_ACLK_DIV_SHIFT,
+};
+
+/* CRU_CLKSEL10_CON */
+enum {
+	PERI_SEL_PLL_SHIFT	= 15,
+	PERI_SEL_PLL_MASK	= 1 << PERI_SEL_PLL_SHIFT,
+	PERI_SEL_CPLL		= 0,
+	PERI_SEL_GPLL,
+
+	/* peri pclk div: aclk_bus:pclk_bus = 1:1, 2:1, 4:1 or 8:1 */
+	PERI_PCLK_DIV_SHIFT	= 12,
+	PERI_PCLK_DIV_MASK	= 3 << PERI_PCLK_DIV_SHIFT,
+
+	/* peripheral bus hclk div:aclk_bus: hclk_bus = 1:1, 2:1 or 4:1 */
+	PERI_HCLK_DIV_SHIFT	= 8,
+	PERI_HCLK_DIV_MASK	= 3 << PERI_HCLK_DIV_SHIFT,
+
+	/* peri aclk div: aclk_peri = periph_src / (peri_aclk_div + 1) */
+	PERI_ACLK_DIV_SHIFT	= 0,
+	PERI_ACLK_DIV_MASK	= 0x1f << PERI_ACLK_DIV_SHIFT,
+};
+
+/* CRU_CLKSEL11_CON */
+enum {
+	MMC0_DIV_SHIFT		= 0,
+	MMC0_DIV_MASK		= 0x3f << MMC0_DIV_SHIFT,
+};
+
+/* CRU_CLKSEL12_CON */
+enum {
+	UART_PLL_SHIFT		= 15,
+	UART_PLL_MASK		= 1 << UART_PLL_SHIFT,
+	UART_PLL_SELECT_GENERAL	= 0,
+	UART_PLL_SELECT_CODEC,
+
+	EMMC_DIV_SHIFT		= 8,
+	EMMC_DIV_MASK		= 0x3f << EMMC_DIV_SHIFT,
+
+	SDIO_DIV_SHIFT		= 0,
+	SDIO_DIV_MASK		= 0x3f << SDIO_DIV_SHIFT,
+};
+
+/* CRU_CLKSEL24_CON */
+enum {
+	SARADC_DIV_SHIFT	= 8,
+	SARADC_DIV_MASK	= 0xff << SARADC_DIV_SHIFT,
+};
+
+/* CRU_CLKSEL25_CON */
+enum {
+	SPI1_DIV_SHIFT		= 8,
+	SPI1_DIV_MASK		= 0x7f << SPI1_DIV_SHIFT,
+
+	SPI0_DIV_SHIFT		= 0,
+	SPI0_DIV_MASK		= 0x7f << SPI0_DIV_SHIFT,
+};
+
+/* CRU_CLKSEL34_CON */
+enum {
+	TSADC_DIV_SHIFT	= 0,
+	TSADC_DIV_MASK		= 0xffff << TSADC_DIV_SHIFT,
+};
+
+/* CRU_MODE_CON */
+enum {
+	GPLL_MODE_SHIFT	= 12,
+	GPLL_MODE_MASK		= 3 << GPLL_MODE_SHIFT,
+	GPLL_MODE_SLOW		= 0,
+	GPLL_MODE_NORMAL,
+	GPLL_MODE_DEEP,
+
+	CPLL_MODE_SHIFT		= 8,
+	CPLL_MODE_MASK		= 3 << CPLL_MODE_SHIFT,
+	CPLL_MODE_SLOW		= 0,
+	CPLL_MODE_NORMAL,
+	CPLL_MODE_DEEP,
+
+	DPLL_MODE_SHIFT		= 4,
+	DPLL_MODE_MASK		= 3 << DPLL_MODE_SHIFT,
+	DPLL_MODE_SLOW		= 0,
+	DPLL_MODE_NORMAL,
+	DPLL_MODE_DEEP,
+
+	APLL_MODE_SHIFT		= 0,
+	APLL_MODE_MASK		= 3 << APLL_MODE_SHIFT,
+	APLL_MODE_SLOW		= 0,
+	APLL_MODE_NORMAL,
+	APLL_MODE_DEEP,
+};
+
+/* CRU_APLL_CON0 */
+enum {
+	CLKR_SHIFT		= 8,
+	CLKR_MASK		= 0x3f << CLKR_SHIFT,
+
+	CLKOD_SHIFT		= 0,
+	CLKOD_MASK		= 0x3f << CLKOD_SHIFT,
+};
+
+/* CRU_APLL_CON1 */
+enum {
+	CLKF_SHIFT		= 0,
+	CLKF_MASK		= 0x1fff << CLKF_SHIFT,
+};
+
+#endif
diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
index 913f611a0f..a72d8fe58a 100644
--- a/drivers/clk/rockchip/Makefile
+++ b/drivers/clk/rockchip/Makefile
@@ -6,6 +6,7 @@
 obj-y += clk_pll.o
 obj-$(CONFIG_ROCKCHIP_PX30) += clk_px30.o
 obj-$(CONFIG_ROCKCHIP_RK3036) += clk_rk3036.o
+obj-$(CONFIG_ROCKCHIP_RK3066) += clk_rk3066.o
 obj-$(CONFIG_ROCKCHIP_RK3128) += clk_rk3128.o
 obj-$(CONFIG_ROCKCHIP_RK3188) += clk_rk3188.o
 obj-$(CONFIG_ROCKCHIP_RK322X) += clk_rk322x.o
diff --git a/drivers/clk/rockchip/clk_rk3066.c b/drivers/clk/rockchip/clk_rk3066.c
new file mode 100644
index 0000000000..6e8eed1fa2
--- /dev/null
+++ b/drivers/clk/rockchip/clk_rk3066.c
@@ -0,0 +1,704 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2015 Google, Inc
+ * (C) Copyright 2016 Heiko Stuebner <heiko@sntech.de>
+ */
+
+#include <bitfield.h>
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <dt-structs.h>
+#include <errno.h>
+#include <log.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_rk3066.h>
+#include <asm/arch-rockchip/grf_rk3066.h>
+#include <asm/arch-rockchip/hardware.h>
+#include <dt-bindings/clock/rk3066a-cru.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/uclass-internal.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/log2.h>
+#include <linux/stringify.h>
+
+struct rk3066_clk_plat {
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct dtd_rockchip_rk3066a_cru dtd;
+#endif
+};
+
+struct pll_div {
+	u32 nr;
+	u32 nf;
+	u32 no;
+};
+
+enum {
+	VCO_MAX_HZ	= 1416U * 1000000,
+	VCO_MIN_HZ	= 300 * 1000000,
+	OUTPUT_MAX_HZ	= 1416U * 1000000,
+	OUTPUT_MIN_HZ	= 30 * 1000000,
+	FREF_MAX_HZ	= 1416U * 1000000,
+	FREF_MIN_HZ	= 30 * 1000,
+};
+
+enum {
+	/* PLL CON0 */
+	PLL_OD_MASK		= GENMASK(3, 0),
+
+	/* PLL CON1 */
+	PLL_NF_MASK		= GENMASK(12, 0),
+
+	/* PLL CON2 */
+	PLL_BWADJ_MASK		= GENMASK(11, 0),
+
+	/* PLL CON3 */
+	PLL_RESET_SHIFT		= 5,
+
+	/* GRF_SOC_STATUS0 */
+	SOCSTS_DPLL_LOCK	= BIT(4),
+	SOCSTS_APLL_LOCK	= BIT(5),
+	SOCSTS_CPLL_LOCK	= BIT(6),
+	SOCSTS_GPLL_LOCK	= BIT(7),
+};
+
+#define DIV_TO_RATE(input_rate, div)	((input_rate) / ((div) + 1))
+
+#define PLL_DIVISORS(hz, _nr, _no) {\
+	.nr = _nr, .nf = (u32)((u64)hz * _nr * _no / OSC_HZ), .no = _no};\
+	_Static_assert(((u64)hz * _nr * _no / OSC_HZ) * OSC_HZ /\
+		       (_nr * _no) == hz, #hz "Hz cannot be hit with PLL "\
+		       "divisors on line " __stringify(__LINE__))
+
+/* Keep divisors as low as possible to reduce jitter and power usage */
+#if IS_ENABLED(CONFIG_TPL_BUILD)
+static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2);
+static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 2);
+#endif
+
+static int rkclk_set_pll(struct rk3066_cru *cru, enum rk_clk_id clk_id,
+			 const struct pll_div *div)
+{
+	int pll_id = rk_pll_id(clk_id);
+	struct rk3066_pll *pll = &cru->pll[pll_id];
+	/* All PLLs have same VCO and output frequency range restrictions. */
+	uint vco_hz = OSC_HZ / 1000 * div->nf / div->nr * 1000;
+	uint output_hz = vco_hz / div->no;
+
+	debug("PLL at %x: nf=%d, nr=%d, no=%d, vco=%u Hz, output=%u Hz\n",
+	      (uint)pll, div->nf, div->nr, div->no, vco_hz, output_hz);
+	assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ &&
+	       output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ &&
+	       (div->no == 1 || !(div->no % 2)));
+
+	/* enter reset */
+	rk_setreg(&pll->con3, BIT(PLL_RESET_SHIFT));
+
+	rk_clrsetreg(&pll->con0,
+		     CLKR_MASK | PLL_OD_MASK,
+		     ((div->nr - 1) << CLKR_SHIFT) | (div->no - 1));
+	rk_clrsetreg(&pll->con1, CLKF_MASK, div->nf - 1);
+
+	rk_clrsetreg(&pll->con2, PLL_BWADJ_MASK, (div->nf >> 1) - 1);
+
+	/* return from reset */
+	rk_clrreg(&pll->con3, BIT(PLL_RESET_SHIFT));
+
+	return 0;
+}
+
+static int rkclk_configure_ddr(struct rk3066_cru *cru, struct rk3066_grf *grf,
+			       unsigned int hz)
+{
+	static const struct pll_div dpll_cfg[] = {
+		{.nf = 25, .nr = 2, .no = 1},
+		{.nf = 400, .nr = 9, .no = 2},
+		{.nf = 500, .nr = 9, .no = 2},
+		{.nf = 100, .nr = 3, .no = 1},
+	};
+	int cfg;
+
+	switch (hz) {
+	case 300000000:
+		cfg = 0;
+		break;
+	case 533000000:	/* actually 533.3P MHz */
+		cfg = 1;
+		break;
+	case 666000000:	/* actually 666.6P MHz */
+		cfg = 2;
+		break;
+	case 800000000:
+		cfg = 3;
+		break;
+	default:
+		debug("Unsupported SDRAM frequency");
+		return -EINVAL;
+	}
+
+	/* pll enter slow-mode */
+	rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK,
+		     DPLL_MODE_SLOW << DPLL_MODE_SHIFT);
+
+	rkclk_set_pll(cru, CLK_DDR, &dpll_cfg[cfg]);
+
+	/* wait for pll lock */
+	while (!(readl(&grf->soc_status0) & SOCSTS_DPLL_LOCK))
+		udelay(1);
+
+	/* PLL enter normal-mode */
+	rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK,
+		     DPLL_MODE_NORMAL << DPLL_MODE_SHIFT);
+
+	return 0;
+}
+
+static int rkclk_configure_cpu(struct rk3066_cru *cru, struct rk3066_grf *grf,
+			       unsigned int hz)
+{
+	static const struct pll_div apll_cfg[] = {
+		{.nf = 50, .nr = 1, .no = 2},
+		{.nf = 59, .nr = 1, .no = 1},
+	};
+	int div_core_peri, div_aclk_core, cfg;
+
+	/*
+	 * We support two possible frequencies, the safe 600MHz
+	 * which will work with default pmic settings and will
+	 * be set to get away from the 24MHz default and
+	 * the maximum of 1.416Ghz, which boards can set if they
+	 * were able to get pmic support for it.
+	 */
+	switch (hz) {
+	case APLL_SAFE_HZ:
+		cfg = 0;
+		div_core_peri = 1;
+		div_aclk_core = 3;
+		break;
+	case APLL_HZ:
+		cfg = 1;
+		div_core_peri = 2;
+		div_aclk_core = 3;
+		break;
+	default:
+		debug("Unsupported ARMCLK frequency");
+		return -EINVAL;
+	}
+
+	/* pll enter slow-mode */
+	rk_clrsetreg(&cru->cru_mode_con, APLL_MODE_MASK,
+		     APLL_MODE_SLOW << APLL_MODE_SHIFT);
+
+	rkclk_set_pll(cru, CLK_ARM, &apll_cfg[cfg]);
+
+	/* waiting for pll lock */
+	while (!(readl(&grf->soc_status0) & SOCSTS_APLL_LOCK))
+		udelay(1);
+
+	/* Set divider for peripherals attached to the cpu core. */
+	rk_clrsetreg(&cru->cru_clksel_con[0],
+		     CORE_PERI_DIV_MASK,
+		     div_core_peri << CORE_PERI_DIV_SHIFT);
+
+	/* set up dependent divisor for aclk_core */
+	rk_clrsetreg(&cru->cru_clksel_con[1],
+		     CORE_ACLK_DIV_MASK,
+		     div_aclk_core << CORE_ACLK_DIV_SHIFT);
+
+	/* PLL enter normal-mode */
+	rk_clrsetreg(&cru->cru_mode_con, APLL_MODE_MASK,
+		     APLL_MODE_NORMAL << APLL_MODE_SHIFT);
+
+	return hz;
+}
+
+/* Get pll rate by id */
+static uint32_t rkclk_pll_get_rate(struct rk3066_cru *cru,
+				   enum rk_clk_id clk_id)
+{
+	u32 nr, no, nf;
+	u32 con;
+	int pll_id = rk_pll_id(clk_id);
+	struct rk3066_pll *pll = &cru->pll[pll_id];
+	static u8 clk_shift[CLK_COUNT] = {
+		0xff, APLL_MODE_SHIFT, DPLL_MODE_SHIFT, CPLL_MODE_SHIFT,
+		GPLL_MODE_SHIFT
+	};
+	uint shift;
+
+	con = readl(&cru->cru_mode_con);
+	shift = clk_shift[clk_id];
+	switch ((con >> shift) & APLL_MODE_MASK >> APLL_MODE_SHIFT) {
+	case APLL_MODE_SLOW:
+		return OSC_HZ;
+	case APLL_MODE_NORMAL:
+		/* normal mode */
+		con = readl(&pll->con0);
+		no = bitfield_extract_by_mask(con, CLKOD_MASK) + 1;
+		nr = bitfield_extract_by_mask(con, CLKR_MASK) + 1;
+		con = readl(&pll->con1);
+		nf = bitfield_extract_by_mask(con, CLKF_MASK) + 1;
+
+		return (OSC_HZ * nf) / (nr * no);
+	case APLL_MODE_DEEP:
+	default:
+		return 32768;
+	}
+}
+
+static ulong rockchip_mmc_get_clk(struct rk3066_cru *cru, uint gclk_rate,
+				  int periph)
+{
+	uint div;
+	u32 con;
+
+	switch (periph) {
+	case HCLK_EMMC:
+	case SCLK_EMMC:
+		con = readl(&cru->cru_clksel_con[12]);
+		div = bitfield_extract_by_mask(con, EMMC_DIV_MASK);
+		break;
+	case HCLK_SDMMC:
+	case SCLK_SDMMC:
+		con = readl(&cru->cru_clksel_con[11]);
+		div = bitfield_extract_by_mask(con, MMC0_DIV_MASK);
+		break;
+	case HCLK_SDIO:
+	case SCLK_SDIO:
+		con = readl(&cru->cru_clksel_con[12]);
+		div = bitfield_extract_by_mask(con, SDIO_DIV_MASK);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return DIV_TO_RATE(gclk_rate, div) / 2;
+}
+
+static ulong rockchip_mmc_set_clk(struct rk3066_cru *cru, uint gclk_rate,
+				  int  periph, uint freq)
+{
+	int src_clk_div;
+
+	debug("%s: gclk_rate=%u\n", __func__, gclk_rate);
+	/* mmc clock defaulg div 2 internal, need provide double in cru */
+	src_clk_div = DIV_ROUND_UP(gclk_rate / 2, freq) - 1;
+	assert(src_clk_div <= 0x3f);
+
+	switch (periph) {
+	case HCLK_EMMC:
+	case SCLK_EMMC:
+		rk_clrsetreg(&cru->cru_clksel_con[12],
+			     EMMC_DIV_MASK,
+			     src_clk_div << EMMC_DIV_SHIFT);
+		break;
+	case HCLK_SDMMC:
+	case SCLK_SDMMC:
+		rk_clrsetreg(&cru->cru_clksel_con[11],
+			     MMC0_DIV_MASK,
+			     src_clk_div << MMC0_DIV_SHIFT);
+		break;
+	case HCLK_SDIO:
+	case SCLK_SDIO:
+		rk_clrsetreg(&cru->cru_clksel_con[12],
+			     SDIO_DIV_MASK,
+			     src_clk_div << SDIO_DIV_SHIFT);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return rockchip_mmc_get_clk(cru, gclk_rate, periph);
+}
+
+static ulong rockchip_spi_get_clk(struct rk3066_cru *cru, uint gclk_rate,
+				  int periph)
+{
+	uint div;
+	u32 con;
+
+	switch (periph) {
+	case SCLK_SPI0:
+		con = readl(&cru->cru_clksel_con[25]);
+		div = bitfield_extract_by_mask(con, SPI0_DIV_MASK);
+		break;
+	case SCLK_SPI1:
+		con = readl(&cru->cru_clksel_con[25]);
+		div = bitfield_extract_by_mask(con, SPI1_DIV_MASK);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return DIV_TO_RATE(gclk_rate, div);
+}
+
+static ulong rockchip_spi_set_clk(struct rk3066_cru *cru, uint gclk_rate,
+				  int periph, uint freq)
+{
+	int src_clk_div = DIV_ROUND_UP(gclk_rate, freq) - 1;
+
+	assert(src_clk_div < 128);
+	switch (periph) {
+	case SCLK_SPI0:
+		assert(src_clk_div <= SPI0_DIV_MASK >> SPI0_DIV_SHIFT);
+		rk_clrsetreg(&cru->cru_clksel_con[25],
+			     SPI0_DIV_MASK,
+			     src_clk_div << SPI0_DIV_SHIFT);
+		break;
+	case SCLK_SPI1:
+		assert(src_clk_div <= SPI1_DIV_MASK >> SPI1_DIV_SHIFT);
+		rk_clrsetreg(&cru->cru_clksel_con[25],
+			     SPI1_DIV_MASK,
+			     src_clk_div << SPI1_DIV_SHIFT);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return rockchip_spi_get_clk(cru, gclk_rate, periph);
+}
+
+static ulong rockchip_saradc_get_clk(struct rk3066_cru *cru, int periph)
+{
+	u32 div, con;
+
+	switch (periph) {
+	case SCLK_SARADC:
+		con = readl(&cru->cru_clksel_con[24]);
+		div = bitfield_extract_by_mask(con, SARADC_DIV_MASK);
+		break;
+	case SCLK_TSADC:
+		con = readl(&cru->cru_clksel_con[34]);
+		div = bitfield_extract_by_mask(con, TSADC_DIV_MASK);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return DIV_TO_RATE(PERI_PCLK_HZ, div);
+}
+
+static ulong rockchip_saradc_set_clk(struct rk3066_cru *cru, uint hz,
+				     int periph)
+{
+	int src_clk_div;
+
+	src_clk_div = DIV_ROUND_UP(PERI_PCLK_HZ, hz) - 1;
+	assert(src_clk_div < 128);
+
+	switch (periph) {
+	case SCLK_SARADC:
+		rk_clrsetreg(&cru->cru_clksel_con[24],
+			     SARADC_DIV_MASK,
+			     src_clk_div << SARADC_DIV_SHIFT);
+		break;
+	case SCLK_TSADC:
+		rk_clrsetreg(&cru->cru_clksel_con[34],
+			     SARADC_DIV_MASK,
+			     src_clk_div << SARADC_DIV_SHIFT);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return rockchip_saradc_get_clk(cru, periph);
+}
+
+#if IS_ENABLED(CONFIG_TPL_BUILD)
+static void rkclk_init(struct rk3066_cru *cru, struct rk3066_grf *grf)
+{
+	u32 aclk_div, hclk_div, pclk_div, h2p_div;
+
+	/* pll enter slow-mode */
+	rk_clrsetreg(&cru->cru_mode_con,
+		     GPLL_MODE_MASK |
+		     CPLL_MODE_MASK,
+		     GPLL_MODE_SLOW << GPLL_MODE_SHIFT |
+		     CPLL_MODE_SLOW << CPLL_MODE_SHIFT);
+
+	/* init pll */
+	rkclk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg);
+	rkclk_set_pll(cru, CLK_CODEC, &cpll_init_cfg);
+
+	/* waiting for pll lock */
+	while ((readl(&grf->soc_status0) &
+		(SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK)) !=
+	       (SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK))
+		udelay(1);
+
+	/*
+	 * cpu clock pll source selection and
+	 * reparent aclk_cpu_pre from apll to gpll
+	 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
+	 */
+	aclk_div = DIV_ROUND_UP(GPLL_HZ, CPU_ACLK_HZ) - 1;
+	assert((aclk_div + 1) * CPU_ACLK_HZ == GPLL_HZ && aclk_div <= 0x1f);
+
+	rk_clrsetreg(&cru->cru_clksel_con[0],
+		     CPU_ACLK_PLL_MASK |
+		     A9_CPU_DIV_MASK,
+		     CPU_ACLK_PLL_SELECT_GPLL << CPU_ACLK_PLL_SHIFT |
+		     aclk_div << A9_CPU_DIV_SHIFT);
+
+	hclk_div = ilog2(CPU_ACLK_HZ / CPU_HCLK_HZ);
+	assert((1 << hclk_div) * CPU_HCLK_HZ == CPU_ACLK_HZ && hclk_div < 0x3);
+	pclk_div = ilog2(CPU_ACLK_HZ / CPU_PCLK_HZ);
+	assert((1 << pclk_div) * CPU_PCLK_HZ == CPU_ACLK_HZ && pclk_div < 0x4);
+	h2p_div = ilog2(CPU_HCLK_HZ / CPU_H2P_HZ);
+	assert((1 << h2p_div) * CPU_H2P_HZ == CPU_HCLK_HZ && pclk_div < 0x3);
+
+	rk_clrsetreg(&cru->cru_clksel_con[1],
+		     AHB2APB_DIV_MASK |
+		     CPU_PCLK_DIV_MASK |
+		     CPU_HCLK_DIV_MASK,
+		     h2p_div << AHB2APB_DIV_SHIFT |
+		     pclk_div << CPU_PCLK_DIV_SHIFT |
+		     hclk_div << CPU_HCLK_DIV_SHIFT);
+
+	/*
+	 * peri clock pll source selection and
+	 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
+	 */
+	aclk_div = GPLL_HZ / PERI_ACLK_HZ - 1;
+	assert((aclk_div + 1) * PERI_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f);
+
+	hclk_div = ilog2(PERI_ACLK_HZ / PERI_HCLK_HZ);
+	assert((1 << hclk_div) * PERI_HCLK_HZ ==
+	       PERI_ACLK_HZ && (hclk_div < 0x4));
+
+	pclk_div = ilog2(PERI_ACLK_HZ / PERI_PCLK_HZ);
+	assert((1 << pclk_div) * PERI_PCLK_HZ ==
+	       PERI_ACLK_HZ && (pclk_div < 0x4));
+
+	rk_clrsetreg(&cru->cru_clksel_con[10],
+		     PERI_PCLK_DIV_MASK |
+		     PERI_HCLK_DIV_MASK |
+		     PERI_ACLK_DIV_MASK,
+		     PERI_SEL_GPLL << PERI_SEL_PLL_SHIFT |
+		     pclk_div << PERI_PCLK_DIV_SHIFT |
+		     hclk_div << PERI_HCLK_DIV_SHIFT |
+		     aclk_div << PERI_ACLK_DIV_SHIFT);
+
+	/* PLL enter normal-mode */
+	rk_clrsetreg(&cru->cru_mode_con,
+		     GPLL_MODE_MASK |
+		     CPLL_MODE_MASK,
+		     GPLL_MODE_NORMAL << GPLL_MODE_SHIFT |
+		     CPLL_MODE_NORMAL << CPLL_MODE_SHIFT);
+
+	rockchip_mmc_set_clk(cru, PERI_HCLK_HZ, HCLK_SDMMC, 16000000);
+}
+#endif
+
+static ulong rk3066_clk_get_rate(struct clk *clk)
+{
+	struct rk3066_clk_priv *priv = dev_get_priv(clk->dev);
+	ulong new_rate, gclk_rate;
+
+	gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL);
+	switch (clk->id) {
+	case 1 ... 4:
+		new_rate = rkclk_pll_get_rate(priv->cru, clk->id);
+		break;
+	case HCLK_EMMC:
+	case HCLK_SDMMC:
+	case HCLK_SDIO:
+	case SCLK_EMMC:
+	case SCLK_SDMMC:
+	case SCLK_SDIO:
+		new_rate = rockchip_mmc_get_clk(priv->cru, PERI_HCLK_HZ,
+						clk->id);
+		break;
+	case SCLK_SPI0:
+	case SCLK_SPI1:
+		new_rate = rockchip_spi_get_clk(priv->cru, PERI_PCLK_HZ,
+						clk->id);
+		break;
+	case PCLK_I2C0:
+	case PCLK_I2C1:
+	case PCLK_I2C2:
+	case PCLK_I2C3:
+	case PCLK_I2C4:
+		return gclk_rate;
+	case SCLK_SARADC:
+	case SCLK_TSADC:
+		new_rate = rockchip_saradc_get_clk(priv->cru, clk->id);
+		break;
+	default:
+		return -ENOENT;
+	}
+
+	return new_rate;
+}
+
+static ulong rk3066_clk_set_rate(struct clk *clk, ulong rate)
+{
+	struct rk3066_clk_priv *priv = dev_get_priv(clk->dev);
+	struct rk3066_cru *cru = priv->cru;
+	ulong new_rate;
+
+	switch (clk->id) {
+	case PLL_APLL:
+		new_rate = rkclk_configure_cpu(priv->cru, priv->grf, rate);
+		break;
+	case CLK_DDR:
+		new_rate = rkclk_configure_ddr(priv->cru, priv->grf, rate);
+		break;
+	case HCLK_EMMC:
+	case HCLK_SDMMC:
+	case HCLK_SDIO:
+	case SCLK_EMMC:
+	case SCLK_SDMMC:
+	case SCLK_SDIO:
+		new_rate = rockchip_mmc_set_clk(cru, PERI_HCLK_HZ,
+						clk->id, rate);
+		break;
+	case SCLK_SPI0:
+	case SCLK_SPI1:
+		new_rate = rockchip_spi_set_clk(cru, PERI_PCLK_HZ,
+						clk->id, rate);
+		break;
+	case SCLK_SARADC:
+	case SCLK_TSADC:
+		new_rate = rockchip_saradc_set_clk(cru, rate, clk->id);
+		break;
+	default:
+		return -ENOENT;
+	}
+
+	return new_rate;
+}
+
+static int rk3066_clk_enable(struct clk *clk)
+{
+	struct rk3066_clk_priv *priv = dev_get_priv(clk->dev);
+
+	switch (clk->id) {
+	case HCLK_NANDC0:
+		rk_clrreg(&priv->cru->cru_clkgate_con[5], BIT(9));
+		break;
+	case HCLK_SDMMC:
+		rk_clrreg(&priv->cru->cru_clkgate_con[5], BIT(10));
+		break;
+	case HCLK_SDIO:
+		rk_clrreg(&priv->cru->cru_clkgate_con[5], BIT(11));
+		break;
+	}
+
+	return 0;
+}
+
+static int rk3066_clk_disable(struct clk *clk)
+{
+	struct rk3066_clk_priv *priv = dev_get_priv(clk->dev);
+
+	switch (clk->id) {
+	case HCLK_NANDC0:
+		rk_setreg(&priv->cru->cru_clkgate_con[5], BIT(9));
+		break;
+	case HCLK_SDMMC:
+		rk_setreg(&priv->cru->cru_clkgate_con[5], BIT(10));
+		break;
+	case HCLK_SDIO:
+		rk_setreg(&priv->cru->cru_clkgate_con[5], BIT(11));
+		break;
+	}
+
+	return 0;
+}
+
+static struct clk_ops rk3066_clk_ops = {
+	.disable	= rk3066_clk_disable,
+	.enable	= rk3066_clk_enable,
+	.get_rate	= rk3066_clk_get_rate,
+	.set_rate	= rk3066_clk_set_rate,
+};
+
+static int rk3066_clk_of_to_plat(struct udevice *dev)
+{
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct rk3066_clk_priv *priv = dev_get_priv(dev);
+
+	priv->cru = dev_read_addr_ptr(dev);
+#endif
+
+	return 0;
+}
+
+static int rk3066_clk_probe(struct udevice *dev)
+{
+	struct rk3066_clk_priv *priv = dev_get_priv(dev);
+
+	priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+	if (IS_ERR(priv->grf))
+		return PTR_ERR(priv->grf);
+
+#if IS_ENABLED(CONFIG_TPL_BUILD)
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct rk3066_clk_plat *plat = dev_get_plat(dev);
+
+	priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]);
+#endif
+
+	rkclk_init(priv->cru, priv->grf);
+
+	/* Init CPU frequency */
+	rkclk_configure_cpu(priv->cru, priv->grf, APLL_SAFE_HZ);
+#endif
+
+	return 0;
+}
+
+static int rk3066_clk_bind(struct udevice *dev)
+{
+	int ret;
+	struct udevice *sys_child;
+	struct sysreset_reg *priv;
+
+	/* The reset driver does not have a device node, so bind it here */
+	ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
+				 &sys_child);
+	if (ret) {
+		debug("Warning: No sysreset driver: ret=%d\n", ret);
+	} else {
+		priv = malloc(sizeof(struct sysreset_reg));
+		priv->glb_srst_fst_value = offsetof(struct rk3066_cru,
+						    cru_glb_srst_fst_value);
+		priv->glb_srst_snd_value = offsetof(struct rk3066_cru,
+						    cru_glb_srst_snd_value);
+		dev_set_priv(sys_child, priv);
+	}
+
+#if CONFIG_IS_ENABLED(RESET_ROCKCHIP)
+	ret = offsetof(struct rk3066_cru, cru_softrst_con[0]);
+	ret = rockchip_reset_bind(dev, ret, 9);
+	if (ret)
+		debug("Warning: software reset driver bind failed\n");
+#endif
+
+	return 0;
+}
+
+static const struct udevice_id rk3066_clk_ids[] = {
+	{ .compatible = "rockchip,rk3066a-cru" },
+	{ }
+};
+
+U_BOOT_DRIVER(rockchip_rk3066a_cru) = {
+	.name			= "rockchip_rk3066a_cru",
+	.id			= UCLASS_CLK,
+	.of_match		= rk3066_clk_ids,
+	.priv_auto		= sizeof(struct rk3066_clk_priv),
+	.plat_auto		= sizeof(struct rk3066_clk_plat),
+	.ops			= &rk3066_clk_ops,
+	.bind			= rk3066_clk_bind,
+	.of_to_plat		= rk3066_clk_of_to_plat,
+	.probe			= rk3066_clk_probe,
+};
--
2.32.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v6 3/4] rockchip: rk3066: add rk3066 pinctrl driver
  2021-07-13 18:58 [PATCH v6 0/4] Add basic support for rk3066 platform Paweł Jarosz
  2021-07-13 18:58 ` [PATCH v6 1/4] rockchip: rk3066: add grf header file Paweł Jarosz
  2021-07-13 18:58 ` [PATCH v6 2/4] rockchip: rk3066: add clock driver for rk3066 soc Paweł Jarosz
@ 2021-07-13 18:58 ` Paweł Jarosz
  2021-07-13 18:59 ` [PATCH v6 4/4] rockchip: rk3066: add sdram driver Paweł Jarosz
  3 siblings, 0 replies; 8+ messages in thread
From: Paweł Jarosz @ 2021-07-13 18:58 UTC (permalink / raw)
  To: kever.yang; +Cc: sjg, philipp.tomsich, lukma, u-boot

Add driver supporting pin multiplexing on rk3066 platform.

Signed-off-by: Paweł Jarosz <paweljarosz3691@gmail.com>
---

Changes since v1:
- updated to shifted masks
- added nand support

Changes since v2:
- none

Changes since v3:
- none

Changes since v4:
- updated driver to pinctrl full

Changes since v5:
- none

 drivers/pinctrl/rockchip/Makefile         |   1 +
 drivers/pinctrl/rockchip/pinctrl-rk3066.c | 113 ++++++++++++++++++++++
 2 files changed, 114 insertions(+)
 create mode 100644 drivers/pinctrl/rockchip/pinctrl-rk3066.c

diff --git a/drivers/pinctrl/rockchip/Makefile b/drivers/pinctrl/rockchip/Makefile
index fcf19f877a..7d03f8101d 100644
--- a/drivers/pinctrl/rockchip/Makefile
+++ b/drivers/pinctrl/rockchip/Makefile
@@ -5,6 +5,7 @@
 obj-y += pinctrl-rockchip-core.o
 obj-$(CONFIG_ROCKCHIP_PX30) += pinctrl-px30.o
 obj-$(CONFIG_ROCKCHIP_RK3036) += pinctrl-rk3036.o
+obj-$(CONFIG_ROCKCHIP_RK3066) += pinctrl-rk3066.o
 obj-$(CONFIG_ROCKCHIP_RK3128) += pinctrl-rk3128.o
 obj-$(CONFIG_ROCKCHIP_RK3188) += pinctrl-rk3188.o
 obj-$(CONFIG_ROCKCHIP_RK322X) += pinctrl-rk322x.o
diff --git a/drivers/pinctrl/rockchip/pinctrl-rk3066.c b/drivers/pinctrl/rockchip/pinctrl-rk3066.c
new file mode 100644
index 0000000000..8faba05a4a
--- /dev/null
+++ b/drivers/pinctrl/rockchip/pinctrl-rk3066.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2021 Rockchip Electronics Co., Ltd
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/pinctrl.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <linux/bitops.h>
+
+#include "pinctrl-rockchip.h"
+
+static int rk3066_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
+{
+	struct rockchip_pinctrl_priv *priv = bank->priv;
+	int iomux_num = (pin / 8);
+	struct regmap *regmap;
+	int reg, ret, mask, mux_type;
+	u8 bit;
+	u32 data;
+
+	regmap = (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
+				? priv->regmap_pmu : priv->regmap_base;
+
+	/* get basic quadrupel of mux registers and the correct reg inside */
+	mux_type = bank->iomux[iomux_num].type;
+	reg = bank->iomux[iomux_num].offset;
+	reg += rockchip_get_mux_data(mux_type, pin, &bit, &mask);
+
+	data = (mask << (bit + 16));
+	data |= (mux & mask) << bit;
+	ret = regmap_write(regmap, reg, data);
+
+	return ret;
+}
+
+#define RK3066_PULL_OFFSET		0x118
+#define RK3066_PULL_PINS_PER_REG	16
+#define RK3066_PULL_BANK_STRIDE		8
+
+static void rk3066_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
+					 int pin_num, struct regmap **regmap,
+					 int *reg, u8 *bit)
+{
+	struct rockchip_pinctrl_priv *priv = bank->priv;
+
+	*regmap = priv->regmap_base;
+	*reg = RK3066_PULL_OFFSET;
+	*reg += bank->bank_num * RK3066_PULL_BANK_STRIDE;
+	*reg += (pin_num / RK3066_PULL_PINS_PER_REG) * 4;
+
+	*bit = pin_num % RK3066_PULL_PINS_PER_REG;
+};
+
+static int rk3066_set_pull(struct rockchip_pin_bank *bank,
+			   int pin_num, int pull)
+{
+	struct regmap *regmap;
+	int reg, ret;
+	u8 bit;
+	u32 data;
+
+	if (pull != PIN_CONFIG_BIAS_PULL_PIN_DEFAULT &&
+	    pull != PIN_CONFIG_BIAS_DISABLE)
+		return -ENOTSUPP;
+
+	rk3066_calc_pull_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+	data = BIT(bit + 16);
+	if (pull == PIN_CONFIG_BIAS_DISABLE)
+		data |= BIT(bit);
+	ret = regmap_write(regmap, reg, data);
+
+	return ret;
+}
+
+static struct rockchip_pin_bank rk3066_pin_banks[] = {
+	PIN_BANK(0, 32, "gpio0"),
+	PIN_BANK(1, 32, "gpio1"),
+	PIN_BANK(2, 32, "gpio2"),
+	PIN_BANK(3, 32, "gpio3"),
+	PIN_BANK(4, 32, "gpio4"),
+	PIN_BANK(6, 16, "gpio6"),
+};
+
+static struct rockchip_pin_ctrl rk3066_pin_ctrl = {
+	.pin_banks		= rk3066_pin_banks,
+	.nr_banks		= ARRAY_SIZE(rk3066_pin_banks),
+	.grf_mux_offset = 0xa8,
+	.set_mux		= rk3066_set_mux,
+	.set_pull		= rk3066_set_pull,
+};
+
+static const struct udevice_id rk3066_pinctrl_ids[] = {
+	{
+		.compatible = "rockchip,rk3066a-pinctrl",
+		.data = (ulong)&rk3066_pin_ctrl
+	},
+	{}
+};
+
+U_BOOT_DRIVER(rockchip_rk3066a_pinctrl) = {
+	.name		= "rockchip_rk3066a_pinctrl",
+	.id		= UCLASS_PINCTRL,
+	.of_match	= rk3066_pinctrl_ids,
+	.priv_auto	= sizeof(struct rockchip_pinctrl_priv),
+	.ops		= &rockchip_pinctrl_ops,
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+	.bind		= dm_scan_fdt_dev,
+#endif
+	.probe		= rockchip_pinctrl_probe,
+};
--
2.32.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v6 4/4] rockchip: rk3066: add sdram driver
  2021-07-13 18:58 [PATCH v6 0/4] Add basic support for rk3066 platform Paweł Jarosz
                   ` (2 preceding siblings ...)
  2021-07-13 18:58 ` [PATCH v6 3/4] rockchip: rk3066: add rk3066 pinctrl driver Paweł Jarosz
@ 2021-07-13 18:59 ` Paweł Jarosz
  3 siblings, 0 replies; 8+ messages in thread
From: Paweł Jarosz @ 2021-07-13 18:59 UTC (permalink / raw)
  To: kever.yang; +Cc: sjg, philipp.tomsich, lukma, u-boot

Add rockchip rk3066 sdram driver

Signed-off-by: Paweł Jarosz <paweljarosz3691@gmail.com>
Acked-by: Simon Glass <sjg@chromium.org>
Acked-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
---

Changes since v1:
- use common rockchip_sdram_size
- moved sdram init from sdram_init.c

Changes since v2:
- none

Changes since v3:
- none

Changes since v4:
- updated to current codebase
- fixed compilation errors

Changes since v5:
- fixed various style issues
- added arch-rockchip/hardware.h include
- used BIT macro
- used #if IS_ENABLED macro instead of #ifdef


 drivers/ram/rockchip/Makefile       |   1 +
 drivers/ram/rockchip/sdram_rk3066.c | 942 ++++++++++++++++++++++++++++
 2 files changed, 943 insertions(+)
 create mode 100644 drivers/ram/rockchip/sdram_rk3066.c

diff --git a/drivers/ram/rockchip/Makefile b/drivers/ram/rockchip/Makefile
index ca1c289b88..6d530c29af 100644
--- a/drivers/ram/rockchip/Makefile
+++ b/drivers/ram/rockchip/Makefile
@@ -5,6 +5,7 @@

 obj-$(CONFIG_ROCKCHIP_PX30) += sdram_px30.o sdram_pctl_px30.o sdram_phy_px30.o
 obj-$(CONFIG_ROCKCHIP_RK3368) = dmc-rk3368.o
+obj-$(CONFIG_ROCKCHIP_RK3066) = sdram_rk3066.o
 obj-$(CONFIG_ROCKCHIP_RK3128) = sdram_rk3128.o
 obj-$(CONFIG_ROCKCHIP_RK3188) = sdram_rk3188.o
 obj-$(CONFIG_ROCKCHIP_RK322X) = sdram_rk322x.o
diff --git a/drivers/ram/rockchip/sdram_rk3066.c b/drivers/ram/rockchip/sdram_rk3066.c
new file mode 100644
index 0000000000..0dd0a496aa
--- /dev/null
+++ b/drivers/ram/rockchip/sdram_rk3066.c
@@ -0,0 +1,942 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * (C) Copyright 2015 Google, Inc
+ * Copyright 2014 Rockchip Inc.
+ *
+ * Adapted from the very similar rk3188 ddr init.
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dt-structs.h>
+#include <errno.h>
+#include <hang.h>
+#include <init.h>
+#include <log.h>
+#include <ram.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_rk3066.h>
+#include <asm/arch-rockchip/ddr_rk3188.h>
+#include <asm/arch-rockchip/grf_rk3066.h>
+#include <asm/arch-rockchip/hardware.h>
+#include <asm/arch-rockchip/pmu_rk3188.h>
+#include <asm/arch-rockchip/sdram_rk3288.h>
+#include <asm/arch-rockchip/sdram.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+struct chan_info {
+	struct rk3288_ddr_pctl *pctl;
+	struct rk3288_ddr_publ *publ;
+	struct rk3188_msch *msch;
+};
+
+struct dram_info {
+	struct chan_info chan[1];
+	struct ram_info info;
+	struct clk ddr_clk;
+	struct rk3066_cru *cru;
+	struct rk3066_grf *grf;
+	struct rk3066_sgrf *sgrf;
+	struct rk3188_pmu *pmu;
+};
+
+struct rk3066_sdram_params {
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct dtd_rockchip_rk3066_dmc of_plat;
+#endif
+	struct rk3288_sdram_channel ch[2];
+	struct rk3288_sdram_pctl_timing pctl_timing;
+	struct rk3288_sdram_phy_timing phy_timing;
+	struct rk3288_base_params base;
+	int num_channels;
+	struct regmap *map;
+};
+
+const int ddrconf_table[] = {
+	/*
+	 * [5:4] row(13+n)
+	 * [1:0] col(9+n), assume bw=2
+	 * row	    col,bw
+	 */
+	0,
+	(2 << DDRCONF_ROW_SHIFT) | 1 << DDRCONF_COL_SHIFT,
+	(1 << DDRCONF_ROW_SHIFT) | 1 << DDRCONF_COL_SHIFT,
+	(0 << DDRCONF_ROW_SHIFT) | 1 << DDRCONF_COL_SHIFT,
+	(2 << DDRCONF_ROW_SHIFT) | 2 << DDRCONF_COL_SHIFT,
+	(1 << DDRCONF_ROW_SHIFT) | 2 << DDRCONF_COL_SHIFT,
+	(0 << DDRCONF_ROW_SHIFT) | 2 << DDRCONF_COL_SHIFT,
+	(1 << DDRCONF_ROW_SHIFT) | 0 << DDRCONF_COL_SHIFT,
+	(0 << DDRCONF_ROW_SHIFT) | 0 << DDRCONF_COL_SHIFT,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+};
+
+#define TEST_PATTEN	0x5aa5f00f
+#define DQS_GATE_TRAINING_ERROR_RANK0	BIT(4)
+#define DQS_GATE_TRAINING_ERROR_RANK1	BIT(5)
+
+#if IS_ENABLED(CONFIG_TPL_BUILD)
+static void copy_to_reg(u32 *dest, const u32 *src, u32 n)
+{
+	int i;
+
+	for (i = 0; i < n / sizeof(u32); i++) {
+		writel(*src, dest);
+		src++;
+		dest++;
+	}
+}
+
+static void ddr_reset(struct rk3066_cru *cru, u32 ch, u32 ctl, u32 phy)
+{
+	u32 phy_ctl_srstn_shift = 13;
+	u32 ctl_psrstn_shift = 11;
+	u32 ctl_srstn_shift = 10;
+	u32 phy_psrstn_shift = 9;
+	u32 phy_srstn_shift = 8;
+
+	rk_clrsetreg(&cru->cru_softrst_con[5],
+		     1 << phy_ctl_srstn_shift | 1 << ctl_psrstn_shift |
+		     1 << ctl_srstn_shift | 1 << phy_psrstn_shift |
+		     1 << phy_srstn_shift,
+		     phy << phy_ctl_srstn_shift | ctl << ctl_psrstn_shift |
+		     ctl << ctl_srstn_shift | phy << phy_psrstn_shift |
+		     phy << phy_srstn_shift);
+}
+
+static void ddr_phy_ctl_reset(struct rk3066_cru *cru, u32 ch, u32 n)
+{
+	u32 phy_ctl_srstn_shift = 13;
+
+	rk_clrsetreg(&cru->cru_softrst_con[5],
+		     1 << phy_ctl_srstn_shift, n << phy_ctl_srstn_shift);
+}
+
+static void phy_pctrl_reset(struct rk3066_cru *cru,
+			    struct rk3288_ddr_publ *publ,
+			    int channel)
+{
+	int i;
+
+	ddr_reset(cru, channel, 1, 1);
+	udelay(1);
+	clrbits_le32(&publ->acdllcr, ACDLLCR_DLLSRST);
+	for (i = 0; i < 4; i++)
+		clrbits_le32(&publ->datx8[i].dxdllcr, DXDLLCR_DLLSRST);
+
+	udelay(10);
+	setbits_le32(&publ->acdllcr, ACDLLCR_DLLSRST);
+	for (i = 0; i < 4; i++)
+		setbits_le32(&publ->datx8[i].dxdllcr, DXDLLCR_DLLSRST);
+
+	udelay(10);
+	ddr_reset(cru, channel, 1, 0);
+	udelay(10);
+	ddr_reset(cru, channel, 0, 0);
+	udelay(10);
+}
+
+static void phy_dll_bypass_set(struct rk3288_ddr_publ *publ,
+			       u32 freq)
+{
+	int i;
+
+	if (freq <= 250000000) {
+		if (freq <= 150000000)
+			clrbits_le32(&publ->dllgcr, SBIAS_BYPASS);
+		else
+			setbits_le32(&publ->dllgcr, SBIAS_BYPASS);
+		setbits_le32(&publ->acdllcr, ACDLLCR_DLLDIS);
+		for (i = 0; i < 4; i++)
+			setbits_le32(&publ->datx8[i].dxdllcr,
+				     DXDLLCR_DLLDIS);
+
+		setbits_le32(&publ->pir, PIR_DLLBYP);
+	} else {
+		clrbits_le32(&publ->dllgcr, SBIAS_BYPASS);
+		clrbits_le32(&publ->acdllcr, ACDLLCR_DLLDIS);
+		for (i = 0; i < 4; i++) {
+			clrbits_le32(&publ->datx8[i].dxdllcr,
+				     DXDLLCR_DLLDIS);
+		}
+
+		clrbits_le32(&publ->pir, PIR_DLLBYP);
+	}
+}
+
+static void dfi_cfg(struct rk3288_ddr_pctl *pctl, u32 dramtype)
+{
+	writel(DFI_INIT_START, &pctl->dfistcfg0);
+	writel(DFI_DRAM_CLK_SR_EN | DFI_DRAM_CLK_DPD_EN,
+	       &pctl->dfistcfg1);
+	writel(DFI_PARITY_INTR_EN | DFI_PARITY_EN, &pctl->dfistcfg2);
+	writel(7 << TLP_RESP_TIME_SHIFT | LP_SR_EN | LP_PD_EN,
+	       &pctl->dfilpcfg0);
+
+	writel(2 << TCTRL_DELAY_TIME_SHIFT, &pctl->dfitctrldelay);
+	writel(1 << TPHY_WRDATA_TIME_SHIFT, &pctl->dfitphywrdata);
+	writel(0xf << TPHY_RDLAT_TIME_SHIFT, &pctl->dfitphyrdlat);
+	writel(2 << TDRAM_CLK_DIS_TIME_SHIFT, &pctl->dfitdramclkdis);
+	writel(2 << TDRAM_CLK_EN_TIME_SHIFT, &pctl->dfitdramclken);
+	writel(1, &pctl->dfitphyupdtype0);
+
+	/* cs0 and cs1 write odt enable */
+	writel((RANK0_ODT_WRITE_SEL | RANK1_ODT_WRITE_SEL),
+	       &pctl->dfiodtcfg);
+	/* odt write length */
+	writel(7 << ODT_LEN_BL8_W_SHIFT, &pctl->dfiodtcfg1);
+	/* phyupd and ctrlupd disabled */
+	writel(0, &pctl->dfiupdcfg);
+}
+
+static void ddr_set_ddr3_mode(struct rk3066_grf *grf, uint channel,
+			      bool ddr3_mode)
+{
+	uint mask, val;
+
+	mask = MSCH4_MAINDDR3_MASK << MSCH4_MAINDDR3_SHIFT;
+	val = ddr3_mode << MSCH4_MAINDDR3_SHIFT;
+	rk_clrsetreg(&grf->soc_con2, mask, val);
+}
+
+static void ddr_rank_2_row15en(struct rk3066_grf *grf, bool enable)
+{
+	uint mask, val;
+
+	mask = RANK_TO_ROW15_EN_MASK << RANK_TO_ROW15_EN_SHIFT;
+	val = enable << RANK_TO_ROW15_EN_SHIFT;
+	rk_clrsetreg(&grf->soc_con2, mask, val);
+}
+
+static void pctl_cfg(int channel, struct rk3288_ddr_pctl *pctl,
+		     struct rk3066_sdram_params *sdram_params,
+		     struct rk3066_grf *grf)
+{
+	copy_to_reg(&pctl->togcnt1u, &sdram_params->pctl_timing.togcnt1u,
+		    sizeof(sdram_params->pctl_timing));
+	switch (sdram_params->base.dramtype) {
+	case DDR3:
+		if (sdram_params->phy_timing.mr[1] & DDR3_DLL_DISABLE) {
+			writel(sdram_params->pctl_timing.tcl - 3,
+			       &pctl->dfitrddataen);
+		} else {
+			writel(sdram_params->pctl_timing.tcl - 2,
+			       &pctl->dfitrddataen);
+		}
+		writel(sdram_params->pctl_timing.tcwl - 1,
+		       &pctl->dfitphywrlat);
+		writel(0 << MDDR_LPDDR2_CLK_STOP_IDLE_SHIFT | DDR3_EN |
+		       DDR2_DDR3_BL_8 | (6 - 4) << TFAW_SHIFT | PD_EXIT_SLOW |
+		       1 << PD_TYPE_SHIFT | 0 << PD_IDLE_SHIFT,
+		       &pctl->mcfg);
+		ddr_set_ddr3_mode(grf, channel, true);
+		break;
+	}
+
+	setbits_le32(&pctl->scfg, 1);
+}
+
+static void phy_cfg(const struct chan_info *chan, int channel,
+		    struct rk3066_sdram_params *sdram_params)
+{
+	struct rk3288_ddr_publ *publ = chan->publ;
+	struct rk3188_msch *msch = chan->msch;
+	uint ddr_freq_mhz = sdram_params->base.ddr_freq / 1000000;
+	u32 dinit2;
+	int i;
+
+	dinit2 = DIV_ROUND_UP(ddr_freq_mhz * 200000, 1000);
+	/* DDR PHY Timing */
+	copy_to_reg(&publ->dtpr[0], &sdram_params->phy_timing.dtpr0,
+		    sizeof(sdram_params->phy_timing));
+	writel(sdram_params->base.noc_timing, &msch->ddrtiming);
+	writel(0x3f, &msch->readlatency);
+	writel(DIV_ROUND_UP(ddr_freq_mhz * 5120, 1000) << PRT_DLLLOCK_SHIFT |
+	       DIV_ROUND_UP(ddr_freq_mhz * 50, 1000) << PRT_DLLSRST_SHIFT |
+	       8 << PRT_ITMSRST_SHIFT, &publ->ptr[0]);
+	writel(DIV_ROUND_UP(ddr_freq_mhz * 500000, 1000) << PRT_DINIT0_SHIFT |
+	       DIV_ROUND_UP(ddr_freq_mhz * 400, 1000) << PRT_DINIT1_SHIFT,
+	       &publ->ptr[1]);
+	writel(min(dinit2, 0x1ffffU) << PRT_DINIT2_SHIFT |
+	       DIV_ROUND_UP(ddr_freq_mhz * 1000, 1000) << PRT_DINIT3_SHIFT,
+	       &publ->ptr[2]);
+
+	switch (sdram_params->base.dramtype) {
+	case DDR3:
+		clrbits_le32(&publ->pgcr, 0x1f);
+		clrsetbits_le32(&publ->dcr, DDRMD_MASK << DDRMD_SHIFT,
+				DDRMD_DDR3 << DDRMD_SHIFT);
+		break;
+	}
+	if (sdram_params->base.odt) {
+		/*dynamic RTT enable */
+		for (i = 0; i < 4; i++)
+			setbits_le32(&publ->datx8[i].dxgcr, DQSRTT | DQRTT);
+	} else {
+		/*dynamic RTT disable */
+		for (i = 0; i < 4; i++)
+			clrbits_le32(&publ->datx8[i].dxgcr, DQSRTT | DQRTT);
+	}
+}
+
+static void phy_init(struct rk3288_ddr_publ *publ)
+{
+	setbits_le32(&publ->pir, PIR_INIT | PIR_DLLSRST
+		     | PIR_DLLLOCK | PIR_ZCAL | PIR_ITMSRST | PIR_CLRSR);
+	udelay(1);
+	while ((readl(&publ->pgsr) &
+		(PGSR_IDONE | PGSR_DLDONE | PGSR_ZCDONE)) !=
+	       (PGSR_IDONE | PGSR_DLDONE | PGSR_ZCDONE))
+		;
+}
+
+static void send_command(struct rk3288_ddr_pctl *pctl, u32 rank,
+			 u32 cmd, u32 arg)
+{
+	writel((START_CMD | (rank << 20) | arg | cmd), &pctl->mcmd);
+	udelay(1);
+	while (readl(&pctl->mcmd) & START_CMD)
+		;
+}
+
+static inline void send_command_op(struct rk3288_ddr_pctl *pctl,
+				   u32 rank, u32 cmd, u32 ma, u32 op)
+{
+	send_command(pctl, rank, cmd, (ma & LPDDR2_MA_MASK) << LPDDR2_MA_SHIFT |
+		     (op & LPDDR2_OP_MASK) << LPDDR2_OP_SHIFT);
+}
+
+static void memory_init(struct rk3288_ddr_publ *publ,
+			u32 dramtype)
+{
+	setbits_le32(&publ->pir,
+		     (PIR_INIT | PIR_DRAMINIT | PIR_LOCKBYP
+		      | PIR_ZCALBYP | PIR_CLRSR | PIR_ICPC
+		      | (dramtype == DDR3 ? PIR_DRAMRST : 0)));
+	udelay(1);
+	while ((readl(&publ->pgsr) & (PGSR_IDONE | PGSR_DLDONE))
+	       != (PGSR_IDONE | PGSR_DLDONE))
+		;
+}
+
+static void move_to_config_state(struct rk3288_ddr_publ *publ,
+				 struct rk3288_ddr_pctl *pctl)
+{
+	unsigned int state;
+
+	while (1) {
+		state = readl(&pctl->stat) & PCTL_STAT_MSK;
+
+		switch (state) {
+		case LOW_POWER:
+			writel(WAKEUP_STATE, &pctl->sctl);
+			while ((readl(&pctl->stat) & PCTL_STAT_MSK)
+			       != ACCESS)
+				;
+			/* wait DLL lock */
+			while ((readl(&publ->pgsr) & PGSR_DLDONE)
+			       != PGSR_DLDONE)
+				;
+		/*
+		 * if at low power state,need wakeup first,
+		 * and then enter the config, so
+		 * fallthrough
+		 */
+		case ACCESS:
+		/* fallthrough */
+		case INIT_MEM:
+			writel(CFG_STATE, &pctl->sctl);
+			while ((readl(&pctl->stat) & PCTL_STAT_MSK) != CONFIG)
+				;
+			break;
+		case CONFIG:
+			return;
+		default:
+			break;
+		}
+	}
+}
+
+static void set_bandwidth_ratio(const struct chan_info *chan, int channel,
+				u32 n, struct rk3066_grf *grf)
+{
+	struct rk3288_ddr_pctl *pctl = chan->pctl;
+	struct rk3288_ddr_publ *publ = chan->publ;
+	struct rk3188_msch *msch = chan->msch;
+
+	if (n == 1) {
+		setbits_le32(&pctl->ppcfg, 1);
+		setbits_le32(&msch->ddrtiming, 1 << 31);
+		/* Data Byte disable*/
+		clrbits_le32(&publ->datx8[2].dxgcr, 1);
+		clrbits_le32(&publ->datx8[3].dxgcr, 1);
+		/* disable DLL */
+		setbits_le32(&publ->datx8[2].dxdllcr, DXDLLCR_DLLDIS);
+		setbits_le32(&publ->datx8[3].dxdllcr, DXDLLCR_DLLDIS);
+	} else {
+		clrbits_le32(&pctl->ppcfg, 1);
+		clrbits_le32(&msch->ddrtiming, 1 << 31);
+		/* Data Byte enable*/
+		setbits_le32(&publ->datx8[2].dxgcr, 1);
+		setbits_le32(&publ->datx8[3].dxgcr, 1);
+
+		/* enable DLL */
+		clrbits_le32(&publ->datx8[2].dxdllcr, DXDLLCR_DLLDIS);
+		clrbits_le32(&publ->datx8[3].dxdllcr, DXDLLCR_DLLDIS);
+		/* reset DLL */
+		clrbits_le32(&publ->datx8[2].dxdllcr, DXDLLCR_DLLSRST);
+		clrbits_le32(&publ->datx8[3].dxdllcr, DXDLLCR_DLLSRST);
+		udelay(10);
+		setbits_le32(&publ->datx8[2].dxdllcr, DXDLLCR_DLLSRST);
+		setbits_le32(&publ->datx8[3].dxdllcr, DXDLLCR_DLLSRST);
+	}
+	setbits_le32(&pctl->dfistcfg0, 1 << 2);
+}
+
+static int data_training(const struct chan_info *chan, int channel,
+			 struct rk3066_sdram_params *sdram_params)
+{
+	unsigned int j;
+	int ret = 0;
+	u32 rank;
+	int i;
+	u32 step[2] = { PIR_QSTRN, PIR_RVTRN };
+	struct rk3288_ddr_publ *publ = chan->publ;
+	struct rk3288_ddr_pctl *pctl = chan->pctl;
+
+	/* disable auto refresh */
+	writel(0, &pctl->trefi);
+
+	if (sdram_params->base.dramtype != LPDDR3)
+		setbits_le32(&publ->pgcr, 1 << PGCR_DQSCFG_SHIFT);
+	rank = sdram_params->ch[channel].rank | 1;
+	for (j = 0; j < ARRAY_SIZE(step); j++) {
+		/*
+		 * trigger QSTRN and RVTRN
+		 * clear DTDONE status
+		 */
+		setbits_le32(&publ->pir, PIR_CLRSR);
+
+		/* trigger DTT */
+		setbits_le32(&publ->pir,
+			     PIR_INIT | step[j] | PIR_LOCKBYP | PIR_ZCALBYP |
+			     PIR_CLRSR);
+		udelay(1);
+		/* wait echo byte DTDONE */
+		while ((readl(&publ->datx8[0].dxgsr[0]) & rank)
+		       != rank)
+			;
+		while ((readl(&publ->datx8[1].dxgsr[0]) & rank)
+		       != rank)
+			;
+		if (!(readl(&pctl->ppcfg) & 1)) {
+			while ((readl(&publ->datx8[2].dxgsr[0])
+				& rank) != rank)
+				;
+			while ((readl(&publ->datx8[3].dxgsr[0])
+				& rank) != rank)
+				;
+		}
+		if (readl(&publ->pgsr) &
+		    (PGSR_DTERR | PGSR_RVERR | PGSR_RVEIRR)) {
+			ret = -1;
+			break;
+		}
+	}
+	/* send some auto refresh to complement the lost while DTT */
+	for (i = 0; i < (rank > 1 ? 8 : 4); i++)
+		send_command(pctl, rank, REF_CMD, 0);
+
+	if (sdram_params->base.dramtype != LPDDR3)
+		clrbits_le32(&publ->pgcr, 1 << PGCR_DQSCFG_SHIFT);
+
+	/* resume auto refresh */
+	writel(sdram_params->pctl_timing.trefi, &pctl->trefi);
+
+	return ret;
+}
+
+static void move_to_access_state(const struct chan_info *chan)
+{
+	struct rk3288_ddr_publ *publ = chan->publ;
+	struct rk3288_ddr_pctl *pctl = chan->pctl;
+	unsigned int state;
+
+	while (1) {
+		state = readl(&pctl->stat) & PCTL_STAT_MSK;
+
+		switch (state) {
+		case LOW_POWER:
+			if (((readl(&pctl->stat) >> LP_TRIG_SHIFT) &
+			     LP_TRIG_MASK) == 1)
+				return;
+
+			writel(WAKEUP_STATE, &pctl->sctl);
+			while ((readl(&pctl->stat) & PCTL_STAT_MSK) != ACCESS)
+				;
+			/* wait DLL lock */
+			while ((readl(&publ->pgsr) & PGSR_DLDONE)
+			       != PGSR_DLDONE)
+				;
+			break;
+		case INIT_MEM:
+			writel(CFG_STATE, &pctl->sctl);
+			while ((readl(&pctl->stat) & PCTL_STAT_MSK) != CONFIG)
+				;
+		/* fallthrough */
+		case CONFIG:
+			writel(GO_STATE, &pctl->sctl);
+			while ((readl(&pctl->stat) & PCTL_STAT_MSK) == CONFIG)
+				;
+			break;
+		case ACCESS:
+			return;
+		default:
+			break;
+		}
+	}
+}
+
+static void dram_cfg_rbc(const struct chan_info *chan, u32 chnum,
+			 struct rk3066_sdram_params *sdram_params)
+{
+	struct rk3288_ddr_publ *publ = chan->publ;
+
+	if (sdram_params->ch[chnum].bk == 3)
+		clrsetbits_le32(&publ->dcr, PDQ_MASK << PDQ_SHIFT,
+				1 << PDQ_SHIFT);
+	else
+		clrbits_le32(&publ->dcr, PDQ_MASK << PDQ_SHIFT);
+
+	writel(sdram_params->base.ddrconfig, &chan->msch->ddrconf);
+}
+
+static void dram_all_config(const struct dram_info *dram,
+			    struct rk3066_sdram_params *sdram_params)
+{
+	unsigned int chan;
+	u32 sys_reg = 0;
+
+	sys_reg |= sdram_params->base.dramtype << SYS_REG_DDRTYPE_SHIFT;
+	sys_reg |= (sdram_params->num_channels - 1) << SYS_REG_NUM_CH_SHIFT;
+	for (chan = 0; chan < sdram_params->num_channels; chan++) {
+		const struct rk3288_sdram_channel *info =
+				&sdram_params->ch[chan];
+
+		sys_reg |= info->row_3_4 << SYS_REG_ROW_3_4_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 ? 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 |= (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);
+	}
+	if (sdram_params->ch[0].rank == 2)
+		ddr_rank_2_row15en(dram->grf, 0);
+	else
+		ddr_rank_2_row15en(dram->grf, 1);
+
+	writel(sys_reg, &dram->pmu->sys_reg[2]);
+}
+
+static int sdram_rank_bw_detect(struct dram_info *dram, int channel,
+				struct rk3066_sdram_params *sdram_params)
+{
+	int reg;
+	int need_trainig = 0;
+	const struct chan_info *chan = &dram->chan[channel];
+	struct rk3288_ddr_publ *publ = chan->publ;
+
+	ddr_rank_2_row15en(dram->grf, 0);
+
+	if (data_training(chan, channel, sdram_params) < 0) {
+		debug("first data training fail!\n");
+		reg = readl(&publ->datx8[0].dxgsr[0]);
+		/* Check the result for rank 0 */
+		if (channel == 0 && (reg & DQS_GATE_TRAINING_ERROR_RANK0)) {
+			debug("data training fail!\n");
+			return -EIO;
+		}
+
+		/* Check the result for rank 1 */
+		if (reg & DQS_GATE_TRAINING_ERROR_RANK1) {
+			sdram_params->ch[channel].rank = 1;
+			clrsetbits_le32(&publ->pgcr, 0xF << 18,
+					sdram_params->ch[channel].rank << 18);
+			need_trainig = 1;
+		}
+		reg = readl(&publ->datx8[2].dxgsr[0]);
+		if (reg & (1 << 4)) {
+			sdram_params->ch[channel].bw = 1;
+			set_bandwidth_ratio(chan, channel,
+					    sdram_params->ch[channel].bw,
+					    dram->grf);
+			need_trainig = 1;
+		}
+	}
+	/* Assume the Die bit width are the same with the chip bit width */
+	sdram_params->ch[channel].dbw = sdram_params->ch[channel].bw;
+
+	if (need_trainig &&
+	    (data_training(chan, channel, sdram_params) < 0)) {
+		if (sdram_params->base.dramtype == LPDDR3) {
+			ddr_phy_ctl_reset(dram->cru, channel, 1);
+			udelay(10);
+			ddr_phy_ctl_reset(dram->cru, channel, 0);
+			udelay(10);
+		}
+		debug("2nd data training failed!");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/*
+ * Detect ram columns and rows.
+ * @dram: dram info struct
+ * @channel: channel number to handle
+ * @sdram_params: sdram parameters, function will fill in col and row values
+ *
+ * Returns 0 or negative on error.
+ */
+static int sdram_col_row_detect(struct dram_info *dram, int channel,
+				struct rk3066_sdram_params *sdram_params)
+{
+	int row, col;
+	unsigned int addr;
+	const struct chan_info *chan = &dram->chan[channel];
+	struct rk3288_ddr_pctl *pctl = chan->pctl;
+	struct rk3288_ddr_publ *publ = chan->publ;
+	int ret = 0;
+
+	/* Detect col */
+	for (col = 11; col >= 9; col--) {
+		writel(0, CONFIG_SYS_SDRAM_BASE);
+		addr = CONFIG_SYS_SDRAM_BASE +
+		       (1 << (col + sdram_params->ch[channel].bw - 1));
+		writel(TEST_PATTEN, addr);
+		if ((readl(addr) == TEST_PATTEN) &&
+		    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
+			break;
+	}
+	if (col == 8) {
+		debug("Col detect error\n");
+		ret = -EINVAL;
+		goto out;
+	} else {
+		sdram_params->ch[channel].col = col;
+	}
+
+	ddr_rank_2_row15en(dram->grf, 1);
+	move_to_config_state(publ, pctl);
+	writel(1, &chan->msch->ddrconf);
+	move_to_access_state(chan);
+	/* Detect row, max 15,min13 in rk3066*/
+	for (row = 16; row >= 13; row--) {
+		writel(0, CONFIG_SYS_SDRAM_BASE);
+		addr = CONFIG_SYS_SDRAM_BASE + (1 << (row + 15 - 1));
+		writel(TEST_PATTEN, addr);
+		if ((readl(addr) == TEST_PATTEN) &&
+		    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
+			break;
+	}
+	if (row == 12) {
+		debug("Row detect error\n");
+		ret = -EINVAL;
+	} else {
+		sdram_params->ch[channel].cs1_row = row;
+		sdram_params->ch[channel].row_3_4 = 0;
+		debug("chn %d col %d, row %d\n", channel, col, row);
+		sdram_params->ch[channel].cs0_row = row;
+	}
+
+out:
+	return ret;
+}
+
+static int sdram_get_niu_config(struct rk3066_sdram_params *sdram_params)
+{
+	int i, tmp, size, ret = 0;
+
+	tmp = sdram_params->ch[0].col - 9;
+	tmp -= (sdram_params->ch[0].bw == 2) ? 0 : 1;
+	tmp |= ((sdram_params->ch[0].cs0_row - 13) << 4);
+	size = ARRAY_SIZE(ddrconf_table) / sizeof(ddrconf_table[0]);
+	for (i = 0; i < size; i++)
+		if (tmp == ddrconf_table[i])
+			break;
+	if (i >= size) {
+		debug("niu config not found\n");
+		ret = -EINVAL;
+	} else {
+		debug("niu config %d\n", i);
+		sdram_params->base.ddrconfig = i;
+	}
+
+	return ret;
+}
+
+static int sdram_init(struct dram_info *dram,
+		      struct rk3066_sdram_params *sdram_params)
+{
+	int channel;
+	int zqcr;
+	int ret;
+
+	if ((sdram_params->base.dramtype == DDR3 &&
+	     sdram_params->base.ddr_freq > 800000000)) {
+		debug("SDRAM frequency is too high!");
+		return -E2BIG;
+	}
+
+	ret = clk_set_rate(&dram->ddr_clk, sdram_params->base.ddr_freq);
+	if (ret) {
+		debug("Could not set DDR clock\n");
+		return ret;
+	}
+
+	for (channel = 0; channel < 1; channel++) {
+		const struct chan_info *chan = &dram->chan[channel];
+		struct rk3288_ddr_pctl *pctl = chan->pctl;
+		struct rk3288_ddr_publ *publ = chan->publ;
+
+		phy_pctrl_reset(dram->cru, publ, channel);
+		phy_dll_bypass_set(publ, sdram_params->base.ddr_freq);
+
+		dfi_cfg(pctl, sdram_params->base.dramtype);
+
+		pctl_cfg(channel, pctl, sdram_params, dram->grf);
+
+		phy_cfg(chan, channel, sdram_params);
+
+		phy_init(publ);
+
+		writel(POWER_UP_START, &pctl->powctl);
+		while (!(readl(&pctl->powstat) & POWER_UP_DONE))
+			;
+
+		memory_init(publ, sdram_params->base.dramtype);
+		move_to_config_state(publ, pctl);
+
+		/* Using 32bit bus width for detect */
+		sdram_params->ch[channel].bw = 2;
+		set_bandwidth_ratio(chan, channel,
+				    sdram_params->ch[channel].bw, dram->grf);
+		/*
+		 * set cs, using n=3 for detect
+		 * CS0, n=1
+		 * CS1, n=2
+		 * CS0 & CS1, n = 3
+		 */
+		sdram_params->ch[channel].rank = 2;
+		clrsetbits_le32(&publ->pgcr, 0xF << 18,
+				(sdram_params->ch[channel].rank | 1) << 18);
+
+		/* DS=40ohm,ODT=155ohm */
+		zqcr = 1 << ZDEN_SHIFT | 2 << PU_ONDIE_SHIFT |
+		       2 << PD_ONDIE_SHIFT | 0x19 << PU_OUTPUT_SHIFT |
+		       0x19 << PD_OUTPUT_SHIFT;
+		writel(zqcr, &publ->zq1cr[0]);
+		writel(zqcr, &publ->zq0cr[0]);
+
+		/* Detect the rank and bit-width with data-training */
+		writel(1, &chan->msch->ddrconf);
+		sdram_rank_bw_detect(dram, channel, sdram_params);
+
+		if (sdram_params->base.dramtype == LPDDR3) {
+			u32 i;
+			writel(0, &pctl->mrrcfg0);
+
+			for (i = 0; i < 17; i++)
+				send_command_op(pctl, 1, MRR_CMD, i, 0);
+		}
+		writel(4, &chan->msch->ddrconf);
+		move_to_access_state(chan);
+		/* DDR3 and LPDDR3 are always 8 bank, no need detect */
+		sdram_params->ch[channel].bk = 3;
+		/* Detect Col and Row number*/
+		ret = sdram_col_row_detect(dram, channel, sdram_params);
+		if (ret)
+			goto error;
+	}
+	/* Find NIU DDR configuration */
+	ret = sdram_get_niu_config(sdram_params);
+	if (ret)
+		goto error;
+
+	dram_all_config(dram, sdram_params);
+	debug("%s done\n", __func__);
+
+	return 0;
+error:
+	debug("DRAM init failed!\n");
+	hang();
+}
+
+static int setup_sdram(struct udevice *dev)
+{
+	struct dram_info *priv = dev_get_priv(dev);
+	struct rk3066_sdram_params *params = dev_get_plat(dev);
+
+	return sdram_init(priv, params);
+}
+
+static int rk3066_dmc_ofdata_to_platdata(struct udevice *dev)
+{
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct rk3066_sdram_params *params = dev_get_plat(dev);
+	int ret;
+
+	/* rk3066 supports only one-channel */
+	params->num_channels = 1;
+	ret = dev_read_u32_array(dev, "rockchip,pctl-timing",
+				 (u32 *)&params->pctl_timing,
+				 sizeof(params->pctl_timing) / sizeof(u32));
+	if (ret) {
+		debug("%s: Cannot read rockchip,pctl-timing\n", __func__);
+		return -EINVAL;
+	}
+	ret = dev_read_u32_array(dev, "rockchip,phy-timing",
+				 (u32 *)&params->phy_timing,
+				 sizeof(params->phy_timing) / sizeof(u32));
+	if (ret) {
+		debug("%s: Cannot read rockchip,phy-timing\n", __func__);
+		return -EINVAL;
+	}
+	ret = dev_read_u32_array(dev, "rockchip,sdram-params",
+				 (u32 *)&params->base,
+				 sizeof(params->base) / sizeof(u32));
+	if (ret) {
+		debug("%s: Cannot read rockchip,sdram-params\n", __func__);
+		return -EINVAL;
+	}
+	ret = regmap_init_mem(dev_ofnode(dev), &params->map);
+	if (ret)
+		return ret;
+#endif
+
+	return 0;
+}
+#endif /* CONFIG_TPL_BUILD */
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+static int conv_of_plat(struct udevice *dev)
+{
+	struct rk3066_sdram_params *plat = dev_get_plat(dev);
+	struct dtd_rockchip_rk3066_dmc *of_plat = &plat->of_plat;
+	int ret;
+
+	memcpy(&plat->pctl_timing, of_plat->rockchip_pctl_timing,
+	       sizeof(plat->pctl_timing));
+	memcpy(&plat->phy_timing, of_plat->rockchip_phy_timing,
+	       sizeof(plat->phy_timing));
+	memcpy(&plat->base, of_plat->rockchip_sdram_params, sizeof(plat->base));
+	/* rk3066 supports dual-channel, set default channel num to 2 */
+	plat->num_channels = 1;
+	ret = regmap_init_mem_plat(dev, of_plat->reg,
+				   ARRAY_SIZE(of_plat->reg) / 2, &plat->map);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+#endif
+
+static int rk3066_dmc_probe(struct udevice *dev)
+{
+#if IS_ENABLED(CONFIG_TPL_BUILD)
+	struct rk3066_sdram_params *plat = dev_get_plat(dev);
+	struct regmap *map;
+	struct udevice *dev_clk;
+	int ret;
+#endif
+	struct dram_info *priv = dev_get_priv(dev);
+
+	priv->pmu = syscon_get_first_range(ROCKCHIP_SYSCON_PMU);
+
+#if IS_ENABLED(CONFIG_TPL_BUILD)
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	ret = conv_of_plat(dev);
+	if (ret)
+		return ret;
+#endif
+	map = syscon_get_regmap_by_driver_data(ROCKCHIP_SYSCON_NOC);
+	if (IS_ERR(map))
+		return PTR_ERR(map);
+	priv->chan[0].msch = regmap_get_range(map, 0);
+	priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+
+	priv->chan[0].pctl = regmap_get_range(plat->map, 0);
+	priv->chan[0].publ = regmap_get_range(plat->map, 1);
+
+	ret = rockchip_get_clk(&dev_clk);
+	if (ret)
+		return ret;
+
+	priv->ddr_clk.id = CLK_DDR;
+	ret = clk_request(dev_clk, &priv->ddr_clk);
+	if (ret)
+		return ret;
+
+	priv->cru = rockchip_get_cru();
+	if (IS_ERR(priv->cru))
+		return PTR_ERR(priv->cru);
+	ret = setup_sdram(dev);
+	if (ret)
+		return ret;
+#else
+	priv->info.base = CONFIG_SYS_SDRAM_BASE;
+	priv->info.size =
+			rockchip_sdram_size((phys_addr_t)&priv->pmu->sys_reg[2]);
+#endif
+
+	return 0;
+}
+
+static int rk3066_dmc_get_info(struct udevice *dev, struct ram_info *info)
+{
+	struct dram_info *priv = dev_get_priv(dev);
+
+	*info = priv->info;
+
+	return 0;
+}
+
+static struct ram_ops rk3066_dmc_ops = {
+	.get_info = rk3066_dmc_get_info,
+};
+
+static const struct udevice_id rk3066_dmc_ids[] = {
+	{ .compatible = "rockchip,rk3066-dmc" },
+	{ }
+};
+
+U_BOOT_DRIVER(rockchip_rk3066_dmc) = {
+	.name = "rockchip_rk3066_dmc",
+	.id = UCLASS_RAM,
+	.of_match = rk3066_dmc_ids,
+	.ops = &rk3066_dmc_ops,
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	.of_to_plat = rk3066_dmc_ofdata_to_platdata,
+#endif
+	.probe = rk3066_dmc_probe,
+	.priv_auto	= sizeof(struct dram_info),
+#if IS_ENABLED(CONFIG_TPL_BUILD)
+	.plat_auto	= sizeof(struct rk3066_sdram_params),
+#endif
+};
--
2.32.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v6 2/4] rockchip: rk3066: add clock driver for rk3066 soc
  2021-07-13 18:58 ` [PATCH v6 2/4] rockchip: rk3066: add clock driver for rk3066 soc Paweł Jarosz
@ 2021-07-13 20:17   ` Simon Glass
  2021-07-25 14:15     ` Paweł Jarosz
  0 siblings, 1 reply; 8+ messages in thread
From: Simon Glass @ 2021-07-13 20:17 UTC (permalink / raw)
  To: Paweł Jarosz
  Cc: Kever Yang, Philipp Tomsich, Lukasz Majewski, U-Boot Mailing List

Hi Paweł,

On Tue, 13 Jul 2021 at 12:59, Paweł Jarosz <paweljarosz3691@gmail.com> wrote:
>
> Add clock driver for rk3066 platform.
>
> Signed-off-by: Paweł Jarosz <paweljarosz3691@gmail.com>
> Acked-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
> ---
>
> Changes since v1:
> - updated to shifted masks
> - moved clk init to tpl
>
> Changes since v2:
> - none
>
> Changes since v3:
> - none
>
> Changes since v4:
> - updated to current codebase
> - fixed compilation errors
>
> Changes since v5:
> - various style changes
> - added clk_enable/clk_disable support for nand and mmc clocks
> - updated maintainer email
> - renamed uint32_t to u32
> - used #if IS_ENABLED macro instead #ifdef
>
>
>
>  .../include/asm/arch-rockchip/cru_rk3066.h    | 203 +++++
>  drivers/clk/rockchip/Makefile                 |   1 +
>  drivers/clk/rockchip/clk_rk3066.c             | 704 ++++++++++++++++++
>  3 files changed, 908 insertions(+)
>  create mode 100644 arch/arm/include/asm/arch-rockchip/cru_rk3066.h
>  create mode 100644 drivers/clk/rockchip/clk_rk3066.c
>
[..]

> +
> +static int rk3066_clk_of_to_plat(struct udevice *dev)
> +{
> +#if !CONFIG_IS_ENABLED(OF_PLATDATA)
> +       struct rk3066_clk_priv *priv = dev_get_priv(dev);
> +
> +       priv->cru = dev_read_addr_ptr(dev);
> +#endif
> +
> +       return 0;
> +}
> +
> +static int rk3066_clk_probe(struct udevice *dev)
> +{
> +       struct rk3066_clk_priv *priv = dev_get_priv(dev);
> +
> +       priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
> +       if (IS_ERR(priv->grf))
> +               return PTR_ERR(priv->grf);
> +
> +#if IS_ENABLED(CONFIG_TPL_BUILD)

Do you need that? The line below should take care of it.

> +#if CONFIG_IS_ENABLED(OF_PLATDATA)
> +       struct rk3066_clk_plat *plat = dev_get_plat(dev);
> +
> +       priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]);
> +#endif
> +
> +       rkclk_init(priv->cru, priv->grf);
> +
> +       /* Init CPU frequency */
> +       rkclk_configure_cpu(priv->cru, priv->grf, APLL_SAFE_HZ);
> +#endif
> +
> +       return 0;
> +}
> +
> +static int rk3066_clk_bind(struct udevice *dev)
> +{
> +       int ret;
> +       struct udevice *sys_child;
> +       struct sysreset_reg *priv;
> +
> +       /* The reset driver does not have a device node, so bind it here */
> +       ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
> +                                &sys_child);
> +       if (ret) {
> +               debug("Warning: No sysreset driver: ret=%d\n", ret);
> +       } else {
> +               priv = malloc(sizeof(struct sysreset_reg));
> +               priv->glb_srst_fst_value = offsetof(struct rk3066_cru,
> +                                                   cru_glb_srst_fst_value);
> +               priv->glb_srst_snd_value = offsetof(struct rk3066_cru,
> +                                                   cru_glb_srst_snd_value);
> +               dev_set_priv(sys_child, priv);
> +       }
> +
> +#if CONFIG_IS_ENABLED(RESET_ROCKCHIP)

Can you use if() instead of #if ?

> +       ret = offsetof(struct rk3066_cru, cru_softrst_con[0]);
> +       ret = rockchip_reset_bind(dev, ret, 9);
> +       if (ret)
> +               debug("Warning: software reset driver bind failed\n");
> +#endif
> +
> +       return 0;
> +}
> +
> +static const struct udevice_id rk3066_clk_ids[] = {
> +       { .compatible = "rockchip,rk3066a-cru" },
> +       { }
> +};
> +
> +U_BOOT_DRIVER(rockchip_rk3066a_cru) = {
> +       .name                   = "rockchip_rk3066a_cru",
> +       .id                     = UCLASS_CLK,
> +       .of_match               = rk3066_clk_ids,
> +       .priv_auto              = sizeof(struct rk3066_clk_priv),
> +       .plat_auto              = sizeof(struct rk3066_clk_plat),
> +       .ops                    = &rk3066_clk_ops,
> +       .bind                   = rk3066_clk_bind,
> +       .of_to_plat             = rk3066_clk_of_to_plat,
> +       .probe                  = rk3066_clk_probe,
> +};
> --
> 2.32.0
>

Regards,
Simon

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v6 2/4] rockchip: rk3066: add clock driver for rk3066 soc
  2021-07-13 20:17   ` Simon Glass
@ 2021-07-25 14:15     ` Paweł Jarosz
  2021-07-26 14:06       ` Simon Glass
  0 siblings, 1 reply; 8+ messages in thread
From: Paweł Jarosz @ 2021-07-25 14:15 UTC (permalink / raw)
  To: Simon Glass
  Cc: Kever Yang, Philipp Tomsich, Lukasz Majewski, U-Boot Mailing List

Hi Simon,


sorry for late response i was offline a bit

W dniu 13.07.2021 o 22:17, Simon Glass pisze:
> Hi Paweł,
>
> On Tue, 13 Jul 2021 at 12:59, Paweł Jarosz <paweljarosz3691@gmail.com> wrote:
>> Add clock driver for rk3066 platform.
>>
>> Signed-off-by: Paweł Jarosz <paweljarosz3691@gmail.com>
>> Acked-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
>> ---
>>
>> Changes since v1:
>> - updated to shifted masks
>> - moved clk init to tpl
>>
>> Changes since v2:
>> - none
>>
>> Changes since v3:
>> - none
>>
>> Changes since v4:
>> - updated to current codebase
>> - fixed compilation errors
>>
>> Changes since v5:
>> - various style changes
>> - added clk_enable/clk_disable support for nand and mmc clocks
>> - updated maintainer email
>> - renamed uint32_t to u32
>> - used #if IS_ENABLED macro instead #ifdef
>>
>>
>>
>>  .../include/asm/arch-rockchip/cru_rk3066.h    | 203 +++++
>>  drivers/clk/rockchip/Makefile                 |   1 +
>>  drivers/clk/rockchip/clk_rk3066.c             | 704 ++++++++++++++++++
>>  3 files changed, 908 insertions(+)
>>  create mode 100644 arch/arm/include/asm/arch-rockchip/cru_rk3066.h
>>  create mode 100644 drivers/clk/rockchip/clk_rk3066.c
>>
> [..]
>
>> +
>> +static int rk3066_clk_of_to_plat(struct udevice *dev)
>> +{
>> +#if !CONFIG_IS_ENABLED(OF_PLATDATA)
>> +       struct rk3066_clk_priv *priv = dev_get_priv(dev);
>> +
>> +       priv->cru = dev_read_addr_ptr(dev);
>> +#endif
>> +
>> +       return 0;
>> +}
>> +
>> +static int rk3066_clk_probe(struct udevice *dev)
>> +{
>> +       struct rk3066_clk_priv *priv = dev_get_priv(dev);
>> +
>> +       priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
>> +       if (IS_ERR(priv->grf))
>> +               return PTR_ERR(priv->grf);
>> +
>> +#if IS_ENABLED(CONFIG_TPL_BUILD)
> Do you need that? The line below should take care of it.


Yep. Later rkclk_init and rkclk_configure_cpu should be only executed in TPL.


>> +#if CONFIG_IS_ENABLED(OF_PLATDATA)
>> +       struct rk3066_clk_plat *plat = dev_get_plat(dev);
>> +
>> +       priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]);
>> +#endif
>> +
>> +       rkclk_init(priv->cru, priv->grf);
>> +
>> +       /* Init CPU frequency */
>> +       rkclk_configure_cpu(priv->cru, priv->grf, APLL_SAFE_HZ);
>> +#endif
>> +
>> +       return 0;
>> +}
>> +
>> +static int rk3066_clk_bind(struct udevice *dev)
>> +{
>> +       int ret;
>> +       struct udevice *sys_child;
>> +       struct sysreset_reg *priv;
>> +
>> +       /* The reset driver does not have a device node, so bind it here */
>> +       ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
>> +                                &sys_child);
>> +       if (ret) {
>> +               debug("Warning: No sysreset driver: ret=%d\n", ret);
>> +       } else {
>> +               priv = malloc(sizeof(struct sysreset_reg));
>> +               priv->glb_srst_fst_value = offsetof(struct rk3066_cru,
>> +                                                   cru_glb_srst_fst_value);
>> +               priv->glb_srst_snd_value = offsetof(struct rk3066_cru,
>> +                                                   cru_glb_srst_snd_value);
>> +               dev_set_priv(sys_child, priv);
>> +       }
>> +
>> +#if CONFIG_IS_ENABLED(RESET_ROCKCHIP)
> Can you use if() instead of #if ?


Yes, but what is the difference? Sorry ... I don't know what to ask google to get the answer.

Is it in this case doing the same thing and just looking better?



Regards,

Paweł Jarosz


>> +       ret = offsetof(struct rk3066_cru, cru_softrst_con[0]);
>> +       ret = rockchip_reset_bind(dev, ret, 9);
>> +       if (ret)
>> +               debug("Warning: software reset driver bind failed\n");
>> +#endif
>> +
>> +       return 0;
>> +}
>> +
>> +static const struct udevice_id rk3066_clk_ids[] = {
>> +       { .compatible = "rockchip,rk3066a-cru" },
>> +       { }
>> +};
>> +
>> +U_BOOT_DRIVER(rockchip_rk3066a_cru) = {
>> +       .name                   = "rockchip_rk3066a_cru",
>> +       .id                     = UCLASS_CLK,
>> +       .of_match               = rk3066_clk_ids,
>> +       .priv_auto              = sizeof(struct rk3066_clk_priv),
>> +       .plat_auto              = sizeof(struct rk3066_clk_plat),
>> +       .ops                    = &rk3066_clk_ops,
>> +       .bind                   = rk3066_clk_bind,
>> +       .of_to_plat             = rk3066_clk_of_to_plat,
>> +       .probe                  = rk3066_clk_probe,
>> +};
>> --
>> 2.32.0
>>
> Regards,
> Simon

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v6 2/4] rockchip: rk3066: add clock driver for rk3066 soc
  2021-07-25 14:15     ` Paweł Jarosz
@ 2021-07-26 14:06       ` Simon Glass
  0 siblings, 0 replies; 8+ messages in thread
From: Simon Glass @ 2021-07-26 14:06 UTC (permalink / raw)
  To: Paweł Jarosz
  Cc: Kever Yang, Philipp Tomsich, Lukasz Majewski, U-Boot Mailing List

Hi Paweł,

On Sun, 25 Jul 2021 at 08:15, Paweł Jarosz <paweljarosz3691@gmail.com> wrote:
>
> Hi Simon,
>
>
> sorry for late response i was offline a bit
>
> W dniu 13.07.2021 o 22:17, Simon Glass pisze:
> > Hi Paweł,
> >
> > On Tue, 13 Jul 2021 at 12:59, Paweł Jarosz <paweljarosz3691@gmail.com> wrote:
> >> Add clock driver for rk3066 platform.
> >>
> >> Signed-off-by: Paweł Jarosz <paweljarosz3691@gmail.com>
> >> Acked-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
> >> ---
> >>
> >> Changes since v1:
> >> - updated to shifted masks
> >> - moved clk init to tpl
> >>
> >> Changes since v2:
> >> - none
> >>
> >> Changes since v3:
> >> - none
> >>
> >> Changes since v4:
> >> - updated to current codebase
> >> - fixed compilation errors
> >>
> >> Changes since v5:
> >> - various style changes
> >> - added clk_enable/clk_disable support for nand and mmc clocks
> >> - updated maintainer email
> >> - renamed uint32_t to u32
> >> - used #if IS_ENABLED macro instead #ifdef
> >>
> >>
> >>
> >>  .../include/asm/arch-rockchip/cru_rk3066.h    | 203 +++++
> >>  drivers/clk/rockchip/Makefile                 |   1 +
> >>  drivers/clk/rockchip/clk_rk3066.c             | 704 ++++++++++++++++++
> >>  3 files changed, 908 insertions(+)
> >>  create mode 100644 arch/arm/include/asm/arch-rockchip/cru_rk3066.h
> >>  create mode 100644 drivers/clk/rockchip/clk_rk3066.c
> >>
> > [..]
> >
> >> +
> >> +static int rk3066_clk_of_to_plat(struct udevice *dev)
> >> +{
> >> +#if !CONFIG_IS_ENABLED(OF_PLATDATA)
> >> +       struct rk3066_clk_priv *priv = dev_get_priv(dev);
> >> +
> >> +       priv->cru = dev_read_addr_ptr(dev);
> >> +#endif
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +static int rk3066_clk_probe(struct udevice *dev)
> >> +{
> >> +       struct rk3066_clk_priv *priv = dev_get_priv(dev);
> >> +
> >> +       priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
> >> +       if (IS_ERR(priv->grf))
> >> +               return PTR_ERR(priv->grf);
> >> +
> >> +#if IS_ENABLED(CONFIG_TPL_BUILD)
> > Do you need that? The line below should take care of it.
>
>
> Yep. Later rkclk_init and rkclk_configure_cpu should be only executed in TPL.

But CONFIG_IS_ENABLED(OF_PLATDATA) should be enough to check that,
right, since it is only true in TPL? You the TPL check seems to be
redundant.

>
>
> >> +#if CONFIG_IS_ENABLED(OF_PLATDATA)
> >> +       struct rk3066_clk_plat *plat = dev_get_plat(dev);
> >> +
> >> +       priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]);
> >> +#endif
> >> +
> >> +       rkclk_init(priv->cru, priv->grf);
> >> +
> >> +       /* Init CPU frequency */
> >> +       rkclk_configure_cpu(priv->cru, priv->grf, APLL_SAFE_HZ);
> >> +#endif
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +static int rk3066_clk_bind(struct udevice *dev)
> >> +{
> >> +       int ret;
> >> +       struct udevice *sys_child;
> >> +       struct sysreset_reg *priv;
> >> +
> >> +       /* The reset driver does not have a device node, so bind it here */
> >> +       ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
> >> +                                &sys_child);
> >> +       if (ret) {
> >> +               debug("Warning: No sysreset driver: ret=%d\n", ret);
> >> +       } else {
> >> +               priv = malloc(sizeof(struct sysreset_reg));
> >> +               priv->glb_srst_fst_value = offsetof(struct rk3066_cru,
> >> +                                                   cru_glb_srst_fst_value);
> >> +               priv->glb_srst_snd_value = offsetof(struct rk3066_cru,
> >> +                                                   cru_glb_srst_snd_value);
> >> +               dev_set_priv(sys_child, priv);
> >> +       }
> >> +
> >> +#if CONFIG_IS_ENABLED(RESET_ROCKCHIP)
> > Can you use if() instead of #if ?
>
>
> Yes, but what is the difference? Sorry ... I don't know what to ask google to get the answer.
>
> Is it in this case doing the same thing and just looking better?

We are avoiding the preprocessor these days in favour of compile-time
checks, since it increases build coverage and makes the code easier to
read (there are many other things here). Also patman should warn you
about this?

Regards,
Simon

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2021-07-26 14:07 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-13 18:58 [PATCH v6 0/4] Add basic support for rk3066 platform Paweł Jarosz
2021-07-13 18:58 ` [PATCH v6 1/4] rockchip: rk3066: add grf header file Paweł Jarosz
2021-07-13 18:58 ` [PATCH v6 2/4] rockchip: rk3066: add clock driver for rk3066 soc Paweł Jarosz
2021-07-13 20:17   ` Simon Glass
2021-07-25 14:15     ` Paweł Jarosz
2021-07-26 14:06       ` Simon Glass
2021-07-13 18:58 ` [PATCH v6 3/4] rockchip: rk3066: add rk3066 pinctrl driver Paweł Jarosz
2021-07-13 18:59 ` [PATCH v6 4/4] rockchip: rk3066: add sdram driver Paweł Jarosz

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.