xref: /rk3399_ARM-atf/plat/ti/k3low/common/drivers/k3-ddrss/lpddr4.c (revision 6c0c3a74dda68e7ffc8bd6c156918ddbfea7e03a)
1 // SPDX-License-Identifier: BSD-3-Clause
2 /*
3  * Cadence DDR Driver
4  *
5  * Copyright (C) 2012-2026 Cadence Design Systems, Inc.
6  * Copyright (C) 2018-2026 Texas Instruments Incorporated - https://www.ti.com/
7  */
8 
9 #include <errno.h>
10 
11 #include <common/bl_common.h>
12 #include <common/debug.h>
13 
14 #include "cps_drv_lpddr4.h"
15 #include "lpddr4.h"
16 #include "lpddr4_if.h"
17 #include "lpddr4_structs_if.h"
18 
lpddr4_pollctlirq(const ti_lpddr4_privatedata * pd,ti_lpddr4_intr_ctlinterrupt irqbit,uint32_t delay)19 static uint32_t lpddr4_pollctlirq(const ti_lpddr4_privatedata *pd,
20 				  ti_lpddr4_intr_ctlinterrupt irqbit,
21 				  uint32_t delay)
22 {
23 	uint32_t result = 0U;
24 	uint32_t timeout = 0U;
25 	bool irqstatus = false;
26 
27 	do {
28 		if (++timeout == delay) {
29 			result = (uint32_t)EIO;
30 			break;
31 		}
32 		result = ti_lpddr4_checkctlinterrupt(pd, irqbit, &irqstatus);
33 	} while ((irqstatus == false) && (result == 0U));
34 
35 	return result;
36 }
37 
lpddr4_pollphyindepirq(const ti_lpddr4_privatedata * pd,ti_lpddr4_intr_phyindepinterrupt irqbit,uint32_t delay)38 static uint32_t lpddr4_pollphyindepirq(const ti_lpddr4_privatedata *pd,
39 				       ti_lpddr4_intr_phyindepinterrupt irqbit,
40 				       uint32_t delay)
41 {
42 	uint32_t result = 0U;
43 	uint32_t timeout = 0U;
44 	bool irqstatus = false;
45 
46 	do {
47 		if (++timeout == delay) {
48 			result = (uint32_t)EIO;
49 			break;
50 		}
51 		result = ti_lpddr4_checkphyindepinterrupt(pd, irqbit, &irqstatus);
52 	} while ((irqstatus == false) && (result == 0U));
53 
54 	return result;
55 }
56 
lpddr4_pollandackirq(const ti_lpddr4_privatedata * pd)57 static uint32_t lpddr4_pollandackirq(const ti_lpddr4_privatedata *pd)
58 {
59 	uint32_t result = 0U;
60 	lpddr4_ctlregs *ctlregbase = pd->ctlbase;
61 
62 	result = lpddr4_pollphyindepirq(pd, LPDDR4_INTR_PHY_INDEP_INIT_DONE_BIT,
63 					TI_LPDDR4_CUSTOM_TIMEOUT_DELAY);
64 	if (result != 0U) {
65 		ERROR("lpddr4: init timeout PI=0x%x CTL=0x%x\n",
66 		       ctlregbase->TI_LPDDR4__PI_INT_STATUS__REG,
67 		       ctlregbase->DENALI_CTL[342]);
68 		return result;
69 	}
70 
71 	result = ti_lpddr4_ackphyindepinterrupt(pd, LPDDR4_INTR_PHY_INDEP_INIT_DONE_BIT);
72 	if (result != 0U) {
73 		return result;
74 	}
75 
76 	result = lpddr4_pollctlirq(pd, LPDDR4_INTR_MC_INIT_DONE, TI_LPDDR4_CUSTOM_TIMEOUT_DELAY);
77 	if (result != 0U) {
78 		ERROR("lpddr4: init timeout MC=0x%x CTL=0x%x\n",
79 		       ctlregbase->TI_LPDDR4__INT_STATUS_MASTER__REG,
80 		       ctlregbase->DENALI_CTL[342]);
81 		return result;
82 	}
83 
84 	result = ti_lpddr4_ackctlinterrupt(pd, LPDDR4_INTR_MC_INIT_DONE);
85 
86 	return result;
87 }
88 
lpddr4_startsequencecontroller(const ti_lpddr4_privatedata * pd)89 static uint32_t lpddr4_startsequencecontroller(const ti_lpddr4_privatedata *pd)
90 {
91 	uint32_t result = 0U;
92 	uint32_t regval = 0U;
93 	ti_lpddr4_infotype infotype;
94 	lpddr4_ctlregs *ctlregbase = pd->ctlbase;
95 
96 	regval = CPS_FLD_SET(TI_LPDDR4__PI_START__FLD,
97 			     ctlregbase->TI_LPDDR4__PI_START__REG);
98 	ctlregbase->TI_LPDDR4__PI_START__REG = regval;
99 
100 	regval = CPS_FLD_SET(TI_LPDDR4__START__FLD,
101 			     ctlregbase->TI_LPDDR4__START__REG);
102 	ctlregbase->TI_LPDDR4__START__REG = regval;
103 
104 	if (pd->infohandler != (lpddr4_infocallback)NULL) {
105 		infotype = LPDDR4_DRV_SOC_PLL_UPDATE;
106 		pd->infohandler(pd, infotype);
107 	}
108 
109 	result = lpddr4_pollandackirq(pd);
110 
111 	return result;
112 }
113 
114 
ti_lpddr4_probe(const ti_lpddr4_config * config,uint16_t * configsize)115 uint32_t ti_lpddr4_probe(const ti_lpddr4_config *config, uint16_t *configsize)
116 {
117 	if ((configsize == NULL) || (config == NULL)) {
118 		return (uint32_t)EINVAL;
119 	}
120 
121 	*configsize = (uint16_t)(sizeof(ti_lpddr4_privatedata));
122 	return 0U;
123 }
124 
ti_lpddr4_init(ti_lpddr4_privatedata * pd,const ti_lpddr4_config * cfg)125 uint32_t ti_lpddr4_init(ti_lpddr4_privatedata *pd, const ti_lpddr4_config *cfg)
126 {
127 	if ((pd == NULL) || (cfg == NULL)) {
128 		return (uint32_t)EINVAL;
129 	}
130 
131 	pd->ctlbase = cfg->ctlbase;
132 	pd->infohandler = (lpddr4_infocallback)cfg->infohandler;
133 	pd->ctlinterrupthandler = (lpddr4_ctlcallback)cfg->ctlinterrupthandler;
134 	pd->phyindepinterrupthandler = (lpddr4_phyindepcallback)cfg->phyindepinterrupthandler;
135 	return 0U;
136 }
137 
ti_lpddr4_start(const ti_lpddr4_privatedata * pd)138 uint32_t ti_lpddr4_start(const ti_lpddr4_privatedata *pd)
139 {
140 	uint32_t result = 0U;
141 
142 	if (pd == NULL) {
143 		return (uint32_t)EINVAL;
144 	}
145 
146 	ti_lpddr4_enable_pi_initiator(pd);
147 
148 	result = lpddr4_startsequencecontroller(pd);
149 
150 	return result;
151 }
152 
ti_lpddr4_readreg(const ti_lpddr4_privatedata * pd,ti_lpddr4_regblock cpp,uint32_t regoffset,uint32_t * regvalue)153 uint32_t ti_lpddr4_readreg(const ti_lpddr4_privatedata *pd, ti_lpddr4_regblock cpp,
154 			   uint32_t regoffset, uint32_t *regvalue)
155 {
156 	if ((pd == NULL) || (regvalue == NULL)) {
157 		return (uint32_t)EINVAL;
158 	} else if ((cpp != LPDDR4_CTL_REGS) &&
159 			(cpp != LPDDR4_PHY_REGS) &&
160 			(cpp != LPDDR4_PHY_INDEP_REGS)) {
161 		return (uint32_t)EINVAL;
162 	}
163 
164 	lpddr4_ctlregs *ctlregbase = pd->ctlbase;
165 
166 	switch (cpp) {
167 	case LPDDR4_CTL_REGS:
168 		if (regoffset >= TI_LPDDR4_INTR_CTL_REG_COUNT) {
169 			return (uint32_t)EINVAL;
170 		}
171 		*regvalue = ctlregbase->DENALI_CTL[regoffset];
172 		break;
173 	case LPDDR4_PHY_REGS:
174 		if (regoffset >= TI_LPDDR4_INTR_PHY_REG_COUNT) {
175 			return (uint32_t)EINVAL;
176 		}
177 		*regvalue = ctlregbase->DENALI_PHY_0[regoffset];
178 		break;
179 	case LPDDR4_PHY_INDEP_REGS:
180 		if (regoffset >= TI_LPDDR4_INTR_PHY_INDEP_REG_COUNT) {
181 			return (uint32_t)EINVAL;
182 		}
183 		*regvalue = ctlregbase->DENALI_PI[regoffset];
184 		break;
185 	default:
186 		break;
187 	}
188 
189 	return 0U;
190 }
191 
ti_lpddr4_writereg(const ti_lpddr4_privatedata * pd,ti_lpddr4_regblock cpp,uint32_t regoffset,uint32_t regvalue)192 uint32_t ti_lpddr4_writereg(const ti_lpddr4_privatedata *pd, ti_lpddr4_regblock cpp,
193 			    uint32_t regoffset, uint32_t regvalue)
194 {
195 	if (pd == NULL) {
196 		return (uint32_t)EINVAL;
197 	} else if ((cpp != LPDDR4_CTL_REGS) &&
198 			(cpp != LPDDR4_PHY_REGS) &&
199 			(cpp != LPDDR4_PHY_INDEP_REGS)) {
200 		return (uint32_t)EINVAL;
201 	}
202 
203 	lpddr4_ctlregs *ctlregbase = pd->ctlbase;
204 
205 	switch (cpp) {
206 	case LPDDR4_CTL_REGS:
207 		if (regoffset >= TI_LPDDR4_INTR_CTL_REG_COUNT) {
208 			return (uint32_t)EINVAL;
209 		}
210 		ctlregbase->DENALI_CTL[regoffset] = regvalue;
211 		break;
212 	case LPDDR4_PHY_REGS:
213 		if (regoffset >= TI_LPDDR4_INTR_PHY_REG_COUNT) {
214 			return (uint32_t)EINVAL;
215 		}
216 		ctlregbase->DENALI_PHY_0[regoffset] = regvalue;
217 		break;
218 	case LPDDR4_PHY_INDEP_REGS:
219 		if (regoffset >= TI_LPDDR4_INTR_PHY_INDEP_REG_COUNT) {
220 			return (uint32_t)EINVAL;
221 		}
222 		ctlregbase->DENALI_PI[regoffset] = regvalue;
223 		break;
224 	default:
225 		break;
226 	}
227 
228 	return 0U;
229 }
230 
ti_lpddr4_writectlconfigex(const ti_lpddr4_privatedata * pd,const uint32_t regvalues[],uint16_t regcount)231 uint32_t ti_lpddr4_writectlconfigex(const ti_lpddr4_privatedata *pd,
232 				    const uint32_t regvalues[], uint16_t regcount)
233 {
234 	uint32_t result = 0U;
235 	uint32_t aindex;
236 
237 	if ((pd == NULL) || (regvalues == (uint32_t *)NULL)) {
238 		return (uint32_t)EINVAL;
239 	}
240 
241 	for (aindex = 0; aindex < regcount; aindex++) {
242 		result = ti_lpddr4_writereg(pd, LPDDR4_CTL_REGS, aindex,
243 					    regvalues[aindex]);
244 		if (result != 0U) {
245 			return result;
246 		}
247 	}
248 
249 	return result;
250 }
251 
ti_lpddr4_writephyindepconfigex(const ti_lpddr4_privatedata * pd,const uint32_t regvalues[],uint16_t regcount)252 uint32_t ti_lpddr4_writephyindepconfigex(const ti_lpddr4_privatedata *pd,
253 					 const uint32_t regvalues[], uint16_t regcount)
254 {
255 	uint32_t result = 0U;
256 	uint32_t aindex;
257 
258 	if ((pd == NULL) || (regvalues == (uint32_t *)NULL)) {
259 		return (uint32_t)EINVAL;
260 	}
261 
262 	for (aindex = 0; aindex < regcount; aindex++) {
263 		result = ti_lpddr4_writereg(pd, LPDDR4_PHY_INDEP_REGS, aindex,
264 					    regvalues[aindex]);
265 		if (result != 0U) {
266 			return result;
267 		}
268 	}
269 
270 	return result;
271 }
272 
ti_lpddr4_writephyconfigex(const ti_lpddr4_privatedata * pd,const uint32_t regvalues[],uint16_t regcount)273 uint32_t ti_lpddr4_writephyconfigex(const ti_lpddr4_privatedata *pd,
274 				    const uint32_t regvalues[], uint16_t regcount)
275 {
276 	uint32_t result = 0U;
277 	uint32_t aindex;
278 
279 	if ((pd == NULL) || (regvalues == (uint32_t *)NULL)) {
280 		return (uint32_t)EINVAL;
281 	}
282 
283 	for (aindex = 0; aindex < regcount; aindex++) {
284 		result = ti_lpddr4_writereg(pd, LPDDR4_PHY_REGS, aindex,
285 					    regvalues[aindex]);
286 		if (result != 0U) {
287 			return result;
288 		}
289 	}
290 
291 	return result;
292 }
293 
ti_lpddr4_checkphyindepinterrupt(const ti_lpddr4_privatedata * pd,ti_lpddr4_intr_phyindepinterrupt intr,bool * irqstatus)294 uint32_t ti_lpddr4_checkphyindepinterrupt(const ti_lpddr4_privatedata *pd,
295 					  ti_lpddr4_intr_phyindepinterrupt intr,
296 					  bool *irqstatus)
297 {
298 	uint32_t result = 0;
299 	uint32_t phyindepirqstatus = 0;
300 
301 	result = ti_lpddr4_intr_phyint_sf(pd, intr, irqstatus);
302 	if ((result == 0U) && ((uint32_t)intr < TI_WORD_SHIFT)) {
303 		lpddr4_ctlregs *ctlregbase = pd->ctlbase;
304 
305 		phyindepirqstatus = ctlregbase->TI_LPDDR4__PI_INT_STATUS__REG;
306 		*irqstatus = (((phyindepirqstatus >> (uint32_t)intr) & TI_LPDDR4_BIT_MASK) > 0U);
307 	}
308 	return result;
309 }
310 
ti_lpddr4_ackphyindepinterrupt(const ti_lpddr4_privatedata * pd,ti_lpddr4_intr_phyindepinterrupt intr)311 uint32_t ti_lpddr4_ackphyindepinterrupt(const ti_lpddr4_privatedata *pd,
312 					ti_lpddr4_intr_phyindepinterrupt intr)
313 {
314 	uint32_t result = 0U;
315 	uint32_t regval = 0U;
316 
317 	result = ti_lpddr4_intr_ack_phyint_sf(pd, intr);
318 	if ((result == 0U) && ((uint32_t)intr < TI_WORD_SHIFT)) {
319 		lpddr4_ctlregs *ctlregbase = pd->ctlbase;
320 
321 		regval = (TI_LPDDR4_BIT_MASK << (uint32_t)intr);
322 		ctlregbase->TI_LPDDR4__PI_INT_ACK__REG = regval;
323 	}
324 
325 	return result;
326 }
327