- Fix regressions caused by the previous reworks - Add pin configuration support - Re-work SPL code - Update DRAM and PLL setup code - Enable needed configs, disable unneeded configsmaster
commit
d38de7cb03
@ -0,0 +1,19 @@ |
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += boot-device.o
|
||||
|
||||
obj-$(CONFIG_ARCH_UNIPHIER_SLD3) += boot-device-sld3.o
|
||||
obj-$(CONFIG_ARCH_UNIPHIER_LD4) += boot-device-ld4.o
|
||||
obj-$(CONFIG_ARCH_UNIPHIER_PRO4) += boot-device-ld4.o
|
||||
obj-$(CONFIG_ARCH_UNIPHIER_SLD8) += boot-device-ld4.o
|
||||
obj-$(CONFIG_ARCH_UNIPHIER_PRO5) += boot-device-pro5.o
|
||||
obj-$(CONFIG_ARCH_UNIPHIER_PXS2) += boot-device-pxs2.o
|
||||
obj-$(CONFIG_ARCH_UNIPHIER_LD6B) += boot-device-pxs2.o
|
||||
obj-$(CONFIG_ARCH_UNIPHIER_LD11) += boot-device-ld11.o
|
||||
obj-$(CONFIG_ARCH_UNIPHIER_LD20) += boot-device-ld11.o
|
||||
|
||||
ifdef CONFIG_SPL_BUILD |
||||
obj-$(CONFIG_SPL_BOARD_LOAD_IMAGE) += spl_board.o
|
||||
endif |
@ -0,0 +1,206 @@ |
||||
/*
|
||||
* Copyright (C) 2015-2017 Socionext Inc. |
||||
* Author: Masahiro Yamada <yamada.masahiro@socionext.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <spl.h> |
||||
#include <linux/log2.h> |
||||
|
||||
#include "../init.h" |
||||
#include "../sbc/sbc-regs.h" |
||||
#include "../sg-regs.h" |
||||
#include "../soc-info.h" |
||||
#include "boot-device.h" |
||||
|
||||
struct uniphier_boot_device_info { |
||||
unsigned int soc_id; |
||||
unsigned int boot_device_sel_shift; |
||||
const struct uniphier_boot_device *boot_device_table; |
||||
const unsigned int *boot_device_count; |
||||
int (*boot_device_is_usb)(u32 pinmon); |
||||
unsigned int (*boot_device_fixup)(unsigned int mode); |
||||
}; |
||||
|
||||
static const struct uniphier_boot_device_info uniphier_boot_device_info[] = { |
||||
#if defined(CONFIG_ARCH_UNIPHIER_SLD3) |
||||
{ |
||||
.soc_id = UNIPHIER_SLD3_ID, |
||||
.boot_device_sel_shift = 0, |
||||
.boot_device_table = uniphier_sld3_boot_device_table, |
||||
.boot_device_count = &uniphier_sld3_boot_device_count, |
||||
}, |
||||
#endif |
||||
#if defined(CONFIG_ARCH_UNIPHIER_LD4) |
||||
{ |
||||
.soc_id = UNIPHIER_LD4_ID, |
||||
.boot_device_sel_shift = 1, |
||||
.boot_device_table = uniphier_ld4_boot_device_table, |
||||
.boot_device_count = &uniphier_ld4_boot_device_count, |
||||
}, |
||||
#endif |
||||
#if defined(CONFIG_ARCH_UNIPHIER_PRO4) |
||||
{ |
||||
.soc_id = UNIPHIER_PRO4_ID, |
||||
.boot_device_sel_shift = 1, |
||||
.boot_device_table = uniphier_ld4_boot_device_table, |
||||
.boot_device_count = &uniphier_ld4_boot_device_count, |
||||
}, |
||||
#endif |
||||
#if defined(CONFIG_ARCH_UNIPHIER_SLD8) |
||||
{ |
||||
.soc_id = UNIPHIER_SLD8_ID, |
||||
.boot_device_sel_shift = 1, |
||||
.boot_device_table = uniphier_ld4_boot_device_table, |
||||
.boot_device_count = &uniphier_ld4_boot_device_count, |
||||
}, |
||||
#endif |
||||
#if defined(CONFIG_ARCH_UNIPHIER_PRO5) |
||||
{ |
||||
.soc_id = UNIPHIER_PRO5_ID, |
||||
.boot_device_sel_shift = 1, |
||||
.boot_device_table = uniphier_pro5_boot_device_table, |
||||
.boot_device_count = &uniphier_pro5_boot_device_count, |
||||
}, |
||||
#endif |
||||
#if defined(CONFIG_ARCH_UNIPHIER_PXS2) |
||||
{ |
||||
.soc_id = UNIPHIER_PXS2_ID, |
||||
.boot_device_sel_shift = 1, |
||||
.boot_device_table = uniphier_pxs2_boot_device_table, |
||||
.boot_device_count = &uniphier_pxs2_boot_device_count, |
||||
.boot_device_is_usb = uniphier_pxs2_boot_device_is_usb, |
||||
.boot_device_fixup = uniphier_pxs2_boot_device_fixup, |
||||
}, |
||||
#endif |
||||
#if defined(CONFIG_ARCH_UNIPHIER_LD6B) |
||||
{ |
||||
.soc_id = UNIPHIER_LD6B_ID, |
||||
.boot_device_sel_shift = 1, |
||||
.boot_device_table = uniphier_pxs2_boot_device_table, |
||||
.boot_device_count = &uniphier_pxs2_boot_device_count, |
||||
.boot_device_is_usb = uniphier_pxs2_boot_device_is_usb, |
||||
.boot_device_fixup = uniphier_pxs2_boot_device_fixup, |
||||
}, |
||||
#endif |
||||
#if defined(CONFIG_ARCH_UNIPHIER_LD11) |
||||
{ |
||||
.soc_id = UNIPHIER_LD11_ID, |
||||
.boot_device_sel_shift = 1, |
||||
.boot_device_table = uniphier_ld11_boot_device_table, |
||||
.boot_device_count = &uniphier_ld11_boot_device_count, |
||||
.boot_device_is_usb = uniphier_ld11_boot_device_is_usb, |
||||
.boot_device_fixup = uniphier_ld11_boot_device_fixup, |
||||
}, |
||||
#endif |
||||
#if defined(CONFIG_ARCH_UNIPHIER_LD20) |
||||
{ |
||||
.soc_id = UNIPHIER_LD20_ID, |
||||
.boot_device_sel_shift = 1, |
||||
.boot_device_table = uniphier_ld11_boot_device_table, |
||||
.boot_device_count = &uniphier_ld11_boot_device_count, |
||||
.boot_device_is_usb = uniphier_ld20_boot_device_is_usb, |
||||
.boot_device_fixup = uniphier_ld11_boot_device_fixup, |
||||
}, |
||||
#endif |
||||
}; |
||||
UNIPHIER_DEFINE_SOCDATA_FUNC(uniphier_get_boot_device_info, |
||||
uniphier_boot_device_info) |
||||
|
||||
static unsigned int __uniphier_boot_device_raw( |
||||
const struct uniphier_boot_device_info *info) |
||||
{ |
||||
u32 pinmon; |
||||
unsigned int boot_sel; |
||||
|
||||
if (boot_is_swapped()) |
||||
return BOOT_DEVICE_NOR; |
||||
|
||||
pinmon = readl(SG_PINMON0); |
||||
|
||||
if (info->boot_device_is_usb && info->boot_device_is_usb(pinmon)) |
||||
return BOOT_DEVICE_USB; |
||||
|
||||
boot_sel = pinmon >> info->boot_device_sel_shift; |
||||
|
||||
BUG_ON(!is_power_of_2(*info->boot_device_count)); |
||||
boot_sel &= *info->boot_device_count - 1; |
||||
|
||||
return info->boot_device_table[boot_sel].boot_device; |
||||
} |
||||
|
||||
unsigned int uniphier_boot_device_raw(void) |
||||
{ |
||||
const struct uniphier_boot_device_info *info; |
||||
|
||||
info = uniphier_get_boot_device_info(); |
||||
if (!info) { |
||||
pr_err("unsupported SoC\n"); |
||||
return BOOT_DEVICE_NONE; |
||||
} |
||||
|
||||
return __uniphier_boot_device_raw(info); |
||||
} |
||||
|
||||
u32 spl_boot_device(void) |
||||
{ |
||||
const struct uniphier_boot_device_info *info; |
||||
u32 raw_mode; |
||||
|
||||
info = uniphier_get_boot_device_info(); |
||||
if (!info) { |
||||
pr_err("unsupported SoC\n"); |
||||
return BOOT_DEVICE_NONE; |
||||
} |
||||
|
||||
raw_mode = __uniphier_boot_device_raw(info); |
||||
|
||||
return info->boot_device_fixup ? |
||||
info->boot_device_fixup(raw_mode) : raw_mode; |
||||
} |
||||
|
||||
#ifndef CONFIG_SPL_BUILD |
||||
|
||||
static int do_pinmon(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
||||
{ |
||||
const struct uniphier_boot_device_info *info; |
||||
u32 pinmon; |
||||
unsigned int boot_device_count, boot_sel; |
||||
int i; |
||||
|
||||
info = uniphier_get_boot_device_info(); |
||||
if (!info) { |
||||
pr_err("unsupported SoC\n"); |
||||
return CMD_RET_FAILURE; |
||||
} |
||||
|
||||
printf("Boot Swap: %s\n\n", boot_is_swapped() ? "ON" : "OFF"); |
||||
|
||||
pinmon = readl(SG_PINMON0); |
||||
|
||||
if (info->boot_device_is_usb) |
||||
printf("USB Boot: %s\n\n", |
||||
info->boot_device_is_usb(pinmon) ? "ON" : "OFF"); |
||||
|
||||
boot_device_count = *info->boot_device_count; |
||||
|
||||
boot_sel = pinmon >> info->boot_device_sel_shift; |
||||
boot_sel &= boot_device_count - 1; |
||||
|
||||
printf("Boot Mode Sel:\n"); |
||||
for (i = 0; i < boot_device_count; i++) |
||||
printf(" %c %02x %s\n", i == boot_sel ? '*' : ' ', i, |
||||
info->boot_device_table[i].desc); |
||||
|
||||
return CMD_RET_SUCCESS; |
||||
} |
||||
|
||||
U_BOOT_CMD( |
||||
pinmon, 1, 1, do_pinmon, |
||||
"pin monitor", |
||||
"" |
||||
); |
||||
|
||||
#endif /* !CONFIG_SPL_BUILD */ |
@ -0,0 +1,35 @@ |
||||
/*
|
||||
* Copyright (C) 2017 Socionext Inc. |
||||
* Author: Masahiro Yamada <yamada.masahiro@socionext.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#ifndef _UNIPHIER_BOOT_DEVICE_H_ |
||||
#define _UNIPHIER_BOOT_DEVICE_H_ |
||||
|
||||
struct uniphier_boot_device { |
||||
unsigned int boot_device; |
||||
const char *desc; |
||||
}; |
||||
|
||||
extern const struct uniphier_boot_device uniphier_sld3_boot_device_table[]; |
||||
extern const struct uniphier_boot_device uniphier_ld4_boot_device_table[]; |
||||
extern const struct uniphier_boot_device uniphier_pro5_boot_device_table[]; |
||||
extern const struct uniphier_boot_device uniphier_pxs2_boot_device_table[]; |
||||
extern const struct uniphier_boot_device uniphier_ld11_boot_device_table[]; |
||||
|
||||
extern const unsigned int uniphier_sld3_boot_device_count; |
||||
extern const unsigned int uniphier_ld4_boot_device_count; |
||||
extern const unsigned int uniphier_pro5_boot_device_count; |
||||
extern const unsigned int uniphier_pxs2_boot_device_count; |
||||
extern const unsigned int uniphier_ld11_boot_device_count; |
||||
|
||||
int uniphier_pxs2_boot_device_is_usb(u32 pinmon); |
||||
int uniphier_ld11_boot_device_is_usb(u32 pinmon); |
||||
int uniphier_ld20_boot_device_is_usb(u32 pinmon); |
||||
|
||||
unsigned int uniphier_pxs2_boot_device_fixup(unsigned int mode); |
||||
unsigned int uniphier_ld11_boot_device_fixup(unsigned int mode); |
||||
|
||||
#endif /* _UNIPHIER_BOOT_DEVICE_H_ */ |
@ -0,0 +1,262 @@ |
||||
/*
|
||||
* Copyright (C) 2017 Socionext Inc. |
||||
* Author: Masahiro Yamada <yamada.masahiro@socionext.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <spl.h> |
||||
#include <linux/bitops.h> |
||||
#include <linux/compat.h> |
||||
#include <linux/io.h> |
||||
#include <asm/processor.h> |
||||
|
||||
#include "../soc-info.h" |
||||
|
||||
#define MMC_CMD_SWITCH 6 |
||||
#define MMC_CMD_SELECT_CARD 7 |
||||
#define MMC_CMD_SEND_CSD 9 |
||||
#define MMC_CMD_READ_MULTIPLE_BLOCK 18 |
||||
|
||||
#define EXT_CSD_PART_CONF 179 /* R/W */ |
||||
|
||||
#define MMC_RSP_PRESENT BIT(0) |
||||
#define MMC_RSP_136 BIT(1) /* 136 bit response */ |
||||
#define MMC_RSP_CRC BIT(2) /* expect valid crc */ |
||||
#define MMC_RSP_BUSY BIT(3) /* card may send busy */ |
||||
#define MMC_RSP_OPCODE BIT(4) /* response contains opcode */ |
||||
|
||||
#define MMC_RSP_NONE (0) |
||||
#define MMC_RSP_R1 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) |
||||
#define MMC_RSP_R1b (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | \ |
||||
MMC_RSP_BUSY) |
||||
#define MMC_RSP_R2 (MMC_RSP_PRESENT | MMC_RSP_136 | MMC_RSP_CRC) |
||||
#define MMC_RSP_R3 (MMC_RSP_PRESENT) |
||||
#define MMC_RSP_R4 (MMC_RSP_PRESENT) |
||||
#define MMC_RSP_R5 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) |
||||
#define MMC_RSP_R6 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) |
||||
#define MMC_RSP_R7 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) |
||||
|
||||
#define SDHCI_DMA_ADDRESS 0x00 |
||||
#define SDHCI_BLOCK_SIZE 0x04 |
||||
#define SDHCI_MAKE_BLKSZ(dma, blksz) ((((dma) & 0x7) << 12) | ((blksz) & 0xFFF)) |
||||
#define SDHCI_BLOCK_COUNT 0x06 |
||||
#define SDHCI_ARGUMENT 0x08 |
||||
#define SDHCI_TRANSFER_MODE 0x0C |
||||
#define SDHCI_TRNS_DMA BIT(0) |
||||
#define SDHCI_TRNS_BLK_CNT_EN BIT(1) |
||||
#define SDHCI_TRNS_ACMD12 BIT(2) |
||||
#define SDHCI_TRNS_READ BIT(4) |
||||
#define SDHCI_TRNS_MULTI BIT(5) |
||||
#define SDHCI_COMMAND 0x0E |
||||
#define SDHCI_CMD_RESP_MASK 0x03 |
||||
#define SDHCI_CMD_CRC 0x08 |
||||
#define SDHCI_CMD_INDEX 0x10 |
||||
#define SDHCI_CMD_DATA 0x20 |
||||
#define SDHCI_CMD_ABORTCMD 0xC0 |
||||
#define SDHCI_CMD_RESP_NONE 0x00 |
||||
#define SDHCI_CMD_RESP_LONG 0x01 |
||||
#define SDHCI_CMD_RESP_SHORT 0x02 |
||||
#define SDHCI_CMD_RESP_SHORT_BUSY 0x03 |
||||
#define SDHCI_MAKE_CMD(c, f) ((((c) & 0xff) << 8) | ((f) & 0xff)) |
||||
#define SDHCI_RESPONSE 0x10 |
||||
#define SDHCI_HOST_CONTROL 0x28 |
||||
#define SDHCI_CTRL_DMA_MASK 0x18 |
||||
#define SDHCI_CTRL_SDMA 0x00 |
||||
#define SDHCI_BLOCK_GAP_CONTROL 0x2A |
||||
#define SDHCI_SOFTWARE_RESET 0x2F |
||||
#define SDHCI_RESET_CMD 0x02 |
||||
#define SDHCI_RESET_DATA 0x04 |
||||
#define SDHCI_INT_STATUS 0x30 |
||||
#define SDHCI_INT_RESPONSE BIT(0) |
||||
#define SDHCI_INT_DATA_END BIT(1) |
||||
#define SDHCI_INT_ERROR BIT(15) |
||||
#define SDHCI_SIGNAL_ENABLE 0x38 |
||||
|
||||
/* RCA assigned by Boot ROM */ |
||||
#define UNIPHIER_EMMC_RCA 0x1000 |
||||
|
||||
struct uniphier_mmc_cmd { |
||||
unsigned int cmdidx; |
||||
unsigned int resp_type; |
||||
unsigned int cmdarg; |
||||
unsigned int is_data; |
||||
}; |
||||
|
||||
static int uniphier_emmc_send_cmd(void __iomem *host_base, |
||||
struct uniphier_mmc_cmd *cmd) |
||||
{ |
||||
u32 mode = 0; |
||||
u32 mask = SDHCI_INT_RESPONSE; |
||||
u32 stat, flags; |
||||
|
||||
writel(U32_MAX, host_base + SDHCI_INT_STATUS); |
||||
writel(0, host_base + SDHCI_SIGNAL_ENABLE); |
||||
writel(cmd->cmdarg, host_base + SDHCI_ARGUMENT); |
||||
|
||||
if (cmd->is_data) |
||||
mode = SDHCI_TRNS_DMA | SDHCI_TRNS_BLK_CNT_EN | |
||||
SDHCI_TRNS_ACMD12 | SDHCI_TRNS_READ | |
||||
SDHCI_TRNS_MULTI; |
||||
|
||||
writew(mode, host_base + SDHCI_TRANSFER_MODE); |
||||
|
||||
if (!(cmd->resp_type & MMC_RSP_PRESENT)) |
||||
flags = SDHCI_CMD_RESP_NONE; |
||||
else if (cmd->resp_type & MMC_RSP_136) |
||||
flags = SDHCI_CMD_RESP_LONG; |
||||
else if (cmd->resp_type & MMC_RSP_BUSY) |
||||
flags = SDHCI_CMD_RESP_SHORT_BUSY; |
||||
else |
||||
flags = SDHCI_CMD_RESP_SHORT; |
||||
|
||||
if (cmd->resp_type & MMC_RSP_CRC) |
||||
flags |= SDHCI_CMD_CRC; |
||||
if (cmd->resp_type & MMC_RSP_OPCODE) |
||||
flags |= SDHCI_CMD_INDEX; |
||||
if (cmd->is_data) |
||||
flags |= SDHCI_CMD_DATA; |
||||
|
||||
if (cmd->resp_type & MMC_RSP_BUSY || cmd->is_data) |
||||
mask |= SDHCI_INT_DATA_END; |
||||
|
||||
writew(SDHCI_MAKE_CMD(cmd->cmdidx, flags), host_base + SDHCI_COMMAND); |
||||
|
||||
do { |
||||
stat = readl(host_base + SDHCI_INT_STATUS); |
||||
if (stat & SDHCI_INT_ERROR) |
||||
return -EIO; |
||||
|
||||
} while ((stat & mask) != mask); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int uniphier_emmc_switch_part(void __iomem *host_base, int part_num) |
||||
{ |
||||
struct uniphier_mmc_cmd cmd = {}; |
||||
|
||||
cmd.cmdidx = MMC_CMD_SWITCH; |
||||
cmd.resp_type = MMC_RSP_R1b; |
||||
cmd.cmdarg = (EXT_CSD_PART_CONF << 16) | (part_num << 8) | (3 << 24); |
||||
|
||||
return uniphier_emmc_send_cmd(host_base, &cmd); |
||||
} |
||||
|
||||
static int uniphier_emmc_is_over_2gb(void __iomem *host_base) |
||||
{ |
||||
struct uniphier_mmc_cmd cmd = {}; |
||||
u32 csd40, csd72; /* CSD[71:40], CSD[103:72] */ |
||||
int ret; |
||||
|
||||
cmd.cmdidx = MMC_CMD_SEND_CSD; |
||||
cmd.resp_type = MMC_RSP_R2; |
||||
cmd.cmdarg = UNIPHIER_EMMC_RCA << 16; |
||||
|
||||
ret = uniphier_emmc_send_cmd(host_base, &cmd); |
||||
if (ret) |
||||
return ret; |
||||
|
||||
csd40 = readl(host_base + SDHCI_RESPONSE + 4); |
||||
csd72 = readl(host_base + SDHCI_RESPONSE + 8); |
||||
|
||||
return !(~csd40 & 0xffc00380) && !(~csd72 & 0x3); |
||||
} |
||||
|
||||
static int uniphier_emmc_load_image(void __iomem *host_base, u32 dev_addr, |
||||
unsigned long load_addr, u32 block_cnt) |
||||
{ |
||||
struct uniphier_mmc_cmd cmd = {}; |
||||
u8 tmp; |
||||
|
||||
WARN_ON(load_addr >> 32); |
||||
|
||||
writel(load_addr, host_base + SDHCI_DMA_ADDRESS); |
||||
writew(SDHCI_MAKE_BLKSZ(7, 512), host_base + SDHCI_BLOCK_SIZE); |
||||
writew(block_cnt, host_base + SDHCI_BLOCK_COUNT); |
||||
|
||||
tmp = readb(host_base + SDHCI_HOST_CONTROL); |
||||
tmp &= ~SDHCI_CTRL_DMA_MASK; |
||||
tmp |= SDHCI_CTRL_SDMA; |
||||
writeb(tmp, host_base + SDHCI_HOST_CONTROL); |
||||
|
||||
tmp = readb(host_base + SDHCI_BLOCK_GAP_CONTROL); |
||||
tmp &= ~1; /* clear Stop At Block Gap Request */ |
||||
writeb(tmp, host_base + SDHCI_BLOCK_GAP_CONTROL); |
||||
|
||||
cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; |
||||
cmd.resp_type = MMC_RSP_R1; |
||||
cmd.cmdarg = dev_addr; |
||||
cmd.is_data = 1; |
||||
|
||||
return uniphier_emmc_send_cmd(host_base, &cmd); |
||||
} |
||||
|
||||
static int spl_board_load_image(struct spl_image_info *spl_image, |
||||
struct spl_boot_device *bootdev) |
||||
{ |
||||
u32 dev_addr = CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR; |
||||
void __iomem *host_base = (void __iomem *)0x5a000200; |
||||
struct uniphier_mmc_cmd cmd = {}; |
||||
int ret; |
||||
|
||||
/*
|
||||
* deselect card before SEND_CSD command. |
||||
* Do not check the return code. It fails, but it is OK. |
||||
*/ |
||||
cmd.cmdidx = MMC_CMD_SELECT_CARD; |
||||
cmd.resp_type = MMC_RSP_R1; |
||||
|
||||
uniphier_emmc_send_cmd(host_base, &cmd); /* CMD7 (arg=0) */ |
||||
|
||||
/* reset CMD Line */ |
||||
writeb(SDHCI_RESET_CMD | SDHCI_RESET_DATA, |
||||
host_base + SDHCI_SOFTWARE_RESET); |
||||
while (readb(host_base + SDHCI_SOFTWARE_RESET)) |
||||
cpu_relax(); |
||||
|
||||
ret = uniphier_emmc_is_over_2gb(host_base); |
||||
if (ret < 0) |
||||
return ret; |
||||
if (ret) { |
||||
debug("card is block addressing\n"); |
||||
} else { |
||||
debug("card is byte addressing\n"); |
||||
dev_addr *= 512; |
||||
} |
||||
|
||||
cmd.cmdarg = UNIPHIER_EMMC_RCA << 16; |
||||
|
||||
/* select card again */ |
||||
ret = uniphier_emmc_send_cmd(host_base, &cmd); |
||||
if (ret) |
||||
printf("failed to select card\n"); |
||||
|
||||
/* Switch to Boot Partition 1 */ |
||||
ret = uniphier_emmc_switch_part(host_base, 1); |
||||
if (ret) |
||||
printf("failed to switch partition\n"); |
||||
|
||||
ret = uniphier_emmc_load_image(host_base, dev_addr, |
||||
CONFIG_SYS_TEXT_BASE, 1); |
||||
if (ret) { |
||||
printf("failed to load image\n"); |
||||
return ret; |
||||
} |
||||
|
||||
ret = spl_parse_image_header(spl_image, (void *)CONFIG_SYS_TEXT_BASE); |
||||
if (ret) |
||||
return ret; |
||||
|
||||
ret = uniphier_emmc_load_image(host_base, dev_addr, |
||||
spl_image->load_addr, |
||||
spl_image->size / 512); |
||||
if (ret) { |
||||
printf("failed to load image\n"); |
||||
return ret; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
SPL_LOAD_IMAGE_METHOD("eMMC", 0, BOOT_DEVICE_BOARD, spl_board_load_image); |
@ -1,21 +0,0 @@ |
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += boot-mode.o
|
||||
|
||||
obj-$(CONFIG_ARCH_UNIPHIER_SLD3) += boot-mode-sld3.o
|
||||
obj-$(CONFIG_ARCH_UNIPHIER_LD4) += boot-mode-ld4.o
|
||||
obj-$(CONFIG_ARCH_UNIPHIER_PRO4) += boot-mode-ld4.o
|
||||
obj-$(CONFIG_ARCH_UNIPHIER_SLD8) += boot-mode-ld4.o
|
||||
obj-$(CONFIG_ARCH_UNIPHIER_PRO5) += boot-mode-pro5.o
|
||||
obj-$(CONFIG_ARCH_UNIPHIER_PXS2) += boot-mode-pxs2.o
|
||||
obj-$(CONFIG_ARCH_UNIPHIER_LD6B) += boot-mode-pxs2.o
|
||||
obj-$(CONFIG_ARCH_UNIPHIER_LD11) += boot-mode-ld20.o
|
||||
obj-$(CONFIG_ARCH_UNIPHIER_LD20) += boot-mode-ld20.o
|
||||
|
||||
ifdef CONFIG_SPL_BUILD |
||||
obj-$(CONFIG_SPL_BOARD_LOAD_IMAGE) += spl_board.o
|
||||
else |
||||
obj-$(CONFIG_CMD_PINMON) += cmd_pinmon.o
|
||||
endif |
@ -1,29 +0,0 @@ |
||||
/*
|
||||
* Copyright (C) 2011-2015 Masahiro Yamada <yamada.masahiro@socionext.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#ifndef _ASM_BOOT_DEVICE_H_ |
||||
#define _ASM_BOOT_DEVICE_H_ |
||||
|
||||
struct boot_device_info { |
||||
u32 type; |
||||
char *info; |
||||
}; |
||||
|
||||
u32 uniphier_sld3_boot_device(void); |
||||
u32 uniphier_ld4_boot_device(void); |
||||
u32 uniphier_pro5_boot_device(void); |
||||
u32 uniphier_pxs2_boot_device(void); |
||||
u32 uniphier_ld20_boot_device(void); |
||||
|
||||
void uniphier_sld3_boot_mode_show(void); |
||||
void uniphier_ld4_boot_mode_show(void); |
||||
void uniphier_pro5_boot_mode_show(void); |
||||
void uniphier_pxs2_boot_mode_show(void); |
||||
void uniphier_ld20_boot_mode_show(void); |
||||
|
||||
u32 spl_boot_device_raw(void); |
||||
|
||||
#endif /* _ASM_BOOT_DEVICE_H_ */ |
@ -1,140 +0,0 @@ |
||||
/*
|
||||
* Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <mmc.h> |
||||
#include <spl.h> |
||||
#include <linux/errno.h> |
||||
|
||||
#include "../sbc/sbc-regs.h" |
||||
#include "../soc-info.h" |
||||
#include "boot-device.h" |
||||
|
||||
u32 spl_boot_device_raw(void) |
||||
{ |
||||
if (boot_is_swapped()) |
||||
return BOOT_DEVICE_NOR; |
||||
|
||||
switch (uniphier_get_soc_id()) { |
||||
#if defined(CONFIG_ARCH_UNIPHIER_SLD3) |
||||
case UNIPHIER_SLD3_ID: |
||||
return uniphier_sld3_boot_device(); |
||||
#endif |
||||
#if defined(CONFIG_ARCH_UNIPHIER_LD4) || defined(CONFIG_ARCH_UNIPHIER_PRO4) || \ |
||||
defined(CONFIG_ARCH_UNIPHIER_SLD8) |
||||
case UNIPHIER_LD4_ID: |
||||
case UNIPHIER_PRO4_ID: |
||||
case UNIPHIER_SLD8_ID: |
||||
return uniphier_ld4_boot_device(); |
||||
#endif |
||||
#if defined(CONFIG_ARCH_UNIPHIER_PRO5) |
||||
case UNIPHIER_PRO5_ID: |
||||
return uniphier_pro5_boot_device(); |
||||
#endif |
||||
#if defined(CONFIG_ARCH_UNIPHIER_PXS2) || defined(CONFIG_ARCH_UNIPHIER_LD6B) |
||||
case UNIPHIER_PXS2_ID: |
||||
case UNIPHIER_LD6B_ID: |
||||
return uniphier_pxs2_boot_device(); |
||||
#endif |
||||
#if defined(CONFIG_ARCH_UNIPHIER_LD11) || defined(CONFIG_ARCH_UNIPHIER_LD20) |
||||
case UNIPHIER_LD11_ID: |
||||
case UNIPHIER_LD20_ID: |
||||
return uniphier_ld20_boot_device(); |
||||
#endif |
||||
default: |
||||
return BOOT_DEVICE_NONE; |
||||
} |
||||
} |
||||
|
||||
u32 spl_boot_device(void) |
||||
{ |
||||
u32 mode; |
||||
|
||||
mode = spl_boot_device_raw(); |
||||
|
||||
switch (uniphier_get_soc_id()) { |
||||
#if defined(CONFIG_ARCH_UNIPHIER_PXS2) || defined(CONFIG_ARCH_UNIPHIER_LD6B) |
||||
case UNIPHIER_PXS2_ID: |
||||
case UNIPHIER_LD6B_ID: |
||||
if (mode == BOOT_DEVICE_USB) |
||||
mode = BOOT_DEVICE_NOR; |
||||
break; |
||||
#endif |
||||
#if defined(CONFIG_ARCH_UNIPHIER_LD11) || defined(CONFIG_ARCH_UNIPHIER_LD20) |
||||
case UNIPHIER_LD11_ID: |
||||
case UNIPHIER_LD20_ID: |
||||
if (mode == BOOT_DEVICE_MMC1 || mode == BOOT_DEVICE_USB) |
||||
mode = BOOT_DEVICE_BOARD; |
||||
break; |
||||
#endif |
||||
default: |
||||
break; |
||||
} |
||||
|
||||
return mode; |
||||
} |
||||
|
||||
u32 spl_boot_mode(const u32 boot_device) |
||||
{ |
||||
struct mmc *mmc; |
||||
|
||||
/*
|
||||
* work around a bug in the Boot ROM of PH1-sLD3, LD4, Pro4, and sLD8: |
||||
* |
||||
* The boot ROM in these SoCs breaks the PARTITION_CONFIG [179] of |
||||
* Extended CSD register; when switching to the Boot Partition 1, the |
||||
* Boot ROM should issue the SWITCH command (CMD6) with Set Bits for |
||||
* the Access Bits, but in fact it uses Write Byte for the Access Bits. |
||||
* As a result, the BOOT_PARTITION_ENABLE field of the PARTITION_CONFIG |
||||
* is lost. This bug was fixed for PH1-Pro5 and later SoCs. |
||||
* |
||||
* Fixup mmc->part_config here because it is used to determine the |
||||
* partition which the U-Boot image is read from. |
||||
*/ |
||||
mmc = find_mmc_device(0); |
||||
mmc->part_config &= ~EXT_CSD_BOOT_PART_NUM(PART_ACCESS_MASK); |
||||
mmc->part_config |= EXT_CSD_BOOT_PARTITION_ENABLE; |
||||
|
||||
return MMCSD_MODE_EMMCBOOT; |
||||
} |
||||
|
||||
#if defined(CONFIG_DM_MMC) && !defined(CONFIG_SPL_BUILD) |
||||
static int find_first_mmc_device(void) |
||||
{ |
||||
struct mmc *mmc; |
||||
int i; |
||||
|
||||
for (i = 0; (mmc = find_mmc_device(i)); i++) { |
||||
if (!mmc_init(mmc) && IS_MMC(mmc)) |
||||
return i; |
||||
} |
||||
|
||||
return -ENODEV; |
||||
} |
||||
|
||||
int mmc_get_env_dev(void) |
||||
{ |
||||
return find_first_mmc_device(); |
||||
} |
||||
|
||||
static int do_mmcsetn(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
||||
{ |
||||
int dev; |
||||
|
||||
dev = find_first_mmc_device(); |
||||
if (dev < 0) |
||||
return CMD_RET_FAILURE; |
||||
|
||||
setenv_ulong("mmc_first_dev", dev); |
||||
return CMD_RET_SUCCESS; |
||||
} |
||||
|
||||
U_BOOT_CMD( |
||||
mmcsetn, 1, 1, do_mmcsetn, |
||||
"Set the first MMC (not SD) dev number to \"mmc_first_dev\" environment", |
||||
"" |
||||
); |
||||
#endif |
@ -1,59 +0,0 @@ |
||||
/*
|
||||
* Copyright (C) 2014-2015 Masahiro Yamada <yamada.masahiro@socionext.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
|
||||
#include "../sbc/sbc-regs.h" |
||||
#include "../soc-info.h" |
||||
#include "boot-device.h" |
||||
|
||||
static int do_pinmon(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
||||
{ |
||||
printf("Boot Swap: %s\n\n", boot_is_swapped() ? "ON" : "OFF"); |
||||
|
||||
switch (uniphier_get_soc_id()) { |
||||
#if defined(CONFIG_ARCH_UNIPHIER_SLD3) |
||||
case UNIPHIER_SLD3_ID: |
||||
uniphier_sld3_boot_mode_show(); |
||||
break; |
||||
#endif |
||||
#if defined(CONFIG_ARCH_UNIPHIER_LD4) || defined(CONFIG_ARCH_UNIPHIER_PRO4) || \ |
||||
defined(CONFIG_ARCH_UNIPHIER_SLD8) |
||||
case UNIPHIER_LD4_ID: |
||||
case UNIPHIER_PRO4_ID: |
||||
case UNIPHIER_SLD8_ID: |
||||
uniphier_ld4_boot_mode_show(); |
||||
break; |
||||
#endif |
||||
#if defined(CONFIG_ARCH_UNIPHIER_PRO5) |
||||
case UNIPHIER_PRO5_ID: |
||||
uniphier_pro5_boot_mode_show(); |
||||
break; |
||||
#endif |
||||
#if defined(CONFIG_ARCH_UNIPHIER_PXS2) || defined(CONFIG_ARCH_UNIPHIER_LD6B) |
||||
case UNIPHIER_PXS2_ID: |
||||
case UNIPHIER_LD6B_ID: |
||||
uniphier_pxs2_boot_mode_show(); |
||||
break; |
||||
#endif |
||||
#if defined(CONFIG_ARCH_UNIPHIER_LD11) || defined(CONFIG_ARCH_UNIPHIER_LD20) |
||||
case UNIPHIER_LD11_ID: |
||||
case UNIPHIER_LD20_ID: |
||||
uniphier_ld20_boot_mode_show(); |
||||
break; |
||||
#endif |
||||
default: |
||||
break; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
U_BOOT_CMD( |
||||
pinmon, 1, 1, do_pinmon, |
||||
"pin monitor", |
||||
"" |
||||
); |
@ -1,125 +0,0 @@ |
||||
/*
|
||||
* Copyright (C) 2016 Socionext Inc. |
||||
* Author: Masahiro Yamada <yamada.masahiro@socionext.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <spl.h> |
||||
#include <linux/io.h> |
||||
#include <asm/processor.h> |
||||
|
||||
#include "../soc-info.h" |
||||
|
||||
struct uniphier_romfunc_table { |
||||
void *mmc_send_cmd; |
||||
void *mmc_card_blockaddr; |
||||
void *mmc_switch_part; |
||||
void *mmc_load_image; |
||||
}; |
||||
|
||||
static const struct uniphier_romfunc_table uniphier_ld11_romfunc_table = { |
||||
.mmc_send_cmd = (void *)0x20d8, |
||||
.mmc_card_blockaddr = (void *)0x1b68, |
||||
.mmc_switch_part = (void *)0x1c38, |
||||
.mmc_load_image = (void *)0x2e48, |
||||
}; |
||||
|
||||
static const struct uniphier_romfunc_table uniphier_ld20_romfunc_table = { |
||||
.mmc_send_cmd = (void *)0x2130, |
||||
.mmc_card_blockaddr = (void *)0x1ba0, |
||||
.mmc_switch_part = (void *)0x1c70, |
||||
.mmc_load_image = (void *)0x2ef0, |
||||
}; |
||||
|
||||
int uniphier_rom_get_mmc_funcptr(int (**send_cmd)(u32, u32), |
||||
int (**card_blockaddr)(u32), |
||||
int (**switch_part)(int), |
||||
int (**load_image)(u32, uintptr_t, u32)) |
||||
{ |
||||
const struct uniphier_romfunc_table *table; |
||||
|
||||
switch (uniphier_get_soc_id()) { |
||||
case UNIPHIER_LD11_ID: |
||||
table = &uniphier_ld11_romfunc_table; |
||||
break; |
||||
case UNIPHIER_LD20_ID: |
||||
table = &uniphier_ld20_romfunc_table; |
||||
break; |
||||
default: |
||||
printf("unsupported SoC\n"); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
*send_cmd = table->mmc_send_cmd; |
||||
*card_blockaddr = table->mmc_card_blockaddr; |
||||
*switch_part = table->mmc_switch_part; |
||||
*load_image = table->mmc_load_image; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int spl_board_load_image(struct spl_image_info *spl_image, |
||||
struct spl_boot_device *bootdev) |
||||
{ |
||||
int (*send_cmd)(u32 cmd, u32 arg); |
||||
int (*card_blockaddr)(u32 rca); |
||||
int (*switch_part)(int part); |
||||
int (*load_image)(u32 dev_addr, uintptr_t load_addr, u32 block_cnt); |
||||
u32 dev_addr = CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR; |
||||
const u32 rca = 0x1000; /* RCA assigned by Boot ROM */ |
||||
int ret; |
||||
|
||||
ret = uniphier_rom_get_mmc_funcptr(&send_cmd, &card_blockaddr, |
||||
&switch_part, &load_image); |
||||
if (ret) |
||||
return ret; |
||||
|
||||
/*
|
||||
* deselect card before SEND_CSD command. |
||||
* Do not check the return code. It fails, but it is OK. |
||||
*/ |
||||
(*send_cmd)(0x071a0000, 0); /* CMD7 (arg=0) */ |
||||
|
||||
/* reset CMD Line */ |
||||
writeb(0x6, 0x5a00022f); |
||||
while (readb(0x5a00022f)) |
||||
cpu_relax(); |
||||
|
||||
ret = (*card_blockaddr)(rca); |
||||
if (ret) { |
||||
debug("card is block addressing\n"); |
||||
} else { |
||||
debug("card is byte addressing\n"); |
||||
dev_addr *= 512; |
||||
} |
||||
|
||||
ret = (*send_cmd)(0x071a0000, rca << 16); /* CMD7: select card again */ |
||||
if (ret) |
||||
printf("failed to select card\n"); |
||||
|
||||
ret = (*switch_part)(1); /* Switch to Boot Partition 1 */ |
||||
if (ret) |
||||
printf("failed to switch partition\n"); |
||||
|
||||
ret = (*load_image)(dev_addr, CONFIG_SYS_TEXT_BASE, 1); |
||||
if (ret) { |
||||
printf("failed to load image\n"); |
||||
return ret; |
||||
} |
||||
|
||||
ret = spl_parse_image_header(spl_image, (void *)CONFIG_SYS_TEXT_BASE); |
||||
if (ret) |
||||
return ret; |
||||
|
||||
ret = (*load_image)(dev_addr, spl_image->load_addr, |
||||
spl_image->size / 512); |
||||
if (ret) { |
||||
printf("failed to load image\n"); |
||||
return ret; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
SPL_LOAD_IMAGE_METHOD("eMMC", 0, BOOT_DEVICE_BOARD, spl_board_load_image); |
@ -0,0 +1,17 @@ |
||||
/*
|
||||
* Copyright (C) 2017 Socionext Inc. |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <linux/io.h> |
||||
|
||||
#include "../init.h" |
||||
|
||||
#define SDCTRL_EMMC_HW_RESET 0x59810280 |
||||
|
||||
void uniphier_ld20_clk_init(void) |
||||
{ |
||||
/* TODO: use "mmc-pwrseq-emmc" */ |
||||
writel(1, SDCTRL_EMMC_HW_RESET); |
||||
} |
@ -0,0 +1,34 @@ |
||||
/*
|
||||
* Copyright (C) 2016 Socionext Inc. |
||||
* Author: Masahiro Yamada <yamada.masahiro@socionext.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <mmc.h> |
||||
#include <spl.h> |
||||
|
||||
u32 spl_boot_mode(const u32 boot_device) |
||||
{ |
||||
struct mmc *mmc; |
||||
|
||||
/*
|
||||
* work around a bug in the Boot ROM of PH1-sLD3, LD4, Pro4, and sLD8: |
||||
* |
||||
* The boot ROM in these SoCs breaks the PARTITION_CONFIG [179] of |
||||
* Extended CSD register; when switching to the Boot Partition 1, the |
||||
* Boot ROM should issue the SWITCH command (CMD6) with Set Bits for |
||||
* the Access Bits, but in fact it uses Write Byte for the Access Bits. |
||||
* As a result, the BOOT_PARTITION_ENABLE field of the PARTITION_CONFIG |
||||
* is lost. This bug was fixed for PH1-Pro5 and later SoCs. |
||||
* |
||||
* Fixup mmc->part_config here because it is used to determine the |
||||
* partition which the U-Boot image is read from. |
||||
*/ |
||||
mmc = find_mmc_device(0); |
||||
mmc->part_config &= ~EXT_CSD_BOOT_PART_NUM(PART_ACCESS_MASK); |
||||
mmc->part_config |= EXT_CSD_BOOT_PARTITION_ENABLE; |
||||
|
||||
return MMCSD_MODE_EMMCBOOT; |
||||
} |
@ -0,0 +1,46 @@ |
||||
/*
|
||||
* Copyright (C) 2016 Socionext Inc. |
||||
* Author: Masahiro Yamada <yamada.masahiro@socionext.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <mmc.h> |
||||
#include <linux/errno.h> |
||||
|
||||
static int find_first_mmc_device(void) |
||||
{ |
||||
struct mmc *mmc; |
||||
int i; |
||||
|
||||
for (i = 0; (mmc = find_mmc_device(i)); i++) { |
||||
if (!mmc_init(mmc) && IS_MMC(mmc)) |
||||
return i; |
||||
} |
||||
|
||||
return -ENODEV; |
||||
} |
||||
|
||||
int mmc_get_env_dev(void) |
||||
{ |
||||
return find_first_mmc_device(); |
||||
} |
||||
|
||||
static int do_mmcsetn(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
||||
{ |
||||
int dev; |
||||
|
||||
dev = find_first_mmc_device(); |
||||
if (dev < 0) |
||||
return CMD_RET_FAILURE; |
||||
|
||||
setenv_ulong("mmc_first_dev", dev); |
||||
return CMD_RET_SUCCESS; |
||||
} |
||||
|
||||
U_BOOT_CMD( |
||||
mmcsetn, 1, 1, do_mmcsetn, |
||||
"Set the first MMC (not SD) dev number to \"mmc_first_dev\" environment", |
||||
"" |
||||
); |
Loading…
Reference in new issue