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