mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-18 10:34:19 +00:00
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:
parent
d596023bff
commit
79629b1a79
41 changed files with 18361 additions and 31 deletions
935
drivers/st/ddr/phy/firmware/include/mnpmusrammsgblock_ddr3.h
Normal file
935
drivers/st/ddr/phy/firmware/include/mnpmusrammsgblock_ddr3.h
Normal 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 */
|
2203
drivers/st/ddr/phy/firmware/include/mnpmusrammsgblock_ddr4.h
Normal file
2203
drivers/st/ddr/phy/firmware/include/mnpmusrammsgblock_ddr4.h
Normal file
File diff suppressed because it is too large
Load diff
925
drivers/st/ddr/phy/firmware/include/mnpmusrammsgblock_lpddr4.h
Normal file
925
drivers/st/ddr/phy/firmware/include/mnpmusrammsgblock_lpddr4.h
Normal 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 */
|
6944
drivers/st/ddr/phy/phyinit/include/ddrphy_csr_all_cdefines.h
Normal file
6944
drivers/st/ddr/phy/phyinit/include/ddrphy_csr_all_cdefines.h
Normal file
File diff suppressed because it is too large
Load diff
37
drivers/st/ddr/phy/phyinit/include/ddrphy_phyinit.h
Normal file
37
drivers/st/ddr/phy/phyinit/include/ddrphy_phyinit.h
Normal 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 */
|
786
drivers/st/ddr/phy/phyinit/include/ddrphy_phyinit_struct.h
Normal file
786
drivers/st/ddr/phy/phyinit/include/ddrphy_phyinit_struct.h
Normal 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 */
|
118
drivers/st/ddr/phy/phyinit/include/ddrphy_phyinit_usercustom.h
Normal file
118
drivers/st/ddr/phy/phyinit/include/ddrphy_phyinit_usercustom.h
Normal 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 */
|
20
drivers/st/ddr/phy/phyinit/include/ddrphy_wrapper.h
Normal file
20
drivers/st/ddr/phy/phyinit/include/ddrphy_wrapper.h
Normal 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 */
|
1139
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_c_initphyconfig.c
Normal file
1139
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_c_initphyconfig.c
Normal file
File diff suppressed because it is too large
Load diff
210
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_calcmb.c
Normal file
210
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_calcmb.c
Normal 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;
|
||||||
|
}
|
43
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_d_loadimem.c
Normal file
43
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_d_loadimem.c
Normal 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);
|
||||||
|
}
|
70
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_f_loaddmem.c
Normal file
70
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_f_loaddmem.c
Normal 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;
|
||||||
|
}
|
66
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_g_execfw.c
Normal file
66
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_g_execfw.c
Normal 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;
|
||||||
|
}
|
394
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_i_loadpieimage.c
Normal file
394
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_i_loadpieimage.c
Normal 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);
|
||||||
|
}
|
262
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_initstruct.c
Normal file
262
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_initstruct.c
Normal 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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
189
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_loadpieprodcode.c
Normal file
189
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_loadpieprodcode.c
Normal 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]);
|
||||||
|
}
|
||||||
|
}
|
282
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_mapdrvstren.c
Normal file
282
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_mapdrvstren.c
Normal 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;
|
||||||
|
}
|
893
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_progcsrskiptrain.c
Normal file
893
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_progcsrskiptrain.c
Normal 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);
|
||||||
|
}
|
170
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_reginterface.c
Normal file
170
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_reginterface.c
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
121
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_sequence.c
Normal file
121
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_sequence.c
Normal 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;
|
||||||
|
}
|
100
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_softsetmb.c
Normal file
100
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_softsetmb.c
Normal 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;
|
||||||
|
}
|
79
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_writeoutmem.c
Normal file
79
drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_writeoutmem.c
Normal 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);
|
||||||
|
}
|
|
@ -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 */
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
479
drivers/st/ddr/stm32mp2_ddr.c
Normal file
479
drivers/st/ddr/stm32mp2_ddr.c
Normal 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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
210
drivers/st/ddr/stm32mp2_ram.c
Normal file
210
drivers/st/ddr/stm32mp2_ram.c
Normal 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();
|
||||||
|
}
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
147
include/drivers/st/stm32mp2_ddr.h
Normal file
147
include/drivers/st/stm32mp2_ddr.h
Normal 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 */
|
|
@ -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 */
|
||||||
|
|
38
include/drivers/st/stm32mp2_ddr_regs.h
Normal file
38
include/drivers/st/stm32mp2_ddr_regs.h
Normal 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 */
|
13
include/drivers/st/stm32mp2_ram.h
Normal file
13
include/drivers/st/stm32mp2_ram.h
Normal 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 */
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue