1 // 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 
lpddr4_mr_read(unsigned int mr_rank,unsigned int mr_addr)25 static unsigned int lpddr4_mr_read(unsigned int mr_rank, unsigned int mr_addr)
26 {
27 	unsigned int tmp;
28 
29 	reg32_write(DRC_PERF_MON_MRR0_DAT(0), 0x1);
30 	do {
31 		tmp = reg32_read(DDRC_MRSTAT(0));
32 	} while (tmp & 0x1);
33 
34 	reg32_write(DDRC_MRCTRL0(0), (mr_rank << 4) | 0x1);
35 	reg32_write(DDRC_MRCTRL1(0), (mr_addr << 8));
36 	reg32setbit(DDRC_MRCTRL0(0), 31);
37 	do {
38 		tmp = reg32_read(DRC_PERF_MON_MRR0_DAT(0));
39 	} while ((tmp & 0x8) == 0);
40 	tmp = reg32_read(DRC_PERF_MON_MRR1_DAT(0));
41 	reg32_write(DRC_PERF_MON_MRR0_DAT(0), 0x4);
42 	while (tmp) { //try to find a significant byte in the word
43 		if (tmp & 0xff) {
44 			tmp &= 0xff;
45 			break;
46 		}
47 		tmp >>= 8;
48 	}
49 	return tmp;
50 }
51 
52 struct lpddr4_desc {
53 	char name[16];
54 	unsigned int id;
55 	unsigned int size;
56 	unsigned int count;
57 	/* an optional field
58 	 * use it if default is not the
59 	 * 1-st array entry
60 	 */
61 	unsigned int _default;
62 	/* An optional field to distiguish DRAM chips that
63 	 * have different geometry, though return the same MRR.
64 	 * Default value 0xff
65 	 */
66 	u8	subind;
67 	struct dram_timing_info *timing;
68 	char *desc[4];
69 };
70 
71 #define DEFAULT (('D' << 24) + ('E' << 16) + ('F' << 8) + 'A')
72 static const struct lpddr4_desc lpddr4_array[] = {
73 	{ .name = "Nanya",	.id = 0x05000010, .subind = 0xff,
74 	  .size = 2048, .count = 1, .timing = &ucm_dram_timing_01061010},
75 	{ .name = "Samsung",	.id = 0x01061010, .subind = 0xff,
76 	  .size = 2048, .count = 1, .timing = &ucm_dram_timing_01061010},
77 	{ .name = "Kingston",	.id = 0xff000010, .subind = 0x04,
78 	  .size = 4096, .count = 1, .timing = &ucm_dram_timing_ff000110},
79 	{ .name = "Kingston",	.id = 0xff000010, .subind = 0x02,
80 	  .size = 2048, .count = 1, .timing = &ucm_dram_timing_01061010},
81 	{ .name = "Micron",	.id = 0xff020008, .subind = 0xff,
82 	  .size = 2048, .count = 1, .timing = &ucm_dram_timing_ff020008},
83 	{ .name = "Micron",	.id = 0xff000110, .subind = 0xff,
84 	  .size = 4096, .count = 1, .timing = &ucm_dram_timing_ff000110},
85 };
86 
lpddr4_get_mr(void)87 static unsigned int lpddr4_get_mr(void)
88 {
89 	int i = 0, attempts = 5;
90 	unsigned int ddr_info = 0;
91 	unsigned int regs[] = { 5, 6, 7, 8 };
92 
93 	do {
94 		for (i = 0 ; i < ARRAY_SIZE(regs) ; i++) {
95 			unsigned int data = 0;
96 
97 			data = lpddr4_mr_read(0xF, regs[i]);
98 			ddr_info <<= 8;
99 			ddr_info += (data & 0xFF);
100 		}
101 		if (ddr_info != 0xFFFFFFFF && ddr_info != 0)
102 			break; // The attempt was successful
103 	} while (--attempts);
104 	return	ddr_info;
105 }
106 
spl_tcm_init(struct lpddr4_tcm_desc * lpddr4_tcm_desc)107 static void spl_tcm_init(struct lpddr4_tcm_desc *lpddr4_tcm_desc)
108 {
109 	if (lpddr4_tcm_desc->sign == DEFAULT)
110 		return;
111 
112 	lpddr4_tcm_desc->sign = DEFAULT;
113 	lpddr4_tcm_desc->index = 0;
114 }
115 
spl_tcm_fini(struct lpddr4_tcm_desc * lpddr4_tcm_desc)116 static void spl_tcm_fini(struct lpddr4_tcm_desc *lpddr4_tcm_desc)
117 {
118 	if (lpddr4_tcm_desc->sign != DEFAULT)
119 		return;
120 
121 	lpddr4_tcm_desc->sign = ~DEFAULT;
122 	lpddr4_tcm_desc->index = 0;
123 }
124 
125 #define SPL_TCM_DATA 0x7e0000
126 #define SPL_TCM_INIT spl_tcm_init(lpddr4_tcm_desc)
127 #define SPL_TCM_FINI spl_tcm_fini(lpddr4_tcm_desc)
128 
spl_dram_init_compulab(void)129 void spl_dram_init_compulab(void)
130 {
131 	unsigned int ddr_info = 0xdeadbeef;
132 	unsigned int ddr_info_mrr = 0xdeadbeef;
133 	unsigned int ddr_found = 0;
134 	int i = 0;
135 
136 	struct lpddr4_tcm_desc *lpddr4_tcm_desc =
137 		(struct lpddr4_tcm_desc *)SPL_TCM_DATA;
138 
139 	if (lpddr4_tcm_desc->sign != DEFAULT) {
140 		/* if not in tcm scan mode */
141 		for (i = 0; i < ARRAY_SIZE(lpddr4_array); i++) {
142 			if (lpddr4_array[i].id == ddr_info &&
143 			    lpddr4_array[i].subind == 0xff) {
144 				ddr_found = 1;
145 				break;
146 			}
147 		}
148 	}
149 
150 	/* Walk trought all available ddr ids and apply
151 	 * one by one. Save the index at the tcm memory that
152 	 * persists after the reset.
153 	 */
154 	if (ddr_found == 0) {
155 		SPL_TCM_INIT;
156 
157 		if (lpddr4_tcm_desc->index < ARRAY_SIZE(lpddr4_array)) {
158 			printf("DDRINFO: Cfg attempt: [ %d/%lu ]\n",
159 			       lpddr4_tcm_desc->index + 1,
160 			       ARRAY_SIZE(lpddr4_array));
161 			i = lpddr4_tcm_desc->index;
162 			lpddr4_tcm_desc->index += 1;
163 		} else {
164 			/* Ran out all available ddr setings */
165 			printf("DDRINFO: Ran out all [ %lu ] cfg attempts. A non supported configuration.\n",
166 			       ARRAY_SIZE(lpddr4_array));
167 			while (1)
168 				;
169 		}
170 		ddr_info = lpddr4_array[i].id;
171 	} else {
172 		printf("DDRINFO(%s): %s %dG\n", (ddr_found ? "D" : "?"),
173 		       lpddr4_array[i].name,
174 		       lpddr4_array[i].size);
175 	}
176 
177 	if (ddr_init(lpddr4_array[i].timing)) {
178 		SPL_TCM_INIT;
179 		do_reset(NULL, 0, 0, NULL);
180 	}
181 
182 	ddr_info_mrr = lpddr4_get_mr();
183 	if (ddr_info_mrr == 0xFFFFFFFF) {
184 		printf("DDRINFO(M): mr5-8 [ 0x%x ] is invalid; reset\n",
185 		       ddr_info_mrr);
186 		SPL_TCM_INIT;
187 		do_reset(NULL, 0, 0, NULL);
188 	}
189 
190 	printf("DDRINFO(M): mr5-8 [ 0x%x ]\n", ddr_info_mrr);
191 	printf("DDRINFO(%s): mr5-8 [ 0x%x ]\n", (ddr_found ? "E" : "T"),
192 	       ddr_info);
193 
194 	if (ddr_info_mrr != ddr_info) {
195 		SPL_TCM_INIT;
196 		do_reset(NULL, 0, 0, NULL);
197 	}
198 
199 	SPL_TCM_FINI;
200 
201 	/* Pass the dram size to th U-Boot through the tcm memory */
202 	{ /* To figure out what to store into the TCM buffer */
203 	  /* For debug purpouse only. To override the real memsize */
204 		unsigned int ddr_tcm_size = 0;
205 
206 		if (ddr_tcm_size == 0 || ddr_tcm_size == -1)
207 			ddr_tcm_size = lpddr4_array[i].size;
208 
209 		lpddr4_tcm_desc->size = ddr_tcm_size;
210 	}
211 }
212