xref: /rk3399_ARM-atf/drivers/nxp/ddr/nxp-ddr/utility.c (revision b35ce0c413a71689a2b46453b9c30596128f13dc)
1*b35ce0c4SPankaj Gupta /*
2*b35ce0c4SPankaj Gupta  * Copyright 2021 NXP
3*b35ce0c4SPankaj Gupta  *
4*b35ce0c4SPankaj Gupta  * SPDX-License-Identifier: BSD-3-Clause
5*b35ce0c4SPankaj Gupta  *
6*b35ce0c4SPankaj Gupta  */
7*b35ce0c4SPankaj Gupta 
8*b35ce0c4SPankaj Gupta #include <errno.h>
9*b35ce0c4SPankaj Gupta #include <stdint.h>
10*b35ce0c4SPankaj Gupta #include <stdio.h>
11*b35ce0c4SPankaj Gupta #include <stdlib.h>
12*b35ce0c4SPankaj Gupta 
13*b35ce0c4SPankaj Gupta #include <common/debug.h>
14*b35ce0c4SPankaj Gupta #include <ddr.h>
15*b35ce0c4SPankaj Gupta #include <immap.h>
16*b35ce0c4SPankaj Gupta #include <lib/mmio.h>
17*b35ce0c4SPankaj Gupta 
18*b35ce0c4SPankaj Gupta #define UL_5POW12	244140625UL
19*b35ce0c4SPankaj Gupta #define ULL_2E12	2000000000000ULL
20*b35ce0c4SPankaj Gupta #define UL_2POW13	(1UL << 13)
21*b35ce0c4SPankaj Gupta #define ULL_8FS		0xFFFFFFFFULL
22*b35ce0c4SPankaj Gupta 
23*b35ce0c4SPankaj Gupta #define do_div(n, base) ({				\
24*b35ce0c4SPankaj Gupta 	unsigned int __base = (base);			\
25*b35ce0c4SPankaj Gupta 	unsigned int __rem;				\
26*b35ce0c4SPankaj Gupta 	__rem = ((unsigned long long)(n)) % __base;	\
27*b35ce0c4SPankaj Gupta 	(n) = ((unsigned long long)(n)) / __base;	\
28*b35ce0c4SPankaj Gupta 	__rem;						\
29*b35ce0c4SPankaj Gupta })
30*b35ce0c4SPankaj Gupta 
31*b35ce0c4SPankaj Gupta #define CCN_HN_F_SAM_NODEID_MASK	0x7f
32*b35ce0c4SPankaj Gupta #ifdef NXP_HAS_CCN504
33*b35ce0c4SPankaj Gupta #define CCN_HN_F_SAM_NODEID_DDR0	0x4
34*b35ce0c4SPankaj Gupta #define CCN_HN_F_SAM_NODEID_DDR1	0xe
35*b35ce0c4SPankaj Gupta #elif defined(NXP_HAS_CCN508)
36*b35ce0c4SPankaj Gupta #define CCN_HN_F_SAM_NODEID_DDR0	0x8
37*b35ce0c4SPankaj Gupta #define CCN_HN_F_SAM_NODEID_DDR1	0x18
38*b35ce0c4SPankaj Gupta #endif
39*b35ce0c4SPankaj Gupta 
40*b35ce0c4SPankaj Gupta unsigned long get_ddr_freq(struct sysinfo *sys, int ctrl_num)
41*b35ce0c4SPankaj Gupta {
42*b35ce0c4SPankaj Gupta 	if (sys->freq_ddr_pll0 == 0) {
43*b35ce0c4SPankaj Gupta 		get_clocks(sys);
44*b35ce0c4SPankaj Gupta 	}
45*b35ce0c4SPankaj Gupta 
46*b35ce0c4SPankaj Gupta 	switch (ctrl_num) {
47*b35ce0c4SPankaj Gupta 	case 0:
48*b35ce0c4SPankaj Gupta 		return sys->freq_ddr_pll0;
49*b35ce0c4SPankaj Gupta 	case 1:
50*b35ce0c4SPankaj Gupta 		return sys->freq_ddr_pll0;
51*b35ce0c4SPankaj Gupta 	case 2:
52*b35ce0c4SPankaj Gupta 		return sys->freq_ddr_pll1;
53*b35ce0c4SPankaj Gupta 	}
54*b35ce0c4SPankaj Gupta 
55*b35ce0c4SPankaj Gupta 	return 0;
56*b35ce0c4SPankaj Gupta }
57*b35ce0c4SPankaj Gupta 
58*b35ce0c4SPankaj Gupta unsigned int get_memory_clk_ps(const unsigned long data_rate)
59*b35ce0c4SPankaj Gupta {
60*b35ce0c4SPankaj Gupta 	unsigned int result;
61*b35ce0c4SPankaj Gupta 	/* Round to nearest 10ps, being careful about 64-bit multiply/divide */
62*b35ce0c4SPankaj Gupta 	unsigned long long rem, mclk_ps = ULL_2E12;
63*b35ce0c4SPankaj Gupta 
64*b35ce0c4SPankaj Gupta 	/* Now perform the big divide, the result fits in 32-bits */
65*b35ce0c4SPankaj Gupta 	rem = do_div(mclk_ps, data_rate);
66*b35ce0c4SPankaj Gupta 	result = (rem >= (data_rate >> 1)) ? mclk_ps + 1 : mclk_ps;
67*b35ce0c4SPankaj Gupta 
68*b35ce0c4SPankaj Gupta 	return result;
69*b35ce0c4SPankaj Gupta }
70*b35ce0c4SPankaj Gupta 
71*b35ce0c4SPankaj Gupta unsigned int picos_to_mclk(unsigned long data_rate, unsigned int picos)
72*b35ce0c4SPankaj Gupta {
73*b35ce0c4SPankaj Gupta 	unsigned long long clks, clks_rem;
74*b35ce0c4SPankaj Gupta 
75*b35ce0c4SPankaj Gupta 	/* Short circuit for zero picos */
76*b35ce0c4SPankaj Gupta 	if ((picos == 0U) || (data_rate == 0UL)) {
77*b35ce0c4SPankaj Gupta 		return 0U;
78*b35ce0c4SPankaj Gupta 	}
79*b35ce0c4SPankaj Gupta 
80*b35ce0c4SPankaj Gupta 	/* First multiply the time by the data rate (32x32 => 64) */
81*b35ce0c4SPankaj Gupta 	clks = picos * (unsigned long long)data_rate;
82*b35ce0c4SPankaj Gupta 	/*
83*b35ce0c4SPankaj Gupta 	 * Now divide by 5^12 and track the 32-bit remainder, then divide
84*b35ce0c4SPankaj Gupta 	 * by 2*(2^12) using shifts (and updating the remainder).
85*b35ce0c4SPankaj Gupta 	 */
86*b35ce0c4SPankaj Gupta 	clks_rem = do_div(clks, UL_5POW12);
87*b35ce0c4SPankaj Gupta 	clks_rem += (clks & (UL_2POW13-1)) * UL_5POW12;
88*b35ce0c4SPankaj Gupta 	clks >>= 13U;
89*b35ce0c4SPankaj Gupta 
90*b35ce0c4SPankaj Gupta 	/* If we had a remainder greater than the 1ps error, then round up */
91*b35ce0c4SPankaj Gupta 	if (clks_rem > data_rate) {
92*b35ce0c4SPankaj Gupta 		clks++;
93*b35ce0c4SPankaj Gupta 	}
94*b35ce0c4SPankaj Gupta 
95*b35ce0c4SPankaj Gupta 	/* Clamp to the maximum representable value */
96*b35ce0c4SPankaj Gupta 	if (clks > ULL_8FS) {
97*b35ce0c4SPankaj Gupta 		clks = ULL_8FS;
98*b35ce0c4SPankaj Gupta 	}
99*b35ce0c4SPankaj Gupta 	return (unsigned int) clks;
100*b35ce0c4SPankaj Gupta }
101*b35ce0c4SPankaj Gupta 
102*b35ce0c4SPankaj Gupta /* valid_spd_mask has been checked by parse_spd */
103*b35ce0c4SPankaj Gupta int disable_unused_ddrc(struct ddr_info *priv,
104*b35ce0c4SPankaj Gupta 			int valid_spd_mask, uintptr_t nxp_ccn_hn_f0_addr)
105*b35ce0c4SPankaj Gupta {
106*b35ce0c4SPankaj Gupta #if defined(NXP_HAS_CCN504) || defined(NXP_HAS_CCN508)
107*b35ce0c4SPankaj Gupta 	void *hnf_sam_ctrl = (void *)(nxp_ccn_hn_f0_addr + CCN_HN_F_SAM_CTL);
108*b35ce0c4SPankaj Gupta 	uint32_t val, nodeid;
109*b35ce0c4SPankaj Gupta #ifdef NXP_HAS_CCN504
110*b35ce0c4SPankaj Gupta 	uint32_t num_hnf_nodes = 4U;
111*b35ce0c4SPankaj Gupta #else
112*b35ce0c4SPankaj Gupta 	uint32_t num_hnf_nodes = 8U;
113*b35ce0c4SPankaj Gupta #endif
114*b35ce0c4SPankaj Gupta 	int disable_ddrc = 0;
115*b35ce0c4SPankaj Gupta 	int i;
116*b35ce0c4SPankaj Gupta 
117*b35ce0c4SPankaj Gupta 	if (priv->num_ctlrs < 2) {
118*b35ce0c4SPankaj Gupta 		debug("%s: nothing to do.\n", __func__);
119*b35ce0c4SPankaj Gupta 	}
120*b35ce0c4SPankaj Gupta 
121*b35ce0c4SPankaj Gupta 	switch (priv->dimm_on_ctlr) {
122*b35ce0c4SPankaj Gupta 	case 1:
123*b35ce0c4SPankaj Gupta 		disable_ddrc = ((valid_spd_mask &0x2) == 0) ? 2 : 0;
124*b35ce0c4SPankaj Gupta 		disable_ddrc = ((valid_spd_mask &0x1) == 0) ? 1 : disable_ddrc;
125*b35ce0c4SPankaj Gupta 		break;
126*b35ce0c4SPankaj Gupta 	case 2:
127*b35ce0c4SPankaj Gupta 		disable_ddrc = ((valid_spd_mask &0x4) == 0) ? 2 : 0;
128*b35ce0c4SPankaj Gupta 		disable_ddrc = ((valid_spd_mask &0x1) == 0) ? 1 : disable_ddrc;
129*b35ce0c4SPankaj Gupta 		break;
130*b35ce0c4SPankaj Gupta 	default:
131*b35ce0c4SPankaj Gupta 		ERROR("Invalid number of DIMMs %d\n", priv->dimm_on_ctlr);
132*b35ce0c4SPankaj Gupta 		return -EINVAL;
133*b35ce0c4SPankaj Gupta 	}
134*b35ce0c4SPankaj Gupta 
135*b35ce0c4SPankaj Gupta 	if (disable_ddrc != 0) {
136*b35ce0c4SPankaj Gupta 		debug("valid_spd_mask = 0x%x\n", valid_spd_mask);
137*b35ce0c4SPankaj Gupta 	}
138*b35ce0c4SPankaj Gupta 
139*b35ce0c4SPankaj Gupta 	switch (disable_ddrc) {
140*b35ce0c4SPankaj Gupta 	case 1:
141*b35ce0c4SPankaj Gupta 		priv->num_ctlrs = 1;
142*b35ce0c4SPankaj Gupta 		priv->spd_addr = &priv->spd_addr[priv->dimm_on_ctlr];
143*b35ce0c4SPankaj Gupta 		priv->ddr[0] = priv->ddr[1];
144*b35ce0c4SPankaj Gupta 		priv->ddr[1] = NULL;
145*b35ce0c4SPankaj Gupta 		priv->phy[0] = priv->phy[0];
146*b35ce0c4SPankaj Gupta 		priv->phy[1] = NULL;
147*b35ce0c4SPankaj Gupta 		debug("Disable first DDR controller\n");
148*b35ce0c4SPankaj Gupta 		break;
149*b35ce0c4SPankaj Gupta 	case 2:
150*b35ce0c4SPankaj Gupta 		priv->num_ctlrs = 1;
151*b35ce0c4SPankaj Gupta 		priv->ddr[1] = NULL;
152*b35ce0c4SPankaj Gupta 		priv->phy[1] = NULL;
153*b35ce0c4SPankaj Gupta 		debug("Disable second DDR controller\n");
154*b35ce0c4SPankaj Gupta 		/* fallthrough */
155*b35ce0c4SPankaj Gupta 	case 0:
156*b35ce0c4SPankaj Gupta 		break;
157*b35ce0c4SPankaj Gupta 	default:
158*b35ce0c4SPankaj Gupta 		ERROR("Program error.\n");
159*b35ce0c4SPankaj Gupta 		return -EINVAL;
160*b35ce0c4SPankaj Gupta 	}
161*b35ce0c4SPankaj Gupta 
162*b35ce0c4SPankaj Gupta 	if (disable_ddrc == 0) {
163*b35ce0c4SPankaj Gupta 		debug("Both controllers in use.\n");
164*b35ce0c4SPankaj Gupta 		return 0;
165*b35ce0c4SPankaj Gupta 	}
166*b35ce0c4SPankaj Gupta 
167*b35ce0c4SPankaj Gupta 	for (i = 0; i < num_hnf_nodes; i++) {
168*b35ce0c4SPankaj Gupta 		val = mmio_read_64((uintptr_t)hnf_sam_ctrl);
169*b35ce0c4SPankaj Gupta 		nodeid = disable_ddrc == 1 ? CCN_HN_F_SAM_NODEID_DDR1 :
170*b35ce0c4SPankaj Gupta 			 (disable_ddrc == 2 ? CCN_HN_F_SAM_NODEID_DDR0 :
171*b35ce0c4SPankaj Gupta 			  (i < 4 ? CCN_HN_F_SAM_NODEID_DDR0
172*b35ce0c4SPankaj Gupta 				 : CCN_HN_F_SAM_NODEID_DDR1));
173*b35ce0c4SPankaj Gupta 		if (nodeid != (val & CCN_HN_F_SAM_NODEID_MASK)) {
174*b35ce0c4SPankaj Gupta 			debug("Setting HN-F node %d\n", i);
175*b35ce0c4SPankaj Gupta 			debug("nodeid = 0x%x\n", nodeid);
176*b35ce0c4SPankaj Gupta 			val &= ~CCN_HN_F_SAM_NODEID_MASK;
177*b35ce0c4SPankaj Gupta 			val |= nodeid;
178*b35ce0c4SPankaj Gupta 			mmio_write_64((uintptr_t)hnf_sam_ctrl, val);
179*b35ce0c4SPankaj Gupta 		}
180*b35ce0c4SPankaj Gupta 		hnf_sam_ctrl += CCN_HN_F_REGION_SIZE;
181*b35ce0c4SPankaj Gupta 	}
182*b35ce0c4SPankaj Gupta #endif
183*b35ce0c4SPankaj Gupta 	return 0;
184*b35ce0c4SPankaj Gupta }
185*b35ce0c4SPankaj Gupta 
186*b35ce0c4SPankaj Gupta unsigned int get_ddrc_version(const struct ccsr_ddr *ddr)
187*b35ce0c4SPankaj Gupta {
188*b35ce0c4SPankaj Gupta 	unsigned int ver;
189*b35ce0c4SPankaj Gupta 
190*b35ce0c4SPankaj Gupta 	ver = (ddr_in32(&ddr->ip_rev1) & 0xFFFF) << 8U;
191*b35ce0c4SPankaj Gupta 	ver |= (ddr_in32(&ddr->ip_rev2) & 0xFF00) >> 8U;
192*b35ce0c4SPankaj Gupta 
193*b35ce0c4SPankaj Gupta 	return ver;
194*b35ce0c4SPankaj Gupta }
195*b35ce0c4SPankaj Gupta 
196*b35ce0c4SPankaj Gupta void print_ddr_info(struct ccsr_ddr *ddr)
197*b35ce0c4SPankaj Gupta {
198*b35ce0c4SPankaj Gupta 	unsigned int cs0_config = ddr_in32(&ddr->csn_cfg[0]);
199*b35ce0c4SPankaj Gupta 	unsigned int sdram_cfg = ddr_in32(&ddr->sdram_cfg);
200*b35ce0c4SPankaj Gupta 	int cas_lat;
201*b35ce0c4SPankaj Gupta 
202*b35ce0c4SPankaj Gupta 	if ((sdram_cfg & SDRAM_CFG_MEM_EN) == 0U) {
203*b35ce0c4SPankaj Gupta 		printf(" (DDR not enabled)\n");
204*b35ce0c4SPankaj Gupta 		return;
205*b35ce0c4SPankaj Gupta 	}
206*b35ce0c4SPankaj Gupta 
207*b35ce0c4SPankaj Gupta 	printf("DDR");
208*b35ce0c4SPankaj Gupta 	switch ((sdram_cfg & SDRAM_CFG_SDRAM_TYPE_MASK) >>
209*b35ce0c4SPankaj Gupta 		SDRAM_CFG_SDRAM_TYPE_SHIFT) {
210*b35ce0c4SPankaj Gupta 	case SDRAM_TYPE_DDR4:
211*b35ce0c4SPankaj Gupta 		printf("4");
212*b35ce0c4SPankaj Gupta 		break;
213*b35ce0c4SPankaj Gupta 	default:
214*b35ce0c4SPankaj Gupta 		printf("?");
215*b35ce0c4SPankaj Gupta 		break;
216*b35ce0c4SPankaj Gupta 	}
217*b35ce0c4SPankaj Gupta 
218*b35ce0c4SPankaj Gupta 	switch (sdram_cfg & SDRAM_CFG_DBW_MASK) {
219*b35ce0c4SPankaj Gupta 	case SDRAM_CFG_32_BW:
220*b35ce0c4SPankaj Gupta 		printf(", 32-bit");
221*b35ce0c4SPankaj Gupta 		break;
222*b35ce0c4SPankaj Gupta 	case SDRAM_CFG_16_BW:
223*b35ce0c4SPankaj Gupta 		printf(", 16-bit");
224*b35ce0c4SPankaj Gupta 		break;
225*b35ce0c4SPankaj Gupta 	case SDRAM_CFG_8_BW:
226*b35ce0c4SPankaj Gupta 		printf(", 8-bit");
227*b35ce0c4SPankaj Gupta 		break;
228*b35ce0c4SPankaj Gupta 	default:
229*b35ce0c4SPankaj Gupta 		printf(", 64-bit");
230*b35ce0c4SPankaj Gupta 		break;
231*b35ce0c4SPankaj Gupta 	}
232*b35ce0c4SPankaj Gupta 
233*b35ce0c4SPankaj Gupta 	/* Calculate CAS latency based on timing cfg values */
234*b35ce0c4SPankaj Gupta 	cas_lat = ((ddr_in32(&ddr->timing_cfg_1) >> 16) & 0xf);
235*b35ce0c4SPankaj Gupta 	cas_lat += 2;	/* for DDRC newer than 4.4 */
236*b35ce0c4SPankaj Gupta 	cas_lat += ((ddr_in32(&ddr->timing_cfg_3) >> 12) & 3) << 4;
237*b35ce0c4SPankaj Gupta 	printf(", CL=%d", cas_lat >> 1);
238*b35ce0c4SPankaj Gupta 	if ((cas_lat & 0x1) != 0) {
239*b35ce0c4SPankaj Gupta 		printf(".5");
240*b35ce0c4SPankaj Gupta 	}
241*b35ce0c4SPankaj Gupta 
242*b35ce0c4SPankaj Gupta 	if ((sdram_cfg & SDRAM_CFG_ECC_EN) != 0) {
243*b35ce0c4SPankaj Gupta 		printf(", ECC on");
244*b35ce0c4SPankaj Gupta 	} else {
245*b35ce0c4SPankaj Gupta 		printf(", ECC off");
246*b35ce0c4SPankaj Gupta 	}
247*b35ce0c4SPankaj Gupta 
248*b35ce0c4SPankaj Gupta 	if ((cs0_config & 0x20000000) != 0) {
249*b35ce0c4SPankaj Gupta 		printf(", ");
250*b35ce0c4SPankaj Gupta 		switch ((cs0_config >> 24) & 0xf) {
251*b35ce0c4SPankaj Gupta 		case DDR_256B_INTLV:
252*b35ce0c4SPankaj Gupta 			printf("256B");
253*b35ce0c4SPankaj Gupta 			break;
254*b35ce0c4SPankaj Gupta 		default:
255*b35ce0c4SPankaj Gupta 			printf("invalid");
256*b35ce0c4SPankaj Gupta 			break;
257*b35ce0c4SPankaj Gupta 		}
258*b35ce0c4SPankaj Gupta 	}
259*b35ce0c4SPankaj Gupta 
260*b35ce0c4SPankaj Gupta 	if (((sdram_cfg >> 8) & 0x7f) != 0) {
261*b35ce0c4SPankaj Gupta 		printf(", ");
262*b35ce0c4SPankaj Gupta 		switch (sdram_cfg >> 8 & 0x7f) {
263*b35ce0c4SPankaj Gupta 		case DDR_BA_INTLV_CS0123:
264*b35ce0c4SPankaj Gupta 			printf("CS0+CS1+CS2+CS3");
265*b35ce0c4SPankaj Gupta 			break;
266*b35ce0c4SPankaj Gupta 		case DDR_BA_INTLV_CS01:
267*b35ce0c4SPankaj Gupta 			printf("CS0+CS1");
268*b35ce0c4SPankaj Gupta 			break;
269*b35ce0c4SPankaj Gupta 		default:
270*b35ce0c4SPankaj Gupta 			printf("invalid");
271*b35ce0c4SPankaj Gupta 			break;
272*b35ce0c4SPankaj Gupta 		}
273*b35ce0c4SPankaj Gupta 	}
274*b35ce0c4SPankaj Gupta 	printf("\n");
275*b35ce0c4SPankaj Gupta }
276