Commit 5894ca00 authored by Masahiro Yamada's avatar Masahiro Yamada
Browse files

ARM: UniPhier: add UniPhier SoC support code



These are used by Panasonic UniPhier SoC family.
Signed-off-by: default avatarMasahiro Yamada <yamada.m@jp.panasonic.com>
parent 7f368553
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-$(CONFIG_SPL_BUILD) += lowlevel_init.o init_page_table.o
obj-$(CONFIG_SPL_BUILD) += spl.o
obj-y += timer.o
obj-y += reset.o
obj-y += cache_uniphier.o
obj-y += dram_init.o
obj-$(CONFIG_DISPLAY_CPUINFO) += cpu_info.o
obj-$(CONFIG_BOARD_LATE_INIT) += board_late_init.o
obj-$(CONFIG_UNIPHIER_SMP) += smp.o
obj-$(if $(CONFIG_SPL_BUILD),,y) += cmd_pinmon.o
obj-y += board_common.o
obj-$(CONFIG_PFC_MICRO_SUPPORT_CARD) += support_card.o
obj-$(CONFIG_DCC_MICRO_SUPPORT_CARD) += support_card.o
obj-$(CONFIG_MACH_PH1_LD4) += ph1-ld4/
obj-$(CONFIG_MACH_PH1_PRO4) += ph1-pro4/
obj-$(CONFIG_MACH_PH1_SLD8) += ph1-sld8/
/*
* Copyright (C) 2012-2014 Panasonic Corporation
* Author: Masahiro Yamada <yamada.m@jp.panasonic.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/arch/led.h>
/*
* Routine: board_init
* Description: Early hardware init.
*/
int board_init(void)
{
led_write(U, B, O, O);
return 0;
}
#if CONFIG_NR_DRAM_BANKS >= 2
void dram_init_banksize(void)
{
DECLARE_GLOBAL_DATA_PTR;
gd->bd->bi_dram[0].start = CONFIG_SDRAM0_BASE;
gd->bd->bi_dram[0].size = CONFIG_SDRAM0_SIZE;
gd->bd->bi_dram[1].start = CONFIG_SDRAM1_BASE;
gd->bd->bi_dram[1].size = CONFIG_SDRAM1_SIZE;
}
#endif
/*
* Copyright (C) 2014 Panasonic Corporation
* Author: Masahiro Yamada <yamada.m@jp.panasonic.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <spl.h>
#include <nand.h>
#include <asm/io.h>
#include <../drivers/mtd/nand/denali.h>
static void nand_denali_wp_disable(void)
{
#ifdef CONFIG_NAND_DENALI
/*
* Since the boot rom enables the write protection for NAND boot mode,
* it must be disabled somewhere for "nand write", "nand erase", etc.
* The workaround is here to not disturb the Denali NAND controller
* driver just for a really SoC-specific thing.
*/
void __iomem *denali_reg = (void __iomem *)CONFIG_SYS_NAND_REGS_BASE;
writel(WRITE_PROTECT__FLAG, denali_reg + WRITE_PROTECT);
#endif
}
static void nand_denali_fixup(void)
{
#if defined(CONFIG_NAND_DENALI) && \
(defined(CONFIG_MACH_PH1_SLD8) || defined(CONFIG_MACH_PH1_PRO4))
/*
* The Denali NAND controller on some of UniPhier SoCs does not
* automatically query the device parameters. For those SoCs,
* some registers must be set after the device is probed.
*/
void __iomem *denali_reg = (void __iomem *)CONFIG_SYS_NAND_REGS_BASE;
struct mtd_info *mtd;
struct nand_chip *chip;
if (nand_curr_device < 0 ||
nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE) {
/* NAND was not detected. Just return. */
return;
}
mtd = &nand_info[nand_curr_device];
chip = mtd->priv;
writel(mtd->erasesize / mtd->writesize, denali_reg + PAGES_PER_BLOCK);
writel(0, denali_reg + DEVICE_WIDTH);
writel(mtd->writesize, denali_reg + DEVICE_MAIN_AREA_SIZE);
writel(mtd->oobsize, denali_reg + DEVICE_SPARE_AREA_SIZE);
writel(1, denali_reg + DEVICES_CONNECTED);
/*
* chip->scan_bbt in nand_scan_tail() has been skipped.
* It should be done in here.
*/
chip->scan_bbt(mtd);
#endif
}
int board_late_init(void)
{
puts("MODE: ");
switch (spl_boot_device()) {
case BOOT_DEVICE_MMC1:
printf("eMMC Boot\n");
setenv("bootmode", "emmcboot");
nand_denali_fixup();
break;
case BOOT_DEVICE_NAND:
printf("NAND Boot\n");
setenv("bootmode", "nandboot");
nand_denali_wp_disable();
break;
case BOOT_DEVICE_NOR:
printf("NOR Boot\n");
setenv("bootmode", "norboot");
nand_denali_fixup();
break;
default:
printf("Unsupported Boot Mode\n");
return -1;
}
return 0;
}
/*
* Copyright (C) 2012-2014 Panasonic Corporation
* Author: Masahiro Yamada <yamada.m@jp.panasonic.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/io.h>
#include <asm/armv7.h>
#include <asm/arch/ssc-regs.h>
#ifdef CONFIG_UNIPHIER_L2CACHE_ON
static void uniphier_cache_maint_all(u32 operation)
{
/* try until the command is successfully set */
do {
writel(SSCOQM_S_ALL | SSCOQM_CE | operation, SSCOQM);
} while (readl(SSCOPPQSEF) & (SSCOPPQSEF_FE | SSCOPPQSEF_OE));
/* wait until the operation is completed */
while (readl(SSCOLPQS) != SSCOLPQS_EF)
;
/* clear the complete notification flag */
writel(SSCOLPQS_EF, SSCOLPQS);
writel(SSCOPE_CM_SYNC, SSCOPE); /* drain internal buffers */
readl(SSCOPE); /* need a read back to confirm */
}
void v7_outer_cache_flush_all(void)
{
uniphier_cache_maint_all(SSCOQM_CM_WB_INV);
}
void v7_outer_cache_inval_all(void)
{
uniphier_cache_maint_all(SSCOQM_CM_INV);
}
static void __uniphier_cache_maint_range(u32 start, u32 size, u32 operation)
{
/* try until the command is successfully set */
do {
writel(SSCOQM_S_ADDRESS | SSCOQM_CE | operation, SSCOQM);
writel(start, SSCOQAD);
writel(size, SSCOQSZ);
} while (readl(SSCOPPQSEF) & (SSCOPPQSEF_FE | SSCOPPQSEF_OE));
/* wait until the operation is completed */
while (readl(SSCOLPQS) != SSCOLPQS_EF)
;
/* clear the complete notification flag */
writel(SSCOLPQS_EF, SSCOLPQS);
}
static void uniphier_cache_maint_range(u32 start, u32 end, u32 operation)
{
u32 size;
/*
* If start address is not aligned to cache-line,
* do cache operation for the first cache-line
*/
start = start & ~(SSC_LINE_SIZE - 1);
if (start == 0 && end >= (u32)(-SSC_LINE_SIZE)) {
/* this means cache operation for all range */
uniphier_cache_maint_all(operation);
return;
}
/*
* If end address is not aligned to cache-line,
* do cache operation for the last cache-line
*/
size = (end - start + SSC_LINE_SIZE - 1) & ~(SSC_LINE_SIZE - 1);
while (size) {
u32 chunk_size = size > SSC_RANGE_OP_MAX_SIZE ?
SSC_RANGE_OP_MAX_SIZE : size;
__uniphier_cache_maint_range(start, chunk_size, operation);
start += chunk_size;
size -= chunk_size;
}
writel(SSCOPE_CM_SYNC, SSCOPE); /* drain internal buffers */
readl(SSCOPE); /* need a read back to confirm */
}
void v7_outer_cache_flush_range(u32 start, u32 end)
{
uniphier_cache_maint_range(start, end, SSCOQM_CM_WB_INV);
}
void v7_outer_cache_inval_range(u32 start, u32 end)
{
uniphier_cache_maint_range(start, end, SSCOQM_CM_INV);
}
void v7_outer_cache_enable(void)
{
u32 tmp;
tmp = readl(SSCC);
tmp |= SSCC_ON;
writel(tmp, SSCC);
}
#endif
void v7_outer_cache_disable(void)
{
u32 tmp;
tmp = readl(SSCC);
tmp &= ~SSCC_ON;
writel(tmp, SSCC);
}
void wakeup_secondary(void);
void enable_caches(void)
{
uint32_t reg;
#ifdef CONFIG_UNIPHIER_SMP
/*
* The secondary CPU must move to DDR,
* before L2 disable.
* On SPL, the Page Table is located on the L2.
*/
wakeup_secondary();
#endif
/*
* UniPhier SoCs must use L2 cache for init stack pointer.
* We disable L2 and L1 in this order.
* If CONFIG_SYS_DCACHE_OFF is not defined,
* caches are enabled again with a new page table.
*/
/* L2 disable */
v7_outer_cache_disable();
/* L1 disable */
reg = get_cr();
reg &= ~(CR_C | CR_M);
set_cr(reg);
#ifndef CONFIG_SYS_DCACHE_OFF
dcache_enable();
#endif
}
/*
* Copyright (C) 2014 Panasonic Corporation
* Author: Masahiro Yamada <yamada.m@jp.panasonic.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/arch/boot-device.h>
static int do_pinmon(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
struct boot_device_info *table;
u32 mode_sel, n = 0;
mode_sel = get_boot_mode_sel();
puts("Boot Mode Pin:\n");
for (table = boot_device_table; strlen(table->info); table++) {
printf(" %c %02x %s\n", n == mode_sel ? '*' : ' ', n,
table->info);
n++;
}
return 0;
}
U_BOOT_CMD(
pinmon, 1, 1, do_pinmon,
"pin monitor",
""
);
/*
* Copyright (C) 2013-2014 Panasonic Corporation
* Author: Masahiro Yamada <yamada.m@jp.panasonic.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/io.h>
#include <asm/arch/sg-regs.h>
int print_cpuinfo(void)
{
u32 revision, type, model, rev, required_model = 1, required_rev = 1;
revision = readl(SG_REVISION);
type = (revision & SG_REVISION_TYPE_MASK) >> SG_REVISION_TYPE_SHIFT;
model = (revision & SG_REVISION_MODEL_MASK) >> SG_REVISION_MODEL_SHIFT;
rev = (revision & SG_REVISION_REV_MASK) >> SG_REVISION_REV_SHIFT;
puts("CPU: ");
switch (type) {
case 0x25:
puts("PH1-sLD3 (MN2WS0220)");
required_model = 2;
break;
case 0x26:
puts("PH1-LD4 (MN2WS0250)");
required_rev = 2;
break;
case 0x28:
puts("PH1-Pro4 (MN2WS0230)");
break;
case 0x29:
puts("PH1-sLD8 (MN2WS0270)");
break;
default:
printf("Unknown Processor ID (0x%x)\n", revision);
return -1;
}
if (model > 1)
printf(" model %d", model);
printf(" (rev. %d)\n", rev);
if (model < required_model) {
printf("Sorry, this model is not supported.\n");
printf("Required model is %d.", required_model);
return -1;
} else if (rev < required_rev) {
printf("Sorry, this revision is not supported.\n");
printf("Required revision is %d.", required_rev);
return -1;
}
return 0;
}
/*
* Copyright (C) 2012-2014 Panasonic Corporation
* Author: Masahiro Yamada <yamada.m@jp.panasonic.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/arch/led.h>
int umc_init(void);
void enable_dpll_ssc(void);
int dram_init(void)
{
DECLARE_GLOBAL_DATA_PTR;
gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
#if !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD)
led_write(B, 4, , );
{
int res;
res = umc_init();
if (res < 0)
return res;
}
led_write(B, 5, , );
enable_dpll_ssc();
#endif
led_write(B, 6, , );
return 0;
}
This diff is collapsed.
/*
* Copyright (C) 2012-2014 Panasonic Corporation
* Author: Masahiro Yamada <yamada.m@jp.panasonic.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <config.h>
#include <linux/linkage.h>
#include <asm/system.h>
#include <asm/arch/led.h>
#include <asm/arch/arm-mpcore.h>
#include <asm/arch/sbc-regs.h>
ENTRY(lowlevel_init)
mov r8, lr @ persevere link reg across call
/*
* The UniPhier Boot ROM loads SPL code to the L2 cache.
* But CPUs can only do instruction fetch now because start.S has
* cleared C and M bits.
* First we need to turn on MMU and Dcache again to get back
* data access to L2.
*/
mrc p15, 0, r0, c1, c0, 0 @ SCTLR (System Contrl Register)
orr r0, r0, #(CR_C | CR_M) @ enable MMU and Dcache
mcr p15, 0, r0, c1, c0, 0
/*
* Now we are using the page table embedded in the Boot ROM.
* It is not handy since it is not a straight mapped table for sLD3.
* What we need to do next is to switch over to the page table in SPL.
*/
ldr r3, =init_page_table @ page table must be 16KB aligned
/* Disable MMU and Dcache before switching Page Table */
mrc p15, 0, r0, c1, c0, 0 @ SCTLR (System Contrl Register)
bic r0, r0, #(CR_C | CR_M) @ disable MMU and Dcache
mcr p15, 0, r0, c1, c0, 0
bl enable_mmu
#ifdef CONFIG_UNIPHIER_SMP
/*
* ACTLR (Auxiliary Control Register) for Cortex-A9
* bit[9] Parity on
* bit[8] Alloc in one way
* bit[7] EXCL (Exclusive cache bit)
* bit[6] SMP
* bit[3] Write full line of zeros mode
* bit[2] L1 Prefetch enable
* bit[1] L2 prefetch enable
* bit[0] FW (Cache and TLB maintenance broadcast)
*/
mrc p15, 0, r0, c1, c0, 1 @ ACTLR (Auxiliary Control Register)
orr r0, r0, #0x41 @ enable SMP, FW bit
mcr p15, 0, r0, c1, c0, 1
/* branch by CPU ID */
mrc p15, 0, r0, c0, c0, 5 @ MPIDR (Multiprocessor Affinity Register)
and r0, r0, #0x3
cmp r0, #0x0
beq primary_cpu
ldr r1, =ROM_BOOT_ROMRSV2
mov r0, #0
str r0, [r1]
0: wfe
ldr r0, [r1]
cmp r0, #0
beq 0b
bx r0 @ r0: entry point of U-Boot main for the secondary CPU
primary_cpu:
ldr r1, =ROM_BOOT_ROMRSV2
ldr r0, =_start @ entry for the secondary CPU
str r0, [r1]
ldr r0, [r1] @ make sure str is complete before sev
sev @ kick the sedoncary CPU
mrc p15, 4, r1, c15, c0, 0 @ Configuration Base Address Register
bfc r1, #0, #13 @ clear bit 12-0
mov r0, #-1
str r0, [r1, #SCU_INV_ALL] @ SCU Invalidate All Register
mov r0, #1 @ SCU enable
str r0, [r1, #SCU_CTRL] @ SCU Control Register
#endif
bl setup_init_ram @ RAM area for temporary stack pointer
mov lr, r8 @ restore link
mov pc, lr @ back to my caller
ENDPROC(lowlevel_init)
ENTRY(enable_mmu)
mrc p15, 0, r0, c2, c0, 2 @ TTBCR (Translation Table Base Control Register)
bic r0, r0, #0x37
orr r0, r0, #0x20 @ disable TTBR1
mcr p15, 0, r0, c2, c0, 2
orr r0, r3, #0x8 @ Outer Cacheability for table walks: WBWA
mcr p15, 0, r0, c2, c0, 0 @ TTBR0
mov r0, #0
mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs
mov r0, #-1 @ manager for all domains (No permission check)
mcr p15, 0, r0, c3, c0, 0 @ DACR (Domain Access Control Register)
dsb
isb
/*
* MMU on:
* TLBs was already invalidated in "../start.S"
* So, we don't need to invalidate it here.
*/
mrc p15, 0, r0, c1, c0, 0 @ SCTLR (System Contrl Register)
orr r0, r0, #(CR_C | CR_M) @ MMU and Dcache enable
mcr p15, 0, r0, c1, c0, 0
mov pc, lr
ENDPROC(enable_mmu)
#include <asm/arch/ssc-regs.h>
#define BOOT_RAM_SIZE (SSC_WAY_SIZE)
#define BOOT_WAY_BITS (0x00000100) /* way 8 */
ENTRY(setup_init_ram)
/*
* Touch to zero for the boot way
*/
0:
/*
* set SSCOQM, SSCOQAD, SSCOQSZ, SSCOQWN in this order
*/
ldr r0, = 0x00408006 @ touch to zero with address range
ldr r1, = SSCOQM
str r0, [r1]
ldr r0, = (CONFIG_SYS_INIT_SP_ADDR - BOOT_RAM_SIZE) @ base address
ldr r1, = SSCOQAD
str r0, [r1]
ldr r0, = BOOT_RAM_SIZE
ldr r1, = SSCOQSZ
str r0, [r1]
ldr r0, = BOOT_WAY_BITS
ldr r1, = SSCOQWN