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