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