1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2015-2017 Socionext Inc.
4  *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
5  */
6 
7 #include <command.h>
8 #include <spl.h>
9 #include <stdio.h>
10 #include <linux/bitops.h>
11 #include <linux/bug.h>
12 #include <linux/errno.h>
13 #include <linux/io.h>
14 #include <linux/log2.h>
15 
16 #include "../init.h"
17 #include "../sbc/sbc-regs.h"
18 #include "../sg-regs.h"
19 #include "../soc-info.h"
20 #include "boot-device.h"
21 
22 struct uniphier_boot_device_info {
23 	unsigned int soc_id;
24 	unsigned int boot_device_sel_shift;
25 	const struct uniphier_boot_device *boot_device_table;
26 	const unsigned int *boot_device_count;
27 	int (*boot_device_is_sd)(u32 pinmon);
28 	int (*boot_device_is_usb)(u32 pinmon);
29 	unsigned int (*boot_device_fixup)(unsigned int mode);
30 	int (*boot_is_swapped)(void);
31 	bool have_internal_stm;
32 };
33 
34 static const struct uniphier_boot_device_info uniphier_boot_device_info[] = {
35 #if defined(CONFIG_ARCH_UNIPHIER_LD4)
36 	{
37 		.soc_id = UNIPHIER_LD4_ID,
38 		.boot_device_sel_shift = 1,
39 		.boot_device_table = uniphier_ld4_boot_device_table,
40 		.boot_device_count = &uniphier_ld4_boot_device_count,
41 		.boot_is_swapped = uniphier_sbc_boot_is_swapped,
42 		.have_internal_stm = true,
43 	},
44 #endif
45 #if defined(CONFIG_ARCH_UNIPHIER_PRO4)
46 	{
47 		.soc_id = UNIPHIER_PRO4_ID,
48 		.boot_device_sel_shift = 1,
49 		.boot_device_table = uniphier_ld4_boot_device_table,
50 		.boot_device_count = &uniphier_ld4_boot_device_count,
51 		.boot_is_swapped = uniphier_sbc_boot_is_swapped,
52 		.have_internal_stm = false,
53 	},
54 #endif
55 #if defined(CONFIG_ARCH_UNIPHIER_SLD8)
56 	{
57 		.soc_id = UNIPHIER_SLD8_ID,
58 		.boot_device_sel_shift = 1,
59 		.boot_device_table = uniphier_ld4_boot_device_table,
60 		.boot_device_count = &uniphier_ld4_boot_device_count,
61 		.boot_is_swapped = uniphier_sbc_boot_is_swapped,
62 		.have_internal_stm = true,
63 	},
64 #endif
65 #if defined(CONFIG_ARCH_UNIPHIER_PRO5)
66 	{
67 		.soc_id = UNIPHIER_PRO5_ID,
68 		.boot_device_sel_shift = 1,
69 		.boot_device_table = uniphier_pro5_boot_device_table,
70 		.boot_device_count = &uniphier_pro5_boot_device_count,
71 		.boot_is_swapped = uniphier_sbc_boot_is_swapped,
72 		.have_internal_stm = false,
73 	},
74 #endif
75 #if defined(CONFIG_ARCH_UNIPHIER_PXS2)
76 	{
77 		.soc_id = UNIPHIER_PXS2_ID,
78 		.boot_device_sel_shift = 1,
79 		.boot_device_table = uniphier_pxs2_boot_device_table,
80 		.boot_device_count = &uniphier_pxs2_boot_device_count,
81 		.boot_device_is_usb = uniphier_pxs2_boot_device_is_usb,
82 		.boot_device_fixup = uniphier_pxs2_boot_device_fixup,
83 		.boot_is_swapped = uniphier_sbc_boot_is_swapped,
84 		.have_internal_stm = false,
85 	},
86 #endif
87 #if defined(CONFIG_ARCH_UNIPHIER_LD6B)
88 	{
89 		.soc_id = UNIPHIER_LD6B_ID,
90 		.boot_device_sel_shift = 1,
91 		.boot_device_table = uniphier_pxs2_boot_device_table,
92 		.boot_device_count = &uniphier_pxs2_boot_device_count,
93 		.boot_device_is_usb = uniphier_pxs2_boot_device_is_usb,
94 		.boot_device_fixup = uniphier_pxs2_boot_device_fixup,
95 		.boot_is_swapped = uniphier_sbc_boot_is_swapped,
96 		.have_internal_stm = true,	/* STM on A-chip */
97 	},
98 #endif
99 #if defined(CONFIG_ARCH_UNIPHIER_LD11)
100 	{
101 		.soc_id = UNIPHIER_LD11_ID,
102 		.boot_device_sel_shift = 1,
103 		.boot_device_table = uniphier_ld11_boot_device_table,
104 		.boot_device_count = &uniphier_ld11_boot_device_count,
105 		.boot_device_is_usb = uniphier_ld11_boot_device_is_usb,
106 		.boot_is_swapped = uniphier_sbc_boot_is_swapped,
107 		.have_internal_stm = true,
108 	},
109 #endif
110 #if defined(CONFIG_ARCH_UNIPHIER_LD20)
111 	{
112 		.soc_id = UNIPHIER_LD20_ID,
113 		.boot_device_sel_shift = 1,
114 		.boot_device_table = uniphier_ld11_boot_device_table,
115 		.boot_device_count = &uniphier_ld11_boot_device_count,
116 		.boot_device_is_usb = uniphier_ld20_boot_device_is_usb,
117 		.boot_is_swapped = uniphier_sbc_boot_is_swapped,
118 		.have_internal_stm = true,
119 	},
120 #endif
121 #if defined(CONFIG_ARCH_UNIPHIER_PXS3)
122 	{
123 		.soc_id = UNIPHIER_PXS3_ID,
124 		.boot_device_sel_shift = 1,
125 		.boot_device_table = uniphier_pxs3_boot_device_table,
126 		.boot_device_count = &uniphier_pxs3_boot_device_count,
127 		.boot_device_is_usb = uniphier_pxs3_boot_device_is_usb,
128 		.boot_is_swapped = uniphier_sbc_boot_is_swapped,
129 		.have_internal_stm = false,
130 	},
131 #endif
132 };
UNIPHIER_DEFINE_SOCDATA_FUNC(uniphier_get_boot_device_info,uniphier_boot_device_info)133 UNIPHIER_DEFINE_SOCDATA_FUNC(uniphier_get_boot_device_info,
134 			     uniphier_boot_device_info)
135 
136 static unsigned int __uniphier_boot_device_raw(
137 				const struct uniphier_boot_device_info *info)
138 {
139 	u32 pinmon;
140 	unsigned int boot_sel;
141 
142 	if (info->boot_is_swapped && info->boot_is_swapped())
143 		return BOOT_DEVICE_NOR;
144 
145 	pinmon = readl(sg_base + SG_PINMON0);
146 
147 	if (info->boot_device_is_sd && info->boot_device_is_sd(pinmon))
148 		return BOOT_DEVICE_MMC2;
149 
150 	if (info->boot_device_is_usb && info->boot_device_is_usb(pinmon))
151 		return BOOT_DEVICE_USB;
152 
153 	boot_sel = pinmon >> info->boot_device_sel_shift;
154 
155 	BUG_ON(!is_power_of_2(*info->boot_device_count));
156 	boot_sel &= *info->boot_device_count - 1;
157 
158 	return info->boot_device_table[boot_sel].boot_device;
159 }
160 
uniphier_boot_device_raw(void)161 unsigned int uniphier_boot_device_raw(void)
162 {
163 	const struct uniphier_boot_device_info *info;
164 
165 	info = uniphier_get_boot_device_info();
166 	if (!info) {
167 		pr_err("unsupported SoC\n");
168 		return BOOT_DEVICE_NONE;
169 	}
170 
171 	return __uniphier_boot_device_raw(info);
172 }
173 
spl_boot_device(void)174 u32 spl_boot_device(void)
175 {
176 	const struct uniphier_boot_device_info *info;
177 	u32 raw_mode;
178 
179 	info = uniphier_get_boot_device_info();
180 	if (!info) {
181 		pr_err("unsupported SoC\n");
182 		return BOOT_DEVICE_NONE;
183 	}
184 
185 	raw_mode = __uniphier_boot_device_raw(info);
186 
187 	return info->boot_device_fixup ?
188 				info->boot_device_fixup(raw_mode) : raw_mode;
189 }
190 
uniphier_have_internal_stm(void)191 int uniphier_have_internal_stm(void)
192 {
193 	const struct uniphier_boot_device_info *info;
194 
195 	info = uniphier_get_boot_device_info();
196 	if (!info) {
197 		pr_err("unsupported SoC\n");
198 		return -ENOTSUPP;
199 	}
200 
201 	return info->have_internal_stm;
202 }
203 
uniphier_boot_from_backend(void)204 int uniphier_boot_from_backend(void)
205 {
206 	return !!(readl(sg_base + SG_PINMON0) & BIT(27));
207 }
208 
209 #ifndef CONFIG_SPL_BUILD
210 
do_pinmon(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])211 static int do_pinmon(struct cmd_tbl *cmdtp, int flag, int argc,
212 		     char *const argv[])
213 {
214 	const struct uniphier_boot_device_info *info;
215 	u32 pinmon;
216 	unsigned int boot_device_count, boot_sel;
217 	int i;
218 
219 	info = uniphier_get_boot_device_info();
220 	if (!info) {
221 		pr_err("unsupported SoC\n");
222 		return CMD_RET_FAILURE;
223 	}
224 
225 	if (uniphier_have_internal_stm())
226 		printf("STB Micon: %s\n",
227 		       uniphier_boot_from_backend() ? "OFF" : "ON");
228 
229 	if (info->boot_is_swapped)
230 		printf("Boot Swap: %s\n",
231 		       info->boot_is_swapped() ? "ON" : "OFF");
232 
233 	pinmon = readl(sg_base + SG_PINMON0);
234 
235 	if (info->boot_device_is_sd)
236 		printf("SD Boot:  %s\n",
237 		       info->boot_device_is_sd(pinmon) ? "ON" : "OFF");
238 
239 	if (info->boot_device_is_usb)
240 		printf("USB Boot:  %s\n",
241 		       info->boot_device_is_usb(pinmon) ? "ON" : "OFF");
242 
243 	boot_device_count = *info->boot_device_count;
244 
245 	boot_sel = pinmon >> info->boot_device_sel_shift;
246 	boot_sel &= boot_device_count - 1;
247 
248 	printf("\nBoot Mode Sel:\n");
249 	for (i = 0; i < boot_device_count; i++)
250 		printf(" %c %02x %s\n", i == boot_sel ? '*' : ' ', i,
251 		       info->boot_device_table[i].desc);
252 
253 	return CMD_RET_SUCCESS;
254 }
255 
256 U_BOOT_CMD(
257 	pinmon,	1,	1,	do_pinmon,
258 	"pin monitor",
259 	""
260 );
261 
262 #endif /* !CONFIG_SPL_BUILD */
263