1*79629b1aSNicolas Le Bayon /*
2*79629b1aSNicolas Le Bayon * Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
3*79629b1aSNicolas Le Bayon *
4*79629b1aSNicolas Le Bayon * SPDX-License-Identifier: BSD-3-Clause
5*79629b1aSNicolas Le Bayon */
6*79629b1aSNicolas Le Bayon
7*79629b1aSNicolas Le Bayon #include <stdlib.h>
8*79629b1aSNicolas Le Bayon
9*79629b1aSNicolas Le Bayon #include <common/debug.h>
10*79629b1aSNicolas Le Bayon
11*79629b1aSNicolas Le Bayon #include <ddrphy_phyinit.h>
12*79629b1aSNicolas Le Bayon
13*79629b1aSNicolas Le Bayon /*
14*79629b1aSNicolas Le Bayon * Reads PhyInit inputs structures and sets relevant message block
15*79629b1aSNicolas Le Bayon * parameters.
16*79629b1aSNicolas Le Bayon *
17*79629b1aSNicolas Le Bayon * This function sets Message Block parameters based on user_input_basic and
18*79629b1aSNicolas Le Bayon * user_input_advanced. user changes in these files takes precedence
19*79629b1aSNicolas Le Bayon * over this function call.
20*79629b1aSNicolas Le Bayon *
21*79629b1aSNicolas Le Bayon * MessageBlock fields set :
22*79629b1aSNicolas Le Bayon * - dramtype
23*79629b1aSNicolas Le Bayon * - pstate
24*79629b1aSNicolas Le Bayon * - dramfreq
25*79629b1aSNicolas Le Bayon * - pllbypassen
26*79629b1aSNicolas Le Bayon * - dfifreqratio
27*79629b1aSNicolas Le Bayon * - phyodtimpedance
28*79629b1aSNicolas Le Bayon * - phydrvimpedance
29*79629b1aSNicolas Le Bayon * - bpznresval
30*79629b1aSNicolas Le Bayon * - enableddqscha (LPDDR4)
31*79629b1aSNicolas Le Bayon * - cspresentcha (LPDDR4)
32*79629b1aSNicolas Le Bayon * - enableddqsChb (LPDDR4)
33*79629b1aSNicolas Le Bayon * - cspresentchb (LPDDR4)
34*79629b1aSNicolas Le Bayon * - enableddqs (DDR3/DDR4)
35*79629b1aSNicolas Le Bayon * - phycfg (DDR3/DDR4)
36*79629b1aSNicolas Le Bayon * - x16present (DDR4)
37*79629b1aSNicolas Le Bayon *
38*79629b1aSNicolas Le Bayon * \return 0 on success.
39*79629b1aSNicolas Le Bayon */
ddrphy_phyinit_calcmb(struct stm32mp_ddr_config * config,struct pmu_smb_ddr_1d * mb_ddr_1d)40*79629b1aSNicolas Le Bayon int ddrphy_phyinit_calcmb(struct stm32mp_ddr_config *config, struct pmu_smb_ddr_1d *mb_ddr_1d)
41*79629b1aSNicolas Le Bayon {
42*79629b1aSNicolas Le Bayon uint32_t nad0 = config->uib.numactivedbytedfi0;
43*79629b1aSNicolas Le Bayon uint32_t nad1 = 0;
44*79629b1aSNicolas Le Bayon uint16_t mr4 __maybe_unused;
45*79629b1aSNicolas Le Bayon uint16_t disableddbyte __maybe_unused;
46*79629b1aSNicolas Le Bayon uint32_t dbyte __maybe_unused;
47*79629b1aSNicolas Le Bayon int ret;
48*79629b1aSNicolas Le Bayon
49*79629b1aSNicolas Le Bayon #if STM32MP_LPDDR4_TYPE
50*79629b1aSNicolas Le Bayon nad1 = config->uib.numactivedbytedfi1;
51*79629b1aSNicolas Le Bayon #endif /* STM32MP_LPDDR4_TYPE */
52*79629b1aSNicolas Le Bayon
53*79629b1aSNicolas Le Bayon /* A few checks to make sure valid programming */
54*79629b1aSNicolas Le Bayon if ((nad0 == 0U) || (config->uib.numdbyte == 0U)) {
55*79629b1aSNicolas Le Bayon ERROR("%s %d\n", __func__, __LINE__);
56*79629b1aSNicolas Le Bayon VERBOSE("%s numactivedbytedfi0, numactivedbytedfi0, NumByte out of range.\n",
57*79629b1aSNicolas Le Bayon __func__);
58*79629b1aSNicolas Le Bayon return -1;
59*79629b1aSNicolas Le Bayon }
60*79629b1aSNicolas Le Bayon
61*79629b1aSNicolas Le Bayon if ((nad0 + nad1) > config->uib.numdbyte) {
62*79629b1aSNicolas Le Bayon ERROR("%s %d\n", __func__, __LINE__);
63*79629b1aSNicolas Le Bayon VERBOSE("%s numactivedbytedfi0+numactivedbytedfi1 is larger than numdbyteDfi0\n",
64*79629b1aSNicolas Le Bayon __func__);
65*79629b1aSNicolas Le Bayon return -1;
66*79629b1aSNicolas Le Bayon }
67*79629b1aSNicolas Le Bayon
68*79629b1aSNicolas Le Bayon if ((config->uib.dfi1exists == 0U) && (nad1 != 0U)) {
69*79629b1aSNicolas Le Bayon ERROR("%s %d\n", __func__, __LINE__);
70*79629b1aSNicolas Le Bayon VERBOSE("%s dfi1exists==0 but numdbyteDfi0 != 0\n", __func__);
71*79629b1aSNicolas Le Bayon return -1;
72*79629b1aSNicolas Le Bayon }
73*79629b1aSNicolas Le Bayon
74*79629b1aSNicolas Le Bayon #if STM32MP_DDR4_TYPE
75*79629b1aSNicolas Le Bayon /* OR all mr4 masked values, to help check in next loop */
76*79629b1aSNicolas Le Bayon mr4 = mb_ddr_1d->mr4 & 0x1C0U;
77*79629b1aSNicolas Le Bayon
78*79629b1aSNicolas Le Bayon /* 1D message block defaults */
79*79629b1aSNicolas Le Bayon if (mr4 != 0x0U) {
80*79629b1aSNicolas Le Bayon ERROR("mr4 != 0x0\n");
81*79629b1aSNicolas Le Bayon VERBOSE("%s Setting DRAM CAL mode is not supported by the PHY.\n", __func__);
82*79629b1aSNicolas Le Bayon VERBOSE("Memory controller may set CAL mode after PHY has entered mission\n");
83*79629b1aSNicolas Le Bayon VERBOSE("mode. Please check value programmed in mb_ddr_1d[*].mr4\n");
84*79629b1aSNicolas Le Bayon VERBOSE("and unset A8:6\n");
85*79629b1aSNicolas Le Bayon return -1;
86*79629b1aSNicolas Le Bayon }
87*79629b1aSNicolas Le Bayon #endif /* STM32MP_DDR4_TYPE */
88*79629b1aSNicolas Le Bayon
89*79629b1aSNicolas Le Bayon #if STM32MP_DDR3_TYPE
90*79629b1aSNicolas Le Bayon if (config->uib.dimmtype == DDR_DIMMTYPE_NODIMM) {
91*79629b1aSNicolas Le Bayon ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_DRAMTYPE, 0x1U);
92*79629b1aSNicolas Le Bayon if (ret != 0) {
93*79629b1aSNicolas Le Bayon return ret;
94*79629b1aSNicolas Le Bayon }
95*79629b1aSNicolas Le Bayon }
96*79629b1aSNicolas Le Bayon #elif STM32MP_DDR4_TYPE
97*79629b1aSNicolas Le Bayon if (config->uib.dimmtype == DDR_DIMMTYPE_NODIMM) {
98*79629b1aSNicolas Le Bayon ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_DRAMTYPE, 0x2U);
99*79629b1aSNicolas Le Bayon if (ret != 0) {
100*79629b1aSNicolas Le Bayon return ret;
101*79629b1aSNicolas Le Bayon }
102*79629b1aSNicolas Le Bayon }
103*79629b1aSNicolas Le Bayon #else /* STM32MP_LPDDR4_TYPE */
104*79629b1aSNicolas Le Bayon /* Nothing to do */
105*79629b1aSNicolas Le Bayon #endif /* STM32MP_DDR3_TYPE */
106*79629b1aSNicolas Le Bayon
107*79629b1aSNicolas Le Bayon ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_PSTATE, 0U);
108*79629b1aSNicolas Le Bayon if (ret != 0) {
109*79629b1aSNicolas Le Bayon return ret;
110*79629b1aSNicolas Le Bayon }
111*79629b1aSNicolas Le Bayon
112*79629b1aSNicolas Le Bayon ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_DRAMFREQ, config->uib.frequency * 2U);
113*79629b1aSNicolas Le Bayon if (ret != 0) {
114*79629b1aSNicolas Le Bayon return ret;
115*79629b1aSNicolas Le Bayon }
116*79629b1aSNicolas Le Bayon
117*79629b1aSNicolas Le Bayon ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_PLLBYPASSEN, config->uib.pllbypass);
118*79629b1aSNicolas Le Bayon if (ret != 0) {
119*79629b1aSNicolas Le Bayon return ret;
120*79629b1aSNicolas Le Bayon }
121*79629b1aSNicolas Le Bayon
122*79629b1aSNicolas Le Bayon if (config->uib.dfifreqratio == 1U) {
123*79629b1aSNicolas Le Bayon ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_DFIFREQRATIO, 0x2U);
124*79629b1aSNicolas Le Bayon if (ret != 0) {
125*79629b1aSNicolas Le Bayon return ret;
126*79629b1aSNicolas Le Bayon }
127*79629b1aSNicolas Le Bayon }
128*79629b1aSNicolas Le Bayon
129*79629b1aSNicolas Le Bayon ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_PHYODTIMPEDANCE, 0U);
130*79629b1aSNicolas Le Bayon if (ret != 0) {
131*79629b1aSNicolas Le Bayon return ret;
132*79629b1aSNicolas Le Bayon }
133*79629b1aSNicolas Le Bayon
134*79629b1aSNicolas Le Bayon ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_PHYDRVIMPEDANCE, 0U);
135*79629b1aSNicolas Le Bayon if (ret != 0) {
136*79629b1aSNicolas Le Bayon return ret;
137*79629b1aSNicolas Le Bayon }
138*79629b1aSNicolas Le Bayon
139*79629b1aSNicolas Le Bayon ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_BPZNRESVAL, 0U);
140*79629b1aSNicolas Le Bayon if (ret != 0) {
141*79629b1aSNicolas Le Bayon return ret;
142*79629b1aSNicolas Le Bayon }
143*79629b1aSNicolas Le Bayon
144*79629b1aSNicolas Le Bayon #if STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE
145*79629b1aSNicolas Le Bayon ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_ENABLEDDQS, nad0 * 8U);
146*79629b1aSNicolas Le Bayon if (ret != 0) {
147*79629b1aSNicolas Le Bayon return ret;
148*79629b1aSNicolas Le Bayon }
149*79629b1aSNicolas Le Bayon
150*79629b1aSNicolas Le Bayon disableddbyte = 0x0U;
151*79629b1aSNicolas Le Bayon
152*79629b1aSNicolas Le Bayon for (dbyte = 0U; (dbyte < config->uib.numdbyte) && (dbyte < 8U); dbyte++) {
153*79629b1aSNicolas Le Bayon if (ddrphy_phyinit_isdbytedisabled(config, mb_ddr_1d, dbyte) != 0) {
154*79629b1aSNicolas Le Bayon disableddbyte |= 0x1U << dbyte;
155*79629b1aSNicolas Le Bayon }
156*79629b1aSNicolas Le Bayon }
157*79629b1aSNicolas Le Bayon
158*79629b1aSNicolas Le Bayon ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_DISABLEDDBYTE, disableddbyte);
159*79629b1aSNicolas Le Bayon if (ret != 0) {
160*79629b1aSNicolas Le Bayon return ret;
161*79629b1aSNicolas Le Bayon }
162*79629b1aSNicolas Le Bayon
163*79629b1aSNicolas Le Bayon #if STM32MP_DDR3_TYPE
164*79629b1aSNicolas Le Bayon ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_PHYCFG, config->uia.is2ttiming);
165*79629b1aSNicolas Le Bayon if (ret != 0) {
166*79629b1aSNicolas Le Bayon return ret;
167*79629b1aSNicolas Le Bayon }
168*79629b1aSNicolas Le Bayon #else /* STM32MP_DDR4_TYPE */
169*79629b1aSNicolas Le Bayon ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_PHYCFG,
170*79629b1aSNicolas Le Bayon ((mb_ddr_1d->mr3 & 0x8U) != 0U) ?
171*79629b1aSNicolas Le Bayon 0U : config->uia.is2ttiming);
172*79629b1aSNicolas Le Bayon if (ret != 0) {
173*79629b1aSNicolas Le Bayon return ret;
174*79629b1aSNicolas Le Bayon }
175*79629b1aSNicolas Le Bayon
176*79629b1aSNicolas Le Bayon ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_X16PRESENT,
177*79629b1aSNicolas Le Bayon (config->uib.dramdatawidth == 0x10U) ?
178*79629b1aSNicolas Le Bayon mb_ddr_1d->cspresent : 0x0U);
179*79629b1aSNicolas Le Bayon if (ret != 0) {
180*79629b1aSNicolas Le Bayon return ret;
181*79629b1aSNicolas Le Bayon }
182*79629b1aSNicolas Le Bayon #endif /* STM32MP_DDR3_TYPE */
183*79629b1aSNicolas Le Bayon #else /* STM32MP_LPDDR4_TYPE */
184*79629b1aSNicolas Le Bayon ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_ENABLEDDQSCHA, nad0 * 8U);
185*79629b1aSNicolas Le Bayon if (ret != 0) {
186*79629b1aSNicolas Le Bayon return ret;
187*79629b1aSNicolas Le Bayon }
188*79629b1aSNicolas Le Bayon
189*79629b1aSNicolas Le Bayon ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_CSPRESENTCHA,
190*79629b1aSNicolas Le Bayon (config->uib.numrank_dfi0 == 2U) ?
191*79629b1aSNicolas Le Bayon 0x3U : config->uib.numrank_dfi0);
192*79629b1aSNicolas Le Bayon if (ret != 0) {
193*79629b1aSNicolas Le Bayon return ret;
194*79629b1aSNicolas Le Bayon }
195*79629b1aSNicolas Le Bayon
196*79629b1aSNicolas Le Bayon ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_ENABLEDDQSCHB, nad1 * 8U);
197*79629b1aSNicolas Le Bayon if (ret != 0) {
198*79629b1aSNicolas Le Bayon return ret;
199*79629b1aSNicolas Le Bayon }
200*79629b1aSNicolas Le Bayon
201*79629b1aSNicolas Le Bayon ret = ddrphy_phyinit_softsetmb(mb_ddr_1d, MB_FIELD_CSPRESENTCHB,
202*79629b1aSNicolas Le Bayon (config->uib.numrank_dfi1 == 2U) ?
203*79629b1aSNicolas Le Bayon 0x3U : config->uib.numrank_dfi1);
204*79629b1aSNicolas Le Bayon if (ret != 0) {
205*79629b1aSNicolas Le Bayon return ret;
206*79629b1aSNicolas Le Bayon }
207*79629b1aSNicolas Le Bayon #endif /* STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE */
208*79629b1aSNicolas Le Bayon
209*79629b1aSNicolas Le Bayon return 0;
210*79629b1aSNicolas Le Bayon }
211