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