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