1 /*
2 * lowlevel_init_v300.c
3 *
4 * The file is Hardware initialization.
5 *
6 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22
23 #include <asm/arch/platform.h>
24 #include <config.h>
25 #include <ddr_training_impl.h>
26 #include <compiler.h>
27
delay(unsigned int num)28 static inline void delay(unsigned int num)
29 {
30 volatile unsigned int i;
31
32 for (i = 0; i < (100 * num); i++) /* 100: Cycle */
33 __asm__ __volatile__("nop");
34 }
35
dwb(void)36 static inline void dwb(void) /* drain write buffer */
37 {
38 }
39
readl(unsigned addr)40 static inline unsigned int readl(unsigned addr)
41 {
42 unsigned int val;
43
44 val = (*(volatile unsigned int *)(uintptr_t)(addr));
45 return val;
46 }
47
writel(unsigned val,unsigned addr)48 static inline void writel(unsigned val, unsigned addr)
49 {
50 dwb();
51 (*(volatile unsigned *)(uintptr_t)(addr)) = val;
52 dwb();
53 }
54
55 #define REG_BASE_RNG_GEN 0x10090000
56 #define TRNG_DSTA_FIFO_DATA_OFST 0x204
57 #define TRNG_DATA_ST_OFST 0x208
58 #define BIT_TRNG_FIFO_DATA_CNT 0x8
59 #define TRNG_FIFO_DATA_CNT_MASK 0xff
60 #define REG_PERI_CRG104 0x1a0
61 #define TRNG_CLK_ENABLE (0x1<<3)
62 #define TRNG_CLK_DISABLE ~(0x1<<3)
63 #define TRNG_CTRL_DEF_VAL 0xa
64 #define HISEC_COM_TRNG_CTRL_OFST 0x200
65
66 #define REG_BASE_MISC 0x12030000
67 #define DDR_CA0_OFST 0x28
68 #define DDR_CA1_OFST 0x2C
69 #define DDR_CA2_OFST 0x30
70
71 #define REG_BASE_DDRC 0x120d0000
72 #define DDRC_CTRL_SREF_OFST (0x8000 + 0x0)
73 #define DDRC_CFG_DDRMODE_OFST (0x8000 + 0x50)
74 #define DDRC_CURR_FUNC_OFST (0x8000 + 0x294)
75
76 #define DDRC_CHANNEL_VALID_MASK 0xf
77 #define DDRC_SELF_REFURBISH_MASK 0x1
78
79 #define DDRC_SELF_REFURBISH_EN 0x1
80 #define DDRC_SELF_REFURBISH_EXIT (0x1 << 1)
81
82 #define HPM_CORE_MIN 150
83 #define HPM_CORE_MAX 350
84
85 #define TEMPERATURE_MIN 117
86 #define TEMPERATURE_MAX 841
87
88 #define HPM_CORE_VALUE_MIN 190
89 #define HPM_CORE_VALUE_MAX 310
90
91 #undef reg_get
92 #undef reg_set
93 #define reg_get(addr) readl(addr)
94 #define reg_set(addr, val) writel(val, (unsigned int)(addr))
95
96 #define temperature_formula(val) (((((val) - 117) * 212) >> 10) - 40)
97 #define hpm_formula(hpm, temp) ((hpm) + 4 + ((((temp) - 70) * 205) >> 10))
98 #define volt_formula(val) (1234 - ((1445 * (val)) >> 10))
99 #define duty_formula(val) ((unsigned int)((1099 - (val)) * 460) >> 10)
100
trng_init(void)101 void trng_init(void)
102 {
103 unsigned int reg_val;
104 /* open rsa and trng clock */
105 reg_val = reg_get(CRG_REG_BASE + REG_PERI_CRG104);
106 reg_val |= TRNG_CLK_ENABLE;
107 reg_set(CRG_REG_BASE + REG_PERI_CRG104, reg_val);
108
109 /* set trng ctrl register */
110 reg_set(REG_BASE_RNG_GEN + HISEC_COM_TRNG_CTRL_OFST,
111 TRNG_CTRL_DEF_VAL);
112 }
113
trng_deinit(void)114 void trng_deinit(void)
115 {
116 unsigned int reg_val;
117
118 /* close rsa and trng clock */
119 reg_val = reg_get(CRG_REG_BASE + REG_PERI_CRG104);
120 reg_val &= TRNG_CLK_DISABLE;
121 reg_set(CRG_REG_BASE + REG_PERI_CRG104, reg_val);
122 }
123
124 /* svb */
125 #define SVB_VER_18EV300 0x10
126
127 #define CYCLE_NUM 4
128 #define HPM_CORE_REG0 0x120280d8
129 #define HPM_CORE_REG1 0x120280dc
130
131 #define PWM0_REG 0X12080000
132 #define PWM_REG_OFFSET 0x20
133 #define PWM_CFG1 0X04
134 #define PWM_CTRL 0X0C
135
136 #define SVB_VER_REG 0x12020168
137 #define HPM_CHECK_REG 0x1202015c
138 #define SYS_CTRL_VOLT_REG 0x12020158
139 #define SVB_PWM_SEL 0x1202009c
140
141 #define TSENSOR_STATUS0 0x120280bc
142 #define OTP_HPM_CORE_REG 0x100a002c
143
hpm_value_avg(unsigned int * val,int num)144 static unsigned hpm_value_avg(unsigned int *val, int num)
145 {
146 unsigned int i;
147 unsigned tmp = 0;
148
149 for (i = 0; i < num; i++)
150 tmp += val[i] >> NUM_2;
151
152 return tmp >> NUM_2;
153 }
154
get_hpm_value(unsigned int * hpm_core)155 static void get_hpm_value(unsigned int *hpm_core)
156 {
157 int i;
158 unsigned int temp;
159 unsigned int core_value[NUM_4];
160
161 core_value[NUM_0] = 0;
162 core_value[NUM_1] = 0;
163 core_value[NUM_2] = 0;
164 core_value[NUM_3] = 0;
165
166 for (i = 0; i < CYCLE_NUM; i++) {
167 temp = readl(HPM_CORE_REG0);
168 core_value[NUM_1] += (temp >> 16) & 0x3ff; /* get hight 16 bits */
169 core_value[NUM_0] += temp & 0x3ff;
170 temp = readl(HPM_CORE_REG1);
171 core_value[NUM_3] += (temp >> 16) & 0x3ff; /* get hight 16 bits */
172 core_value[NUM_2] += temp & 0x3ff;
173 }
174
175 *hpm_core = hpm_value_avg(core_value, NUM_4);
176 }
177
start_hpm(unsigned int * hpm_core)178 static void start_hpm(unsigned int *hpm_core)
179 {
180 get_hpm_value(hpm_core);
181 }
182
hpm_check(unsigned int * hpm_core)183 static void hpm_check(unsigned int *hpm_core)
184 {
185 union {
186 struct {
187 unsigned int reserved_0 : 16; /* [15..0] */
188 unsigned int sys_hpm_core : 9; /* [24..16] */
189 unsigned int reserved_1 : 1; /* [25] */
190 unsigned int hpm_core_err : 1; /* [26] */
191 unsigned int reserved_2 : 5; /* [27..31] */
192 } bits;
193
194 unsigned int u32;
195 } sysboot10;
196 sysboot10.u32 = readl(HPM_CHECK_REG);
197 sysboot10.bits.sys_hpm_core = 0;
198 sysboot10.bits.hpm_core_err = 0;
199
200 if (*hpm_core < HPM_CORE_MIN) {
201 *hpm_core = HPM_CORE_MIN;
202 sysboot10.bits.hpm_core_err = 1;
203 }
204 if (*hpm_core > HPM_CORE_MAX) {
205 *hpm_core = HPM_CORE_MAX;
206 sysboot10.bits.hpm_core_err = 1;
207 }
208
209 sysboot10.bits.sys_hpm_core = *hpm_core;
210
211 writel(sysboot10.u32, HPM_CHECK_REG);
212 }
213
get_temperature(unsigned int * temperature)214 static void get_temperature(unsigned int *temperature)
215 {
216 unsigned int value;
217
218 value = readl(TSENSOR_STATUS0);
219 value = value & 0x3ff;
220
221 if (value <= TEMPERATURE_MIN)
222 *temperature = -40; /* -40: temperature value */
223 else if (value >= TEMPERATURE_MAX)
224 *temperature = 110; /* 110: temperature value */
225 else
226 *temperature = temperature_formula(value);
227 }
228
adjust_hpm(unsigned int * hpm_core,unsigned int temperature)229 static void adjust_hpm(unsigned int *hpm_core, unsigned int temperature)
230 {
231 /* 283 70: hpm_core and temperature Threshold */
232 if ((*hpm_core >= 283) && (temperature >= 70))
233 *hpm_core = hpm_formula(*hpm_core, temperature);
234 /* 222 70: hpm_core and temperature Threshold */
235 else if ((*hpm_core <= 222) && (temperature >= 70))
236 *hpm_core = *hpm_core - NUM_4;
237 }
238
set_hpm_core_volt(unsigned int hpm_core_value,unsigned int pwm_id)239 static void set_hpm_core_volt(unsigned int hpm_core_value, unsigned int pwm_id)
240 {
241 unsigned int volt;
242 unsigned int duty;
243 unsigned int otp_vmin_core = readl(OTP_HPM_CORE_REG);
244
245 if (hpm_core_value <= HPM_CORE_VALUE_MIN)
246 volt = 966; /* 966:vole val */
247 else if (hpm_core_value >= HPM_CORE_VALUE_MAX)
248 volt = 796; /* 796:vole val */
249 else
250 volt = volt_formula(hpm_core_value);
251
252 volt = volt + (int)((short int)(otp_vmin_core >> 16)); /* get hight 16 bits */
253
254 writel(volt, SYS_CTRL_VOLT_REG);
255 duty = duty_formula(volt);
256 writel(duty, PWM0_REG + pwm_id * PWM_REG_OFFSET + PWM_CFG1);
257 writel(0x5, PWM0_REG + pwm_id * PWM_REG_OFFSET + PWM_CTRL);
258 }
259
start_svb(void)260 void start_svb(void)
261 {
262 unsigned int hpm_core = 0;
263 unsigned int pwm_id;
264 unsigned int temperature = 0;
265
266 unsigned int tmp_reg = readl(SVB_VER_REG);
267 tmp_reg = (tmp_reg & 0xff00ffff) | (SVB_VER_18EV300 << 16); /* Move Left 16bit */
268 writel(tmp_reg, SVB_VER_REG);
269
270 get_temperature(&temperature);
271 start_hpm(&hpm_core);
272 adjust_hpm(&hpm_core, temperature);
273 hpm_check(&hpm_core);
274
275 pwm_id = readl(SVB_PWM_SEL) & 0xf;
276 set_hpm_core_volt(hpm_core, pwm_id);
277 delay(160); /* delay 160ms */
278 }
279
280 /* [CUSTOM] DDR PHY0-PHY1 base register */
281 #define DDR_REG_BASE_PHY0 0x120dc000
282
283 /* [CUSTOM] DDR DMC0-DMC3 base register */
284 #define DDR_REG_BASE_DMC0 0x120d8000
285 #define DDR_REG_BASE_DMC1 0x120d8000
286
287 #ifdef DDR_REG_BASE_PHY1
288 #define DDR_REG_BASE_DMC2 0x120d9000
289 #define DDR_REG_BASE_DMC3 0x120d9000
290 #endif
291
292 #define CRG_REG_BASE 0x12010000
293 #define PERI_CRG_DDRT 0x198
294
295 #define DDR_REG_BASE_SYSCTRL 0x12020000
296 /* [SYSCTRL]RAM Retention control register 0 */
297 #define SYSCTRL_MISC_CTRL4 0x8010
298
299 #define DDR_PHY_DRAMCFG 0x2c /* DRAM config register */
300 #define PHY_DRAMCFG_TYPE_MASK 0xf /* [3:0] */
301 #define PHY_DRAMCFG_TYPE_LPDDR4 0x6 /* [2:0] 110 LPDDR4 */
302
303 #define BYTE_NUM 2
304
305 /**
306 * ddr_boot_prepare
307 * @void
308 *
309 * Do some prepare before ddr training.
310 * Keep empty when nothing to do.
311 */
ddr_boot_prepare(struct tr_relate_reg * reg)312 static void ddr_boot_prepare(struct tr_relate_reg *reg)
313 {
314 /* select ddrt bus path */
315 reg->custom.ive_ddrt_mst_sel = readl(DDR_REG_BASE_SYSCTRL + SYSCTRL_MISC_CTRL4);
316 writel(reg->custom.ive_ddrt_mst_sel & 0xffffffdf,
317 DDR_REG_BASE_SYSCTRL + SYSCTRL_MISC_CTRL4);
318
319 /* turn on ddrt clock */
320 reg->custom.ddrt_clk_reg = readl(CRG_REG_BASE + PERI_CRG_DDRT);
321 /* enable ddrt0 clock */
322 writel(reg->custom.ddrt_clk_reg | (0x1 << 1), CRG_REG_BASE + PERI_CRG_DDRT);
323 __asm__ __volatile__("nop");
324 /* disable ddrt0 soft reset */
325 writel(readl(CRG_REG_BASE + PERI_CRG_DDRT) & (~(0x1 << 0)),
326 CRG_REG_BASE + PERI_CRG_DDRT);
327
328 /* disable rdqs anti-aging */
329 reg->custom.phy0_age_compst_en = readl(DDR_REG_BASE_PHY0 + DDR_PHY_PHYRSCTRL);
330 writel((reg->custom.phy0_age_compst_en & 0x7fffffff),
331 DDR_REG_BASE_PHY0 + DDR_PHY_PHYRSCTRL);
332 #ifdef DDR_REG_BASE_PHY1
333 reg->custom.phy1_age_compst_en = readl(DDR_REG_BASE_PHY1 + DDR_PHY_PHYRSCTRL);
334 writel((reg->custom.phy1_age_compst_en & 0x7fffffff),
335 DDR_REG_BASE_PHY1 + DDR_PHY_PHYRSCTRL);
336 #endif
337 }
338
339 /**
340 * ddr_boot_restore
341 * @void
342 *
343 * Restore register config after ddr training.
344 * Keep empty when nothing to do.
345 */
ddr_boot_restore(struct tr_relate_reg * reg)346 static void ddr_boot_restore(struct tr_relate_reg *reg)
347 {
348 /* restore ddrt bus path */
349 writel(reg->custom.ive_ddrt_mst_sel, DDR_REG_BASE_SYSCTRL + SYSCTRL_MISC_CTRL4);
350
351 /* restore ddrt clock */
352 writel(reg->custom.ddrt_clk_reg, CRG_REG_BASE + PERI_CRG_DDRT);
353
354 /* restore rdqs anti-aging */
355 writel(reg->custom.phy0_age_compst_en, DDR_REG_BASE_PHY0 + DDR_PHY_PHYRSCTRL);
356 #ifdef DDR_REG_BASE_PHY1
357 writel(reg->custom.phy1_age_compst_en, DDR_REG_BASE_PHY1 + DDR_PHY_PHYRSCTRL);
358 #endif
359 }
360
361 /**
362 * ddr_rdqs_bdl_adj
363 * @void
364 *
365 * Adjust rdqs/rdq/rdm bdl to avoid problem cause by ddr anti-aging.
366 */
ddr_rdqs_bdl_adj(void)367 static void ddr_rdqs_bdl_adj(void)
368 {
369 int i;
370 unsigned int rdqs;
371 unsigned int rdq03;
372 unsigned int rdq47;
373 unsigned int rdm;
374 unsigned int tmp;
375
376 for (i = 0; i < BYTE_NUM; i++) {
377 rdqs = readl(DDR_REG_BASE_PHY0 + 0x22c + i * 0x80);
378 rdq03 = readl(DDR_REG_BASE_PHY0 + 0x21c + i * 0x80);
379 rdq47 = readl(DDR_REG_BASE_PHY0 + 0x220 + i * 0x80);
380 rdm = readl(DDR_REG_BASE_PHY0 + 0x224 + i * 0x80);
381
382 /* rdqs bdl lower two bit shoud be 0x11 */
383 while ((rdqs & 0x3) < 0x3) {
384 /* rdqs/rdq/rdm bdl + 1 */
385 rdqs = rdqs + 0x1;
386 rdq03 = rdq03 + 0x01010101;
387 rdq47 = rdq47 + 0x01010101;
388 rdm = rdm + 0x1;
389
390 writel(rdqs, DDR_REG_BASE_PHY0 + 0x22c + i * 0x80);
391 writel(rdq03, DDR_REG_BASE_PHY0 + 0x21c + i * 0x80);
392 writel(rdq47, DDR_REG_BASE_PHY0 + 0x220 + i * 0x80);
393 writel(rdm, DDR_REG_BASE_PHY0 + 0x224 + i * 0x80);
394 }
395 }
396
397 tmp = readl(DDR_REG_BASE_PHY0 + DDR_PHY_MISC);
398 tmp |= (1 << PHY_MISC_UPDATE_BIT);
399 /* update new config to PHY */
400 writel(tmp, DDR_REG_BASE_PHY0 + DDR_PHY_MISC);
401 tmp &= ~(1 << PHY_MISC_UPDATE_BIT);
402 writel(tmp, DDR_REG_BASE_PHY0 + DDR_PHY_MISC);
403 tmp = readl(DDR_REG_BASE_PHY0 + DDR_PHY_PHYINITCTRL);
404 /* set 1 to issue PHY counter reset signal */
405 tmp |= (1 << PHY_PHYCONN_RST_BIT);
406 writel(tmp, DDR_REG_BASE_PHY0 + DDR_PHY_PHYINITCTRL);
407 /* set 0 to end the reset signal */
408 tmp &= ~(1 << PHY_PHYCONN_RST_BIT);
409 writel(tmp, DDR_REG_BASE_PHY0 + DDR_PHY_PHYINITCTRL);
410 }
411
start_ddr_training(unsigned int base)412 void start_ddr_training(unsigned int base)
413 {
414 struct tr_relate_reg relate_reg;
415 struct tr_relate_reg *reg = &relate_reg;
416
417 start_svb();
418
419 ddr_boot_prepare(reg);
420
421 /* ddr pcode training */
422 ddr_pcode_training_if();
423 /* ddr hw training */
424 ddr_hw_training_if();
425 /* ddr sw training */
426 ddr_sw_training_if();
427
428 ddr_rdqs_bdl_adj();
429
430 ddr_boot_restore(reg);
431
432 /* the value should config after trainning, or
433 it will cause chip compatibility problems */
434 if ((readl(DDR_REG_BASE_PHY0 + DDR_PHY_DRAMCFG) &
435 PHY_DRAMCFG_TYPE_MASK) == PHY_DRAMCFG_TYPE_LPDDR4) {
436 writel(0x401, DDR_REG_BASE_DMC0 + 0x28);
437 writel(0x401, DDR_REG_BASE_DMC1 + 0x28);
438 } else {
439 writel(0x401, DDR_REG_BASE_DMC0 + 0x28);
440 }
441 #ifdef DDR_REG_BASE_PHY1
442 if ((readl(DDR_REG_BASE_PHY1 + DDR_PHY_DRAMCFG) &
443 PHY_DRAMCFG_TYPE_MASK) == PHY_DRAMCFG_TYPE_LPDDR4) {
444 writel(0x401, DDR_REG_BASE_DMC2 + 0x28);
445 writel(0x401, DDR_REG_BASE_DMC3 + 0x28);
446 } else {
447 writel(0x401, DDR_REG_BASE_DMC1 + 0x28);
448 }
449 #endif
450 /* enable ddr scramb */
451 }
452