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