[PATCH v8 00/15] Add Rikomagic MK808 board

MK808 is a RK3066-based board with 1 USB host and 1 USB OTG port, HDMI and a micro-SD card slot. It also includes on-board NAND and 1GB of SDRAM.
===
Boot procedure flow for a Rockchip rk3066 SoC:
1.Read 2K SDRAM initialization image code to internal SRAM 2.Run image code to do SDRAM initialization 3.Transfer boot image code to SDRAM 4.Run boot image code
Supported system boot from the following devices: Nand Flash SPI nor Flash eMMC device UART interface
If all boot options fail then enter into BootROM mode on the USB OTG port. Unlike later SoC models the rk3066 BootROM doesn't have SDMMC support.
The size of a full U-boot binary is too large for the internal SDRAM memory. Of that 64k size only 32kb sram - 2kb bootrom is available for the first stage.
Similar to the already supported rk3188, the BootROM will attempt to load up the first stage image in two steps: first 1KB to offset 0x800 in the SRAM and then the remainder to offset 0xc00 in the SRAM. It always enters at offset 0x804 after a 4 ASCII character "RK30" header.
With CONFIG_TPL_ROCKCHIP_EARLYRETURN_TO_BROM=y this first stage is combined with the U-boot TPL binary (u-boot-tpl.bin).
For rk3066 with NAND flash and U-boot this gives the following stages:
- TPL: init external SDRAM - SPL: init SDMMC and read U-boot from SD CARD. - U-boot: read Linux kernel from SD CARD. - Kernel
Additionally the rk3066 requires everything the BootROM loads to be RC4-encrypted.
===
Boot solution with full U-boot stored on SD CARD:
Compile commands(U-boot):
ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make mk808_defconfig ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make menuconfig ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make all
===
Size of SPL and TPL must be aligned to 2kb. If bricked and no BootROM mode shows up then connect pin 8 and 9 of the NAND flash with a needle while reconnecting to the USB OTG port to a PC.
===
Show connected devices with:
lsusb
Bus 001 Device 004: ID 2207:300a Fuzhou Rockchip Electronics Company RK3066 in Mask ROM mode
===
Program commands with ./flash.sh:
#!/bin/sh
printf "RK30" > tplspl.bin dd if=u-boot-tpl.bin >> tplspl.bin truncate -s %2048 tplspl.bin truncate -s %2048 u-boot-spl.bin ../tools/boot_merger --verbose config-flash.ini ../tools/upgrade_tool ul ./RK30xxLoader_uboot.bin
===
config-flash.ini:
[CHIP_NAME] NAME=RK30 [VERSION] MAJOR=2 MINOR=21 [CODE471_OPTION] NUM=1 Path1=30_LPDDR2_300MHz_DD.bin [CODE472_OPTION] NUM=1 Path1=rk30usbplug.bin [LOADER_OPTION] NUM=2 LOADER1=FlashData LOADER2=FlashBoot FlashData=tplspl.bin FlashBoot=u-boot-spl.bin [OUTPUT] PATH=RK30xxLoader_uboot.bin
===
Partition Map for MMC device 0 -- Partition Type: EFI
Part Start LBA End LBA Name Attributes Type GUID Partition GUID 1 0x00000040 0x00001f7f "loader1" 2 0x00004000 0x00005fff "loader2" 3 0x00006000 0x00007fff "trust" 4 0x00008000 0x0003ffff "boot" 5 0x00040000 0x00ed7fde "rootfs"
Make sure boot and esp flag are set for boot partition. Loader1 not used by
===
Boot partition:
extlinux -- extlinux.conf zImage rk3066a-mk808.dtb
===
extlinux.conf:
label kernel kernel /zImage fdt /rk3066a-mk808.dtb append root=LABEL=linuxroot init=/sbin/init rootfstype=ext4 rootwait
===
Program commands (SD CARD with GPT partition):
sudo dd if=u-boot-dtb.img of=/dev/sda seek=16384
===
TODO: Better program flow/tools USB NAND etc etc
===
Johan Jonker (11): rockchip: rk3066-power: sync power domain dt-binding header from Linux arm: dts: rockchip: fix rk3xxx-u-boot.dtsi arm: dts: rockchip: add rk3066a.dtsi arm: dts: rockchip: add rk3066a-mk808.dts rockchip: rk3066: add include rockchip: rk3066: add rk3066_common.h include rockchip: rk3066: add core support rockchip: rk3066: add Rikomagic MK808 board rockchip: rk3066: add mk808_defconfig rockchip: tools: add rk3066 support to rkcommon.c doc: rockchip: add rk3066 Rikomagic MK808
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
arch/arm/dts/Makefile | 3 + arch/arm/dts/rk3066a-mk808-u-boot.dtsi | 42 + arch/arm/dts/rk3066a-mk808.dts | 216 +++++ arch/arm/dts/rk3066a-u-boot.dtsi | 3 + arch/arm/dts/rk3066a.dtsi | 880 +++++++++++++++++ arch/arm/dts/rk3xxx-u-boot.dtsi | 8 +- arch/arm/include/asm/arch-rk3066/boot0.h | 8 + arch/arm/include/asm/arch-rk3066/gpio.h | 8 + arch/arm/include/asm/arch-rk3066/timer.h | 6 + .../include/asm/arch-rockchip/cru_rk3066.h | 157 +++ .../include/asm/arch-rockchip/grf_rk3066.h | 210 +++++ arch/arm/mach-rockchip/Kconfig | 23 + arch/arm/mach-rockchip/Makefile | 1 + arch/arm/mach-rockchip/rk3066/Kconfig | 39 + arch/arm/mach-rockchip/rk3066/Makefile | 5 + arch/arm/mach-rockchip/rk3066/clk_rk3066.c | 33 + arch/arm/mach-rockchip/rk3066/rk3066.c | 49 + arch/arm/mach-rockchip/rk3066/syscon_rk3066.c | 55 ++ board/rikomagic/mk808/Kconfig | 15 + board/rikomagic/mk808/MAINTAINERS | 6 + board/rikomagic/mk808/Makefile | 3 + board/rikomagic/mk808/mk808.c | 3 + configs/mk808_defconfig | 99 ++ doc/board/rockchip/rockchip.rst | 2 + drivers/clk/rockchip/Makefile | 1 + drivers/clk/rockchip/clk_rk3066.c | 717 ++++++++++++++ drivers/pinctrl/rockchip/Makefile | 1 + drivers/pinctrl/rockchip/pinctrl-rk3066.c | 113 +++ drivers/ram/rockchip/Makefile | 1 + drivers/ram/rockchip/sdram_rk3066.c | 892 ++++++++++++++++++ include/configs/mk808.h | 9 + include/configs/rk3066_common.h | 56 ++ include/dt-bindings/power/rk3066-power.h | 22 + tools/rkcommon.c | 1 + 34 files changed, 3683 insertions(+), 4 deletions(-) create mode 100644 arch/arm/dts/rk3066a-mk808-u-boot.dtsi create mode 100644 arch/arm/dts/rk3066a-mk808.dts create mode 100644 arch/arm/dts/rk3066a-u-boot.dtsi create mode 100644 arch/arm/dts/rk3066a.dtsi create mode 100644 arch/arm/include/asm/arch-rk3066/boot0.h create mode 100644 arch/arm/include/asm/arch-rk3066/gpio.h create mode 100644 arch/arm/include/asm/arch-rk3066/timer.h 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 arch/arm/mach-rockchip/rk3066/Kconfig create mode 100644 arch/arm/mach-rockchip/rk3066/Makefile create mode 100644 arch/arm/mach-rockchip/rk3066/clk_rk3066.c create mode 100644 arch/arm/mach-rockchip/rk3066/rk3066.c create mode 100644 arch/arm/mach-rockchip/rk3066/syscon_rk3066.c create mode 100644 board/rikomagic/mk808/Kconfig create mode 100644 board/rikomagic/mk808/MAINTAINERS create mode 100644 board/rikomagic/mk808/Makefile create mode 100644 board/rikomagic/mk808/mk808.c create mode 100644 configs/mk808_defconfig 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 create mode 100644 include/configs/mk808.h create mode 100644 include/configs/rk3066_common.h create mode 100644 include/dt-bindings/power/rk3066-power.h

In order to update the DT for rk3066 sync the power domain dt-binding header. This is the state as of v5.12 in Linux.
Signed-off-by: Johan Jonker jbx6244@gmail.com --- include/dt-bindings/power/rk3066-power.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 include/dt-bindings/power/rk3066-power.h
diff --git a/include/dt-bindings/power/rk3066-power.h b/include/dt-bindings/power/rk3066-power.h new file mode 100644 index 00000000..acf9f310 --- /dev/null +++ b/include/dt-bindings/power/rk3066-power.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __DT_BINDINGS_POWER_RK3066_POWER_H__ +#define __DT_BINDINGS_POWER_RK3066_POWER_H__ + +/* VD_CORE */ +#define RK3066_PD_A9_0 0 +#define RK3066_PD_A9_1 1 +#define RK3066_PD_DBG 4 +#define RK3066_PD_SCU 5 + +/* VD_LOGIC */ +#define RK3066_PD_VIDEO 6 +#define RK3066_PD_VIO 7 +#define RK3066_PD_GPU 8 +#define RK3066_PD_PERI 9 +#define RK3066_PD_CPU 10 +#define RK3066_PD_ALIVE 11 + +/* VD_PMU */ +#define RK3066_PD_RTC 12 + +#endif

From: Paweł Jarosz paweljarosz3691@gmail.com
grf is needed by various drivers for rk3066 soc.
Signed-off-by: Paweł Jarosz paweljarosz3691@gmail.com Signed-off-by: Johan Jonker jbx6244@gmail.com ---
Changed V8: add GRF_GPIO3B_IOMUX for SDMMC0 use GENMASK, __bf_shf and REG defines add includes --- .../include/asm/arch-rockchip/grf_rk3066.h | 210 ++++++++++++++++++ 1 file changed, 210 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 00000000..9863560c --- /dev/null +++ b/arch/arm/include/asm/arch-rockchip/grf_rk3066.h @@ -0,0 +1,210 @@ +/* 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 + +#include <linux/bitops.h> +#include <linux/bitfield.h> + +#define REG(name, h, l) \ + name##_MASK = GENMASK(h, l), \ + name##_SHIFT = __bf_shf(name##_MASK) + +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 { + REG(GPIO1B1, 2, 2), + GPIO1B1_GPIO = 0, + GPIO1B1_UART2_SOUT, + + REG(GPIO1B0, 0, 0), + GPIO1B0_GPIO = 0, + GPIO1B0_UART2_SIN +}; + +/* GRF_GPIO3B_IOMUX */ +enum { + REG(GPIO3B6, 12, 12), + GPIO3B6_GPIO = 0, + GPIO3B6_SDMMC0_DECTN, + + REG(GPIO3B5, 10, 10), + GPIO3B5_GPIO = 0, + GPIO3B5_SDMMC0_DATA3, + + REG(GPIO3B4, 8, 8), + GPIO3B4_GPIO = 0, + GPIO3B4_SDMMC0_DATA2, + + REG(GPIO3B3, 6, 6), + GPIO3B3_GPIO = 0, + GPIO3B3_SDMMC0_DATA1, + + REG(GPIO3B2, 4, 4), + GPIO3B2_GPIO = 0, + GPIO3B2_SDMMC0_DATA0, + + REG(GPIO3B1, 2, 2), + GPIO3B1_GPIO = 0, + GPIO3B1_SDMMC0_CMD, + + REG(GPIO3B0, 0, 0), + GPIO3B0_GPIO = 0, + GPIO3B0_SDMMC0_CLKOUT, +}; + +/* GRF_SOC_CON0 */ +enum { + REG(SMC_MUX_CON, 13, 13), + + REG(NOC_REMAP, 12, 12), + + REG(EMMC_FLASH_SEL, 11, 11), + + REG(TZPC_REVISION, 10, 7), + + REG(L2CACHE_ACC, 6, 5), + + REG(L2RD_WAIT, 4, 3), + + REG(IMEMRD_WAIT, 2, 1), + + REG(SOC_REMAP, 0, 0), +}; + +/* GRF_SOC_CON1 */ +enum { + REG(RKI2C4_SEL, 15, 15), + + REG(RKI2C3_SEL, 14, 14), + + REG(RKI2C2_SEL, 13, 13), + + REG(RKI2C1_SEL, 12, 12), + + REG(RKI2C0_SEL, 11, 11), + + REG(VCODEC_SEL, 10, 10), + + REG(PERI_EMEM_PAUSE, 9, 9), + + REG(PERI_USB_PAUSE, 8, 8), + + REG(SMC_MUX_MODE_0, 6, 6), + + REG(SMC_SRAM_MW_0, 5, 4), + + REG(SMC_REMAP_0, 3, 3), + + REG(SMC_A_GT_M0_SYNC, 2, 2), + + REG(EMAC_SPEED, 1, 1), + + REG(EMAC_MODE, 0, 0), +}; + +/* GRF_SOC_CON2 */ +enum { + REG(MSCH4_MAINDDR3, 7, 7), + MSCH4_MAINDDR3_DDR3 = 1, + + REG(EMAC_NEWRCV_EN, 6, 6), + + REG(SW_ADDR15_EN, 5, 5), + + REG(SW_ADDR16_EN, 4, 4), + + REG(SW_ADDR17_EN, 3, 3), + + REG(BANK2_TO_RANK_EN, 2, 2), + + REG(RANK_TO_ROW15_EN, 1, 1), + + REG(UPCTL_C_ACTIVE_IN, 0, 0), + UPCTL_C_ACTIVE_IN_MAY = 0, + UPCTL_C_ACTIVE_IN_WILL, +}; + +/* GRF_DDRC_CON0 */ +enum { + REG(DTO_LB, 12, 11), + + REG(DTO_TE, 10, 9), + + REG(DTO_PDR, 8, 7), + + REG(DTO_PDD, 6, 5), + + REG(DTO_IOM, 4, 3), + + REG(DTO_OE, 2, 1), + + REG(ATO_AE, 0, 0), +}; +#endif

