diff options
| author | Boyan Karatotev <boyan.karatotev@arm.com> | 2026-06-25 06:43:09 +0000 |
|---|---|---|
| committer | TrustedFirmware Code Review <review@review.trustedfirmware.org> | 2026-06-25 06:43:09 +0000 |
| commit | 5da9bc26bb5bfbb466a092d2169f0c82ea49b938 (patch) | |
| tree | ae22183291d2c655c9e46375d8c170c2b24b0845 | |
| parent | d4809615cc25a7beb0fe292f8a66e3933783a149 (diff) | |
| parent | 93307ca915830c9795440282a70923866f87bc3b (diff) | |
| download | arm-trusted-firmware-5da9bc26bb5bfbb466a092d2169f0c82ea49b938.tar.gz arm-trusted-firmware-5da9bc26bb5bfbb466a092d2169f0c82ea49b938.zip | |
Merge changes from topic "nxp-ddr-lx2160-fixes" into integration
* changes:
fix(nxp-ddr): adjust DDR_DSR2[2] per LX2160A RM
fix(nxp-ddr): support SPD diffs between dual DIMMs
| -rw-r--r-- | drivers/nxp/ddr/nxp-ddr/ddr.c | 78 | ||||
| -rw-r--r-- | drivers/nxp/ddr/nxp-ddr/ddr.mk | 8 | ||||
| -rw-r--r-- | drivers/nxp/ddr/nxp-ddr/ddrc.c | 15 |
3 files changed, 93 insertions, 8 deletions
diff --git a/drivers/nxp/ddr/nxp-ddr/ddr.c b/drivers/nxp/ddr/nxp-ddr/ddr.c index 17c2bbb2a..4346ce646 100644 --- a/drivers/nxp/ddr/nxp-ddr/ddr.c +++ b/drivers/nxp/ddr/nxp-ddr/ddr.c @@ -6,6 +6,7 @@ #include <errno.h> #include <inttypes.h> +#include <stdbool.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -571,8 +572,85 @@ static int parse_spd(struct ddr_info *priv) if (spd_idx != 0 && spd_checksum[0] != spd_checksum[spd_idx]) { +#if defined(NXP_DDR_DUAL_DIMM_TOLERANT) + /* DDR4 SPD bytes that have impacts */ + static const unsigned int timing_bytes[] = { + + /* device key + organisation */ + 2, /* mem_type DDR3 / DDR4 / LPDDR4 key */ + 4, /* density_banks SDRAM density + bank groups */ + 5, /* addressing row/col bit counts */ + 6, /* package_type SDP / DDP / 3DS / QDP */ + 7, /* opt_feature MAW, fault detect */ + 8, /* thermal_ref refresh interval mode */ + 9, /* oth_opt_features PPR / soft-PPR */ + 11, /* module_vdd nominal voltage (DDR4 = 1.2 V) */ + 12, /* organization ranks + DRAM width (x4/x8/x16) */ + 13, /* bus_width primary bus width + ECC bit */ + 14, /* therm_sensor on-DIMM temp-sensor presence */ + + /* DDR4 base timing block - MTB units (MTB = 125 ps) */ + 17, /* timebases MTB/FTB select (0x00 on DDR4) */ + 18, /* tck_min min SDRAM cycle time -> speed bin */ + 19, /* tck_max max SDRAM cycle time */ + 20, /* caslat_b1 supported CAS latencies, byte 1 */ + 21, /* caslat_b2 supported CAS latencies, byte 2 */ + 22, /* caslat_b3 supported CAS latencies, byte 3 */ + 23, /* caslat_b4 supported CAS latencies, byte 4 */ + 24, /* taa_min min CAS latency time -> CL pick */ + 25, /* trcd_min RAS-to-CAS delay */ + 26, /* trp_min row precharge time */ + 27, /* tras_trc_ext upper nibbles for tRAS / tRC */ + 28, /* tras_min_lsb active-to-precharge LSB */ + 29, /* trc_min_lsb row-cycle time LSB */ + 30, /* trfc1_min_lsb refresh recovery 1x mode LSB */ + 31, /* trfc1_min_msb refresh recovery 1x mode MSB */ + 32, /* trfc2_min_lsb refresh recovery 2x mode LSB */ + 33, /* trfc2_min_msb refresh recovery 2x mode MSB */ + 34, /* trfc4_min_lsb refresh recovery 4x mode LSB */ + 35, /* trfc4_min_msb refresh recovery 4x mode MSB */ + 36, /* tfaw_msb four-activate-window upper nibble */ + 37, /* tfaw_min four-activate-window LSB */ + 38, /* trrds_min act-to-act, different bank groups */ + 39, /* trrdl_min act-to-act, same bank group */ + 40, /* tccdl_min CAS-to-CAS, same bank group */ + + /* DDR4 fine timing - FTB units (1 ps), signed deltas */ + 117, /* fine_tccdl_min adds to byte 40 (tccdl_min) */ + 118, /* fine_trrdl_min adds to byte 39 (trrdl_min) */ + 119, /* fine_trrds_min adds to byte 38 (trrds_min) */ + 120, /* fine_trc_min adds to byte 27/29 (trc) */ + 121, /* fine_trp_min adds to byte 26 (trp) */ + 122, /* fine_trcd_min adds to byte 25 (trcd) */ + 123, /* fine_taa_min adds to byte 24 (taa) */ + 124, /* fine_tck_max adds to byte 19 (tck_max) */ + 125, /* fine_tck_min adds to byte 18 (tck_min) */ + }; + const unsigned char *pa = + (const unsigned char *)&spd[0]; + const unsigned char *pb = + (const unsigned char *)&spd[spd_idx]; + bool timing_ok = true; + unsigned int t; + + for (t = 0U; t < ARRAY_SIZE(timing_bytes); t++) { + unsigned int bx = timing_bytes[t]; + + if (pa[bx] != pb[bx]) { + ERROR("DDR SPD timing byte %u: 0x%02x vs 0x%02x\n", + bx, pa[bx], pb[bx]); + timing_ok = false; + } + } + if (!timing_ok) { + ERROR("Not identical DIMMs (timing-relevant mismatch).\n"); + return -EINVAL; + } + NOTICE("DDR SPDs differ for non-timing bytes only -> accepting\n"); +#else ERROR("Not identical DIMMs.\n"); return -EINVAL; +#endif } conf->dimm_in_use[j] = 1; valid_mask |= 1 << addr_idx; diff --git a/drivers/nxp/ddr/nxp-ddr/ddr.mk b/drivers/nxp/ddr/nxp-ddr/ddr.mk index be9163384..35d615dbd 100644 --- a/drivers/nxp/ddr/nxp-ddr/ddr.mk +++ b/drivers/nxp/ddr/nxp-ddr/ddr.mk @@ -74,6 +74,14 @@ ifeq ($(DEBUG_DDR_INPUT_CONFIG), yes) $(eval $(call add_define, DEBUG_DDR_INPUT_CONFIG)) endif +# Tolerant SPD compare workaround is for a dual-DIMM pair whose +# base/module CRCs differ but whose timing-relevant bytes match +# Default off: a CRC mismatch is a hard error unless a board +# wants to be tolerant for such cases. +ifeq ($(NXP_DDR_DUAL_DIMM_TOLERANT), yes) +$(eval $(call add_define,NXP_DDR_DUAL_DIMM_TOLERANT)) +endif + DDR_CNTLR_SOURCES := $(PLAT_DRIVERS_PATH)/ddr/nxp-ddr/ddr.c \ $(PLAT_DRIVERS_PATH)/ddr/nxp-ddr/ddrc.c \ $(PLAT_DRIVERS_PATH)/ddr/nxp-ddr/dimm.c \ diff --git a/drivers/nxp/ddr/nxp-ddr/ddrc.c b/drivers/nxp/ddr/nxp-ddr/ddrc.c index 4133fac1a..24cc0775e 100644 --- a/drivers/nxp/ddr/nxp-ddr/ddrc.c +++ b/drivers/nxp/ddr/nxp-ddr/ddrc.c @@ -426,19 +426,18 @@ after_reset: mb(); isb(); } else { - /* wait for PHY complete */ - timeout = 40; - while (((ddr_in32(&ddr->ddr_dsr2) & 0x4) != 0) && + /* Wait up to 50 ms for DDR_DSR2[2] PHY_INIT_CMPLT to be set. */ + timeout = 100; + while (((ddr_in32(&ddr->ddr_dsr2) & 0x4) == 0) && (timeout > 0)) { udelay(500); timeout--; } - if (timeout <= 0) { - printf("PHY handshake timeout, ddr_dsr2 = %x\n", - ddr_in32(&ddr->ddr_dsr2)); + if (timeout > 0) { + debug("PHY init complete (DSR2[2]=1) in ~%d ms\n", + (100 - timeout) / 2); } else { - debug("PHY handshake completed, timer remains %d\n", - timeout); + WARN("PHY init NOT complete after 50 ms (DSR2[2]=0) -> proceeding, training will report any real fault\n"); } } |
