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