From: Paweł Jarosz paweljarosz3691@gmail.com
Add the clock driver for the rk3066 platform.
Derived from the rk3288 and rk3188 driver it supports only a bare minimum to bring up the system to reduce the TPL size for: SDRAM clock configuration. The boot devices NAND, EMMC, SDMMC, SPI. A UART for the debug messages (fixed) at 115200n8. A SARADC for the recovery button. A TIMER for the delays (fixed).
There's support for 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.
After the clock tree is set during the TPL probe there's no parent update support.
In OF_REAL mode the drivers ns16550.c and dw-apb-timer.c obtain the (fixed) clk_get_rate from the clock driver instead of platdata.
The rk3066 cru node has a number of assigned-clocks properties that call the .set_rate() function. Add them to the list so that they return a 0 instead of -ENOENT.
Signed-off-by: Paweł Jarosz paweljarosz3691@gmail.com Signed-off-by: Johan Jonker jbx6244@gmail.com ---
Changed V8: add SCLK_TIMER[0..2] add SCLK_UART[0..3] fix assigned-clocks use GENMASK, __bf_shf and REG defines fix clk defines add includes fix bit position CRU_CLKSEL0_CON rk3066 vs rk3188 fix comments rename PLL_MODE defines use dev_bind use dev_dbg use a different variable name
Changed V7: changed function prefix changed #if where possible restyle U_BOOT_DRIVER structure --- .../include/asm/arch-rockchip/cru_rk3066.h | 157 ++++ drivers/clk/rockchip/Makefile | 1 + drivers/clk/rockchip/clk_rk3066.c | 717 ++++++++++++++++++ 3 files changed, 875 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 00000000..45937736 --- /dev/null +++ b/arch/arm/include/asm/arch-rockchip/cru_rk3066.h @@ -0,0 +1,157 @@ +/* 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 + +#include <linux/bitops.h> +#include <linux/bitfield.h> + +#define REG(name, h, l) \ + name##_MASK = GENMASK(h, l), \ + name##_SHIFT = __bf_shf(name##_MASK) + +#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 { + REG(CPU_ACLK_PLL, 8, 8), + CPU_ACLK_PLL_SELECT_APLL = 0, + CPU_ACLK_PLL_SELECT_GPLL, + + REG(CORE_PERI_DIV, 7, 6), + + REG(A9_CORE_DIV, 4, 0), +}; + +/* CRU_CLKSEL1_CON */ +enum { + REG(AHB2APB_DIV, 15, 14), + + REG(CPU_PCLK_DIV, 13, 12), + + REG(CPU_HCLK_DIV, 9, 8), + + REG(CPU_ACLK_DIV, 2, 0), +}; + +/* CRU_CLKSEL10_CON */ +enum { + REG(PERI_SEL_PLL, 15, 15), + PERI_SEL_CPLL = 0, + PERI_SEL_GPLL, + + REG(PERI_PCLK_DIV, 13, 12), + + REG(PERI_HCLK_DIV, 9, 8), + + REG(PERI_ACLK_DIV, 4, 0), +}; + +/* CRU_CLKSEL11_CON */ +enum { + REG(MMC0_DIV, 5, 0), +}; + +/* CRU_CLKSEL12_CON */ +enum { + REG(UART_PLL, 15, 15), + UART_PLL_SELECT_GENERAL = 0, + UART_PLL_SELECT_CODEC, + + REG(EMMC_DIV, 13, 8), + + REG(SDIO_DIV, 5, 0), +}; + +/* CRU_CLKSEL24_CON */ +enum { + REG(SARADC_DIV, 15, 8), +}; + +/* CRU_CLKSEL25_CON */ +enum { + REG(SPI1_DIV, 14, 8), + + REG(SPI0_DIV, 6, 0), +}; + +/* CRU_CLKSEL34_CON */ +enum { + REG(TSADC_DIV, 15, 0), +}; + +/* CRU_MODE_CON */ +enum { + REG(GPLL_MODE, 13, 12), + + REG(CPLL_MODE, 9, 8), + + REG(DPLL_MODE, 5, 4), + + REG(APLL_MODE, 1, 0), + PLL_MODE_SLOW = 0, + PLL_MODE_NORMAL, + PLL_MODE_DEEP, +}; + +/* CRU_APLL_CON0 */ +enum { + REG(CLKR, 13, 8), + + REG(CLKOD, 3, 0), +}; + +/* CRU_APLL_CON1 */ +enum { + REG(CLKF, 12, 0), +}; + +#endif diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index 913f611a..a72d8fe5 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 00000000..39c1c157 --- /dev/null +++ b/drivers/clk/rockchip/clk_rk3066.c @@ -0,0 +1,717 @@ +// 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_compat.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. */ +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); + +static int rk3066_clk_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 the 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("%s: PLL at %x: nf=%d, nr=%d, no=%d, vco=%u Hz, output=%u Hz\n", __func__, + (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); + + /* Exit reset. */ + rk_clrreg(&pll->con3, BIT(PLL_RESET_SHIFT)); + + return 0; +} + +static int rk3066_clk_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("%s: unsupported SDRAM frequency", __func__); + return -EINVAL; + } + + /* Enter PLL slow mode. */ + rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK, + PLL_MODE_SLOW << DPLL_MODE_SHIFT); + + rk3066_clk_set_pll(cru, CLK_DDR, &dpll_cfg[cfg]); + + /* Wait for PLL lock. */ + while (!(readl(&grf->soc_status0) & SOCSTS_DPLL_LOCK)) + udelay(1); + + /* Enter PLL normal mode. */ + rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK, + PLL_MODE_NORMAL << DPLL_MODE_SHIFT); + + return 0; +} + +static int rk3066_clk_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_cpu_aclk, 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_cpu_aclk = 3; + break; + case APLL_HZ: + cfg = 1; + div_core_peri = 2; + div_cpu_aclk = 3; + break; + default: + debug("unsupported ARMCLK frequency"); + return -EINVAL; + } + + /* Enter PLL slow mode. */ + rk_clrsetreg(&cru->cru_mode_con, APLL_MODE_MASK, + PLL_MODE_SLOW << APLL_MODE_SHIFT); + + rk3066_clk_set_pll(cru, CLK_ARM, &apll_cfg[cfg]); + + /* Wait 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 cpu_aclk. */ + rk_clrsetreg(&cru->cru_clksel_con[1], + CPU_ACLK_DIV_MASK, + div_cpu_aclk << CPU_ACLK_DIV_SHIFT); + + /* Enter PLL normal mode. */ + rk_clrsetreg(&cru->cru_mode_con, APLL_MODE_MASK, + PLL_MODE_NORMAL << APLL_MODE_SHIFT); + + return hz; +} + +static uint32_t rk3066_clk_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(FIELD_GET(APLL_MODE_MASK, con >> shift)) { + case PLL_MODE_SLOW: + return OSC_HZ; + case PLL_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 PLL_MODE_DEEP: + default: + return 32768; + } +} + +static ulong rk3066_clk_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 rk3066_clk_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 by default divides by 2 internally, so need to 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 rk3066_clk_mmc_get_clk(cru, gclk_rate, periph); +} + +static ulong rk3066_clk_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 rk3066_clk_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 rk3066_clk_spi_get_clk(cru, gclk_rate, periph); +} + +static ulong rk3066_clk_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 rk3066_clk_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 rk3066_clk_saradc_get_clk(cru, periph); +} + +static void rk3066_clk_init(struct rk3066_cru *cru, struct rk3066_grf *grf) +{ + u32 aclk_div, hclk_div, pclk_div, h2p_div; + + /* Enter PLL slow mode. */ + rk_clrsetreg(&cru->cru_mode_con, + GPLL_MODE_MASK | + CPLL_MODE_MASK, + PLL_MODE_SLOW << GPLL_MODE_SHIFT | + PLL_MODE_SLOW << CPLL_MODE_SHIFT); + + /* Init PLL. */ + rk3066_clk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg); + rk3066_clk_set_pll(cru, CLK_CODEC, &cpll_init_cfg); + + /* Wait for PLL lock. */ + while ((readl(&grf->soc_status0) & + (SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK)) != + (SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK)) + udelay(1); + + /* + * Select CPU clock PLL source and + * reparent aclk_cpu_pre from APPL 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_CORE_DIV_MASK, + CPU_ACLK_PLL_SELECT_GPLL << CPU_ACLK_PLL_SHIFT | + aclk_div << A9_CORE_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); + + /* + * Select PERI clock PLL source 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); + + /* Enter PLL normal mode. */ + rk_clrsetreg(&cru->cru_mode_con, + GPLL_MODE_MASK | + CPLL_MODE_MASK, + PLL_MODE_NORMAL << GPLL_MODE_SHIFT | + PLL_MODE_NORMAL << CPLL_MODE_SHIFT); + + rk3066_clk_mmc_set_clk(cru, PERI_HCLK_HZ, HCLK_SDMMC, 16000000); +} + +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 = rk3066_clk_pll_get_rate(priv->cru, CLK_GENERAL); + switch (clk->id) { + case 1 ... 4: + new_rate = rk3066_clk_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 = rk3066_clk_mmc_get_clk(priv->cru, PERI_HCLK_HZ, + clk->id); + break; + case SCLK_SPI0: + case SCLK_SPI1: + new_rate = rk3066_clk_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 = rk3066_clk_saradc_get_clk(priv->cru, clk->id); + break; + case SCLK_TIMER0: + case SCLK_TIMER1: + case SCLK_TIMER2: + case SCLK_UART0: + case SCLK_UART1: + case SCLK_UART2: + case SCLK_UART3: + return OSC_HZ; + 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 = rk3066_clk_configure_cpu(priv->cru, priv->grf, rate); + break; + case CLK_DDR: + new_rate = rk3066_clk_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 = rk3066_clk_mmc_set_clk(cru, PERI_HCLK_HZ, + clk->id, rate); + break; + case SCLK_SPI0: + case SCLK_SPI1: + new_rate = rk3066_clk_spi_set_clk(cru, PERI_PCLK_HZ, + clk->id, rate); + break; + case SCLK_SARADC: + case SCLK_TSADC: + new_rate = rk3066_clk_saradc_set_clk(cru, rate, clk->id); + break; + case PLL_CPLL: + case PLL_GPLL: + case ACLK_CPU: + case HCLK_CPU: + case PCLK_CPU: + case ACLK_PERI: + case HCLK_PERI: + case PCLK_PERI: + return 0; + 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_REAL)) { + struct rk3066_clk_priv *priv = dev_get_priv(dev); + + priv->cru = dev_read_addr_ptr(dev); + } + + 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 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 + + if (IS_ENABLED(CONFIG_TPL_BUILD)) { + rk3066_clk_init(priv->cru, priv->grf); + + /* Init CPU frequency. */ + rk3066_clk_configure_cpu(priv->cru, priv->grf, APLL_SAFE_HZ); + } + + return 0; +} + +static int rk3066_clk_bind(struct udevice *dev) +{ + struct udevice *sys_child; + struct sysreset_reg *priv; + int reg_offset, ret; + + /* The reset driver does not have a device node, so bind it here. */ + ret = device_bind(dev, DM_DRIVER_GET(sysreset_rockchip), "sysreset", + NULL, ofnode_null(), &sys_child); + if (ret) { + dev_dbg(dev, "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)) { + reg_offset = offsetof(struct rk3066_cru, cru_softrst_con[0]); + ret = rockchip_reset_bind(dev, reg_offset, 9); + if (ret) + dev_dbg(dev, "Warning: software reset driver bind failed\n"); + } + + 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, + .ops = &rk3066_clk_ops, + .probe = rk3066_clk_probe, + .bind = rk3066_clk_bind, + .of_match = rk3066_clk_ids, + .of_to_plat = rk3066_clk_of_to_plat, + .priv_auto = sizeof(struct rk3066_clk_priv), + .plat_auto = sizeof(struct rk3066_clk_plat), +};

