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