1*d8e26cc8SYouMin Chen // SPDX-License-Identifier: GPL-2.0+ 2*d8e26cc8SYouMin Chen /* 3*d8e26cc8SYouMin Chen * (C) Copyright 2021 Rockchip Electronics Co., Ltd. 4*d8e26cc8SYouMin Chen */ 5*d8e26cc8SYouMin Chen 6*d8e26cc8SYouMin Chen #include <common.h> 7*d8e26cc8SYouMin Chen #include <dm.h> 8*d8e26cc8SYouMin Chen #include <syscon.h> 9*d8e26cc8SYouMin Chen #include <asm/io.h> 10*d8e26cc8SYouMin Chen #include <dm/of_access.h> 11*d8e26cc8SYouMin Chen #include <asm/arch/clock.h> 12*d8e26cc8SYouMin Chen #include <asm/arch/rockchip_smccc.h> 13*d8e26cc8SYouMin Chen #include <asm/arch/sdram.h> 14*d8e26cc8SYouMin Chen #include <asm/arch/sdram_common.h> 15*d8e26cc8SYouMin Chen 16*d8e26cc8SYouMin Chen #define DDR2_PARAMS_PHANDLE_NAME "ddr2_params" 17*d8e26cc8SYouMin Chen #define DDR3_PARAMS_PHANDLE_NAME "ddr3_params" 18*d8e26cc8SYouMin Chen #define DDR4_PARAMS_PHANDLE_NAME "ddr4_params" 19*d8e26cc8SYouMin Chen #define LPDDR2_PARAMS_PHANDLE_NAME "lpddr2_params" 20*d8e26cc8SYouMin Chen #define LPDDR3_PARAMS_PHANDLE_NAME "lpddr3_params" 21*d8e26cc8SYouMin Chen #define LPDDR4_PARAMS_PHANDLE_NAME "lpddr4_params" 22*d8e26cc8SYouMin Chen #define LPDDR4X_PARAMS_PHANDLE_NAME "lpddr4x_params" 23*d8e26cc8SYouMin Chen #define LPDDR5_PARAMS_PHANDLE_NAME "lpddr5_params" 24*d8e26cc8SYouMin Chen 25*d8e26cc8SYouMin Chen #define DTS_PAR_OFFSET (4096) 26*d8e26cc8SYouMin Chen #define PARAMS_INVALID_VAL (0xff00aa99) 27*d8e26cc8SYouMin Chen 28*d8e26cc8SYouMin Chen #define PMUGRF_OS_REG(n) (0x200 + (n) * 4) 29*d8e26cc8SYouMin Chen 30*d8e26cc8SYouMin Chen /* there is a matching relationship, modify it with caution */ 31*d8e26cc8SYouMin Chen static char *dmc_fsp_params[] = { 32*d8e26cc8SYouMin Chen "debug_print_level", 33*d8e26cc8SYouMin Chen /* if need, add parameter after */ 34*d8e26cc8SYouMin Chen }; 35*d8e26cc8SYouMin Chen 36*d8e26cc8SYouMin Chen /* there is a matching relationship, modify it with caution */ 37*d8e26cc8SYouMin Chen static char *ddr_params_v1[] = { 38*d8e26cc8SYouMin Chen /* version information V1.00 */ 39*d8e26cc8SYouMin Chen "version", 40*d8e26cc8SYouMin Chen "expanded_version", 41*d8e26cc8SYouMin Chen "reserved", 42*d8e26cc8SYouMin Chen /* freq info, freq_0 is final frequency, unit: MHz */ 43*d8e26cc8SYouMin Chen "freq_0", 44*d8e26cc8SYouMin Chen "freq_1", 45*d8e26cc8SYouMin Chen "freq_2", 46*d8e26cc8SYouMin Chen "freq_3", 47*d8e26cc8SYouMin Chen "freq_4", 48*d8e26cc8SYouMin Chen "freq_5", 49*d8e26cc8SYouMin Chen /* power save setting */ 50*d8e26cc8SYouMin Chen "pd_idle", 51*d8e26cc8SYouMin Chen "sr_idle", 52*d8e26cc8SYouMin Chen "sr_mc_gate_idle", 53*d8e26cc8SYouMin Chen "srpd_lite_idle", 54*d8e26cc8SYouMin Chen "standby_idle", 55*d8e26cc8SYouMin Chen "pd_dis_freq", 56*d8e26cc8SYouMin Chen "sr_dis_freq", 57*d8e26cc8SYouMin Chen "dram_dll_dis_freq", 58*d8e26cc8SYouMin Chen "phy_dll_dis_freq", 59*d8e26cc8SYouMin Chen /* drv when odt on */ 60*d8e26cc8SYouMin Chen "phy_dq_drv_odten", 61*d8e26cc8SYouMin Chen "phy_ca_drv_odten", 62*d8e26cc8SYouMin Chen "phy_clk_drv_odten", 63*d8e26cc8SYouMin Chen "dram_dq_drv_odten", 64*d8e26cc8SYouMin Chen /* drv when odt off */ 65*d8e26cc8SYouMin Chen "phy_dq_drv_odtoff", 66*d8e26cc8SYouMin Chen "phy_ca_drv_odtoff", 67*d8e26cc8SYouMin Chen "phy_clk_drv_odtoff", 68*d8e26cc8SYouMin Chen "dram_dq_drv_odtoff", 69*d8e26cc8SYouMin Chen /* odt info */ 70*d8e26cc8SYouMin Chen "dram_odt", 71*d8e26cc8SYouMin Chen "phy_odt", 72*d8e26cc8SYouMin Chen "phy_odt_puup_en", 73*d8e26cc8SYouMin Chen "phy_odt_pudn_en", 74*d8e26cc8SYouMin Chen /* odt enable freq */ 75*d8e26cc8SYouMin Chen "dram_dq_odt_en_freq", 76*d8e26cc8SYouMin Chen "phy_odt_en_freq", 77*d8e26cc8SYouMin Chen /* slew rate when odt enable */ 78*d8e26cc8SYouMin Chen "phy_dq_sr_odten", 79*d8e26cc8SYouMin Chen "phy_ca_sr_odten", 80*d8e26cc8SYouMin Chen "phy_clk_sr_odten", 81*d8e26cc8SYouMin Chen /* slew rate when odt disable */ 82*d8e26cc8SYouMin Chen "phy_dq_sr_odtoff", 83*d8e26cc8SYouMin Chen "phy_ca_sr_odtoff", 84*d8e26cc8SYouMin Chen "phy_clk_sr_odtoff", 85*d8e26cc8SYouMin Chen /* ssmod setting*/ 86*d8e26cc8SYouMin Chen "ssmod_downspread", 87*d8e26cc8SYouMin Chen "ssmod_div", 88*d8e26cc8SYouMin Chen "ssmod_spread", 89*d8e26cc8SYouMin Chen /* 2T mode */ 90*d8e26cc8SYouMin Chen "mode_2t", 91*d8e26cc8SYouMin Chen /* speed bin */ 92*d8e26cc8SYouMin Chen "speed_bin", 93*d8e26cc8SYouMin Chen /* dram extended temperature support */ 94*d8e26cc8SYouMin Chen "dram_ext_temp", 95*d8e26cc8SYouMin Chen /* byte map */ 96*d8e26cc8SYouMin Chen "byte_map", 97*d8e26cc8SYouMin Chen /* dq map */ 98*d8e26cc8SYouMin Chen "dq_map_cs0_dq_l", 99*d8e26cc8SYouMin Chen "dq_map_cs0_dq_h", 100*d8e26cc8SYouMin Chen "dq_map_cs1_dq_l", 101*d8e26cc8SYouMin Chen "dq_map_cs1_dq_h", 102*d8e26cc8SYouMin Chen /* for LPDDR4 and LPDDR4X */ 103*d8e26cc8SYouMin Chen /* odt info */ 104*d8e26cc8SYouMin Chen "lp4_ca_odt", 105*d8e26cc8SYouMin Chen "lp4_drv_pu_cal_odten", 106*d8e26cc8SYouMin Chen "lp4_drv_pu_cal_odtoff", 107*d8e26cc8SYouMin Chen "phy_lp4_drv_pulldown_en_odten", 108*d8e26cc8SYouMin Chen "phy_lp4_drv_pulldown_en_odtoff", 109*d8e26cc8SYouMin Chen /* odt enable freq */ 110*d8e26cc8SYouMin Chen "lp4_ca_odt_en_freq", 111*d8e26cc8SYouMin Chen /* lp4 cs drv info and ca odt info */ 112*d8e26cc8SYouMin Chen "phy_lp4_cs_drv_odten", 113*d8e26cc8SYouMin Chen "phy_lp4_cs_drv_odtoff", 114*d8e26cc8SYouMin Chen "lp4_odte_ck_en", 115*d8e26cc8SYouMin Chen "lp4_odte_cs_en", 116*d8e26cc8SYouMin Chen "lp4_odtd_ca_en", 117*d8e26cc8SYouMin Chen /* lp4 vref info when odt enable */ 118*d8e26cc8SYouMin Chen "phy_lp4_dq_vref_odten", 119*d8e26cc8SYouMin Chen "lp4_dq_vref_odten", 120*d8e26cc8SYouMin Chen "lp4_ca_vref_odten", 121*d8e26cc8SYouMin Chen /* lp4 vref info when odt disable */ 122*d8e26cc8SYouMin Chen "phy_lp4_dq_vref_odtoff", 123*d8e26cc8SYouMin Chen "lp4_dq_vref_odtoff", 124*d8e26cc8SYouMin Chen "lp4_ca_vref_odtoff", 125*d8e26cc8SYouMin Chen /* if need, add parameter after and change the minor version. */ 126*d8e26cc8SYouMin Chen }; 127*d8e26cc8SYouMin Chen 128*d8e26cc8SYouMin Chen static int get_atf_version(void) 129*d8e26cc8SYouMin Chen { 130*d8e26cc8SYouMin Chen struct arm_smccc_res res; 131*d8e26cc8SYouMin Chen 132*d8e26cc8SYouMin Chen res = sip_smc_dram(0, 0, ROCKCHIP_SIP_CONFIG_DRAM_GET_VERSION); 133*d8e26cc8SYouMin Chen 134*d8e26cc8SYouMin Chen if (res.a0) 135*d8e26cc8SYouMin Chen return -ENOMEM; 136*d8e26cc8SYouMin Chen else 137*d8e26cc8SYouMin Chen return res.a1; 138*d8e26cc8SYouMin Chen } 139*d8e26cc8SYouMin Chen 140*d8e26cc8SYouMin Chen static int dmc_fsp_probe(struct udevice *dev) 141*d8e26cc8SYouMin Chen { 142*d8e26cc8SYouMin Chen struct device_node *np_params; 143*d8e26cc8SYouMin Chen struct arm_smccc_res res; 144*d8e26cc8SYouMin Chen void *pmugrf_base; 145*d8e26cc8SYouMin Chen int *p = NULL; 146*d8e26cc8SYouMin Chen char *phandle_name = NULL; 147*d8e26cc8SYouMin Chen char **ddr_params; 148*d8e26cc8SYouMin Chen int ddr_params_version; 149*d8e26cc8SYouMin Chen u32 dram_type, os_reg2_val, os_reg3_val; 150*d8e26cc8SYouMin Chen u32 i = 0, count = 0, size = 0; 151*d8e26cc8SYouMin Chen ulong atf_version_limit; 152*d8e26cc8SYouMin Chen 153*d8e26cc8SYouMin Chen atf_version_limit = dev_get_driver_data(dev); 154*d8e26cc8SYouMin Chen if (get_atf_version() < atf_version_limit) { 155*d8e26cc8SYouMin Chen printf("%s: trusted firmware need to update or is invalid!\n", __func__); 156*d8e26cc8SYouMin Chen printf("%s: current ATF version 0x%x, required version 0x%lx\n", 157*d8e26cc8SYouMin Chen __func__, get_atf_version(), atf_version_limit); 158*d8e26cc8SYouMin Chen return 0; 159*d8e26cc8SYouMin Chen } 160*d8e26cc8SYouMin Chen 161*d8e26cc8SYouMin Chen pmugrf_base = syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF); 162*d8e26cc8SYouMin Chen os_reg2_val = readl(pmugrf_base + PMUGRF_OS_REG(2)); 163*d8e26cc8SYouMin Chen os_reg3_val = readl(pmugrf_base + PMUGRF_OS_REG(3)); 164*d8e26cc8SYouMin Chen dram_type = SYS_REG_DEC_DDRTYPE_V3(os_reg2_val, os_reg3_val); 165*d8e26cc8SYouMin Chen 166*d8e26cc8SYouMin Chen if (dram_type == DDR2) 167*d8e26cc8SYouMin Chen phandle_name = DDR2_PARAMS_PHANDLE_NAME; 168*d8e26cc8SYouMin Chen else if (dram_type == DDR3) 169*d8e26cc8SYouMin Chen phandle_name = DDR3_PARAMS_PHANDLE_NAME; 170*d8e26cc8SYouMin Chen else if (dram_type == DDR4) 171*d8e26cc8SYouMin Chen phandle_name = DDR4_PARAMS_PHANDLE_NAME; 172*d8e26cc8SYouMin Chen else if (dram_type == LPDDR2) 173*d8e26cc8SYouMin Chen phandle_name = LPDDR2_PARAMS_PHANDLE_NAME; 174*d8e26cc8SYouMin Chen else if (dram_type == LPDDR3) 175*d8e26cc8SYouMin Chen phandle_name = LPDDR3_PARAMS_PHANDLE_NAME; 176*d8e26cc8SYouMin Chen else if (dram_type == LPDDR4) 177*d8e26cc8SYouMin Chen phandle_name = LPDDR4_PARAMS_PHANDLE_NAME; 178*d8e26cc8SYouMin Chen else if (dram_type == LPDDR4X) 179*d8e26cc8SYouMin Chen phandle_name = LPDDR4X_PARAMS_PHANDLE_NAME; 180*d8e26cc8SYouMin Chen else if (dram_type == LPDDR5) 181*d8e26cc8SYouMin Chen phandle_name = LPDDR5_PARAMS_PHANDLE_NAME; 182*d8e26cc8SYouMin Chen else 183*d8e26cc8SYouMin Chen printf("%s: dram_type unsupported\n", __func__); 184*d8e26cc8SYouMin Chen 185*d8e26cc8SYouMin Chen np_params = of_parse_phandle(ofnode_to_np(dev_ofnode(dev)), phandle_name, 0); 186*d8e26cc8SYouMin Chen if (!np_params) { 187*d8e26cc8SYouMin Chen printf("%s: of_parse_phandle %s error!\n", __func__, phandle_name); 188*d8e26cc8SYouMin Chen return -EINVAL; 189*d8e26cc8SYouMin Chen } 190*d8e26cc8SYouMin Chen 191*d8e26cc8SYouMin Chen ddr_params_version = ofnode_read_u32_default(np_to_ofnode(np_params), "version", -1); 192*d8e26cc8SYouMin Chen if (ddr_params_version < 0) { 193*d8e26cc8SYouMin Chen printf("%s: get ddr_params_version error\n", __func__); 194*d8e26cc8SYouMin Chen return -EINVAL; 195*d8e26cc8SYouMin Chen } 196*d8e26cc8SYouMin Chen 197*d8e26cc8SYouMin Chen if ((ddr_params_version & 0xff00) == 0x100 && 198*d8e26cc8SYouMin Chen (ddr_params_version & 0xffff) <= 0x100) { 199*d8e26cc8SYouMin Chen count = ARRAY_SIZE(ddr_params_v1); 200*d8e26cc8SYouMin Chen ddr_params = ddr_params_v1; 201*d8e26cc8SYouMin Chen } else { 202*d8e26cc8SYouMin Chen printf("%s: ddr_params_version=0x%x unsupported\n", __func__, ddr_params_version); 203*d8e26cc8SYouMin Chen return -EINVAL; 204*d8e26cc8SYouMin Chen } 205*d8e26cc8SYouMin Chen 206*d8e26cc8SYouMin Chen size = count * 4; 207*d8e26cc8SYouMin Chen res = sip_smc_request_share_mem(DIV_ROUND_UP(size, 4096) + 1, SHARE_PAGE_TYPE_DDRFSP); 208*d8e26cc8SYouMin Chen if (res.a0 != 0) { 209*d8e26cc8SYouMin Chen printf("%s:no share memory for init\n", __func__); 210*d8e26cc8SYouMin Chen return -ENOMEM; 211*d8e26cc8SYouMin Chen } 212*d8e26cc8SYouMin Chen 213*d8e26cc8SYouMin Chen /* fill share memory and pass to the atf */ 214*d8e26cc8SYouMin Chen p = (int *)(res.a1); 215*d8e26cc8SYouMin Chen for (i = 0; i < ARRAY_SIZE(dmc_fsp_params); i++) 216*d8e26cc8SYouMin Chen p[i] = dev_read_u32_default(dev, dmc_fsp_params[i], PARAMS_INVALID_VAL); 217*d8e26cc8SYouMin Chen 218*d8e26cc8SYouMin Chen p = (int *)(res.a1 + DTS_PAR_OFFSET / 4); 219*d8e26cc8SYouMin Chen for (i = 0; i < count; i++) { 220*d8e26cc8SYouMin Chen p[i] = ofnode_read_u32_default(np_to_ofnode(np_params), ddr_params[i], 221*d8e26cc8SYouMin Chen PARAMS_INVALID_VAL); 222*d8e26cc8SYouMin Chen } 223*d8e26cc8SYouMin Chen 224*d8e26cc8SYouMin Chen flush_cache((unsigned long)(res.a1), (DIV_ROUND_UP(size, 4096) + 1) * 0x1000); 225*d8e26cc8SYouMin Chen res = sip_smc_dram(SHARE_PAGE_TYPE_DDRFSP, 0, ROCKCHIP_SIP_CONFIG_DRAM_FSP_INIT); 226*d8e26cc8SYouMin Chen if (res.a0) { 227*d8e26cc8SYouMin Chen printf("%s: rockchip_sip_config_dram_fsp_init error:%lx\n", __func__, res.a0); 228*d8e26cc8SYouMin Chen return -ENOMEM; 229*d8e26cc8SYouMin Chen } 230*d8e26cc8SYouMin Chen 231*d8e26cc8SYouMin Chen return 0; 232*d8e26cc8SYouMin Chen } 233*d8e26cc8SYouMin Chen 234*d8e26cc8SYouMin Chen static const struct udevice_id rockchip_dmc_fsp_ids[] = { 235*d8e26cc8SYouMin Chen { .compatible = "rockchip,rk3568-dmc-fsp", .data = 0x102}, 236*d8e26cc8SYouMin Chen { } 237*d8e26cc8SYouMin Chen }; 238*d8e26cc8SYouMin Chen 239*d8e26cc8SYouMin Chen U_BOOT_DRIVER(dmc_fsp) = { 240*d8e26cc8SYouMin Chen .name = "rockchip_dmc_fsp", 241*d8e26cc8SYouMin Chen .id = UCLASS_DMC, 242*d8e26cc8SYouMin Chen .probe = dmc_fsp_probe, 243*d8e26cc8SYouMin Chen .of_match = rockchip_dmc_fsp_ids, 244*d8e26cc8SYouMin Chen }; 245