feat(st-ddr): add STM32MP2 driver

Add driver to support DDR on STM32MP2 platform. It drives the DDR PHY
and its firmware, as well as the DDR controller.

Signed-off-by: Nicolas Le Bayon <nicolas.le.bayon@st.com>
Signed-off-by: Maxime Méré <maxime.mere@foss.st.com>
Change-Id: I93de2db1b9378d5654e76b3bf6f3407d80bc4ca5
This commit is contained in:
Nicolas Le Bayon 2021-07-01 14:44:22 +02:00 committed by Maxime Méré
parent d596023bff
commit 79629b1a79
41 changed files with 18361 additions and 31 deletions

View file

@ -0,0 +1,935 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MNPMUSRAMMSGBLOCK_DDR3_H
#define MNPMUSRAMMSGBLOCK_DDR3_H
/*
* DDR3U_1D training firmware message block structure
*
* Please refer to the Training Firmware App Note for futher information about
* the usage for Message Block.
*/
struct pmu_smb_ddr_1d {
uint8_t reserved00; /*
* Byte offset 0x00, CSR Addr 0x54000, Direction=In
* reserved00[0:4] RFU, must be zero
*
* reserved00[5] = Train vrefDAC0 During Read Deskew
* 0x1 = Read Deskew will begin by enabling and roughly
* training the phy's per-lane reference voltages.
* Training the vrefDACs CSRs will increase the maximum 1D
* training time by around half a millisecond, but will
* improve 1D training accuracy on systems with
* significant voltage-offsets between lane read eyes.
* 0x0 = Read Deskew will assume the messageblock's
* phyVref setting will work for all lanes.
*
* reserved00[6] = Enable High Effort WrDQ1D
* 0x1 = WrDQ1D will conditionally retry training at
* several extra RxClkDly Timings. This will increase the
* maximum 1D training time by up to 4 extra iterations of
* WrDQ1D. This is only required in systems that suffer
* from very large, asymmetric eye-collapse when receiving
* PRBS patterns.
* 0x0 = WrDQ1D assume rxClkDly values found by SI
* Friendly RdDqs1D will work for receiving PRBS patterns
*
* reserved00[7] = Optimize for the special hard macros in
* TSMC28.
* 0x1 = set if the phy being trained was manufactured in
* any TSMC28 process node.
* 0x0 = otherwise, when not training a TSMC28 phy, leave
* this field as 0.
*/
uint8_t msgmisc; /*
* Byte offset 0x01, CSR Addr 0x54000, Direction=In
* Contains various global options for training.
*
* Bit fields:
*
* msgmisc[0] = MTESTEnable
* 0x1 = Pulse primary digital test output bump at the end
* of each major training stage. This enables observation
* of training stage completion by observing the digital
* test output.
* 0x0 = Do not pulse primary digital test output bump
*
* msgmisc[1] = SimulationOnlyReset
* 0x1 = Verilog only simulation option to shorten
* duration of DRAM reset pulse length to 1ns.
* Must never be set to 1 in silicon.
* 0x0 = Use reset pulse length specified by JEDEC
* standard.
*
* msgmisc[2] = SimulationOnlyTraining
* 0x1 = Verilog only simulation option to shorten the
* duration of the training steps by performing fewer
* iterations.
* Must never be set to 1 in silicon.
* 0x0 = Use standard training duration.
*
* msgmisc[3] = RFU, must be zero
*
* msgmisc[4] = Suppress streaming messages, including
* assertions, regardless of hdtctrl setting.
* Stage Completion messages, as well as training completion
* and error messages are still sent depending on hdtctrl
* setting.
*
* msgmisc[5] = PerByteMaxRdLat
* 0x1 = Each DBYTE will return dfi_rddata_valid at the
* lowest possible latency. This may result in unaligned
* data between bytes to be returned to the DFI.
* 0x0 = Every DBYTE will return dfi_rddata_valid
* simultaneously. This will ensure that data bytes will
* return aligned accesses to the DFI.
*
* msgmisc[6] = PartialRank (DDR3 UDIMM and DDR4 UDIMM only,
* otherwise RFU, must be zero)
* 0x1 = Support rank populated with a subset of byte, but
* where even-odd pair of rank support all the byte
* 0x0 = All rank populated with all the byte (tyical
* configuration)
*
* msgmisc[7] RFU, must be zero
*
* Notes:
*
* - SimulationOnlyReset and SimulationOnlyTraining can be
* used to speed up simulation run times, and must never
* be used in real silicon. Some VIPs may have checks on
* DRAM reset parameters that may need to be disabled when
* using SimulationOnlyReset.
*/
uint16_t pmurevision; /*
* Byte offset 0x02, CSR Addr 0x54001, Direction=Out
* PMU firmware revision ID
* After training is run, this address will contain the
* revision ID of the firmware.
* Please reference this revision ID when filing support
* cases.
*/
uint8_t pstate; /*
* Byte offset 0x04, CSR Addr 0x54002, Direction=In
* Must be set to the target pstate to be trained
* 0x0 = pstate 0
* 0x1 = pstate 1
* 0x2 = pstate 2
* 0x3 = pstate 3
* All other encodings are reserved
*/
uint8_t pllbypassen; /*
* Byte offset 0x05, CSR Addr 0x54002, Direction=In
* Set according to whether target pstate uses PHY PLL
* bypass
* 0x0 = PHY PLL is enabled for target pstate
* 0x1 = PHY PLL is bypassed for target pstate
*/
uint16_t dramfreq; /*
* Byte offset 0x06, CSR Addr 0x54003, Direction=In
* DDR data rate for the target pstate in units of MT/s.
* For example enter 0x0640 for DDR1600.
*/
uint8_t dfifreqratio; /*
* Byte offset 0x08, CSR Addr 0x54004, Direction=In
* Frequency ratio betwen DfiCtlClk and SDRAM memclk.
* 0x1 = 1:1
* 0x2 = 1:2
* 0x4 = 1:4
*/
uint8_t bpznresval; /*
* Byte offset 0x09, CSR Addr 0x54004, Direction=In
* Overwrite the value of precision resistor connected to
* Phy BP_ZN
* 0x00 = Do not program. Use current CSR value.
* 0xf0 = 240 Ohm
* 0x78 = 120 Ohm
* 0x28 = 40 Ohm
* All other values are reserved.
* It is recommended to set this to 0x00.
*/
uint8_t phyodtimpedance; /*
* Byte offset 0x0a, CSR Addr 0x54005, Direction=In
* Must be programmed to the termination impedance in ohms
* used by PHY during reads.
*
* 0x0 = Firmware skips programming (must be manually
* programmed by user prior to training start)
*
* See PHY databook for legal termination impedance values.
*
* For digital simulation, any legal value can be used. For
* silicon, the users must determine the correct value
* through SI simulation or other methods.
*/
uint8_t phydrvimpedance; /*
* Byte offset 0x0b, CSR Addr 0x54005, Direction=In
* Must be programmed to the driver impedance in ohms used
* by PHY during writes for all DBYTE drivers
* (DQ/DM/DBI/DQS).
*
* 0x0 = Firmware skips programming (must be manually
* programmed by user prior to training start)
*
* See PHY databook for legal R_on driver impedance values.
*
* For digital simulation, any value can be used that is not
* Hi-Z. For silicon, the users must determine the correct
* value through SI simulation or other methods.
*/
uint8_t phyvref; /*
* Byte offset 0x0c, CSR Addr 0x54006, Direction=In
* Must be programmed with the Vref level to be used by the
* PHY during reads
*
* The units of this field are a percentage of VDDQ
* according to the following equation:
*
* Receiver Vref = VDDQ*phyvref[6:0]/128
*
* For example to set Vref at 0.75*VDDQ, set this field to
* 0x60.
*
* For digital simulation, any legal value can be used. For
* silicon, the users must calculate the analytical Vref by
* using the impedances, terminations, and series resistance
* present in the system.
*/
uint8_t dramtype; /*
* Byte offset 0x0d, CSR Addr 0x54006, Direction=In
* Module Type:
* 0x01 = DDR3 unbuffered
* 0x02 = Reserved
* 0x03 = Reserved
* 0x04 = Reserved
* 0x05 = Reserved
*/
uint8_t disableddbyte; /*
* Byte offset 0x0e, CSR Addr 0x54007, Direction=In
* Bitmap to indicate which Dbyte are not connected (for
* DByte 0 to 7):
* Set disableddbyte[i] to 1 only to specify that DByte is
* not need to be trained (DByte 8 can be disabled via
* enableddqs setting)
*/
uint8_t enableddqs; /*
* Byte offset 0x0f, CSR Addr 0x54007, Direction=In
* Total number of DQ bits enabled in PHY
*/
uint8_t cspresent; /*
* Byte offset 0x10, CSR Addr 0x54008, Direction=In
* Indicates presence of DRAM at each chip select for PHY.
* Each bit corresponds to a logical CS.
*
* If the bit is set to 1, the CS is connected to DRAM.
* If the bit is set to 0, the CS is not connected to DRAM.
*
* cspresent[0] = CS0 is populated with DRAM
* cspresent[1] = CS1 is populated with DRAM
* cspresent[2] = CS2 is populated with DRAM
* cspresent[3] = CS3 is populated with DRAM
* cspresent[7:4] = Reserved (must be programmed to 0)
*/
uint8_t cspresentd0; /*
* Byte offset 0x11, CSR Addr 0x54008, Direction=In
* The CS signals from field cspresent that are routed to
* DIMM connector 0
*/
uint8_t cspresentd1; /*
* Byte offset 0x12, CSR Addr 0x54009, Direction=In
* The CS signals from field cspresent that are routed to
* DIMM connector 1
*/
uint8_t addrmirror; /*
* Byte offset 0x13, CSR Addr 0x54009, Direction=In
* Corresponds to CS[3:0]
* 1 = Address Mirror.
* 0 = No Address Mirror.
*/
uint8_t cstestfail; /*
* Byte offset 0x14, CSR Addr 0x5400a, Direction=Out
* This field will be set if training fails on any rank.
* 0x0 = No failures
* non-zero = one or more ranks failed training
*/
uint8_t phycfg; /*
* Byte offset 0x15, CSR Addr 0x5400a, Direction=In
* Additional mode bits.
*
* Bit fields:
* [0] SlowAccessMode:
* 1 = 2T Address Timing.
* 0 = 1T Address Timing.
* [7-1] RFU, must be zero
*
* WARNING: In case of DDR4 Geardown Mode (mr3[A3] == 1),
* phycfg[0] must be 0.
*/
uint16_t sequencectrl; /*
* Byte offset 0x16, CSR Addr 0x5400b, Direction=In
* Controls the training steps to be run. Each bit
* corresponds to a training step.
*
* If the bit is set to 1, the training step will run.
* If the bit is set to 0, the training step will be
* skipped.
*
* Training step to bit mapping:
* sequencectrl[0] = Run DevInit - Device/phy
* initialization. Should always be set.
* sequencectrl[1] = Run WrLvl - Write leveling
* sequencectrl[2] = Run RxEn - Read gate training
* sequencectrl[3] = Run RdDQS1D - 1d read dqs training
* sequencectrl[4] = Run WrDQ1D - 1d write dq training
* sequencectrl[5] = RFU, must be zero
* sequencectrl[6] = RFU, must be zero
* sequencectrl[7] = RFU, must be zero
* sequencectrl[8] = Run RdDeskew - Per lane read dq deskew
* training
* sequencectrl[9] = Run MxRdLat - Max read latency training
* sequencectrl[10] = RFU, must be zero
* sequencectrl[11] = RFU, must be zero
* sequencectrl[12] = RFU, must be zero
* sequencectrl[13] = RFU, must be zero
* sequencectrl[15-14] = RFU, must be zero
*/
uint8_t hdtctrl; /*
* Byte offset 0x18, CSR Addr 0x5400c, Direction=In
* To control the total number of debug messages, a
* verbosity subfield (hdtctrl, Hardware Debug Trace
* Control) exists in the message block. Every message has a
* verbosity level associated with it, and as the hdtctrl
* value is increased, less important s messages stop being
* sent through the mailboxes. The meanings of several major
* hdtctrl thresholds are explained below:
*
* 0x04 = Maximal debug messages (e.g., Eye contours)
* 0x05 = Detailed debug messages (e.g. Eye delays)
* 0x0A = Coarse debug messages (e.g. rank information)
* 0xC8 = Stage completion
* 0xC9 = Assertion messages
* 0xFF = Firmware completion messages only
*/
uint8_t reserved19; /* Byte offset 0x19, CSR Addr 0x5400c, Direction=N/A */
uint8_t reserved1a; /* Byte offset 0x1a, CSR Addr 0x5400d, Direction=N/A */
uint8_t share2dvrefresult; /*
* Byte offset 0x1b, CSR Addr 0x5400d, Direction=In
* Bitmap that designates the phy's vref source for every
* pstate
* If share2dvrefresult[x] = 0, then after 2D training,
* pstate x will continue using the phyVref provided in
* pstate x's 1D messageblock.
* If share2dvrefresult[x] = 1, then after 2D training,
* pstate x will use the per-lane VrefDAC0/1 CSRs trained by
* 2d training.
*/
uint8_t reserved1c; /* Byte offset 0x1c, CSR Addr 0x5400e, Direction=N/A */
uint8_t reserved1d; /* Byte offset 0x1d, CSR Addr 0x5400e, Direction=N/A */
uint8_t reserved1e; /*
* Byte offset 0x1e, CSR Addr 0x5400f, Direction=In
* Input for constraining the range of vref(DQ) values
* training will collect data for, usually reducing training
* time. However, too large of a voltage range may cause
* longer 2D training times while too small of a voltage
* range may truncate passing regions. When in doubt, leave
* this field set to 0.
* Used by 2D training in: Rd2D, Wr2D
*
* reserved1E[0-3]: Rd2D Voltage Range
* 0 = Training will search all phy vref(DQ) settings
* 1 = limit to +/-2 %VDDQ from phyVref
* 2 = limit to +/-4 %VDDQ from phyVref
* . . .
* 15 = limit to +/-30% VDDQ from phyVref
*
* reserved1E[4-7]: Wr2D Voltage Range
* 0 = Training will search all dram vref(DQ) settings
* 1 = limit to +/-2 %VDDQ from mr6
* 2 = limit to +/-4 %VDDQ from mr6
* . . .
* 15 = limit to +/-30% VDDQ from mr6
*/
uint8_t reserved1f; /*
* Byte offset 0x1f, CSR Addr 0x5400f, Direction=In
* Extended training option:
*
* reserved1F[1:0]: Configured RxClkDly offset try during
* WrDq1D high-effort (i.e., when reserved00[6] is set)
* 0: -8, +8, -16, +16
* 1: -4, +4, -8, +8, -12, +12, -16, +16
* 2: -2, +2, -4, +4, -6, +6, -8, +8
* 3: -2, +2, -4, +4, -6, +6, -8, +8, -10, +10, -12, +12,
* -14, +14, -16, +16
*
* reserved1F[2]: When set, execute again WrDq1D after
* RdDqs1D PRBS
*
* reserved1F[3]: When set redo RdDeskew with PRBS after
* (first) WrDqs1D
*
* reserved1F[7:4]: This field is reserved and must be
* programmed to 0x00.
*/
uint8_t reserved20; /*
* Byte offset 0x20, CSR Addr 0x54010, Direction=In
* This field is reserved and must be programmed to 0x00,
* excepted for Reserved:
* Reserved MREP assume raising edge is found when
* reserved20[3:0]+3 consecutive 1 are received during MREP
* fine delay swept; reserved20[6:0] thus permits to
* increase tolerance for noisy system. And if reserved20[7]
* is set, MREP training is failing if no raising edge is
* found (otherwise the raising edge is assume close to
* delay 0).
*/
uint8_t reserved21; /*
* Byte offset 0x21, CSR Addr 0x54010, Direction=In
* This field is reserved and must be programmed to 0x00,
* excepted for Reserved:
* Reserved DWL assume raising edge is found when
* reserved21[3:0]+3 consecutive 1 are received during DWL
* fine delay swept; reserved21[6:0] thus permits to
* increase tolerance for noisy system. And if reserved21[7]
* is set, DWL training is failing if no raising edge is
* found (otherwise the raising edge is assume close to
* delay 0).
*/
uint16_t phyconfigoverride; /*
* Byte offset 0x22, CSR Addr 0x54011, Direction=In
* Override PhyConfig csr.
* 0x0: Use hardware csr value for PhyConfing
* (recommended)
* Other values: Use value for PhyConfig instead of
* Hardware value.
*/
uint8_t dfimrlmargin; /*
* Byte offset 0x24, CSR Addr 0x54012, Direction=In
* Margin added to smallest passing trained DFI Max Read
* Latency value, in units of DFI clocks. Recommended to be
* >= 1.
*/
int8_t cdd_rr_3_2; /*
* Byte offset 0x25, CSR Addr 0x54012, Direction=Out
* This is a signed integer value.
* Read to read critical delay difference from cs 3 to cs 2.
*/
int8_t cdd_rr_3_1; /*
* Byte offset 0x26, CSR Addr 0x54013, Direction=Out
* This is a signed integer value.
* Read to read critical delay difference from cs 3 to cs 1.
*/
int8_t cdd_rr_3_0; /*
* Byte offset 0x27, CSR Addr 0x54013, Direction=Out
* This is a signed integer value.
* Read to read critical delay difference from cs 3 to cs 0.
*/
int8_t cdd_rr_2_3; /*
* Byte offset 0x28, CSR Addr 0x54014, Direction=Out
* This is a signed integer value.
* Read to read critical delay difference from cs 2 to cs 3.
*/
int8_t cdd_rr_2_1; /*
* Byte offset 0x29, CSR Addr 0x54014, Direction=Out
* This is a signed integer value.
* Read to read critical delay difference from cs 2 to cs 1.
*/
int8_t cdd_rr_2_0; /*
* Byte offset 0x2a, CSR Addr 0x54015, Direction=Out
* This is a signed integer value.
* Read to read critical delay difference from cs 2 to cs 0.
*/
int8_t cdd_rr_1_3; /*
* Byte offset 0x2b, CSR Addr 0x54015, Direction=Out
* This is a signed integer value.
* Read to read critical delay difference from cs 1 to cs 3.
*/
int8_t cdd_rr_1_2; /*
* Byte offset 0x2c, CSR Addr 0x54016, Direction=Out
* This is a signed integer value.
* Read to read critical delay difference from cs 1 to cs 2.
*/
int8_t cdd_rr_1_0; /*
* Byte offset 0x2d, CSR Addr 0x54016, Direction=Out
* This is a signed integer value.
* Read to read critical delay difference from cs 1 to cs 0.
*/
int8_t cdd_rr_0_3; /*
* Byte offset 0x2e, CSR Addr 0x54017, Direction=Out
* This is a signed integer value.
* Read to read critical delay difference from cs 0 to cs 3.
*/
int8_t cdd_rr_0_2; /*
* Byte offset 0x2f, CSR Addr 0x54017, Direction=Out
* This is a signed integer value.
* Read to read critical delay difference from cs 0 to cs 2.
*/
int8_t cdd_rr_0_1; /*
* Byte offset 0x30, CSR Addr 0x54018, Direction=Out
* This is a signed integer value.
* Read to read critical delay difference from cs 0 to cs 1.
*/
int8_t cdd_ww_3_2; /*
* Byte offset 0x31, CSR Addr 0x54018, Direction=Out
* This is a signed integer value.
* Write to write critical delay difference from cs 3 to cs
* 2.
*/
int8_t cdd_ww_3_1; /*
* Byte offset 0x32, CSR Addr 0x54019, Direction=Out
* This is a signed integer value.
* Write to write critical delay difference from cs 3 to cs
* 1.
*/
int8_t cdd_ww_3_0; /*
* Byte offset 0x33, CSR Addr 0x54019, Direction=Out
* This is a signed integer value.
* Write to write critical delay difference from cs 3 to cs
* 0.
*/
int8_t cdd_ww_2_3; /*
* Byte offset 0x34, CSR Addr 0x5401a, Direction=Out
* This is a signed integer value.
* Write to write critical delay difference from cs 2 to cs
* 3.
*/
int8_t cdd_ww_2_1; /*
* Byte offset 0x35, CSR Addr 0x5401a, Direction=Out
* This is a signed integer value.
* Write to write critical delay difference from cs 2 to cs
* 1.
*/
int8_t cdd_ww_2_0; /*
* Byte offset 0x36, CSR Addr 0x5401b, Direction=Out
* This is a signed integer value.
* Write to write critical delay difference from cs 2 to cs
* 0.
*/
int8_t cdd_ww_1_3; /*
* Byte offset 0x37, CSR Addr 0x5401b, Direction=Out
* This is a signed integer value.
* Write to write critical delay difference from cs 1 to cs
* 3.
*/
int8_t cdd_ww_1_2; /*
* Byte offset 0x38, CSR Addr 0x5401c, Direction=Out
* This is a signed integer value.
* Write to write critical delay difference from cs 1 to cs
* 2.
*/
int8_t cdd_ww_1_0; /*
* Byte offset 0x39, CSR Addr 0x5401c, Direction=Out
* This is a signed integer value.
* Write to write critical delay difference from cs 1 to cs
* 0.
*/
int8_t cdd_ww_0_3; /*
* Byte offset 0x3a, CSR Addr 0x5401d, Direction=Out
* This is a signed integer value.
* Write to write critical delay difference from cs 0 to cs
* 3.
*/
int8_t cdd_ww_0_2; /*
* Byte offset 0x3b, CSR Addr 0x5401d, Direction=Out
* This is a signed integer value.
* Write to write critical delay difference from cs 0 to cs
* 2.
*/
int8_t cdd_ww_0_1; /*
* Byte offset 0x3c, CSR Addr 0x5401e, Direction=Out
* This is a signed integer value.
* Write to write critical delay difference from cs 0 to cs
* 1.
*/
int8_t cdd_rw_3_3; /*
* Byte offset 0x3d, CSR Addr 0x5401e, Direction=Out
* This is a signed integer value.
* Read to write critical delay difference from cs 3 to
* cs 3.
*/
int8_t cdd_rw_3_2; /*
* Byte offset 0x3e, CSR Addr 0x5401f, Direction=Out
* This is a signed integer value.
* Read to write critical delay difference from cs 3 to
* cs 2.
*/
int8_t cdd_rw_3_1; /*
* Byte offset 0x3f, CSR Addr 0x5401f, Direction=Out
* This is a signed integer value.
* Read to write critical delay difference from cs 3 to
* cs 1.
*/
int8_t cdd_rw_3_0; /*
* Byte offset 0x40, CSR Addr 0x54020, Direction=Out
* This is a signed integer value.
* Read to write critical delay difference from cs 3 to
* cs 0.
*/
int8_t cdd_rw_2_3; /*
* Byte offset 0x41, CSR Addr 0x54020, Direction=Out
* This is a signed integer value.
* Read to write critical delay difference from cs 2 to
* cs 3.
*/
int8_t cdd_rw_2_2; /*
* Byte offset 0x42, CSR Addr 0x54021, Direction=Out
* This is a signed integer value.
* Read to write critical delay difference from cs 2 to
* cs 2.
*/
int8_t cdd_rw_2_1; /*
* Byte offset 0x43, CSR Addr 0x54021, Direction=Out
* This is a signed integer value.
* Read to write critical delay difference from cs 2 to
* cs 1.
*/
int8_t cdd_rw_2_0; /*
* Byte offset 0x44, CSR Addr 0x54022, Direction=Out
* This is a signed integer value.
* Read to write critical delay difference from cs 2 to
* cs 0.
*/
int8_t cdd_rw_1_3; /*
* Byte offset 0x45, CSR Addr 0x54022, Direction=Out
* This is a signed integer value.
* Read to write critical delay difference from cs 1 to
* cs 3.
*/
int8_t cdd_rw_1_2; /*
* Byte offset 0x46, CSR Addr 0x54023, Direction=Out
* This is a signed integer value.
* Read to write critical delay difference from cs 1 to
* cs 2.
*/
int8_t cdd_rw_1_1; /*
* Byte offset 0x47, CSR Addr 0x54023, Direction=Out
* This is a signed integer value.
* Read to write critical delay difference from cs 1 to
* cs 1.
*/
int8_t cdd_rw_1_0; /*
* Byte offset 0x48, CSR Addr 0x54024, Direction=Out
* This is a signed integer value.
* Read to write critical delay difference from cs 1 to
* cs 0.
*/
int8_t cdd_rw_0_3; /*
* Byte offset 0x49, CSR Addr 0x54024, Direction=Out
* This is a signed integer value.
* Read to write critical delay difference from cs 0 to
* cs 3.
*/
int8_t cdd_rw_0_2; /*
* Byte offset 0x4a, CSR Addr 0x54025, Direction=Out
* This is a signed integer value.
* Read to write critical delay difference from cs 0 to
* cs 2.
*/
int8_t cdd_rw_0_1; /*
* Byte offset 0x4b, CSR Addr 0x54025, Direction=Out
* This is a signed integer value.
* Read to write critical delay difference from cs 0 to
* cs 1.
*/
int8_t cdd_rw_0_0; /*
* Byte offset 0x4c, CSR Addr 0x54026, Direction=Out
* This is a signed integer value.
* Read to write critical delay difference from cs 0 to
* cs 0.
*/
int8_t cdd_wr_3_3; /*
* Byte offset 0x4d, CSR Addr 0x54026, Direction=Out
* This is a signed integer value.
* Write to read critical delay difference from cs 3 to
* cs 3.
*/
int8_t cdd_wr_3_2; /*
* Byte offset 0x4e, CSR Addr 0x54027, Direction=Out
* This is a signed integer value.
* Write to read critical delay difference from cs 3 to
* cs 2.
*/
int8_t cdd_wr_3_1; /*
* Byte offset 0x4f, CSR Addr 0x54027, Direction=Out
* This is a signed integer value.
* Write to read critical delay difference from cs 3 to
* cs 1.
*/
int8_t cdd_wr_3_0; /*
* Byte offset 0x50, CSR Addr 0x54028, Direction=Out
* This is a signed integer value.
* Write to read critical delay difference from cs 3 to
* cs 0.
*/
int8_t cdd_wr_2_3; /*
* Byte offset 0x51, CSR Addr 0x54028, Direction=Out
* This is a signed integer value.
* Write to read critical delay difference from cs 2 to
* cs 3.
*/
int8_t cdd_wr_2_2; /*
* Byte offset 0x52, CSR Addr 0x54029, Direction=Out
* This is a signed integer value.
* Write to read critical delay difference from cs 2 to
* cs 2.
*/
int8_t cdd_wr_2_1; /*
* Byte offset 0x53, CSR Addr 0x54029, Direction=Out
* This is a signed integer value.
* Write to read critical delay difference from cs 2 to
* cs 1.
*/
int8_t cdd_wr_2_0; /*
* Byte offset 0x54, CSR Addr 0x5402a, Direction=Out
* This is a signed integer value.
* Write to read critical delay difference from cs 2 to
* cs 0.
*/
int8_t cdd_wr_1_3; /*
* Byte offset 0x55, CSR Addr 0x5402a, Direction=Out
* This is a signed integer value.
* Write to read critical delay difference from cs 1 to
* cs 3.
*/
int8_t cdd_wr_1_2; /*
* Byte offset 0x56, CSR Addr 0x5402b, Direction=Out
* This is a signed integer value.
* Write to read critical delay difference from cs 1 to
* cs 2.
*/
int8_t cdd_wr_1_1; /*
* Byte offset 0x57, CSR Addr 0x5402b, Direction=Out
* This is a signed integer value.
* Write to read critical delay difference from cs 1 to
* cs 1.
*/
int8_t cdd_wr_1_0; /*
* Byte offset 0x58, CSR Addr 0x5402c, Direction=Out
* This is a signed integer value.
* Write to read critical delay difference from cs 1 to
* cs 0.
*/
int8_t cdd_wr_0_3; /*
* Byte offset 0x59, CSR Addr 0x5402c, Direction=Out
* This is a signed integer value.
* Write to read critical delay difference from cs 0 to
* cs 3.
*/
int8_t cdd_wr_0_2; /*
* Byte offset 0x5a, CSR Addr 0x5402d, Direction=Out
* This is a signed integer value.
* Write to read critical delay difference from cs 0 to
* cs 2.
*/
int8_t cdd_wr_0_1; /*
* Byte offset 0x5b, CSR Addr 0x5402d, Direction=Out
* This is a signed integer value.
* Write to read critical delay difference from cs 0 to
* cs 1.
*/
int8_t cdd_wr_0_0; /*
* Byte offset 0x5c, CSR Addr 0x5402e, Direction=Out
* This is a signed integer value.
* Write to read critical delay difference from cs 0 to
* cs 0.
*/
uint8_t reserved5d; /*
* Byte offset 0x5d, CSR Addr 0x5402e, Direction=In
* This field is reserved and must be programmed to 0x00,
* excepted for DDR4:
* By default, if this parameter is 0, the offset applied at
* the end of DDR4 RxEn training resulting in the trained
* RxEnDly is 3/8 of the RX preamble width; if reserved5D is
* non zero, this offset is used instead (in fine step).
*/
uint16_t mr0; /*
* Byte offset 0x5e, CSR Addr 0x5402f, Direction=In
* Value of DDR mode register mr0 for all ranks for current
* pstate.
*/
uint16_t mr1; /*
* Byte offset 0x60, CSR Addr 0x54030, Direction=In
* Value of DDR mode register mr1 for all ranks for current
* pstate.
*/
uint16_t mr2; /*
* Byte offset 0x62, CSR Addr 0x54031, Direction=In
* Value of DDR mode register mr2 for all ranks for current
* pstate.
*/
uint8_t reserved64; /*
* Byte offset 0x64, CSR Addr 0x54032, Direction=In
* Reserved64[0] = protect memory reset
* 0x0 = dfi_reset_n cannot control CP_MEMRESET_L to
* devices after training. (Default value)
* 0x1 = dfi_reset_n can control CP_MEMRESET_L to
* devices after training.
*
* Reserved64[7:1] RFU, must be zero
*/
uint8_t reserved65; /*
* Byte offset 0x65, CSR Addr 0x54032, Direction=N/A
* This field is reserved and must be programmed to 0x00.
*/
uint8_t reserved66; /*
* Byte offset 0x66, CSR Addr 0x54033, Direction=N/A
* This field is reserved and must be programmed to 0x00.
*/
uint8_t reserved67; /*
* Byte offset 0x67, CSR Addr 0x54033, Direction=N/A
* This field is reserved and must be programmed to 0x00.
*/
uint8_t reserved68; /*
* Byte offset 0x68, CSR Addr 0x54034, Direction=N/A
* This field is reserved and must be programmed to 0x00.
*/
uint8_t reserved69; /*
* Byte offset 0x69, CSR Addr 0x54034, Direction=N/A
* This field is reserved and must be programmed to 0x00.
*/
uint8_t reserved6a; /*
* Byte offset 0x6a, CSR Addr 0x54035, Direction=N/A
* This field is reserved and must be programmed to 0x00.
*/
uint8_t reserved6b; /*
* Byte offset 0x6b, CSR Addr 0x54035, Direction=N/A
* This field is reserved and must be programmed to 0x00.
*/
uint8_t reserved6c; /*
* Byte offset 0x6c, CSR Addr 0x54036, Direction=N/A
* This field is reserved and must be programmed to 0x00.
*/
uint8_t reserved6d; /*
* Byte offset 0x6d, CSR Addr 0x54036, Direction=N/A
* This field is reserved and must be programmed to 0x00.
*/
uint8_t reserved6e; /*
* Byte offset 0x6e, CSR Addr 0x54037, Direction=N/A
* This field is reserved and must be programmed to 0x00.
*/
uint8_t reserved6f; /*
* Byte offset 0x6f, CSR Addr 0x54037, Direction=N/A
* This field is reserved and must be programmed to 0x00.
*/
uint8_t reserved70; /*
* Byte offset 0x70, CSR Addr 0x54038, Direction=N/A
* This field is reserved and must be programmed to 0x00.
*/
uint8_t reserved71; /*
* Byte offset 0x71, CSR Addr 0x54038, Direction=N/A
* This field is reserved and must be programmed to 0x00.
*/
uint8_t reserved72; /*
* Byte offset 0x72, CSR Addr 0x54039, Direction=N/A
* This field is reserved and must be programmed to 0x00.
*/
uint8_t reserved73; /*
* Byte offset 0x73, CSR Addr 0x54039, Direction=N/A
* This field is reserved and must be programmed to 0x00.
*/
uint8_t acsmodtctrl0; /*
* Byte offset 0x74, CSR Addr 0x5403a, Direction=In
* Odt pattern for accesses targeting rank 0. [3:0] is used
* for write ODT [7:4] is used for read ODT
*/
uint8_t acsmodtctrl1; /*
* Byte offset 0x75, CSR Addr 0x5403a, Direction=In
* Odt pattern for accesses targeting rank 1. [3:0] is used
* for write ODT [7:4] is used for read ODT
*/
uint8_t acsmodtctrl2; /*
* Byte offset 0x76, CSR Addr 0x5403b, Direction=In
* Odt pattern for accesses targeting rank 2. [3:0] is used
* for write ODT [7:4] is used for read ODT
*/
uint8_t acsmodtctrl3; /*
* Byte offset 0x77, CSR Addr 0x5403b, Direction=In
* Odt pattern for accesses targeting rank 3. [3:0] is used
* for write ODT [7:4] is used for read ODT
*/
uint8_t acsmodtctrl4; /*
* Byte offset 0x78, CSR Addr 0x5403c, Direction=In
* This field is reserved and must be programmed to 0x00.
*/
uint8_t acsmodtctrl5; /*
* Byte offset 0x79, CSR Addr 0x5403c, Direction=In
* This field is reserved and must be programmed to 0x00.
*/
uint8_t acsmodtctrl6; /*
* Byte offset 0x7a, CSR Addr 0x5403d, Direction=In
* This field is reserved and must be programmed to 0x00.
*/
uint8_t acsmodtctrl7; /*
* Byte offset 0x7b, CSR Addr 0x5403d, Direction=In
* This field is reserved and must be programmed to 0x00.
*/
uint8_t reserved7c; /*
* Byte offset 0x7c, CSR Addr 0x5403e, Direction=N/A
* This field is reserved and must be programmed to 0x00.
*/
uint8_t reserved7d; /*
* Byte offset 0x7d, CSR Addr 0x5403e, Direction=N/A
* This field is reserved and must be programmed to 0x00.
*/
uint8_t reserved7e; /*
* Byte offset 0x7e, CSR Addr 0x5403f, Direction=N/A
* This field is reserved and must be programmed to 0x00.
*/
uint8_t reserved7f; /*
* Byte offset 0x7f, CSR Addr 0x5403f, Direction=N/A
* This field is reserved and must be programmed to 0x00.
*/
uint8_t reserved80; /*
* Byte offset 0x80, CSR Addr 0x54040, Direction=N/A
* This field is reserved and must be programmed to 0x00.
*/
uint8_t reserved81; /*
* Byte offset 0x81, CSR Addr 0x54040, Direction=N/A
* This field is reserved and must be programmed to 0x00.
*/
uint8_t reserved82; /*
* Byte offset 0x82, CSR Addr 0x54041, Direction=N/A
* This field is reserved and must be programmed to 0x00.
*/
uint8_t reserved83; /*
* Byte offset 0x83, CSR Addr 0x54041, Direction=N/A
* This field is reserved and must be programmed to 0x00.
*/
uint8_t reserved84; /* Byte offset 0x84, CSR Addr 0x54042, Direction=N/A */
uint8_t reserved85; /* Byte offset 0x85, CSR Addr 0x54042, Direction=N/A */
uint8_t reserved86; /* Byte offset 0x86, CSR Addr 0x54043, Direction=N/A */
uint8_t reserved87; /* Byte offset 0x87, CSR Addr 0x54043, Direction=N/A */
uint8_t reserved88; /* Byte offset 0x88, CSR Addr 0x54044, Direction=N/A */
uint8_t reserved89; /* Byte offset 0x89, CSR Addr 0x54044, Direction=N/A */
uint8_t reserved8a; /* Byte offset 0x8a, CSR Addr 0x54045, Direction=N/A */
uint8_t reserved8b; /* Byte offset 0x8b, CSR Addr 0x54045, Direction=N/A */
uint8_t reserved8c; /* Byte offset 0x8c, CSR Addr 0x54046, Direction=N/A */
uint8_t reserved8d; /* Byte offset 0x8d, CSR Addr 0x54046, Direction=N/A */
uint8_t reserved8e; /* Byte offset 0x8e, CSR Addr 0x54047, Direction=N/A */
uint8_t reserved8f; /* Byte offset 0x8f, CSR Addr 0x54047, Direction=N/A */
uint8_t reserved90; /* Byte offset 0x90, CSR Addr 0x54048, Direction=N/A */
uint8_t reserved91; /* Byte offset 0x91, CSR Addr 0x54048, Direction=N/A */
uint8_t reserved92; /* Byte offset 0x92, CSR Addr 0x54049, Direction=N/A */
uint8_t reserved93; /* Byte offset 0x93, CSR Addr 0x54049, Direction=N/A */
uint8_t reserved94; /* Byte offset 0x94, CSR Addr 0x5404a, Direction=N/A */
uint8_t reserved95; /* Byte offset 0x95, CSR Addr 0x5404a, Direction=N/A */
uint8_t reserved96; /* Byte offset 0x96, CSR Addr 0x5404b, Direction=N/A */
uint8_t reserved97; /* Byte offset 0x97, CSR Addr 0x5404b, Direction=N/A */
uint8_t reserved98; /* Byte offset 0x98, CSR Addr 0x5404c, Direction=N/A */
uint8_t reserved99; /* Byte offset 0x99, CSR Addr 0x5404c, Direction=N/A */
uint8_t reserved9a; /* Byte offset 0x9a, CSR Addr 0x5404d, Direction=N/A */
uint8_t reserved9b; /* Byte offset 0x9b, CSR Addr 0x5404d, Direction=N/A */
uint8_t reserved9c; /* Byte offset 0x9c, CSR Addr 0x5404e, Direction=N/A */
uint8_t reserved9d; /* Byte offset 0x9d, CSR Addr 0x5404e, Direction=N/A */
uint8_t reserved9e; /* Byte offset 0x9e, CSR Addr 0x5404f, Direction=N/A */
uint8_t reserved9f; /* Byte offset 0x9f, CSR Addr 0x5404f, Direction=N/A */
uint8_t reserveda0; /* Byte offset 0xa0, CSR Addr 0x54050, Direction=N/A */
uint8_t reserveda1; /* Byte offset 0xa1, CSR Addr 0x54050, Direction=N/A */
uint8_t reserveda2; /* Byte offset 0xa2, CSR Addr 0x54051, Direction=N/A */
uint8_t reserveda3; /* Byte offset 0xa3, CSR Addr 0x54051, Direction=N/A */
} __packed __aligned(2);
#endif /* MNPMUSRAMMSGBLOCK_DDR3_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,925 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MNPMUSRAMMSGBLOCK_LPDDR4_H
#define MNPMUSRAMMSGBLOCK_LPDDR4_H
/* LPDDR4_1D training firmware message block structure
*
* Please refer to the Training Firmware App Note for futher information about
* the usage for Message Block.
*/
struct pmu_smb_ddr_1d {
uint8_t reserved00; /*
* Byte offset 0x00, CSR Addr 0x54000, Direction=In
* reserved00[0:4] RFU, must be zero
*
* reserved00[5] = Quick Rd2D during 1D Training
* 0x1 = Read Deskew will begin by enabling and quickly
* training the phy's per-lane reference voltages.
* Training the vrefDACs CSRs will increase the maximum 1D
* training time by around half a millisecond, but will
* improve 1D training accuracy on systems with
* significant voltage-offsets between lane read eyes.
* 0x0 = Read Deskew will assume the messageblock's
* phyVref setting is optimal for all lanes.
*
* reserved00[6] = Enable High Effort WrDQ1D
* 0x1 = WrDQ1D will conditionally retry training at
* several extra RxClkDly Timings. This will increase the
* maximum 1D training time by up to 4 extra iterations of
* WrDQ1D. This is only required in systems that suffer
* from very large, asymmetric eye-collapse when receiving
* PRBS patterns.
* 0x0 = WrDQ1D assume rxClkDly values found by SI
* Friendly RdDqs1D will work for receiving PRBS patterns
*
* reserved00[7] = Optimize for the special hard macros in
* TSMC28.
* 0x1 = set if the phy being trained was manufactured in
* any TSMC28 process node.
* 0x0 = otherwise, when not training a TSMC28 phy, leave
* this field as 0.
*/
uint8_t msgmisc; /*
* Byte offset 0x01, CSR Addr 0x54000, Direction=In
* Contains various global options for training.
*
* Bit fields:
*
* msgmisc[0] MTESTEnable
* 0x1 = Pulse primary digital test output bump at the end
* of each major training stage. This enables observation
* of training stage completion by observing the digital
* test output.
* 0x0 = Do not pulse primary digital test output bump
*
* msgmisc[1] SimulationOnlyReset
* 0x1 = Verilog only simulation option to shorten
* duration of DRAM reset pulse length to 1ns.
* Must never be set to 1 in silicon.
* 0x0 = Use reset pulse length specified by JEDEC
* standard.
*
* msgmisc[2] SimulationOnlyTraining
* 0x1 = Verilog only simulation option to shorten the
* duration of the training steps by performing fewer
* iterations.
* Must never be set to 1 in silicon.
* 0x0 = Use standard training duration.
*
* msgmisc[3] Disable Boot Clock
* 0x1 = Disable boot frequency clock when initializing
* DRAM. (not recommended)
* 0x0 = Use Boot Frequency Clock
*
* msgmisc[4] Suppress streaming messages, including
* assertions, regardless of hdtctrl setting.
* Stage Completion messages, as well as training completion
* and error messages are still sent depending on hdtctrl
* setting.
*
* msgmisc[5] PerByteMaxRdLat
* 0x1 = Each DBYTE will return dfi_rddata_valid at the
* lowest possible latency. This may result in unaligned
* data between bytes to be returned to the DFI.
* 0x0 = Every DBYTE will return dfi_rddata_valid
* simultaneously. This will ensure that data bytes will
* return aligned accesses to the DFI.
*
* msgmisc[7-6] RFU, must be zero
*
* Notes:
*
* - SimulationOnlyReset and SimulationOnlyTraining can be
* used to speed up simulation run times, and must never
* be used in real silicon. Some VIPs may have checks on
* DRAM reset parameters that may need to be disabled when
* using SimulationOnlyReset.
*/
uint16_t pmurevision; /*
* Byte offset 0x02, CSR Addr 0x54001, Direction=Out
* PMU firmware revision ID
* After training is run, this address will contain the
* revision ID of the firmware
*/
uint8_t pstate; /*
* Byte offset 0x04, CSR Addr 0x54002, Direction=In
* Must be set to the target pstate to be trained
* 0x0 = pstate 0
* 0x1 = pstate 1
* 0x2 = pstate 2
* 0x3 = pstate 3
* All other encodings are reserved
*/
uint8_t pllbypassen; /*
* Byte offset 0x05, CSR Addr 0x54002, Direction=In
* Set according to whether target pstate uses PHY PLL
* bypass
* 0x0 = PHY PLL is enabled for target pstate
* 0x1 = PHY PLL is bypassed for target pstate
*/
uint16_t dramfreq; /*
* Byte offset 0x06, CSR Addr 0x54003, Direction=In
* DDR data rate for the target pstate in units of MT/s.
* For example enter 0x0640 for DDR1600.
*/
uint8_t dfifreqratio; /*
* Byte offset 0x08, CSR Addr 0x54004, Direction=In
* Frequency ratio betwen DfiCtlClk and SDRAM memclk.
* 0x1 = 1:1
* 0x2 = 1:2
* 0x4 = 1:4
*/
uint8_t bpznresval; /*
* Byte offset 0x09, CSR Addr 0x54004, Direction=In
* Overwrite the value of precision resistor connected to
* Phy BP_ZN
* 0x00 = Do not program. Use current CSR value.
* 0xf0 = 240 Ohm
* 0x78 = 120 Ohm
* 0x28 = 40 Ohm
* All other values are reserved.
* It is recommended to set this to 0x00.
*/
uint8_t phyodtimpedance; /*
* Byte offset 0x0a, CSR Addr 0x54005, Direction=In
* Must be programmed to the termination impedance in ohms
* used by PHY during reads.
*
* 0x0 = Firmware skips programming (must be manually
* programmed by user prior to training start)
*
* See PHY databook for legal termination impedance values.
*
* For digital simulation, any legal value can be used. For
* silicon, the users must determine the correct value
* through SI simulation or other methods.
*/
uint8_t phydrvimpedance; /*
* Byte offset 0x0b, CSR Addr 0x54005, Direction=In
* Must be programmed to the driver impedance in ohms used
* by PHY during writes for all DBYTE drivers
* (DQ/DM/DBI/DQS).
*
* 0x0 = Firmware skips programming (must be manually
* programmed by user prior to training start)
*
* See PHY databook for legal R_on driver impedance values.
*
* For digital simulation, any value can be used that is not
* Hi-Z. For silicon, the users must determine the correct
* value through SI simulation or other methods.
*/
uint8_t phyvref; /*
* Byte offset 0x0c, CSR Addr 0x54006, Direction=In
* Must be programmed with the Vref level to be used by the
* PHY during reads
*
* The units of this field are a percentage of VDDQ
* according to the following equation:
*
* Receiver Vref = VDDQ*phyvref[6:0]/128
*
* For example to set Vref at 0.25*VDDQ, set this field to
* 0x20.
*
* For digital simulation, any legal value can be used. For
* silicon, the users must calculate the analytical Vref by
* using the impedances, terminations, and series resistance
* present in the system.
*/
uint8_t lp4misc; /*
* Byte offset 0x0d, CSR Addr 0x54006, Direction=In
* Lp4 specific options for training.
*
* Bit fields:
*
* lp4misc[0] Enable dfi_reset_n
*
* 0x0 = (Recommended) PHY internal registers control
* memreset during training, and also after training.
* dfi_reset_n cannot control the PHY BP_MEMRESET_L pin.
*
* 0x1 = Enables dfi_reset_n to control memreset after
* training. PHY Internal registers control memreset
* during training only. To ensure that no glitches occur
* on BP_MEMRESET at the end of training, The MC must
* drive dfi_reset_n=1'b1 _prior to starting training_
*
* lp4misc[7-1] RFU, must be zero
*/
uint8_t reserved0e; /*
* Byte offset 0x0e, CSR Addr 0x54007, Direction=In
* Bit Field for enabling optional 2D training features
* that impact both Rx2D and Tx2D.
*
* reserved0E[0:3]: bitTimeControl
* input for the amount of data bits 2D writes/reads per DQ
* before deciding if any specific voltage and delay setting
* passes or fails. Every time this input increases by 1,
* the number of 2D data comparisons is doubled. The 2D run
* time will increase proportionally to the number of bit
* times requested per point.
* 0 = 288 bits per point (legacy behavior)
* 1 = 576 bits per point
* 2 = 1.125 kilobits per point
* . . .
* 15 = 9 megabits per point
*
* reserved0E[4]: Exhaustive2D
* 0 = 2D optimization assumes the optimal trained point
* is near the 1D trained point (legacy behavior)
* 1 = 2D optimization searches the entire passing region
* at the cost of run time. Recommended for optimal
* results any time the optimal trained point is expected
* to be near the edges of the eyes instead of near the 1D
* trained point.
*
* reserved0E[5]: Detect Vref Eye Truncation, ignored if
* eyeWeight2DControl == 0.
* 0 = 2D optimizes for the passing region it can measure.
* 1 = For every eye, 2D checks If the legal voltage range
* truncated the eye. If the true voltage margin cannot be
* measured, 2D will optimize heavily for delay margin
* instead of using incomplete voltage margin data. Eyes
* that are not truncated will still be optimized using
* user programmed weights.
*
* reserved0E[6]: eyeWeight2DControl
* 0 = Use 8 bit weights for Delay_Weight2D and
* Voltage_Weight2D and disable TrunkV behavior.
* 1 = Use 4 bit weights for Delay_weight2D and
* Voltage_Weight2D and enable TrunkV behavior.
*
* reserved0E[7]: RFU, must be 0
*/
uint8_t cstestfail; /*
* Byte offset 0x0f, CSR Addr 0x54007, Direction=Out
* This field will be set if training fails on any rank.
* 0x0 = No failures
* non-zero = one or more ranks failed training
*/
uint16_t sequencectrl; /*
* Byte offset 0x10, CSR Addr 0x54008, Direction=In
* Controls the training steps to be run. Each bit
* corresponds to a training step.
*
* If the bit is set to 1, the training step will run.
* If the bit is set to 0, the training step will be
* skipped.
*
* Training step to bit mapping:
* sequencectrl[0] = Run DevInit - Device/phy
* initialization. Should always be set.
* sequencectrl[1] = Run WrLvl - Write leveling
* sequencectrl[2] = Run RxEn - Read gate training
* sequencectrl[3] = Run RdDQS1D - 1d read dqs training
* sequencectrl[4] = Run WrDQ1D - 1d write dq training
* sequencectrl[5] = RFU, must be zero
* sequencectrl[6] = RFU, must be zero
* sequencectrl[7] = RFU, must be zero
* sequencectrl[8] = Run RdDeskew - Per lane read dq deskew
* training
* sequencectrl[9] = Run MxRdLat - Max read latency training
* sequencectrl[11-10] = RFU, must be zero
* sequencectrl[12] = Run LPCA - CA Training
* sequencectrl[15-13] = RFU, must be zero
*/
uint8_t hdtctrl; /*
* Byte offset 0x12, CSR Addr 0x54009, Direction=In
* To control the total number of debug messages, a
* verbosity subfield (hdtctrl, Hardware Debug Trace
* Control) exists in the message block. Every message has a
* verbosity level associated with it, and as the hdtctrl
* value is increased, less important s messages stop being
* sent through the mailboxes. The meanings of several major
* hdtctrl thresholds are explained below:
*
* 0x04 = Maximal debug messages (e.g., Eye contours)
* 0x05 = Detailed debug messages (e.g. Eye delays)
* 0x0A = Coarse debug messages (e.g. rank information)
* 0xC8 = Stage completion
* 0xC9 = Assertion messages
* 0xFF = Firmware completion messages only
*/
uint8_t reserved13; /*
* Byte offset 0x13, CSR Addr 0x54009, Direction=In
*
* 0 = Default operation, unchanged.
* Others = RD DQ calibration Training steps are completed
* with user specified pattern.
*/
uint8_t reserved14; /*
* Byte offset 0x14, CSR Addr 0x5400a, Direction=In
* Configure rd2D search iteration from a starting seed
* point:
*
* reserved14[5:0]: If reserved14[6] is 0, Number of search
* iterations (if 0, then default is 20); otherwise if this
* value non zero, this value is used as a delta to filter
* out points during the averaging: when averaging over a
* dimension (delay or voltage), the points having a margin
* smaller than the max of the eye in this dimension by at
* least this delta value are filtered out.
*
* reserved14[6]: If set, instead of search, extract center
* using an averaging function over the eye surface area,
* where some points can be filtered out using
* reserved14[5:0]
*
* reserved14[7]: if set, start search with large step size,
* decreasing at each 4 iterations, down to 1 (do not care
* if reserved14[6] is set)
*/
uint8_t reserved15; /*
* Byte offset 0x15, CSR Addr 0x5400a, Direction=In
* Configure wr2D search iteration from a starting seed
* point:
*
* reserved15[5:0]: If reserved15[6] is 0, Number of search
* iterations (if 0, then default is 20); otherwise if this
* value non zero, this value is used as a delta to filter
* out points during the averaging: when averaging over a
* dimension (delay or voltage), the points having a margin
* smaller than the max of the eye in this dimension by at
* least this delta value are filtered out.
*
* reserved15[6]: If set, instead of search, extract center
* using an averaging function over the eye surface area,
* where some points can be filtered out using
* reserved15[5:0]
*
* reserved15[7]: if set, start search with large step size,
* decreasing at each 4 iterations, down to 1 (do not care
* if reserved15[6] is set)
*/
uint8_t dfimrlmargin; /*
* Byte offset 0x16, CSR Addr 0x5400b, Direction=In
* Margin added to smallest passing trained DFI Max Read
* Latency value, in units of DFI clocks. Recommended to be
* >= 1.
*
* This margin must include the maximum positive drift
* expected in tDQSCK over the target temperature and
* voltage range of the users system.
*/
uint8_t reserved17; /*
* Byte offset 0x17, CSR Addr 0x5400b, Direction=In
* Configure DB from which extra info is dump during 2D
* training when maximal debug is set:
*
* reserved17[3:0]: first DB
*
* reserved17[7:4]: number of DB, including first DB (if 0,
* no extra debug per DB is dump)
*/
uint8_t usebroadcastmr; /*
* Byte offset 0x18, CSR Addr 0x5400c, Direction=In
* Training firmware can optionally set per rank mode
* register values for DRAM partial array self-refresh
* features if desired.
*
* 0x0 = Use mr<1:4, 11:14, 16:17, 22, 24>_a0 for rank 0
* channel A
* Use mr<1:4, 11:14, 16:17, 22, 24>_b0 for rank 0
* channel B
* Use mr<1:4, 11:14, 16:17, 22, 24>_a1 for rank 1
* channel A
* Use mr<1:4, 11:14, 16:17, 22, 24>_b1 for rank 1
* channel B
*
* 0x1 = Use mr<1:4, 11:14, 16:17, 22, 24>_a0 setting for
* all channels/ranks
*
* It is recommended in most LPDDR4 system configurations
* to set this to 1.
* It is recommended in LPDDR4x system configurations to
* set this to 0.
*/
uint8_t lp4quickboot; /*
* Byte offset 0x19, CSR Addr 0x5400c, Direction=In
* Enable Quickboot. It must be set to 0x0 since Quickboot
* is only supported in dedicated Quickboot firmware.
*/
uint8_t reserved1a; /*
* Byte offset 0x1a, CSR Addr 0x5400d, Direction=In
* Input for constraining the range of vref(DQ) values
* training will collect data for, usually reducing training
* time. However, too large of a voltage range may cause
* longer 2D training times while too small of a voltage
* range may truncate passing regions. When in doubt, leave
* this field set to 0.
* Used by 2D stages: Rd2D, Wr2D
*
* reserved1A[0-3]: Rd2D Voltage Range
* 0 = Training will search all phy vref(DQ) settings
* 1 = limit to +/-2 %VDDQ from phyVref
* 2 = limit to +/-4 %VDDQ from phyVref
* . . .
* 15 = limit to +/-30% VDDQ from phyVref
*
* reserved1A[4-7]: Wr2D Voltage Range
* 0 = Training will search all dram vref(DQ) settings
* 1 = limit to +/-2 %VDDQ from mr14
* 2 = limit to +/-4 %VDDQ from mr14
* . . .
* 15 = limit to +/-30% VDDQ from mr14
*/
uint8_t catrainopt; /*
* Byte offset 0x1b, CSR Addr 0x5400d, Direction=In
* CA training option bit field
* [0] CA VREF Training
* 1 = Enable CA VREF Training
* 0 = Disable CA VREF Training
* WARNING: catrainopt[0] must be set to the same value in
* 1D and 2D training.
*
* [1] Train terminated Rank only
* 1 = Only train terminated rank in CA training
* 0 = Train all ranks in CA training
*
* [2-7] RFU must be zero
*/
uint8_t x8mode; /*
* Byte offset 0x1c, CSR Addr 0x5400e, Direction=In
* X8 mode configuration:
* 0x0 = x16 configuration for all devices
* 0xF = x8 configuration for all devices
* All other values are RFU
*/
uint8_t reserved1d; /* Byte offset 0x1d, CSR Addr 0x5400e, Direction=N/A */
uint8_t reserved1e; /* Byte offset 0x1e, CSR Addr 0x5400f, Direction=N/A */
uint8_t share2dvrefresult; /*
* Byte offset 0x1f, CSR Addr 0x5400f, Direction=In
* Bitmap that designates the phy's vref source for every
* pstate
* If share2dvrefresult[x] = 0, then after 2D training,
* pstate x will continue using the phyVref provided in
* pstate x's 1D messageblock.
* If share2dvrefresult[x] = 1, then after 2D training,
* pstate x will use the per-lane VrefDAC0/1 CSRs trained by
* 2d training.
*/
uint8_t reserved20; /* Byte offset 0x20, CSR Addr 0x54010, Direction=N/A */
uint8_t reserved21; /* Byte offset 0x21, CSR Addr 0x54010, Direction=N/A */
uint16_t phyconfigoverride; /*
* Byte offset 0x22, CSR Addr 0x54011, Direction=In
* Override PhyConfig csr.
* 0x0: Use hardware csr value for PhyConfing
* (recommended)
* Other values: Use value for PhyConfig instead of
* Hardware value.
*
*/
uint8_t enableddqscha; /*
* Byte offset 0x24, CSR Addr 0x54012, Direction=In
* Total number of DQ bits enabled in PHY Channel A
*/
uint8_t cspresentcha; /*
* Byte offset 0x25, CSR Addr 0x54012, Direction=In
* Indicates presence of DRAM at each chip select for PHY
* channel A.
* 0x1 = CS0 is populated with DRAM
* 0x3 = CS0 and CS1 are populated with DRAM
*
* All other encodings are illegal
*/
int8_t cdd_cha_rr_1_0; /*
* Byte offset 0x26, CSR Addr 0x54013, Direction=Out
* This is a signed integer value.
* Read to read critical delay difference from cs 1 to cs 0
* on Channel A.
*/
int8_t cdd_cha_rr_0_1; /*
* Byte offset 0x27, CSR Addr 0x54013, Direction=Out
* This is a signed integer value.
* Read to read critical delay difference from cs 0 to cs 1
* on Channel A.
*/
int8_t cdd_cha_rw_1_1; /*
* Byte offset 0x28, CSR Addr 0x54014, Direction=Out
* This is a signed integer value.
* Read to write critical delay difference from cs 1 to cs 1
* on Channel A.
*/
int8_t cdd_cha_rw_1_0; /*
* Byte offset 0x29, CSR Addr 0x54014, Direction=Out
* This is a signed integer value.
* Read to write critical delay difference from cs 1 to cs 0
* on Channel A.
*/
int8_t cdd_cha_rw_0_1; /*
* Byte offset 0x2a, CSR Addr 0x54015, Direction=Out
* This is a signed integer value.
* Read to write critical delay difference from cs 0 to cs 1
* on Channel A.
*/
int8_t cdd_cha_rw_0_0; /*
* Byte offset 0x2b, CSR Addr 0x54015, Direction=Out
* This is a signed integer value.
* Read to write critical delay difference from cs0 to cs 0
* on Channel A.
*/
int8_t cdd_cha_wr_1_1; /*
* Byte offset 0x2c, CSR Addr 0x54016, Direction=Out
* This is a signed integer value.
* Write to read critical delay difference from cs 1 to cs 1
* on Channel A.
*/
int8_t cdd_cha_wr_1_0; /*
* Byte offset 0x2d, CSR Addr 0x54016, Direction=Out
* This is a signed integer value.
* Write to read critical delay difference from cs 1 to cs 0
* on Channel A.
*/
int8_t cdd_cha_wr_0_1; /*
* Byte offset 0x2e, CSR Addr 0x54017, Direction=Out
* This is a signed integer value.
* Write to read critical delay difference from cs 0 to cs 1
* on Channel A.
*/
int8_t cdd_cha_wr_0_0; /*
* Byte offset 0x2f, CSR Addr 0x54017, Direction=Out
* This is a signed integer value.
* Write to read critical delay difference from cs 0 to cs 0
* on Channel A.
*/
int8_t cdd_cha_ww_1_0; /*
* Byte offset 0x30, CSR Addr 0x54018, Direction=Out
* This is a signed integer value.
* Write to write critical delay difference from cs 1 to cs
* 0 on Channel A.
*/
int8_t cdd_cha_ww_0_1; /*
* Byte offset 0x31, CSR Addr 0x54018, Direction=Out
* This is a signed integer value.
* Write to write critical delay difference from cs 0 to cs
* 1 on Channel A.
*/
uint8_t mr1_a0; /*
* Byte offset 0x32, CSR Addr 0x54019, Direction=In
* Value to be programmed in DRAM Mode Register 1
* {Channel A, Rank 0}
*/
uint8_t mr2_a0; /*
* Byte offset 0x33, CSR Addr 0x54019, Direction=In
* Value to be programmed in DRAM Mode Register 2
* {Channel A, Rank 0}
*/
uint8_t mr3_a0; /*
* Byte offset 0x34, CSR Addr 0x5401a, Direction=In
* Value to be programmed in DRAM Mode Register 3
* {Channel A, Rank 0}
*/
uint8_t mr4_a0; /*
* Byte offset 0x35, CSR Addr 0x5401a, Direction=In
* Value to be programmed in DRAM Mode Register 4
* {Channel A, Rank 0}
*/
uint8_t mr11_a0; /*
* Byte offset 0x36, CSR Addr 0x5401b, Direction=In
* Value to be programmed in DRAM Mode Register 11
* {Channel A, Rank 0}
*/
uint8_t mr12_a0; /*
* Byte offset 0x37, CSR Addr 0x5401b, Direction=In
* Value to be programmed in DRAM Mode Register 12
* {Channel A, Rank 0}
*/
uint8_t mr13_a0; /*
* Byte offset 0x38, CSR Addr 0x5401c, Direction=In
* Value to be programmed in DRAM Mode Register 13
* {Channel A, Rank 0}
*/
uint8_t mr14_a0; /*
* Byte offset 0x39, CSR Addr 0x5401c, Direction=In
* Value to be programmed in DRAM Mode Register 14
* {Channel A, Rank 0}
*/
uint8_t mr16_a0; /*
* Byte offset 0x3a, CSR Addr 0x5401d, Direction=In
* Value to be programmed in DRAM Mode Register 16
* {Channel A, Rank 0}
*/
uint8_t mr17_a0; /*
* Byte offset 0x3b, CSR Addr 0x5401d, Direction=In
* Value to be programmed in DRAM Mode Register 17
* {Channel A, Rank 0}
*/
uint8_t mr22_a0; /*
* Byte offset 0x3c, CSR Addr 0x5401e, Direction=In
* Value to be programmed in DRAM Mode Register 22
* {Channel A, Rank 0}
*/
uint8_t mr24_a0; /*
* Byte offset 0x3d, CSR Addr 0x5401e, Direction=In
* Value to be programmed in DRAM Mode Register 24
* {Channel A, Rank 0}
*/
uint8_t mr1_a1; /*
* Byte offset 0x3e, CSR Addr 0x5401f, Direction=In
* Value to be programmed in DRAM Mode Register 1
* {Channel A, Rank 1}
*/
uint8_t mr2_a1; /*
* Byte offset 0x3f, CSR Addr 0x5401f, Direction=In
* Value to be programmed in DRAM Mode Register 2
* {Channel A, Rank 1}
*/
uint8_t mr3_a1; /*
* Byte offset 0x40, CSR Addr 0x54020, Direction=In
* Value to be programmed in DRAM Mode Register 3
* {Channel A, Rank 1}
*/
uint8_t mr4_a1; /*
* Byte offset 0x41, CSR Addr 0x54020, Direction=In
* Value to be programmed in DRAM Mode Register 4
* {Channel A, Rank 1}
*/
uint8_t mr11_a1; /*
* Byte offset 0x42, CSR Addr 0x54021, Direction=In
* Value to be programmed in DRAM Mode Register 11
* {Channel A, Rank 1}
*/
uint8_t mr12_a1; /*
* Byte offset 0x43, CSR Addr 0x54021, Direction=In
* Value to be programmed in DRAM Mode Register 12
* {Channel A, Rank 1}
*/
uint8_t mr13_a1; /*
* Byte offset 0x44, CSR Addr 0x54022, Direction=In
* Value to be programmed in DRAM Mode Register 13
* {Channel A, Rank 1}
*/
uint8_t mr14_a1; /*
* Byte offset 0x45, CSR Addr 0x54022, Direction=In
* Value to be programmed in DRAM Mode Register 14
* {Channel A, Rank 1}
*/
uint8_t mr16_a1; /*
* Byte offset 0x46, CSR Addr 0x54023, Direction=In
* Value to be programmed in DRAM Mode Register 16
* {Channel A, Rank 1}
*/
uint8_t mr17_a1; /*
* Byte offset 0x47, CSR Addr 0x54023, Direction=In
* Value to be programmed in DRAM Mode Register 17
* {Channel A, Rank 1}
*/
uint8_t mr22_a1; /*
* Byte offset 0x48, CSR Addr 0x54024, Direction=In
* Value to be programmed in DRAM Mode Register 22
* {Channel A, Rank 1}
*/
uint8_t mr24_a1; /*
* Byte offset 0x49, CSR Addr 0x54024, Direction=In
* Value to be programmed in DRAM Mode Register 24
* {Channel A, Rank 1}
*/
uint8_t caterminatingrankcha; /* Byte offset 0x4a, CSR Addr 0x54025, Direction=In
* Terminating Rank for CA bus on Channel A
* 0x0 = Rank 0 is terminating rank
* 0x1 = Rank 1 is terminating rank
*/
uint8_t reserved4b; /* Byte offset 0x4b, CSR Addr 0x54025, Direction=N/A */
uint8_t reserved4c; /* Byte offset 0x4c, CSR Addr 0x54026, Direction=N/A */
uint8_t reserved4d; /* Byte offset 0x4d, CSR Addr 0x54026, Direction=N/A */
uint8_t reserved4e; /* Byte offset 0x4e, CSR Addr 0x54027, Direction=N/A */
uint8_t reserved4f; /* Byte offset 0x4f, CSR Addr 0x54027, Direction=N/A */
uint8_t reserved50; /* Byte offset 0x50, CSR Addr 0x54028, Direction=N/A */
uint8_t reserved51; /* Byte offset 0x51, CSR Addr 0x54028, Direction=N/A */
uint8_t reserved52; /* Byte offset 0x52, CSR Addr 0x54029, Direction=N/A */
uint8_t reserved53; /* Byte offset 0x53, CSR Addr 0x54029, Direction=N/A */
uint8_t reserved54; /* Byte offset 0x54, CSR Addr 0x5402a, Direction=N/A */
uint8_t reserved55; /* Byte offset 0x55, CSR Addr 0x5402a, Direction=N/A */
uint8_t reserved56; /* Byte offset 0x56, CSR Addr 0x5402b, Direction=N/A */
uint8_t enableddqschb; /*
* Byte offset 0x57, CSR Addr 0x5402b, Direction=In
* Total number of DQ bits enabled in PHY Channel B
*/
uint8_t cspresentchb; /*
* Byte offset 0x58, CSR Addr 0x5402c, Direction=In
* Indicates presence of DRAM at each chip select for PHY
* channel B.
* 0x0 = No chip selects are populated with DRAM
* 0x1 = CS0 is populated with DRAM
* 0x3 = CS0 and CS1 are populated with DRAM
*
* All other encodings are illegal
*/
int8_t cdd_chb_rr_1_0; /*
* Byte offset 0x59, CSR Addr 0x5402c, Direction=Out
* This is a signed integer value.
* Read to read critical delay difference from cs 1 to cs 0
* on Channel B.
*/
int8_t cdd_chb_rr_0_1; /*
* Byte offset 0x5a, CSR Addr 0x5402d, Direction=Out
* This is a signed integer value.
* Read to read critical delay difference from cs 0 to cs 1
* on Channel B.
*/
int8_t cdd_chb_rw_1_1; /*
* Byte offset 0x5b, CSR Addr 0x5402d, Direction=Out
* This is a signed integer value.
* Read to write critical delay difference from cs 1 to cs 1
* on Channel B.
*/
int8_t cdd_chb_rw_1_0; /*
* Byte offset 0x5c, CSR Addr 0x5402e, Direction=Out
* This is a signed integer value.
* Read to write critical delay difference from cs 1 to cs 0
* on Channel B.
*/
int8_t cdd_chb_rw_0_1; /*
* Byte offset 0x5d, CSR Addr 0x5402e, Direction=Out
* This is a signed integer value.
* Read to write critical delay difference from cs 0 to cs 1
* on Channel B.
*/
int8_t cdd_chb_rw_0_0; /*
* Byte offset 0x5e, CSR Addr 0x5402f, Direction=Out
* This is a signed integer value.
* Read to write critical delay difference from cs01 to cs 0
* on Channel B.
*/
int8_t cdd_chb_wr_1_1; /*
* Byte offset 0x5f, CSR Addr 0x5402f, Direction=Out
* This is a signed integer value.
* Write to read critical delay difference from cs 1 to cs 1
* on Channel B.
*/
int8_t cdd_chb_wr_1_0; /*
* Byte offset 0x60, CSR Addr 0x54030, Direction=Out
* This is a signed integer value.
* Write to read critical delay difference from cs 1 to cs 0
* on Channel B.
*/
int8_t cdd_chb_wr_0_1; /*
* Byte offset 0x61, CSR Addr 0x54030, Direction=Out
* This is a signed integer value.
* Write to read critical delay difference from cs 0 to cs 1
* on Channel B.
*/
int8_t cdd_chb_wr_0_0; /*
* Byte offset 0x62, CSR Addr 0x54031, Direction=Out
* This is a signed integer value.
* Write to read critical delay difference from cs 0 to cs 0
* on Channel B.
*/
int8_t cdd_chb_ww_1_0; /*
* Byte offset 0x63, CSR Addr 0x54031, Direction=Out
* This is a signed integer value.
* Write to write critical delay difference from cs 1 to cs
* 0 on Channel B.
*/
int8_t cdd_chb_ww_0_1; /*
* Byte offset 0x64, CSR Addr 0x54032, Direction=Out
* This is a signed integer value.
* Write to write critical delay difference from cs 0 to cs
* 1 on Channel B.
*/
uint8_t mr1_b0; /*
* Byte offset 0x65, CSR Addr 0x54032, Direction=In
* Value to be programmed in DRAM Mode Register 1
* {Channel B, Rank 0}
*/
uint8_t mr2_b0; /*
* Byte offset 0x66, CSR Addr 0x54033, Direction=In
* Value to be programmed in DRAM Mode Register 2
* {Channel B, Rank 0}
*/
uint8_t mr3_b0; /*
* Byte offset 0x67, CSR Addr 0x54033, Direction=In
* Value to be programmed in DRAM Mode Register 3
* {Channel B, Rank 0}
*/
uint8_t mr4_b0; /*
* Byte offset 0x68, CSR Addr 0x54034, Direction=In
* Value to be programmed in DRAM Mode Register 4
* {Channel B, Rank 0}
*/
uint8_t mr11_b0; /*
* Byte offset 0x69, CSR Addr 0x54034, Direction=In
* Value to be programmed in DRAM Mode Register 11
* {Channel B, Rank 0}
*/
uint8_t mr12_b0; /*
* Byte offset 0x6a, CSR Addr 0x54035, Direction=In
* Value to be programmed in DRAM Mode Register 12
* {Channel B, Rank 0}
*/
uint8_t mr13_b0; /*
* Byte offset 0x6b, CSR Addr 0x54035, Direction=In
* Value to be programmed in DRAM Mode Register 13
* {Channel B, Rank 0}
*/
uint8_t mr14_b0; /*
* Byte offset 0x6c, CSR Addr 0x54036, Direction=In
* Value to be programmed in DRAM Mode Register 14
* {Channel B, Rank 0}
*/
uint8_t mr16_b0; /*
* Byte offset 0x6d, CSR Addr 0x54036, Direction=In
* Value to be programmed in DRAM Mode Register 16
* {Channel B, Rank 0}
*/
uint8_t mr17_b0; /*
* Byte offset 0x6e, CSR Addr 0x54037, Direction=In
* Value to be programmed in DRAM Mode Register 17
* {Channel B, Rank 0}
*/
uint8_t mr22_b0; /*
* Byte offset 0x6f, CSR Addr 0x54037, Direction=In
* Value to be programmed in DRAM Mode Register 22
* {Channel B, Rank 0}
*/
uint8_t mr24_b0; /*
* Byte offset 0x70, CSR Addr 0x54038, Direction=In
* Value to be programmed in DRAM Mode Register 24
* {Channel B, Rank 0}
*/
uint8_t mr1_b1; /*
* Byte offset 0x71, CSR Addr 0x54038, Direction=In
* Value to be programmed in DRAM Mode Register 1
* {Channel B, Rank 1}
*/
uint8_t mr2_b1; /*
* Byte offset 0x72, CSR Addr 0x54039, Direction=In
* Value to be programmed in DRAM Mode Register 2
* {Channel B, Rank 1}
*/
uint8_t mr3_b1; /*
* Byte offset 0x73, CSR Addr 0x54039, Direction=In
* Value to be programmed in DRAM Mode Register 3
* {Channel B, Rank 1}
*/
uint8_t mr4_b1; /*
* Byte offset 0x74, CSR Addr 0x5403a, Direction=In
* Value to be programmed in DRAM Mode Register 4
* {Channel B, Rank 1}
*/
uint8_t mr11_b1; /*
* Byte offset 0x75, CSR Addr 0x5403a, Direction=In
* Value to be programmed in DRAM Mode Register 11
* {Channel B, Rank 1}
*/
uint8_t mr12_b1; /*
* Byte offset 0x76, CSR Addr 0x5403b, Direction=In
* Value to be programmed in DRAM Mode Register 12
* {Channel B, Rank 1}
*/
uint8_t mr13_b1; /*
* Byte offset 0x77, CSR Addr 0x5403b, Direction=In
* Value to be programmed in DRAM Mode Register 13
* {Channel B, Rank 1}
*/
uint8_t mr14_b1; /*
* Byte offset 0x78, CSR Addr 0x5403c, Direction=In
* Value to be programmed in DRAM Mode Register 14
* {Channel B, Rank 1}
*/
uint8_t mr16_b1; /*
* Byte offset 0x79, CSR Addr 0x5403c, Direction=In
* Value to be programmed in DRAM Mode Register 16
* {Channel B, Rank 1}
*/
uint8_t mr17_b1; /*
* Byte offset 0x7a, CSR Addr 0x5403d, Direction=In
* Value to be programmed in DRAM Mode Register 17
* {Channel B, Rank 1}
*/
uint8_t mr22_b1; /*
* Byte offset 0x7b, CSR Addr 0x5403d, Direction=In
* Value to be programmed in DRAM Mode Register 22
* {Channel B, Rank 1}
*/
uint8_t mr24_b1; /*
* Byte offset 0x7c, CSR Addr 0x5403e, Direction=In
* Value to be programmed in DRAM Mode Register 24
* {Channel B, Rank 1}
*/
uint8_t caterminatingrankchb; /* Byte offset 0x7d, CSR Addr 0x5403e, Direction=In
* Terminating Rank for CA bus on Channel B
* 0x0 = Rank 0 is terminating rank
* 0x1 = Rank 1 is terminating rank
*/
uint8_t reserved7e; /* Byte offset 0x7e, CSR Addr 0x5403f, Direction=N/A */
uint8_t reserved7f; /* Byte offset 0x7f, CSR Addr 0x5403f, Direction=N/A */
uint8_t reserved80; /* Byte offset 0x80, CSR Addr 0x54040, Direction=N/A */
uint8_t reserved81; /* Byte offset 0x81, CSR Addr 0x54040, Direction=N/A */
uint8_t reserved82; /* Byte offset 0x82, CSR Addr 0x54041, Direction=N/A */
uint8_t reserved83; /* Byte offset 0x83, CSR Addr 0x54041, Direction=N/A */
uint8_t reserved84; /* Byte offset 0x84, CSR Addr 0x54042, Direction=N/A */
uint8_t reserved85; /* Byte offset 0x85, CSR Addr 0x54042, Direction=N/A */
uint8_t reserved86; /* Byte offset 0x86, CSR Addr 0x54043, Direction=N/A */
uint8_t reserved87; /* Byte offset 0x87, CSR Addr 0x54043, Direction=N/A */
uint8_t reserved88; /* Byte offset 0x88, CSR Addr 0x54044, Direction=N/A */
uint8_t reserved89; /* Byte offset 0x89, CSR Addr 0x54044, Direction=N/A */
} __packed __aligned(2);
#endif /* MNPMUSRAMMSGBLOCK_LPDDR4_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,37 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef DDRPHY_PHYINIT_H
#define DDRPHY_PHYINIT_H
#include <stdbool.h>
#include <ddrphy_phyinit_usercustom.h>
enum message_block_field {
MB_FIELD_PSTATE,
MB_FIELD_PLLBYPASSEN,
MB_FIELD_DRAMFREQ,
MB_FIELD_DFIFREQRATIO,
MB_FIELD_BPZNRESVAL,
MB_FIELD_PHYODTIMPEDANCE,
MB_FIELD_PHYDRVIMPEDANCE,
MB_FIELD_DRAMTYPE,
MB_FIELD_DISABLEDDBYTE,
MB_FIELD_ENABLEDDQS,
MB_FIELD_PHYCFG,
MB_FIELD_X16PRESENT,
MB_FIELD_ENABLEDDQSCHA,
MB_FIELD_CSPRESENTCHA,
MB_FIELD_ENABLEDDQSCHB,
MB_FIELD_CSPRESENTCHB,
};
/* Function definitions */
int ddrphy_phyinit_softsetmb(struct pmu_smb_ddr_1d *mb_ddr_1d, enum message_block_field field,
uint32_t value);
void ddrphy_phyinit_initstruct(struct stm32mp_ddr_config *config, struct pmu_smb_ddr_1d *mb_ddr_1d);
#endif /* DDRPHY_PHYINIT_H */

View file

@ -0,0 +1,786 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef DDRPHY_PHYINIT_STRUCT_H
#define DDRPHY_PHYINIT_STRUCT_H
/* This file defines the internal data structures used in PhyInit to store user configuration */
/* DIMM Type definitions */
#define DDR_DIMMTYPE_NODIMM 4U /* No DIMM (Soldered-on) */
/*
* Structure for basic user inputs
*
* The following basic data structure must be set and completed correctly so
* that the PhyInit software package can accurate program PHY registers.
*/
struct user_input_basic {
uint32_t dramtype; /*
* DRAM module type.
*
* Value | Description
* ----- | ------
* 0x0 | DDR4
* 0x1 | DDR3
* 0x2 | LPDDR4
*/
uint32_t dimmtype; /*
* DIMM type.
*
* Value | Description
* ----- | ------
* 0x4 | No DIMM (Soldered-on) (DDR_DIMMTYPE_NODIMM)
*/
uint32_t lp4xmode; /*
* LPDDR4X mode support.
* Only used for LPDDR4, but not valid here.
*
* Value | Description
* ----- | ------
* 0x0 | LPDDR4 mode, when dramtype is LPDDR4
*/
uint32_t numdbyte; /* Number of dbytes physically instantiated */
uint32_t numactivedbytedfi0; /* Number of active dbytes to be controlled by dfi0 */
uint32_t numactivedbytedfi1; /*
* Number of active dbytes to be controlled by dfi1.
* Only used for LPDDR4.
*/
uint32_t numanib; /* Number of ANIBs physically instantiated */
uint32_t numrank_dfi0; /* Number of ranks in DFI0 channel */
uint32_t numrank_dfi1; /* Number of ranks in DFI1 channel (if DFI1 exists) */
uint32_t dramdatawidth; /*
* Width of the DRAM device.
*
* Enter 4,8,16 or 32 depending on protocol and dram type
* according below table.
*
* Protocol | Valid Options | Default
* -------- | ------------- | ---
* DDR3 | 4,8,16 | 8
* DDR4 | 4,8,16 | 8
* LPDDR4 | 8,16 | 16
*
* For mixed x8 and x16 width devices, set variable to x8.
*/
uint32_t numpstates; /* Number of p-states used. Must be set to 1 */
uint32_t frequency; /*
* Memclk frequency for each PState.
* Memclk frequency in MHz round up to next highest integer.
* Enter 334 for 333.333, etc.
*/
uint32_t pllbypass; /*
* Indicates if PLL should be in Bypass mode.
* If DDR datarate < 333, PLL must be in Bypass Mode.
*
* Value | Description
* ----- | ------
* 0x1 | Enabled
* 0x0 | Disabled
*/
uint32_t dfifreqratio; /*
* Selected Dfi Frequency ratio.
* Used to program the dfifreqratio register. This register
* controls how dfi_freq_ratio input pin should be driven
* inaccordance with DFI Spec.
*
* Binary Value | Description
* ----- | ------
* 2'b01 | 1:2 DFI Frequency Ratio (default)
*/
uint32_t dfi1exists; /* Indicates if the PHY configuration has Dfi1 channel */
uint32_t train2d; /* Obsolete. Not used. */
uint32_t hardmacrover; /*
* Hard Macro Family version in use.
*
* Value | Description
* ----- | ------
* 3 | hardmacro family D
*/
uint32_t readdbienable; /* Obsolete. Not Used. */
uint32_t dfimode; /* Obsolete. Not Used. */
};
/*
* Structure for advanced user inputs
*/
struct user_input_advanced {
uint32_t lp4rxpreamblemode; /*
* Selects between DRAM read static vs toggle preamble.
* Determine desired DRAM Read Preamble Mode based on SI
* Analysis and DRAM Part in use.
* The PHY training firmware will program DRAM mr1-OP[3]
* after training based on setting.
*
* Value | Description
* ----- | ------
* 0x1 | toggling preamble
* 0x0 | static preamble
*/
uint32_t lp4postambleext; /*
* Extend write postamble in LPDDR4.
* Only used for LPDDR4.
* This variable is used to calculate LPDDR4 mr3-OP[1] set
* in the messageBlock.
* The training firmware will set DRAM MR according to MR
* value in the messageBlock at the end of training.
* Set value according to your SI analysis and DRAM
* requirement.
*
* Value | Description
* ----- | ------
* 0x0 | half Memclk postamble
* 0x1 | 1.5 Memclk postabmle (default)
*/
uint32_t d4rxpreamblelength; /*
* Length of read preamble in DDR4 mode.
* Only used for DDR4.
* This variable is used to calculate DDR4 mr4-OP[11] set
* in the messageBlock.
* The training firmware will set DRAM MR according to MR
* value in the messageBlock at the end of training.
* Set value according to your SI analysis and DRAM
* requirement.
*
* Value | Description
* ----- | ------
* 0x0 | 1 Tck
* 0x1 | 2 Tck (default)
*/
uint32_t d4txpreamblelength; /*
* Length of write preamble in DDR4 mode.
* Only used for DDR4.
* This variable is used to calculate DDR4 mr4-OP[12] set
* in the messageBlock.
* The training firmware will set DRAM MR according to MR
* value in the messageBlock at the end of training.
* Set value according to your SI analysis and DRAM
* requirement.
*
* Value | Description
* ----- | ------
* 0x0 | 1 Tck (default)
* 0x1 | 2 Tck
*/
uint32_t extcalresval; /*
* External Impedance calibration pull-down resistor value
* select.
* Indicates value of impedance calibration pull-down
* resistor connected to BP_ZN pin of the PHY.
* Value | Description
* ----- | ------
* 0x0 | 240 ohm (default)
*/
uint32_t is2ttiming; /*
* Set to 1 to use 2T timing for address/command, otherwise
* 1T timing will be used.
* Determine 1T or 2T Timing operation mode based on SI
* Analysis and DRAM Timing.
* - In 1T mode, CK, CS, CA all have the same nominal
* timing, ie. ATxDly[6:0] will have same value for all
* ANIBs.
* - In 2T mode, CK, CS,have the same nominal timing
* (e.g. AtxDly[6:0]=0x00), while CA is delayed by 1UI
* (e.g. ATxDly[6:0]=0x40)
* Used to program phycfg setting in messageBlock.
*
* Value | Description
* ----- | ------
* 0x0 | 1T Timing (default)
* 0x1 | 2T Timing
*/
uint32_t odtimpedance; /*
* ODT impedance in ohm.
* Used for programming TxOdtDrvStren registers.
* Enter 0 for open/high-impedance.
* Default value: 60
*/
uint32_t tximpedance; /*
* Tx Drive Impedance for DQ/DQS in ohm.
* Used for programming TxImpedanceCtrl1 registers.
* Enter 0 for open/high-impedance.
* Default value: 60
*/
uint32_t atximpedance; /*
* Tx Drive Impedance for AC in ohm.
* Used for programming ATxImpedance register.
* Enter 0 for open/high-impedance
* Default value: 20 (HMA,HMB,HMC,HMD), 40 (HME)
*/
uint32_t memalerten; /*
* Enables BP_ALERT programming of PHY registers.
* Only used for DDR3 and DDR4.
* Used for programming MemAlertControl and MemAlertControl2
* registers.
* Program if you require using BP_ALERT pin (to receive or
* terminate signal) of the PHY otherwise leave at default
* value to save power.
*
* Value | Description
* ----- | ------
* 0x0 | Disable BP_ALERT (default)
*/
uint32_t memalertpuimp; /*
* Specify MemAlert Pull-up Termination Impedance.
* Programs the pull-up termination on BP_ALERT.
* Not valid here (fixed 0 value).
*/
uint32_t memalertvreflevel; /*
* Specify the Vref level for BP_ALERT(MemAlert) Receiver.
* Not valid here (fixed 0 value).
*/
uint32_t memalertsyncbypass; /*
* When set, this bit bypasses the DfiClk synchronizer on
* dfi_alert_n.
* Not valid here (fixed 0 value).
*/
uint32_t disdynadrtri; /*
* Disable Dynamic Per-MEMCLK Address Tristate feature.
* Program this variable if you require to disable this
* feature.
* - In DDR3/2T and DDR4/2T/2N modes, the dynamic tristate
* feature should be disabled if the controller cannot
* follow the 2T PHY tristate protocol.
* - In LPDDR4 mode, the dynamic tristate feature should
* be disabled.
*
* Value | Description
* ----- | ------
* 0x1 | Disable Dynamic Tristate
*/
uint32_t phymstrtraininterval; /*
* Specifies the how frequent dfi_phymstr_req is issued by
* PHY.
* Only required in LPDDR4.
* Based on SI analysis determine how frequent DRAM drift
* compensation and re-training is required.
* Determine if Memory controller supports DFI PHY Master
* Interface.
* Program based on desired setting for
* PPTTrainSetup.PhyMstrTrainInterval register.
* Default value: 0xa
*
* Example:
* Value | Description
* ----- | ------
* 0xa | PPT Train Interval = 268435456 MEMCLKs (default)
*/
uint32_t phymstrmaxreqtoack; /*
* Max time from dfi_phymstr_req asserted to dfi_phymstr_ack
* asserted.
* Only required in LPDDR4.
* Based on your Memory controller's(MC) specification
* determine how long the PHY should wait for the assertion
* of dfi_phymstr_ack once dfi_phymstr_req has been issued
* by the PHY. If the MC does not ack the PHY's request, PHY
* may issue dfi_error.
* This value will be used to program
* PPTTrainSetup.PhyMstrMaxReqToAck register.
* Default value: 0x5
*
* Example:
* Value | Description
* ----- | ------
* 0x5 | PPT Max. Req to Ack. = 8192 MEMCLKs (default)
*/
uint32_t wdqsext; /*
* Enable Write DQS Extension feature of PHY.
*
* Value | Description
* ----- | ------
* 0x0 | Disable Write DQS Extension feature. (default)
* 0x1 | Enable Write DQS Extension feature.
*/
uint32_t calinterval; /*
* Specifies the interval between successive calibrations,
* in mS.
* Program variable based on desired setting for
* CalRate.CalInterval register.
* - Fixed 0x9 value (20mS interval)
*/
uint32_t calonce; /*
* This setting changes the behaviour of CalRun register.
* If you desire to manually trigger impedance calibration
* in mission mode set this variable to 1, and toggle CalRun
* in mission mode.
*
* Value | Description
* ----- | ------
* 0x0 | Calibration will proceed at the rate determined
* | by CalInterval. This field should only be changed
* | while the calibrator is idle. ie before csr
* | CalRun is set.
*/
uint32_t lp4rl; /*
* LPDDR4 Dram Read Latency.
* Applicable only if dramtype == LPDDR4.
* This variable is used to calculate LPDDR4 mr2-OP[2:0]
* set in the messageBlock.
* The training firmware will set DRAM MR according to MR
* value in the messageBlock at the end of training.
* Please refer to JEDEC JESD209-4A (LPDDR4) Spec for
* definition of MR.
* Determine values based on your DRAM part's supported
* speed and latency bin.
* Default: calculated based on user_input_basic.frequency
* and "JEDEC JESD209-4A (LPDDR4)" Table 28 "Read and Write
* Latencies".
* Lowest latency selected when more than one latency can be
* used. For example given configuration for LPDDR4, x16,
* NoDbi and DDR533, RL=10 is selected rather than 14.
*/
uint32_t lp4wl; /*
* LPDDR4 Dram Write Latency.
* Applicable only if dramtype == LPDDR4.
* This variable is used to calculate LPDDR4 mr2-OP[5:3]
* set in the messageBlock.
* The training firmware will set DRAM MR according to MR
* value in the messageBlock at the end of training.
* Please refer to JEDEC JESD209-4A (LPDDR4) Spec for
* definition of MR.
* Determine values based on your DRAM part's supported
* speed and latency bin.
* Default: calculated based on user_input_basic.frequency
* and "JEDEC JESD209-4A (LPDDR4)" Table 28 "Read and Write
* Latencies".
* Lowest latency selected when more than one latency can be
* used.
*/
uint32_t lp4wls; /*
* LPDDR4 Dram WL Set.
* Applicable only if dramtype == LPDDR4.
* This variable is used to calculate LPDDR4 mr2-OP[6] set
* in the messageBlock.
* The training firmware will set DRAM MR according to MR
* value in the messageBlock at the end of training.
* Please refer to JEDEC JESD209-4A (LPDDR4) Spec for
* definition of MR.
* Determine value based on Memory controllers requirement
* of DRAM State after PHY training.
*
* Value | Description
* --- | ---
* 0x0 | WL Set "A" (default)
*/
uint32_t lp4dbird; /*
* LPDDR4 Dram DBI-Read Enable.
* Applicable only if dramtype == LPDDR4.
* Determine if you require to using DBI for the given
* PState.
* If Read DBI is not used PHY receivers are turned off to
* save power.
* This variable is used to calculate LPDDR4 mr3-OP[6] set
* in the messageBlock.
* The training firmware will set DRAM MR according to MR
* value in the messageBlock at the end of training.
* PHY register DMIPinPresent is programmed based on this
* parameter.
* Please refer to JEDEC JESD209-4A (LPDDR4) Spec for
* definition of MR.
*
* Value | Description
* --- | ---
* 0x0 | Disabled (default)
* 0x1 | Enabled
*/
uint32_t lp4dbiwr; /*
* LPDDR4 Dram DBI-Write Enable.
* Applicable only if dramtype == LPDDR4.
* This variable is used to calculate LPDDR4 mr3-OP[7] set
* in the messageBlock.
* The training firmware will set DRAM MR according to MR
* value in the messageBlock at the end of training.
* Please refer to JEDEC JESD209-4A (LPDDR4) Spec for
* definition of MR.
*
* Value | Description
* --- | ---
* 0x0 | Disabled (default)
* 0x1 | Enabled
*/
uint32_t lp4nwr; /*
* LPDDR4 Write-Recovery for Auto- Pre-charge commands.
* Applicable only if dramtype == LPDDR4.
* This variable is used to calculate LPDDR4 mr1-OP[6:4] set
* in the messageBlock.
* The training firmware will set DRAM MR according to MR
* value in the messageBlock at the end of training.
* Please refer to JEDEC JESD209-4A (LPDDR4) Spec for
* definition of MR.
* Determine values based on your DRAM part's supported
* speed and latency bin.
* Default: calculated based on user_input_basic.frequency
* and "JEDEC JESD209-4A (LPDDR4)" Table 28 "Read and Write
* Latencies".
* Lowest latency selected when more than one latency can be
* used.
*
* Binary Value | Description
* --- | ---
* 000 | nWR = 6 (default)
* 001 | nWR = 10
* 010 | nWR = 16
* 011 | nWR = 20
* 100 | nWR = 24
* 101 | nWR = 30
* 110 | nWR = 34
* 111 | nWR = 40
*/
uint32_t lp4lowpowerdrv; /*
* Configure output Driver in Low power mode.
* Feature only supported for Hard Macro Family E (HME).
* Use NMOS Pull-up for Low-Power IO.
* Not valid here
*/
uint32_t drambyteswap; /*
* DRAM Oscillator count source mapping for skip_training.
* The PHY supports swapping of DRAM oscillator count values
* between paired DBytes for the purpose of tDQSDQ DRAM
* Drift Compensation(DDC).
* Each DByte has a register bit to control the source of
* the oscillator count value used to perform tDQSDQ Drift
* compensation.
* On silicon the training firmware will determine the DByte
* swap and program PptCtlStatic register to select
* oscillator count source. When skip_train is used,
* training firmware is skipped thus manual programming may
* be required depending on configuration.
* The default hardware configuration is for odd Dbyte
* instance n to use oscillator count values from its paired
* Dbyte instance n-1. So Dbyte1 will use the oscillator
* count values from Dbyte0, Dbyte3 will use Dbyte2 and so
* on. This is required for DRAM Data width =16.
* Each bit of this field corresponds to a DBYTE:
* - bit-0 = setting for DBYTE0
* - bit-1 = setting for DBYTE1
* - bit-2 = setting for DBYTE2
* - . . .
* - bit-n = setting for DBYTEn
* By setting the associated bit for each DByte to 1, PHY
* will use non-default source for count value.
* - for even Dbytes, non-default source is to use the odd
* pair count value.
* - for odd Dbytes, no-default source to use data
* received directly from the DRAM.
* Byte swapping must be the same across different ranks.
* Default value: 0x0
* If Byte mode devices are indicated via the x8mode
* messageBlock parameter, this variable is ignored as PHY
* only supports a limited configuration set based on Byte
* mode configuration.
*
* Example:
* DramByteSwap = 0x03 - Dbyte0: use count values from
* Dbyte1, Dbyte1 uses count values received directly
* received from DRAM.
* Rest of Dbytes have default source for DRAM oscilator
* count.
*/
uint32_t rxenbackoff; /*
* Determines the Placement of PHY Read Gate signal.
* Only used in LPDDR4 when lp4rxpreamblemode==0 (static
* preamble) for skip_train==true.
* For other dramtypes or LPDDR4-toggling-preamble no
* options are available and PhyInit will set position as
* required. See source code in
* ddrphy_phyinit_c_initphyconfig() to see how the
* RxEnBackOff register is set.
* For skip_train==false, FW will set the position based on
* Preamble.
* We recommend keeping this setting at default value.
* SI analysis is required to determine if default value
* needs to be changed.
*
* Value | Description
* ----- | ---
* 0x1 | Position read gate 1UI from the first valid edge
* | of DQS_t (LPDDR4 Static preamble only) (default)
*/
uint32_t trainsequencectrl; /*
* Firmware Training Sequence Control.
* This input is used to program sequencectrl in
* messageBlock.
* It controls the training stages executed by firmware.
* For production silicon we recommend to use default value
* programmed by PhyInit.
*/
uint32_t snpsumctlopt; /*
* Enable Fast Frequency Change (FFC) Optimizations
* specific to UMCTL2 (DDRCTRL).
* Not valid for dimmtype=NODIMM.
* Consult DDRCTRL documentation in Reference Manual to
* ensure when optimizations can be enabled.
*
* Value | Description
* ----- | ---
* 0 | Disable FFC MRW optimization (default)
*/
uint32_t snpsumctlf0rc5x; /*
* F0RX5x RCD Control Word when using Fast Frequency
* Change(FFC) optimizations specific to UMCTL2
* Not valid for dimmtype=NODIMM.
* Only valid for when SnpsUmctlOpt=1.
* When UMCTL2 optimizations are enabled PHY will perform
* RCD MRW during fast frequency change request.
* The correct RCD control word value for each PState must
* be programmed in this field.
* Consult the RCD spec and UMCTL documentation to
* determine the correct value based on DRAM configuration
* and operating speed.
*/
uint32_t txslewrisedq; /*
* Pull-up slew rate control for DBYTE Tx.
* Value specified here will be written to register
* TxSlewRate.TxPreP by PhyInit.
* See register description for more information.
*/
uint32_t txslewfalldq; /*
* Pull-down slew rate control for DBYTE Tx.
* Value specified here will be written to
* TxSlewRate.TxPreN by PhyInit.
* See register description for more information.
*/
uint32_t txslewriseac; /*
* Pull-up slew rate control for ANIB Tx.
* Value specified here will be written to
* ATxSlewRate.ATxPreP.
* See register description for more information.
*/
uint32_t txslewfallac; /*
* Pull-down slew rate control for ANIB Tx.
* Value specified here will be written to
* ATxSlewRate.ATxPreN.
* See register description for more information.
*/
uint32_t disableretraining; /*
* Disable PHY DRAM Drift compensation re-training.
* Only applied to LPDDR4. No retraining is required in
* DDR4/3.
* Disable PHY re-training during DFI frequency change
* requests in LPDDR4.
* The purpose of retraining is to compensate for drift in
* the DRAM.
* Determine based on SI analysis and DRAM datasheet if
* retraining can be disabled.
*
* Value | Description
* ----- | ---
* 0x1 | Disable retraining
* 0x0 | Enable retraining
*/
uint32_t disablephyupdate; /*
* Disable DFI PHY Update feature.
* Only effects LPDDR4.
* Disable DFI PHY Update feature. When set PHY will not
* assert dfi0/1_phyupd_req.
*
* Value | Description
* ----- | ---
* 0x1 | Disable DFI PHY Update
* 0x0 | Enable DFI PHY Update
*/
uint32_t enablehighclkskewfix; /*
* Enable alternative PIE program.
* If enabled the PIE reinitializes the FIFO pointers a
* second time due for designs with large skew between
* chiplet DfiClk branches. If enabled PIE latencies in all
* protocols are increased by 60 DfiClks.
*
* Value | Description
* ----- | ---
* 0x0 | Disable (default)
*/
uint32_t disableunusedaddrlns; /*
* Turn off or tristate Address Lanes when possible.
*
* When enabled, PHY will tristate unused address lanes to
* save power when possible by using Acx4AnibDis and
* AForceTriCont registers.
* This feature is only implemented for the default PHY
* Address bump mapping and Ranks must be populated in
* order. ie Rank1 cannot be used if Rank0 is unpopulated.
* For alternative bump mapping follow the following
* guideline to achieve maximum power savings:
* - For each unused BP_A bump program AForceTriCont[4:0]
* bits based on register description.
* - if all lanes of an Anib are unused _AND_ ANIB is not
* the first or last instance set bit associated with
* the instance in Acs4AnibDis registers. see register
* description for details.
*
* Value | Description
* ----- | ---
* 0x1 | Enable
*/
uint32_t phyinitsequencenum; /*
* Switches between supported phyinit training sequences.
*
* Value | Description
* ----- | ---
* 0x0 | Minimizes number of Imem/Dmem loads (default)
*/
uint32_t enabledficspolarityfix;/*
* Enable alternative PIE program.
* Set to 1 if PUB_VERSION <2.43a, otherwise set to 0. If
* enabled the PIE programs Dfi{Rd,Wr}DataCsDestMap CSR's
* to default values 0x00E4 before running PPT.
* Before exiting PPT, PIE will restore
* Dfi{Rd,Wr}DataCsDestMap CSR's to 0x00E1.
*
* Value | Description
* ----- | ---
* 0x0 | Disable (default)
*/
uint32_t phyvref; /*
* Must be programmed with the Vref level to be used by the
* PHY during reads.
* The units of this field are a percentage of VDDQ
* according to the following equation:
* Receiver Vref = VDDQ*phyvref[6:0]/128
* For example to set Vref at 0.75*VDDQ, set this field to
* 0x60.
* For digital simulation, any legal value can be used. For
* silicon, the users must calculate the analytical Vref by
* using the impedances, terminations, and series resistance
* present in the system.
*/
uint32_t sequencectrl; /*
* Controls the training steps to be run. Each bit
* corresponds to a training step.
* If the bit is set to 1, the training step will run.
* If the bit is set to 0, the training step will be
* skipped.
* Training step to bit mapping:
* sequencectrl[0] = Run DevInit - Device/phy
* initialization. Should always be set.
* sequencectrl[1] = Run WrLvl - Write leveling
* sequencectrl[2] = Run RxEn - Read gate training
* sequencectrl[3] = Run RdDQS1D - 1d read dqs training
* sequencectrl[4] = Run WrDQ1D - 1d write dq training
* sequencectrl[5] = RFU, must be zero
* sequencectrl[6] = RFU, must be zero
* sequencectrl[7] = RFU, must be zero
* sequencectrl[8] = Run RdDeskew - Per lane read dq deskew
* training
* sequencectrl[9] = Run MxRdLat - Max read latency training
* sequencectrl[10] = RFU, must be zero
* sequencectrl[11] = RFU, must be zero
* sequencectrl[12] = RFU, must be zero
* sequencectrl[13] = RFU, must be zero
* sequencectrl[15-14] = RFU, must be zero
*/
};
/*
* Structure for mode register user inputs
*
* The following data structure must be set and completed correctly so that the PhyInit software
* package can accurate fill message block structure.
* Only some mrx are used per DDR type, on related width:
* - DDR3: mr0..2 are used (16-bits values)
* - DDR4: mr0..6 are used (16-bits values)
* - LPDDR4: mr1..4 and mr11..22 are used (8-bits values)
*/
struct user_input_mode_register {
uint32_t mr0;
uint32_t mr1;
uint32_t mr2;
uint32_t mr3;
uint32_t mr4;
uint32_t mr5;
uint32_t mr6;
uint32_t mr11;
uint32_t mr12;
uint32_t mr13;
uint32_t mr14;
uint32_t mr22;
};
/*
* Structure for swizzle user inputs
*
* The following data structure must be set and completed correctly sothat the PhyInit software
* package can accurate set swizzle (IO muxing) config.
* Only some swizzles are used per DDR type:
* - DDR3/DDR4: swizzle 0..32 are used
* - 26 for hwtswizzle
* - 7 for acswizzle
* - LPDDR4: swizzle 0..43 are used
* - 8 per byte for dqlnsel (total 32)
* - 6 for mapcaatodfi
* - 6 for mapcabtodfi
*/
#define NB_HWT_SWIZZLE 26U
#define NB_AC_SWIZZLE 7U
#define NB_DQLNSEL_SWIZZLE_PER_BYTE 8U
#define NB_MAPCAATODFI_SWIZZLE 6U
#define NB_MAPCABTODFI_SWIZZLE 6U
#define NB_SWIZZLE 44
struct user_input_swizzle {
uint32_t swizzle[NB_SWIZZLE];
};
#endif /* DDRPHY_PHYINIT_STRUCT_H */

View file

@ -0,0 +1,118 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef DDRPHY_PHYINIT_USERCUSTOM_H
#define DDRPHY_PHYINIT_USERCUSTOM_H
#include <stdbool.h>
#include <stdint.h>
#include <ddrphy_csr_all_cdefines.h>
#include <drivers/st/stm32mp2_ddr.h>
/* Message Block Structure Definitions */
#if STM32MP_DDR3_TYPE
#include <mnpmusrammsgblock_ddr3.h>
#elif STM32MP_DDR4_TYPE
#include <mnpmusrammsgblock_ddr4.h>
#else /* STM32MP_LPDDR4_TYPE */
#include <mnpmusrammsgblock_lpddr4.h>
#endif /* STM32MP_DDR3_TYPE */
/*
* -------------------------------------------------------------
* Defines for Firmware Images
* - indicate IMEM/DMEM address, size (bytes) and offsets.
* -------------------------------------------------------------
*
* IMEM_SIZE max size of instruction memory.
* DMEM_SIZE max size of data memory.
*
* IMEM_ST_ADDR start of IMEM address in memory.
* DMEM_ST_ADDR start of DMEM address in memory.
* DMEM_BIN_OFFSET start offset in DMEM memory (message block).
*/
#if STM32MP_DDR3_TYPE
#define IMEM_SIZE 0x4C28U
#define DMEM_SIZE 0x6C8U
#elif STM32MP_DDR4_TYPE
#define IMEM_SIZE 0x6D24U
#define DMEM_SIZE 0x6CCU
#else /* STM32MP_LPDDR4_TYPE */
#define IMEM_SIZE 0x7E50U
#define DMEM_SIZE 0x67CU
#endif /* STM32MP_DDR3_TYPE */
#define IMEM_ST_ADDR 0x50000U
#define DMEM_ST_ADDR 0x54000U
#define DMEM_BIN_OFFSET 0x200U
/*
* ------------------
* Type definitions
* ------------------
*/
/* A structure used to SRAM memory address space */
enum return_offset_lastaddr {
RETURN_OFFSET,
RETURN_LASTADDR
};
/* Enumeration of instructions for PhyInit Register Interface */
enum reginstr {
STARTTRACK, /* Start register tracking */
STOPTRACK, /* Stop register tracking */
SAVEREGS, /* Save(read) tracked register values */
RESTOREREGS, /* Restore (write) saved register values */
};
/* Data structure to store register address/value pairs */
struct reg_addr_val {
uint32_t address; /* Register address */
uint16_t value; /* Register value */
};
/* Target CSR for the impedance value for ddrphy_phyinit_mapdrvstren() */
enum drvtype {
DRVSTRENFSDQP,
DRVSTRENFSDQN,
ODTSTRENP,
ODTSTRENN,
ADRVSTRENP,
ADRVSTRENN
};
/*
* -------------------------------------------------------------
* Fixed Function prototypes
* -------------------------------------------------------------
*/
int ddrphy_phyinit_sequence(struct stm32mp_ddr_config *config, bool skip_training, bool reten);
int ddrphy_phyinit_restore_sequence(void);
int ddrphy_phyinit_c_initphyconfig(struct stm32mp_ddr_config *config,
struct pmu_smb_ddr_1d *mb_ddr_1d, uint32_t *ardptrinitval);
void ddrphy_phyinit_d_loadimem(void);
void ddrphy_phyinit_progcsrskiptrain(struct stm32mp_ddr_config *config,
struct pmu_smb_ddr_1d *mb_ddr_1d, uint32_t ardptrinitval);
int ddrphy_phyinit_f_loaddmem(struct stm32mp_ddr_config *config, struct pmu_smb_ddr_1d *mb_ddr_1d);
int ddrphy_phyinit_g_execfw(void);
void ddrphy_phyinit_i_loadpieimage(struct stm32mp_ddr_config *config, bool skip_training);
void ddrphy_phyinit_loadpieprodcode(void);
int ddrphy_phyinit_mapdrvstren(uint32_t drvstren_ohm, enum drvtype targetcsr);
int ddrphy_phyinit_calcmb(struct stm32mp_ddr_config *config, struct pmu_smb_ddr_1d *mb_ddr_1d);
void ddrphy_phyinit_writeoutmem(uint32_t *mem, uint32_t mem_offset, uint32_t mem_size);
void ddrphy_phyinit_writeoutmsgblk(uint16_t *mem, uint32_t mem_offset, uint32_t mem_size);
int ddrphy_phyinit_isdbytedisabled(struct stm32mp_ddr_config *config,
struct pmu_smb_ddr_1d *mb_ddr_1d, uint32_t dbytenumber);
int ddrphy_phyinit_trackreg(uint32_t adr);
int ddrphy_phyinit_reginterface(enum reginstr myreginstr, uint32_t adr, uint16_t dat);
void ddrphy_phyinit_usercustom_custompretrain(struct stm32mp_ddr_config *config);
int ddrphy_phyinit_usercustom_g_waitfwdone(void);
int ddrphy_phyinit_usercustom_saveretregs(struct stm32mp_ddr_config *config);
#endif /* DDRPHY_PHYINIT_USERCUSTOM_H */

View file

@ -0,0 +1,20 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef DDRPHY_WRAPPER_H
#define DDRPHY_WRAPPER_H
static inline long long fmodll(long long x, long long y)
{
return x - ((x / y) * y);
}
static inline int fmodi(int x, int y)
{
return (int)fmodll((long long)x, (long long)y);
}
#endif /* DDRPHY_WRAPPER_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,210 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdlib.h>
#include <common/debug.h>
#include <ddrphy_phyinit.h>
/*
* Reads PhyInit inputs structures and sets relevant message block
* parameters.
*
* This function sets Message Block parameters based on user_input_basic and
* user_input_advanced. user changes in these files takes precedence
* over this function call.
*
* MessageBlock fields set :
* - dramtype
* - pstate
* - dramfreq
* - pllbypassen
* - dfifreqratio
* - phyodtimpedance
* - phydrvimpedance
* - bpznresval
* - enableddqscha (LPDDR4)
* - cspresentcha (LPDDR4)
* - enableddqsChb (LPDDR4)
* - cspresentchb (LPDDR4)
* - enableddqs (DDR3/DDR4)
* - phycfg (DDR3/DDR4)
* - x16present (DDR4)
*
* \return 0 on success.
*/
int ddrphy_phyinit_calcmb(struct stm32mp_ddr_config *config, struct pmu_smb_ddr_1d *mb_ddr_1d)
{
uint32_t nad0 = config->uib.numactivedbytedfi0;
uint32_t nad1 = 0;
uint16_t mr4 __maybe_unused;
uint16_t disableddbyte __maybe_unused;
uint32_t dbyte __maybe_unused;
int ret;
#if STM32MP_LPDDR4_TYPE
nad1 = config->uib.numactivedbytedfi1;
#endif /* STM32MP_LPDDR4_TYPE */
/* A few checks to make sure valid programming */
if ((nad0 == 0U) || (config->uib.numdbyte == 0U)) {
ERROR("%s %d\n", __func__, __LINE__);
VERBOSE("%s numactivedbytedfi0, numactivedbytedfi0, NumByte out of range.\n",
__func__);
return -1;
}
if ((nad0 + nad1) > config->uib.numdbyte) {
ERROR("%s %d\n", __func__, __LINE__);
VERBOSE("%s numactivedbytedfi0+numactivedbytedfi1 is larger than numdbyteDfi0\n",
__func__);
return -1;
}
if ((config->uib.dfi1exists == 0U) && (nad1 != 0U)) {
ERROR("%s %d\n", __func__, __LINE__);
VERBOSE("%s dfi1exists==0 but numdbyteDfi0 != 0\n", __func__);
return -1;
}
#if STM32MP_DDR4_TYPE
/* OR all mr4 masked values, to help check in next loop */
mr4 = mb_ddr_1d->mr4 & 0x1C0U;
/* 1D message block defaults */
if (mr4 != 0x0U) {
ERROR("mr4 != 0x0\n");
VERBOSE("%s Setting DRAM CAL mode is not supported by the PHY.\n", __func__);
VERBOSE("Memory controller may set CAL mode after PHY has entered mission\n");
VERBOSE("mode. Please check value programmed in mb_ddr_1d[*].mr4\n");
VERBOSE("and unset A8:6\n");
return -1;
}
#endif /* STM32MP_DDR4_TYPE */
#if STM32MP_DDR3_TYPE
if (config->uib.dimmtype == DDR_DIMMTYPE_NODIMM) {
ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_DRAMTYPE, 0x1U);
if (ret != 0) {
return ret;
}
}
#elif STM32MP_DDR4_TYPE
if (config->uib.dimmtype == DDR_DIMMTYPE_NODIMM) {
ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_DRAMTYPE, 0x2U);
if (ret != 0) {
return ret;
}
}
#else /* STM32MP_LPDDR4_TYPE */
/* Nothing to do */
#endif /* STM32MP_DDR3_TYPE */
ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_PSTATE, 0U);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_DRAMFREQ, config->uib.frequency * 2U);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_PLLBYPASSEN, config->uib.pllbypass);
if (ret != 0) {
return ret;
}
if (config->uib.dfifreqratio == 1U) {
ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_DFIFREQRATIO, 0x2U);
if (ret != 0) {
return ret;
}
}
ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_PHYODTIMPEDANCE, 0U);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_PHYDRVIMPEDANCE, 0U);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_BPZNRESVAL, 0U);
if (ret != 0) {
return ret;
}
#if STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE
ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_ENABLEDDQS, nad0 * 8U);
if (ret != 0) {
return ret;
}
disableddbyte = 0x0U;
for (dbyte = 0U; (dbyte < config->uib.numdbyte) && (dbyte < 8U); dbyte++) {
if (ddrphy_phyinit_isdbytedisabled(config, mb_ddr_1d, dbyte) != 0) {
disableddbyte |= 0x1U << dbyte;
}
}
ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_DISABLEDDBYTE, disableddbyte);
if (ret != 0) {
return ret;
}
#if STM32MP_DDR3_TYPE
ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_PHYCFG, config->uia.is2ttiming);
if (ret != 0) {
return ret;
}
#else /* STM32MP_DDR4_TYPE */
ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_PHYCFG,
((mb_ddr_1d->mr3 & 0x8U) != 0U) ?
0U : config->uia.is2ttiming);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_X16PRESENT,
(config->uib.dramdatawidth == 0x10U) ?
mb_ddr_1d->cspresent : 0x0U);
if (ret != 0) {
return ret;
}
#endif /* STM32MP_DDR3_TYPE */
#else /* STM32MP_LPDDR4_TYPE */
ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_ENABLEDDQSCHA, nad0 * 8U);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_CSPRESENTCHA,
(config->uib.numrank_dfi0 == 2U) ?
0x3U : config->uib.numrank_dfi0);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_ENABLEDDQSCHB, nad1 * 8U);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_CSPRESENTCHB,
(config->uib.numrank_dfi1 == 2U) ?
0x3U : config->uib.numrank_dfi1);
if (ret != 0) {
return ret;
}
#endif /* STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE */
return 0;
}

View file

@ -0,0 +1,43 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <stdlib.h>
#include <common/debug.h>
#include <ddrphy_phyinit.h>
#include <lib/mmio.h>
#include <platform_def.h>
/*
* This function loads the training firmware IMEM image into the PHY.
*
* This function reads the DDR firmware source memory area to generate a
* set of apb writes to load IMEM image into the PHY. The exact steps in this
* function are as follows:
*
* -# Ensure DRAM is in reset.
* -# Load the microcontroller memory with the provided training firmware
* -# Initialize the firmware mailbox structures to be able to communicate with
* the firmware.
*
* \return void
*/
void ddrphy_phyinit_d_loadimem(void)
{
uint16_t memresetl;
uint32_t *ptr32;
/* Set memresetl to avoid glitch on BP_MemReset_L during training */
memresetl = CSR_PROTECTMEMRESET_MASK;
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_MEMRESETL_ADDR))), memresetl);
ptr32 = (uint32_t *)(STM32MP_DDR_FW_BASE + STM32MP_DDR_FW_IMEM_OFFSET);
ddrphy_phyinit_writeoutmem(ptr32, IMEM_ST_ADDR, IMEM_SIZE);
}

View file

@ -0,0 +1,70 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <stdlib.h>
#include <common/debug.h>
#include <ddrphy_phyinit.h>
#include <platform_def.h>
/*
* This function loads the training firmware DMEM image and write the
* Message Block parameters for the training firmware into the PHY.
*
* This function performs the following tasks:
*
* -# Load the firmware DMEM segment to initialize the data structures from the
* DDR firmware source memory area.
* -# Write the Firmware Message Block with the required contents detailing the training parameters.
*
* \return 0 on success.
*/
int ddrphy_phyinit_f_loaddmem(struct stm32mp_ddr_config *config, struct pmu_smb_ddr_1d *mb_ddr_1d)
{
uint32_t sizeofmsgblk;
uint16_t *ptr16;
uint32_t *ptr32;
/* Some basic checks on MessageBlock */
#if STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE
if ((mb_ddr_1d->enableddqs > (8U * (uint8_t)config->uib.numactivedbytedfi0)) ||
(mb_ddr_1d->enableddqs <= 0U)) {
ERROR("%s %d\n", __func__, __LINE__);
VERBOSE("%s enableddqs is Zero or greater than NumActiveDbytes for Dfi0\n",
__func__);
return -1;
}
#else /* STM32MP_LPDDR4_TYPE */
if (((mb_ddr_1d->enableddqscha % 16U) != 0U) || ((mb_ddr_1d->enableddqschb % 16U) != 0U)) {
ERROR("%s %d\n", __func__, __LINE__);
VERBOSE("%s Lp3/Lp4 - Number of Dq's Enabled per Channel much be multipe of 16\n",
__func__);
return -1;
}
if ((mb_ddr_1d->enableddqscha > (uint8_t)(8U * config->uib.numactivedbytedfi0)) ||
(mb_ddr_1d->enableddqschb > (uint8_t)(8U * config->uib.numactivedbytedfi1)) ||
((mb_ddr_1d->enableddqscha == 0U) && (mb_ddr_1d->enableddqschb == 0U))) {
ERROR("%s %d\n", __func__, __LINE__);
VERBOSE("%s EnabledDqsChA/B are not set correctly./1\n", __func__);
return -1;
}
#endif /* STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE */
sizeofmsgblk = sizeof(struct pmu_smb_ddr_1d);
ptr16 = (uint16_t *)mb_ddr_1d;
ddrphy_phyinit_writeoutmsgblk(ptr16, DMEM_ST_ADDR, sizeofmsgblk);
ptr32 = (uint32_t *)(STM32MP_DDR_FW_BASE + STM32MP_DDR_FW_DMEM_OFFSET);
ddrphy_phyinit_writeoutmem(ptr32, DMEM_ST_ADDR + DMEM_BIN_OFFSET,
DMEM_SIZE - STM32MP_DDR_FW_DMEM_OFFSET);
return 0;
}

View file

@ -0,0 +1,66 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
#include <ddrphy_phyinit.h>
#include <lib/mmio.h>
#include <platform_def.h>
/*
* Execute the Training Firmware
*
* The training firmware is executed with the procedure:
*
* -# Reset the firmware microcontroller by writing the MicroReset register to
* set the StallToMicro and ResetToMicro fields to 1 (all other fields should be
* zero). Then rewrite the registers so that only the StallToMicro remains set
* (all other fields should be zero).
* -# Begin execution of the training firmware by setting the MicroReset
* register to 0.
* -# Wait for the training firmware to complete by following the procedure implemented in
* ddrphy_phyinit_usercustom_g_waitfwdone() function.
* -# Halt the microcontroller.
*
* \return 0 on success.
*/
int ddrphy_phyinit_g_execfw(void)
{
int ret;
/*
* 1. Reset the firmware microcontroller by writing the MicroReset CSR to set the
* StallToMicro and ResetToMicro fields to 1 (all other fields should be zero).
* Then rewrite the CSR so that only the StallToMicro remains set (all other fields should
* be zero).
*/
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TAPBONLY | CSR_MICROCONTMUXSEL_ADDR))),
CSR_STALLTOMICRO_MASK);
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TAPBONLY | CSR_MICRORESET_ADDR))),
CSR_RESETTOMICRO_MASK | CSR_STALLTOMICRO_MASK);
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TAPBONLY | CSR_MICRORESET_ADDR))),
CSR_STALLTOMICRO_MASK);
/* 2. Begin execution of the training firmware by setting the MicroReset CSR to 0 */
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TAPBONLY | CSR_MICRORESET_ADDR))), 0x0U);
/*
* 3. Wait for the training firmware to complete by following the procedure
* implemented in ddrphy_phyinit_usercustom_g_waitfwdone() function.
*/
ret = ddrphy_phyinit_usercustom_g_waitfwdone();
if (ret != 0) {
return ret;
}
/* 4. Halt the microcontroller */
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TAPBONLY | CSR_MICRORESET_ADDR))),
CSR_STALLTOMICRO_MASK);
return 0;
}

View file

@ -0,0 +1,394 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <common/debug.h>
#include <ddrphy_phyinit.h>
#include <lib/mmio.h>
#include <platform_def.h>
#if STM32MP_LPDDR4_TYPE
/*
* Program DfiWrRdDataCsConfig
* - Fields:
* - dfiwrdatacspolarity
* - dfirddatacspolarity
*/
static void dfiwrrddatacsconfig_program(void)
{
uint16_t dfiwrdatacspolarity;
uint16_t dfirddatacspolarity;
/*
* DfiWrRdDataCsConfig : dfiwrdatacspolarity=0x1 and dfirddatacspolarity=0x1.
* Set DataCsPolarity bits to enable active high
*/
dfiwrdatacspolarity = 0x1U;
dfirddatacspolarity = 0x1U;
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | C0 |
CSR_DFIWRRDDATACSCONFIG_ADDR))),
(dfiwrdatacspolarity << CSR_DFIWRDATACSPOLARITY_LSB) |
(dfirddatacspolarity << CSR_DFIRDDATACSPOLARITY_LSB));
}
#endif /* STM32MP_LPDDR4_TYPE */
/*
* Registers: Seq0BDLY0, Seq0BDLY1, Seq0BDLY2, Seq0BDLY3
* - Program PIE instruction delays
* - Dependencies:
* - user_input_basic.frequency
*/
static void seq0bdly_program(struct stm32mp_ddr_config *config)
{
uint16_t lowfreqopt __unused;
uint16_t dfifrq_x10;
uint16_t pscount_ref;
uint16_t pscount[4]; /* Need delays for 0.5us, 1us, 10us, and 25us */
/*
* Calculate the counts to obtain the correct delay for each frequency
* Need to divide by 4 since the delay value are specified in units of
* 4 clocks.
*/
dfifrq_x10 = (10U * (uint16_t)config->uib.frequency) / 2U;
pscount_ref = dfifrq_x10 / 4U;
pscount[0] = pscount_ref / (2U * 10U);
#if STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE
if (config->uib.frequency < 400U) {
lowfreqopt = 3U;
} else if (config->uib.frequency < 533U) {
lowfreqopt = 11U;
} else {
lowfreqopt = 0U;
}
pscount[1] = (pscount_ref / 10U) - lowfreqopt;
#else /* STM32MP_LPDDR4_TYPE */
pscount[1] = pscount_ref / 10U;
#endif /* STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE */
pscount[2] = pscount_ref;
if (dfifrq_x10 > 2665U) {
pscount[3] = 44U;
} else if ((dfifrq_x10 <= 2665U) && (dfifrq_x10 > 2000U)) {
pscount[3] = 33U;
} else {
pscount[3] = 16U;
}
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (C0 | TMASTER | CSR_SEQ0BDLY0_ADDR))),
pscount[0]);
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (C0 | TMASTER | CSR_SEQ0BDLY1_ADDR))),
pscount[1]);
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (C0 | TMASTER | CSR_SEQ0BDLY2_ADDR))),
pscount[2]);
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (C0 | TMASTER | CSR_SEQ0BDLY3_ADDR))),
pscount[3]);
}
/*
* Registers: Seq0BDisableFlag0..7
* - Program PIE Instruction Disable Flags
* - Dependencies:
* - user_input_advanced.DisableRetraining (LPDDR4)
* - skip_training (LPDDR4)
* - user_input_basic.frequency (LPDDR4)
*/
static void seq0bdisableflag_program(struct stm32mp_ddr_config *config, bool skip_training)
{
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TINITENG | CSR_SEQ0BDISABLEFLAG0_ADDR))),
0x0000U);
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TINITENG | CSR_SEQ0BDISABLEFLAG1_ADDR))),
0x0173U);
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TINITENG | CSR_SEQ0BDISABLEFLAG2_ADDR))),
0x0060U);
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TINITENG | CSR_SEQ0BDISABLEFLAG3_ADDR))),
0x6110U);
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TINITENG | CSR_SEQ0BDISABLEFLAG4_ADDR))),
0x2152U);
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TINITENG | CSR_SEQ0BDISABLEFLAG5_ADDR))),
0xDFBDU);
#if STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TINITENG | CSR_SEQ0BDISABLEFLAG6_ADDR))),
0xFFFFU);
#else /* STM32MP_LPDDR4_TYPE */
if (skip_training || (config->uia.disableretraining != 0U) ||
(config->uib.frequency < 333U)) {
/* Disabling DRAM drift compensation */
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TINITENG |
CSR_SEQ0BDISABLEFLAG6_ADDR))),
0xFFFFU);
} else {
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TINITENG |
CSR_SEQ0BDISABLEFLAG6_ADDR))),
0x2060U);
}
#endif /* STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE */
/*
* - Register: Seq0BGPR7
* - Program active CSx for MRS7 during D4 RDIMM frequency change
*/
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TINITENG | CSR_SEQ0BDISABLEFLAG7_ADDR))),
0x6152U);
}
#if STM32MP_LPDDR4_TYPE
/*
* Registers: ppttrainsetup and ppttrainsetup2
* - Related to DFI PHY Master Interface (PMI).
* - Enable DFI PMI if training firmware was run
* - Fields:
* - PhyMstrTrainInterval
* - PhyMstrMaxReqToAck
* - PhyMstrFreqOverride
* - Dependencies:
* - user_input_basic.frequency
* - user_input_advanced.PhyMstrTrainInterval
* - user_input_advanced.PhyMstrMaxReqToAck
*/
static void ppttrainsetup_program(struct stm32mp_ddr_config *config)
{
uint16_t ppttrainsetup;
/* Enabling Phy Master Interface for DRAM drift compensation */
if (config->uib.frequency >= 333U) {
ppttrainsetup = (uint16_t)((config->uia.phymstrtraininterval <<
CSR_PHYMSTRTRAININTERVAL_LSB) |
(config->uia.phymstrmaxreqtoack <<
CSR_PHYMSTRMAXREQTOACK_LSB));
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_PPTTRAINSETUP_ADDR))),
ppttrainsetup);
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER |
CSR_PPTTRAINSETUP2_ADDR))),
0x0003U);
}
}
/*
* Registers AcsmPlayback*x*
* - Program Address/Command Sequence Engine (ACSM) registers with
* required instructions for retraining algorithm.
*/
static void acsmplayback_program(void)
{
uint32_t vec;
for (vec = 0U; vec < 3U; vec++) {
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TACSM | (CSR_ACSMPLAYBACK0X0_ADDR +
(vec * 2U))))),
0xE0U);
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TACSM | (CSR_ACSMPLAYBACK1X0_ADDR +
(vec * 2U))))),
0x12U);
}
}
/*
* Program Training Hardware Registers for mission mode retraining
* and DRAM drift compensation algorithm.
*/
static void traininghwreg_program(struct stm32mp_ddr_config *config)
{
uint32_t byte;
/* Programing Training Hardware Registers for mission mode retraining */
/*
* - Register: AcsmCtrl13
* - Fields: AcsmCkeEnb
*/
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (C0 | TACSM | CSR_ACSMCTRL13_ADDR))),
0xFU << CSR_ACSMCKEENB_LSB);
/*
* - Register: AcsmCtrl1
* - Fields: AcsmRepCnt
* Need 19 iterations @ 0.25ui increments to cover 4.5UI
*/
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (C0 | TACSM | CSR_ACSMCTRL1_ADDR))),
0xEU << CSR_ACSMREPCNT_LSB);
/*
* - Register: TsmByte1, TsmByte2
* - Dependencies: config->uib.numdbyte
*/
for (byte = 0U; byte < config->uib.numdbyte; byte++) {
uint32_t c_addr;
uint32_t i_addr;
uint16_t regdata;
uint32_t vec;
c_addr = byte * C1;
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (c_addr | TDBYTE |
CSR_TSMBYTE1_ADDR))),
0x1U); /* [15:8] gstep; [7:0]bstep; */
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (c_addr | TDBYTE |
CSR_TSMBYTE2_ADDR))),
0x1U); /* [15:0] good_bar; */
regdata = (CSR_DTSMSTATICCMPR_MASK | CSR_DTSMSTATICCMPRVAL_MASK);
/*
* - Register: TsmByte3, TsmByte5
* - Fields:
* - DtsmStaticCmpr
* - DtsmStaticCmprVal
*/
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (c_addr | TDBYTE |
CSR_TSMBYTE3_ADDR))),
regdata);
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (c_addr | TDBYTE |
CSR_TSMBYTE5_ADDR))),
0x1U); /* [15:0] bad_bar; */
/*
* - Register: TrainingParam
* - Fields:
* - EnDynRateReduction
* - RollIntoCoarse
* - IncDecRate
* - TrainEnRxEn
* - Dependencies:
* - user_input_advanced.DisableRetraining
*/
regdata = (CSR_ENDYNRATEREDUCTION_MASK | CSR_ROLLINTOCOARSE_MASK |
(0x3U << CSR_INCDECRATE_LSB));
regdata = config->uia.disableretraining ?
regdata : (regdata | CSR_TRAINENRXEN_MASK);
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (c_addr | TDBYTE |
CSR_TRAININGPARAM_ADDR))),
regdata);
/*
* - Register: Tsm0
* - Fields:
* - DtsmEnb
*/
regdata = (0x1U << CSR_DTSMENB_LSB);
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (c_addr | I0 | TDBYTE |
CSR_TSM0_ADDR))),
regdata);
/*
* - Register: Tsm2
* - Fields:
* - DtsmDisErrChk
*/
regdata = (0x1U << CSR_DTSMDISERRCHK_LSB);
for (vec = 1U; vec <= I_MAX; vec++) {
i_addr = vec * I1;
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (c_addr | i_addr | TDBYTE |
CSR_TSM2_ADDR))),
regdata);
}
}
}
#endif /* STM32MP_LPDDR4_TYPE */
/*
* - Register: calrate
* - Fields:
* - calOnce
* - calinterval
* - Dependencies
* - user_input_advanced.calinterval
* - user_input_advanced.calonce
*/
static void calrate_program(struct stm32mp_ddr_config *config)
{
uint32_t calinterval;
uint32_t calonce;
uint16_t calrate;
calinterval = config->uia.calinterval;
calonce = config->uia.calonce;
calrate = (uint16_t)((0x1U << CSR_CALRUN_LSB) | (calonce << CSR_CALONCE_LSB) |
(calinterval << CSR_CALINTERVAL_LSB));
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_CALRATE_ADDR))), calrate);
}
/*
* Loads registers after training
*
* This function programs the PHY Initialization Engine (PIE) instructions and
* the associated registers.
* Training hardware registers are also programmed to for mission mode
* retraining. (LPDDR4)
*
* \return void
*/
void ddrphy_phyinit_i_loadpieimage(struct stm32mp_ddr_config *config, bool skip_training)
{
/*
* Enable access to the internal CSRs by setting the MicroContMuxSel CSR to 0.
* This allows the memory controller unrestricted access to the configuration CSRs.
*/
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TAPBONLY | CSR_MICROCONTMUXSEL_ADDR))),
0x0U);
ddrphy_phyinit_loadpieprodcode();
#if STM32MP_LPDDR4_TYPE
/*
* No user specified EnableDfiCsPolarityFix, running with new PUB with DFI CS polarity fix
* so program the data polarity CSR.
*/
dfiwrrddatacsconfig_program();
#endif /* STM32MP_LPDDR4_TYPE */
seq0bdly_program(config);
seq0bdisableflag_program(config, skip_training);
#if STM32MP_LPDDR4_TYPE
if (!skip_training) {
ppttrainsetup_program(config);
}
acsmplayback_program();
traininghwreg_program(config);
#endif /* STM32MP_LPDDR4_TYPE */
/*
* - Register: CalZap
* - Prepare the calibration controller for mission mode.
* Turn on calibration and hold idle until dfi_init_start is asserted sequence is
* triggered.
*/
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_CALZAP_ADDR))), 0x1U);
calrate_program(config);
/*
* At the end of this function, PHY Clk gating register UcclkHclkEnables is
* set for mission mode. Additionally APB access is Isolated by setting
* MicroContMuxSel.
*/
/* Disabling Ucclk (PMU) and Hclk (training hardware) */
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TDRTUB | CSR_UCCLKHCLKENABLES_ADDR))),
0x0U);
/* Isolate the APB access from the internal CSRs by setting the MicroContMuxSel CSR to 1 */
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TAPBONLY | CSR_MICROCONTMUXSEL_ADDR))),
0x1U);
}

View file

@ -0,0 +1,262 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <string.h>
#include <common/debug.h>
#include <ddrphy_phyinit.h>
/*
* This is used to initialize the PhyInit structures before user defaults and overrides are applied.
*
* @return Void
*/
void ddrphy_phyinit_initstruct(struct stm32mp_ddr_config *config, struct pmu_smb_ddr_1d *mb_ddr_1d)
{
/*
* ##############################################################
* Basic Message Block Variables
* ##############################################################
*/
uint8_t msgmisc = 0x00U; /* For fast simulation */
uint8_t reserved00 = 0x0U; /*
* Set reserved00[7] = 1 (If using T28 attenuated receivers)
* Set reserved00[6:0] = 0 (Reserved; must be set to 0)
*/
uint8_t hdtctrl = 0xFFU;
#if STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE
uint8_t cspresent = 0x01U; /*
* Indicates presence of DRAM at each chip select for PHY.
*
* If the bit is set to 1, the CS is connected to DRAM.
* If the bit is set to 0, the CS is not connected to DRAM.
*
* Set cspresent[0] = 1 (if CS0 is populated with DRAM)
* Set cspresent[1] = 1 (if CS1 is populated with DRAM)
* Set cspresent[2] = 1 (if CS2 is populated with DRAM)
* Set cspresent[3] = 1 (if CS3 is populated with DRAM)
* Set cspresent[7:4] = 0 (Reserved; must be set to 0)
*/
uint8_t dfimrlmargin = 0x01U; /* 1 is typically good in DDR3 */
#if STM32MP_DDR3_TYPE
uint8_t addrmirror = 0x00U; /*
* Set addrmirror if CS is mirrored.
* (typically odd CS are mirroed in DIMMs)
*/
#else /* STM32MP_DDR4_TYPE */
uint8_t addrmirror = 0xAAU;
#endif /* STM32MP_DDR3_TYPE */
uint8_t wrodtpat_rank0 = 0x01U; /*
* When Writing Rank0 : Bits[3:0] should be set to the
* desired setting of ODT[3:0] to the DRAM
*/
uint8_t wrodtpat_rank1 = 0x02U; /*
* When Writing Rank1 : Bits[3:0] should be set to the
* desired setting of ODT[3:0] to the DRAM
*/
#if STM32MP_DDR3_TYPE
uint8_t wrodtpat_rank2 = 0x04U; /*
* When Writing Rank2 : Bits[3:0] should be set to the
* desired setting of ODT[3:0] to the DRAM
*/
uint8_t wrodtpat_rank3 = 0x08U; /*
* When Writing Rank3 : Bits[3:0] should be set to the
* desired setting of ODT[3:0] to the DRAM
*/
#else /* STM32MP_DDR4_TYPE */
uint8_t wrodtpat_rank2 = 0x00U;
uint8_t wrodtpat_rank3 = 0x00U;
#endif /* STM32MP_DDR3_TYPE */
uint8_t rdodtpat_rank0 = 0x20U; /*
* When Reading Rank0 : Bits[7:4] should be set to the
* desired setting of ODT[3:0] to the DRAM
*/
uint8_t rdodtpat_rank1 = 0x10U; /*
* When Reading Rank1 : Bits[7:4] should be set to the
* desired setting of ODT[3:0] to the DRAM
*/
#if STM32MP_DDR3_TYPE
uint8_t rdodtpat_rank2 = 0x80U; /*
* When Reading Rank2 : Bits[7:4] should be set to the
* desired setting of ODT[3:0] to the DRAM
*/
uint8_t rdodtpat_rank3 = 0x40U; /*
* When Reading Rank3 : Bits[7:4] should be set to the
* desired setting of ODT[3:0] to the DRAM
*/
#else /* STM32MP_DDR4_TYPE */
uint8_t rdodtpat_rank2 = 0x00U;
uint8_t rdodtpat_rank3 = 0x00U;
uint8_t d4misc = 0x1U; /*
* Protect memory reset:
* 0x1 = dfi_reset_n cannot control BP_MEMRESERT_L to
* devices after training.
* 0x0 = dfi_resert_n can control BP_MEMRESERT_L to
* devices after training.
*/
#endif /* STM32MP_DDR3_TYPE */
#else /* STM32MP_LPDDR4_TYPE */
uint8_t caterminatingrankcha = 0x00U; /* Usually Rank0 is terminating rank */
uint8_t caterminatingrankchb = 0x00U; /* Usually Rank0 is terminating rank */
uint8_t dfimrlmargin = 0x02U; /* This needs to be large enough for max tDQSCK variation */
#endif /* STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE */
#if STM32MP_DDR3_TYPE
uint8_t share2dvrefresult = 0x0U; /*
* Bitmap that controls which vref generator the
* phy will use per pstate
* If share2dvrefresult[x] = 1, pstate x will
* use the per-lane VrefDAC0/1 CSRs which can be
* trained by 2d training. If 2D has not run
* yet, VrefDAC0/1 will default to pstate 0's
* 1D phyVref messageBlock setting.
* If share2dvrefresult[x] = 0, pstate x will
* use the per-phy VrefInGlobal CSR, which are
* set to pstate x's 1D phyVref messageBlock
* setting.
*/
#elif STM32MP_DDR4_TYPE
uint8_t share2dvrefresult = 0x1U;
#else /* STM32MP_LPDDR4_TYPE */
uint8_t share2dvrefresult = 0x1U;
uint8_t usebroadcastmr = 0x00U;
#endif /* STM32MP_DDR3_TYPE */
/* 1D message block defaults */
memset((void *)mb_ddr_1d, 0, sizeof(struct pmu_smb_ddr_1d));
mb_ddr_1d->pstate = 0U;
mb_ddr_1d->sequencectrl = (uint16_t)config->uia.sequencectrl;
mb_ddr_1d->phyconfigoverride = 0x0U;
mb_ddr_1d->hdtctrl = hdtctrl;
mb_ddr_1d->msgmisc = msgmisc;
mb_ddr_1d->reserved00 = reserved00;
mb_ddr_1d->dfimrlmargin = dfimrlmargin;
mb_ddr_1d->phyvref = (uint8_t)config->uia.phyvref;
#if STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE
mb_ddr_1d->cspresent = cspresent;
mb_ddr_1d->cspresentd0 = cspresent;
/* mb_ddr_1d->cspresentd1 = 0x0U; Unused */
mb_ddr_1d->addrmirror = addrmirror;
mb_ddr_1d->acsmodtctrl0 = wrodtpat_rank0 | rdodtpat_rank0;
mb_ddr_1d->acsmodtctrl1 = wrodtpat_rank1 | rdodtpat_rank1;
mb_ddr_1d->acsmodtctrl2 = wrodtpat_rank2 | rdodtpat_rank2;
mb_ddr_1d->acsmodtctrl3 = wrodtpat_rank3 | rdodtpat_rank3;
/* mb_ddr_1d->acsmodtctrl4 = 0x0U; Unused */
/* mb_ddr_1d->acsmodtctrl5 = 0x0U; Unused */
/* mb_ddr_1d->acsmodtctrl6 = 0x0U; Unused */
/* mb_ddr_1d->acsmodtctrl7 = 0x0U; Unused */
mb_ddr_1d->enableddqs = (uint8_t)((config->uib.numactivedbytedfi0 +
config->uib.numactivedbytedfi1) * 8U);
#if STM32MP_DDR3_TYPE
mb_ddr_1d->phycfg = (uint8_t)config->uia.is2ttiming;
#else /* STM32MP_DDR4_TYPE */
mb_ddr_1d->phycfg = ((config->uim.mr3 & 0x8U) == 0x8U) ?
0U : (uint8_t)config->uia.is2ttiming;
mb_ddr_1d->x16present = (config->uib.dramdatawidth == 0x10) ?
mb_ddr_1d->cspresent : 0x0U;
mb_ddr_1d->d4misc = d4misc;
mb_ddr_1d->cssetupgddec = 0x1U; /* If Geardown is chosen, dynamically modify CS timing */
/*
* Outputs - just initialize these to zero
* mb_ddr_1d->rtt_nom_wr_park<0..7>
*/
#endif /* STM32MP_DDR3_TYPE */
mb_ddr_1d->mr0 = (uint16_t)config->uim.mr0;
mb_ddr_1d->mr1 = (uint16_t)config->uim.mr1;
mb_ddr_1d->mr2 = (uint16_t)config->uim.mr2;
#if STM32MP_DDR4_TYPE
mb_ddr_1d->mr3 = (uint16_t)config->uim.mr3;
mb_ddr_1d->mr4 = (uint16_t)config->uim.mr4;
mb_ddr_1d->mr5 = (uint16_t)config->uim.mr5;
mb_ddr_1d->mr6 = (uint16_t)config->uim.mr6;
mb_ddr_1d->alt_cas_l = 0x0U;
mb_ddr_1d->alt_wcas_l = 0x0U;
/*
* Outputs - just initialize these to zero
* mb_ddr_1d->vrefdqr<0..3>nib<0..19>
*/
#endif /* STM32MP_DDR4_TYPE */
#else /* STM32MP_LPDDR4_TYPE */
mb_ddr_1d->enableddqscha = (uint8_t)(config->uib.numactivedbytedfi0 * 8U);
mb_ddr_1d->cspresentcha = (config->uib.numrank_dfi0 == 2U) ?
0x3U : (uint8_t)config->uib.numrank_dfi0;
mb_ddr_1d->enableddqschb = (uint8_t)(config->uib.numactivedbytedfi1 * 8U);
mb_ddr_1d->cspresentchb = (config->uib.numrank_dfi1 == 2U) ?
0x3U : (uint8_t)config->uib.numrank_dfi1;
mb_ddr_1d->usebroadcastmr = usebroadcastmr;
mb_ddr_1d->lp4misc = 0x00U;
mb_ddr_1d->caterminatingrankcha = caterminatingrankcha;
mb_ddr_1d->caterminatingrankchb = caterminatingrankchb;
mb_ddr_1d->lp4quickboot = 0x00U;
mb_ddr_1d->catrainopt = 0x00U;
mb_ddr_1d->x8mode = 0x00U;
mb_ddr_1d->mr1_a0 = (uint8_t)config->uim.mr1;
mb_ddr_1d->mr2_a0 = (uint8_t)config->uim.mr2;
mb_ddr_1d->mr3_a0 = (uint8_t)config->uim.mr3;
mb_ddr_1d->mr4_a0 = (uint8_t)config->uim.mr4;
mb_ddr_1d->mr11_a0 = (uint8_t)config->uim.mr11;
mb_ddr_1d->mr12_a0 = (uint8_t)config->uim.mr12;
mb_ddr_1d->mr13_a0 = (uint8_t)config->uim.mr13;
mb_ddr_1d->mr14_a0 = (uint8_t)config->uim.mr14;
mb_ddr_1d->mr16_a0 = 0x00U;
mb_ddr_1d->mr17_a0 = 0x00U;
mb_ddr_1d->mr22_a0 = (uint8_t)config->uim.mr22;
mb_ddr_1d->mr24_a0 = 0x00U;
mb_ddr_1d->mr1_a1 = (uint8_t)config->uim.mr1;
mb_ddr_1d->mr2_a1 = (uint8_t)config->uim.mr2;
mb_ddr_1d->mr3_a1 = (uint8_t)config->uim.mr3;
mb_ddr_1d->mr4_a1 = (uint8_t)config->uim.mr4;
mb_ddr_1d->mr11_a1 = (uint8_t)config->uim.mr11;
mb_ddr_1d->mr12_a1 = (uint8_t)config->uim.mr12;
mb_ddr_1d->mr13_a1 = (uint8_t)config->uim.mr13;
mb_ddr_1d->mr14_a1 = (uint8_t)config->uim.mr14;
mb_ddr_1d->mr16_a1 = 0x00U;
mb_ddr_1d->mr17_a1 = 0x00U;
mb_ddr_1d->mr22_a1 = (uint8_t)config->uim.mr22;
mb_ddr_1d->mr24_a1 = 0x00U;
mb_ddr_1d->mr1_b0 = (uint8_t)config->uim.mr1;
mb_ddr_1d->mr2_b0 = (uint8_t)config->uim.mr2;
mb_ddr_1d->mr3_b0 = (uint8_t)config->uim.mr3;
mb_ddr_1d->mr4_b0 = (uint8_t)config->uim.mr4;
mb_ddr_1d->mr11_b0 = (uint8_t)config->uim.mr11;
mb_ddr_1d->mr12_b0 = (uint8_t)config->uim.mr12;
mb_ddr_1d->mr13_b0 = (uint8_t)config->uim.mr13;
mb_ddr_1d->mr14_b0 = (uint8_t)config->uim.mr14;
mb_ddr_1d->mr16_b0 = 0x00U;
mb_ddr_1d->mr17_b0 = 0x00U;
mb_ddr_1d->mr22_b0 = (uint8_t)config->uim.mr22;
mb_ddr_1d->mr24_b0 = 0x00U;
mb_ddr_1d->mr1_b1 = (uint8_t)config->uim.mr1;
mb_ddr_1d->mr2_b1 = (uint8_t)config->uim.mr2;
mb_ddr_1d->mr3_b1 = (uint8_t)config->uim.mr3;
mb_ddr_1d->mr4_b1 = (uint8_t)config->uim.mr4;
mb_ddr_1d->mr11_b1 = (uint8_t)config->uim.mr11;
mb_ddr_1d->mr12_b1 = (uint8_t)config->uim.mr12;
mb_ddr_1d->mr13_b1 = (uint8_t)config->uim.mr13;
mb_ddr_1d->mr14_b1 = (uint8_t)config->uim.mr14;
mb_ddr_1d->mr16_b1 = 0x00U;
mb_ddr_1d->mr17_b1 = 0x00U;
mb_ddr_1d->mr22_b1 = (uint8_t)config->uim.mr22;
mb_ddr_1d->mr24_b1 = 0x00U;
#endif /* STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE */
mb_ddr_1d->share2dvrefresult = share2dvrefresult;
}

View file

@ -0,0 +1,88 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdlib.h>
#include <common/debug.h>
#include <ddrphy_phyinit.h>
#include <ddrphy_wrapper.h>
/*
* Helper function to determine if a given DByte is Disabled given PhyInit inputs.
* @return 1 if disabled, 0 if enabled.
*/
int ddrphy_phyinit_isdbytedisabled(struct stm32mp_ddr_config *config,
struct pmu_smb_ddr_1d *mb_ddr_1d, uint32_t dbytenumber)
{
int disabledbyte;
uint32_t nad0 __maybe_unused;
uint32_t nad1 __maybe_unused;
disabledbyte = 0; /* Default assume Dbyte is Enabled */
#if STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE
disabledbyte = (dbytenumber > (config->uib.numactivedbytedfi0 - 1U)) ? 1 : 0;
#else /* STM32MP_LPDDR4_TYPE */
nad0 = config->uib.numactivedbytedfi0;
nad1 = config->uib.numactivedbytedfi1;
if ((nad0 + nad1) > config->uib.numdbyte) {
ERROR("%s %d\n", __func__, __LINE__);
VERBOSE("%s invalid PHY configuration:\n", __func__);
VERBOSE("numactivedbytedfi0(%u)+numactivedbytedfi1(%u)>numdbytes(%u).\n",
nad0, nad1, config->uib.numdbyte);
}
if (config->uib.dfi1exists != 0U) {
if (config->uib.numactivedbytedfi1 == 0U) {
/* Only dfi0 (ChA) is enabled, dfi1 (ChB) disabled */
disabledbyte = (dbytenumber > (config->uib.numactivedbytedfi0 - 1U)) ?
1 : 0;
} else {
/* DFI1 enabled */
disabledbyte = (((config->uib.numactivedbytedfi0 - 1U) < dbytenumber) &&
(dbytenumber < (config->uib.numdbyte / 2U))) ?
1 : (dbytenumber >
((config->uib.numdbyte / 2U) +
config->uib.numactivedbytedfi1 - 1U)) ? 1 : 0;
}
} else {
disabledbyte = (dbytenumber > (config->uib.numactivedbytedfi0 - 1U)) ? 1 : 0;
}
#endif /* STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE */
/* Qualify results against MessageBlock */
#if STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE
if ((mb_ddr_1d->enableddqs < 1U) ||
(mb_ddr_1d->enableddqs > (uint8_t)(8U * config->uib.numactivedbytedfi0))) {
ERROR("%s %d\n", __func__, __LINE__);
VERBOSE("%s enableddqs(%u)\n", __func__, mb_ddr_1d->enableddqs);
VERBOSE("Value must be 0 < enableddqs < config->uib.numactivedbytedfi0 * 8.\n");
}
if (dbytenumber < 8) {
disabledbyte |= (int)mb_ddr_1d->disableddbyte & (0x1 << dbytenumber);
}
#else /* STM32MP_LPDDR4_TYPE */
if ((mb_ddr_1d->enableddqscha < 1U) ||
(mb_ddr_1d->enableddqscha > (uint8_t)(8U * config->uib.numactivedbytedfi0))) {
ERROR("%s %d\n", __func__, __LINE__);
VERBOSE("%s enableddqscha(%u)\n", __func__, mb_ddr_1d->enableddqscha);
VERBOSE("Value must be 0 < enableddqscha < config->uib.numactivedbytedfi0*8\n");
}
if ((config->uib.dfi1exists != 0U) && (config->uib.numactivedbytedfi1 > 0U) &&
((mb_ddr_1d->enableddqschb < 1U) ||
(mb_ddr_1d->enableddqschb > (uint8_t)(8U * config->uib.numactivedbytedfi1)))) {
ERROR("%s %d\n", __func__, __LINE__);
VERBOSE("%s enableddqschb(%u)\n", __func__, mb_ddr_1d->enableddqschb);
VERBOSE("Value must be 0 < enableddqschb < config->uib.numactivedbytedfi1*8\n");
}
#endif /* STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE */
return disabledbyte;
}

View file

@ -0,0 +1,189 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdint.h>
#include <common/debug.h>
#include <ddrphy_phyinit.h>
#include <lib/mmio.h>
#include <platform_def.h>
#if STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE
#define PRODCODE_SIZE 177
static const uint32_t prodcode_addr[PRODCODE_SIZE] = {
0x90000U, 0x90001U, 0x90002U, 0x90003U, 0x90004U, 0x90005U, 0x90029U, 0x9002AU, 0x9002BU,
0x9002CU, 0x9002DU, 0x9002EU, 0x9002FU, 0x90030U, 0x90031U, 0x90032U, 0x90033U, 0x90034U,
0x90035U, 0x90036U, 0x90037U, 0x90038U, 0x90039U, 0x9003AU, 0x9003BU, 0x9003CU, 0x9003DU,
0x9003EU, 0x9003FU, 0x90040U, 0x90041U, 0x90042U, 0x90043U, 0x90044U, 0x90045U, 0x90046U,
0x90047U, 0x90048U, 0x90049U, 0x9004AU, 0x9004BU, 0x9004CU, 0x9004DU, 0x9004EU, 0x9004FU,
0x90050U, 0x90051U, 0x90052U, 0x90053U, 0x90054U, 0x90055U, 0x90056U, 0x90057U, 0x90058U,
0x90059U, 0x9005AU, 0x9005BU, 0x9005CU, 0x9005DU, 0x9005EU, 0x9005FU, 0x90060U, 0x90061U,
0x90062U, 0x90063U, 0x90064U, 0x90065U, 0x90066U, 0x90067U, 0x90068U, 0x90069U, 0x9006AU,
0x9006BU, 0x9006CU, 0x9006DU, 0x9006EU, 0x9006FU, 0x90070U, 0x90071U, 0x90072U, 0x90073U,
0x90074U, 0x90075U, 0x90076U, 0x90077U, 0x90078U, 0x90079U, 0x9007AU, 0x9007BU, 0x9007CU,
0x9007DU, 0x9007EU, 0x9007FU, 0x90080U, 0x90081U, 0x90082U, 0x90083U, 0x90084U, 0x90085U,
0x90086U, 0x90087U, 0x90088U, 0x90089U, 0x9008AU, 0x9008BU, 0x9008CU, 0x9008DU, 0x9008EU,
0x9008FU, 0x90090U, 0x90091U, 0x90092U, 0x90093U, 0x90094U, 0x90095U, 0x90096U, 0x90097U,
0x90098U, 0x90099U, 0x9009AU, 0x9009BU, 0x9009CU, 0x9009DU, 0x9009EU, 0x9009FU, 0x900A0U,
0x900A1U, 0x900A2U, 0x900A3U, 0x900A4U, 0x900A5U, 0x900A6U, 0x900A7U, 0x900A8U, 0x900A9U,
0x900AAU, 0x900ABU, 0x900ACU, 0x900ADU, 0x900AEU, 0x900AFU, 0x900B0U, 0x900B1U, 0x900B2U,
0x900B3U, 0x900B4U, 0x900B5U, 0x900B6U, 0x900B7U, 0x900B8U, 0x900B9U, 0x900BAU, 0x900BBU,
0x900BCU, 0x900BDU, 0x900BEU, 0x900BFU, 0x900C0U, 0x900C1U, 0x900C2U, 0x900C3U, 0x900C4U,
0x900C5U, 0x900C6U, 0x900C7U, 0x900C8U, 0x900C9U, 0x900CAU, 0x90006U, 0x90007U, 0x90008U,
0x90009U, 0x9000AU, 0x9000BU, 0xD00E7U, 0x90017U, 0x90026U,
};
static const uint16_t prodcode_data[PRODCODE_SIZE] = {
0x0010U, 0x0400U, 0x010EU, 0x0000U, 0x0000U, 0x0008U, 0x000BU, 0x0480U, 0x0109U, 0x0008U,
0x0448U, 0x0139U, 0x0008U, 0x0478U, 0x0109U, 0x0002U, 0x0010U, 0x0139U, 0x000BU, 0x07C0U,
0x0139U, 0x0044U, 0x0633U, 0x0159U, 0x014FU, 0x0630U, 0x0159U, 0x0047U, 0x0633U, 0x0149U,
0x004FU, 0x0633U, 0x0179U, 0x0008U, 0x00E0U, 0x0109U, 0x0000U, 0x07C8U, 0x0109U, 0x0000U,
0x0001U, 0x0008U, 0x0030U, 0x065AU, 0x0009U, 0x0000U, 0x045AU, 0x0009U, 0x0000U, 0x0448U,
0x0109U, 0x0040U, 0x0633U, 0x0179U, 0x0001U, 0x0618U, 0x0109U, 0x40C0U, 0x0633U, 0x0149U,
0x0008U, 0x0004U, 0x0048U, 0x4040U, 0x0633U, 0x0149U, 0x0000U, 0x0004U, 0x0048U, 0x0040U,
0x0633U, 0x0149U, 0x0000U, 0x0658U, 0x0109U, 0x0010U, 0x0004U, 0x0018U, 0x0000U, 0x0004U,
0x0078U, 0x0549U, 0x0633U, 0x0159U, 0x0D49U, 0x0633U, 0x0159U, 0x094AU, 0x0633U, 0x0159U,
0x0441U, 0x0633U, 0x0149U, 0x0042U, 0x0633U, 0x0149U, 0x0001U, 0x0633U, 0x0149U, 0x0000U,
0x00E0U, 0x0109U, 0x000AU, 0x0010U, 0x0109U, 0x0009U, 0x03C0U, 0x0149U, 0x0009U, 0x03C0U,
0x0159U, 0x0018U, 0x0010U, 0x0109U, 0x0000U, 0x03C0U, 0x0109U, 0x0018U, 0x0004U, 0x0048U,
0x0018U, 0x0004U, 0x0058U, 0x000BU, 0x0010U, 0x0109U, 0x0001U, 0x0010U, 0x0109U, 0x0005U,
0x07C0U, 0x0109U, 0x0000U, 0x8140U, 0x010CU, 0x0010U, 0x8138U, 0x0104U, 0x0008U, 0x0448U,
0x0109U, 0x000FU, 0x07C0U, 0x0109U, 0x0047U, 0x0630U, 0x0109U, 0x0008U, 0x0618U, 0x0109U,
0x0008U, 0x00E0U, 0x0109U, 0x0000U, 0x07C8U, 0x0109U, 0x0008U, 0x8140U, 0x010CU, 0x0000U,
0x0478U, 0x0109U, 0x0000U, 0x0001U, 0x0008U, 0x0008U, 0x0004U, 0x0000U, 0x0008U, 0x07C8U,
0x0109U, 0x0000U, 0x0400U, 0x0106U, 0x0400U, 0x0000U, 0x002CU,
};
#else /* STM32MP_LPDDR4_TYPE */
#define PRODCODE_SIZE 481
static const uint32_t prodcode_addr[PRODCODE_SIZE] = {
0x90000U, 0x90001U, 0x90002U, 0x90003U, 0x90004U, 0x90005U, 0x90029U, 0x9002AU, 0x9002BU,
0x9002CU, 0x9002DU, 0x9002EU, 0x9002FU, 0x90030U, 0x90031U, 0x90032U, 0x90033U, 0x90034U,
0x90035U, 0x90036U, 0x90037U, 0x90038U, 0x90039U, 0x9003AU, 0x9003BU, 0x9003CU, 0x9003DU,
0x9003EU, 0x9003FU, 0x90040U, 0x90041U, 0x90042U, 0x90043U, 0x90044U, 0x90045U, 0x90046U,
0x90047U, 0x90048U, 0x90049U, 0x9004AU, 0x9004BU, 0x9004CU, 0x9004DU, 0x9004EU, 0x9004FU,
0x90050U, 0x90051U, 0x90052U, 0x90053U, 0x90054U, 0x90055U, 0x90056U, 0x90057U, 0x90058U,
0x90059U, 0x9005AU, 0x9005BU, 0x9005CU, 0x9005DU, 0x9005EU, 0x9005FU, 0x90060U, 0x90061U,
0x90062U, 0x90063U, 0x90064U, 0x90065U, 0x90066U, 0x90067U, 0x90068U, 0x90069U, 0x9006AU,
0x9006BU, 0x9006CU, 0x9006DU, 0x9006EU, 0x9006FU, 0x90070U, 0x90071U, 0x90072U, 0x90073U,
0x90074U, 0x90075U, 0x90076U, 0x90077U, 0x90078U, 0x90079U, 0x9007AU, 0x9007BU, 0x9007CU,
0x9007DU, 0x9007EU, 0x9007FU, 0x90080U, 0x90081U, 0x90082U, 0x90083U, 0x90084U, 0x90085U,
0x90086U, 0x90087U, 0x90088U, 0x90089U, 0x9008AU, 0x9008BU, 0x9008CU, 0x9008DU, 0x9008EU,
0x9008FU, 0x90090U, 0x90091U, 0x90092U, 0x90093U, 0x90094U, 0x90095U, 0x90096U, 0x90097U,
0x90098U, 0x90099U, 0x9009AU, 0x9009BU, 0x9009CU, 0x9009DU, 0x9009EU, 0x9009FU, 0x900A0U,
0x900A1U, 0x900A2U, 0x900A3U, 0x900A4U, 0x900A5U, 0x900A6U, 0x900A7U, 0x900A8U, 0x900A9U,
0x40000U, 0x40020U, 0x40040U, 0x40060U, 0x40001U, 0x40021U, 0x40041U, 0x40061U, 0x40002U,
0x40022U, 0x40042U, 0x40062U, 0x40003U, 0x40023U, 0x40043U, 0x40063U, 0x40004U, 0x40024U,
0x40044U, 0x40064U, 0x40005U, 0x40025U, 0x40045U, 0x40065U, 0x40006U, 0x40026U, 0x40046U,
0x40066U, 0x40007U, 0x40027U, 0x40047U, 0x40067U, 0x40008U, 0x40028U, 0x40048U, 0x40068U,
0x40009U, 0x40029U, 0x40049U, 0x40069U, 0x4000AU, 0x4002AU, 0x4004AU, 0x4006AU, 0x4000BU,
0x4002BU, 0x4004BU, 0x4006BU, 0x4000CU, 0x4002CU, 0x4004CU, 0x4006CU, 0x4000DU, 0x4002DU,
0x4004DU, 0x4006DU, 0x4000EU, 0x4002EU, 0x4004EU, 0x4006EU, 0x4000FU, 0x4002FU, 0x4004FU,
0x4006FU, 0x40010U, 0x40030U, 0x40050U, 0x40070U, 0x40011U, 0x40031U, 0x40051U, 0x40071U,
0x40012U, 0x40032U, 0x40052U, 0x40072U, 0x40013U, 0x40033U, 0x40053U, 0x40073U, 0x40014U,
0x40034U, 0x40054U, 0x40074U, 0x40015U, 0x40035U, 0x40055U, 0x40075U, 0x40016U, 0x40036U,
0x40056U, 0x40076U, 0x40017U, 0x40037U, 0x40057U, 0x40077U, 0x40018U, 0x40038U, 0x40058U,
0x40078U, 0x40019U, 0x40039U, 0x40059U, 0x40079U, 0x4001AU, 0x4003AU, 0x4005AU, 0x4007AU,
0x900AAU, 0x900ABU, 0x900ACU, 0x900ADU, 0x900AEU, 0x900AFU, 0x900B0U, 0x900B1U, 0x900B2U,
0x900B3U, 0x900B4U, 0x900B5U, 0x900B6U, 0x900B7U, 0x900B8U, 0x900B9U, 0x900BAU, 0x900BBU,
0x900BCU, 0x900BDU, 0x900BEU, 0x900BFU, 0x900C0U, 0x900C1U, 0x900C2U, 0x900C3U, 0x900C4U,
0x900C5U, 0x900C6U, 0x900C7U, 0x900C8U, 0x900C9U, 0x900CAU, 0x900CBU, 0x900CCU, 0x900CDU,
0x900CEU, 0x900CFU, 0x900D0U, 0x900D1U, 0x900D2U, 0x900D3U, 0x900D4U, 0x900D5U, 0x900D6U,
0x900D7U, 0x900D8U, 0x900D9U, 0x900DAU, 0x900DBU, 0x900DCU, 0x900DDU, 0x900DEU, 0x900DFU,
0x900E0U, 0x900E1U, 0x900E2U, 0x900E3U, 0x900E4U, 0x900E5U, 0x900E6U, 0x900E7U, 0x900E8U,
0x900E9U, 0x900EAU, 0x900EBU, 0x900ECU, 0x900EDU, 0x900EEU, 0x900EFU, 0x900F0U, 0x900F1U,
0x900F2U, 0x900F3U, 0x900F4U, 0x900F5U, 0x900F6U, 0x900F7U, 0x900F8U, 0x900F9U, 0x900FAU,
0x900FBU, 0x900FCU, 0x900FDU, 0x900FEU, 0x900FFU, 0x90100U, 0x90101U, 0x90102U, 0x90103U,
0x90104U, 0x90105U, 0x90106U, 0x90107U, 0x90108U, 0x90109U, 0x9010AU, 0x9010BU, 0x9010CU,
0x9010DU, 0x9010EU, 0x9010FU, 0x90110U, 0x90111U, 0x90112U, 0x90113U, 0x90114U, 0x90115U,
0x90116U, 0x90117U, 0x90118U, 0x90119U, 0x9011AU, 0x9011BU, 0x9011CU, 0x9011DU, 0x9011EU,
0x9011FU, 0x90120U, 0x90121U, 0x90122U, 0x90123U, 0x90124U, 0x90125U, 0x90126U, 0x90127U,
0x90128U, 0x90129U, 0x9012AU, 0x9012BU, 0x9012CU, 0x9012DU, 0x9012EU, 0x9012FU, 0x90130U,
0x90131U, 0x90132U, 0x90133U, 0x90134U, 0x90135U, 0x90136U, 0x90137U, 0x90138U, 0x90139U,
0x9013AU, 0x9013BU, 0x9013CU, 0x9013DU, 0x9013EU, 0x9013FU, 0x90140U, 0x90141U, 0x90142U,
0x90143U, 0x90144U, 0x90145U, 0x90146U, 0x90147U, 0x90148U, 0x90149U, 0x9014AU, 0x9014BU,
0x9014CU, 0x9014DU, 0x9014EU, 0x9014FU, 0x90150U, 0x90151U, 0x90152U, 0x90153U, 0x90154U,
0x90155U, 0x90156U, 0x90157U, 0x90158U, 0x90159U, 0x9015AU, 0x9015BU, 0x9015CU, 0x9015DU,
0x9015EU, 0x9015FU, 0x90160U, 0x90161U, 0x90162U, 0x90163U, 0x90164U, 0x90165U, 0x90166U,
0x90167U, 0x90168U, 0x90169U, 0x9016AU, 0x9016BU, 0x9016CU, 0x9016DU, 0x9016EU, 0x9016FU,
0x90170U, 0x90171U, 0x90172U, 0x90173U, 0x90174U, 0x90175U, 0x90176U, 0x90177U, 0x90178U,
0x90179U, 0x9017AU, 0x9017BU, 0x9017CU, 0x9017DU, 0x9017EU, 0x9017FU, 0x90180U, 0x90181U,
0x90182U, 0x90183U, 0x90184U, 0x90006U, 0x90007U, 0x90008U, 0x90009U, 0x9000AU, 0x9000BU,
0xD00E7U, 0x90017U, 0x9001FU, 0x90026U, 0x400D0U, 0x400D1U, 0x400D2U, 0x400D3U, 0x400D4U,
0x400D5U, 0x400D6U, 0x400D7U, 0x2003AU,
};
static const uint16_t prodcode_data[PRODCODE_SIZE] = {
0x0010U, 0x0400U, 0x010EU, 0x0000U, 0x0000U, 0x0008U, 0x000BU, 0x0480U, 0x0109U, 0x0008U,
0x0448U, 0x0139U, 0x0008U, 0x0478U, 0x0109U, 0x0000U, 0x00E8U, 0x0109U, 0x0002U, 0x0010U,
0x0139U, 0x000BU, 0x07C0U, 0x0139U, 0x0044U, 0x0633U, 0x0159U, 0x014FU, 0x0630U, 0x0159U,
0x0047U, 0x0633U, 0x0149U, 0x004FU, 0x0633U, 0x0179U, 0x0008U, 0x00E0U, 0x0109U, 0x0000U,
0x07C8U, 0x0109U, 0x0000U, 0x0001U, 0x0008U, 0x0030U, 0x065AU, 0x0009U, 0x0000U, 0x045AU,
0x0009U, 0x0000U, 0x0448U, 0x0109U, 0x0040U, 0x0633U, 0x0179U, 0x0001U, 0x0618U, 0x0109U,
0x40C0U, 0x0633U, 0x0149U, 0x0008U, 0x0004U, 0x0048U, 0x4040U, 0x0633U, 0x0149U, 0x0000U,
0x0004U, 0x0048U, 0x0040U, 0x0633U, 0x0149U, 0x0000U, 0x0658U, 0x0109U, 0x0010U, 0x0004U,
0x0018U, 0x0000U, 0x0004U, 0x0078U, 0x0549U, 0x0633U, 0x0159U, 0x0D49U, 0x0633U, 0x0159U,
0x094AU, 0x0633U, 0x0159U, 0x0441U, 0x0633U, 0x0149U, 0x0042U, 0x0633U, 0x0149U, 0x0001U,
0x0633U, 0x0149U, 0x0000U, 0x00E0U, 0x0109U, 0x000AU, 0x0010U, 0x0109U, 0x0009U, 0x03C0U,
0x0149U, 0x0009U, 0x03C0U, 0x0159U, 0x0018U, 0x0010U, 0x0109U, 0x0000U, 0x03C0U, 0x0109U,
0x0018U, 0x0004U, 0x0048U, 0x0018U, 0x0004U, 0x0058U, 0x000BU, 0x0010U, 0x0109U, 0x0001U,
0x0010U, 0x0109U, 0x0005U, 0x07C0U, 0x0109U, 0x0811U, 0x0880U, 0x0000U, 0x0000U, 0x4008U,
0x0083U, 0x004FU, 0x0000U, 0x4040U, 0x0083U, 0x0051U, 0x0000U, 0x0811U, 0x0880U, 0x0000U,
0x0000U, 0x0720U, 0x000FU, 0x1740U, 0x0000U, 0x0016U, 0x0083U, 0x004BU, 0x0000U, 0x0716U,
0x000FU, 0x2001U, 0x0000U, 0x0716U, 0x000FU, 0x2800U, 0x0000U, 0x0716U, 0x000FU, 0x0F00U,
0x0000U, 0x0720U, 0x000FU, 0x1400U, 0x0000U, 0x0E08U, 0x0C15U, 0x0000U, 0x0000U, 0x0625U,
0x0015U, 0x0000U, 0x0000U, 0x4028U, 0x0080U, 0x0000U, 0x0000U, 0x0E08U, 0x0C1AU, 0x0000U,
0x0000U, 0x0625U, 0x001AU, 0x0000U, 0x0000U, 0x4040U, 0x0080U, 0x0000U, 0x0000U, 0x2604U,
0x0015U, 0x0000U, 0x0000U, 0x0708U, 0x0005U, 0x0000U, 0x2002U, 0x0008U, 0x0080U, 0x0000U,
0x0000U, 0x2604U, 0x001AU, 0x0000U, 0x0000U, 0x0708U, 0x000AU, 0x0000U, 0x2002U, 0x4040U,
0x0080U, 0x0000U, 0x0000U, 0x060AU, 0x0015U, 0x1200U, 0x0000U, 0x061AU, 0x0015U, 0x1300U,
0x0000U, 0x060AU, 0x001AU, 0x1200U, 0x0000U, 0x0642U, 0x001AU, 0x1300U, 0x0000U, 0x4808U,
0x0880U, 0x0000U, 0x0000U, 0x0000U, 0x0790U, 0x011AU, 0x0008U, 0x07AAU, 0x002AU, 0x0010U,
0x07B2U, 0x002AU, 0x0000U, 0x07C8U, 0x0109U, 0x0010U, 0x0010U, 0x0109U, 0x0010U, 0x02A8U,
0x0129U, 0x0008U, 0x0370U, 0x0129U, 0x000AU, 0x03C8U, 0x01A9U, 0x000CU, 0x0408U, 0x0199U,
0x0014U, 0x0790U, 0x011AU, 0x0008U, 0x0004U, 0x0018U, 0x000EU, 0x0408U, 0x0199U, 0x0008U,
0x8568U, 0x0108U, 0x0018U, 0x0790U, 0x016AU, 0x0008U, 0x01D8U, 0x0169U, 0x0010U, 0x8558U,
0x0168U, 0x1FF8U, 0x85A8U, 0x01E8U, 0x0050U, 0x0798U, 0x016AU, 0x0060U, 0x07A0U, 0x016AU,
0x0008U, 0x8310U, 0x0168U, 0x0008U, 0xA310U, 0x0168U, 0x000AU, 0x0408U, 0x0169U, 0x006EU,
0x0000U, 0x0068U, 0x0000U, 0x0408U, 0x0169U, 0x0000U, 0x8310U, 0x0168U, 0x0000U, 0xA310U,
0x0168U, 0x1FF8U, 0x85A8U, 0x01E8U, 0x0068U, 0x0798U, 0x016AU, 0x0078U, 0x07A0U, 0x016AU,
0x0068U, 0x0790U, 0x016AU, 0x0008U, 0x8B10U, 0x0168U, 0x0008U, 0xAB10U, 0x0168U, 0x000AU,
0x0408U, 0x0169U, 0x0058U, 0x0000U, 0x0068U, 0x0000U, 0x0408U, 0x0169U, 0x0000U, 0x8B10U,
0x0168U, 0x0001U, 0xAB10U, 0x0168U, 0x0000U, 0x01D8U, 0x0169U, 0x0080U, 0x0790U, 0x016AU,
0x0018U, 0x07AAU, 0x006AU, 0x000AU, 0x0000U, 0x01E9U, 0x0008U, 0x8080U, 0x0108U, 0x000FU,
0x0408U, 0x0169U, 0x000CU, 0x0000U, 0x0068U, 0x0009U, 0x0000U, 0x01A9U, 0x0000U, 0x0408U,
0x0169U, 0x0000U, 0x8080U, 0x0108U, 0x0008U, 0x07AAU, 0x006AU, 0x0000U, 0x8568U, 0x0108U,
0x00B7U, 0x0790U, 0x016AU, 0x001FU, 0x0000U, 0x0068U, 0x0008U, 0x8558U, 0x0168U, 0x000FU,
0x0408U, 0x0169U, 0x000DU, 0x0000U, 0x0068U, 0x0000U, 0x0408U, 0x0169U, 0x0000U, 0x8558U,
0x0168U, 0x0008U, 0x03C8U, 0x01A9U, 0x0003U, 0x0370U, 0x0129U, 0x0020U, 0x02AAU, 0x0009U,
0x0008U, 0x00E8U, 0x0109U, 0x0000U, 0x8140U, 0x010CU, 0x0010U, 0x8138U, 0x0104U, 0x0008U,
0x0448U, 0x0109U, 0x000FU, 0x07C0U, 0x0109U, 0x0000U, 0x00E8U, 0x0109U, 0x0047U, 0x0630U,
0x0109U, 0x0008U, 0x0618U, 0x0109U, 0x0008U, 0x00E0U, 0x0109U, 0x0000U, 0x07C8U, 0x0109U,
0x0008U, 0x8140U, 0x010CU, 0x0000U, 0x0478U, 0x0109U, 0x0000U, 0x0001U, 0x0008U, 0x0008U,
0x0004U, 0x0000U, 0x0008U, 0x07C8U, 0x0109U, 0x0000U, 0x0400U, 0x0106U, 0x0400U, 0x0000U,
0x002BU, 0x0069U, 0x0000U, 0x0101U, 0x0105U, 0x0107U, 0x010FU, 0x0202U, 0x020AU, 0x020BU,
0x0002U,
};
#endif /* STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE */
/*
* Loads PIE instruction sequence PHY registers
* @returns void
*/
void ddrphy_phyinit_loadpieprodcode(void)
{
int i;
for (i = 0; i < PRODCODE_SIZE; i++) {
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * prodcode_addr[i])),
prodcode_data[i]);
}
}

View file

@ -0,0 +1,282 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdlib.h>
#include <string.h>
#include <common/debug.h>
#include <ddrphy_phyinit.h>
/*
* Maps impedance values to register settings
*
* Reads the pull-up/pull-down driver impedance from drvstren_ohm input
* and encodes that value for the CSR field specified in targetcsr input,
* based on DDR protocol.
*
* @param[in] drvstren_ohm drive strenght / ODT impedance in Ohms
*
* @param[in] targetcsr Target CSR for the impedance value. on of following
* enum drvtype:
* - DRVSTRENFSDQP
* - DRVSTRENFSDQN
* - ODTSTRENP
* - ODTSTRENN
* - ADRVSTRENP
* - ADRVSTRENN
*
* \return >=0 value on success, else negative.
*/
int ddrphy_phyinit_mapdrvstren(uint32_t drvstren_ohm, enum drvtype targetcsr)
{
int stren_setting = -1;
if ((targetcsr == DRVSTRENFSDQP) || (targetcsr == DRVSTRENFSDQN)) {
if (drvstren_ohm == 0U) {
stren_setting = 0x00; /* High-impedance */
} else if (drvstren_ohm < 29U) {
stren_setting = 0x3f;
} else if (drvstren_ohm < 31U) {
stren_setting = 0x3e;
} else if (drvstren_ohm < 33U) {
stren_setting = 0x3b;
} else if (drvstren_ohm < 35U) {
stren_setting = 0x3a;
} else if (drvstren_ohm < 38U) {
stren_setting = 0x39;
} else if (drvstren_ohm < 41U) {
stren_setting = 0x38;
} else if (drvstren_ohm < 45U) {
stren_setting = 0x1b;
} else if (drvstren_ohm < 50U) {
stren_setting = 0x1a;
} else if (drvstren_ohm < 56U) {
stren_setting = 0x19;
} else if (drvstren_ohm < 64U) {
stren_setting = 0x18;
} else if (drvstren_ohm < 74U) {
stren_setting = 0x0b;
} else if (drvstren_ohm < 88U) {
stren_setting = 0x0a;
} else if (drvstren_ohm < 108U) {
stren_setting = 0x09;
} else if (drvstren_ohm < 140U) {
stren_setting = 0x08;
} else if (drvstren_ohm < 200U) {
stren_setting = 0x03;
} else if (drvstren_ohm < 360U) {
stren_setting = 0x02;
} else if (drvstren_ohm < 481U) {
stren_setting = 0x01;
} else {
stren_setting = 0x00; /* High-impedance */
}
} else if (targetcsr == ODTSTRENP) {
#if STM32MP_DDR3_TYPE
/*
* DDR3 - P and N has the same impedance and non-zero.
* user input is half the individual pull-up and pull-down impedances values
* because of parallel between them.
*/
if (drvstren_ohm == 0U) {
stren_setting = 0x00; /* High-impedance */
} else if (drvstren_ohm < 15U) {
stren_setting = 0x3f;
} else if (drvstren_ohm < 16U) {
stren_setting = 0x3e;
} else if (drvstren_ohm < 17U) {
stren_setting = 0x3b;
} else if (drvstren_ohm < 18U) {
stren_setting = 0x3a;
} else if (drvstren_ohm < 20U) {
stren_setting = 0x39;
} else if (drvstren_ohm < 21U) {
stren_setting = 0x38;
} else if (drvstren_ohm < 23U) {
stren_setting = 0x1b;
} else if (drvstren_ohm < 26U) {
stren_setting = 0x1a;
} else if (drvstren_ohm < 29U) {
stren_setting = 0x19;
} else if (drvstren_ohm < 33U) {
stren_setting = 0x18;
} else if (drvstren_ohm < 38U) {
stren_setting = 0x0b;
} else if (drvstren_ohm < 45U) {
stren_setting = 0x0a;
} else if (drvstren_ohm < 55U) {
stren_setting = 0x09;
} else if (drvstren_ohm < 71U) {
stren_setting = 0x08;
} else if (drvstren_ohm < 101U) {
stren_setting = 0x03;
} else if (drvstren_ohm < 181U) {
stren_setting = 0x02;
} else if (drvstren_ohm < 241U) {
stren_setting = 0x01;
} else {
stren_setting = 0x00; /* High-impedance */
}
#elif STM32MP_DDR4_TYPE
/* DDR4 - P is non-zero */
if (drvstren_ohm == 0U) {
stren_setting = 0x00; /* High-impedance */
} else if (drvstren_ohm < 29U) {
stren_setting = 0x3f;
} else if (drvstren_ohm < 31U) {
stren_setting = 0x3e;
} else if (drvstren_ohm < 33U) {
stren_setting = 0x3b;
} else if (drvstren_ohm < 35U) {
stren_setting = 0x3a;
} else if (drvstren_ohm < 38U) {
stren_setting = 0x39;
} else if (drvstren_ohm < 41U) {
stren_setting = 0x38;
} else if (drvstren_ohm < 45U) {
stren_setting = 0x1b;
} else if (drvstren_ohm < 50U) {
stren_setting = 0x1a;
} else if (drvstren_ohm < 56U) {
stren_setting = 0x19;
} else if (drvstren_ohm < 64U) {
stren_setting = 0x18;
} else if (drvstren_ohm < 74U) {
stren_setting = 0x0b;
} else if (drvstren_ohm < 88U) {
stren_setting = 0x0a;
} else if (drvstren_ohm < 108U) {
stren_setting = 0x09;
} else if (drvstren_ohm < 140U) {
stren_setting = 0x08;
} else if (drvstren_ohm < 200U) {
stren_setting = 0x03;
} else if (drvstren_ohm < 360U) {
stren_setting = 0x02;
} else if (drvstren_ohm < 481U) {
stren_setting = 0x01;
} else {
stren_setting = 0x00; /* High-impedance */
}
#else /* STM32MP_LPDDR4_TYPE */
/* LPDDR4 - P is high-Z */
stren_setting = 0x00; /* High-impedance */
#endif /* STM32MP_DDR3_TYPE */
} else if (targetcsr == ODTSTRENN) {
#if STM32MP_DDR3_TYPE
/*
* DDR3 - P and N has the same impedance and non-zero.
* Times 2 of user input because of parallel pull-up and pull-down termination.
*/
if (drvstren_ohm == 0U) {
stren_setting = 0x00; /* High-impedance */
} else if (drvstren_ohm < 15U) {
stren_setting = 0x3f;
} else if (drvstren_ohm < 16U) {
stren_setting = 0x3e;
} else if (drvstren_ohm < 17U) {
stren_setting = 0x3b;
} else if (drvstren_ohm < 18U) {
stren_setting = 0x3a;
} else if (drvstren_ohm < 20U) {
stren_setting = 0x39;
} else if (drvstren_ohm < 21U) {
stren_setting = 0x38;
} else if (drvstren_ohm < 23U) {
stren_setting = 0x1b;
} else if (drvstren_ohm < 26U) {
stren_setting = 0x1a;
} else if (drvstren_ohm < 29U) {
stren_setting = 0x19;
} else if (drvstren_ohm < 33U) {
stren_setting = 0x18;
} else if (drvstren_ohm < 38U) {
stren_setting = 0x0b;
} else if (drvstren_ohm < 45U) {
stren_setting = 0x0a;
} else if (drvstren_ohm < 55U) {
stren_setting = 0x09;
} else if (drvstren_ohm < 71U) {
stren_setting = 0x08;
} else if (drvstren_ohm < 101U) {
stren_setting = 0x03;
} else if (drvstren_ohm < 181U) {
stren_setting = 0x02;
} else if (drvstren_ohm < 241U) {
stren_setting = 0x01;
} else {
stren_setting = 0x00; /* High-impedance */
}
#elif STM32MP_DDR4_TYPE
/* DDR4 - N is high-Z */
stren_setting = 0x00; /* High-impedance */
#else /* STM32MP_LPDDR4_TYPE */
/* LPDDR4 - N is non-zero */
if (drvstren_ohm == 0U) {
stren_setting = 0x00; /* High-impedance */
} else if (drvstren_ohm < 29U) {
stren_setting = 0x3f;
} else if (drvstren_ohm < 31U) {
stren_setting = 0x3e;
} else if (drvstren_ohm < 33U) {
stren_setting = 0x3b;
} else if (drvstren_ohm < 35U) {
stren_setting = 0x3a;
} else if (drvstren_ohm < 38U) {
stren_setting = 0x39;
} else if (drvstren_ohm < 41U) {
stren_setting = 0x38;
} else if (drvstren_ohm < 45U) {
stren_setting = 0x1b;
} else if (drvstren_ohm < 50U) {
stren_setting = 0x1a;
} else if (drvstren_ohm < 56U) {
stren_setting = 0x19;
} else if (drvstren_ohm < 64U) {
stren_setting = 0x18;
} else if (drvstren_ohm < 74U) {
stren_setting = 0x0b;
} else if (drvstren_ohm < 88U) {
stren_setting = 0x0a;
} else if (drvstren_ohm < 108U) {
stren_setting = 0x09;
} else if (drvstren_ohm < 140U) {
stren_setting = 0x08;
} else if (drvstren_ohm < 200U) {
stren_setting = 0x03;
} else if (drvstren_ohm < 360U) {
stren_setting = 0x02;
} else if (drvstren_ohm < 481U) {
stren_setting = 0x01;
} else {
stren_setting = 0x00; /* High-impedance */
}
#endif /* STM32MP_DDR3_TYPE */
} else {
/* if ((targetcsr == ADRVSTRENP) || (targetcsr == ADRVSTRENN)) */
if (drvstren_ohm == 120U) {
stren_setting = 0x00;
} else if (drvstren_ohm == 60U) {
stren_setting = 0x01;
} else if (drvstren_ohm == 40U) {
stren_setting = 0x03;
} else if (drvstren_ohm == 30U) {
stren_setting = 0x07;
} else if (drvstren_ohm == 24U) {
stren_setting = 0x0F;
} else if (drvstren_ohm == 20U) {
stren_setting = 0x1F;
} else {
ERROR("%s %d\n", __func__, __LINE__);
VERBOSE("%s userinputadvanced.atximpedance %u Ohms value is not valid.\n",
__func__, drvstren_ohm);
VERBOSE("Valid values are: 20, 24, 30, 40, 60 and 120 Ohms.\n");
}
}
return stren_setting;
}

View file

@ -0,0 +1,893 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <common/debug.h>
#include <ddrphy_phyinit.h>
#include <ddrphy_wrapper.h>
#include <lib/mmio.h>
#include <platform_def.h>
struct phyinit_timings {
int tstaoff;
int tpdm;
int tcasl_add;
};
static struct phyinit_timings timings;
/*
* Program dfimrl according to this formula:
*
* dfimrl = ceiling( (ARdPtrinitval*UI + phy_tx_insertion_dly +
* phy_rx_insertion_dly + PHY_Rx_Fifo_dly + tDQSCK + tstaoff) /
* dficlk_period)
*
* All terms in above equation specified in ps
* tDQSCK - determine from memory model
* tstaoff - determine from memory model
* phy_tx_insertion_dly = 200ps
* phy_rx_insertion_dly = 200ps
* phy_rx_fifo_dly = 200ps + 4UI
*/
static void dfimrl_program(struct stm32mp_ddr_config *config, struct pmu_smb_ddr_1d *mb_ddr_1d,
int ardptrinitval)
{
uint32_t byte;
int dfimrl_in_dficlk;
int phy_rx_fifo_dly;
int phy_rx_insertion_dly = 200;
int phy_tx_insertion_dly = 200;
long long dficlk_period_x1000;
long long dfimrl_in_fs;
long long uifs;
uint16_t dfimrl;
uifs = (1000 * 1000000) / ((int)config->uib.frequency * 2);
dficlk_period_x1000 = 4 * uifs;
phy_rx_fifo_dly = (int)(((200 * 1000) + (4 * uifs)) / 1000);
dfimrl_in_fs = (ardptrinitval * uifs) +
((phy_tx_insertion_dly + phy_rx_insertion_dly + phy_rx_fifo_dly +
timings.tstaoff + timings.tcasl_add + timings.tpdm) * 1000);
dfimrl_in_dficlk = (int)(dfimrl_in_fs / dficlk_period_x1000);
if ((dfimrl_in_fs % dficlk_period_x1000) != 0) {
dfimrl_in_dficlk++;
}
dfimrl = (uint16_t)(dfimrl_in_dficlk + mb_ddr_1d->dfimrlmargin);
/*
* mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TDBYTE | CBRD | CSR_DFIMRL_ADDR))),
* dfimrl);
*/
for (byte = 0U; byte < config->uib.numdbyte; byte++) {
uint32_t c_addr;
c_addr = byte << 12;
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TDBYTE | c_addr |
CSR_DFIMRL_ADDR))),
dfimrl);
}
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_HWTMRL_ADDR))), dfimrl);
}
/*
* Program txdqsdlytg0/1[9:0]:
*
* txdqsdlytg*[9:6] = floor( (4*UI + tstaoff) / UI)
* txdqsdlytg*[5:0] = ceiling( (tstaoff%UI / UI) * 32)
*
* tstaoff and UI expressed in ps
*
* For HMD and LPDDR4X and MEMCLK <= 533 mhz:
* txdqsdlytg*[9:6] = 0x5
*
* For other dimm types, leave TDqsDlyTg*[9:0] at default 0x100
*
* ppp_0001_cccc_uuuu_1101_0000
*
* if DDR3 or DDR4
* num_timingroup = numrank_dfi0;
* else
* num_timingroup = numrank_dfi0 + numrank_dfi1 * dfi1exists;
*/
static void txdqsdlytg_program(struct stm32mp_ddr_config *config, struct pmu_smb_ddr_1d *mb_ddr_1d,
uint16_t *txdqsdly)
{
uint32_t byte;
int txdqsdlytg_5to0; /* Fine delay - 1/32UI per increment */
int txdqsdlytg_9to6; /* Coarse delay - 1UI per increment */
int txdqsdlytg_fine_default = 0;
int txdqsdlytg_coarse_default = 4;
long long tmp_value;
long long uifs;
uifs = (1000 * 1000000) / ((int)config->uib.frequency * 2);
txdqsdlytg_9to6 = (int)(((int)((txdqsdlytg_coarse_default * uifs) / 1000) +
timings.tstaoff + timings.tcasl_add
- timings.tpdm) / (int)(uifs / 1000));
tmp_value = fmodll(((txdqsdlytg_fine_default * uifs / 32) +
((timings.tstaoff + timings.tcasl_add) * 1000) -
(timings.tpdm * 1000)),
uifs);
txdqsdlytg_5to0 = (int)(tmp_value / uifs * 32);
if ((tmp_value % uifs) != 0) {
txdqsdlytg_5to0++;
}
/* Bit-5 of LCDL is no longer used, so bumping bit-5 of fine_dly up to coarse_dly */
if (txdqsdlytg_5to0 >= 32) {
txdqsdlytg_9to6 = txdqsdlytg_9to6 + 1;
txdqsdlytg_5to0 = txdqsdlytg_5to0 - 32;
}
*txdqsdly = (uint16_t)((txdqsdlytg_9to6 << 6) | txdqsdlytg_5to0);
for (byte = 0U; byte < config->uib.numdbyte; byte++) {
uint32_t c_addr;
uint32_t nibble;
c_addr = byte << 12;
for (nibble = 0U; nibble < 2U; nibble++) {
uint32_t u_addr;
if (ddrphy_phyinit_isdbytedisabled(config, mb_ddr_1d, byte) != 0) {
continue;
}
u_addr = nibble << 8;
#if STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE
if ((mb_ddr_1d->cspresent & 0x1U) != 0U) {
#else /* STM32MP_LPDDR4_TYPE */
if (((mb_ddr_1d->cspresentcha & 0x1U) |
(mb_ddr_1d->cspresentchb & 0x1U)) != 0U) {
#endif /* STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE */
mmio_write_16((uintptr_t)
(DDRPHYC_BASE + (4U * (TDBYTE | c_addr | u_addr |
CSR_TXDQSDLYTG0_ADDR))),
*txdqsdly);
}
#if STM32MP_LPDDR4_TYPE
if ((((mb_ddr_1d->cspresentcha & 0x2U) >> 1) |
((mb_ddr_1d->cspresentchb & 0x2U) >> 1)) != 0U) {
mmio_write_16((uintptr_t)
(DDRPHYC_BASE + (4U * (TDBYTE | c_addr | u_addr |
CSR_TXDQSDLYTG1_ADDR))),
*txdqsdly);
}
#endif /* STM32MP_LPDDR4_TYPE */
}
}
}
/*
* ##############################################################
*
* Program txdqdlyTg0/1[8:0]:
*
* txdqdlyTg*[8:6] = floor( (txdqsdlytg*[5:0]*UI/32 + tDQS2DQ + 0.5UI) / UI)
* txdqdlyTg*[5:0] = ceil( ((txdqsdlytg*[5:0]*UI/32 + tDQS2DQ + 0.5UI)%UI / UI) * 32)
*
* ##############################################################
*/
static void txdqdlytg_program(struct stm32mp_ddr_config *config, struct pmu_smb_ddr_1d *mb_ddr_1d,
uint16_t txdqsdly)
{
uint32_t byte;
int txdqdly_5to0; /* Fine delay - 1/32UI per increment */
int txdqdly_8to6; /* Coarse delay - 1UI per increment */
int txdqsdlytg_5to0; /* Fine delay - 1/32UI per increment */
long long tmp_value;
long long uifs;
uint16_t txdqdly;
uifs = (1000 * 1000000) / ((int)config->uib.frequency * 2);
txdqsdlytg_5to0 = (int)txdqsdly & 0x3F;
txdqdly_8to6 = (int)(((txdqsdlytg_5to0 * uifs / 32) + (uifs / 2)) / uifs);
tmp_value = fmodll(((txdqsdlytg_5to0 * uifs / 32) + (uifs / 2)), uifs);
txdqdly_5to0 = (int)(((tmp_value * 32) / uifs));
if ((tmp_value % uifs) != 0) {
txdqdly_5to0++;
}
/* Bit-5 of LCDL is no longer used, so bumping bit-5 of fine_dly up to coarse_dly */
if (txdqdly_5to0 >= 32) {
txdqdly_8to6 = txdqdly_8to6 + 1;
txdqdly_5to0 = txdqdly_5to0 - 32;
}
txdqdly = (uint16_t)((txdqdly_8to6 << 6) | txdqdly_5to0);
for (byte = 0U; byte < config->uib.numdbyte; byte++) {
uint32_t c_addr;
uint32_t lane;
c_addr = byte << 12;
for (lane = 0U; lane < 9U; lane++) {
uint32_t r_addr;
if (ddrphy_phyinit_isdbytedisabled(config, mb_ddr_1d, byte) != 0) {
continue;
}
r_addr = lane << 8;
#if STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE
if ((mb_ddr_1d->cspresent & 0x1U) != 0U) {
#else /* STM32MP_LPDDR4_TYPE */
if (((mb_ddr_1d->cspresentcha & 0x1U) |
(mb_ddr_1d->cspresentchb & 0x1U)) != 0U) {
#endif /* STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE */
mmio_write_16((uintptr_t)
(DDRPHYC_BASE + (4U * (TDBYTE | c_addr | r_addr |
CSR_TXDQDLYTG0_ADDR))),
txdqdly);
}
#if STM32MP_LPDDR4_TYPE
if ((((mb_ddr_1d->cspresentcha & 0x2U) >> 1) |
((mb_ddr_1d->cspresentchb & 0x2U) >> 1)) != 0U) {
mmio_write_16((uintptr_t)
(DDRPHYC_BASE + (4U * (TDBYTE | c_addr | r_addr |
CSR_TXDQDLYTG1_ADDR))),
txdqdly);
}
#endif /* STM32MP_LPDDR4_TYPE */
}
}
}
/*
* Program rxendly0/1[10:0]:
*
* rxendly[10:6] = floor( (4*UI + tDQSCK + tstaoff) / UI)
* rxendly[5:0] = ceil( ((tDQSCK + tstaoff) % UI) * 32)
*
* tDQSCK, tstaoff and UI expressed in ps
*/
static void rxendly_program(struct stm32mp_ddr_config *config, struct pmu_smb_ddr_1d *mb_ddr_1d)
{
int rxendly_coarse_default = 4;
int rxendly_fine_default = 0;
int backoff_x1000 __maybe_unused;
int zerobackoff_x1000 __maybe_unused;
uint32_t byte;
int rxendly_10to6; /* Coarse delay - 1UI per increment */
int rxendly_5to0; /* Fine delay - 1/32UI per increment */
int totfinestep;
long long finestepfs; /* Fine steps in fs */
long long rxendly_offset_x1000000 = 0; /* 0 Offset is 1UI before the first DQS. */
long long totfs;
long long uifs;
uint16_t rxendly;
uifs = (1000 * 1000000) / ((int)config->uib.frequency * 2);
#if STM32MP_LPDDR4_TYPE
/* Compensate for pptenrxenbackoff */
zerobackoff_x1000 = (1000 * 24) / 32;
if (config->uia.lp4rxpreamblemode == 1U) {
backoff_x1000 = 1000 - ((1000 * 2) / 32);
} else {
backoff_x1000 = (1000 * (int)config->uia.rxenbackoff) - ((1000 * 2) / 32);
}
if (config->uia.disableretraining == 0U) {
rxendly_offset_x1000000 = config->uib.frequency < 333U ?
backoff_x1000 * uifs : zerobackoff_x1000 * uifs;
} else {
rxendly_offset_x1000000 = zerobackoff_x1000 * uifs;
}
#endif /* STM32MP_LPDDR4_TYPE */
finestepfs = uifs / 32;
totfs = ((32 * rxendly_coarse_default * finestepfs) +
(rxendly_fine_default * finestepfs) +
((timings.tstaoff + timings.tcasl_add +
timings.tpdm) * 1000) + (rxendly_offset_x1000000 / 1000));
totfinestep = totfs / finestepfs;
rxendly_10to6 = totfinestep / 32;
rxendly_5to0 = fmodi(totfinestep, 32);
/* Bit-5 of LCDL is no longer used, so bumping bit-5 of fine_dly up to coarse_dly */
if (rxendly_5to0 >= 32) {
rxendly_10to6 = rxendly_10to6 + 1;
rxendly_5to0 = rxendly_5to0 - 32;
}
rxendly = (uint16_t)((rxendly_10to6 << 6) | rxendly_5to0);
for (byte = 0U; byte < config->uib.numdbyte; byte++) {
uint32_t c_addr;
uint32_t nibble;
c_addr = byte << 12;
for (nibble = 0U; nibble < 2U; nibble++) {
uint32_t u_addr;
if (ddrphy_phyinit_isdbytedisabled(config, mb_ddr_1d, byte) != 0) {
continue;
}
u_addr = nibble << 8;
#if STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE
if ((mb_ddr_1d->cspresent & 0x1U) != 0) {
#else /* STM32MP_LPDDR4_TYPE */
if (((mb_ddr_1d->cspresentcha & 0x1U) |
(mb_ddr_1d->cspresentchb & 0x1U)) != 0U) {
#endif /* STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE */
mmio_write_16((uintptr_t)
(DDRPHYC_BASE + (4U * (TDBYTE | c_addr | u_addr |
CSR_RXENDLYTG0_ADDR))),
rxendly);
}
#if STM32MP_LPDDR4_TYPE
if ((((mb_ddr_1d->cspresentcha & 0x2U) >> 1) |
((mb_ddr_1d->cspresentchb & 0x2U) >> 1)) != 0U) {
mmio_write_16((uintptr_t)
(DDRPHYC_BASE + (4U * (TDBYTE | c_addr | u_addr |
CSR_RXENDLYTG1_ADDR))),
rxendly);
}
#endif /* STM32MP_LPDDR4_TYPE */
}
}
}
#if STM32MP_LPDDR4_TYPE
/*
* Programming Seq0BGPR1/2/3 for LPDDR4
*/
static void seq0bgpr_program(struct stm32mp_ddr_config *config)
{
uint32_t extradly = 3U;
uint32_t rl = 0U; /* Computed read latency */
uint32_t wl = 0U; /* Computed write latency */
uint16_t mr_dbi_rd; /* Extracted field from MR */
uint16_t mr_rl;
uint16_t mr_wl;
uint16_t mr_wls;
uint16_t regdata;
mr_rl = (uint16_t)config->uia.lp4rl; /* RL[2:0] */
mr_wl = (uint16_t)config->uia.lp4wl; /* WL[5:3] */
mr_wls = (uint16_t)config->uia.lp4wls; /* WLS */
mr_dbi_rd = (uint16_t)config->uia.lp4dbird; /* DBI-RD */
switch ((mr_dbi_rd << 3) | mr_rl) {
/* DBI-RD Disabled */
case 0U:
rl = 6U;
break;
case 1U:
rl = 10U;
break;
case 2U:
rl = 14U;
break;
case 3U:
rl = 20U;
break;
case 4U:
rl = 24U;
break;
case 5U:
rl = 28U;
break;
case 6U:
rl = 32U;
break;
case 7U:
rl = 36U;
break;
/* DBI-RD Enabled */
case 8U:
rl = 6U;
break;
case 9U:
rl = 12U;
break;
case 10U:
rl = 16U;
break;
case 11U:
rl = 22U;
break;
case 12U:
rl = 28U;
break;
case 13U:
rl = 32U;
break;
case 14U:
rl = 36U;
break;
case 15U:
rl = 40U;
break;
default:
rl = 6U;
break;
}
switch ((mr_wls << 3) | mr_wl) {
/* DBI-RD Disabled */
case 0U:
wl = 4U;
break;
case 1U:
wl = 6U;
break;
case 2U:
wl = 8U;
break;
case 3U:
wl = 10U;
break;
case 4U:
wl = 12U;
break;
case 5U:
wl = 14U;
break;
case 6U:
wl = 16U;
break;
case 7U:
wl = 18U;
break;
/* DBI-RD Enabled */
case 8U:
wl = 4U;
break;
case 9U:
wl = 8U;
break;
case 10U:
wl = 12U;
break;
case 11U:
wl = 18U;
break;
case 12U:
wl = 22U;
break;
case 13U:
wl = 26U;
break;
case 14U:
wl = 30U;
break;
case 15U:
wl = 34U;
break;
default:
wl = 4U;
break;
}
/* Program Seq0b_GPRx */
regdata = (uint16_t)((rl - 5U + extradly) << CSR_ACSMRCASLAT_LSB);
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (P0 | C0 | TINITENG | R2 |
CSR_SEQ0BGPR1_ADDR))),
regdata);
regdata = (uint16_t)((wl - 5U + extradly) << CSR_ACSMWCASLAT_LSB);
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (P0 | C0 | TINITENG | R2 |
CSR_SEQ0BGPR2_ADDR))),
regdata);
regdata = (uint16_t)((rl - 5U + extradly + 4U + 8U) << CSR_ACSMRCASLAT_LSB);
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (P0 | C0 | TINITENG | R2 |
CSR_SEQ0BGPR3_ADDR))),
regdata);
}
/*
* Program hwtlpcsena and hwtlpcsenb based on number of ranks per channel
* Applicable only for LPDDR4. These CSRs have no effect for DDR3/4.
*
* CSRs to program:
* hwtlpcsena
* hwtlpcsenb
*
* User input dependencies:
* config->uib.numrank_dfi0
* config->uib.numrank_dfi1
* config->uib.dfi1exists
* config->uib.numactivedbytedfi1
*/
static void hwtlpcsen_program(struct stm32mp_ddr_config *config)
{
uint16_t hwtlpcsena;
uint16_t hwtlpcsenb;
/* Channel A - 1'b01 if signal-rank, 2'b11 if dual-rank */
hwtlpcsena = (uint16_t)config->uib.numrank_dfi0 | 0x1U;
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_HWTLPCSENA_ADDR))),
hwtlpcsena);
/*
* Channel B - 1'b01 if signal-rank, 2'b11 if dual-rank
* If DFI1 exists but disabled, numrank_dfi0 is used to program CsEnB
*/
if ((config->uib.dfi1exists != 0U) && (config->uib.numactivedbytedfi1 == 0U)) {
hwtlpcsenb = (uint16_t)config->uib.numrank_dfi0 | 0x1U;
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_HWTLPCSENB_ADDR))),
hwtlpcsenb);
} else if ((config->uib.dfi1exists != 0U) && (config->uib.numactivedbytedfi1 > 0U)) {
hwtlpcsenb = (uint16_t)config->uib.numrank_dfi1 | 0x1U;
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_HWTLPCSENB_ADDR))),
hwtlpcsenb);
} else {
/* Disable Channel B */
hwtlpcsenb = 0x0U;
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_HWTLPCSENB_ADDR))),
hwtlpcsenb);
}
}
/*
* Program pptdqscntinvtrntg0 and pptdqscntinvtrntg1
* Calculated based on tDQS2DQ and Frequencey
* Applicable to LPDDR4 only
*
* 65536*(tdqs2dq_value_rank<rank>_chan<chan>*2)/(2*2048*UI(ps)_int)
*
* CSRs to program:
* pptdqscntinvtrntg0
* pptdqscntinvtrntg1
*
* User input dependencies:
* config->uib.numrank_dfi0
* config->uib.numrank_dfi1
* config->uib.dfi1exists
* config->uib.numdbyte
*/
static void pptdqscntinvtrntg_program(struct stm32mp_ddr_config *config)
{
uint32_t numrank_total = config->uib.numrank_dfi0;
uint32_t rank;
/* Calculate total number of timing groups (ranks) */
if (config->uib.dfi1exists != 0U) {
numrank_total += config->uib.numrank_dfi1;
}
/* Set per timing group */
for (rank = 0U; rank < numrank_total; rank++) {
uint32_t byte;
for (byte = 0U; byte < config->uib.numdbyte; byte++) {
uint32_t c_addr;
c_addr = byte << 12;
if (rank == 0U) {
mmio_write_16((uintptr_t)
(DDRPHYC_BASE + (4U * (TDBYTE | c_addr |
CSR_PPTDQSCNTINVTRNTG0_ADDR))),
0U);
} else if (rank == 1U) {
mmio_write_16((uintptr_t)
(DDRPHYC_BASE + (4U * (TDBYTE | c_addr |
CSR_PPTDQSCNTINVTRNTG1_ADDR))),
0U);
}
}
}
}
/*
* CSRs to program:
* PptCtlStatic:: DOCByteSelTg0/1
* :: pptenrxenbackoff
*
* User input dependencies::
* config->uib.numdbyte
* config->uib.numrank_dfi0
* config->uib.numrank_dfi1
* config->uia.lp4rxpreamblemode
* config->uia.rxenbackoff
* config->uia.drambyteswap
*/
static void pptctlstatic_program(struct stm32mp_ddr_config *config)
{
uint32_t byte;
uint32_t pptenrxenbackoff;
/*
* The customer will setup some fields in this csr so the fw needs to do a
* read-modify-write here.
*/
if (config->uia.lp4rxpreamblemode == 1U) {
/* Rx-preamble mode for PS0 */
/* Programming PptCtlStatic detected toggling preamble */
pptenrxenbackoff = 0x1U; /* Toggling RD_PRE */
} else {
pptenrxenbackoff = config->uia.rxenbackoff; /* Static RD_PRE */
}
for (byte = 0U; byte < config->uib.numdbyte; byte++) {
uint32_t c_addr;
uint16_t regdata;
uint8_t pptentg1;
uint32_t docbytetg0;
uint32_t docbytetg1;
/* Each Dbyte could have a different configuration */
c_addr = byte * C1;
if ((byte % 2) == 0) {
docbytetg0 = 0x1U & (config->uia.drambyteswap >> byte);
docbytetg1 = 0x1U & (config->uia.drambyteswap >> byte);
} else {
docbytetg0 = 0x1U & (~(config->uia.drambyteswap >> byte));
docbytetg1 = 0x1U & (~(config->uia.drambyteswap >> byte));
}
pptentg1 = ((config->uib.numrank_dfi0 == 2U) || (config->uib.numrank_dfi1 == 2U)) ?
0x1U : 0x0U;
regdata = (uint16_t)((0x1U << CSR_PPTENDQS2DQTG0_LSB) |
(pptentg1 << CSR_PPTENDQS2DQTG1_LSB) |
(0x1U << CSR_PPTENRXENDLYTG0_LSB) |
(pptentg1 << CSR_PPTENRXENDLYTG1_LSB) |
(pptenrxenbackoff << CSR_PPTENRXENBACKOFF_LSB) |
(docbytetg0 << CSR_DOCBYTESELTG0_LSB) |
(docbytetg1 << CSR_DOCBYTESELTG1_LSB));
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (c_addr | TDBYTE |
CSR_PPTCTLSTATIC_ADDR))),
regdata);
}
}
#endif /* STM32MP_LPDDR4_TYPE */
/*
* Program hwtcamode based on dram type
*
* CSRs to program:
* hwtcamode::hwtlp3camode
* ::hwtd4camode
* ::hwtlp4camode
* ::hwtd4altcamode
* ::hwtcsinvert
* ::hwtdbiinvert
*/
static void hwtcamode_program(void)
{
uint32_t hwtlp3camode = 0U;
uint32_t hwtd4camode = 0U;
uint32_t hwtlp4camode = 0U;
uint32_t hwtd4altcamode = 0U;
uint32_t hwtcsinvert = 0U;
uint32_t hwtdbiinvert = 0U;
uint16_t hwtcamode;
#if STM32MP_DDR4_TYPE
hwtd4camode = 1U;
#elif STM32MP_LPDDR4_TYPE
hwtlp4camode = 1U;
hwtcsinvert = 1U;
hwtdbiinvert = 1U;
#else /* STM32MP_DDR3_TYPE */
/* Nothing to declare */
#endif /* STM32MP_DDR4_TYPE */
hwtcamode = (uint16_t)((hwtdbiinvert << CSR_HWTDBIINVERT_LSB) |
(hwtcsinvert << CSR_HWTCSINVERT_LSB) |
(hwtd4altcamode << CSR_HWTD4ALTCAMODE_LSB) |
(hwtlp4camode << CSR_HWTLP4CAMODE_LSB) |
(hwtd4camode << CSR_HWTD4CAMODE_LSB) |
(hwtlp3camode << CSR_HWTLP3CAMODE_LSB));
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_HWTCAMODE_ADDR))), hwtcamode);
}
/*
* Program DllGainCtl and DllLockParam based on frequency
*/
static void dllgainctl_dlllockparam_program(struct stm32mp_ddr_config *config)
{
uint32_t dllgainiv;
uint32_t dllgaintv;
uint32_t lcdlseed;
uint32_t memck_freq;
uint32_t stepsize_x10 = 47U; /*
* Nominal stepsize, in units of tenths of a ps,
* if nominal=4.7ps use 47
*/
uint16_t wddllgainctl;
uint16_t wddlllockparam;
memck_freq = config->uib.frequency;
/*
* lcdlseed = ((1000000/memck_freq)/2)/lcdl_stepsize ...
* where default lcdl_stepsize=4.7 in simulation.
*/
if (memck_freq >= 1200U) {
dllgainiv = 0x04U;
dllgaintv = 0x05U;
} else if (memck_freq >= 800U) {
dllgainiv = 0x03U;
dllgaintv = 0x05U;
} else if (memck_freq >= 532U) {
dllgainiv = 0x02U;
dllgaintv = 0x04U;
} else if (memck_freq >= 332U) {
dllgainiv = 0x01U;
dllgaintv = 0x03U;
} else {
dllgainiv = 0x00U;
dllgaintv = 0x02U;
}
/*
* lcdlseed= (1000000/(2*memck_freq)) * (100/(120*(stepsize_nominal)));
* *100/105 is to bias the seed low.
*/
lcdlseed = (1000000U * 10U * 100U) / (2U * memck_freq * stepsize_x10 * 105U);
if (lcdlseed > (511U - 32U)) {
lcdlseed = 511U - 32U;
}
if (lcdlseed < 32U) {
lcdlseed = 32U;
}
wddllgainctl = (uint16_t)((CSR_DLLGAINTV_MASK & (dllgaintv << CSR_DLLGAINTV_LSB)) |
(CSR_DLLGAINIV_MASK & (dllgainiv << CSR_DLLGAINIV_LSB)));
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_DLLGAINCTL_ADDR))),
wddllgainctl);
wddlllockparam = (uint16_t)((CSR_LCDLSEED0_MASK & (lcdlseed << CSR_LCDLSEED0_LSB)) |
(CSR_DISDLLGAINIVSEED_MASK & 0xFFFFU));
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_DLLLOCKPARAM_ADDR))),
wddlllockparam);
}
/*
* Program AcsmCtrl23 for Fw and Ppt.
*
* CSRs to program:
* AcsmCtrl23::AcsmCsMask
* AcsmCsMode
*/
static void acsmctrl23_program(void)
{
uint16_t regdata;
regdata = (0x0FU << CSR_ACSMCSMASK_LSB) | (0x1U << CSR_ACSMCSMODE_LSB);
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (C0 | TACSM | CSR_ACSMCTRL23_ADDR))),
regdata);
}
/*
* Set PllForceCal to 1 and PllDacValIn to some arbitrary value
*/
static void pllforcecal_plldacvalin_program(void)
{
uint32_t dacval_in = 0x10U;
uint32_t force_cal = 0x1U;
uint32_t pllencal = 0x1U;
uint32_t maxrange = 0x1FU;
uint16_t pllctrl3_gpr;
uint16_t pllctrl3_startup;
pllctrl3_startup = (uint16_t)((dacval_in << CSR_PLLDACVALIN_LSB) |
(maxrange << CSR_PLLMAXRANGE_LSB));
pllctrl3_gpr = pllctrl3_startup | (uint16_t)((force_cal << CSR_PLLFORCECAL_LSB) |
(pllencal << CSR_PLLENCAL_LSB));
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_PLLCTRL3_ADDR))),
pllctrl3_startup);
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TINITENG | CSR_SEQ0BGPR6_ADDR))),
pllctrl3_gpr);
}
/*
* This function programs registers that are normally set by training
* firmware.
*
* This function is used in place of running 1D or 1D training steps. PhyInit
* calls this function when skip_train = true. In that case, PhyInit does not
* execute training firmware and this function is called instead to program
* PHY registers according to DRAM timing parameters specified in userInput
* data structure. See documentation of ddrphy_phyinit_struct.h file
* details of timing parameters available in skip training.
*
* \warning ddrphy_phyinit_progcsrskiptrain() only supports zero board
* delay model. If system board delays are set or randomized, full 1D or 1D
* initialization flow must be executed.
*
* This function replaces these steps in the PHY Initialization sequence:
* - (E) Set the PHY input clocks to the desired frequency
* - (F) Write the Message Block parameters for the training firmware
* - (G) Execute the Training Firmware
* - (H) Read the Message Block results
*
* \returns \c void
*/
void ddrphy_phyinit_progcsrskiptrain(struct stm32mp_ddr_config *config,
struct pmu_smb_ddr_1d *mb_ddr_1d, uint32_t ardptrinitval)
{
uint16_t txdqsdly;
/*
* Program ATxDlY
* For DDR4, DDR3 and LPDDR4, leave AtxDly[6:0] at default (0x0)
*/
dfimrl_program(config, mb_ddr_1d, ardptrinitval);
txdqsdlytg_program(config, mb_ddr_1d, &txdqsdly);
txdqdlytg_program(config, mb_ddr_1d, txdqsdly);
rxendly_program(config, mb_ddr_1d);
#if STM32MP_LPDDR4_TYPE
seq0bgpr_program(config);
hwtlpcsen_program(config);
pptdqscntinvtrntg_program(config);
pptctlstatic_program(config);
#endif /* STM32MP_LPDDR4_TYPE */
hwtcamode_program();
dllgainctl_dlllockparam_program(config);
acsmctrl23_program();
pllforcecal_plldacvalin_program();
/*
* ##############################################################
*
* Setting PhyInLP3 to 0 to cause PIE to execute LP2 sequence instead of INIT on first
* dfi_init_start.
* This prevents any DRAM commands before DRAM is initialized, which is the case for
* skip_train.
*
* Moved to here from dddrphy_phyinit_I_loadPIEImage()
* These should not be needed on S3-exit
*
* Note this executes for SkipTrain only, *not* DevInit+SkipTrain
* DevInit+SkipTrain already initializes DRAM and thus don't need to avoid DRAM commands
*
* ##############################################################
*/
/*
* Special skipTraining configuration to Prevent DRAM Commands on the first dfi
* status interface handshake. In order to see this behavior, the first dfi_freq
* should be in the range of 0x0f < dfi_freq_sel[4:0] < 0x14.
*/
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TINITENG | CSR_PHYINLP3_ADDR))), 0x0U);
}

View file

@ -0,0 +1,170 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* This file provides a group of functions that are used to track PHY register
* writes by intercepting io_write16 function calls. Once the registers are
* tracked, their value can be saved at a given time spot, and restored later
* as required. This implementation is useful to capture any PHY register
* programing in any function during PHY initialization.
*/
#include <stdint.h>
#include <common/debug.h>
#include <ddrphy_phyinit.h>
#include <lib/mmio.h>
#include <platform_def.h>
/*
* MAX_NUM_RET_REGS default Max number of retention registers.
*
* This define is only used by the PhyInit Register interface to define the max
* amount of registered that can be saved. The user may increase this variable
* as desired if a larger number of registers need to be restored.
*/
#if STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE
#define MAX_NUM_RET_REGS 129
#else /* STM32MP_LPDDR4_TYPE */
#define MAX_NUM_RET_REGS 283
#endif /* STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE */
/*
* Array of Address/value pairs used to store register values for the purpose
* of retention restore.
*/
#define RETREG_AREA (MAX_NUM_RET_REGS + 1) * sizeof(struct reg_addr_val)
#define RETREG_BASE RETRAM_BASE + RETRAM_SIZE - RETREG_AREA
static int *retregsize = (int *)(RETREG_BASE);
static struct reg_addr_val *retreglist = (struct reg_addr_val *)(RETREG_BASE + sizeof(int));
static int numregsaved; /* Current Number of registers saved. */
static int tracken = 1; /* Enabled tracking of registers */
/*
* Tags a register if tracking is enabled in the register
* interface.
*
* During PhyInit registers writes, keeps track of address
* for the purpose of restoring the PHY register state during PHY
* retention exit process. Tracking can be turned on/off via the
* ddrphy_phyinit_reginterface STARTTRACK, STOPTRACK instructions. By
* default tracking is always turned on.
*
* \return 0 on success.
*/
int ddrphy_phyinit_trackreg(uint32_t adr)
{
int regindx = 0;
/* Return if tracking is disabled */
if (tracken == 0) {
return 0;
}
/* Search register address within the array */
for (regindx = 0; regindx < numregsaved; regindx++) {
if (retreglist[regindx].address == adr) {
/* Register found */
return 0;
}
}
/* Register not found, so add it */
if (numregsaved > MAX_NUM_RET_REGS) {
ERROR("numregsaved > MAX_NUM_RET_REGS\n");
VERBOSE("[ddrphy_phyinit_reginterface:%s]\n", __func__);
VERBOSE("Max Number of Restore Registers reached: %d.\n", numregsaved);
VERBOSE("Please recompile PhyInit with larger MAX_NUM_RET_REG value.\n");
return -1;
}
retreglist[regindx].address = adr;
numregsaved++;
return 0;
}
/*
* Register interface function used to track, save and restore retention registers.
*
* ### Usage
* Register tracking is enabled by calling:
*
* \code
* ddrphy_phyinit_reginterface(STARTTRACK,0,0);
* \endcode
*
* from this point on any call to mmio_write_16() in
* return will be capture by the register interface via a call to
* ddrphy_phyinit_trackreg(). Tracking is disabled by calling:
*
* \code
* ddrphy_phyinit_reginterface(STOPTRACK,0,0);
* \endcode
*
* On calling this function, register write via mmio_write_16 are no longer tracked until a
* STARTTRACK call is made. Once all the register write are complete, SAVEREGS
* command can be issue to save register values into the internal data array of
* the register interface. Upon retention exit RESTOREREGS are command can be
* used to issue register write commands to the PHY based on values stored in
* the array.
* \code
* ddrphy_phyinit_reginterface(SAVEREGS,0,0);
* ddrphy_phyinit_reginterface(RESTOREREGS,0,0);
* \endcode
* \return 0 on success.
*/
int ddrphy_phyinit_reginterface(enum reginstr myreginstr, uint32_t adr, uint16_t dat)
{
if (myreginstr == SAVEREGS) {
int regindx;
/*
* Go through all the tracked registers, issue a register read and place
* the result in the data structure for future recovery.
*/
for (regindx = 0; regindx < numregsaved; regindx++) {
uint16_t data;
data = mmio_read_16((uintptr_t)(DDRPHYC_BASE +
(4U * retreglist[regindx].address)));
retreglist[regindx].value = data;
}
*retregsize = numregsaved;
return 0;
} else if (myreginstr == RESTOREREGS) {
int regindx;
/*
* Write PHY registers based on Address, Data value pairs stores in
* retreglist.
*/
for (regindx = 0; regindx < *retregsize; regindx++) {
mmio_write_16((uintptr_t)
(DDRPHYC_BASE + (4U * retreglist[regindx].address)),
retreglist[regindx].value);
}
return 0;
} else if (myreginstr == STARTTRACK) {
/* Enable tracking */
tracken = 1;
return 0;
} else if (myreginstr == STOPTRACK) {
/* Disable tracking */
tracken = 0;
return 0;
} else {
return -1;
}
}

View file

@ -0,0 +1,78 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
#include <ddrphy_phyinit.h>
#include <lib/mmio.h>
#include <platform_def.h>
/*
* This function implements the register restore portion of S3/IO
* retention sequence.
*
* \note This function requiers the runtime_config.reten=1 to enable PhyInit exit retention feature.
* This variable can be set as in
* \return 0 on completion of the sequence, EXIT_FAILURE on error.
*/
int ddrphy_phyinit_restore_sequence(void)
{
int ret;
/*
* Before you call this functions perform the following:
* --------------------------------------------------------------------------
* -# Bring up VDD, VDDQ should already be up
* -# Since the CKE* and MEMRESET pin state must be protected, special care
* must be taken to ensure that the following signals
* - atpg_mode = 1'b0
* - PwrOkIn = 1'b0
*
* -# The {BypassModeEn*, WRSTN} signals may be defined at VDD power-on, but
* must be driven to ZERO at least 10ns prior to the asserting edge of PwrOkIn.
*
* -# Start Clocks and Reset the PHY
* This step is identical to ddrphy_phyinit_usercustom_b_startclockresetphy()
*/
/* Write the MicroContMuxSel CSR to 0x0 to allow access to the internal CSRs */
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TAPBONLY | CSR_MICROCONTMUXSEL_ADDR))),
0x0U);
/*
* Write the UcclkHclkEnables CSR to 0x3 to enable all the clocks so the reads can
* complete.
*/
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TDRTUB | CSR_UCCLKHCLKENABLES_ADDR))),
0x3U);
/*
* Assert CalZap to force impedance calibration FSM to idle.
* De-asserted as part of dfi_init_start/complete handshake by the PIE when DfiClk is valid.
*/
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_CALZAP_ADDR))), 0x1U);
/* Issue register writes to restore registers values */
ret = ddrphy_phyinit_reginterface(RESTOREREGS, 0U, 0U);
if (ret != 0) {
return ret;
}
/*
* Write the UcclkHclkEnables CSR to disable the appropriate clocks after all reads done.
* Disabling Ucclk (PMU) and Hclk (training hardware).
*/
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TDRTUB | CSR_UCCLKHCLKENABLES_ADDR))),
0x0U);
/* Write the MicroContMuxSel CSR to 0x1 to isolate the internal CSRs during mission mode */
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TAPBONLY | CSR_MICROCONTMUXSEL_ADDR))),
0x1U);
return 0;
}

View file

@ -0,0 +1,121 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <common/debug.h>
#include <ddrphy_phyinit.h>
/*
* This function implements the flow of PhyInit software to initialize the PHY.
*
* The execution sequence follows the overview figure provided in the Reference Manual.
*
* \returns 0 on completion of the sequence, EXIT_FAILURE on error.
*/
int ddrphy_phyinit_sequence(struct stm32mp_ddr_config *config, bool skip_training, bool reten)
{
int ret;
uint32_t ardptrinitval; /*
* Represents the value stored in Step C into the register with the
* same name. Defined as a global variable so that implementation
* of ddrphy_phyinit_progcsrskiptrain() function does not require
* a PHY read register implementation.
*/
struct pmu_smb_ddr_1d mb_ddr_1d; /* Firmware 1D Message Block structure */
/* Check user input pstate number consistency vs. SW capabilities */
if (config->uib.numpstates > 1U) {
return -1;
}
/* Initialize structures */
ddrphy_phyinit_initstruct(config, &mb_ddr_1d);
/* Re-calculate Firmware Message Block input based on final user input */
ret = ddrphy_phyinit_calcmb(config, &mb_ddr_1d);
if (ret != 0) {
return ret;
}
/* (A) Bring up VDD, VDDQ, and VAA */
/* ddrphy_phyinit_usercustom_a_bringuppower(); */
/* (B) Start Clocks and Reset the PHY */
/* ddrphy_phyinit_usercustom_b_startclockresetphy(); */
/* (C) Initialize PHY Configuration */
ret = ddrphy_phyinit_c_initphyconfig(config, &mb_ddr_1d, &ardptrinitval);
if (ret != 0) {
return ret;
}
/*
* Customize any register write desired; This can include any CSR not covered by PhyInit
* or user wish to override values calculated in step_C.
*/
ddrphy_phyinit_usercustom_custompretrain(config);
/* Stop retention register tracking for training firmware related registers */
ret = ddrphy_phyinit_reginterface(STOPTRACK, 0U, 0U);
if (ret != 0) {
return ret;
}
if (skip_training) {
/* Skip running training firmware entirely */
ddrphy_phyinit_progcsrskiptrain(config, &mb_ddr_1d, ardptrinitval);
} else {
/* (D) Load the IMEM Memory for 1D training */
ddrphy_phyinit_d_loadimem();
/* (E) Set the PHY input clocks to the desired frequency */
/* ddrphy_phyinit_usercustom_e_setdficlk(pstate); */
/* (F) Write the Message Block parameters for the training firmware */
ret = ddrphy_phyinit_f_loaddmem(config, &mb_ddr_1d);
if (ret != 0) {
return ret;
}
/* (G) Execute the Training Firmware */
ret = ddrphy_phyinit_g_execfw();
if (ret != 0) {
return ret;
}
/* (H) Read the Message Block results */
/* ddrphy_phyinit_h_readmsgblock(); */
}
/* Start retention register tracking for training firmware related registers */
ret = ddrphy_phyinit_reginterface(STARTTRACK, 0U, 0U);
if (ret != 0) {
return ret;
}
/* (I) Load PHY Init Engine Image */
ddrphy_phyinit_i_loadpieimage(config, skip_training);
/*
* Customize any CSR write desired to override values programmed by firmware or
* ddrphy_phyinit_i_loadpieimage()
*/
/* ddrphy_phyinit_usercustom_customposttrain(); */
if (reten) {
/* Save value of tracked registers for retention restore sequence. */
ret = ddrphy_phyinit_usercustom_saveretregs(config);
if (ret != 0) {
return ret;
}
}
/* (J) Initialize the PHY to Mission Mode through DFI Initialization */
/* ddrphy_phyinit_usercustom_j_entermissionmode(); */
return 0;
}

View file

@ -0,0 +1,100 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <string.h>
#include <common/debug.h>
#include <ddrphy_phyinit.h>
/*
* Set messageBlock variable only if not set by user
*
* This function is used by ddrphy_phyinit_calcmb() to set calculated
* messageBlock variables only when the user has not directly programmed them.
*
* @param[in] field A string representing the messageBlock field to be programed.
* @param[in] value filed value
*
* @return 0 on success.
* On error returns the following values based on error:
* - -1 : message block field specified by the input \c field string is not
* found in the message block data structure.
*/
int ddrphy_phyinit_softsetmb(struct pmu_smb_ddr_1d *mb_ddr_1d, enum message_block_field field,
uint32_t value)
{
int ret = 0;
if (field == MB_FIELD_DRAMFREQ) {
assert(value <= UINT16_MAX);
} else {
assert(value <= UINT8_MAX);
}
switch (field) {
case MB_FIELD_PSTATE:
mb_ddr_1d->pstate = (uint8_t)value;
break;
case MB_FIELD_PLLBYPASSEN:
mb_ddr_1d->pllbypassen = (uint8_t)value;
break;
case MB_FIELD_DRAMFREQ:
mb_ddr_1d->dramfreq = (uint16_t)value;
break;
case MB_FIELD_DFIFREQRATIO:
mb_ddr_1d->dfifreqratio = (uint8_t)value;
break;
case MB_FIELD_BPZNRESVAL:
mb_ddr_1d->bpznresval = (uint8_t)value;
break;
case MB_FIELD_PHYODTIMPEDANCE:
mb_ddr_1d->phyodtimpedance = (uint8_t)value;
break;
case MB_FIELD_PHYDRVIMPEDANCE:
mb_ddr_1d->phydrvimpedance = (uint8_t)value;
break;
#if STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE
case MB_FIELD_DRAMTYPE:
mb_ddr_1d->dramtype = (uint8_t)value;
break;
case MB_FIELD_DISABLEDDBYTE:
mb_ddr_1d->disableddbyte = (uint8_t)value;
break;
case MB_FIELD_ENABLEDDQS:
mb_ddr_1d->enableddqs = (uint8_t)value;
break;
case MB_FIELD_PHYCFG:
mb_ddr_1d->phycfg = (uint8_t)value;
break;
#if STM32MP_DDR4_TYPE
case MB_FIELD_X16PRESENT:
mb_ddr_1d->x16present = (uint8_t)value;
break;
#endif /* STM32MP_DDR4_TYPE */
#else /* STM32MP_LPDDR4_TYPE */
case MB_FIELD_ENABLEDDQSCHA:
mb_ddr_1d->enableddqscha = (uint8_t)value;
break;
case MB_FIELD_CSPRESENTCHA:
mb_ddr_1d->cspresentcha = (uint8_t)value;
break;
case MB_FIELD_ENABLEDDQSCHB:
mb_ddr_1d->enableddqschb = (uint8_t)value;
break;
case MB_FIELD_CSPRESENTCHB:
mb_ddr_1d->cspresentchb = (uint8_t)value;
break;
#endif /* STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE */
default:
ERROR("unknown message block field %u\n", field);
ret = -1;
break;
}
return ret;
}

View file

@ -0,0 +1,79 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <common/debug.h>
#include <ddrphy_phyinit.h>
#include <lib/mmio.h>
#include <platform_def.h>
/*
* Writes local memory content into the SRAM via APB interface.
*
* This function issued APB writes commands to SRAM address based on values
* stored in a local PhyInit array that contains consolidated IMEM and DMEM
* data.
* @param[in] mem[] Local memory array.
* @param[in] mem_offset offset index. if provided, skips to the offset index
* from the local array and issues APB commands from mem_offset to mem_size.
* @param[in] mem_size size of the memroy (in mem array index)
* @returns void
*/
void ddrphy_phyinit_writeoutmem(uint32_t *mem, uint32_t mem_offset, uint32_t mem_size)
{
uint32_t index;
/*
* 1. Enable access to the internal CSRs by setting the MicroContMuxSel CSR to 0.
* This allows the memory controller unrestricted access to the configuration CSRs.
*/
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TAPBONLY | CSR_MICROCONTMUXSEL_ADDR))),
0x0U);
for (index = 0U; index < mem_size / sizeof(uint32_t); index++) {
uint32_t data = mem[index];
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * ((index * 2) + mem_offset))),
data & 0xFFFFU);
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * ((index * 2) + 1 + mem_offset))),
(data >> 16) & 0xFFFFU);
}
/*
* 2. Isolate the APB access from the internal CSRs by setting the MicroContMuxSel CSR to 1.
* This allows the firmware unrestricted access to the configuration CSRs.
*/
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TAPBONLY | CSR_MICROCONTMUXSEL_ADDR))),
0x1U);
}
/* Similar function for message block */
void ddrphy_phyinit_writeoutmsgblk(uint16_t *mem, uint32_t mem_offset, uint32_t mem_size)
{
uint32_t index;
/*
* 1. Enable access to the internal CSRs by setting the MicroContMuxSel CSR to 0.
* This allows the memory controller unrestricted access to the configuration CSRs.
*/
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TAPBONLY | CSR_MICROCONTMUXSEL_ADDR))),
0x0U);
for (index = 0U; index < mem_size / sizeof(uint16_t); index++) {
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (index + mem_offset))), mem[index]);
}
/*
* 2. Isolate the APB access from the internal CSRs by setting the MicroContMuxSel CSR to 1.
* This allows the firmware unrestricted access to the configuration CSRs.
*/
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TAPBONLY | CSR_MICROCONTMUXSEL_ADDR))),
0x1U);
}

View file

@ -0,0 +1,90 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <stdlib.h>
#include <common/debug.h>
#include <ddrphy_phyinit.h>
#include <lib/mmio.h>
#include <platform_def.h>
/* DDRDBG registers */
#define DDRDBG_DDR34_AC_SWIZZLE_ADD3_0 U(0x100)
/*
* This function is called before training firmware is executed. Any
* register override in this function might affect the firmware training
* results.
*
* This function is executed before firmware execution loop. Thus this function
* should be used only for the following:
*
* - Override PHY register values written by
* ddrphy_phyinit_c_initphyconfig. An example use case is when this
* function does not perform the exact programing desired by the user.
* - Write custom PHY registers that need to take effect before training
* firmware execution.
*
* User shall use mmio_write_16 to write PHY registers in order for the register
* to be tracked by PhyInit for retention restore.
*
* To override settings in the message block, users can assign values to the
* fields in the message block data structure directly.
*
* \ref examples/simple/ddrphy_phyinit_usercustom_custompretrain.c example of this function.
*
* @return Void
*/
void ddrphy_phyinit_usercustom_custompretrain(struct stm32mp_ddr_config *config)
{
uint32_t byte __unused;
uint32_t i = 0U;
uint32_t j;
uintptr_t base;
#if STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE
base = (uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_HWTSWIZZLEHWTADDRESS0_ADDR)));
for (i = 0U; i < NB_HWT_SWIZZLE; i++) {
mmio_write_16(base + (i * sizeof(uint32_t)),
(uint16_t)config->uis.swizzle[i]);
}
base = (uintptr_t)(stm32_ddrdbg_get_base() + DDRDBG_DDR34_AC_SWIZZLE_ADD3_0);
for (j = 0U; j < NB_AC_SWIZZLE; j++, i++) {
mmio_write_32(base + (j * sizeof(uint32_t)), config->uis.swizzle[i]);
}
#else /* STM32MP_LPDDR4_TYPE */
for (byte = 0U; byte < config->uib.numdbyte; byte++) {
base = (uintptr_t)(DDRPHYC_BASE + (4U *
((byte << 12) | TDBYTE | CSR_DQ0LNSEL_ADDR)));
for (j = 0U; j < NB_DQLNSEL_SWIZZLE_PER_BYTE; j++, i++) {
mmio_write_16(base + (j * sizeof(uint32_t)),
(uint16_t)config->uis.swizzle[i]);
}
}
base = (uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_MAPCAA0TODFI_ADDR)));
for (j = 0U; j < NB_MAPCAATODFI_SWIZZLE; j++, i++) {
mmio_write_16(base + (j * sizeof(uint32_t)),
(uint16_t)config->uis.swizzle[i]);
}
base = (uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_MAPCAB0TODFI_ADDR)));
for (j = 0U; j < NB_MAPCABTODFI_SWIZZLE; j++, i++) {
mmio_write_16(base + (j * sizeof(uint32_t)),
(uint16_t)config->uis.swizzle[i]);
}
#endif /* STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE */
}

View file

@ -0,0 +1,183 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
#include <ddrphy_phyinit.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <platform_def.h>
/* Firmware major messages */
#define FW_MAJ_MSG_TRAINING_SUCCESS 0x0000007U
#define FW_MAJ_MSG_START_STREAMING 0x0000008U
#define FW_MAJ_MSG_TRAINING_FAILED 0x00000FFU
#define PHYINIT_DELAY_1US 1U
#define PHYINIT_DELAY_10US 10U
#define PHYINIT_TIMEOUT_US_1S 1000000U
static int wait_uctwriteprotshadow(bool state)
{
uint64_t timeout;
uint16_t read_data;
uint16_t value = state ? BIT(0) : 0U;
timeout = timeout_init_us(PHYINIT_TIMEOUT_US_1S);
do {
read_data = mmio_read_16((uintptr_t)(DDRPHYC_BASE +
(4U * (TAPBONLY | CSR_UCTSHADOWREGS_ADDR))));
udelay(PHYINIT_DELAY_1US);
if (timeout_elapsed(timeout)) {
return -1;
}
} while ((read_data & BIT(0)) != value);
return 0;
}
static int ack_message_receipt(void)
{
int ret;
/* Acknowledge the receipt of the message */
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TAPBONLY | CSR_DCTWRITEPROT_ADDR))), 0U);
udelay(PHYINIT_DELAY_1US);
ret = wait_uctwriteprotshadow(true);
if (ret != 0) {
return ret;
}
/* Complete the 4-phase protocol */
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TAPBONLY | CSR_DCTWRITEPROT_ADDR))), 1U);
udelay(PHYINIT_DELAY_1US);
return 0;
}
static int get_major_message(uint32_t *msg)
{
uint16_t message_number;
int ret;
ret = wait_uctwriteprotshadow(false);
if (ret != 0) {
return ret;
}
message_number = mmio_read_16((uintptr_t)(DDRPHYC_BASE +
(4U * (TAPBONLY |
CSR_UCTWRITEONLYSHADOW_ADDR))));
ret = ack_message_receipt();
if (ret != 0) {
return ret;
}
*msg = (uint32_t)message_number;
return 0;
}
static int get_streaming_message(uint32_t *msg)
{
uint16_t stream_word_lower_part;
uint16_t stream_word_upper_part;
int ret;
ret = wait_uctwriteprotshadow(false);
if (ret != 0) {
return ret;
}
stream_word_lower_part = mmio_read_16((uintptr_t)(DDRPHYC_BASE +
(4U * (TAPBONLY |
CSR_UCTWRITEONLYSHADOW_ADDR))));
stream_word_upper_part = mmio_read_16((uintptr_t)(DDRPHYC_BASE +
(4U * (TAPBONLY |
CSR_UCTDATWRITEONLYSHADOW_ADDR))));
ret = ack_message_receipt();
if (ret != 0) {
return ret;
}
*msg = (uint32_t)stream_word_lower_part | ((uint32_t)stream_word_upper_part << 16);
return 0;
}
/*
* Implements the mechanism to wait for completion of training firmware execution.
*
* The purpose of user this function is to wait for firmware to finish training.
* The user can either implement a counter to wait or implement the polling
* mechanism (our choice here). The wait time is highly dependent on the training features
* enabled via sequencectrl input to the message block.
*
* The default behavior of this function is to print comments relating to this
* process. A function call of the same name will be printed in the output text
* file.
*
* The user can choose to leave this function as is, or implement mechanism to
* trigger mailbox poling event in simulation.
*
* \return 0 on success.
*/
int ddrphy_phyinit_usercustom_g_waitfwdone(void)
{
uint32_t fw_major_message;
int ret;
do {
ret = get_major_message(&fw_major_message);
if (ret != 0) {
return ret;
}
VERBOSE("fw_major_message = %x\n", (unsigned int)fw_major_message);
if (fw_major_message == FW_MAJ_MSG_START_STREAMING) {
uint32_t i;
uint32_t read_data;
uint32_t stream_len;
ret = get_streaming_message(&read_data);
if (ret != 0) {
return ret;
}
stream_len = read_data & 0xFFFFU;
for (i = 0U; i < stream_len; i++) {
ret = get_streaming_message(&read_data);
if (ret != 0) {
return ret;
}
VERBOSE("streaming message = %x\n", (unsigned int)read_data);
}
}
} while ((fw_major_message != FW_MAJ_MSG_TRAINING_SUCCESS) &&
(fw_major_message != FW_MAJ_MSG_TRAINING_FAILED));
udelay(PHYINIT_DELAY_10US);
if (fw_major_message == FW_MAJ_MSG_TRAINING_FAILED) {
ERROR("%s Training has failed.\n", __func__);
return -1;
}
return 0;
}

View file

@ -0,0 +1,399 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdlib.h>
#include <common/debug.h>
#include <ddrphy_phyinit.h>
#include <lib/mmio.h>
#include <platform_def.h>
/*
* This function can be used to implement saving of PHY registers to be
* restored on retention exit.
*
* The requirement of this function is to issue register reads and store the
* value to be recovered on retention exit. The following is an example
* implementation and the user may implement alternate methods that suit their
* specific SoC system needs.
*
* In this implementation PhyInit saves register values in an internal C array.
* During retention exit it restores register values from the array. The exact
* list of registers to save and later restore can be seen in the output txt
* file with an associated calls to mmio_read_16().
*
* PhyInit provides a register interface and a tracking mechanism to minimize
* the number registers needing restore. Refer to source code for
* ddrphy_phyinit_reginterface() for detailed implementation of tracking
* mechanism. Tracking is disabled from step D to Step H as these involve
* loading, executing and checking the state of training firmware execution
* which are not required to implement the retention exit sequence. The registers
* specified representing training results are also saved in addition to registers
* written by PhyInit during PHY initialization.
*
* \return 0 on success.
*/
int ddrphy_phyinit_usercustom_saveretregs(struct stm32mp_ddr_config *config)
{
uint32_t anib;
uint32_t byte;
uint32_t nibble;
uint32_t lane;
uint32_t c_addr;
uint32_t u_addr;
uint32_t b_addr;
uint32_t r_addr;
int ret;
/*
* --------------------------------------------------------------------------
* 1. Enable tracking of training firmware result registers
*
* \note The tagged registers in this step are in
* addition to what is automatically tagged during Steps C to I.
*
* --------------------------------------------------------------------------
*/
ret = ddrphy_phyinit_trackreg(TMASTER | CSR_PLLCTRL3_ADDR);
if (ret != 0) {
return ret;
}
/* Non-PState Dbyte Registers */
for (byte = 0U; byte < config->uib.numdbyte; byte++) {
c_addr = byte << 12;
for (lane = 0U; lane <= R_MAX; lane++) {
r_addr = lane << 8;
ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | r_addr |
CSR_RXPBDLYTG0_ADDR);
if (ret != 0) {
return ret;
}
#if STM32MP_LPDDR4_TYPE
ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | r_addr |
CSR_RXPBDLYTG1_ADDR);
if (ret != 0) {
return ret;
}
#endif /* STM32MP_LPDDR4_TYPE */
}
#if STM32MP_LPDDR4_TYPE
ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_PPTCTLSTATIC_ADDR);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_TRAININGINCDECDTSMEN_ADDR);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_TSMBYTE0_ADDR);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DQ0LNSEL_ADDR);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DQ1LNSEL_ADDR);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DQ2LNSEL_ADDR);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DQ3LNSEL_ADDR);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DQ4LNSEL_ADDR);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DQ5LNSEL_ADDR);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DQ6LNSEL_ADDR);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DQ7LNSEL_ADDR);
if (ret != 0) {
return ret;
}
#endif /* STM32MP_LPDDR4_TYPE */
}
ret = ddrphy_phyinit_trackreg(TMASTER | CSR_VREFINGLOBAL_ADDR);
if (ret != 0) {
return ret;
}
/* Anib Registers */
for (anib = 0U; anib < config->uib.numanib; anib++) {
c_addr = anib << 12;
ret = ddrphy_phyinit_trackreg(TANIB | c_addr | CSR_ATXDLY_ADDR);
if (ret != 0) {
return ret;
}
}
/* Dbyte Registers */
for (byte = 0U; byte < config->uib.numdbyte; byte++) {
c_addr = byte << 12;
ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DFIMRL_ADDR);
if (ret != 0) {
return ret;
}
for (nibble = 0U; nibble <= B_MAX; nibble++) {
b_addr = nibble << 8;
ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | b_addr |
CSR_DQDQSRCVCNTRL_ADDR);
if (ret != 0) {
return ret;
}
}
for (nibble = 0U; nibble < 2U; nibble++) {
u_addr = nibble << 8;
ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | u_addr |
CSR_RXENDLYTG0_ADDR);
if (ret != 0) {
return ret;
}
#if STM32MP_LPDDR4_TYPE
ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | u_addr |
CSR_RXENDLYTG1_ADDR);
if (ret != 0) {
return ret;
}
#endif /* STM32MP_LPDDR4_TYPE */
ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | u_addr |
CSR_TXDQSDLYTG0_ADDR);
if (ret != 0) {
return ret;
}
#if STM32MP_LPDDR4_TYPE
ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | u_addr |
CSR_TXDQSDLYTG1_ADDR);
if (ret != 0) {
return ret;
}
#endif /* STM32MP_LPDDR4_TYPE */
ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | u_addr |
CSR_RXCLKDLYTG0_ADDR);
if (ret != 0) {
return ret;
}
#if STM32MP_LPDDR4_TYPE
ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | u_addr |
CSR_RXCLKDLYTG1_ADDR);
if (ret != 0) {
return ret;
}
#endif /* STM32MP_LPDDR4_TYPE */
}
for (lane = R_MIN; lane <= R_MAX; lane++) {
r_addr = lane << 8;
ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | r_addr |
CSR_TXDQDLYTG0_ADDR);
if (ret != 0) {
return ret;
}
#if STM32MP_LPDDR4_TYPE
ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | r_addr |
CSR_TXDQDLYTG1_ADDR);
if (ret != 0) {
return ret;
}
#endif /* STM32MP_LPDDR4_TYPE */
}
#if STM32MP_LPDDR4_TYPE
ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_PPTDQSCNTINVTRNTG0_ADDR);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_PPTDQSCNTINVTRNTG1_ADDR);
if (ret != 0) {
return ret;
}
#endif /* STM32MP_LPDDR4_TYPE */
}
/* PIE Registers */
ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BGPR1_ADDR);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BGPR2_ADDR);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BGPR3_ADDR);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BGPR4_ADDR);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BGPR5_ADDR);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BGPR6_ADDR);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BGPR7_ADDR);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BGPR8_ADDR);
if (ret != 0) {
return ret;
}
/* Master Registers */
ret = ddrphy_phyinit_trackreg(TMASTER | CSR_DLLGAINCTL_ADDR);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_trackreg(TMASTER | CSR_DLLLOCKPARAM_ADDR);
if (ret != 0) {
return ret;
}
#if STM32MP_LPDDR4_TYPE
ret = ddrphy_phyinit_trackreg(TMASTER | CSR_HWTMRL_ADDR);
if (ret != 0) {
return ret;
}
/* INITENG Registers */
ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BDISABLEFLAG6_ADDR);
if (ret != 0) {
return ret;
}
#endif /* STM32MP_LPDDR4_TYPE */
ret = ddrphy_phyinit_trackreg(TMASTER | CSR_HWTCAMODE_ADDR);
if (ret != 0) {
return ret;
}
#if STM32MP_LPDDR4_TYPE
ret = ddrphy_phyinit_trackreg(TMASTER | CSR_HWTLPCSENA_ADDR);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_trackreg(TMASTER | CSR_HWTLPCSENB_ADDR);
if (ret != 0) {
return ret;
}
/* ACSM registers */
ret = ddrphy_phyinit_trackreg(TACSM | CSR_ACSMCTRL13_ADDR);
if (ret != 0) {
return ret;
}
ret = ddrphy_phyinit_trackreg(TACSM | CSR_ACSMCTRL23_ADDR);
if (ret != 0) {
return ret;
}
#endif /* STM32MP_LPDDR4_TYPE */
/*
* --------------------------------------------------------------------------
* 2. Track any additional registers
* Register writes made using the any of the PhyInit functions are
* automatically tracked using the call to ddrphy_phyinit_trackreg() in
* mmio_write_16(). Use this section to track additional registers.
* --------------------------------------------------------------------------
*/
/*
* Example:
* ddrphy_phyinit_trackreg(<addr>);
*/
/*
* --------------------------------------------------------------------------
* 3. Prepare for register reads
* - Write the MicroContMuxSel CSR to 0x0 to allow access to the internal CSRs
* - Write the UcclkHclkEnables CSR to 0x3 to enable all the clocks so the reads
* can complete.
* --------------------------------------------------------------------------
*/
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TAPBONLY | CSR_MICROCONTMUXSEL_ADDR))),
0x0U);
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TDRTUB | CSR_UCCLKHCLKENABLES_ADDR))),
0x3U);
/*
* --------------------------------------------------------------------------
* / 4. Read and save all the registers
* / - The list of registers differ depending on protocol and 1D training.
* --------------------------------------------------------------------------
*/
ret = ddrphy_phyinit_reginterface(SAVEREGS, 0U, 0U);
if (ret != 0) {
return ret;
}
/*
* --------------------------------------------------------------------------
* 5. Prepare for mission mode
* - Write the UcclkHclkEnables CSR to disable the appropriate clocks after all reads done.
* - Write the MicroContMuxSel CSR to 0x1 to isolate the internal CSRs during mission mode.
* --------------------------------------------------------------------------
*/
/* Disabling Ucclk (PMU) and Hclk (training hardware) */
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TDRTUB | CSR_UCCLKHCLKENABLES_ADDR))),
0x0U);
mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TAPBONLY | CSR_MICROCONTMUXSEL_ADDR))),
0x1U);
return 0;
}

View file

@ -0,0 +1,479 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
#include <common/debug.h>
#include <ddrphy_phyinit.h>
#include <drivers/delay_timer.h>
#include <drivers/st/stm32mp2_ddr_helpers.h>
#include <drivers/st/stm32mp2_ddr_regs.h>
#include <drivers/st/stm32mp_ddr.h>
#include <lib/mmio.h>
#include <platform_def.h>
#define DDRDBG_FRAC_PLL_LOCK U(0x10)
#define DDRCTL_REG(x, y, z) \
{ \
.offset = offsetof(struct stm32mp_ddrctl, x), \
.par_offset = offsetof(struct y, x), \
.qd = z \
}
/*
* PARAMETERS: value get from device tree :
* size / order need to be aligned with binding
* modification NOT ALLOWED !!!
*/
#define DDRCTL_REG_REG_SIZE 48 /* st,ctl-reg */
#define DDRCTL_REG_TIMING_SIZE 20 /* st,ctl-timing */
#define DDRCTL_REG_MAP_SIZE 12 /* st,ctl-map */
#if STM32MP_DDR_DUAL_AXI_PORT
#define DDRCTL_REG_PERF_SIZE 21 /* st,ctl-perf */
#else /* !STM32MP_DDR_DUAL_AXI_PORT */
#define DDRCTL_REG_PERF_SIZE 14 /* st,ctl-perf */
#endif /* STM32MP_DDR_DUAL_AXI_PORT */
#define DDRPHY_REG_REG_SIZE 0 /* st,phy-reg */
#define DDRPHY_REG_TIMING_SIZE 0 /* st,phy-timing */
#define DDRCTL_REG_REG(x, z) DDRCTL_REG(x, stm32mp2_ddrctrl_reg, z)
static const struct stm32mp_ddr_reg_desc ddr_reg[DDRCTL_REG_REG_SIZE] = {
DDRCTL_REG_REG(mstr, true),
DDRCTL_REG_REG(mrctrl0, false),
DDRCTL_REG_REG(mrctrl1, false),
DDRCTL_REG_REG(mrctrl2, false),
DDRCTL_REG_REG(derateen, true),
DDRCTL_REG_REG(derateint, false),
DDRCTL_REG_REG(deratectl, false),
DDRCTL_REG_REG(pwrctl, false),
DDRCTL_REG_REG(pwrtmg, true),
DDRCTL_REG_REG(hwlpctl, true),
DDRCTL_REG_REG(rfshctl0, false),
DDRCTL_REG_REG(rfshctl1, false),
DDRCTL_REG_REG(rfshctl3, true),
DDRCTL_REG_REG(crcparctl0, false),
DDRCTL_REG_REG(crcparctl1, false),
DDRCTL_REG_REG(init0, true),
DDRCTL_REG_REG(init1, false),
DDRCTL_REG_REG(init2, false),
DDRCTL_REG_REG(init3, true),
DDRCTL_REG_REG(init4, true),
DDRCTL_REG_REG(init5, false),
DDRCTL_REG_REG(init6, true),
DDRCTL_REG_REG(init7, true),
DDRCTL_REG_REG(dimmctl, false),
DDRCTL_REG_REG(rankctl, true),
DDRCTL_REG_REG(rankctl1, true),
DDRCTL_REG_REG(zqctl0, true),
DDRCTL_REG_REG(zqctl1, false),
DDRCTL_REG_REG(zqctl2, false),
DDRCTL_REG_REG(dfitmg0, true),
DDRCTL_REG_REG(dfitmg1, true),
DDRCTL_REG_REG(dfilpcfg0, false),
DDRCTL_REG_REG(dfilpcfg1, false),
DDRCTL_REG_REG(dfiupd0, true),
DDRCTL_REG_REG(dfiupd1, false),
DDRCTL_REG_REG(dfiupd2, false),
DDRCTL_REG_REG(dfimisc, true),
DDRCTL_REG_REG(dfitmg2, true),
DDRCTL_REG_REG(dfitmg3, false),
DDRCTL_REG_REG(dbictl, true),
DDRCTL_REG_REG(dfiphymstr, false),
DDRCTL_REG_REG(dbg0, false),
DDRCTL_REG_REG(dbg1, false),
DDRCTL_REG_REG(dbgcmd, false),
DDRCTL_REG_REG(swctl, false), /* forced qd value */
DDRCTL_REG_REG(swctlstatic, false),
DDRCTL_REG_REG(poisoncfg, false),
DDRCTL_REG_REG(pccfg, false),
};
#define DDRCTL_REG_TIMING(x, z) DDRCTL_REG(x, stm32mp2_ddrctrl_timing, z)
static const struct stm32mp_ddr_reg_desc ddr_timing[DDRCTL_REG_TIMING_SIZE] = {
DDRCTL_REG_TIMING(rfshtmg, false),
DDRCTL_REG_TIMING(rfshtmg1, false),
DDRCTL_REG_TIMING(dramtmg0, true),
DDRCTL_REG_TIMING(dramtmg1, true),
DDRCTL_REG_TIMING(dramtmg2, true),
DDRCTL_REG_TIMING(dramtmg3, true),
DDRCTL_REG_TIMING(dramtmg4, true),
DDRCTL_REG_TIMING(dramtmg5, true),
DDRCTL_REG_TIMING(dramtmg6, true),
DDRCTL_REG_TIMING(dramtmg7, true),
DDRCTL_REG_TIMING(dramtmg8, true),
DDRCTL_REG_TIMING(dramtmg9, true),
DDRCTL_REG_TIMING(dramtmg10, true),
DDRCTL_REG_TIMING(dramtmg11, true),
DDRCTL_REG_TIMING(dramtmg12, true),
DDRCTL_REG_TIMING(dramtmg13, true),
DDRCTL_REG_TIMING(dramtmg14, true),
DDRCTL_REG_TIMING(dramtmg15, true),
DDRCTL_REG_TIMING(odtcfg, true),
DDRCTL_REG_TIMING(odtmap, false),
};
#define DDRCTL_REG_MAP(x) DDRCTL_REG(x, stm32mp2_ddrctrl_map, false)
static const struct stm32mp_ddr_reg_desc ddr_map[DDRCTL_REG_MAP_SIZE] = {
DDRCTL_REG_MAP(addrmap0),
DDRCTL_REG_MAP(addrmap1),
DDRCTL_REG_MAP(addrmap2),
DDRCTL_REG_MAP(addrmap3),
DDRCTL_REG_MAP(addrmap4),
DDRCTL_REG_MAP(addrmap5),
DDRCTL_REG_MAP(addrmap6),
DDRCTL_REG_MAP(addrmap7),
DDRCTL_REG_MAP(addrmap8),
DDRCTL_REG_MAP(addrmap9),
DDRCTL_REG_MAP(addrmap10),
DDRCTL_REG_MAP(addrmap11),
};
#define DDRCTL_REG_PERF(x, z) DDRCTL_REG(x, stm32mp2_ddrctrl_perf, z)
static const struct stm32mp_ddr_reg_desc ddr_perf[DDRCTL_REG_PERF_SIZE] = {
DDRCTL_REG_PERF(sched, true),
DDRCTL_REG_PERF(sched1, false),
DDRCTL_REG_PERF(perfhpr1, true),
DDRCTL_REG_PERF(perflpr1, true),
DDRCTL_REG_PERF(perfwr1, true),
DDRCTL_REG_PERF(sched3, false),
DDRCTL_REG_PERF(sched4, false),
DDRCTL_REG_PERF(pcfgr_0, false),
DDRCTL_REG_PERF(pcfgw_0, false),
DDRCTL_REG_PERF(pctrl_0, false),
DDRCTL_REG_PERF(pcfgqos0_0, true),
DDRCTL_REG_PERF(pcfgqos1_0, true),
DDRCTL_REG_PERF(pcfgwqos0_0, true),
DDRCTL_REG_PERF(pcfgwqos1_0, true),
#if STM32MP_DDR_DUAL_AXI_PORT
DDRCTL_REG_PERF(pcfgr_1, false),
DDRCTL_REG_PERF(pcfgw_1, false),
DDRCTL_REG_PERF(pctrl_1, false),
DDRCTL_REG_PERF(pcfgqos0_1, true),
DDRCTL_REG_PERF(pcfgqos1_1, true),
DDRCTL_REG_PERF(pcfgwqos0_1, true),
DDRCTL_REG_PERF(pcfgwqos1_1, true),
#endif /* STM32MP_DDR_DUAL_AXI_PORT */
};
static const struct stm32mp_ddr_reg_desc ddrphy_reg[DDRPHY_REG_REG_SIZE] = {};
static const struct stm32mp_ddr_reg_desc ddrphy_timing[DDRPHY_REG_TIMING_SIZE] = {};
/*
* REGISTERS ARRAY: used to parse device tree and interactive mode
*/
static const struct stm32mp_ddr_reg_info ddr_registers[REG_TYPE_NB] __unused = {
[REG_REG] = {
.name = "static",
.desc = ddr_reg,
.size = DDRCTL_REG_REG_SIZE,
.base = DDR_BASE
},
[REG_TIMING] = {
.name = "timing",
.desc = ddr_timing,
.size = DDRCTL_REG_TIMING_SIZE,
.base = DDR_BASE
},
[REG_PERF] = {
.name = "perf",
.desc = ddr_perf,
.size = DDRCTL_REG_PERF_SIZE,
.base = DDR_BASE
},
[REG_MAP] = {
.name = "map",
.desc = ddr_map,
.size = DDRCTL_REG_MAP_SIZE,
.base = DDR_BASE
},
[REGPHY_REG] = {
.name = "static",
.desc = ddrphy_reg,
.size = DDRPHY_REG_REG_SIZE,
.base = DDRPHY_BASE
},
[REGPHY_TIMING] = {
.name = "timing",
.desc = ddrphy_timing,
.size = DDRPHY_REG_TIMING_SIZE,
.base = DDRPHY_BASE
},
};
static void ddr_reset(struct stm32mp_ddr_priv *priv)
{
udelay(DDR_DELAY_1US);
mmio_setbits_32(priv->rcc + RCC_DDRITFCFGR, RCC_DDRITFCFGR_DDRRST);
mmio_write_32(priv->rcc + RCC_DDRPHYCAPBCFGR,
RCC_DDRPHYCAPBCFGR_DDRPHYCAPBEN | RCC_DDRPHYCAPBCFGR_DDRPHYCAPBLPEN |
RCC_DDRPHYCAPBCFGR_DDRPHYCAPBRST);
mmio_write_32(priv->rcc + RCC_DDRCAPBCFGR,
RCC_DDRCAPBCFGR_DDRCAPBEN | RCC_DDRCAPBCFGR_DDRCAPBLPEN |
RCC_DDRCAPBCFGR_DDRCAPBRST);
mmio_write_32(priv->rcc + RCC_DDRCFGR,
RCC_DDRCFGR_DDRCFGEN | RCC_DDRCFGR_DDRCFGLPEN | RCC_DDRCFGR_DDRCFGRST);
udelay(DDR_DELAY_1US);
mmio_setbits_32(priv->rcc + RCC_DDRITFCFGR, RCC_DDRITFCFGR_DDRRST);
mmio_write_32(priv->rcc + RCC_DDRPHYCAPBCFGR,
RCC_DDRPHYCAPBCFGR_DDRPHYCAPBEN | RCC_DDRPHYCAPBCFGR_DDRPHYCAPBLPEN);
mmio_write_32(priv->rcc + RCC_DDRCAPBCFGR,
RCC_DDRCAPBCFGR_DDRCAPBEN | RCC_DDRCAPBCFGR_DDRCAPBLPEN);
mmio_write_32(priv->rcc + RCC_DDRCFGR, RCC_DDRCFGR_DDRCFGEN | RCC_DDRCFGR_DDRCFGLPEN);
udelay(DDR_DELAY_1US);
}
static void ddr_standby_reset(struct stm32mp_ddr_priv *priv)
{
udelay(DDR_DELAY_1US);
mmio_write_32(priv->rcc + RCC_DDRCPCFGR,
RCC_DDRCPCFGR_DDRCPEN | RCC_DDRCPCFGR_DDRCPLPEN | RCC_DDRCPCFGR_DDRCPRST);
mmio_setbits_32(priv->rcc + RCC_DDRITFCFGR, RCC_DDRITFCFGR_DDRRST);
mmio_write_32(priv->rcc + RCC_DDRPHYCAPBCFGR,
RCC_DDRPHYCAPBCFGR_DDRPHYCAPBEN | RCC_DDRPHYCAPBCFGR_DDRPHYCAPBLPEN |
RCC_DDRPHYCAPBCFGR_DDRPHYCAPBRST);
mmio_write_32(priv->rcc + RCC_DDRCAPBCFGR,
RCC_DDRCAPBCFGR_DDRCAPBEN | RCC_DDRCAPBCFGR_DDRCAPBLPEN |
RCC_DDRCAPBCFGR_DDRCAPBRST);
mmio_clrbits_32(priv->rcc + RCC_DDRITFCFGR, RCC_DDRITFCFGR_DDRPHYDLP);
mmio_setbits_32(priv->rcc + RCC_DDRPHYCCFGR, RCC_DDRPHYCCFGR_DDRPHYCEN);
udelay(DDR_DELAY_1US);
}
static void ddr_standby_reset_release(struct stm32mp_ddr_priv *priv)
{
udelay(DDR_DELAY_1US);
mmio_write_32(priv->rcc + RCC_DDRCPCFGR, RCC_DDRCPCFGR_DDRCPEN | RCC_DDRCPCFGR_DDRCPLPEN);
mmio_clrbits_32(priv->rcc + RCC_DDRITFCFGR, RCC_DDRITFCFGR_DDRRST);
mmio_clrbits_32(priv->rcc + RCC_DDRPHYCAPBCFGR, RCC_DDRPHYCAPBCFGR_DDRPHYCAPBRST);
mmio_write_32(priv->rcc + RCC_DDRCFGR, RCC_DDRCFGR_DDRCFGEN | RCC_DDRCFGR_DDRCFGLPEN);
udelay(DDR_DELAY_1US);
}
static void ddr_sysconf_configuration(struct stm32mp_ddr_priv *priv,
struct stm32mp_ddr_config *config)
{
mmio_write_32(stm32_ddrdbg_get_base() + DDRDBG_LP_DISABLE,
DDRDBG_LP_DISABLE_LPI_XPI_DISABLE | DDRDBG_LP_DISABLE_LPI_DDRC_DISABLE);
mmio_write_32(stm32_ddrdbg_get_base() + DDRDBG_BYPASS_PCLKEN,
(uint32_t)config->uib.pllbypass);
mmio_write_32(priv->rcc + RCC_DDRPHYCCFGR, RCC_DDRPHYCCFGR_DDRPHYCEN);
mmio_setbits_32(priv->rcc + RCC_DDRITFCFGR, RCC_DDRITFCFGR_DDRRST);
udelay(DDR_DELAY_1US);
}
static void set_dfi_init_complete_en(struct stm32mp_ddrctl *ctl, bool phy_init_done)
{
/*
* Manage quasi-dynamic registers modification
* dfimisc.dfi_init_complete_en : Group 3
*/
stm32mp_ddr_set_qd3_update_conditions(ctl);
udelay(DDR_DELAY_1US);
if (phy_init_done) {
/* Indicates to controller that PHY has completed initialization */
mmio_setbits_32((uintptr_t)&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
} else {
/* PHY not initialized yet, wait for completion */
mmio_clrbits_32((uintptr_t)&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
}
udelay(DDR_DELAY_1US);
stm32mp_ddr_unset_qd3_update_conditions(ctl);
}
static void disable_refresh(struct stm32mp_ddrctl *ctl)
{
mmio_setbits_32((uintptr_t)&ctl->rfshctl3, DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH);
stm32mp_ddr_wait_refresh_update_done_ack(ctl);
udelay(DDR_DELAY_1US);
mmio_clrbits_32((uintptr_t)&ctl->pwrctl,
DDRCTRL_PWRCTL_POWERDOWN_EN | DDRCTRL_PWRCTL_SELFREF_EN);
udelay(DDR_DELAY_1US);
set_dfi_init_complete_en(ctl, false);
}
static void restore_refresh(struct stm32mp_ddrctl *ctl, uint32_t rfshctl3, uint32_t pwrctl)
{
if ((rfshctl3 & DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH) == 0U) {
mmio_clrbits_32((uintptr_t)&ctl->rfshctl3, DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH);
stm32mp_ddr_wait_refresh_update_done_ack(ctl);
udelay(DDR_DELAY_1US);
}
if ((pwrctl & DDRCTRL_PWRCTL_SELFREF_SW) != 0U) {
mmio_clrbits_32((uintptr_t)&ctl->pwrctl, DDRCTRL_PWRCTL_SELFREF_SW);
udelay(DDR_DELAY_1US);
}
if ((pwrctl & DDRCTRL_PWRCTL_POWERDOWN_EN) != 0U) {
mmio_setbits_32((uintptr_t)&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN);
udelay(DDR_DELAY_1US);
}
if ((pwrctl & DDRCTRL_PWRCTL_SELFREF_EN) != 0U) {
mmio_setbits_32((uintptr_t)&ctl->pwrctl, DDRCTRL_PWRCTL_SELFREF_EN);
udelay(DDR_DELAY_1US);
}
set_dfi_init_complete_en(ctl, true);
}
void stm32mp2_ddr_init(struct stm32mp_ddr_priv *priv,
struct stm32mp_ddr_config *config)
{
int ret = -EINVAL;
uint32_t ddr_retdis;
enum ddr_type ddr_type;
if ((config->c_reg.mstr & DDRCTRL_MSTR_DDR3) != 0U) {
ddr_type = STM32MP_DDR3;
} else if ((config->c_reg.mstr & DDRCTRL_MSTR_DDR4) != 0U) {
ddr_type = STM32MP_DDR4;
} else if ((config->c_reg.mstr & DDRCTRL_MSTR_LPDDR4) != 0U) {
ddr_type = STM32MP_LPDDR4;
} else {
ERROR("DDR type not supported\n");
panic();
}
VERBOSE("name = %s\n", config->info.name);
VERBOSE("speed = %u kHz\n", config->info.speed);
VERBOSE("size = 0x%zx\n", config->info.size);
if (config->self_refresh) {
VERBOSE("sel-refresh exit (zdata = 0x%x)\n", config->zdata);
}
/* Check DDR PHY pads retention */
ddr_retdis = mmio_read_32(priv->pwr + PWR_CR11) & PWR_CR11_DDRRETDIS;
if (config->self_refresh) {
if (ddr_retdis == PWR_CR11_DDRRETDIS) {
VERBOSE("self-refresh aborted: no retention\n");
config->self_refresh = false;
}
}
if (config->self_refresh) {
ddr_standby_reset(priv);
VERBOSE("disable DDR PHY retention\n");
mmio_setbits_32(priv->pwr + PWR_CR11, PWR_CR11_DDRRETDIS);
udelay(DDR_DELAY_1US);
mmio_clrbits_32(priv->rcc + RCC_DDRCAPBCFGR, RCC_DDRCAPBCFGR_DDRCAPBRST);
udelay(DDR_DELAY_1US);
} else {
if (stm32mp_board_ddr_power_init(ddr_type) != 0) {
ERROR("DDR power init failed\n");
panic();
}
VERBOSE("disable DDR PHY retention\n");
mmio_setbits_32(priv->pwr + PWR_CR11, PWR_CR11_DDRRETDIS);
ddr_reset(priv);
ddr_sysconf_configuration(priv, config);
}
#if STM32MP_LPDDR4_TYPE
/*
* Enable PWRCTL.SELFREF_SW to ensure correct setting of PWRCTL.LPDDR4_SR_ALLOWED.
* Later disabled in restore_refresh().
*/
config->c_reg.pwrctl |= DDRCTRL_PWRCTL_SELFREF_SW;
#endif /* STM32MP_LPDDR4_TYPE */
stm32mp_ddr_set_reg(priv, REG_REG, &config->c_reg, ddr_registers);
stm32mp_ddr_set_reg(priv, REG_TIMING, &config->c_timing, ddr_registers);
stm32mp_ddr_set_reg(priv, REG_MAP, &config->c_map, ddr_registers);
stm32mp_ddr_set_reg(priv, REG_PERF, &config->c_perf, ddr_registers);
if (!config->self_refresh) {
/* DDR core and PHY reset de-assert */
mmio_clrbits_32(priv->rcc + RCC_DDRITFCFGR, RCC_DDRITFCFGR_DDRRST);
disable_refresh(priv->ctl);
}
if (config->self_refresh) {
ddr_standby_reset_release(priv);
/* Initialize DDR by skipping training and disabling result saving */
ret = ddrphy_phyinit_sequence(config, true, false);
if (ret == 0) {
ret = ddrphy_phyinit_restore_sequence();
}
/* Poll on ddrphy_initeng0_phyinlpx.phyinlp3 = 0 */
ddr_wait_lp3_mode(false);
} else {
/* Initialize DDR including training and result saving */
ret = ddrphy_phyinit_sequence(config, false, true);
}
if (ret != 0) {
ERROR("DDR PHY init: Error %d\n", ret);
panic();
}
ddr_activate_controller(priv->ctl, false);
if (config->self_refresh) {
struct stm32mp_ddrctl *ctl = priv->ctl;
/* SW self refresh exit prequested */
mmio_clrbits_32((uintptr_t)&ctl->pwrctl, DDRCTRL_PWRCTL_SELFREF_SW);
if (ddr_sr_exit_loop() != 0) {
ERROR("DDR Standby exit error\n");
panic();
}
/* Re-enable DFI low-power interface */
mmio_clrbits_32((uintptr_t)&ctl->dfilpcfg0, DDRCTRL_DFILPCFG0_DFI_LP_EN_SR);
} else {
restore_refresh(priv->ctl, config->c_reg.rfshctl3, config->c_reg.pwrctl);
}
stm32mp_ddr_enable_axi_port(priv->ctl);
}

View file

@ -4,12 +4,524 @@
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*/ */
#include <errno.h>
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <drivers/st/stm32mp2_ddr.h>
#include <drivers/st/stm32mp2_ddr_helpers.h>
#include <drivers/st/stm32mp2_ddr_regs.h>
#include <drivers/st/stm32mp_ddr.h>
#include <lib/mmio.h> #include <lib/mmio.h>
#include <platform_def.h> #include <platform_def.h>
/* HW idle period (unit: Multiples of 32 DFI clock cycles) */
#define HW_IDLE_PERIOD 0x3U
static enum stm32mp2_ddr_sr_mode saved_ddr_sr_mode;
#pragma weak stm32_ddrdbg_get_base
uintptr_t stm32_ddrdbg_get_base(void)
{
return 0U;
}
static void set_qd1_qd3_update_conditions(struct stm32mp_ddrctl *ctl)
{
mmio_setbits_32((uintptr_t)&ctl->dbg1, DDRCTRL_DBG1_DIS_DQ);
stm32mp_ddr_set_qd3_update_conditions(ctl);
}
static void unset_qd1_qd3_update_conditions(struct stm32mp_ddrctl *ctl)
{
stm32mp_ddr_unset_qd3_update_conditions(ctl);
mmio_clrbits_32((uintptr_t)&ctl->dbg1, DDRCTRL_DBG1_DIS_DQ);
}
static void wait_dfi_init_complete(struct stm32mp_ddrctl *ctl)
{
uint64_t timeout;
uint32_t dfistat;
timeout = timeout_init_us(DDR_TIMEOUT_US_1S);
do {
dfistat = mmio_read_32((uintptr_t)&ctl->dfistat);
VERBOSE("[0x%lx] dfistat = 0x%x ", (uintptr_t)&ctl->dfistat, dfistat);
if (timeout_elapsed(timeout)) {
panic();
}
} while ((dfistat & DDRCTRL_DFISTAT_DFI_INIT_COMPLETE) == 0U);
VERBOSE("[0x%lx] dfistat = 0x%x\n", (uintptr_t)&ctl->dfistat, dfistat);
}
static void disable_dfi_low_power_interface(struct stm32mp_ddrctl *ctl)
{
uint64_t timeout;
uint32_t dfistat;
uint32_t stat;
mmio_clrbits_32((uintptr_t)&ctl->dfilpcfg0, DDRCTRL_DFILPCFG0_DFI_LP_EN_SR);
timeout = timeout_init_us(DDR_TIMEOUT_US_1S);
do {
dfistat = mmio_read_32((uintptr_t)&ctl->dfistat);
stat = mmio_read_32((uintptr_t)&ctl->stat);
VERBOSE("[0x%lx] dfistat = 0x%x ", (uintptr_t)&ctl->dfistat, dfistat);
VERBOSE("[0x%lx] stat = 0x%x ", (uintptr_t)&ctl->stat, stat);
if (timeout_elapsed(timeout)) {
panic();
}
} while (((dfistat & DDRCTRL_DFISTAT_DFI_LP_ACK) != 0U) ||
((stat & DDRCTRL_STAT_OPERATING_MODE_MASK) == DDRCTRL_STAT_OPERATING_MODE_SR));
VERBOSE("[0x%lx] dfistat = 0x%x\n", (uintptr_t)&ctl->dfistat, dfistat);
VERBOSE("[0x%lx] stat = 0x%x\n", (uintptr_t)&ctl->stat, stat);
}
void ddr_activate_controller(struct stm32mp_ddrctl *ctl, bool sr_entry)
{
/*
* Manage quasi-dynamic registers modification
* dfimisc.dfi_frequency : Group 1
* dfimisc.dfi_init_complete_en and dfimisc.dfi_init_start : Group 3
*/
set_qd1_qd3_update_conditions(ctl);
if (sr_entry) {
mmio_setbits_32((uintptr_t)&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_FREQUENCY);
} else {
mmio_clrbits_32((uintptr_t)&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_FREQUENCY);
}
mmio_setbits_32((uintptr_t)&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_START);
mmio_clrbits_32((uintptr_t)&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_START);
wait_dfi_init_complete(ctl);
udelay(DDR_DELAY_1US);
if (sr_entry) {
mmio_clrbits_32((uintptr_t)&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
} else {
mmio_setbits_32((uintptr_t)&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
}
udelay(DDR_DELAY_1US);
unset_qd1_qd3_update_conditions(ctl);
}
#if STM32MP_LPDDR4_TYPE
static void disable_phy_ddc(void)
{
/* Enable APB access to internal CSR registers */
mmio_write_32(stm32mp_ddrphyc_base() + DDRPHY_APBONLY0_MICROCONTMUXSEL, 0U);
mmio_write_32(stm32mp_ddrphyc_base() + DDRPHY_DRTUB0_UCCLKHCLKENABLES,
DDRPHY_DRTUB0_UCCLKHCLKENABLES_UCCLKEN |
DDRPHY_DRTUB0_UCCLKHCLKENABLES_HCLKEN);
/* Disable DRAM drift compensation */
mmio_write_32(stm32mp_ddrphyc_base() + DDRPHY_INITENG0_P0_SEQ0BDISABLEFLAG6, 0xFFFFU);
/* Disable APB access to internal CSR registers */
mmio_write_32(stm32mp_ddrphyc_base() + DDRPHY_DRTUB0_UCCLKHCLKENABLES,
DDRPHY_DRTUB0_UCCLKHCLKENABLES_HCLKEN);
mmio_write_32(stm32mp_ddrphyc_base() + DDRPHY_APBONLY0_MICROCONTMUXSEL,
DDRPHY_APBONLY0_MICROCONTMUXSEL_MICROCONTMUXSEL);
}
#endif /* STM32MP_LPDDR4_TYPE */
void ddr_wait_lp3_mode(bool sr_entry)
{
uint64_t timeout;
bool repeat_loop = false;
/* Enable APB access to internal CSR registers */
mmio_write_32(stm32mp_ddrphyc_base() + DDRPHY_APBONLY0_MICROCONTMUXSEL, 0U);
mmio_write_32(stm32mp_ddrphyc_base() + DDRPHY_DRTUB0_UCCLKHCLKENABLES,
DDRPHY_DRTUB0_UCCLKHCLKENABLES_UCCLKEN |
DDRPHY_DRTUB0_UCCLKHCLKENABLES_HCLKEN);
timeout = timeout_init_us(DDR_TIMEOUT_US_1S);
do {
uint16_t phyinlpx = mmio_read_32(stm32mp_ddrphyc_base() +
DDRPHY_INITENG0_P0_PHYINLPX);
if (timeout_elapsed(timeout)) {
panic();
}
if (sr_entry) {
repeat_loop = (phyinlpx & DDRPHY_INITENG0_P0_PHYINLPX_PHYINLP3) == 0U;
} else {
repeat_loop = (phyinlpx & DDRPHY_INITENG0_P0_PHYINLPX_PHYINLP3) != 0U;
}
} while (repeat_loop);
/* Disable APB access to internal CSR registers */
#if STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE
mmio_write_32(stm32mp_ddrphyc_base() + DDRPHY_DRTUB0_UCCLKHCLKENABLES, 0U);
#else /* STM32MP_LPDDR4_TYPE */
mmio_write_32(stm32mp_ddrphyc_base() + DDRPHY_DRTUB0_UCCLKHCLKENABLES,
DDRPHY_DRTUB0_UCCLKHCLKENABLES_HCLKEN);
#endif /* STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE */
mmio_write_32(stm32mp_ddrphyc_base() + DDRPHY_APBONLY0_MICROCONTMUXSEL,
DDRPHY_APBONLY0_MICROCONTMUXSEL_MICROCONTMUXSEL);
}
static int sr_loop(bool is_entry)
{
uint32_t type;
uint32_t state __maybe_unused;
uint64_t timeout = timeout_init_us(DDR_TIMEOUT_US_1S);
bool repeat_loop = false;
/*
* Wait for DDRCTRL to be out of or back to "normal/mission mode".
* Consider also SRPD mode for LPDDR4 only.
*/
do {
type = mmio_read_32(stm32mp_ddrctrl_base() + DDRCTRL_STAT) &
DDRCTRL_STAT_SELFREF_TYPE_MASK;
#if STM32MP_LPDDR4_TYPE
state = mmio_read_32(stm32mp_ddrctrl_base() + DDRCTRL_STAT) &
DDRCTRL_STAT_SELFREF_STATE_MASK;
#endif /* STM32MP_LPDDR4_TYPE */
if (timeout_elapsed(timeout)) {
return -ETIMEDOUT;
}
if (is_entry) {
#if STM32MP_LPDDR4_TYPE
repeat_loop = (type == 0x0U) || (state != DDRCTRL_STAT_SELFREF_STATE_SRPD);
#else /* !STM32MP_LPDDR4_TYPE */
repeat_loop = (type == 0x0U);
#endif /* STM32MP_LPDDR4_TYPE */
} else {
#if STM32MP_LPDDR4_TYPE
repeat_loop = (type != 0x0U) || (state != 0x0U);
#else /* !STM32MP_LPDDR4_TYPE */
repeat_loop = (type != 0x0U);
#endif /* STM32MP_LPDDR4_TYPE */
}
} while (repeat_loop);
return 0;
}
static int sr_entry_loop(void)
{
return sr_loop(true);
}
int ddr_sr_exit_loop(void)
{
return sr_loop(false);
}
static int sr_ssr_set(void)
{
uintptr_t ddrctrl_base = stm32mp_ddrctrl_base();
/*
* Disable Clock disable with LP modes
* (used in RUN mode for LPDDR2 with specific timing).
*/
mmio_clrbits_32(ddrctrl_base + DDRCTRL_PWRCTL, DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE);
/* Disable automatic Self-Refresh mode */
mmio_clrbits_32(ddrctrl_base + DDRCTRL_PWRCTL, DDRCTRL_PWRCTL_SELFREF_EN);
mmio_write_32(stm32_ddrdbg_get_base() + DDRDBG_LP_DISABLE,
DDRDBG_LP_DISABLE_LPI_XPI_DISABLE | DDRDBG_LP_DISABLE_LPI_DDRC_DISABLE);
return 0;
}
static int sr_ssr_entry(bool standby)
{
uintptr_t ddrctrl_base = stm32mp_ddrctrl_base();
uintptr_t rcc_base = stm32mp_rcc_base();
if (stm32mp_ddr_disable_axi_port((struct stm32mp_ddrctl *)ddrctrl_base) != 0) {
panic();
}
#if STM32MP_LPDDR4_TYPE
if (standby) {
/* Disable DRAM drift compensation */
disable_phy_ddc();
}
#endif /* STM32MP_LPDDR4_TYPE */
disable_dfi_low_power_interface((struct stm32mp_ddrctl *)ddrctrl_base);
/* SW self refresh entry prequested */
mmio_setbits_32(ddrctrl_base + DDRCTRL_PWRCTL, DDRCTRL_PWRCTL_SELFREF_SW);
#if STM32MP_LPDDR4_TYPE
mmio_clrbits_32(ddrctrl_base + DDRCTRL_PWRCTL, DDRCTRL_PWRCTL_STAY_IN_SELFREF);
#endif /* STM32MP_LPDDR4_TYPE */
if (sr_entry_loop() != 0) {
return -1;
}
ddr_activate_controller((struct stm32mp_ddrctl *)ddrctrl_base, true);
/* Poll on ddrphy_initeng0_phyinlpx.phyinlp3 = 1 */
ddr_wait_lp3_mode(true);
if (standby) {
mmio_clrbits_32(stm32mp_pwr_base() + PWR_CR11, PWR_CR11_DDRRETDIS);
}
mmio_clrsetbits_32(rcc_base + RCC_DDRCPCFGR, RCC_DDRCPCFGR_DDRCPLPEN,
RCC_DDRCPCFGR_DDRCPEN);
mmio_setbits_32(rcc_base + RCC_DDRPHYCCFGR, RCC_DDRPHYCCFGR_DDRPHYCEN);
mmio_setbits_32(rcc_base + RCC_DDRITFCFGR, RCC_DDRITFCFGR_DDRPHYDLP);
return 0;
}
static int sr_ssr_exit(void)
{
uintptr_t ddrctrl_base = stm32mp_ddrctrl_base();
uintptr_t rcc_base = stm32mp_rcc_base();
mmio_setbits_32(rcc_base + RCC_DDRCPCFGR,
RCC_DDRCPCFGR_DDRCPLPEN | RCC_DDRCPCFGR_DDRCPEN);
mmio_clrbits_32(rcc_base + RCC_DDRITFCFGR, RCC_DDRITFCFGR_DDRPHYDLP);
mmio_setbits_32(rcc_base + RCC_DDRPHYCCFGR, RCC_DDRPHYCCFGR_DDRPHYCEN);
udelay(DDR_DELAY_1US);
ddr_activate_controller((struct stm32mp_ddrctl *)ddrctrl_base, false);
/* Poll on ddrphy_initeng0_phyinlpx.phyinlp3 = 0 */
ddr_wait_lp3_mode(false);
/* SW self refresh exit prequested */
mmio_clrbits_32(ddrctrl_base + DDRCTRL_PWRCTL, DDRCTRL_PWRCTL_SELFREF_SW);
if (ddr_sr_exit_loop() != 0) {
return -1;
}
/* Re-enable DFI low-power interface */
mmio_setbits_32(ddrctrl_base + DDRCTRL_DFILPCFG0, DDRCTRL_DFILPCFG0_DFI_LP_EN_SR);
stm32mp_ddr_enable_axi_port((struct stm32mp_ddrctl *)ddrctrl_base);
return 0;
}
static int sr_hsr_set(void)
{
uintptr_t ddrctrl_base = stm32mp_ddrctrl_base();
mmio_clrsetbits_32(stm32mp_rcc_base() + RCC_DDRITFCFGR,
RCC_DDRITFCFGR_DDRCKMOD_MASK, RCC_DDRITFCFGR_DDRCKMOD_HSR);
/*
* manage quasi-dynamic registers modification
* hwlpctl.hw_lp_en : Group 2
*/
if (stm32mp_ddr_sw_selfref_entry((struct stm32mp_ddrctl *)ddrctrl_base) != 0) {
panic();
}
stm32mp_ddr_start_sw_done((struct stm32mp_ddrctl *)ddrctrl_base);
mmio_write_32(ddrctrl_base + DDRCTRL_HWLPCTL,
DDRCTRL_HWLPCTL_HW_LP_EN | DDRCTRL_HWLPCTL_HW_LP_EXIT_IDLE_EN |
(HW_IDLE_PERIOD << DDRCTRL_HWLPCTL_HW_LP_IDLE_X32_SHIFT));
stm32mp_ddr_wait_sw_done_ack((struct stm32mp_ddrctl *)ddrctrl_base);
stm32mp_ddr_sw_selfref_exit((struct stm32mp_ddrctl *)ddrctrl_base);
return 0;
}
static int sr_hsr_entry(void)
{
mmio_write_32(stm32mp_rcc_base() + RCC_DDRCPCFGR, RCC_DDRCPCFGR_DDRCPLPEN);
return sr_entry_loop(); /* read_data should be equal to 0x223 */
}
static int sr_hsr_exit(void)
{
mmio_write_32(stm32mp_rcc_base() + RCC_DDRCPCFGR,
RCC_DDRCPCFGR_DDRCPLPEN | RCC_DDRCPCFGR_DDRCPEN);
/* TODO: check if ddr_sr_exit_loop() is needed here */
return 0;
}
static int sr_asr_set(void)
{
mmio_write_32(stm32_ddrdbg_get_base() + DDRDBG_LP_DISABLE, 0U);
return 0;
}
static int sr_asr_entry(void)
{
/*
* Automatically enter into self refresh when there is no ddr traffic
* for the delay programmed into SYSCONF_DDRC_AUTO_SR_DELAY register.
* Default value is 0x20 (unit: Multiples of 32 DFI clock cycles).
*/
return sr_entry_loop();
}
static int sr_asr_exit(void)
{
return ddr_sr_exit_loop();
}
uint32_t ddr_get_io_calibration_val(void)
{
/* TODO create related service */
return 0U;
}
int ddr_sr_entry(bool standby)
{
int ret = -EINVAL;
switch (saved_ddr_sr_mode) {
case DDR_SSR_MODE:
ret = sr_ssr_entry(standby);
break;
case DDR_HSR_MODE:
ret = sr_hsr_entry();
break;
case DDR_ASR_MODE:
ret = sr_asr_entry();
break;
default:
break;
}
return ret;
}
int ddr_sr_exit(void)
{
int ret = -EINVAL;
switch (saved_ddr_sr_mode) {
case DDR_SSR_MODE:
ret = sr_ssr_exit();
break;
case DDR_HSR_MODE:
ret = sr_hsr_exit();
break;
case DDR_ASR_MODE:
ret = sr_asr_exit();
break;
default:
break;
}
return ret;
}
enum stm32mp2_ddr_sr_mode ddr_read_sr_mode(void)
{
uint32_t pwrctl = mmio_read_32(stm32mp_ddrctrl_base() + DDRCTRL_PWRCTL);
enum stm32mp2_ddr_sr_mode mode = DDR_SR_MODE_INVALID;
switch (pwrctl & (DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE |
DDRCTRL_PWRCTL_SELFREF_EN)) {
case 0U:
mode = DDR_SSR_MODE;
break;
case DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE:
mode = DDR_HSR_MODE;
break;
case DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE | DDRCTRL_PWRCTL_SELFREF_EN:
mode = DDR_ASR_MODE;
break;
default:
break;
}
return mode;
}
void ddr_set_sr_mode(enum stm32mp2_ddr_sr_mode mode)
{
int ret = -EINVAL;
if (mode == saved_ddr_sr_mode) {
return;
}
switch (mode) {
case DDR_SSR_MODE:
ret = sr_ssr_set();
break;
case DDR_HSR_MODE:
ret = sr_hsr_set();
break;
case DDR_ASR_MODE:
ret = sr_asr_set();
break;
default:
break;
}
if (ret != 0) {
ERROR("Unknown Self Refresh mode\n");
panic();
}
saved_ddr_sr_mode = mode;
}
void ddr_save_sr_mode(void)
{
saved_ddr_sr_mode = ddr_read_sr_mode();
}
void ddr_restore_sr_mode(void)
{
ddr_set_sr_mode(saved_ddr_sr_mode);
}
void ddr_sub_system_clk_init(void) void ddr_sub_system_clk_init(void)
{ {
mmio_write_32(stm32mp_rcc_base() + RCC_DDRCPCFGR, mmio_write_32(stm32mp_rcc_base() + RCC_DDRCPCFGR,
RCC_DDRCPCFGR_DDRCPEN | RCC_DDRCPCFGR_DDRCPLPEN); RCC_DDRCPCFGR_DDRCPEN | RCC_DDRCPCFGR_DDRCPLPEN);
} }
void ddr_sub_system_clk_off(void)
{
uintptr_t rcc_base = stm32mp_rcc_base();
/* Clear DDR IO retention */
mmio_clrbits_32(stm32mp_pwr_base() + PWR_CR11, PWR_CR11_DDRRETDIS);
/* Reset DDR sub system */
mmio_write_32(rcc_base + RCC_DDRCPCFGR, RCC_DDRCPCFGR_DDRCPRST);
mmio_write_32(rcc_base + RCC_DDRITFCFGR, RCC_DDRITFCFGR_DDRRST);
mmio_write_32(rcc_base + RCC_DDRPHYCAPBCFGR, RCC_DDRPHYCAPBCFGR_DDRPHYCAPBRST);
mmio_write_32(rcc_base + RCC_DDRCAPBCFGR, RCC_DDRCAPBCFGR_DDRCAPBRST);
/* Deactivate clocks and PLL2 */
mmio_clrbits_32(rcc_base + RCC_DDRPHYCCFGR, RCC_DDRPHYCCFGR_DDRPHYCEN);
mmio_clrbits_32(rcc_base + RCC_PLL2CFGR1, RCC_PLL2CFGR1_PLLEN);
}

View file

@ -0,0 +1,210 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
*/
#include <errno.h>
#include <arch_helpers.h>
#include <common/debug.h>
#include <common/fdt_wrappers.h>
#include <drivers/clk.h>
#include <drivers/st/stm32mp2_ddr.h>
#include <drivers/st/stm32mp2_ddr_helpers.h>
#include <drivers/st/stm32mp2_ram.h>
#include <drivers/st/stm32mp_ddr.h>
#include <drivers/st/stm32mp_ddr_test.h>
#include <drivers/st/stm32mp_ram.h>
#include <lib/mmio.h>
#include <libfdt.h>
#include <platform_def.h>
static struct stm32mp_ddr_priv ddr_priv_data;
static bool ddr_self_refresh;
static int ddr_dt_get_ui_param(void *fdt, int node, struct stm32mp_ddr_config *config)
{
int ret;
uint32_t size;
size = sizeof(struct user_input_basic) / sizeof(int);
ret = fdt_read_uint32_array(fdt, node, "st,phy-basic", size, (uint32_t *)&config->uib);
VERBOSE("%s: %s[0x%x] = %d\n", __func__, "st,phy-basic", size, ret);
if (ret != 0) {
ERROR("%s: can't read %s, error=%d\n", __func__, "st,phy-basic", ret);
return -EINVAL;
}
size = sizeof(struct user_input_advanced) / sizeof(int);
ret = fdt_read_uint32_array(fdt, node, "st,phy-advanced", size, (uint32_t *)&config->uia);
VERBOSE("%s: %s[0x%x] = %d\n", __func__, "st,phy-advanced", size, ret);
if (ret != 0) {
ERROR("%s: can't read %s, error=%d\n", __func__, "st,phy-advanced", ret);
return -EINVAL;
}
size = sizeof(struct user_input_mode_register) / sizeof(int);
ret = fdt_read_uint32_array(fdt, node, "st,phy-mr", size, (uint32_t *)&config->uim);
VERBOSE("%s: %s[0x%x] = %d\n", __func__, "st,phy-mr", size, ret);
if (ret != 0) {
ERROR("%s: can't read %s, error=%d\n", __func__, "st,phy-mr", ret);
return -EINVAL;
}
size = sizeof(struct user_input_swizzle) / sizeof(int);
ret = fdt_read_uint32_array(fdt, node, "st,phy-swizzle", size, (uint32_t *)&config->uis);
VERBOSE("%s: %s[0x%x] = %d\n", __func__, "st,phy-swizzle", size, ret);
if (ret != 0) {
ERROR("%s: can't read %s, error=%d\n", __func__, "st,phy-swizzle", ret);
return -EINVAL;
}
return 0;
}
static int stm32mp2_ddr_setup(void)
{
struct stm32mp_ddr_priv *priv = &ddr_priv_data;
int ret;
struct stm32mp_ddr_config config;
int node;
uintptr_t uret;
void *fdt;
const struct stm32mp_ddr_param param[] = {
CTL_PARAM(reg),
CTL_PARAM(timing),
CTL_PARAM(map),
CTL_PARAM(perf)
};
if (fdt_get_address(&fdt) == 0) {
return -ENOENT;
}
node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
if (node < 0) {
ERROR("%s: can't read DDR node in DT\n", __func__);
return -EINVAL;
}
ret = stm32mp_ddr_dt_get_info(fdt, node, &config.info);
if (ret < 0) {
return ret;
}
ret = stm32mp_ddr_dt_get_param(fdt, node, param, ARRAY_SIZE(param), (uintptr_t)&config);
if (ret < 0) {
return ret;
}
ret = ddr_dt_get_ui_param(fdt, node, &config);
if (ret < 0) {
return ret;
}
config.self_refresh = false;
if (stm32mp_is_wakeup_from_standby()) {
config.self_refresh = true;
}
/* Map dynamically RETRAM area to save or restore PHY retention registers */
if (stm32mp_map_retram() != 0) {
panic();
}
stm32mp2_ddr_init(priv, &config);
/* Unmap RETRAM, no more used until next DDR initialization call */
if (stm32mp_unmap_retram() != 0) {
panic();
}
priv->info.size = config.info.size;
VERBOSE("%s : ram size(%lx, %lx)\n", __func__, priv->info.base, priv->info.size);
if (stm32mp_map_ddr_non_cacheable() != 0) {
panic();
}
if (config.self_refresh) {
uret = stm32mp_ddr_test_rw_access();
if (uret != 0UL) {
ERROR("DDR rw test: can't access memory @ 0x%lx\n", uret);
panic();
}
/* TODO Restore area overwritten by training */
//stm32_restore_ddr_training_area();
} else {
size_t retsize;
uret = stm32mp_ddr_test_data_bus();
if (uret != 0UL) {
ERROR("DDR data bus test: can't access memory @ 0x%lx\n", uret);
panic();
}
uret = stm32mp_ddr_test_addr_bus(config.info.size);
if (uret != 0UL) {
ERROR("DDR addr bus test: can't access memory @ 0x%lx\n", uret);
panic();
}
retsize = stm32mp_ddr_check_size();
if (retsize < config.info.size) {
ERROR("DDR size: 0x%zx does not match DT config: 0x%zx\n",
retsize, config.info.size);
panic();
}
INFO("Memory size = 0x%zx (%zu MB)\n", retsize, retsize / (1024U * 1024U));
}
/*
* Initialization sequence has configured DDR registers with settings.
* The Self Refresh (SR) mode corresponding to these settings has now
* to be set.
*/
ddr_set_sr_mode(ddr_read_sr_mode());
if (stm32mp_unmap_ddr() != 0) {
panic();
}
/* Save DDR self_refresh state */
ddr_self_refresh = config.self_refresh;
return 0;
}
bool stm32mp2_ddr_is_restored(void)
{
return ddr_self_refresh;
}
int stm32mp2_ddr_probe(void)
{
struct stm32mp_ddr_priv *priv = &ddr_priv_data;
VERBOSE("STM32MP DDR probe\n");
priv->ctl = (struct stm32mp_ddrctl *)stm32mp_ddrctrl_base();
priv->phy = (struct stm32mp_ddrphy *)stm32mp_ddrphyc_base();
priv->pwr = stm32mp_pwr_base();
priv->rcc = stm32mp_rcc_base();
priv->info.base = STM32MP_DDR_BASE;
priv->info.size = 0;
return stm32mp2_ddr_setup();
}

View file

@ -44,9 +44,19 @@ void stm32mp_ddr_set_reg(const struct stm32mp_ddr_priv *priv, enum stm32mp_ddr_r
ddr_registers[type].name, i); ddr_registers[type].name, i);
panic(); panic();
} else { } else {
#if !STM32MP13 && !STM32MP15
if (desc[i].qd) {
stm32mp_ddr_start_sw_done(priv->ctl);
}
#endif
value = *((uint32_t *)((uintptr_t)param + value = *((uint32_t *)((uintptr_t)param +
desc[i].par_offset)); desc[i].par_offset));
mmio_write_32(ptr, value); mmio_write_32(ptr, value);
#if !STM32MP13 && !STM32MP15
if (desc[i].qd) {
stm32mp_ddr_wait_sw_done_ack(priv->ctl);
}
#endif
} }
} }
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2022-2023, STMicroelectronics - All Rights Reserved * Copyright (C) 2022-2024, STMicroelectronics - All Rights Reserved
* *
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*/ */
@ -10,8 +10,31 @@
#include <platform_def.h> #include <platform_def.h>
#ifdef __aarch64__
#define DDR_PATTERN 0xAAAAAAAAAAAAAAAAUL
#define DDR_ANTIPATTERN 0x5555555555555555UL
#else /* !__aarch64__ */
#define DDR_PATTERN 0xAAAAAAAAU #define DDR_PATTERN 0xAAAAAAAAU
#define DDR_ANTIPATTERN 0x55555555U #define DDR_ANTIPATTERN 0x55555555U
#endif /* __aarch64__ */
static void mmio_write_pattern(uintptr_t addr, u_register_t value)
{
#ifdef __aarch64__
mmio_write_64(addr, (uint64_t)value);
#else /* !__aarch64__ */
mmio_write_32(addr, (uint32_t)value);
#endif /* __aarch64__ */
}
static u_register_t mmio_read_pattern(uintptr_t addr)
{
#ifdef __aarch64__
return (u_register_t)mmio_read_64(addr);
#else /* !__aarch64__ */
return (u_register_t)mmio_read_32(addr);
#endif /* __aarch64__ */
}
/******************************************************************************* /*******************************************************************************
* This function tests a simple read/write access to the DDR. * This function tests a simple read/write access to the DDR.
@ -20,15 +43,15 @@
******************************************************************************/ ******************************************************************************/
uintptr_t stm32mp_ddr_test_rw_access(void) uintptr_t stm32mp_ddr_test_rw_access(void)
{ {
uint32_t saved_value = mmio_read_32(STM32MP_DDR_BASE); u_register_t saved_value = mmio_read_pattern(STM32MP_DDR_BASE);
mmio_write_32(STM32MP_DDR_BASE, DDR_PATTERN); mmio_write_pattern(STM32MP_DDR_BASE, DDR_PATTERN);
if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) { if (mmio_read_pattern(STM32MP_DDR_BASE) != DDR_PATTERN) {
return STM32MP_DDR_BASE; return STM32MP_DDR_BASE;
} }
mmio_write_32(STM32MP_DDR_BASE, saved_value); mmio_write_pattern(STM32MP_DDR_BASE, saved_value);
return 0UL; return 0UL;
} }
@ -43,12 +66,12 @@ uintptr_t stm32mp_ddr_test_rw_access(void)
******************************************************************************/ ******************************************************************************/
uintptr_t stm32mp_ddr_test_data_bus(void) uintptr_t stm32mp_ddr_test_data_bus(void)
{ {
uint32_t pattern; u_register_t pattern;
for (pattern = 1U; pattern != 0U; pattern <<= 1U) { for (pattern = 1U; pattern != 0U; pattern <<= 1U) {
mmio_write_32(STM32MP_DDR_BASE, pattern); mmio_write_pattern(STM32MP_DDR_BASE, pattern);
if (mmio_read_32(STM32MP_DDR_BASE) != pattern) { if (mmio_read_pattern(STM32MP_DDR_BASE) != pattern) {
return STM32MP_DDR_BASE; return STM32MP_DDR_BASE;
} }
} }
@ -72,41 +95,41 @@ uintptr_t stm32mp_ddr_test_addr_bus(size_t size)
size_t testoffset = 0U; size_t testoffset = 0U;
/* Write the default pattern at each of the power-of-two offsets. */ /* Write the default pattern at each of the power-of-two offsets. */
for (offset = sizeof(uint32_t); (offset & addressmask) != 0U; for (offset = sizeof(u_register_t); (offset & addressmask) != 0U;
offset <<= 1U) { offset <<= 1U) {
mmio_write_32(STM32MP_DDR_BASE + offset, DDR_PATTERN); mmio_write_pattern(STM32MP_DDR_BASE + offset, DDR_PATTERN);
} }
/* Check for address bits stuck high. */ /* Check for address bits stuck high. */
mmio_write_32(STM32MP_DDR_BASE + testoffset, DDR_ANTIPATTERN); mmio_write_pattern(STM32MP_DDR_BASE + testoffset, DDR_ANTIPATTERN);
for (offset = sizeof(uint32_t); (offset & addressmask) != 0U; for (offset = sizeof(u_register_t); (offset & addressmask) != 0U;
offset <<= 1U) { offset <<= 1U) {
if (mmio_read_32(STM32MP_DDR_BASE + offset) != DDR_PATTERN) { if (mmio_read_pattern(STM32MP_DDR_BASE + offset) != DDR_PATTERN) {
return STM32MP_DDR_BASE + offset; return STM32MP_DDR_BASE + offset;
} }
} }
mmio_write_32(STM32MP_DDR_BASE + testoffset, DDR_PATTERN); mmio_write_pattern(STM32MP_DDR_BASE + testoffset, DDR_PATTERN);
/* Check for address bits stuck low or shorted. */ /* Check for address bits stuck low or shorted. */
for (testoffset = sizeof(uint32_t); (testoffset & addressmask) != 0U; for (testoffset = sizeof(u_register_t); (testoffset & addressmask) != 0U;
testoffset <<= 1U) { testoffset <<= 1U) {
mmio_write_32(STM32MP_DDR_BASE + testoffset, DDR_ANTIPATTERN); mmio_write_pattern(STM32MP_DDR_BASE + testoffset, DDR_ANTIPATTERN);
if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) { if (mmio_read_pattern(STM32MP_DDR_BASE) != DDR_PATTERN) {
return STM32MP_DDR_BASE; return STM32MP_DDR_BASE;
} }
for (offset = sizeof(uint32_t); (offset & addressmask) != 0U; for (offset = sizeof(u_register_t); (offset & addressmask) != 0U;
offset <<= 1) { offset <<= 1U) {
if ((mmio_read_32(STM32MP_DDR_BASE + offset) != DDR_PATTERN) && if ((mmio_read_pattern(STM32MP_DDR_BASE + offset) != DDR_PATTERN) &&
(offset != testoffset)) { (offset != testoffset)) {
return STM32MP_DDR_BASE + offset; return STM32MP_DDR_BASE + offset;
} }
} }
mmio_write_32(STM32MP_DDR_BASE + testoffset, DDR_PATTERN); mmio_write_pattern(STM32MP_DDR_BASE + testoffset, DDR_PATTERN);
} }
return 0UL; return 0UL;
@ -121,15 +144,15 @@ uintptr_t stm32mp_ddr_test_addr_bus(size_t size)
******************************************************************************/ ******************************************************************************/
size_t stm32mp_ddr_check_size(void) size_t stm32mp_ddr_check_size(void)
{ {
size_t offset = sizeof(uint32_t); size_t offset = sizeof(u_register_t);
mmio_write_32(STM32MP_DDR_BASE, DDR_PATTERN); mmio_write_pattern(STM32MP_DDR_BASE, DDR_PATTERN);
while (offset < STM32MP_DDR_MAX_SIZE) { while (offset < STM32MP_DDR_MAX_SIZE) {
mmio_write_32(STM32MP_DDR_BASE + offset, DDR_ANTIPATTERN); mmio_write_pattern(STM32MP_DDR_BASE + offset, DDR_ANTIPATTERN);
dsb(); dsb();
if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) { if (mmio_read_pattern(STM32MP_DDR_BASE) != DDR_PATTERN) {
break; break;
} }

View file

@ -0,0 +1,147 @@
/*
* Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
*/
#ifndef STM32MP2_DDR_H
#define STM32MP2_DDR_H
#include <stdbool.h>
#include <ddrphy_phyinit_struct.h>
#include <drivers/st/stm32mp_ddr.h>
struct stm32mp2_ddrctrl_reg {
uint32_t mstr;
uint32_t mrctrl0;
uint32_t mrctrl1;
uint32_t mrctrl2;
uint32_t derateen;
uint32_t derateint;
uint32_t deratectl;
uint32_t pwrctl;
uint32_t pwrtmg;
uint32_t hwlpctl;
uint32_t rfshctl0;
uint32_t rfshctl1;
uint32_t rfshctl3;
uint32_t crcparctl0;
uint32_t crcparctl1;
uint32_t init0;
uint32_t init1;
uint32_t init2;
uint32_t init3;
uint32_t init4;
uint32_t init5;
uint32_t init6;
uint32_t init7;
uint32_t dimmctl;
uint32_t rankctl;
uint32_t rankctl1;
uint32_t zqctl0;
uint32_t zqctl1;
uint32_t zqctl2;
uint32_t dfitmg0;
uint32_t dfitmg1;
uint32_t dfilpcfg0;
uint32_t dfilpcfg1;
uint32_t dfiupd0;
uint32_t dfiupd1;
uint32_t dfiupd2;
uint32_t dfimisc;
uint32_t dfitmg2;
uint32_t dfitmg3;
uint32_t dbictl;
uint32_t dfiphymstr;
uint32_t dbg0;
uint32_t dbg1;
uint32_t dbgcmd;
uint32_t swctl;
uint32_t swctlstatic;
uint32_t poisoncfg;
uint32_t pccfg;
};
struct stm32mp2_ddrctrl_timing {
uint32_t rfshtmg;
uint32_t rfshtmg1;
uint32_t dramtmg0;
uint32_t dramtmg1;
uint32_t dramtmg2;
uint32_t dramtmg3;
uint32_t dramtmg4;
uint32_t dramtmg5;
uint32_t dramtmg6;
uint32_t dramtmg7;
uint32_t dramtmg8;
uint32_t dramtmg9;
uint32_t dramtmg10;
uint32_t dramtmg11;
uint32_t dramtmg12;
uint32_t dramtmg13;
uint32_t dramtmg14;
uint32_t dramtmg15;
uint32_t odtcfg;
uint32_t odtmap;
};
struct stm32mp2_ddrctrl_map {
uint32_t addrmap0;
uint32_t addrmap1;
uint32_t addrmap2;
uint32_t addrmap3;
uint32_t addrmap4;
uint32_t addrmap5;
uint32_t addrmap6;
uint32_t addrmap7;
uint32_t addrmap8;
uint32_t addrmap9;
uint32_t addrmap10;
uint32_t addrmap11;
};
struct stm32mp2_ddrctrl_perf {
uint32_t sched;
uint32_t sched1;
uint32_t perfhpr1;
uint32_t perflpr1;
uint32_t perfwr1;
uint32_t sched3;
uint32_t sched4;
uint32_t pcfgr_0;
uint32_t pcfgw_0;
uint32_t pctrl_0;
uint32_t pcfgqos0_0;
uint32_t pcfgqos1_0;
uint32_t pcfgwqos0_0;
uint32_t pcfgwqos1_0;
#if STM32MP_DDR_DUAL_AXI_PORT
uint32_t pcfgr_1;
uint32_t pcfgw_1;
uint32_t pctrl_1;
uint32_t pcfgqos0_1;
uint32_t pcfgqos1_1;
uint32_t pcfgwqos0_1;
uint32_t pcfgwqos1_1;
#endif /* STM32MP_DDR_DUAL_AXI_PORT */
};
struct stm32mp_ddr_config {
struct stm32mp_ddr_info info;
struct stm32mp2_ddrctrl_reg c_reg;
struct stm32mp2_ddrctrl_timing c_timing;
struct stm32mp2_ddrctrl_map c_map;
struct stm32mp2_ddrctrl_perf c_perf;
bool self_refresh;
uint32_t zdata;
struct user_input_basic uib;
struct user_input_advanced uia;
struct user_input_mode_register uim;
struct user_input_swizzle uis;
};
void stm32mp2_ddr_init(struct stm32mp_ddr_priv *priv, struct stm32mp_ddr_config *config);
#endif /* STM32MP2_DDR_H */

View file

@ -7,6 +7,29 @@
#ifndef STM32MP2_DDR_HELPERS_H #ifndef STM32MP2_DDR_HELPERS_H
#define STM32MP2_DDR_HELPERS_H #define STM32MP2_DDR_HELPERS_H
#include <stdbool.h>
#include <stdint.h>
#include <drivers/st/stm32mp2_ddr_regs.h>
enum stm32mp2_ddr_sr_mode {
DDR_SR_MODE_INVALID = 0,
DDR_SSR_MODE,
DDR_HSR_MODE,
DDR_ASR_MODE,
};
void ddr_activate_controller(struct stm32mp_ddrctl *ctl, bool sr_entry);
void ddr_wait_lp3_mode(bool state);
int ddr_sr_exit_loop(void);
uint32_t ddr_get_io_calibration_val(void);
int ddr_sr_entry(bool standby);
int ddr_sr_exit(void);
enum stm32mp2_ddr_sr_mode ddr_read_sr_mode(void);
void ddr_set_sr_mode(enum stm32mp2_ddr_sr_mode mode);
void ddr_save_sr_mode(void);
void ddr_restore_sr_mode(void);
void ddr_sub_system_clk_init(void); void ddr_sub_system_clk_init(void);
void ddr_sub_system_clk_off(void);
#endif /* STM32MP2_DDR_HELPERS_H */ #endif /* STM32MP2_DDR_HELPERS_H */

View file

@ -0,0 +1,38 @@
/*
* Copyright (c) 2021-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
*/
#ifndef STM32MP2_DDR_REGS_H
#define STM32MP2_DDR_REGS_H
#include <drivers/st/stm32mp_ddrctrl_regs.h>
#include <lib/utils_def.h>
/* DDR Physical Interface Control (DDRPHYC) registers*/
struct stm32mp_ddrphy {
uint32_t dummy;
} __packed;
/* DDRPHY registers offsets */
#define DDRPHY_INITENG0_P0_SEQ0BDISABLEFLAG6 U(0x240004)
#define DDRPHY_INITENG0_P0_PHYINLPX U(0x2400A0)
#define DDRPHY_DRTUB0_UCCLKHCLKENABLES U(0x300200)
#define DDRPHY_APBONLY0_MICROCONTMUXSEL U(0x340000)
/* DDRPHY registers fields */
#define DDRPHY_INITENG0_P0_PHYINLPX_PHYINLP3 BIT(0)
#define DDRPHY_DRTUB0_UCCLKHCLKENABLES_UCCLKEN BIT(0)
#define DDRPHY_DRTUB0_UCCLKHCLKENABLES_HCLKEN BIT(1)
#define DDRPHY_APBONLY0_MICROCONTMUXSEL_MICROCONTMUXSEL BIT(0)
/* DDRDBG registers offsets */
#define DDRDBG_LP_DISABLE U(0x0)
#define DDRDBG_BYPASS_PCLKEN U(0x4)
/* DDRDBG registers fields */
#define DDRDBG_LP_DISABLE_LPI_XPI_DISABLE BIT(0)
#define DDRDBG_LP_DISABLE_LPI_DDRC_DISABLE BIT(8)
#endif /* STM32MP2_DDR_REGS_H */

View file

@ -0,0 +1,13 @@
/*
* Copyright (c) 2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef STM32MP2_RAM_H
#define STM32MP2_RAM_H
bool stm32mp2_ddr_is_restored(void);
int stm32mp2_ddr_probe(void);
#endif /* STM32MP2_RAM_H */

View file

@ -28,6 +28,9 @@ enum stm32mp_ddr_reg_type {
struct stm32mp_ddr_reg_desc { struct stm32mp_ddr_reg_desc {
uint16_t offset; /* Offset for base address */ uint16_t offset; /* Offset for base address */
uint8_t par_offset; /* Offset for parameter array */ uint8_t par_offset; /* Offset for parameter array */
#if !STM32MP13 && !STM32MP15
bool qd; /* quasi-dynamic register if true */
#endif
}; };
struct stm32mp_ddr_reg_info { struct stm32mp_ddr_reg_info {

View file

@ -51,7 +51,8 @@ struct stm32mp_ddrctl {
uint32_t init7; /* 0xec SDRAM Initialization 7 */ uint32_t init7; /* 0xec SDRAM Initialization 7 */
uint32_t dimmctl; /* 0xf0 DIMM Control */ uint32_t dimmctl; /* 0xf0 DIMM Control */
uint32_t rankctl; /* 0xf4 Rank Control */ uint32_t rankctl; /* 0xf4 Rank Control */
uint8_t reserved0f4[0x100 - 0xf8]; uint32_t rankctl1; /* 0xf8 Rank Control 1 */
uint8_t reserved0fc[0x100 - 0xfc];
uint32_t dramtmg0; /* 0x100 SDRAM Timing 0 */ uint32_t dramtmg0; /* 0x100 SDRAM Timing 0 */
uint32_t dramtmg1; /* 0x104 SDRAM Timing 1 */ uint32_t dramtmg1; /* 0x104 SDRAM Timing 1 */
uint32_t dramtmg2; /* 0x108 SDRAM Timing 2 */ uint32_t dramtmg2; /* 0x108 SDRAM Timing 2 */
@ -112,7 +113,9 @@ struct stm32mp_ddrctl {
uint32_t perflpr1; /* 0x264 Low Priority Read CAM 1 */ uint32_t perflpr1; /* 0x264 Low Priority Read CAM 1 */
uint32_t reserved268; uint32_t reserved268;
uint32_t perfwr1; /* 0x26c Write CAM 1 */ uint32_t perfwr1; /* 0x26c Write CAM 1 */
uint8_t reserved27c[0x300 - 0x270]; uint32_t sched3; /* 0x270 Scheduler Control 3 */
uint32_t sched4; /* 0x274 Scheduler Control 4 */
uint8_t reserved278[0x300 - 0x278];
uint32_t dbg0; /* 0x300 Debug 0 */ uint32_t dbg0; /* 0x300 Debug 0 */
uint32_t dbg1; /* 0x304 Debug 1 */ uint32_t dbg1; /* 0x304 Debug 1 */
uint32_t dbgcam; /* 0x308 CAM Debug */ uint32_t dbgcam; /* 0x308 CAM Debug */
@ -121,7 +124,8 @@ struct stm32mp_ddrctl {
uint8_t reserved314[0x320 - 0x314]; uint8_t reserved314[0x320 - 0x314];
uint32_t swctl; /* 0x320 Software Programming Control Enable */ uint32_t swctl; /* 0x320 Software Programming Control Enable */
uint32_t swstat; /* 0x324 Software Programming Control Status */ uint32_t swstat; /* 0x324 Software Programming Control Status */
uint8_t reserved328[0x36c - 0x328]; uint32_t swctlstatic; /* 0x328 Statics Write Enable */
uint8_t reserved32c[0x36c - 0x32c];
uint32_t poisoncfg; /* 0x36c AXI Poison Configuration Register */ uint32_t poisoncfg; /* 0x36c AXI Poison Configuration Register */
uint32_t poisonstat; /* 0x370 AXI Poison Status Register */ uint32_t poisonstat; /* 0x370 AXI Poison Status Register */
uint8_t reserved374[0x3f0 - 0x374]; uint8_t reserved374[0x3f0 - 0x374];
@ -153,7 +157,7 @@ struct stm32mp_ddrctl {
uint32_t pcfgqos1_1; /* 0x548 Read QoS Configuration 1 */ uint32_t pcfgqos1_1; /* 0x548 Read QoS Configuration 1 */
uint32_t pcfgwqos0_1; /* 0x54c Write QoS Configuration 0 */ uint32_t pcfgwqos0_1; /* 0x54c Write QoS Configuration 0 */
uint32_t pcfgwqos1_1; /* 0x550 Write QoS Configuration 1 */ uint32_t pcfgwqos1_1; /* 0x550 Write QoS Configuration 1 */
#endif #endif /* STM32MP_DDR_DUAL_AXI_PORT */
uint8_t reserved554[0xff0 - 0x554]; uint8_t reserved554[0xff0 - 0x554];
uint32_t umctl2_ver_number; /* 0xff0 UMCTL2 Version Number */ uint32_t umctl2_ver_number; /* 0xff0 UMCTL2 Version Number */
@ -170,6 +174,7 @@ struct stm32mp_ddrctl {
#define DDRCTRL_RFSHCTL3 0x060 #define DDRCTRL_RFSHCTL3 0x060
#define DDRCTRL_RFSHTMG 0x064 #define DDRCTRL_RFSHTMG 0x064
#define DDRCTRL_INIT0 0x0D0 #define DDRCTRL_INIT0 0x0D0
#define DDRCTRL_DFILPCFG0 0x198
#define DDRCTRL_DFIMISC 0x1B0 #define DDRCTRL_DFIMISC 0x1B0
#define DDRCTRL_DBG1 0x304 #define DDRCTRL_DBG1 0x304
#define DDRCTRL_DBGCAM 0x308 #define DDRCTRL_DBGCAM 0x308
@ -181,7 +186,7 @@ struct stm32mp_ddrctl {
#define DDRCTRL_PCTRL_0 0x490 #define DDRCTRL_PCTRL_0 0x490
#if STM32MP_DDR_DUAL_AXI_PORT #if STM32MP_DDR_DUAL_AXI_PORT
#define DDRCTRL_PCTRL_1 0x540 #define DDRCTRL_PCTRL_1 0x540
#endif #endif /* STM32MP_DDR_DUAL_AXI_PORT */
/* DDR Controller Register fields */ /* DDR Controller Register fields */
#define DDRCTRL_MSTR_DDR3 BIT(0) #define DDRCTRL_MSTR_DDR3 BIT(0)
@ -201,6 +206,8 @@ struct stm32mp_ddrctl {
#define DDRCTRL_STAT_SELFREF_TYPE_MASK GENMASK(5, 4) #define DDRCTRL_STAT_SELFREF_TYPE_MASK GENMASK(5, 4)
#define DDRCTRL_STAT_SELFREF_TYPE_ASR (BIT(4) | BIT(5)) #define DDRCTRL_STAT_SELFREF_TYPE_ASR (BIT(4) | BIT(5))
#define DDRCTRL_STAT_SELFREF_TYPE_SR BIT(5) #define DDRCTRL_STAT_SELFREF_TYPE_SR BIT(5)
#define DDRCTRL_STAT_SELFREF_STATE_MASK GENMASK(9, 8)
#define DDRCTRL_STAT_SELFREF_STATE_SRPD BIT(9)
#define DDRCTRL_MRCTRL0_MR_TYPE_WRITE U(0) #define DDRCTRL_MRCTRL0_MR_TYPE_WRITE U(0)
/* Only one rank supported */ /* Only one rank supported */
@ -217,6 +224,7 @@ struct stm32mp_ddrctl {
#define DDRCTRL_PWRCTL_POWERDOWN_EN BIT(1) #define DDRCTRL_PWRCTL_POWERDOWN_EN BIT(1)
#define DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE BIT(3) #define DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE BIT(3)
#define DDRCTRL_PWRCTL_SELFREF_SW BIT(5) #define DDRCTRL_PWRCTL_SELFREF_SW BIT(5)
#define DDRCTRL_PWRCTL_STAY_IN_SELFREF BIT(6)
#define DDRCTRL_PWRTMG_SELFREF_TO_X32_MASK GENMASK(23, 16) #define DDRCTRL_PWRTMG_SELFREF_TO_X32_MASK GENMASK(23, 16)
#define DDRCTRL_PWRTMG_SELFREF_TO_X32_0 BIT(16) #define DDRCTRL_PWRTMG_SELFREF_TO_X32_0 BIT(16)
@ -225,6 +233,9 @@ struct stm32mp_ddrctl {
#define DDRCTRL_RFSHCTL3_REFRESH_UPDATE_LEVEL BIT(1) #define DDRCTRL_RFSHCTL3_REFRESH_UPDATE_LEVEL BIT(1)
#define DDRCTRL_HWLPCTL_HW_LP_EN BIT(0) #define DDRCTRL_HWLPCTL_HW_LP_EN BIT(0)
#define DDRCTRL_HWLPCTL_HW_LP_EXIT_IDLE_EN BIT(1)
#define DDRCTRL_HWLPCTL_HW_LP_IDLE_X32_MASK GENMASK(27, 16)
#define DDRCTRL_HWLPCTL_HW_LP_IDLE_X32_SHIFT 16
#define DDRCTRL_RFSHTMG_T_RFC_NOM_X1_X32_MASK GENMASK(27, 16) #define DDRCTRL_RFSHTMG_T_RFC_NOM_X1_X32_MASK GENMASK(27, 16)
#define DDRCTRL_RFSHTMG_T_RFC_NOM_X1_X32_SHIFT 16 #define DDRCTRL_RFSHTMG_T_RFC_NOM_X1_X32_SHIFT 16
@ -232,11 +243,16 @@ struct stm32mp_ddrctl {
#define DDRCTRL_INIT0_SKIP_DRAM_INIT_MASK GENMASK(31, 30) #define DDRCTRL_INIT0_SKIP_DRAM_INIT_MASK GENMASK(31, 30)
#define DDRCTRL_INIT0_SKIP_DRAM_INIT_NORMAL BIT(30) #define DDRCTRL_INIT0_SKIP_DRAM_INIT_NORMAL BIT(30)
#define DDRCTRL_DFILPCFG0_DFI_LP_EN_SR BIT(8)
#define DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN BIT(0) #define DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN BIT(0)
#define DDRCTRL_DFIMISC_DFI_INIT_START BIT(5) #define DDRCTRL_DFIMISC_DFI_INIT_START BIT(5)
#define DDRCTRL_DFIMISC_DFI_FREQUENCY GENMASK(12, 8)
#define DDRCTRL_DFISTAT_DFI_INIT_COMPLETE BIT(0) #define DDRCTRL_DFISTAT_DFI_INIT_COMPLETE BIT(0)
#define DDRCTRL_DFISTAT_DFI_LP_ACK BIT(1)
#define DDRCTRL_DBG1_DIS_DQ BIT(0)
#define DDRCTRL_DBG1_DIS_HIF BIT(1) #define DDRCTRL_DBG1_DIS_HIF BIT(1)
#define DDRCTRL_DBGCAM_WR_DATA_PIPELINE_EMPTY BIT(29) #define DDRCTRL_DBGCAM_WR_DATA_PIPELINE_EMPTY BIT(29)

View file

@ -9,11 +9,13 @@
#include <stdint.h> #include <stdint.h>
#include <common/fdt_wrappers.h> #include <common/fdt_wrappers.h>
#include <drivers/delay_timer.h> #include <drivers/delay_timer.h>
#include <drivers/st/regulator.h> #include <drivers/st/regulator.h>
#include <drivers/st/stm32mp_ddr.h> #include <drivers/st/stm32mp_ddr.h>
#include <libfdt.h> #include <libfdt.h>
#include <platform_def.h> #include <platform_def.h>
#if STM32MP_DDR3_TYPE #if STM32MP_DDR3_TYPE

View file

@ -42,6 +42,7 @@ DDR_TYPE := lpddr4
endif endif
# DDR features # DDR features
STM32MP_DDR_DUAL_AXI_PORT := 1
STM32MP_DDR_FIP_IO_STORAGE := 1 STM32MP_DDR_FIP_IO_STORAGE := 1
# Device tree # Device tree
@ -71,6 +72,7 @@ endif
# Enable flags for C files # Enable flags for C files
$(eval $(call assert_booleans,\ $(eval $(call assert_booleans,\
$(sort \ $(sort \
STM32MP_DDR_DUAL_AXI_PORT \
STM32MP_DDR_FIP_IO_STORAGE \ STM32MP_DDR_FIP_IO_STORAGE \
STM32MP_DDR3_TYPE \ STM32MP_DDR3_TYPE \
STM32MP_DDR4_TYPE \ STM32MP_DDR4_TYPE \
@ -92,6 +94,7 @@ $(eval $(call add_defines,\
PLAT_PARTITION_MAX_ENTRIES \ PLAT_PARTITION_MAX_ENTRIES \
PLAT_TBBR_IMG_DEF \ PLAT_TBBR_IMG_DEF \
STM32_TF_A_COPIES \ STM32_TF_A_COPIES \
STM32MP_DDR_DUAL_AXI_PORT \
STM32MP_DDR_FIP_IO_STORAGE \ STM32MP_DDR_FIP_IO_STORAGE \
STM32MP_DDR3_TYPE \ STM32MP_DDR3_TYPE \
STM32MP_DDR4_TYPE \ STM32MP_DDR4_TYPE \
@ -105,6 +108,8 @@ TF_CFLAGS += -mbranch-protection=none
# Include paths and source files # Include paths and source files
PLAT_INCLUDES += -Iplat/st/stm32mp2/include/ PLAT_INCLUDES += -Iplat/st/stm32mp2/include/
PLAT_INCLUDES += -Idrivers/st/ddr/phy/phyinit/include/
PLAT_INCLUDES += -Idrivers/st/ddr/phy/firmware/include/
PLAT_BL_COMMON_SOURCES += lib/cpus/${ARCH}/cortex_a35.S PLAT_BL_COMMON_SOURCES += lib/cpus/${ARCH}/cortex_a35.S
PLAT_BL_COMMON_SOURCES += drivers/st/uart/${ARCH}/stm32_console.S PLAT_BL_COMMON_SOURCES += drivers/st/uart/${ARCH}/stm32_console.S
@ -137,7 +142,30 @@ ifeq (${STM32MP_USB_PROGRAMMER},1)
BL2_SOURCES += plat/st/stm32mp2/stm32mp2_usb_dfu.c BL2_SOURCES += plat/st/stm32mp2/stm32mp2_usb_dfu.c
endif endif
BL2_SOURCES += drivers/st/ddr/stm32mp2_ddr_helpers.c BL2_SOURCES += drivers/st/ddr/stm32mp2_ddr.c \
drivers/st/ddr/stm32mp2_ddr_helpers.c \
drivers/st/ddr/stm32mp2_ram.c
BL2_SOURCES += drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_c_initphyconfig.c \
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_calcmb.c \
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_i_loadpieimage.c \
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_initstruct.c \
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_isdbytedisabled.c \
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_loadpieprodcode.c \
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_mapdrvstren.c \
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_progcsrskiptrain.c \
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_reginterface.c \
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_restore_sequence.c \
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_sequence.c \
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_softsetmb.c \
drivers/st/ddr/phy/phyinit/usercustom/ddrphy_phyinit_usercustom_custompretrain.c \
drivers/st/ddr/phy/phyinit/usercustom/ddrphy_phyinit_usercustom_saveretregs.c
BL2_SOURCES += drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_d_loadimem.c \
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_f_loaddmem.c \
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_g_execfw.c \
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_writeoutmem.c \
drivers/st/ddr/phy/phyinit/usercustom/ddrphy_phyinit_usercustom_g_waitfwdone.c
# BL31 sources # BL31 sources
BL31_SOURCES += ${FDT_WRAPPERS_SOURCES} BL31_SOURCES += ${FDT_WRAPPERS_SOURCES}

View file

@ -153,6 +153,8 @@ enum ddr_type {
#if STM32MP_DDR_FIP_IO_STORAGE #if STM32MP_DDR_FIP_IO_STORAGE
#define STM32MP_DDR_FW_BASE SRAM1_BASE #define STM32MP_DDR_FW_BASE SRAM1_BASE
#define STM32MP_DDR_FW_DMEM_OFFSET U(0x400)
#define STM32MP_DDR_FW_IMEM_OFFSET U(0x800)
#define STM32MP_DDR_FW_MAX_SIZE U(0x8800) #define STM32MP_DDR_FW_MAX_SIZE U(0x8800)
#endif #endif