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