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 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 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 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 */ 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 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 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