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