From 16a92a426ee3d8bcd4aba3ee039c6e94031d7fbd Mon Sep 17 00:00:00 2001 From: Tang Yun ping Date: Wed, 5 Sep 2018 11:19:18 +0800 Subject: [PATCH] rockchip dmc: add rockchip dmc code This dmc code is prepare for ddr test tool to scanning ddr freq, normal firmware no need to enable it. Current version only support PX30/RK3326 and RK3328/RK3228H, CONFIG_ROCKCHIP_DMC=y to enable it Change-Id: I25360846bb5af74eb82bdc6e64bdaa2d55ab0f64 Signed-off-by: Tang Yun ping --- .../include/asm/arch-rockchip/rockchip_dmc.h | 15 + .../asm/arch-rockchip/rockchip_smccc.h | 10 + drivers/ram/Kconfig | 2 + drivers/ram/rockchip/Kconfig | 4 + drivers/ram/rockchip/Makefile | 3 + drivers/ram/rockchip/rockchip_dmc.c | 888 ++++++++++++++++++ drivers/ram/rockchip/rockchip_sdram.c | 43 +- drivers/ram/rockchip/sdram_rk3328.c | 23 +- 8 files changed, 966 insertions(+), 22 deletions(-) create mode 100644 arch/arm/include/asm/arch-rockchip/rockchip_dmc.h create mode 100644 drivers/ram/rockchip/Kconfig create mode 100644 drivers/ram/rockchip/rockchip_dmc.c diff --git a/arch/arm/include/asm/arch-rockchip/rockchip_dmc.h b/arch/arm/include/asm/arch-rockchip/rockchip_dmc.h new file mode 100644 index 0000000000..555998e6b7 --- /dev/null +++ b/arch/arm/include/asm/arch-rockchip/rockchip_dmc.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2018 Rockchip Electronics Co., Ltd + */ + +#ifndef __ROCKCHIP_DMC_H_ +#define __ROCKCHIP_DMC_H_ +#include + +int rockchip_ddrclk_sip_set_rate_v2(unsigned long drate); +unsigned long rockchip_ddrclk_sip_recalc_rate_v2(void); +unsigned long rockchip_ddrclk_sip_round_rate_v2(unsigned long rate); +int rockchip_dmcfreq_probe(struct udevice *dev); + +#endif diff --git a/arch/arm/include/asm/arch-rockchip/rockchip_smccc.h b/arch/arm/include/asm/arch-rockchip/rockchip_smccc.h index 0167f3c4df..e16ef93eb9 100644 --- a/arch/arm/include/asm/arch-rockchip/rockchip_smccc.h +++ b/arch/arm/include/asm/arch-rockchip/rockchip_smccc.h @@ -24,6 +24,16 @@ #define SIP_REMOTECTL_CFG 0x8200000b #define PSCI_SIP_VPU_RESET 0x8200000c +#define ROCKCHIP_SIP_CONFIG_DRAM_INIT 0x00 +#define ROCKCHIP_SIP_CONFIG_DRAM_SET_RATE 0x01 +#define ROCKCHIP_SIP_CONFIG_DRAM_ROUND_RATE 0x02 +#define ROCKCHIP_SIP_CONFIG_DRAM_SET_AT_SR 0x03 +#define ROCKCHIP_SIP_CONFIG_DRAM_GET_BW 0x04 +#define ROCKCHIP_SIP_CONFIG_DRAM_GET_RATE 0x05 +#define ROCKCHIP_SIP_CONFIG_DRAM_CLR_IRQ 0x06 +#define ROCKCHIP_SIP_CONFIG_DRAM_SET_PARAM 0x07 +#define ROCKCHIP_SIP_CONFIG_DRAM_GET_VERSION 0x08 + /* Rockchip Sip version */ #define SIP_IMPLEMENT_V1 (1) #define SIP_IMPLEMENT_V2 (2) diff --git a/drivers/ram/Kconfig b/drivers/ram/Kconfig index d26c590d9f..2cf8adefb6 100644 --- a/drivers/ram/Kconfig +++ b/drivers/ram/Kconfig @@ -46,3 +46,5 @@ config RAMDISK_READONLY depends on DM_RAMDISK help This enables the read only ramdisk support. + +source "drivers/ram/rockchip/Kconfig" diff --git a/drivers/ram/rockchip/Kconfig b/drivers/ram/rockchip/Kconfig new file mode 100644 index 0000000000..ab21b34daf --- /dev/null +++ b/drivers/ram/rockchip/Kconfig @@ -0,0 +1,4 @@ +config ROCKCHIP_DMC + bool "ROCKCHIP DMC" + help + This enable dram devfreq driver. diff --git a/drivers/ram/rockchip/Makefile b/drivers/ram/rockchip/Makefile index 9b12db19d4..44c95981ac 100644 --- a/drivers/ram/rockchip/Makefile +++ b/drivers/ram/rockchip/Makefile @@ -17,3 +17,6 @@ obj-$(CONFIG_ROCKCHIP_PX30) += rockchip_sdram.o obj-$(CONFIG_ROCKCHIP_RK1808) = rockchip_sdram.o obj-$(CONFIG_ROCKCHIP_RK3036) = rockchip_sdram.o obj-$(CONFIG_ROCKCHIP_RK3308) = rockchip_sdram.o +ifeq ($(CONFIG_SPL_BUILD)$(CONFIG_TPL_BUILD),) +obj-$(CONFIG_ROCKCHIP_DMC) += rockchip_dmc.o +endif diff --git a/drivers/ram/rockchip/rockchip_dmc.c b/drivers/ram/rockchip/rockchip_dmc.c new file mode 100644 index 0000000000..37aaa6eab5 --- /dev/null +++ b/drivers/ram/rockchip/rockchip_dmc.c @@ -0,0 +1,888 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * (C) Copyright 2018 Rockchip Electronics Co., Ltd + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DTS_PAR_OFFSET (4096) + +struct share_params { + u32 hz; + u32 lcdc_type; + u32 vop; + u32 vop_dclk_mode; + u32 sr_idle_en; + u32 addr_mcu_el3; + /* + * 1: need to wait flag1 + * 0: never wait flag1 + */ + u32 wait_flag1; + /* + * 1: need to wait flag1 + * 0: never wait flag1 + */ + u32 wait_flag0; + u32 complt_hwirq; + /* if need, add parameter after */ +}; + +static struct share_params *ddr_psci_param; + +/* hope this define can adapt all future platfor */ +static const char * const rk3328_dts_timing[] = { + "ddr3_speed_bin", + "ddr4_speed_bin", + "pd_idle", + "sr_idle", + "sr_mc_gate_idle", + "srpd_lite_idle", + "standby_idle", + + "auto_pd_dis_freq", + "auto_sr_dis_freq", + "ddr3_dll_dis_freq", + "ddr4_dll_dis_freq", + "phy_dll_dis_freq", + + "ddr3_odt_dis_freq", + "phy_ddr3_odt_dis_freq", + "ddr3_drv", + "ddr3_odt", + "phy_ddr3_ca_drv", + "phy_ddr3_ck_drv", + "phy_ddr3_dq_drv", + "phy_ddr3_odt", + + "lpddr3_odt_dis_freq", + "phy_lpddr3_odt_dis_freq", + "lpddr3_drv", + "lpddr3_odt", + "phy_lpddr3_ca_drv", + "phy_lpddr3_ck_drv", + "phy_lpddr3_dq_drv", + "phy_lpddr3_odt", + + "lpddr4_odt_dis_freq", + "phy_lpddr4_odt_dis_freq", + "lpddr4_drv", + "lpddr4_dq_odt", + "lpddr4_ca_odt", + "phy_lpddr4_ca_drv", + "phy_lpddr4_ck_cs_drv", + "phy_lpddr4_dq_drv", + "phy_lpddr4_odt", + + "ddr4_odt_dis_freq", + "phy_ddr4_odt_dis_freq", + "ddr4_drv", + "ddr4_odt", + "phy_ddr4_ca_drv", + "phy_ddr4_ck_drv", + "phy_ddr4_dq_drv", + "phy_ddr4_odt", +}; + +static const char * const px30_dts_timing[] = { + "ddr2_speed_bin", + "ddr3_speed_bin", + "ddr4_speed_bin", + "pd_idle", + "sr_idle", + "sr_mc_gate_idle", + "srpd_lite_idle", + "standby_idle", + + "auto_pd_dis_freq", + "auto_sr_dis_freq", + "ddr2_dll_dis_freq", + "ddr3_dll_dis_freq", + "ddr4_dll_dis_freq", + "phy_dll_dis_freq", + + "ddr2_odt_dis_freq", + "phy_ddr2_odt_dis_freq", + "ddr2_drv", + "ddr2_odt", + "phy_ddr2_ca_drv", + "phy_ddr2_ck_drv", + "phy_ddr2_dq_drv", + "phy_ddr2_odt", + + "ddr3_odt_dis_freq", + "phy_ddr3_odt_dis_freq", + "ddr3_drv", + "ddr3_odt", + "phy_ddr3_ca_drv", + "phy_ddr3_ck_drv", + "phy_ddr3_dq_drv", + "phy_ddr3_odt", + + "phy_lpddr2_odt_dis_freq", + "lpddr2_drv", + "phy_lpddr2_ca_drv", + "phy_lpddr2_ck_drv", + "phy_lpddr2_dq_drv", + "phy_lpddr2_odt", + + "lpddr3_odt_dis_freq", + "phy_lpddr3_odt_dis_freq", + "lpddr3_drv", + "lpddr3_odt", + "phy_lpddr3_ca_drv", + "phy_lpddr3_ck_drv", + "phy_lpddr3_dq_drv", + "phy_lpddr3_odt", + + "lpddr4_odt_dis_freq", + "phy_lpddr4_odt_dis_freq", + "lpddr4_drv", + "lpddr4_dq_odt", + "lpddr4_ca_odt", + "phy_lpddr4_ca_drv", + "phy_lpddr4_ck_cs_drv", + "phy_lpddr4_dq_drv", + "phy_lpddr4_odt", + + "ddr4_odt_dis_freq", + "phy_ddr4_odt_dis_freq", + "ddr4_drv", + "ddr4_odt", + "phy_ddr4_ca_drv", + "phy_ddr4_ck_drv", + "phy_ddr4_dq_drv", + "phy_ddr4_odt", +}; + +static const char * const rk3328_dts_ca_timing[] = { + "ddr3a1_ddr4a9_de-skew", + "ddr3a0_ddr4a10_de-skew", + "ddr3a3_ddr4a6_de-skew", + "ddr3a2_ddr4a4_de-skew", + "ddr3a5_ddr4a8_de-skew", + "ddr3a4_ddr4a5_de-skew", + "ddr3a7_ddr4a11_de-skew", + "ddr3a6_ddr4a7_de-skew", + "ddr3a9_ddr4a0_de-skew", + "ddr3a8_ddr4a13_de-skew", + "ddr3a11_ddr4a3_de-skew", + "ddr3a10_ddr4cs0_de-skew", + "ddr3a13_ddr4a2_de-skew", + "ddr3a12_ddr4ba1_de-skew", + "ddr3a15_ddr4odt0_de-skew", + "ddr3a14_ddr4a1_de-skew", + "ddr3ba1_ddr4a15_de-skew", + "ddr3ba0_ddr4bg0_de-skew", + "ddr3ras_ddr4cke_de-skew", + "ddr3ba2_ddr4ba0_de-skew", + "ddr3we_ddr4bg1_de-skew", + "ddr3cas_ddr4a12_de-skew", + "ddr3ckn_ddr4ckn_de-skew", + "ddr3ckp_ddr4ckp_de-skew", + "ddr3cke_ddr4a16_de-skew", + "ddr3odt0_ddr4a14_de-skew", + "ddr3cs0_ddr4act_de-skew", + "ddr3reset_ddr4reset_de-skew", + "ddr3cs1_ddr4cs1_de-skew", + "ddr3odt1_ddr4odt1_de-skew", +}; + +static const char * const rk3328_dts_cs0_timing[] = { + "cs0_dm0_rx_de-skew", + "cs0_dm0_tx_de-skew", + "cs0_dq0_rx_de-skew", + "cs0_dq0_tx_de-skew", + "cs0_dq1_rx_de-skew", + "cs0_dq1_tx_de-skew", + "cs0_dq2_rx_de-skew", + "cs0_dq2_tx_de-skew", + "cs0_dq3_rx_de-skew", + "cs0_dq3_tx_de-skew", + "cs0_dq4_rx_de-skew", + "cs0_dq4_tx_de-skew", + "cs0_dq5_rx_de-skew", + "cs0_dq5_tx_de-skew", + "cs0_dq6_rx_de-skew", + "cs0_dq6_tx_de-skew", + "cs0_dq7_rx_de-skew", + "cs0_dq7_tx_de-skew", + "cs0_dqs0_rx_de-skew", + "cs0_dqs0p_tx_de-skew", + "cs0_dqs0n_tx_de-skew", + + "cs0_dm1_rx_de-skew", + "cs0_dm1_tx_de-skew", + "cs0_dq8_rx_de-skew", + "cs0_dq8_tx_de-skew", + "cs0_dq9_rx_de-skew", + "cs0_dq9_tx_de-skew", + "cs0_dq10_rx_de-skew", + "cs0_dq10_tx_de-skew", + "cs0_dq11_rx_de-skew", + "cs0_dq11_tx_de-skew", + "cs0_dq12_rx_de-skew", + "cs0_dq12_tx_de-skew", + "cs0_dq13_rx_de-skew", + "cs0_dq13_tx_de-skew", + "cs0_dq14_rx_de-skew", + "cs0_dq14_tx_de-skew", + "cs0_dq15_rx_de-skew", + "cs0_dq15_tx_de-skew", + "cs0_dqs1_rx_de-skew", + "cs0_dqs1p_tx_de-skew", + "cs0_dqs1n_tx_de-skew", + + "cs0_dm2_rx_de-skew", + "cs0_dm2_tx_de-skew", + "cs0_dq16_rx_de-skew", + "cs0_dq16_tx_de-skew", + "cs0_dq17_rx_de-skew", + "cs0_dq17_tx_de-skew", + "cs0_dq18_rx_de-skew", + "cs0_dq18_tx_de-skew", + "cs0_dq19_rx_de-skew", + "cs0_dq19_tx_de-skew", + "cs0_dq20_rx_de-skew", + "cs0_dq20_tx_de-skew", + "cs0_dq21_rx_de-skew", + "cs0_dq21_tx_de-skew", + "cs0_dq22_rx_de-skew", + "cs0_dq22_tx_de-skew", + "cs0_dq23_rx_de-skew", + "cs0_dq23_tx_de-skew", + "cs0_dqs2_rx_de-skew", + "cs0_dqs2p_tx_de-skew", + "cs0_dqs2n_tx_de-skew", + + "cs0_dm3_rx_de-skew", + "cs0_dm3_tx_de-skew", + "cs0_dq24_rx_de-skew", + "cs0_dq24_tx_de-skew", + "cs0_dq25_rx_de-skew", + "cs0_dq25_tx_de-skew", + "cs0_dq26_rx_de-skew", + "cs0_dq26_tx_de-skew", + "cs0_dq27_rx_de-skew", + "cs0_dq27_tx_de-skew", + "cs0_dq28_rx_de-skew", + "cs0_dq28_tx_de-skew", + "cs0_dq29_rx_de-skew", + "cs0_dq29_tx_de-skew", + "cs0_dq30_rx_de-skew", + "cs0_dq30_tx_de-skew", + "cs0_dq31_rx_de-skew", + "cs0_dq31_tx_de-skew", + "cs0_dqs3_rx_de-skew", + "cs0_dqs3p_tx_de-skew", + "cs0_dqs3n_tx_de-skew", +}; + +static const char * const rk3328_dts_cs1_timing[] = { + "cs1_dm0_rx_de-skew", + "cs1_dm0_tx_de-skew", + "cs1_dq0_rx_de-skew", + "cs1_dq0_tx_de-skew", + "cs1_dq1_rx_de-skew", + "cs1_dq1_tx_de-skew", + "cs1_dq2_rx_de-skew", + "cs1_dq2_tx_de-skew", + "cs1_dq3_rx_de-skew", + "cs1_dq3_tx_de-skew", + "cs1_dq4_rx_de-skew", + "cs1_dq4_tx_de-skew", + "cs1_dq5_rx_de-skew", + "cs1_dq5_tx_de-skew", + "cs1_dq6_rx_de-skew", + "cs1_dq6_tx_de-skew", + "cs1_dq7_rx_de-skew", + "cs1_dq7_tx_de-skew", + "cs1_dqs0_rx_de-skew", + "cs1_dqs0p_tx_de-skew", + "cs1_dqs0n_tx_de-skew", + + "cs1_dm1_rx_de-skew", + "cs1_dm1_tx_de-skew", + "cs1_dq8_rx_de-skew", + "cs1_dq8_tx_de-skew", + "cs1_dq9_rx_de-skew", + "cs1_dq9_tx_de-skew", + "cs1_dq10_rx_de-skew", + "cs1_dq10_tx_de-skew", + "cs1_dq11_rx_de-skew", + "cs1_dq11_tx_de-skew", + "cs1_dq12_rx_de-skew", + "cs1_dq12_tx_de-skew", + "cs1_dq13_rx_de-skew", + "cs1_dq13_tx_de-skew", + "cs1_dq14_rx_de-skew", + "cs1_dq14_tx_de-skew", + "cs1_dq15_rx_de-skew", + "cs1_dq15_tx_de-skew", + "cs1_dqs1_rx_de-skew", + "cs1_dqs1p_tx_de-skew", + "cs1_dqs1n_tx_de-skew", + + "cs1_dm2_rx_de-skew", + "cs1_dm2_tx_de-skew", + "cs1_dq16_rx_de-skew", + "cs1_dq16_tx_de-skew", + "cs1_dq17_rx_de-skew", + "cs1_dq17_tx_de-skew", + "cs1_dq18_rx_de-skew", + "cs1_dq18_tx_de-skew", + "cs1_dq19_rx_de-skew", + "cs1_dq19_tx_de-skew", + "cs1_dq20_rx_de-skew", + "cs1_dq20_tx_de-skew", + "cs1_dq21_rx_de-skew", + "cs1_dq21_tx_de-skew", + "cs1_dq22_rx_de-skew", + "cs1_dq22_tx_de-skew", + "cs1_dq23_rx_de-skew", + "cs1_dq23_tx_de-skew", + "cs1_dqs2_rx_de-skew", + "cs1_dqs2p_tx_de-skew", + "cs1_dqs2n_tx_de-skew", + + "cs1_dm3_rx_de-skew", + "cs1_dm3_tx_de-skew", + "cs1_dq24_rx_de-skew", + "cs1_dq24_tx_de-skew", + "cs1_dq25_rx_de-skew", + "cs1_dq25_tx_de-skew", + "cs1_dq26_rx_de-skew", + "cs1_dq26_tx_de-skew", + "cs1_dq27_rx_de-skew", + "cs1_dq27_tx_de-skew", + "cs1_dq28_rx_de-skew", + "cs1_dq28_tx_de-skew", + "cs1_dq29_rx_de-skew", + "cs1_dq29_tx_de-skew", + "cs1_dq30_rx_de-skew", + "cs1_dq30_tx_de-skew", + "cs1_dq31_rx_de-skew", + "cs1_dq31_tx_de-skew", + "cs1_dqs3_rx_de-skew", + "cs1_dqs3p_tx_de-skew", + "cs1_dqs3n_tx_de-skew", +}; + +struct rk3328_ddr_dts_config_timing { + unsigned int ddr3_speed_bin; + unsigned int ddr4_speed_bin; + unsigned int pd_idle; + unsigned int sr_idle; + unsigned int sr_mc_gate_idle; + unsigned int srpd_lite_idle; + unsigned int standby_idle; + + unsigned int auto_pd_dis_freq; + unsigned int auto_sr_dis_freq; + /* for ddr3 only */ + unsigned int ddr3_dll_dis_freq; + /* for ddr4 only */ + unsigned int ddr4_dll_dis_freq; + unsigned int phy_dll_dis_freq; + + unsigned int ddr3_odt_dis_freq; + unsigned int phy_ddr3_odt_dis_freq; + unsigned int ddr3_drv; + unsigned int ddr3_odt; + unsigned int phy_ddr3_ca_drv; + unsigned int phy_ddr3_ck_drv; + unsigned int phy_ddr3_dq_drv; + unsigned int phy_ddr3_odt; + + unsigned int lpddr3_odt_dis_freq; + unsigned int phy_lpddr3_odt_dis_freq; + unsigned int lpddr3_drv; + unsigned int lpddr3_odt; + unsigned int phy_lpddr3_ca_drv; + unsigned int phy_lpddr3_ck_drv; + unsigned int phy_lpddr3_dq_drv; + unsigned int phy_lpddr3_odt; + + unsigned int lpddr4_odt_dis_freq; + unsigned int phy_lpddr4_odt_dis_freq; + unsigned int lpddr4_drv; + unsigned int lpddr4_dq_odt; + unsigned int lpddr4_ca_odt; + unsigned int phy_lpddr4_ca_drv; + unsigned int phy_lpddr4_ck_cs_drv; + unsigned int phy_lpddr4_dq_drv; + unsigned int phy_lpddr4_odt; + + unsigned int ddr4_odt_dis_freq; + unsigned int phy_ddr4_odt_dis_freq; + unsigned int ddr4_drv; + unsigned int ddr4_odt; + unsigned int phy_ddr4_ca_drv; + unsigned int phy_ddr4_ck_drv; + unsigned int phy_ddr4_dq_drv; + unsigned int phy_ddr4_odt; + + unsigned int ca_skew[15]; + unsigned int cs0_skew[44]; + unsigned int cs1_skew[44]; + + unsigned int available; +}; + +struct px30_ddr_dts_config_timing { + unsigned int ddr2_speed_bin; + unsigned int ddr3_speed_bin; + unsigned int ddr4_speed_bin; + unsigned int pd_idle; + unsigned int sr_idle; + unsigned int sr_mc_gate_idle; + unsigned int srpd_lite_idle; + unsigned int standby_idle; + + unsigned int auto_pd_dis_freq; + unsigned int auto_sr_dis_freq; + /* for ddr2 only */ + unsigned int ddr2_dll_dis_freq; + /* for ddr3 only */ + unsigned int ddr3_dll_dis_freq; + /* for ddr4 only */ + unsigned int ddr4_dll_dis_freq; + unsigned int phy_dll_dis_freq; + + unsigned int ddr2_odt_dis_freq; + unsigned int phy_ddr2_odt_dis_freq; + unsigned int ddr2_drv; + unsigned int ddr2_odt; + unsigned int phy_ddr2_ca_drv; + unsigned int phy_ddr2_ck_drv; + unsigned int phy_ddr2_dq_drv; + unsigned int phy_ddr2_odt; + + unsigned int ddr3_odt_dis_freq; + unsigned int phy_ddr3_odt_dis_freq; + unsigned int ddr3_drv; + unsigned int ddr3_odt; + unsigned int phy_ddr3_ca_drv; + unsigned int phy_ddr3_ck_drv; + unsigned int phy_ddr3_dq_drv; + unsigned int phy_ddr3_odt; + + unsigned int phy_lpddr2_odt_dis_freq; + unsigned int lpddr2_drv; + unsigned int phy_lpddr2_ca_drv; + unsigned int phy_lpddr2_ck_drv; + unsigned int phy_lpddr2_dq_drv; + unsigned int phy_lpddr2_odt; + + unsigned int lpddr3_odt_dis_freq; + unsigned int phy_lpddr3_odt_dis_freq; + unsigned int lpddr3_drv; + unsigned int lpddr3_odt; + unsigned int phy_lpddr3_ca_drv; + unsigned int phy_lpddr3_ck_drv; + unsigned int phy_lpddr3_dq_drv; + unsigned int phy_lpddr3_odt; + + unsigned int lpddr4_odt_dis_freq; + unsigned int phy_lpddr4_odt_dis_freq; + unsigned int lpddr4_drv; + unsigned int lpddr4_dq_odt; + unsigned int lpddr4_ca_odt; + unsigned int phy_lpddr4_ca_drv; + unsigned int phy_lpddr4_ck_cs_drv; + unsigned int phy_lpddr4_dq_drv; + unsigned int phy_lpddr4_odt; + + unsigned int ddr4_odt_dis_freq; + unsigned int phy_ddr4_odt_dis_freq; + unsigned int ddr4_drv; + unsigned int ddr4_odt; + unsigned int phy_ddr4_ca_drv; + unsigned int phy_ddr4_ck_drv; + unsigned int phy_ddr4_dq_drv; + unsigned int phy_ddr4_odt; + + unsigned int ca_skew[15]; + unsigned int cs0_skew[44]; + unsigned int cs1_skew[44]; + + unsigned int available; +}; + +struct rk3328_ddr_de_skew_setting { + unsigned int ca_de_skew[30]; + unsigned int cs0_de_skew[84]; + unsigned int cs1_de_skew[84]; +}; + +static void +rk3328_de_skew_setting_2_register(struct rk3328_ddr_de_skew_setting *de_skew, + struct rk3328_ddr_dts_config_timing *tim) +{ + u32 n; + u32 offset; + u32 shift; + + memset_io(tim->ca_skew, 0, sizeof(tim->ca_skew)); + memset_io(tim->cs0_skew, 0, sizeof(tim->cs0_skew)); + memset_io(tim->cs1_skew, 0, sizeof(tim->cs1_skew)); + + /* CA de-skew */ + for (n = 0; n < ARRAY_SIZE(de_skew->ca_de_skew); n++) { + offset = n / 2; + shift = n % 2; + /* 0 => 4; 1 => 0 */ + shift = (shift == 0) ? 4 : 0; + tim->ca_skew[offset] &= ~(0xf << shift); + tim->ca_skew[offset] |= (de_skew->ca_de_skew[n] << shift); + } + + /* CS0 data de-skew */ + for (n = 0; n < ARRAY_SIZE(de_skew->cs0_de_skew); n++) { + offset = ((n / 21) * 11) + ((n % 21) / 2); + shift = ((n % 21) % 2); + if ((n % 21) == 20) + shift = 0; + else + /* 0 => 4; 1 => 0 */ + shift = (shift == 0) ? 4 : 0; + tim->cs0_skew[offset] &= ~(0xf << shift); + tim->cs0_skew[offset] |= (de_skew->cs0_de_skew[n] << shift); + } + + /* CS1 data de-skew */ + for (n = 0; n < ARRAY_SIZE(de_skew->cs1_de_skew); n++) { + offset = ((n / 21) * 11) + ((n % 21) / 2); + shift = ((n % 21) % 2); + if ((n % 21) == 20) + shift = 0; + else + /* 0 => 4; 1 => 0 */ + shift = (shift == 0) ? 4 : 0; + tim->cs1_skew[offset] &= ~(0xf << shift); + tim->cs1_skew[offset] |= (de_skew->cs1_de_skew[n] << shift); + } +} + +static void px30_de_skew_set_2_reg(struct rk3328_ddr_de_skew_setting *de_skew, + struct px30_ddr_dts_config_timing *tim) +{ + u32 n; + u32 offset; + u32 shift; + + memset_io(tim->ca_skew, 0, sizeof(tim->ca_skew)); + memset_io(tim->cs0_skew, 0, sizeof(tim->cs0_skew)); + memset_io(tim->cs1_skew, 0, sizeof(tim->cs1_skew)); + + /* CA de-skew */ + for (n = 0; n < ARRAY_SIZE(de_skew->ca_de_skew); n++) { + offset = n / 2; + shift = n % 2; + /* 0 => 4; 1 => 0 */ + shift = (shift == 0) ? 4 : 0; + tim->ca_skew[offset] &= ~(0xf << shift); + tim->ca_skew[offset] |= (de_skew->ca_de_skew[n] << shift); + } + + /* CS0 data de-skew */ + for (n = 0; n < ARRAY_SIZE(de_skew->cs0_de_skew); n++) { + offset = ((n / 21) * 11) + ((n % 21) / 2); + shift = ((n % 21) % 2); + if ((n % 21) == 20) + shift = 0; + else + /* 0 => 4; 1 => 0 */ + shift = (shift == 0) ? 4 : 0; + tim->cs0_skew[offset] &= ~(0xf << shift); + tim->cs0_skew[offset] |= (de_skew->cs0_de_skew[n] << shift); + } + + /* CS1 data de-skew */ + for (n = 0; n < ARRAY_SIZE(de_skew->cs1_de_skew); n++) { + offset = ((n / 21) * 11) + ((n % 21) / 2); + shift = ((n % 21) % 2); + if ((n % 21) == 20) + shift = 0; + else + /* 0 => 4; 1 => 0 */ + shift = (shift == 0) ? 4 : 0; + tim->cs1_skew[offset] &= ~(0xf << shift); + tim->cs1_skew[offset] |= (de_skew->cs1_de_skew[n] << shift); + } +} + +static void of_get_rk3328_timings(struct udevice *dev, uint32_t *timing) +{ + struct device_node *np_tim; + u32 *p; + struct rk3328_ddr_dts_config_timing *dts_timing; + struct rk3328_ddr_de_skew_setting *de_skew; + int ret = 0; + u32 i; + + dts_timing = + (struct rk3328_ddr_dts_config_timing *)(timing + + DTS_PAR_OFFSET / 4); + + np_tim = of_parse_phandle(ofnode_to_np(dev_ofnode(dev)), + "ddr_timing", 0); + if (!np_tim) { + ret = -EINVAL; + goto end; + } + de_skew = malloc(sizeof(*de_skew)); + if (!de_skew) { + ret = -ENOMEM; + goto end; + } + p = (u32 *)dts_timing; + for (i = 0; i < ARRAY_SIZE(rk3328_dts_timing); i++) + ret |= ofnode_read_u32(np_to_ofnode(np_tim), + rk3328_dts_timing[i], p + i); + + p = (u32 *)de_skew->ca_de_skew; + for (i = 0; i < ARRAY_SIZE(rk3328_dts_ca_timing); i++) + ret |= ofnode_read_u32(np_to_ofnode(np_tim), + rk3328_dts_ca_timing[i], p + i); + p = (u32 *)de_skew->cs0_de_skew; + for (i = 0; i < ARRAY_SIZE(rk3328_dts_cs0_timing); i++) + ret |= ofnode_read_u32(np_to_ofnode(np_tim), + rk3328_dts_cs0_timing[i], p + i); + p = (u32 *)de_skew->cs1_de_skew; + for (i = 0; i < ARRAY_SIZE(rk3328_dts_cs1_timing); i++) + ret |= ofnode_read_u32(np_to_ofnode(np_tim), + rk3328_dts_cs1_timing[i], p + i); + + if (!ret) + rk3328_de_skew_setting_2_register(de_skew, dts_timing); + free(de_skew); +end: + if (!ret) { + dts_timing->available = 1; + } else { + dts_timing->available = 0; + printf("of_get_ddr_timings: fail\n"); + } +} + +static void of_get_px30_timings(struct udevice *dev, uint32_t *timing) +{ + struct device_node *np_tim; + u32 *p; + struct px30_ddr_dts_config_timing *dts_timing; + struct rk3328_ddr_de_skew_setting *de_skew; + int ret = 0; + u32 i; + + dts_timing = + (struct px30_ddr_dts_config_timing *)(timing + + DTS_PAR_OFFSET / 4); + + np_tim = of_parse_phandle(ofnode_to_np(dev_ofnode(dev)), + "ddr_timing", 0); + if (!np_tim) { + ret = -EINVAL; + goto end; + } + de_skew = malloc(sizeof(*de_skew)); + if (!de_skew) { + ret = -ENOMEM; + goto end; + } + p = (u32 *)dts_timing; + for (i = 0; i < ARRAY_SIZE(px30_dts_timing); i++) + ret |= ofnode_read_u32(np_to_ofnode(np_tim), px30_dts_timing[i], + p + i); + p = (u32 *)de_skew->ca_de_skew; + for (i = 0; i < ARRAY_SIZE(rk3328_dts_ca_timing); i++) + ret |= ofnode_read_u32(np_to_ofnode(np_tim), + rk3328_dts_ca_timing[i], p + i); + p = (u32 *)de_skew->cs0_de_skew; + for (i = 0; i < ARRAY_SIZE(rk3328_dts_cs0_timing); i++) + ret |= ofnode_read_u32(np_to_ofnode(np_tim), + rk3328_dts_cs0_timing[i], p + i); + p = (u32 *)de_skew->cs1_de_skew; + for (i = 0; i < ARRAY_SIZE(rk3328_dts_cs1_timing); i++) + ret |= ofnode_read_u32(np_to_ofnode(np_tim), + rk3328_dts_cs1_timing[i], p + i); + if (!ret) + px30_de_skew_set_2_reg(de_skew, dts_timing); + free(de_skew); +end: + if (!ret) { + dts_timing->available = 1; + } else { + dts_timing->available = 0; + printf("of_get_ddr_timings: fail\n"); + } +} + +static __maybe_unused int rk3328_devfreq_init(struct udevice *dev) +{ + struct arm_smccc_res res; + u32 size; + + res = sip_smc_dram(0, 0, + ROCKCHIP_SIP_CONFIG_DRAM_GET_VERSION); + printf("current ATF version 0x%lx!\n", res.a1); + if (res.a0 || res.a1 < 0x101) { + printf("trusted firmware need to update or is invalid!\n"); + return -ENXIO; + } + + printf("read tf version 0x%lx!\n", res.a1); + + /* + * first 4KB is used for interface parameters + * after 4KB * N is dts parameters + */ + size = sizeof(struct rk3328_ddr_dts_config_timing); + res = sip_smc_request_share_mem(DIV_ROUND_UP(size, 4096) + 1, + SHARE_PAGE_TYPE_DDR); + if (res.a0 != 0) { + printf("no ATF memory for init\n"); + return -ENOMEM; + } + ddr_psci_param = (struct share_params *)res.a1; + of_get_rk3328_timings(dev, (uint32_t *)ddr_psci_param); + + flush_cache((unsigned long)ddr_psci_param, + (DIV_ROUND_UP(size, 4096) + 1) * 0x1000); + + res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, + ROCKCHIP_SIP_CONFIG_DRAM_INIT); + if (res.a0) { + printf("rockchip_sip_config_dram_init error:%lx\n", + res.a0); + return -ENOMEM; + } + + return 0; +} + +static __maybe_unused int px30_devfreq_init(struct udevice *dev) +{ + struct arm_smccc_res res; + u32 size; + + res = sip_smc_dram(0, 0, + ROCKCHIP_SIP_CONFIG_DRAM_GET_VERSION); + printf("current ATF version 0x%lx!\n", res.a1); + if (res.a0 || res.a1 < 0x103) { + printf("trusted firmware need to update or is invalid!\n"); + return -ENXIO; + } + + printf("read tf version 0x%lx!\n", res.a1); + + /* + * first 4KB is used for interface parameters + * after 4KB * N is dts parameters + */ + size = sizeof(struct px30_ddr_dts_config_timing); + res = sip_smc_request_share_mem(DIV_ROUND_UP(size, 4096) + 1, + SHARE_PAGE_TYPE_DDR); + if (res.a0 != 0) { + printf("no ATF memory for init\n"); + return -ENOMEM; + } + + ddr_psci_param = (struct share_params *)res.a1; + of_get_px30_timings(dev, (uint32_t *)ddr_psci_param); + + flush_cache((unsigned long)ddr_psci_param, + (DIV_ROUND_UP(size, 4096) + 1) * 0x1000); + res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, + ROCKCHIP_SIP_CONFIG_DRAM_INIT); + if (res.a0) { + printf("rockchip_sip_config_dram_init error:%lx\n", + res.a0); + return -ENOMEM; + } + + return 0; +} + +int rockchip_ddrclk_sip_set_rate_v2(unsigned long drate) +{ + struct share_params *p; + struct arm_smccc_res res; + + p = ddr_psci_param; + + p->hz = drate; + p->lcdc_type = 0; + p->wait_flag1 = 0; + p->wait_flag0 = 0; + p->complt_hwirq = 105; + + flush_cache((unsigned long)ddr_psci_param, sizeof(struct share_params)); + res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, + ROCKCHIP_SIP_CONFIG_DRAM_SET_RATE); + + return res.a0; +} + +unsigned long rockchip_ddrclk_sip_recalc_rate_v2(void) +{ + struct arm_smccc_res res; + + res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, + ROCKCHIP_SIP_CONFIG_DRAM_GET_RATE); + if (!res.a0) + return res.a1; + else + return 0; +} + +unsigned long rockchip_ddrclk_sip_round_rate_v2(unsigned long rate) +{ + struct share_params *p; + struct arm_smccc_res res; + + p = ddr_psci_param; + + p->hz = rate; + + flush_cache((unsigned long)ddr_psci_param, sizeof(struct share_params)); + + res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, + ROCKCHIP_SIP_CONFIG_DRAM_ROUND_RATE); + if (!res.a0) + return res.a1; + else + return 0; +} + +int rockchip_dmcfreq_probe(struct udevice *dev) +{ + int ret; + +#if defined(CONFIG_ROCKCHIP_PX30) + ret = px30_devfreq_init(dev); +#elif defined(CONFIG_ROCKCHIP_RK3328) + ret = rk3328_devfreq_init(dev); +#else + ret = -1; + printf("Unsupported chip type\n"); +#endif + if (ret) + return ret; + + printf("dram freq:%ld Hz\n", rockchip_ddrclk_sip_recalc_rate_v2()); + + return 0; +} diff --git a/drivers/ram/rockchip/rockchip_sdram.c b/drivers/ram/rockchip/rockchip_sdram.c index aa65623108..78e15eb142 100644 --- a/drivers/ram/rockchip/rockchip_sdram.c +++ b/drivers/ram/rockchip/rockchip_sdram.c @@ -12,6 +12,7 @@ #include #include #include +#include #include DECLARE_GLOBAL_DATA_PTR; @@ -23,35 +24,47 @@ struct dram_info { static int dmc_probe(struct udevice *dev) { + int ret = 0; struct dram_info *priv = dev_get_priv(dev); + if (!(gd->flags & GD_FLG_RELOC)) { #if defined(CONFIG_ROCKCHIP_RK3036) - struct rk3036_grf *grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + struct rk3036_grf *grf = + syscon_get_first_range(ROCKCHIP_SYSCON_GRF); - priv->info.size = rockchip_sdram_size((phys_addr_t)&grf->os_reg[1]); + priv->info.size = + rockchip_sdram_size((phys_addr_t)&grf->os_reg[1]); #elif defined(CONFIG_ROCKCHIP_RK3308) - struct rk3308_grf *grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + struct rk3308_grf *grf = + syscon_get_first_range(ROCKCHIP_SYSCON_GRF); - priv->info.size = rockchip_sdram_size((phys_addr_t)&grf->os_reg2); + priv->info.size = + rockchip_sdram_size((phys_addr_t)&grf->os_reg2); #elif defined(CONFIG_ROCKCHIP_PX30) - struct px30_pmugrf *pmugrf = - syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF); + struct px30_pmugrf *pmugrf = + syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF); - priv->info.size = - rockchip_sdram_size((phys_addr_t)&pmugrf->os_reg[2]); + priv->info.size = + rockchip_sdram_size((phys_addr_t)&pmugrf->os_reg[2]); #elif defined(CONFIG_ROCKCHIP_RK1808) - struct rk1808_pmugrf *pmugrf = - syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF); + struct rk1808_pmugrf *pmugrf = + syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF); - priv->info.size = - rockchip_sdram_size((phys_addr_t)&pmugrf->os_reg[2]); + priv->info.size = + rockchip_sdram_size((phys_addr_t)&pmugrf->os_reg[2]); #else #error chip error #endif + priv->info.base = CONFIG_SYS_SDRAM_BASE; + } else { +#if defined(CONFIG_ROCKCHIP_PX30) +#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_ROCKCHIP_DMC) + ret = rockchip_dmcfreq_probe(dev); +#endif +#endif + } - priv->info.base = CONFIG_SYS_SDRAM_BASE; - - return 0; + return ret; } static int dmc_get_info(struct udevice *dev, struct ram_info *info) diff --git a/drivers/ram/rockchip/sdram_rk3328.c b/drivers/ram/rockchip/sdram_rk3328.c index 7782d6a690..1941e1c9e2 100644 --- a/drivers/ram/rockchip/sdram_rk3328.c +++ b/drivers/ram/rockchip/sdram_rk3328.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -981,17 +982,20 @@ static int rk3328_dmc_ofdata_to_platdata(struct udevice *dev) static int rk3328_dmc_probe(struct udevice *dev) { + int ret = 0; #ifdef CONFIG_TPL_BUILD if (rk3328_dmc_init(dev)) return 0; #else - struct dram_info *priv = dev_get_priv(dev); + struct dram_info *priv; - priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); - debug("%s: grf=%p\n", __func__, priv->grf); - priv->info.base = CONFIG_SYS_SDRAM_BASE; - priv->info.size = rockchip_sdram_size( - (phys_addr_t)&priv->grf->os_reg[2]); + if (!(gd->flags & GD_FLG_RELOC)) { + priv = dev_get_priv(dev); + priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + debug("%s: grf=%p\n", __func__, priv->grf); + priv->info.base = CONFIG_SYS_SDRAM_BASE; + priv->info.size = + rockchip_sdram_size((phys_addr_t)&priv->grf->os_reg[2]); #ifdef CONFIG_SPL_BUILD struct ddr_param ddr_parem; @@ -1000,8 +1004,13 @@ static int rk3328_dmc_probe(struct udevice *dev) ddr_parem.para[1] = priv->info.size; rockchip_setup_ddr_param(&ddr_parem); #endif + } else { +#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_ROCKCHIP_DMC) + ret = rockchip_dmcfreq_probe(dev); #endif - return 0; + } +#endif + return ret; } static int rk3328_dmc_get_info(struct udevice *dev, struct ram_info *info)