blob: 6a3d816a48a622eb8b687ef7ae55563e6156c91f [file] [log] [blame]
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2017 NXP
4 * Copyright 2020 Linaro
5 *
6 */
7
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +08008#include <spl.h>
9#include <asm/io.h>
10#include <errno.h>
11#include <command.h>
12#include <asm/io.h>
13#include <asm/arch/lpddr4_define.h>
14#include <asm/mach-imx/iomux-v3.h>
15#include <asm/mach-imx/gpio.h>
16#include <asm-generic/gpio.h>
17#include <asm/arch/ddr.h>
18#include <asm/arch/imx8mq_pins.h>
19#include <asm/arch/sys_proto.h>
20#include <asm/arch/clock.h>
21#include <asm/mach-imx/gpio.h>
22#include "ddr.h"
23
Fabio Estevam6c2024d2022-04-12 13:05:36 -030024#include <linux/delay.h>
25
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +080026struct lpddr4_desc {
27 char name[16];
28 unsigned int id;
29 unsigned int size;
30 unsigned int count;
31 /* an optional field
32 * use it if default is not the
33 * 1-st array entry
34 */
35 unsigned int _default;
36 /* An optional field to distiguish DRAM chips that
37 * have different geometry, though return the same MRR.
38 * Default value 0xff
39 */
40 u8 subind;
41 struct dram_timing_info *timing;
42 char *desc[4];
43};
44
45#define DEFAULT (('D' << 24) + ('E' << 16) + ('F' << 8) + 'A')
46static const struct lpddr4_desc lpddr4_array[] = {
47 { .name = "Nanya", .id = 0x05000010, .subind = 0xff,
48 .size = 2048, .count = 1, .timing = &ucm_dram_timing_01061010},
Fabio Estevam0ae0a822024-05-28 16:15:09 -030049 { .name = "Samsung", .id = 0x01061010, .subind = 0x04,
50 .size = 4096, .count = 1, .timing = &ucm_dram_timing_ff000110},
51 { .name = "Samsung", .id = 0x01061010, .subind = 0x02,
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +080052 .size = 2048, .count = 1, .timing = &ucm_dram_timing_01061010},
53 { .name = "Kingston", .id = 0xff000010, .subind = 0x04,
54 .size = 4096, .count = 1, .timing = &ucm_dram_timing_ff000110},
55 { .name = "Kingston", .id = 0xff000010, .subind = 0x02,
56 .size = 2048, .count = 1, .timing = &ucm_dram_timing_01061010},
57 { .name = "Micron", .id = 0xff020008, .subind = 0xff,
58 .size = 2048, .count = 1, .timing = &ucm_dram_timing_ff020008},
59 { .name = "Micron", .id = 0xff000110, .subind = 0xff,
60 .size = 4096, .count = 1, .timing = &ucm_dram_timing_ff000110},
61};
62
63static unsigned int lpddr4_get_mr(void)
64{
65 int i = 0, attempts = 5;
66 unsigned int ddr_info = 0;
67 unsigned int regs[] = { 5, 6, 7, 8 };
68
69 do {
70 for (i = 0 ; i < ARRAY_SIZE(regs) ; i++) {
71 unsigned int data = 0;
72
73 data = lpddr4_mr_read(0xF, regs[i]);
74 ddr_info <<= 8;
75 ddr_info += (data & 0xFF);
76 }
77 if (ddr_info != 0xFFFFFFFF && ddr_info != 0)
78 break; // The attempt was successful
79 } while (--attempts);
80 return ddr_info;
81}
82
83static void spl_tcm_init(struct lpddr4_tcm_desc *lpddr4_tcm_desc)
84{
85 if (lpddr4_tcm_desc->sign == DEFAULT)
86 return;
87
88 lpddr4_tcm_desc->sign = DEFAULT;
89 lpddr4_tcm_desc->index = 0;
90}
91
92static void spl_tcm_fini(struct lpddr4_tcm_desc *lpddr4_tcm_desc)
93{
94 if (lpddr4_tcm_desc->sign != DEFAULT)
95 return;
96
97 lpddr4_tcm_desc->sign = ~DEFAULT;
98 lpddr4_tcm_desc->index = 0;
99}
100
101#define SPL_TCM_DATA 0x7e0000
102#define SPL_TCM_INIT spl_tcm_init(lpddr4_tcm_desc)
103#define SPL_TCM_FINI spl_tcm_fini(lpddr4_tcm_desc)
104
105void spl_dram_init_compulab(void)
106{
107 unsigned int ddr_info = 0xdeadbeef;
108 unsigned int ddr_info_mrr = 0xdeadbeef;
109 unsigned int ddr_found = 0;
110 int i = 0;
111
112 struct lpddr4_tcm_desc *lpddr4_tcm_desc =
113 (struct lpddr4_tcm_desc *)SPL_TCM_DATA;
114
115 if (lpddr4_tcm_desc->sign != DEFAULT) {
Fabio Estevam6c2024d2022-04-12 13:05:36 -0300116 /* get ddr type from the eeprom if not in tcm scan mode */
117 ddr_info = cl_eeprom_get_ddrinfo();
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +0800118 for (i = 0; i < ARRAY_SIZE(lpddr4_array); i++) {
119 if (lpddr4_array[i].id == ddr_info &&
Fabio Estevam6c2024d2022-04-12 13:05:36 -0300120 lpddr4_array[i].subind == cl_eeprom_get_subind()) {
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +0800121 ddr_found = 1;
122 break;
123 }
124 }
125 }
126
127 /* Walk trought all available ddr ids and apply
128 * one by one. Save the index at the tcm memory that
129 * persists after the reset.
130 */
131 if (ddr_found == 0) {
132 SPL_TCM_INIT;
133
134 if (lpddr4_tcm_desc->index < ARRAY_SIZE(lpddr4_array)) {
135 printf("DDRINFO: Cfg attempt: [ %d/%lu ]\n",
136 lpddr4_tcm_desc->index + 1,
137 ARRAY_SIZE(lpddr4_array));
138 i = lpddr4_tcm_desc->index;
139 lpddr4_tcm_desc->index += 1;
140 } else {
141 /* Ran out all available ddr setings */
142 printf("DDRINFO: Ran out all [ %lu ] cfg attempts. A non supported configuration.\n",
143 ARRAY_SIZE(lpddr4_array));
144 while (1)
145 ;
146 }
147 ddr_info = lpddr4_array[i].id;
148 } else {
149 printf("DDRINFO(%s): %s %dG\n", (ddr_found ? "D" : "?"),
150 lpddr4_array[i].name,
151 lpddr4_array[i].size);
152 }
153
154 if (ddr_init(lpddr4_array[i].timing)) {
155 SPL_TCM_INIT;
156 do_reset(NULL, 0, 0, NULL);
157 }
158
159 ddr_info_mrr = lpddr4_get_mr();
160 if (ddr_info_mrr == 0xFFFFFFFF) {
161 printf("DDRINFO(M): mr5-8 [ 0x%x ] is invalid; reset\n",
162 ddr_info_mrr);
163 SPL_TCM_INIT;
164 do_reset(NULL, 0, 0, NULL);
165 }
166
167 printf("DDRINFO(M): mr5-8 [ 0x%x ]\n", ddr_info_mrr);
168 printf("DDRINFO(%s): mr5-8 [ 0x%x ]\n", (ddr_found ? "E" : "T"),
169 ddr_info);
170
171 if (ddr_info_mrr != ddr_info) {
172 SPL_TCM_INIT;
173 do_reset(NULL, 0, 0, NULL);
174 }
175
176 SPL_TCM_FINI;
177
Fabio Estevam6c2024d2022-04-12 13:05:36 -0300178 if (ddr_found == 0) {
179 /* Update eeprom */
180 cl_eeprom_set_ddrinfo(ddr_info_mrr);
181 mdelay(10);
182 ddr_info = cl_eeprom_get_ddrinfo();
183 mdelay(10);
184 cl_eeprom_set_subind(lpddr4_array[i].subind);
185 /* make sure that the ddr_info has reached the eeprom */
186 printf("DDRINFO(E): mr5-8 [ 0x%x ], read back\n", ddr_info);
187 if (ddr_info_mrr != ddr_info || cl_eeprom_get_subind() != lpddr4_array[i].subind) {
188 printf("DDRINFO(EEPROM): make sure that the eeprom is accessible\n");
189 printf("DDRINFO(EEPROM): i2c dev 1; i2c md 0x51 0x40 0x50\n");
190 }
191 }
192
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +0800193 /* Pass the dram size to th U-Boot through the tcm memory */
194 { /* To figure out what to store into the TCM buffer */
195 /* For debug purpouse only. To override the real memsize */
Fabio Estevam6c2024d2022-04-12 13:05:36 -0300196 unsigned int ddr_tcm_size = cl_eeprom_get_osize();
Ying-Chun Liu (PaulLiu)a97107f2021-04-22 04:50:31 +0800197
198 if (ddr_tcm_size == 0 || ddr_tcm_size == -1)
199 ddr_tcm_size = lpddr4_array[i].size;
200
201 lpddr4_tcm_desc->size = ddr_tcm_size;
202 }
203}