On 1/17/22 7:36 PM, Johan Jonker wrote:
From: Paweł Jarosz paweljarosz3691@gmail.com
Add the clock driver for the rk3066 platform.
Derived from the rk3288 and rk3188 driver it supports only a bare minimum to bring up the system to reduce the TPL size for: SDRAM clock configuration. The boot devices NAND, EMMC, SDMMC, SPI. A UART for the debug messages (fixed) at 115200n8. A SARADC for the recovery button. A TIMER for the delays (fixed).
There's support for 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.
After the clock tree is set during the TPL probe there's no parent update support.
In OF_REAL mode the drivers ns16550.c and dw-apb-timer.c obtain the (fixed) clk_get_rate from the clock driver instead of platdata.
The rk3066 cru node has a number of assigned-clocks properties that call the .set_rate() function. Add them to the list so that they return a 0 instead of -ENOENT.
Signed-off-by: Paweł Jarosz paweljarosz3691@gmail.com Signed-off-by: Johan Jonker jbx6244@gmail.com
Changed V8: add SCLK_TIMER[0..2] add SCLK_UART[0..3] fix assigned-clocks use GENMASK, __bf_shf and REG defines fix clk defines add includes fix bit position CRU_CLKSEL0_CON rk3066 vs rk3188 fix comments rename PLL_MODE defines use dev_bind use dev_dbg use a different variable name
Changed V7: changed function prefix changed #if where possible restyle U_BOOT_DRIVER structure
.../include/asm/arch-rockchip/cru_rk3066.h | 157 ++++ drivers/clk/rockchip/Makefile | 1 + drivers/clk/rockchip/clk_rk3066.c | 717 ++++++++++++++++++ 3 files changed, 875 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 00000000..45937736 --- /dev/null +++ b/arch/arm/include/asm/arch-rockchip/cru_rk3066.h @@ -0,0 +1,157 @@ +/* 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
+#include <linux/bitops.h> +#include <linux/bitfield.h>
+#define REG(name, h, l) \
name##_MASK = GENMASK(h, l), \
name##_SHIFT = __bf_shf(name##_MASK)
+#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 {
- REG(CPU_ACLK_PLL, 8, 8),
- CPU_ACLK_PLL_SELECT_APLL = 0,
- CPU_ACLK_PLL_SELECT_GPLL,
- REG(CORE_PERI_DIV, 7, 6),
- REG(A9_CORE_DIV, 4, 0),
+};
+/* CRU_CLKSEL1_CON */ +enum {
- REG(AHB2APB_DIV, 15, 14),
- REG(CPU_PCLK_DIV, 13, 12),
- REG(CPU_HCLK_DIV, 9, 8),
- REG(CPU_ACLK_DIV, 2, 0),
+};
+/* CRU_CLKSEL10_CON */ +enum {
- REG(PERI_SEL_PLL, 15, 15),
- PERI_SEL_CPLL = 0,
- PERI_SEL_GPLL,
- REG(PERI_PCLK_DIV, 13, 12),
- REG(PERI_HCLK_DIV, 9, 8),
- REG(PERI_ACLK_DIV, 4, 0),
+};
+/* CRU_CLKSEL11_CON */ +enum {
- REG(MMC0_DIV, 5, 0),
+};
+/* CRU_CLKSEL12_CON */ +enum {
- REG(UART_PLL, 15, 15),
- UART_PLL_SELECT_GENERAL = 0,
- UART_PLL_SELECT_CODEC,
- REG(EMMC_DIV, 13, 8),
- REG(SDIO_DIV, 5, 0),
+};
+/* CRU_CLKSEL24_CON */ +enum {
- REG(SARADC_DIV, 15, 8),
+};
+/* CRU_CLKSEL25_CON */ +enum {
- REG(SPI1_DIV, 14, 8),
- REG(SPI0_DIV, 6, 0),
+};
+/* CRU_CLKSEL34_CON */ +enum {
- REG(TSADC_DIV, 15, 0),
+};
+/* CRU_MODE_CON */ +enum {
- REG(GPLL_MODE, 13, 12),
- REG(CPLL_MODE, 9, 8),
- REG(DPLL_MODE, 5, 4),
- REG(APLL_MODE, 1, 0),
- PLL_MODE_SLOW = 0,
- PLL_MODE_NORMAL,
- PLL_MODE_DEEP,
+};
+/* CRU_APLL_CON0 */ +enum {
- REG(CLKR, 13, 8),
- REG(CLKOD, 3, 0),
+};
+/* CRU_APLL_CON1 */ +enum {
- REG(CLKF, 12, 0),
+};
+#endif diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index 913f611a..a72d8fe5 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 00000000..39c1c157 --- /dev/null +++ b/drivers/clk/rockchip/clk_rk3066.c @@ -0,0 +1,717 @@ +// 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_compat.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. */ +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);
+static int rk3066_clk_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 the 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("%s: PLL at %x: nf=%d, nr=%d, no=%d, vco=%u Hz, output=%u Hz\n", __func__,
(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);
- /* Exit reset. */
- rk_clrreg(&pll->con3, BIT(PLL_RESET_SHIFT));
- return 0;
+}
+static int rk3066_clk_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("%s: unsupported SDRAM frequency", __func__);
return -EINVAL;
- }
- /* Enter PLL slow mode. */
- rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK,
PLL_MODE_SLOW << DPLL_MODE_SHIFT);
- rk3066_clk_set_pll(cru, CLK_DDR, &dpll_cfg[cfg]);
- /* Wait for PLL lock. */
- while (!(readl(&grf->soc_status0) & SOCSTS_DPLL_LOCK))
udelay(1);
- /* Enter PLL normal mode. */
- rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK,
PLL_MODE_NORMAL << DPLL_MODE_SHIFT);
- return 0;
+}
+static int rk3066_clk_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_cpu_aclk, 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_cpu_aclk = 3;
break;
- case APLL_HZ:
cfg = 1;
div_core_peri = 2;
div_cpu_aclk = 3;
break;
- default:
debug("unsupported ARMCLK frequency");
return -EINVAL;
- }
- /* Enter PLL slow mode. */
- rk_clrsetreg(&cru->cru_mode_con, APLL_MODE_MASK,
PLL_MODE_SLOW << APLL_MODE_SHIFT);
- rk3066_clk_set_pll(cru, CLK_ARM, &apll_cfg[cfg]);
- /* Wait 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 cpu_aclk. */
- rk_clrsetreg(&cru->cru_clksel_con[1],
CPU_ACLK_DIV_MASK,
div_cpu_aclk << CPU_ACLK_DIV_SHIFT);
- /* Enter PLL normal mode. */
- rk_clrsetreg(&cru->cru_mode_con, APLL_MODE_MASK,
PLL_MODE_NORMAL << APLL_MODE_SHIFT);
- return hz;
+}
+static uint32_t rk3066_clk_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(FIELD_GET(APLL_MODE_MASK, con >> shift)) {
- case PLL_MODE_SLOW:
return OSC_HZ;
- case PLL_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 PLL_MODE_DEEP:
- default:
return 32768;
- }
+}
+static ulong rk3066_clk_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 rk3066_clk_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 by default divides by 2 internally, so need to 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 rk3066_clk_mmc_get_clk(cru, gclk_rate, periph);
+}
+static ulong rk3066_clk_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 rk3066_clk_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 rk3066_clk_spi_get_clk(cru, gclk_rate, periph);
+}
+static ulong rk3066_clk_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 rk3066_clk_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 rk3066_clk_saradc_get_clk(cru, periph);
+}
+static void rk3066_clk_init(struct rk3066_cru *cru, struct rk3066_grf *grf) +{
- u32 aclk_div, hclk_div, pclk_div, h2p_div;
- /* Enter PLL slow mode. */
- rk_clrsetreg(&cru->cru_mode_con,
GPLL_MODE_MASK |
CPLL_MODE_MASK,
PLL_MODE_SLOW << GPLL_MODE_SHIFT |
PLL_MODE_SLOW << CPLL_MODE_SHIFT);
- /* Init PLL. */
- rk3066_clk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg);
- rk3066_clk_set_pll(cru, CLK_CODEC, &cpll_init_cfg);
- /* Wait for PLL lock. */
- while ((readl(&grf->soc_status0) &
(SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK)) !=
(SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK))
udelay(1);
- /*
* Select CPU clock PLL source and
* reparent aclk_cpu_pre from APPL 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_CORE_DIV_MASK,
CPU_ACLK_PLL_SELECT_GPLL << CPU_ACLK_PLL_SHIFT |
aclk_div << A9_CORE_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);
- /*
* Select PERI clock PLL source 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);
- /* Enter PLL normal mode. */
- rk_clrsetreg(&cru->cru_mode_con,
GPLL_MODE_MASK |
CPLL_MODE_MASK,
PLL_MODE_NORMAL << GPLL_MODE_SHIFT |
PLL_MODE_NORMAL << CPLL_MODE_SHIFT);
- rk3066_clk_mmc_set_clk(cru, PERI_HCLK_HZ, HCLK_SDMMC, 16000000);
+}
+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 = rk3066_clk_pll_get_rate(priv->cru, CLK_GENERAL);
- switch (clk->id) {
- case 1 ... 4:
new_rate = rk3066_clk_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 = rk3066_clk_mmc_get_clk(priv->cru, PERI_HCLK_HZ,
clk->id);
break;
- case SCLK_SPI0:
- case SCLK_SPI1:
new_rate = rk3066_clk_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 = rk3066_clk_saradc_get_clk(priv->cru, clk->id);
break;
- case SCLK_TIMER0:
- case SCLK_TIMER1:
- case SCLK_TIMER2:
- case SCLK_UART0:
- case SCLK_UART1:
- case SCLK_UART2:
- case SCLK_UART3:
return OSC_HZ;
- 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 = rk3066_clk_configure_cpu(priv->cru, priv->grf, rate);
break;
- case CLK_DDR:
new_rate = rk3066_clk_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 = rk3066_clk_mmc_set_clk(cru, PERI_HCLK_HZ,
clk->id, rate);
break;
- case SCLK_SPI0:
- case SCLK_SPI1:
new_rate = rk3066_clk_spi_set_clk(cru, PERI_PCLK_HZ,
clk->id, rate);
break;
- case SCLK_SARADC:
- case SCLK_TSADC:
new_rate = rk3066_clk_saradc_set_clk(cru, rate, clk->id);
break;
- case PLL_CPLL:
- case PLL_GPLL:
- case ACLK_CPU:
- case HCLK_CPU:
- case PCLK_CPU:
- case ACLK_PERI:
- case HCLK_PERI:
- case PCLK_PERI:
return 0;
- 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_REAL)) {
struct rk3066_clk_priv *priv = dev_get_priv(dev);
priv->cru = dev_read_addr_ptr(dev);
- }
- 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 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
- if (IS_ENABLED(CONFIG_TPL_BUILD)) {
rk3066_clk_init(priv->cru, priv->grf);
/* Init CPU frequency. */
rk3066_clk_configure_cpu(priv->cru, priv->grf, APLL_SAFE_HZ);
- }
- return 0;
+}
+static int rk3066_clk_bind(struct udevice *dev) +{
- struct udevice *sys_child;
- struct sysreset_reg *priv;
- int reg_offset, ret;
- /* The reset driver does not have a device node, so bind it here. */
- ret = device_bind(dev, DM_DRIVER_GET(sysreset_rockchip), "sysreset",
NULL, ofnode_null(), &sys_child);
- if (ret) {
dev_dbg(dev, "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)) {
reg_offset = offsetof(struct rk3066_cru, cru_softrst_con[0]);
ret = rockchip_reset_bind(dev, reg_offset, 9);
if (ret)
dev_dbg(dev, "Warning: software reset driver bind failed\n");
- }
- 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,
- .ops = &rk3066_clk_ops,
- .probe = rk3066_clk_probe,
- .bind = rk3066_clk_bind,
- .of_match = rk3066_clk_ids,
- .of_to_plat = rk3066_clk_of_to_plat,
- .priv_auto = sizeof(struct rk3066_clk_priv),
- .plat_auto = sizeof(struct rk3066_clk_plat),
+};
Reviewed-by: Sean Anderson seanga2@gmail.com

From: Paweł Jarosz paweljarosz3691@gmail.com
Add driver supporting pin multiplexing on rk3066 platform.
Signed-off-by: Paweł Jarosz paweljarosz3691@gmail.com Signed-off-by: Johan Jonker jbx6244@gmail.com ---
Changed V7: restyle changed function prefix. restyle U_BOOT_DRIVER structure use OF_REAL use EOPNOTSUPP --- 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 fcf19f87..7d03f810 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 00000000..c329dd45 --- /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_pinctrl_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_pinctrl_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_pinctrl_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 -EOPNOTSUPP; + + rk3066_pinctrl_calc_pull_reg_and_bit(bank, pin_num, ®map, ®, &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_pinctrl_set_mux, + .set_pull = rk3066_pinctrl_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, + .ops = &rockchip_pinctrl_ops, + .probe = rockchip_pinctrl_probe, +#if CONFIG_IS_ENABLED(OF_REAL) + .bind = dm_scan_fdt_dev, +#endif + .of_match = rk3066_pinctrl_ids, + .priv_auto = sizeof(struct rockchip_pinctrl_priv), +};

From: Paweł Jarosz paweljarosz3691@gmail.com
Add rockchip rk3066 sdram driver
Signed-off-by: Paweł Jarosz paweljarosz3691@gmail.com Signed-off-by: Johan Jonker jbx6244@gmail.com ---
Changed V7: restyle rename TEST_PATTERN changed function prefix changed #if where possible restyle U_BOOT_DRIVER structure remove rk3066_dmc_of_to_plat because dmc DT data only used in TPL in combination with OF_PLATDATA --- drivers/ram/rockchip/Makefile | 1 + drivers/ram/rockchip/sdram_rk3066.c | 892 ++++++++++++++++++++++++++++ 2 files changed, 893 insertions(+) create mode 100644 drivers/ram/rockchip/sdram_rk3066.c
diff --git a/drivers/ram/rockchip/Makefile b/drivers/ram/rockchip/Makefile index ca1c289b..6d530c29 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 00000000..832154ee --- /dev/null +++ b/drivers/ram/rockchip/sdram_rk3066.c @@ -0,0 +1,892 @@ +// 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 rk3066_dmc_chan_info { + struct rk3288_ddr_pctl *pctl; + struct rk3288_ddr_publ *publ; + struct rk3188_msch *msch; +}; + +struct rk3066_dmc_dram_info { + struct rk3066_dmc_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_dmc_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 rk3066_dmc_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_PATTERN 0x5aa5f00f +#define DQS_GATE_TRAINING_ERROR_RANK0 BIT(4) +#define DQS_GATE_TRAINING_ERROR_RANK1 BIT(5) + +static void rk3066_dmc_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 rk3066_dmc_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 rk3066_dmc_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 rk3066_dmc_phy_pctrl_reset(struct rk3066_cru *cru, + struct rk3288_ddr_publ *publ, + int channel) +{ + int i; + + rk3066_dmc_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); + rk3066_dmc_ddr_reset(cru, channel, 1, 0); + udelay(10); + rk3066_dmc_ddr_reset(cru, channel, 0, 0); + udelay(10); +} + +static void rk3066_dmc_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 rk3066_dmc_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); + /* Write ODT length. */ + writel(7 << ODT_LEN_BL8_W_SHIFT, &pctl->dfiodtcfg1); + /* Disable phyupd and ctrlupd. */ + writel(0, &pctl->dfiupdcfg); +} + +static void rk3066_dmc_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 rk3066_dmc_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 rk3066_dmc_pctl_cfg(int channel, struct rk3288_ddr_pctl *pctl, + struct rk3066_dmc_sdram_params *sdram_params, + struct rk3066_grf *grf) +{ + rk3066_dmc_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); + rk3066_dmc_ddr_set_ddr3_mode(grf, channel, true); + break; + } + + setbits_le32(&pctl->scfg, 1); +} + +static void rk3066_dmc_phy_cfg(const struct rk3066_dmc_chan_info *chan, int channel, + struct rk3066_dmc_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); + /* Set DDR PHY timing. */ + rk3066_dmc_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) { + /* Enable dynamic RTT. */ + for (i = 0; i < 4; i++) + setbits_le32(&publ->datx8[i].dxgcr, DQSRTT | DQRTT); + } else { + /* Disable dynamic RTT. */ + for (i = 0; i < 4; i++) + clrbits_le32(&publ->datx8[i].dxgcr, DQSRTT | DQRTT); + } +} + +static void rk3066_dmc_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 rk3066_dmc_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 rk3066_dmc_send_command_op(struct rk3288_ddr_pctl *pctl, + u32 rank, u32 cmd, u32 ma, u32 op) +{ + rk3066_dmc_send_command(pctl, rank, cmd, (ma & LPDDR2_MA_MASK) << LPDDR2_MA_SHIFT | + (op & LPDDR2_OP_MASK) << LPDDR2_OP_SHIFT); +} + +static void rk3066_dmc_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 rk3066_dmc_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 we need to wakeup first + * and then enter the config. + */ + 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 rk3066_dmc_set_bandwidth_ratio(const struct rk3066_dmc_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 rk3066_dmc_data_training(const struct rk3066_dmc_chan_info *chan, int channel, + struct rk3066_dmc_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++) + rk3066_dmc_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 rk3066_dmc_move_to_access_state(const struct rk3066_dmc_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 rk3066_dmc_dram_cfg_rbc(const struct rk3066_dmc_chan_info *chan, u32 chnum, + struct rk3066_dmc_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 rk3066_dmc_dram_all_config(const struct rk3066_dmc_dram_info *dram, + struct rk3066_dmc_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); + + rk3066_dmc_dram_cfg_rbc(&dram->chan[chan], chan, sdram_params); + } + if (sdram_params->ch[0].rank == 2) + rk3066_dmc_ddr_rank_2_row15en(dram->grf, 0); + else + rk3066_dmc_ddr_rank_2_row15en(dram->grf, 1); + + writel(sys_reg, &dram->pmu->sys_reg[2]); +} + +static int rk3066_dmc_sdram_rank_bw_detect(struct rk3066_dmc_dram_info *dram, int channel, + struct rk3066_dmc_sdram_params *sdram_params) +{ + int reg; + int need_trainig = 0; + const struct rk3066_dmc_chan_info *chan = &dram->chan[channel]; + struct rk3288_ddr_publ *publ = chan->publ; + + rk3066_dmc_ddr_rank_2_row15en(dram->grf, 0); + + if (rk3066_dmc_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; + rk3066_dmc_set_bandwidth_ratio(chan, channel, + sdram_params->ch[channel].bw, + dram->grf); + need_trainig = 1; + } + } + /* Assume that the die bit width is equel to the chip bit width. */ + sdram_params->ch[channel].dbw = sdram_params->ch[channel].bw; + + if (need_trainig && + (rk3066_dmc_data_training(chan, channel, sdram_params) < 0)) { + if (sdram_params->base.dramtype == LPDDR3) { + rk3066_dmc_ddr_phy_ctl_reset(dram->cru, channel, 1); + udelay(10); + rk3066_dmc_ddr_phy_ctl_reset(dram->cru, channel, 0); + udelay(10); + } + debug("2nd data training failed!"); + return -EIO; + } + + return 0; +} + +static int rk3066_dmc_sdram_col_row_detect(struct rk3066_dmc_dram_info *dram, int channel, + struct rk3066_dmc_sdram_params *sdram_params) +{ + int row, col; + unsigned int addr; + const struct rk3066_dmc_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_PATTERN, addr); + if ((readl(addr) == TEST_PATTERN) && + (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; + } + + rk3066_dmc_ddr_rank_2_row15en(dram->grf, 1); + rk3066_dmc_move_to_config_state(publ, pctl); + writel(1, &chan->msch->ddrconf); + rk3066_dmc_move_to_access_state(chan); + /* Detect row, max 15, min13 for rk3066 */ + for (row = 16; row >= 13; row--) { + writel(0, CONFIG_SYS_SDRAM_BASE); + addr = CONFIG_SYS_SDRAM_BASE + (1 << (row + 15 - 1)); + writel(TEST_PATTERN, addr); + if ((readl(addr) == TEST_PATTERN) && + (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 rk3066_dmc_sdram_get_niu_config(struct rk3066_dmc_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(rk3066_dmc_ddrconf_table) / sizeof(rk3066_dmc_ddrconf_table[0]); + for (i = 0; i < size; i++) + if (tmp == rk3066_dmc_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 rk3066_dmc_sdram_init(struct rk3066_dmc_dram_info *dram, + struct rk3066_dmc_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 rk3066_dmc_chan_info *chan = &dram->chan[channel]; + struct rk3288_ddr_pctl *pctl = chan->pctl; + struct rk3288_ddr_publ *publ = chan->publ; + + rk3066_dmc_phy_pctrl_reset(dram->cru, publ, channel); + rk3066_dmc_phy_dll_bypass_set(publ, sdram_params->base.ddr_freq); + + rk3066_dmc_dfi_cfg(pctl, sdram_params->base.dramtype); + + rk3066_dmc_pctl_cfg(channel, pctl, sdram_params, dram->grf); + + rk3066_dmc_phy_cfg(chan, channel, sdram_params); + + rk3066_dmc_phy_init(publ); + + writel(POWER_UP_START, &pctl->powctl); + while (!(readl(&pctl->powstat) & POWER_UP_DONE)) + ; + + rk3066_dmc_memory_init(publ, sdram_params->base.dramtype); + rk3066_dmc_move_to_config_state(publ, pctl); + + /* Use 32bit bus width for detection. */ + sdram_params->ch[channel].bw = 2; + rk3066_dmc_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); + rk3066_dmc_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++) + rk3066_dmc_send_command_op(pctl, 1, MRR_CMD, i, 0); + } + writel(4, &chan->msch->ddrconf); + rk3066_dmc_move_to_access_state(chan); + /* DDR3 and LPDDR3 are always 8 bank, no need to detect. */ + sdram_params->ch[channel].bk = 3; + /* Detect Col and Row number. */ + ret = rk3066_dmc_sdram_col_row_detect(dram, channel, sdram_params); + if (ret) + goto error; + } + /* Find NIU DDR configuration. */ + ret = rk3066_dmc_sdram_get_niu_config(sdram_params); + if (ret) + goto error; + + rk3066_dmc_dram_all_config(dram, sdram_params); + debug("SDRAM init OK!\n"); + + return 0; +error: + debug("SDRAM init failed!\n"); + hang(); +} + +static int rk3066_dmc_setup_sdram(struct udevice *dev) +{ + struct rk3066_dmc_dram_info *priv = dev_get_priv(dev); + struct rk3066_dmc_sdram_params *params = dev_get_plat(dev); + + return rk3066_dmc_sdram_init(priv, params); +} + +static int rk3066_dmc_conv_of_plat(struct udevice *dev) +{ +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct rk3066_dmc_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; +#else + return -EINVAL; +#endif +} + +static int rk3066_dmc_probe(struct udevice *dev) +{ + struct rk3066_dmc_dram_info *priv = dev_get_priv(dev); + + priv->pmu = syscon_get_first_range(ROCKCHIP_SYSCON_PMU); + + if (IS_ENABLED(CONFIG_TPL_BUILD)) { + struct rk3066_dmc_sdram_params *plat = dev_get_plat(dev); + struct regmap *map; + struct udevice *dev_clk; + int ret; + + ret = rk3066_dmc_conv_of_plat(dev); + if (ret) + return ret; + + 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 = rk3066_dmc_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]); + } + + return 0; +} + +static int rk3066_dmc_get_info(struct udevice *dev, struct ram_info *info) +{ + struct rk3066_dmc_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, + .ops = &rk3066_dmc_ops, + .probe = rk3066_dmc_probe, + .of_match = rk3066_dmc_ids, + .priv_auto = sizeof(struct rk3066_dmc_dram_info), +#if IS_ENABLED(CONFIG_TPL_BUILD) + .plat_auto = sizeof(struct rk3066_dmc_sdram_params), +#endif +};

The file rk3xxx-u-boot.dtsi was original only for rk3188 and SPL. With rk3066 added some nodes are also needed in TPL, so change them to u-boot,dm-pre-reloc
Signed-off-by: Johan Jonker jbx6244@gmail.com --- arch/arm/dts/rk3xxx-u-boot.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/arm/dts/rk3xxx-u-boot.dtsi b/arch/arm/dts/rk3xxx-u-boot.dtsi index 581594c3..e67432fb 100644 --- a/arch/arm/dts/rk3xxx-u-boot.dtsi +++ b/arch/arm/dts/rk3xxx-u-boot.dtsi @@ -4,7 +4,7 @@ noc: syscon@10128000 { compatible = "rockchip,rk3188-noc", "syscon"; reg = <0x10128000 0x2000>; - u-boot,dm-spl; + u-boot,dm-pre-reloc; };
dmc: dmc@20020000 { @@ -18,16 +18,16 @@ rockchip,grf = <&grf>; rockchip,pmu = <&pmu>; rockchip,noc = <&noc>; - u-boot,dm-spl; + u-boot,dm-pre-reloc; }; };
&grf { - u-boot,dm-spl; + u-boot,dm-pre-reloc; };
&pmu { - u-boot,dm-spl; + u-boot,dm-pre-reloc; };
&uart2 {

In the Linux DT the file rk3xxx.dtsi is shared between rk3066 and rk3188. Add rk3066a.dtsi. Move U-boot specific things in a rk3066a-u-boot.dtsi file.
Signed-off-by: Johan Jonker jbx6244@gmail.com ---
Changed V8: update dtsi --- arch/arm/dts/rk3066a-u-boot.dtsi | 3 + arch/arm/dts/rk3066a.dtsi | 880 +++++++++++++++++++++++++++++++ 2 files changed, 883 insertions(+) create mode 100644 arch/arm/dts/rk3066a-u-boot.dtsi create mode 100644 arch/arm/dts/rk3066a.dtsi
diff --git a/arch/arm/dts/rk3066a-u-boot.dtsi b/arch/arm/dts/rk3066a-u-boot.dtsi new file mode 100644 index 00000000..fefef42b --- /dev/null +++ b/arch/arm/dts/rk3066a-u-boot.dtsi @@ -0,0 +1,3 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include "rockchip-u-boot.dtsi" diff --git a/arch/arm/dts/rk3066a.dtsi b/arch/arm/dts/rk3066a.dtsi new file mode 100644 index 00000000..da16fa23 --- /dev/null +++ b/arch/arm/dts/rk3066a.dtsi @@ -0,0 +1,880 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2013 MundoReader S.L. + * Author: Heiko Stuebner heiko@sntech.de + */ + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/pinctrl/rockchip.h> +#include <dt-bindings/clock/rk3066a-cru.h> +#include <dt-bindings/power/rk3066-power.h> +#include "rk3xxx.dtsi" +#include "rk3xxx-u-boot.dtsi" + +/ { + compatible = "rockchip,rk3066a"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + enable-method = "rockchip,rk3066-smp"; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + next-level-cache = <&L2>; + reg = <0x0>; + operating-points = + /* kHz uV */ + <1416000 1300000>, + <1200000 1175000>, + <1008000 1125000>, + <816000 1125000>, + <600000 1100000>, + <504000 1100000>, + <312000 1075000>; + clock-latency = <40000>; + clocks = <&cru ARMCLK>; + }; + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + next-level-cache = <&L2>; + reg = <0x1>; + }; + }; + + display-subsystem { + compatible = "rockchip,display-subsystem"; + ports = <&vop0_out>, <&vop1_out>; + }; + + sram: sram@10080000 { + compatible = "mmio-sram"; + reg = <0x10080000 0x10000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x10080000 0x10000>; + + smp-sram@0 { + compatible = "rockchip,rk3066-smp-sram"; + reg = <0x0 0x50>; + }; + }; + + vop0: vop@1010c000 { + compatible = "rockchip,rk3066-vop"; + reg = <0x1010c000 0x19c>; + interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru ACLK_LCDC0>, + <&cru DCLK_LCDC0>, + <&cru HCLK_LCDC0>; + clock-names = "aclk_vop", "dclk_vop", "hclk_vop"; + power-domains = <&power RK3066_PD_VIO>; + resets = <&cru SRST_LCDC0_AXI>, + <&cru SRST_LCDC0_AHB>, + <&cru SRST_LCDC0_DCLK>; + reset-names = "axi", "ahb", "dclk"; + status = "disabled"; + + vop0_out: port { + #address-cells = <1>; + #size-cells = <0>; + + vop0_out_hdmi: endpoint@0 { + reg = <0>; + remote-endpoint = <&hdmi_in_vop0>; + }; + }; + }; + + vop1: vop@1010e000 { + compatible = "rockchip,rk3066-vop"; + reg = <0x1010e000 0x19c>; + interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru ACLK_LCDC1>, + <&cru DCLK_LCDC1>, + <&cru HCLK_LCDC1>; + clock-names = "aclk_vop", "dclk_vop", "hclk_vop"; + power-domains = <&power RK3066_PD_VIO>; + resets = <&cru SRST_LCDC1_AXI>, + <&cru SRST_LCDC1_AHB>, + <&cru SRST_LCDC1_DCLK>; + reset-names = "axi", "ahb", "dclk"; + status = "disabled"; + + vop1_out: port { + #address-cells = <1>; + #size-cells = <0>; + + vop1_out_hdmi: endpoint@0 { + reg = <0>; + remote-endpoint = <&hdmi_in_vop1>; + }; + }; + }; + + hdmi: hdmi@10116000 { + compatible = "rockchip,rk3066-hdmi"; + reg = <0x10116000 0x2000>; + interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru HCLK_HDMI>; + clock-names = "hclk"; + pinctrl-names = "default"; + pinctrl-0 = <&hdmii2c_xfer>, <&hdmi_hpd>; + power-domains = <&power RK3066_PD_VIO>; + rockchip,grf = <&grf>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + hdmi_in: port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + hdmi_in_vop0: endpoint@0 { + reg = <0>; + remote-endpoint = <&vop0_out_hdmi>; + }; + + hdmi_in_vop1: endpoint@1 { + reg = <1>; + remote-endpoint = <&vop1_out_hdmi>; + }; + }; + + hdmi_out: port@1 { + reg = <1>; + }; + }; + }; + + i2s0: i2s@10118000 { + compatible = "rockchip,rk3066-i2s"; + reg = <0x10118000 0x2000>; + interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&i2s0_bus>; + clocks = <&cru SCLK_I2S0>, <&cru HCLK_I2S0>; + clock-names = "i2s_clk", "i2s_hclk"; + dmas = <&dmac1_s 4>, <&dmac1_s 5>; + dma-names = "tx", "rx"; + rockchip,playback-channels = <8>; + rockchip,capture-channels = <2>; + #sound-dai-cells = <0>; + status = "disabled"; + }; + + i2s1: i2s@1011a000 { + compatible = "rockchip,rk3066-i2s"; + reg = <0x1011a000 0x2000>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&i2s1_bus>; + clocks = <&cru SCLK_I2S1>, <&cru HCLK_I2S1>; + clock-names = "i2s_clk", "i2s_hclk"; + dmas = <&dmac1_s 6>, <&dmac1_s 7>; + dma-names = "tx", "rx"; + rockchip,playback-channels = <2>; + rockchip,capture-channels = <2>; + #sound-dai-cells = <0>; + status = "disabled"; + }; + + i2s2: i2s@1011c000 { + compatible = "rockchip,rk3066-i2s"; + reg = <0x1011c000 0x2000>; + interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&i2s2_bus>; + clocks = <&cru SCLK_I2S2>, <&cru HCLK_I2S2>; + clock-names = "i2s_clk", "i2s_hclk"; + dmas = <&dmac1_s 9>, <&dmac1_s 10>; + dma-names = "tx", "rx"; + rockchip,playback-channels = <2>; + rockchip,capture-channels = <2>; + #sound-dai-cells = <0>; + status = "disabled"; + }; + + cru: clock-controller@20000000 { + compatible = "rockchip,rk3066a-cru"; + reg = <0x20000000 0x1000>; + rockchip,grf = <&grf>; + + #clock-cells = <1>; + #reset-cells = <1>; + assigned-clocks = <&cru PLL_CPLL>, <&cru PLL_GPLL>, + <&cru ACLK_CPU>, <&cru HCLK_CPU>, + <&cru PCLK_CPU>, <&cru ACLK_PERI>, + <&cru HCLK_PERI>, <&cru PCLK_PERI>; + assigned-clock-rates = <400000000>, <594000000>, + <300000000>, <150000000>, + <75000000>, <300000000>, + <150000000>, <75000000>; + }; + + timer2: timer@2000e000 { + compatible = "snps,dw-apb-timer"; + reg = <0x2000e000 0x100>; + interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru SCLK_TIMER2>, <&cru PCLK_TIMER2>; + clock-names = "timer", "pclk"; + }; + + efuse: efuse@20010000 { + compatible = "rockchip,rk3066a-efuse"; + reg = <0x20010000 0x4000>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&cru PCLK_EFUSE>; + clock-names = "pclk_efuse"; + + cpu_leakage: cpu_leakage@17 { + reg = <0x17 0x1>; + }; + }; + + timer0: timer@20038000 { + compatible = "snps,dw-apb-timer"; + reg = <0x20038000 0x100>; + interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru SCLK_TIMER0>, <&cru PCLK_TIMER0>; + clock-names = "timer", "pclk"; + }; + + timer1: timer@2003a000 { + compatible = "snps,dw-apb-timer"; + reg = <0x2003a000 0x100>; + interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru SCLK_TIMER1>, <&cru PCLK_TIMER1>; + clock-names = "timer", "pclk"; + }; + + tsadc: tsadc@20060000 { + compatible = "rockchip,rk3066-tsadc"; + reg = <0x20060000 0x100>; + clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>; + clock-names = "saradc", "apb_pclk"; + interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; + #io-channel-cells = <1>; + resets = <&cru SRST_TSADC>; + reset-names = "saradc-apb"; + status = "disabled"; + }; + + pinctrl: pinctrl { + compatible = "rockchip,rk3066a-pinctrl"; + rockchip,grf = <&grf>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + gpio0: gpio@20034000 { + compatible = "rockchip,gpio-bank"; + reg = <0x20034000 0x100>; + interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru PCLK_GPIO0>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio1: gpio@2003c000 { + compatible = "rockchip,gpio-bank"; + reg = <0x2003c000 0x100>; + interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru PCLK_GPIO1>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio2: gpio@2003e000 { + compatible = "rockchip,gpio-bank"; + reg = <0x2003e000 0x100>; + interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru PCLK_GPIO2>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio3: gpio@20080000 { + compatible = "rockchip,gpio-bank"; + reg = <0x20080000 0x100>; + interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru PCLK_GPIO3>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio4: gpio@20084000 { + compatible = "rockchip,gpio-bank"; + reg = <0x20084000 0x100>; + interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru PCLK_GPIO4>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio6: gpio@2000a000 { + compatible = "rockchip,gpio-bank"; + reg = <0x2000a000 0x100>; + interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru PCLK_GPIO6>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + pcfg_pull_default: pcfg-pull-default { + bias-pull-pin-default; + }; + + pcfg_pull_none: pcfg-pull-none { + bias-disable; + }; + + emac { + emac_xfer: emac-xfer { + rockchip,pins = <1 RK_PC0 2 &pcfg_pull_none>, /* mac_clk */ + <1 RK_PC1 2 &pcfg_pull_none>, /* tx_en */ + <1 RK_PC2 2 &pcfg_pull_none>, /* txd1 */ + <1 RK_PC3 2 &pcfg_pull_none>, /* txd0 */ + <1 RK_PC4 2 &pcfg_pull_none>, /* rx_err */ + <1 RK_PC5 2 &pcfg_pull_none>, /* crs_dvalid */ + <1 RK_PC6 2 &pcfg_pull_none>, /* rxd1 */ + <1 RK_PC7 2 &pcfg_pull_none>; /* rxd0 */ + }; + + emac_mdio: emac-mdio { + rockchip,pins = <1 RK_PD0 2 &pcfg_pull_none>, /* mac_md */ + <1 RK_PD1 2 &pcfg_pull_none>; /* mac_mdclk */ + }; + }; + + emmc { + emmc_clk: emmc-clk { + rockchip,pins = <3 RK_PD7 2 &pcfg_pull_default>; + }; + + emmc_cmd: emmc-cmd { + rockchip,pins = <4 RK_PB1 2 &pcfg_pull_default>; + }; + + emmc_rst: emmc-rst { + rockchip,pins = <4 RK_PB2 2 &pcfg_pull_default>; + }; + + /* + * The data pins are shared between nandc and emmc and + * not accessible through pinctrl. Also they should've + * been already set correctly by firmware, as + * flash/emmc is the boot-device. + */ + }; + + hdmi { + hdmi_hpd: hdmi-hpd { + rockchip,pins = <0 RK_PA0 1 &pcfg_pull_default>; + }; + + hdmii2c_xfer: hdmii2c-xfer { + rockchip,pins = <0 RK_PA1 1 &pcfg_pull_none>, + <0 RK_PA2 1 &pcfg_pull_none>; + }; + }; + + i2c0 { + i2c0_xfer: i2c0-xfer { + rockchip,pins = <2 RK_PD4 1 &pcfg_pull_none>, + <2 RK_PD5 1 &pcfg_pull_none>; + }; + }; + + i2c1 { + i2c1_xfer: i2c1-xfer { + rockchip,pins = <2 RK_PD6 1 &pcfg_pull_none>, + <2 RK_PD7 1 &pcfg_pull_none>; + }; + }; + + i2c2 { + i2c2_xfer: i2c2-xfer { + rockchip,pins = <3 RK_PA0 1 &pcfg_pull_none>, + <3 RK_PA1 1 &pcfg_pull_none>; + }; + }; + + i2c3 { + i2c3_xfer: i2c3-xfer { + rockchip,pins = <3 RK_PA2 2 &pcfg_pull_none>, + <3 RK_PA3 2 &pcfg_pull_none>; + }; + }; + + i2c4 { + i2c4_xfer: i2c4-xfer { + rockchip,pins = <3 RK_PA4 1 &pcfg_pull_none>, + <3 RK_PA5 1 &pcfg_pull_none>; + }; + }; + + pwm0 { + pwm0_out: pwm0-out { + rockchip,pins = <0 RK_PA3 1 &pcfg_pull_none>; + }; + }; + + pwm1 { + pwm1_out: pwm1-out { + rockchip,pins = <0 RK_PA4 1 &pcfg_pull_none>; + }; + }; + + pwm2 { + pwm2_out: pwm2-out { + rockchip,pins = <0 RK_PD6 1 &pcfg_pull_none>; + }; + }; + + pwm3 { + pwm3_out: pwm3-out { + rockchip,pins = <0 RK_PD7 1 &pcfg_pull_none>; + }; + }; + + spi0 { + spi0_clk: spi0-clk { + rockchip,pins = <1 RK_PA5 2 &pcfg_pull_default>; + }; + spi0_cs0: spi0-cs0 { + rockchip,pins = <1 RK_PA4 2 &pcfg_pull_default>; + }; + spi0_tx: spi0-tx { + rockchip,pins = <1 RK_PA7 2 &pcfg_pull_default>; + }; + spi0_rx: spi0-rx { + rockchip,pins = <1 RK_PA6 2 &pcfg_pull_default>; + }; + spi0_cs1: spi0-cs1 { + rockchip,pins = <4 RK_PB7 1 &pcfg_pull_default>; + }; + }; + + spi1 { + spi1_clk: spi1-clk { + rockchip,pins = <2 RK_PC3 2 &pcfg_pull_default>; + }; + spi1_cs0: spi1-cs0 { + rockchip,pins = <2 RK_PC4 2 &pcfg_pull_default>; + }; + spi1_rx: spi1-rx { + rockchip,pins = <2 RK_PC6 2 &pcfg_pull_default>; + }; + spi1_tx: spi1-tx { + rockchip,pins = <2 RK_PC5 2 &pcfg_pull_default>; + }; + spi1_cs1: spi1-cs1 { + rockchip,pins = <2 RK_PC7 2 &pcfg_pull_default>; + }; + }; + + uart0 { + uart0_xfer: uart0-xfer { + rockchip,pins = <1 RK_PA0 1 &pcfg_pull_default>, + <1 RK_PA1 1 &pcfg_pull_default>; + }; + + uart0_cts: uart0-cts { + rockchip,pins = <1 RK_PA2 1 &pcfg_pull_default>; + }; + + uart0_rts: uart0-rts { + rockchip,pins = <1 RK_PA3 1 &pcfg_pull_default>; + }; + }; + + uart1 { + uart1_xfer: uart1-xfer { + rockchip,pins = <1 RK_PA4 1 &pcfg_pull_default>, + <1 RK_PA5 1 &pcfg_pull_default>; + }; + + uart1_cts: uart1-cts { + rockchip,pins = <1 RK_PA6 1 &pcfg_pull_default>; + }; + + uart1_rts: uart1-rts { + rockchip,pins = <1 RK_PA7 1 &pcfg_pull_default>; + }; + }; + + uart2 { + uart2_xfer: uart2-xfer { + rockchip,pins = <1 RK_PB0 1 &pcfg_pull_default>, + <1 RK_PB1 1 &pcfg_pull_default>; + }; + /* no rts / cts for uart2 */ + }; + + uart3 { + uart3_xfer: uart3-xfer { + rockchip,pins = <3 RK_PD3 1 &pcfg_pull_default>, + <3 RK_PD4 1 &pcfg_pull_default>; + }; + + uart3_cts: uart3-cts { + rockchip,pins = <3 RK_PD5 1 &pcfg_pull_default>; + }; + + uart3_rts: uart3-rts { + rockchip,pins = <3 RK_PD6 1 &pcfg_pull_default>; + }; + }; + + sd0 { + sd0_clk: sd0-clk { + rockchip,pins = <3 RK_PB0 1 &pcfg_pull_default>; + }; + + sd0_cmd: sd0-cmd { + rockchip,pins = <3 RK_PB1 1 &pcfg_pull_default>; + }; + + sd0_cd: sd0-cd { + rockchip,pins = <3 RK_PB6 1 &pcfg_pull_default>; + }; + + sd0_wp: sd0-wp { + rockchip,pins = <3 RK_PB7 1 &pcfg_pull_default>; + }; + + sd0_bus1: sd0-bus-width1 { + rockchip,pins = <3 RK_PB2 1 &pcfg_pull_default>; + }; + + sd0_bus4: sd0-bus-width4 { + rockchip,pins = <3 RK_PB2 1 &pcfg_pull_default>, + <3 RK_PB3 1 &pcfg_pull_default>, + <3 RK_PB4 1 &pcfg_pull_default>, + <3 RK_PB5 1 &pcfg_pull_default>; + }; + }; + + sd1 { + sd1_clk: sd1-clk { + rockchip,pins = <3 RK_PC5 1 &pcfg_pull_default>; + }; + + sd1_cmd: sd1-cmd { + rockchip,pins = <3 RK_PC0 1 &pcfg_pull_default>; + }; + + sd1_cd: sd1-cd { + rockchip,pins = <3 RK_PC6 1 &pcfg_pull_default>; + }; + + sd1_wp: sd1-wp { + rockchip,pins = <3 RK_PC7 1 &pcfg_pull_default>; + }; + + sd1_bus1: sd1-bus-width1 { + rockchip,pins = <3 RK_PC1 1 &pcfg_pull_default>; + }; + + sd1_bus4: sd1-bus-width4 { + rockchip,pins = <3 RK_PC1 1 &pcfg_pull_default>, + <3 RK_PC2 1 &pcfg_pull_default>, + <3 RK_PC3 1 &pcfg_pull_default>, + <3 RK_PC4 1 &pcfg_pull_default>; + }; + }; + + i2s0 { + i2s0_bus: i2s0-bus { + rockchip,pins = <0 RK_PA7 1 &pcfg_pull_default>, + <0 RK_PB0 1 &pcfg_pull_default>, + <0 RK_PB1 1 &pcfg_pull_default>, + <0 RK_PB2 1 &pcfg_pull_default>, + <0 RK_PB3 1 &pcfg_pull_default>, + <0 RK_PB4 1 &pcfg_pull_default>, + <0 RK_PB5 1 &pcfg_pull_default>, + <0 RK_PB6 1 &pcfg_pull_default>, + <0 RK_PB7 1 &pcfg_pull_default>; + }; + }; + + i2s1 { + i2s1_bus: i2s1-bus { + rockchip,pins = <0 RK_PC0 1 &pcfg_pull_default>, + <0 RK_PC1 1 &pcfg_pull_default>, + <0 RK_PC2 1 &pcfg_pull_default>, + <0 RK_PC3 1 &pcfg_pull_default>, + <0 RK_PC4 1 &pcfg_pull_default>, + <0 RK_PC5 1 &pcfg_pull_default>; + }; + }; + + i2s2 { + i2s2_bus: i2s2-bus { + rockchip,pins = <0 RK_PD0 1 &pcfg_pull_default>, + <0 RK_PD1 1 &pcfg_pull_default>, + <0 RK_PD2 1 &pcfg_pull_default>, + <0 RK_PD3 1 &pcfg_pull_default>, + <0 RK_PD4 1 &pcfg_pull_default>, + <0 RK_PD5 1 &pcfg_pull_default>; + }; + }; + }; +}; + +&gpu { + compatible = "rockchip,rk3066-mali", "arm,mali-400"; + interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "gp", + "gpmmu", + "pp0", + "ppmmu0", + "pp1", + "ppmmu1", + "pp2", + "ppmmu2", + "pp3", + "ppmmu3"; + power-domains = <&power RK3066_PD_GPU>; +}; + +&grf { + compatible = "rockchip,rk3066-grf", "syscon", "simple-mfd"; + + usbphy: usbphy { + compatible = "rockchip,rk3066a-usb-phy"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + usbphy0: usb-phy@17c { + reg = <0x17c>; + clocks = <&cru SCLK_OTGPHY0>; + clock-names = "phyclk"; + #clock-cells = <0>; + #phy-cells = <0>; + }; + + usbphy1: usb-phy@188 { + reg = <0x188>; + clocks = <&cru SCLK_OTGPHY1>; + clock-names = "phyclk"; + #clock-cells = <0>; + #phy-cells = <0>; + }; + }; +}; + +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_xfer>; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_xfer>; +}; + +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_xfer>; +}; + +&i2c3 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c3_xfer>; +}; + +&i2c4 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c4_xfer>; +}; + +&mmc0 { + clock-frequency = <50000000>; + dmas = <&dmac2 1>; + dma-names = "rx-tx"; + max-frequency = <50000000>; + pinctrl-names = "default"; + pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_cd &sd0_bus4>; +}; + +&mmc1 { + dmas = <&dmac2 3>; + dma-names = "rx-tx"; + pinctrl-names = "default"; + pinctrl-0 = <&sd1_clk &sd1_cmd &sd1_cd &sd1_bus4>; +}; + +&emmc { + dmas = <&dmac2 4>; + dma-names = "rx-tx"; +}; + +&pmu { + power: power-controller { + compatible = "rockchip,rk3066-power-controller"; + #power-domain-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + power-domain@RK3066_PD_VIO { + reg = <RK3066_PD_VIO>; + clocks = <&cru ACLK_LCDC0>, + <&cru ACLK_LCDC1>, + <&cru DCLK_LCDC0>, + <&cru DCLK_LCDC1>, + <&cru HCLK_LCDC0>, + <&cru HCLK_LCDC1>, + <&cru SCLK_CIF1>, + <&cru ACLK_CIF1>, + <&cru HCLK_CIF1>, + <&cru SCLK_CIF0>, + <&cru ACLK_CIF0>, + <&cru HCLK_CIF0>, + <&cru HCLK_HDMI>, + <&cru ACLK_IPP>, + <&cru HCLK_IPP>, + <&cru ACLK_RGA>, + <&cru HCLK_RGA>; + pm_qos = <&qos_lcdc0>, + <&qos_lcdc1>, + <&qos_cif0>, + <&qos_cif1>, + <&qos_ipp>, + <&qos_rga>; + #power-domain-cells = <0>; + }; + + power-domain@RK3066_PD_VIDEO { + reg = <RK3066_PD_VIDEO>; + clocks = <&cru ACLK_VDPU>, + <&cru ACLK_VEPU>, + <&cru HCLK_VDPU>, + <&cru HCLK_VEPU>; + pm_qos = <&qos_vpu>; + #power-domain-cells = <0>; + }; + + power-domain@RK3066_PD_GPU { + reg = <RK3066_PD_GPU>; + clocks = <&cru ACLK_GPU>; + pm_qos = <&qos_gpu>; + #power-domain-cells = <0>; + }; + }; +}; + +&pwm0 { + pinctrl-names = "default"; + pinctrl-0 = <&pwm0_out>; +}; + +&pwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&pwm1_out>; +}; + +&pwm2 { + pinctrl-names = "default"; + pinctrl-0 = <&pwm2_out>; +}; + +&pwm3 { + pinctrl-names = "default"; + pinctrl-0 = <&pwm3_out>; +}; + +&spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&spi0_clk &spi0_tx &spi0_rx &spi0_cs0>; +}; + +&spi1 { + pinctrl-names = "default"; + pinctrl-0 = <&spi1_clk &spi1_tx &spi1_rx &spi1_cs0>; +}; + +&uart0 { + compatible = "rockchip,rk3066-uart", "snps,dw-apb-uart"; + dmas = <&dmac1_s 0>, <&dmac1_s 1>; + dma-names = "tx", "rx"; + pinctrl-names = "default"; + pinctrl-0 = <&uart0_xfer>; +}; + +&uart1 { + compatible = "rockchip,rk3066-uart", "snps,dw-apb-uart"; + dmas = <&dmac1_s 2>, <&dmac1_s 3>; + dma-names = "tx", "rx"; + pinctrl-names = "default"; + pinctrl-0 = <&uart1_xfer>; +}; + +&uart2 { + compatible = "rockchip,rk3066-uart", "snps,dw-apb-uart"; + dmas = <&dmac2 6>, <&dmac2 7>; + dma-names = "tx", "rx"; + pinctrl-names = "default"; + pinctrl-0 = <&uart2_xfer>; +}; + +&uart3 { + compatible = "rockchip,rk3066-uart", "snps,dw-apb-uart"; + dmas = <&dmac2 8>, <&dmac2 9>; + dma-names = "tx", "rx"; + pinctrl-names = "default"; + pinctrl-0 = <&uart3_xfer>; +}; + +&vpu { + power-domains = <&power RK3066_PD_VIDEO>; +}; + +&wdt { + compatible = "rockchip,rk3066-wdt", "snps,dw-wdt"; +}; + +&emac { + compatible = "rockchip,rk3066-emac"; +};

MK808 is a RK3066-based board with 1 USB host and 1 USB OTG port, HDMI and a micro-SD card slot. It also includes on-board NAND and 1GB of SDRAM. Add rk3066a-mk808.dts. Move U-boot specific things in a rk3066a-mk808-u-boot.dtsi file.
Signed-off-by: Johan Jonker jbx6244@gmail.com ---
Changed V8: update dts --- arch/arm/dts/Makefile | 3 + arch/arm/dts/rk3066a-mk808-u-boot.dtsi | 42 +++++ arch/arm/dts/rk3066a-mk808.dts | 216 +++++++++++++++++++++++++ 3 files changed, 261 insertions(+) create mode 100644 arch/arm/dts/rk3066a-mk808-u-boot.dtsi create mode 100644 arch/arm/dts/rk3066a-mk808.dts
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index b3e2a9c9..189f61bd 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -89,6 +89,9 @@ dtb-$(CONFIG_ROCKCHIP_RK3036) += \ dtb-$(CONFIG_ROCKCHIP_RK3128) += \ rk3128-evb.dtb
+dtb-$(CONFIG_ROCKCHIP_RK3066) += \ + rk3066a-mk808.dtb + dtb-$(CONFIG_ROCKCHIP_RK3188) += \ rk3188-radxarock.dtb
diff --git a/arch/arm/dts/rk3066a-mk808-u-boot.dtsi b/arch/arm/dts/rk3066a-mk808-u-boot.dtsi new file mode 100644 index 00000000..6e5990f9 --- /dev/null +++ b/arch/arm/dts/rk3066a-mk808-u-boot.dtsi @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +#include "rk3066a-u-boot.dtsi" + +&cru { + u-boot,dm-pre-reloc; +}; + +&dmc { + compatible = "rockchip,rk3066-dmc", "syscon"; + rockchip,pctl-timing = <0x12c 0xc8 0x1f4 0x1e 0x4e 0x4 0x69 0x6 + 0x3 0x0 0x6 0x5 0xc 0x10 0x6 0x4 + 0x4 0x5 0x4 0x200 0x3 0xa 0x40 0x0 + 0x1 0x5 0x5 0x3 0xc 0x1e 0x100 0x0 + 0x4 0x0>; + rockchip,phy-timing = <0x208c6690 0x690878 0x10022a00 + 0x220 0x40 0x0 0x0>; + rockchip,sdram-params = <0x24716310 0 2 300000000 3 9 0>; +}; + +&mmc0 { + fifo-mode; + max-frequency = <4000000>; + u-boot,dm-spl; +}; + +&mmc1 { + status = "disabled"; +}; + +&noc { + compatible = "rockchip,rk3066-noc", "syscon"; +}; + +&timer2 { + clock-frequency = <24000000>; + u-boot,dm-pre-reloc; +}; + +&uart2 { + u-boot,dm-pre-reloc; +}; diff --git a/arch/arm/dts/rk3066a-mk808.dts b/arch/arm/dts/rk3066a-mk808.dts new file mode 100644 index 00000000..667d57a4 --- /dev/null +++ b/arch/arm/dts/rk3066a-mk808.dts @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2016 Paweł Jarosz paweljarosz3691@gmail.com + */ + +/dts-v1/; +#include <dt-bindings/input/input.h> +#include "rk3066a.dtsi" + +/ { + model = "Rikomagic MK808"; + compatible = "rikomagic,mk808", "rockchip,rk3066a"; + + aliases { + mmc0 = &mmc0; + mmc1 = &mmc1; + }; + + chosen { + stdout-path = "serial2:115200n8"; + }; + + memory@60000000 { + reg = <0x60000000 0x40000000>; + device_type = "memory"; + }; + + adc-keys { + compatible = "adc-keys"; + io-channels = <&saradc 1>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <2500000>; + poll-interval = <100>; + + recovery { + label = "recovery"; + linux,code = <KEY_VENDOR>; + press-threshold-microvolt = <0>; + }; + }; + + gpio-leds { + compatible = "gpio-leds"; + + blue_led: led-0 { + label = "mk808:blue:power"; + gpios = <&gpio0 RK_PA3 GPIO_ACTIVE_HIGH>; + default-state = "off"; + linux,default-trigger = "default-on"; + }; + }; + + hdmi_con { + compatible = "hdmi-connector"; + type = "c"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi_out_con>; + }; + }; + }; + + vcc_2v5: vcc-2v5 { + compatible = "regulator-fixed"; + regulator-name = "vcc_2v5"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + }; + + vcc_io: vcc-io { + compatible = "regulator-fixed"; + regulator-name = "vcc_io"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + vcc_host: usb-host-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&host_drv>; + pinctrl-names = "default"; + regulator-always-on; + regulator-name = "host-pwr"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + startup-delay-us = <100000>; + vin-supply = <&vcc_io>; + }; + + vcc_otg: usb-otg-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio0 RK_PA5 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&otg_drv>; + pinctrl-names = "default"; + regulator-always-on; + regulator-name = "vcc_otg"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + startup-delay-us = <100000>; + vin-supply = <&vcc_io>; + }; + + vcc_sd: sdmmc-regulator { + compatible = "regulator-fixed"; + gpio = <&gpio3 RK_PA7 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&sdmmc_pwr>; + pinctrl-names = "default"; + regulator-name = "vcc_sd"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + startup-delay-us = <100000>; + vin-supply = <&vcc_io>; + }; + + vcc_wifi: sdio-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio3 RK_PD0 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&wifi_pwr>; + pinctrl-names = "default"; + regulator-name = "vcc_wifi"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + startup-delay-us = <100000>; + vin-supply = <&vcc_io>; + }; +}; + +&hdmi { + status = "okay"; +}; + +&hdmi_in_vop1 { + status = "disabled"; +}; + +&hdmi_out { + hdmi_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; +}; + +&mmc0 { + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + vmmc-supply = <&vcc_sd>; + status = "okay"; +}; + +&mmc1 { + bus-width = <4>; + non-removable; + pinctrl-0 = <&sd1_clk &sd1_cmd &sd1_bus4>; + pinctrl-names = "default"; + vmmc-supply = <&vcc_wifi>; + status = "okay"; +}; + +&pinctrl { + usb-host { + host_drv: host-drv { + rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_default>; + }; + }; + + usb-otg { + otg_drv: otg-drv { + rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_default>; + }; + }; + + sdmmc { + sdmmc_pwr: sdmmc-pwr { + rockchip,pins = <3 RK_PA7 RK_FUNC_GPIO &pcfg_pull_default>; + }; + }; + + sdio { + wifi_pwr: wifi-pwr { + rockchip,pins = <3 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&saradc { + vref-supply = <&vcc_2v5>; + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&usb_host { + status = "okay"; +}; + +&usb_otg { + status = "okay"; +}; + +&usbphy { + status = "okay"; +}; + +&vop0 { + status = "okay"; +}; + +&wdt { + status = "okay"; +};

Add include for rk3066.
Signed-off-by: Johan Jonker jbx6244@gmail.com --- arch/arm/include/asm/arch-rk3066/boot0.h | 8 ++++++++ arch/arm/include/asm/arch-rk3066/gpio.h | 8 ++++++++ arch/arm/include/asm/arch-rk3066/timer.h | 6 ++++++ 3 files changed, 22 insertions(+) create mode 100644 arch/arm/include/asm/arch-rk3066/boot0.h create mode 100644 arch/arm/include/asm/arch-rk3066/gpio.h create mode 100644 arch/arm/include/asm/arch-rk3066/timer.h
diff --git a/arch/arm/include/asm/arch-rk3066/boot0.h b/arch/arm/include/asm/arch-rk3066/boot0.h new file mode 100644 index 00000000..28c0fb9a --- /dev/null +++ b/arch/arm/include/asm/arch-rk3066/boot0.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#ifndef __ASM_ARCH_BOOT0_H__ +#define __ASM_ARCH_BOOT0_H__ + +#include <asm/arch-rockchip/boot0.h> + +#endif diff --git a/arch/arm/include/asm/arch-rk3066/gpio.h b/arch/arm/include/asm/arch-rk3066/gpio.h new file mode 100644 index 00000000..a4a3b328 --- /dev/null +++ b/arch/arm/include/asm/arch-rk3066/gpio.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#ifndef __ASM_ARCH_GPIO_H__ +#define __ASM_ARCH_GPIO_H__ + +#include <asm/arch-rockchip/gpio.h> + +#endif diff --git a/arch/arm/include/asm/arch-rk3066/timer.h b/arch/arm/include/asm/arch-rk3066/timer.h new file mode 100644 index 00000000..3bb39428 --- /dev/null +++ b/arch/arm/include/asm/arch-rk3066/timer.h @@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#ifndef __ASM_ARCH_TIMER_H__ +#define __ASM_ARCH_TIMER_H__ + +#endif

Add rk3066_common.h include.
Signed-off-by: Johan Jonker jbx6244@gmail.com --- include/configs/mk808.h | 9 ++++++ include/configs/rk3066_common.h | 56 +++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 include/configs/mk808.h create mode 100644 include/configs/rk3066_common.h
diff --git a/include/configs/mk808.h b/include/configs/mk808.h new file mode 100644 index 00000000..e2ab2b51 --- /dev/null +++ b/include/configs/mk808.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#define ROCKCHIP_DEVICE_SETTINGS +#include <configs/rk3066_common.h> + +#endif diff --git a/include/configs/rk3066_common.h b/include/configs/rk3066_common.h new file mode 100644 index 00000000..b8dc0242 --- /dev/null +++ b/include/configs/rk3066_common.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2015 Google, Inc + */ + +#ifndef __CONFIG_RK3066_COMMON_H +#define __CONFIG_RK3066_COMMON_H + +#define CONFIG_SYS_CACHELINE_SIZE 64 + +#include <asm/arch-rockchip/hardware.h> +#include "rockchip-common.h" + +#define CONFIG_SKIP_LOWLEVEL_INIT_ONLY +#define CONFIG_SYS_CBSIZE 256 + +#define CONFIG_SYS_INIT_SP_ADDR 0x78000000 + +#define CONFIG_ROCKCHIP_MAX_INIT_SIZE (0x10000 - 0xC00) + +#define CONFIG_IRAM_BASE 0x10080000 + +/* spl size max 200k */ +#define CONFIG_SPL_MAX_SIZE 0x32000 + +#define CONFIG_SPL_STACK 0x1008FFFF + +#define CONFIG_SYS_SDRAM_BASE 0x60000000 +#define CONFIG_NR_DRAM_BANKS 1 +#define SDRAM_BANK_SIZE (1024UL << 20UL) +#define SDRAM_MAX_SIZE CONFIG_NR_DRAM_BANKS * SDRAM_BANK_SIZE + +#ifndef CONFIG_SPL_BUILD +/* usb otg */ + +/* usb host support */ +#define ENV_MEM_LAYOUT_SETTINGS \ + "scriptaddr=0x60000000\0" \ + "pxefile_addr_r=0x60100000\0" \ + "fdt_addr_r=0x61f00000\0" \ + "kernel_addr_r=0x62000000\0" \ + "ramdisk_addr_r=0x64000000\0" + +#include <config_distro_bootcmd.h> + +#define CONFIG_EXTRA_ENV_SETTINGS \ + "fdt_high=0x6fffffff\0" \ + "initrd_high=0x6fffffff\0" \ + "partitions=" PARTS_DEFAULT \ + ENV_MEM_LAYOUT_SETTINGS \ + ROCKCHIP_DEVICE_SETTINGS \ + BOOTENV + +#endif /* CONFIG_SPL_BUILD */ + +#endif

Add the core architecture code for the rk3066.
Signed-off-by: Johan Jonker jbx6244@gmail.com --- arch/arm/mach-rockchip/Kconfig | 23 ++++++++ arch/arm/mach-rockchip/Makefile | 1 + arch/arm/mach-rockchip/rk3066/Kconfig | 30 ++++++++++ arch/arm/mach-rockchip/rk3066/Makefile | 5 ++ arch/arm/mach-rockchip/rk3066/clk_rk3066.c | 33 +++++++++++ arch/arm/mach-rockchip/rk3066/rk3066.c | 49 +++++++++++++++++ arch/arm/mach-rockchip/rk3066/syscon_rk3066.c | 55 +++++++++++++++++++ 7 files changed, 196 insertions(+) create mode 100644 arch/arm/mach-rockchip/rk3066/Kconfig create mode 100644 arch/arm/mach-rockchip/rk3066/Makefile create mode 100644 arch/arm/mach-rockchip/rk3066/clk_rk3066.c create mode 100644 arch/arm/mach-rockchip/rk3066/rk3066.c create mode 100644 arch/arm/mach-rockchip/rk3066/syscon_rk3066.c
diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig index a3733e2f..6535d8dd 100644 --- a/arch/arm/mach-rockchip/Kconfig +++ b/arch/arm/mach-rockchip/Kconfig @@ -36,6 +36,28 @@ config ROCKCHIP_RK3036 and video codec support. Peripherals include Gigabit Ethernet, USB2 host and OTG, SDIO, I2S, UART, SPI, I2C and PWMs.
+config ROCKCHIP_RK3066 + bool "Support Rockchip RK3066" + select CPU_V7A + select SPL_BOARD_INIT if SPL + select SUPPORT_SPL + select SUPPORT_TPL + select SPL + select TPL + select TPL_ROCKCHIP_BACK_TO_BROM + select TPL_ROCKCHIP_EARLYRETURN_TO_BROM + imply ROCKCHIP_COMMON_BOARD + imply SPL_ROCKCHIP_COMMON_BOARD + imply SPL_SERIAL + imply TPL_ROCKCHIP_COMMON_BOARD + imply TPL_SERIAL + help + The Rockchip RK3066 is a ARM-based SoC with a dual-core Cortex-A9 + including NEON and GPU, 512KB L2 cache, Mali-400 graphics, two + video interfaces, several memory options and video codec support. + Peripherals include Fast Ethernet, USB2 host and OTG, SDIO, I2S, + UART, SPI, I2C and PWMs. + config ROCKCHIP_RK3128 bool "Support Rockchip RK3128" select CPU_V7A @@ -420,6 +442,7 @@ config ROCKCHIP_SPI_IMAGE
source "arch/arm/mach-rockchip/px30/Kconfig" source "arch/arm/mach-rockchip/rk3036/Kconfig" +source "arch/arm/mach-rockchip/rk3066/Kconfig" source "arch/arm/mach-rockchip/rk3128/Kconfig" source "arch/arm/mach-rockchip/rk3188/Kconfig" source "arch/arm/mach-rockchip/rk322x/Kconfig" diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile index 00aef0ec..6c1c7b8a 100644 --- a/arch/arm/mach-rockchip/Makefile +++ b/arch/arm/mach-rockchip/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_$(SPL_TPL_)RAM) += sdram.o
obj-$(CONFIG_ROCKCHIP_PX30) += px30/ obj-$(CONFIG_ROCKCHIP_RK3036) += rk3036/ +obj-$(CONFIG_ROCKCHIP_RK3066) += rk3066/ obj-$(CONFIG_ROCKCHIP_RK3128) += rk3128/ obj-$(CONFIG_ROCKCHIP_RK3188) += rk3188/ obj-$(CONFIG_ROCKCHIP_RK322X) += rk322x/ diff --git a/arch/arm/mach-rockchip/rk3066/Kconfig b/arch/arm/mach-rockchip/rk3066/Kconfig new file mode 100644 index 00000000..335f49bc --- /dev/null +++ b/arch/arm/mach-rockchip/rk3066/Kconfig @@ -0,0 +1,30 @@ +if ROCKCHIP_RK3066 + +config ROCKCHIP_BOOT_MODE_REG + default 0x20004040 + +config SYS_SOC + default "rk3066" + +config SYS_MALLOC_F_LEN + default 0x0800 + +config SPL_LIBCOMMON_SUPPORT + default y + +config SPL_LIBGENERIC_SUPPORT + default y + +config SPL_SERIAL + default y + +config TPL_LIBCOMMON_SUPPORT + default y + +config TPL_LIBGENERIC_SUPPORT + default y + +config TPL_SERIAL + default y + +endif diff --git a/arch/arm/mach-rockchip/rk3066/Makefile b/arch/arm/mach-rockchip/rk3066/Makefile new file mode 100644 index 00000000..9e2a9d4b --- /dev/null +++ b/arch/arm/mach-rockchip/rk3066/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0+ + +obj-y += clk_rk3066.o +obj-y += rk3066.o +obj-y += syscon_rk3066.o diff --git a/arch/arm/mach-rockchip/rk3066/clk_rk3066.c b/arch/arm/mach-rockchip/rk3066/clk_rk3066.c new file mode 100644 index 00000000..c47526dc --- /dev/null +++ b/arch/arm/mach-rockchip/rk3066/clk_rk3066.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2015 Google, Inc + * Written by Simon Glass sjg@chromium.org + */ + +#include <common.h> +#include <dm.h> +#include <syscon.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/cru_rk3066.h> +#include <linux/err.h> + +int rockchip_get_clk(struct udevice **devp) +{ + return uclass_get_device_by_driver(UCLASS_CLK, + DM_DRIVER_GET(rockchip_rk3066a_cru), devp); +} + +void *rockchip_get_cru(void) +{ + struct rk3066_clk_priv *priv; + struct udevice *dev; + int ret; + + ret = rockchip_get_clk(&dev); + if (ret) + return ERR_PTR(ret); + + priv = dev_get_priv(dev); + + return priv->cru; +} diff --git a/arch/arm/mach-rockchip/rk3066/rk3066.c b/arch/arm/mach-rockchip/rk3066/rk3066.c new file mode 100644 index 00000000..78c7d894 --- /dev/null +++ b/arch/arm/mach-rockchip/rk3066/rk3066.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2016 Rockchip Electronics Co., Ltd + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch-rockchip/bootrom.h> +#include <asm/arch-rockchip/grf_rk3066.h> + +#define GRF_BASE 0x20008000 + +const char * const boot_devices[BROM_LAST_BOOTSOURCE + 1] = { + [BROM_BOOTSOURCE_EMMC] = "/mmc@1021c000", + [BROM_BOOTSOURCE_SD] = "/mmc@10214000", +}; + +void board_debug_uart_init(void) +{ + struct rk3066_grf * const grf = (void *)GRF_BASE; + + /* Enable early UART on the RK3066 */ + rk_clrsetreg(&grf->gpio1b_iomux, + GPIO1B1_MASK | GPIO1B0_MASK, + GPIO1B1_UART2_SOUT << GPIO1B1_SHIFT | + GPIO1B0_UART2_SIN << GPIO1B0_SHIFT); +} + +void spl_board_init(void) +{ + if (!IS_ENABLED(CONFIG_SPL_BUILD)) + return; + + if (IS_ENABLED(CONFIG_SPL_DM_MMC)) { + struct rk3066_grf * const grf = (void *)GRF_BASE; + + rk_clrsetreg(&grf->gpio3b_iomux, + GPIO3B0_MASK | GPIO3B1_MASK | GPIO3B2_MASK | + GPIO3B3_MASK | GPIO3B4_MASK | GPIO3B5_MASK | + GPIO3B6_MASK, + GPIO3B0_SDMMC0_CLKOUT << GPIO3B0_SHIFT | + GPIO3B1_SDMMC0_CMD << GPIO3B1_SHIFT | + GPIO3B2_SDMMC0_DATA0 << GPIO3B2_SHIFT | + GPIO3B3_SDMMC0_DATA1 << GPIO3B3_SHIFT | + GPIO3B4_SDMMC0_DATA2 << GPIO3B4_SHIFT | + GPIO3B5_SDMMC0_DATA3 << GPIO3B5_SHIFT | + GPIO3B6_SDMMC0_DECTN << GPIO3B6_SHIFT); + } +} diff --git a/arch/arm/mach-rockchip/rk3066/syscon_rk3066.c b/arch/arm/mach-rockchip/rk3066/syscon_rk3066.c new file mode 100644 index 00000000..a598f640 --- /dev/null +++ b/arch/arm/mach-rockchip/rk3066/syscon_rk3066.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2015 Google, Inc + * Written by Simon Glass sjg@chromium.org + */ + +#include <common.h> +#include <dm.h> +#include <log.h> +#include <syscon.h> +#include <asm/arch-rockchip/clock.h> + +static const struct udevice_id rk3066_syscon_ids[] = { + { .compatible = "rockchip,rk3066-noc", .data = ROCKCHIP_SYSCON_NOC }, + { .compatible = "rockchip,rk3066-grf", .data = ROCKCHIP_SYSCON_GRF }, + { .compatible = "rockchip,rk3066-pmu", .data = ROCKCHIP_SYSCON_PMU }, + { } +}; + +U_BOOT_DRIVER(syscon_rk3066) = { + .name = "rk3066_syscon", + .id = UCLASS_SYSCON, + .of_match = rk3066_syscon_ids, +}; + +#if CONFIG_IS_ENABLED(OF_PLATDATA) +static int rk3066_syscon_bind_of_plat(struct udevice *dev) +{ + dev->driver_data = dev->driver->of_match->data; + debug("syscon: %s %d\n", dev->name, (uint)dev->driver_data); + + return 0; +} + +U_BOOT_DRIVER(rockchip_rk3066_noc) = { + .name = "rockchip_rk3066_noc", + .id = UCLASS_SYSCON, + .of_match = rk3066_syscon_ids, + .bind = rk3066_syscon_bind_of_plat, +}; + +U_BOOT_DRIVER(rockchip_rk3066_grf) = { + .name = "rockchip_rk3066_grf", + .id = UCLASS_SYSCON, + .of_match = rk3066_syscon_ids + 1, + .bind = rk3066_syscon_bind_of_plat, +}; + +U_BOOT_DRIVER(rockchip_rk3066_pmu) = { + .name = "rockchip_rk3066_pmu", + .id = UCLASS_SYSCON, + .of_match = rk3066_syscon_ids + 2, + .bind = rk3066_syscon_bind_of_plat, +}; +#endif

MK808 is a RK3066-based board with 1 USB host and 1 USB OTG port, HDMI and a micro-SD card slot. It also includes on-board NAND and 1GB of SDRAM.
Signed-off-by: Johan Jonker jbx6244@gmail.com --- arch/arm/mach-rockchip/rk3066/Kconfig | 9 +++++++++ board/rikomagic/mk808/Kconfig | 15 +++++++++++++++ board/rikomagic/mk808/MAINTAINERS | 6 ++++++ board/rikomagic/mk808/Makefile | 3 +++ board/rikomagic/mk808/mk808.c | 3 +++ 5 files changed, 36 insertions(+) create mode 100644 board/rikomagic/mk808/Kconfig create mode 100644 board/rikomagic/mk808/MAINTAINERS create mode 100644 board/rikomagic/mk808/Makefile create mode 100644 board/rikomagic/mk808/mk808.c
diff --git a/arch/arm/mach-rockchip/rk3066/Kconfig b/arch/arm/mach-rockchip/rk3066/Kconfig index 335f49bc..95d7fc8a 100644 --- a/arch/arm/mach-rockchip/rk3066/Kconfig +++ b/arch/arm/mach-rockchip/rk3066/Kconfig @@ -1,5 +1,12 @@ if ROCKCHIP_RK3066
+config TARGET_MK808 + bool "MK808" + help + MK808 is a RK3066-based board with 1 USB host and 1 USB OTG port, + HDMI and a micro-SD card slot. It also includes on-board NAND + and 1GB of SDRAM. + config ROCKCHIP_BOOT_MODE_REG default 0x20004040
@@ -27,4 +34,6 @@ config TPL_LIBGENERIC_SUPPORT config TPL_SERIAL default y
+source "board/rikomagic/mk808/Kconfig" + endif diff --git a/board/rikomagic/mk808/Kconfig b/board/rikomagic/mk808/Kconfig new file mode 100644 index 00000000..4abad7e7 --- /dev/null +++ b/board/rikomagic/mk808/Kconfig @@ -0,0 +1,15 @@ +if TARGET_MK808 + +config SYS_BOARD + default "mk808" + +config SYS_VENDOR + default "rikomagic" + +config SYS_CONFIG_NAME + default "mk808" + +config BOARD_SPECIFIC_OPTIONS # dummy + def_bool y + +endif diff --git a/board/rikomagic/mk808/MAINTAINERS b/board/rikomagic/mk808/MAINTAINERS new file mode 100644 index 00000000..b3ef6adb --- /dev/null +++ b/board/rikomagic/mk808/MAINTAINERS @@ -0,0 +1,6 @@ +MK808 +M: Johan Jonker jbx6244@gmail.com +S: Maintained +F: board/rikomagic/mk808 +F: configs/mk808_defconfig +F: include/configs/mk808.h diff --git a/board/rikomagic/mk808/Makefile b/board/rikomagic/mk808/Makefile new file mode 100644 index 00000000..a4d16884 --- /dev/null +++ b/board/rikomagic/mk808/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0+ + +obj-y += mk808.o diff --git a/board/rikomagic/mk808/mk808.c b/board/rikomagic/mk808/mk808.c new file mode 100644 index 00000000..e0bfc6f3 --- /dev/null +++ b/board/rikomagic/mk808/mk808.c @@ -0,0 +1,3 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <common.h>

This commit adds the default configuration file and relevant description for a MK808 board.
Signed-off-by: Johan Jonker jbx6244@gmail.com ---
Changed V8: use default log level ENV_IS_NOWHERE --- configs/mk808_defconfig | 99 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 configs/mk808_defconfig
diff --git a/configs/mk808_defconfig b/configs/mk808_defconfig new file mode 100644 index 00000000..a0e71d1f --- /dev/null +++ b/configs/mk808_defconfig @@ -0,0 +1,99 @@ +CONFIG_ARM=y +# CONFIG_SPL_SYS_THUMB_BUILD is not set +# CONFIG_TPL_SYS_THUMB_BUILD is not set +# CONFIG_SPL_USE_ARCH_MEMCPY is not set +# CONFIG_SPL_USE_ARCH_MEMSET is not set +CONFIG_ARCH_ROCKCHIP=y +CONFIG_SYS_TEXT_BASE=0x60408000 +CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_NR_DRAM_BANKS=1 +CONFIG_ENV_SIZE=0x8000 +CONFIG_DEFAULT_DEVICE_TREE="rk3066a-mk808" +CONFIG_SPL_TEXT_BASE=0x60000000 +CONFIG_ROCKCHIP_RK3066=y +CONFIG_TPL_TEXT_BASE=0x10080C04 +CONFIG_TPL_MAX_SIZE=32764 +CONFIG_TPL_STACK=0x1008FFFF +CONFIG_TARGET_MK808=y +CONFIG_SPL_STACK_R_ADDR=0x70000000 +CONFIG_DEBUG_UART_BASE=0x20064000 +CONFIG_DEBUG_UART_CLOCK=24000000 +CONFIG_SPL_FS_FAT=y +CONFIG_SPL_PAYLOAD="u-boot.bin" +CONFIG_DEBUG_UART=y +CONFIG_SYS_LOAD_ADDR=0x70800800 +CONFIG_SD_BOOT=y +CONFIG_USE_PREBOOT=y +CONFIG_DEFAULT_FDT_FILE="rk3066a-mk808.dtb" +# CONFIG_DISPLAY_CPUINFO is not set +CONFIG_DISPLAY_BOARDINFO_LATE=y +CONFIG_BOARD_LATE_INIT=y +CONFIG_SPL_STACK_R=y +CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN=0x200000 +CONFIG_SPL_SEPARATE_BSS=y +CONFIG_SPL_FS_EXT4=y +CONFIG_SYS_MMCSD_FS_BOOT_PARTITION=2 +CONFIG_TPL_NEEDS_SEPARATE_TEXT_BASE=y +CONFIG_TPL_NEEDS_SEPARATE_STACK=y +# CONFIG_BOOTM_PLAN9 is not set +# CONFIG_BOOTM_RTEMS is not set +# CONFIG_BOOTM_VXWORKS is not set +CONFIG_CMD_GPT=y +CONFIG_CMD_MMC=y +# CONFIG_CMD_SETEXPR is not set +CONFIG_CMD_CACHE=y +CONFIG_CMD_TIME=y +CONFIG_CMD_REGULATOR=y +CONFIG_SPL_OF_CONTROL=y +CONFIG_TPL_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_OF_DTB_PROPS_REMOVE=y +CONFIG_SPL_OF_PLATDATA=y +CONFIG_TPL_OF_PLATDATA=y +CONFIG_SYS_RELOC_GD_ENV_ADDR=y +# CONFIG_NET is not set +CONFIG_TPL_DM=y +# CONFIG_DM_WARN is not set +CONFIG_REGMAP=y +CONFIG_SPL_REGMAP=y +CONFIG_TPL_REGMAP=y +CONFIG_SYSCON=y +CONFIG_SPL_SYSCON=y +CONFIG_TPL_SYSCON=y +# CONFIG_SIMPLE_BUS is not set +# CONFIG_SPL_SIMPLE_BUS is not set +# CONFIG_TPL_BLK is not set +CONFIG_CLK=y +CONFIG_SPL_CLK=y +CONFIG_TPL_CLK=y +CONFIG_ROCKCHIP_GPIO=y +# CONFIG_SPL_DM_I2C is not set +CONFIG_LED=y +CONFIG_MMC_IO_VOLTAGE=y +CONFIG_SPL_MMC_IO_VOLTAGE=y +CONFIG_MMC_UHS_SUPPORT=y +CONFIG_SPL_MMC_UHS_SUPPORT=y +CONFIG_MMC_DW=y +CONFIG_MMC_DW_ROCKCHIP=y +CONFIG_SF_DEFAULT_SPEED=20000000 +CONFIG_PINCTRL=y +CONFIG_DM_PMIC=y +# CONFIG_SPL_PMIC_CHILDREN is not set +CONFIG_DM_REGULATOR_FIXED=y +CONFIG_DM_REGULATOR_GPIO=y +CONFIG_RAM=y +CONFIG_SPL_RAM=y +CONFIG_TPL_RAM=y +CONFIG_DM_RESET=y +# CONFIG_REQUIRE_SERIAL_CONSOLE is not set +CONFIG_DEBUG_UART_SHIFT=2 +CONFIG_DEBUG_UART_ANNOUNCE=y +CONFIG_ROCKCHIP_SERIAL=y +CONFIG_SYSRESET=y +CONFIG_TIMER=y +CONFIG_SPL_TIMER=y +CONFIG_TPL_TIMER=y +CONFIG_DESIGNWARE_APB_TIMER=y +CONFIG_SPL_TINY_MEMSET=y +CONFIG_ERRNO_STR=y +# CONFIG_TPL_OF_LIBFDT is not set

Add rk3066 support to rkcommon.c
Signed-off-by: Johan Jonker jbx6244@gmail.com --- tools/rkcommon.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/tools/rkcommon.c b/tools/rkcommon.c index 29f2676c..860785f8 100644 --- a/tools/rkcommon.c +++ b/tools/rkcommon.c @@ -123,6 +123,7 @@ struct spl_info { static struct spl_info spl_infos[] = { { "px30", "RK33", 0x2800, false, RK_HEADER_V1 }, { "rk3036", "RK30", 0x1000, false, RK_HEADER_V1 }, + { "rk3066", "RK30", 0x8000 - 0x800, true, RK_HEADER_V1 }, { "rk3128", "RK31", 0x1800, false, RK_HEADER_V1 }, { "rk3188", "RK31", 0x8000 - 0x800, true, RK_HEADER_V1 }, { "rk322x", "RK32", 0x8000 - 0x1000, false, RK_HEADER_V1 },

Add rk3066 Rikomagic MK808 to the list of mainline supported Rockchip boards.
Signed-off-by: Johan Jonker jbx6244@gmail.com --- doc/board/rockchip/rockchip.rst | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/doc/board/rockchip/rockchip.rst b/doc/board/rockchip/rockchip.rst index 144cb98e..a4fca88b 100644 --- a/doc/board/rockchip/rockchip.rst +++ b/doc/board/rockchip/rockchip.rst @@ -24,6 +24,8 @@ List of mainline supported Rockchip boards: * rk3036 - Rockchip Evb-RK3036 (evb-rk3036) - Kylin (kylin_rk3036) +* rk3066 + - Rikomagic MK808 (mk808) * rk3128 - Rockchip Evb-RK3128 (evb-rk3128) * rk3188
participants (2)
-
Johan Jonker
-
Sean Anderson