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 }; 119 UNIPHIER_DEFINE_SOCDATA_FUNC(uniphier_get_boot_device_info, 120 uniphier_boot_device_info) 121 122 static unsigned int __uniphier_boot_device_raw( 123 const struct uniphier_boot_device_info *info) 124 { 125 u32 pinmon; 126 unsigned int boot_sel; 127 128 if (boot_is_swapped()) 129 return BOOT_DEVICE_NOR; 130 131 pinmon = readl(SG_PINMON0); 132 133 if (info->boot_device_is_usb && info->boot_device_is_usb(pinmon)) 134 return BOOT_DEVICE_USB; 135 136 boot_sel = pinmon >> info->boot_device_sel_shift; 137 138 BUG_ON(!is_power_of_2(*info->boot_device_count)); 139 boot_sel &= *info->boot_device_count - 1; 140 141 return info->boot_device_table[boot_sel].boot_device; 142 } 143 144 unsigned int uniphier_boot_device_raw(void) 145 { 146 const struct uniphier_boot_device_info *info; 147 148 info = uniphier_get_boot_device_info(); 149 if (!info) { 150 pr_err("unsupported SoC\n"); 151 return BOOT_DEVICE_NONE; 152 } 153 154 return __uniphier_boot_device_raw(info); 155 } 156 157 u32 spl_boot_device(void) 158 { 159 const struct uniphier_boot_device_info *info; 160 u32 raw_mode; 161 162 info = uniphier_get_boot_device_info(); 163 if (!info) { 164 pr_err("unsupported SoC\n"); 165 return BOOT_DEVICE_NONE; 166 } 167 168 raw_mode = __uniphier_boot_device_raw(info); 169 170 return info->boot_device_fixup ? 171 info->boot_device_fixup(raw_mode) : raw_mode; 172 } 173 174 int uniphier_have_internal_stm(void) 175 { 176 const struct uniphier_boot_device_info *info; 177 178 info = uniphier_get_boot_device_info(); 179 if (!info) { 180 pr_err("unsupported SoC\n"); 181 return -ENOTSUPP; 182 } 183 184 return info->have_internal_stm; 185 } 186 187 int uniphier_boot_from_backend(void) 188 { 189 return !!(readl(SG_PINMON0) & BIT(27)); 190 } 191 192 #ifndef CONFIG_SPL_BUILD 193 194 static int do_pinmon(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 195 { 196 const struct uniphier_boot_device_info *info; 197 u32 pinmon; 198 unsigned int boot_device_count, boot_sel; 199 int i; 200 201 info = uniphier_get_boot_device_info(); 202 if (!info) { 203 pr_err("unsupported SoC\n"); 204 return CMD_RET_FAILURE; 205 } 206 207 if (uniphier_have_internal_stm()) 208 printf("STB Micon: %s\n", 209 uniphier_boot_from_backend() ? "OFF" : "ON"); 210 211 printf("Boot Swap: %s\n", boot_is_swapped() ? "ON" : "OFF"); 212 213 pinmon = readl(SG_PINMON0); 214 215 if (info->boot_device_is_usb) 216 printf("USB Boot: %s\n", 217 info->boot_device_is_usb(pinmon) ? "ON" : "OFF"); 218 219 boot_device_count = *info->boot_device_count; 220 221 boot_sel = pinmon >> info->boot_device_sel_shift; 222 boot_sel &= boot_device_count - 1; 223 224 printf("\nBoot Mode Sel:\n"); 225 for (i = 0; i < boot_device_count; i++) 226 printf(" %c %02x %s\n", i == boot_sel ? '*' : ' ', i, 227 info->boot_device_table[i].desc); 228 229 return CMD_RET_SUCCESS; 230 } 231 232 U_BOOT_CMD( 233 pinmon, 1, 1, do_pinmon, 234 "pin monitor", 235 "" 236 ); 237 238 #endif /* !CONFIG_SPL_BUILD */ 239