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