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 }; 26 27 static const struct uniphier_boot_device_info uniphier_boot_device_info[] = { 28 #if defined(CONFIG_ARCH_UNIPHIER_SLD3) 29 { 30 .soc_id = UNIPHIER_SLD3_ID, 31 .boot_device_sel_shift = 0, 32 .boot_device_table = uniphier_sld3_boot_device_table, 33 .boot_device_count = &uniphier_sld3_boot_device_count, 34 }, 35 #endif 36 #if defined(CONFIG_ARCH_UNIPHIER_LD4) 37 { 38 .soc_id = UNIPHIER_LD4_ID, 39 .boot_device_sel_shift = 1, 40 .boot_device_table = uniphier_ld4_boot_device_table, 41 .boot_device_count = &uniphier_ld4_boot_device_count, 42 }, 43 #endif 44 #if defined(CONFIG_ARCH_UNIPHIER_PRO4) 45 { 46 .soc_id = UNIPHIER_PRO4_ID, 47 .boot_device_sel_shift = 1, 48 .boot_device_table = uniphier_ld4_boot_device_table, 49 .boot_device_count = &uniphier_ld4_boot_device_count, 50 }, 51 #endif 52 #if defined(CONFIG_ARCH_UNIPHIER_SLD8) 53 { 54 .soc_id = UNIPHIER_SLD8_ID, 55 .boot_device_sel_shift = 1, 56 .boot_device_table = uniphier_ld4_boot_device_table, 57 .boot_device_count = &uniphier_ld4_boot_device_count, 58 }, 59 #endif 60 #if defined(CONFIG_ARCH_UNIPHIER_PRO5) 61 { 62 .soc_id = UNIPHIER_PRO5_ID, 63 .boot_device_sel_shift = 1, 64 .boot_device_table = uniphier_pro5_boot_device_table, 65 .boot_device_count = &uniphier_pro5_boot_device_count, 66 }, 67 #endif 68 #if defined(CONFIG_ARCH_UNIPHIER_PXS2) 69 { 70 .soc_id = UNIPHIER_PXS2_ID, 71 .boot_device_sel_shift = 1, 72 .boot_device_table = uniphier_pxs2_boot_device_table, 73 .boot_device_count = &uniphier_pxs2_boot_device_count, 74 .boot_device_is_usb = uniphier_pxs2_boot_device_is_usb, 75 .boot_device_fixup = uniphier_pxs2_boot_device_fixup, 76 }, 77 #endif 78 #if defined(CONFIG_ARCH_UNIPHIER_LD6B) 79 { 80 .soc_id = UNIPHIER_LD6B_ID, 81 .boot_device_sel_shift = 1, 82 .boot_device_table = uniphier_pxs2_boot_device_table, 83 .boot_device_count = &uniphier_pxs2_boot_device_count, 84 .boot_device_is_usb = uniphier_pxs2_boot_device_is_usb, 85 .boot_device_fixup = uniphier_pxs2_boot_device_fixup, 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 }, 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 }, 107 #endif 108 }; 109 UNIPHIER_DEFINE_SOCDATA_FUNC(uniphier_get_boot_device_info, 110 uniphier_boot_device_info) 111 112 static unsigned int __uniphier_boot_device_raw( 113 const struct uniphier_boot_device_info *info) 114 { 115 u32 pinmon; 116 unsigned int boot_sel; 117 118 if (boot_is_swapped()) 119 return BOOT_DEVICE_NOR; 120 121 pinmon = readl(SG_PINMON0); 122 123 if (info->boot_device_is_usb && info->boot_device_is_usb(pinmon)) 124 return BOOT_DEVICE_USB; 125 126 boot_sel = pinmon >> info->boot_device_sel_shift; 127 128 BUG_ON(!is_power_of_2(*info->boot_device_count)); 129 boot_sel &= *info->boot_device_count - 1; 130 131 return info->boot_device_table[boot_sel].boot_device; 132 } 133 134 unsigned int uniphier_boot_device_raw(void) 135 { 136 const struct uniphier_boot_device_info *info; 137 138 info = uniphier_get_boot_device_info(); 139 if (!info) { 140 pr_err("unsupported SoC\n"); 141 return BOOT_DEVICE_NONE; 142 } 143 144 return __uniphier_boot_device_raw(info); 145 } 146 147 u32 spl_boot_device(void) 148 { 149 const struct uniphier_boot_device_info *info; 150 u32 raw_mode; 151 152 info = uniphier_get_boot_device_info(); 153 if (!info) { 154 pr_err("unsupported SoC\n"); 155 return BOOT_DEVICE_NONE; 156 } 157 158 raw_mode = __uniphier_boot_device_raw(info); 159 160 return info->boot_device_fixup ? 161 info->boot_device_fixup(raw_mode) : raw_mode; 162 } 163 164 #ifndef CONFIG_SPL_BUILD 165 166 static int do_pinmon(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 167 { 168 const struct uniphier_boot_device_info *info; 169 u32 pinmon; 170 unsigned int boot_device_count, boot_sel; 171 int i; 172 173 info = uniphier_get_boot_device_info(); 174 if (!info) { 175 pr_err("unsupported SoC\n"); 176 return CMD_RET_FAILURE; 177 } 178 179 printf("Boot Swap: %s\n\n", boot_is_swapped() ? "ON" : "OFF"); 180 181 pinmon = readl(SG_PINMON0); 182 183 if (info->boot_device_is_usb) 184 printf("USB Boot: %s\n\n", 185 info->boot_device_is_usb(pinmon) ? "ON" : "OFF"); 186 187 boot_device_count = *info->boot_device_count; 188 189 boot_sel = pinmon >> info->boot_device_sel_shift; 190 boot_sel &= boot_device_count - 1; 191 192 printf("Boot Mode Sel:\n"); 193 for (i = 0; i < boot_device_count; i++) 194 printf(" %c %02x %s\n", i == boot_sel ? '*' : ' ', i, 195 info->boot_device_table[i].desc); 196 197 return CMD_RET_SUCCESS; 198 } 199 200 U_BOOT_CMD( 201 pinmon, 1, 1, do_pinmon, 202 "pin monitor", 203 "" 204 ); 205 206 #endif /* !CONFIG_SPL_BUILD */ 207