xref: /rk3399_rockchip-uboot/drivers/ram/rockchip/dmc_fsp.c (revision d8e26cc8fb2365d0eb393f5466a00d7e2c83db4d)
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