mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-20 11:34:20 +00:00

Corrects mapping of HNFs nodes with SNFs nodes based on their proximity in CCN508 ring when disabling unused ddr controller. When DDRC 2 disabled and DDR 1 is active the mapping is 0x3/3/8/8/8/8/3/3. When DDRC 1 is disabled and DDR2 is active the mapping is 0x 18/18/13/13/13/13/18/18 . Signed-off-by: Maninder Singh <maninder.singh_1@nxp.com> Signed-off-by: JaiPrakash Singh <JaiPrakash.singh@nxp.com> Signed-off-by: Jiafei Pan <Jiafei.Pan@nxp.com> Change-Id: I6ec1e02f8ad7e8bb8628913625ff5313a054dcc6
288 lines
6.4 KiB
C
288 lines
6.4 KiB
C
/*
|
|
* Copyright 2021-2022 NXP
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <common/debug.h>
|
|
#include <ddr.h>
|
|
#include <immap.h>
|
|
#include <lib/mmio.h>
|
|
|
|
#define UL_5POW12 244140625UL
|
|
#define ULL_2E12 2000000000000ULL
|
|
#define UL_2POW13 (1UL << 13)
|
|
#define ULL_8FS 0xFFFFFFFFULL
|
|
|
|
#define do_div(n, base) ({ \
|
|
unsigned int __base = (base); \
|
|
unsigned int __rem; \
|
|
__rem = ((unsigned long long)(n)) % __base; \
|
|
(n) = ((unsigned long long)(n)) / __base; \
|
|
__rem; \
|
|
})
|
|
|
|
#define CCN_HN_F_SAM_NODEID_MASK 0x7f
|
|
#ifdef NXP_HAS_CCN504
|
|
#define CCN_HN_F_SAM_NODEID_DDR0 0x4
|
|
#define CCN_HN_F_SAM_NODEID_DDR1 0xe
|
|
#elif defined(NXP_HAS_CCN508)
|
|
#define CCN_HN_F_SAM_NODEID_DDR0_0 0x3
|
|
#define CCN_HN_F_SAM_NODEID_DDR0_1 0x8
|
|
#define CCN_HN_F_SAM_NODEID_DDR1_0 0x13
|
|
#define CCN_HN_F_SAM_NODEID_DDR1_1 0x18
|
|
#endif
|
|
|
|
unsigned long get_ddr_freq(struct sysinfo *sys, int ctrl_num)
|
|
{
|
|
if (sys->freq_ddr_pll0 == 0) {
|
|
get_clocks(sys);
|
|
}
|
|
|
|
switch (ctrl_num) {
|
|
case 0:
|
|
return sys->freq_ddr_pll0;
|
|
case 1:
|
|
return sys->freq_ddr_pll0;
|
|
case 2:
|
|
return sys->freq_ddr_pll1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
unsigned int get_memory_clk_ps(const unsigned long data_rate)
|
|
{
|
|
unsigned int result;
|
|
/* Round to nearest 10ps, being careful about 64-bit multiply/divide */
|
|
unsigned long long rem, mclk_ps = ULL_2E12;
|
|
|
|
/* Now perform the big divide, the result fits in 32-bits */
|
|
rem = do_div(mclk_ps, data_rate);
|
|
result = (rem >= (data_rate >> 1)) ? mclk_ps + 1 : mclk_ps;
|
|
|
|
return result;
|
|
}
|
|
|
|
unsigned int picos_to_mclk(unsigned long data_rate, unsigned int picos)
|
|
{
|
|
unsigned long long clks, clks_rem;
|
|
|
|
/* Short circuit for zero picos */
|
|
if ((picos == 0U) || (data_rate == 0UL)) {
|
|
return 0U;
|
|
}
|
|
|
|
/* First multiply the time by the data rate (32x32 => 64) */
|
|
clks = picos * (unsigned long long)data_rate;
|
|
/*
|
|
* Now divide by 5^12 and track the 32-bit remainder, then divide
|
|
* by 2*(2^12) using shifts (and updating the remainder).
|
|
*/
|
|
clks_rem = do_div(clks, UL_5POW12);
|
|
clks_rem += (clks & (UL_2POW13-1)) * UL_5POW12;
|
|
clks >>= 13U;
|
|
|
|
/* If we had a remainder greater than the 1ps error, then round up */
|
|
if (clks_rem > data_rate) {
|
|
clks++;
|
|
}
|
|
|
|
/* Clamp to the maximum representable value */
|
|
if (clks > ULL_8FS) {
|
|
clks = ULL_8FS;
|
|
}
|
|
return (unsigned int) clks;
|
|
}
|
|
|
|
/* valid_spd_mask has been checked by parse_spd */
|
|
int disable_unused_ddrc(struct ddr_info *priv,
|
|
int valid_spd_mask, uintptr_t nxp_ccn_hn_f0_addr)
|
|
{
|
|
#if defined(NXP_HAS_CCN504) || defined(NXP_HAS_CCN508)
|
|
void *hnf_sam_ctrl = (void *)(nxp_ccn_hn_f0_addr + CCN_HN_F_SAM_CTL);
|
|
uint32_t val, nodeid;
|
|
#ifdef NXP_HAS_CCN504
|
|
uint32_t num_hnf_nodes = 4U;
|
|
#else
|
|
uint32_t num_hnf_nodes = 8U;
|
|
#endif
|
|
int disable_ddrc = 0;
|
|
int i;
|
|
|
|
if (priv->num_ctlrs < 2) {
|
|
debug("%s: nothing to do.\n", __func__);
|
|
}
|
|
|
|
switch (priv->dimm_on_ctlr) {
|
|
case 1:
|
|
disable_ddrc = ((valid_spd_mask &0x2) == 0) ? 2 : 0;
|
|
disable_ddrc = ((valid_spd_mask &0x1) == 0) ? 1 : disable_ddrc;
|
|
break;
|
|
case 2:
|
|
disable_ddrc = ((valid_spd_mask &0x4) == 0) ? 2 : 0;
|
|
disable_ddrc = ((valid_spd_mask &0x1) == 0) ? 1 : disable_ddrc;
|
|
break;
|
|
default:
|
|
ERROR("Invalid number of DIMMs %d\n", priv->dimm_on_ctlr);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (disable_ddrc != 0) {
|
|
debug("valid_spd_mask = 0x%x\n", valid_spd_mask);
|
|
}
|
|
|
|
switch (disable_ddrc) {
|
|
case 1:
|
|
priv->num_ctlrs = 1;
|
|
priv->spd_addr = &priv->spd_addr[priv->dimm_on_ctlr];
|
|
priv->ddr[0] = priv->ddr[1];
|
|
priv->ddr[1] = NULL;
|
|
priv->phy[0] = priv->phy[0];
|
|
priv->phy[1] = NULL;
|
|
debug("Disable first DDR controller\n");
|
|
break;
|
|
case 2:
|
|
priv->num_ctlrs = 1;
|
|
priv->ddr[1] = NULL;
|
|
priv->phy[1] = NULL;
|
|
debug("Disable second DDR controller\n");
|
|
/* fallthrough */
|
|
case 0:
|
|
break;
|
|
default:
|
|
ERROR("Program error.\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (disable_ddrc == 0) {
|
|
debug("Both controllers in use.\n");
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0; i < num_hnf_nodes; i++) {
|
|
val = mmio_read_64((uintptr_t)hnf_sam_ctrl);
|
|
#ifdef NXP_HAS_CCN504
|
|
nodeid = disable_ddrc == 1 ? CCN_HN_F_SAM_NODEID_DDR1 :
|
|
(disable_ddrc == 2 ? CCN_HN_F_SAM_NODEID_DDR0 :
|
|
0x0); /*Failure condition. never hit */
|
|
#elif defined(NXP_HAS_CCN508)
|
|
if (disable_ddrc == 1) {
|
|
nodeid = (i < 2 || i >= 6) ? CCN_HN_F_SAM_NODEID_DDR1_1 :
|
|
CCN_HN_F_SAM_NODEID_DDR1_0;
|
|
} else if (disable_ddrc == 2) {
|
|
nodeid = (i < 2 || i >= 6) ? CCN_HN_F_SAM_NODEID_DDR0_0 :
|
|
CCN_HN_F_SAM_NODEID_DDR0_1;
|
|
} else {
|
|
nodeid = 0; /* Failure condition. never hit */
|
|
}
|
|
#endif
|
|
if (nodeid != (val & CCN_HN_F_SAM_NODEID_MASK)) {
|
|
debug("Setting HN-F node %d\n", i);
|
|
debug("nodeid = 0x%x\n", nodeid);
|
|
val &= ~CCN_HN_F_SAM_NODEID_MASK;
|
|
val |= nodeid;
|
|
mmio_write_64((uintptr_t)hnf_sam_ctrl, val);
|
|
}
|
|
hnf_sam_ctrl += CCN_HN_F_REGION_SIZE;
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
unsigned int get_ddrc_version(const struct ccsr_ddr *ddr)
|
|
{
|
|
unsigned int ver;
|
|
|
|
ver = (ddr_in32(&ddr->ip_rev1) & 0xFFFF) << 8U;
|
|
ver |= (ddr_in32(&ddr->ip_rev2) & 0xFF00) >> 8U;
|
|
|
|
return ver;
|
|
}
|
|
|
|
void print_ddr_info(struct ccsr_ddr *ddr)
|
|
{
|
|
unsigned int cs0_config = ddr_in32(&ddr->csn_cfg[0]);
|
|
unsigned int sdram_cfg = ddr_in32(&ddr->sdram_cfg);
|
|
int cas_lat;
|
|
|
|
if ((sdram_cfg & SDRAM_CFG_MEM_EN) == 0U) {
|
|
printf(" (DDR not enabled)\n");
|
|
return;
|
|
}
|
|
|
|
printf("DDR");
|
|
switch ((sdram_cfg & SDRAM_CFG_SDRAM_TYPE_MASK) >>
|
|
SDRAM_CFG_SDRAM_TYPE_SHIFT) {
|
|
case SDRAM_TYPE_DDR4:
|
|
printf("4");
|
|
break;
|
|
default:
|
|
printf("?");
|
|
break;
|
|
}
|
|
|
|
switch (sdram_cfg & SDRAM_CFG_DBW_MASK) {
|
|
case SDRAM_CFG_32_BW:
|
|
printf(", 32-bit");
|
|
break;
|
|
case SDRAM_CFG_16_BW:
|
|
printf(", 16-bit");
|
|
break;
|
|
case SDRAM_CFG_8_BW:
|
|
printf(", 8-bit");
|
|
break;
|
|
default:
|
|
printf(", 64-bit");
|
|
break;
|
|
}
|
|
|
|
/* Calculate CAS latency based on timing cfg values */
|
|
cas_lat = ((ddr_in32(&ddr->timing_cfg_1) >> 16) & 0xf);
|
|
cas_lat += 2; /* for DDRC newer than 4.4 */
|
|
cas_lat += ((ddr_in32(&ddr->timing_cfg_3) >> 12) & 3) << 4;
|
|
printf(", CL=%d", cas_lat >> 1);
|
|
if ((cas_lat & 0x1) != 0) {
|
|
printf(".5");
|
|
}
|
|
|
|
if ((sdram_cfg & SDRAM_CFG_ECC_EN) != 0) {
|
|
printf(", ECC on");
|
|
} else {
|
|
printf(", ECC off");
|
|
}
|
|
|
|
if ((cs0_config & 0x20000000) != 0) {
|
|
printf(", ");
|
|
switch ((cs0_config >> 24) & 0xf) {
|
|
case DDR_256B_INTLV:
|
|
printf("256B");
|
|
break;
|
|
default:
|
|
printf("invalid");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (((sdram_cfg >> 8) & 0x7f) != 0) {
|
|
printf(", ");
|
|
switch (sdram_cfg >> 8 & 0x7f) {
|
|
case DDR_BA_INTLV_CS0123:
|
|
printf("CS0+CS1+CS2+CS3");
|
|
break;
|
|
case DDR_BA_INTLV_CS01:
|
|
printf("CS0+CS1");
|
|
break;
|
|
default:
|
|
printf("invalid");
|
|
break;
|
|
}
|
|
}
|
|
printf("\n");
|
|
}
|