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