GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
@@ -0,0 +1,122 @@
if ARCH_UNIPHIER
config SYS_CONFIG_NAME
default "uniphier"
config ARCH_UNIPHIER_32BIT
bool
select ARCH_SUPPORT_PSCI
select ARMV7_NONSEC
select CPU_V7A
select CPU_V7_HAS_NONSEC
choice
prompt "UniPhier SoC select"
default ARCH_UNIPHIER_V7_MULTI
config ARCH_UNIPHIER_LD4_SLD8
bool "UniPhier LD4/sLD8 SoCs"
select ARCH_UNIPHIER_32BIT
config ARCH_UNIPHIER_V7_MULTI
bool "UniPhier Pro4/Pro5/PXs2/LD6b SoCs"
select ARCH_UNIPHIER_32BIT
config ARCH_UNIPHIER_V8_MULTI
bool "UniPhier V8 SoCs"
depends on !SPL
select ARM64
select CMD_UNZIP
endchoice
config ARCH_UNIPHIER_LD4
bool "Enable UniPhier LD4 SoC support"
depends on ARCH_UNIPHIER_LD4_SLD8
default y
config ARCH_UNIPHIER_SLD8
bool "Enable UniPhier sLD8 SoC support"
depends on ARCH_UNIPHIER_LD4_SLD8
default y
config ARCH_UNIPHIER_PRO4
bool "Enable UniPhier Pro4 SoC support"
depends on ARCH_UNIPHIER_V7_MULTI
default y
config ARCH_UNIPHIER_PRO5
bool "Enable UniPhier Pro5 SoC support"
depends on ARCH_UNIPHIER_V7_MULTI
default y
config ARCH_UNIPHIER_PXS2
bool "Enable UniPhier Pxs2 SoC support"
depends on ARCH_UNIPHIER_V7_MULTI
default y
config ARCH_UNIPHIER_LD6B
bool "Enable UniPhier LD6b SoC support"
depends on ARCH_UNIPHIER_V7_MULTI
default y
config ARCH_UNIPHIER_LD11
bool "Enable UniPhier LD11 SoC support"
depends on ARCH_UNIPHIER_V8_MULTI
default y
config ARCH_UNIPHIER_LD20
bool "Enable UniPhier LD20 SoC support"
depends on ARCH_UNIPHIER_V8_MULTI
default y
select OF_BOARD_SETUP
config ARCH_UNIPHIER_PXS3
bool "Enable UniPhier PXs3 SoC support"
depends on ARCH_UNIPHIER_V8_MULTI
default y
config CACHE_UNIPHIER
bool "Enable the UniPhier L2 cache controller"
depends on ARCH_UNIPHIER_32BIT
default y
select SYS_CACHE_SHIFT_7
help
This option allows to use the UniPhier System Cache as L2 cache.
config MICRO_SUPPORT_CARD
bool "Use Micro Support Card"
help
This option provides support for the expansion board, available
on some UniPhier reference boards.
Say Y to use the on-board UART, Ether, LED devices.
config CMD_PINMON
bool "Enable boot mode pins monitor command"
default y
help
The command "pinmon" shows the state of the boot mode pins.
The boot mode pins are latched when the system reset is deasserted
and determine which device the system should load a boot image from.
config CMD_DDRPHY_DUMP
bool "Enable dump command of DDR PHY parameters"
depends on ARCH_UNIPHIER_LD4 || ARCH_UNIPHIER_PRO4 || \
ARCH_UNIPHIER_SLD8 || ARCH_UNIPHIER_LD11
default y
help
The command "ddrphy" shows the resulting parameters of DDR PHY
training; it is useful for the evaluation of DDR PHY training.
config CMD_DDRMPHY_DUMP
bool "Enable dump command of DDR Multi PHY parameters"
depends on ARCH_UNIPHIER_PXS2 || ARCH_UNIPHIER_LD6B
default y
help
The command "ddrmphy" shows the resulting parameters of DDR Multi PHY
training; it is useful for the evaluation of DDR Multi PHY training.
config SYS_SOC
default "uniphier-v7" if ARCH_UNIPHIER_LD4_SLD8 || ARCH_UNIPHIER_V7_MULTI
endif
@@ -0,0 +1,38 @@
# SPDX-License-Identifier: GPL-2.0+
ifdef CONFIG_SPL_BUILD
obj-y += boards.o
obj-y += spl_board_init.o
obj-y += memconf.o
obj-y += bcu/
obj-$(CONFIG_SPL_MMC_SUPPORT) += mmc-boot-mode.o
else
obj-$(CONFIG_DISPLAY_CPUINFO) += cpu-info.o
obj-y += dram_init.o
obj-y += board_init.o
obj-$(CONFIG_ARCH_UNIPHIER_V8_MULTI) += base-address.o
obj-$(CONFIG_BOARD_LATE_INIT) += board_late_init.o
ifndef CONFIG_SYSRESET
obj-y += reset.o
endif
obj-$(CONFIG_MICRO_SUPPORT_CARD) += micro-support-card.o
obj-y += pinctrl-glue.o
obj-$(CONFIG_MMC) += mmc-first-dev.o
obj-y += fdt-fixup.o
endif
obj-y += sbc/
obj-y += soc-info.o
obj-y += boot-device/
obj-y += clk/
obj-y += dram/
obj-$(CONFIG_DEBUG_UART_UNIPHIER) += debug-uart/
obj-$(CONFIG_CPU_V7A) += arm32/
obj-$(CONFIG_ARM64) += arm64/
@@ -0,0 +1,12 @@
# SPDX-License-Identifier: GPL-2.0+
ifdef CONFIG_SPL_BUILD
obj-y += lowlevel_init.o
obj-$(CONFIG_DEBUG_LL) += debug_ll.o
else
obj-y += late_lowlevel_init.o
obj-y += cache-uniphier.o
obj-$(CONFIG_ARMV7_PSCI) += psci.o psci_smp.o
endif
obj-y += timer.o
@@ -0,0 +1,48 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2011-2014 Panasonic Corporation
*/
#ifndef ARCH_ARM_MPCORE_H
#define ARCH_ARM_MPCORE_H
/* Snoop Control Unit */
#define SCU_OFFSET 0x00
/* SCU Control Register */
#define SCU_CTRL 0x00
#define SCU_ENABLE (1 << 0)
#define SCU_STANDBY_ENABLE (1 << 5)
/* SCU Configuration Register */
#define SCU_CONF 0x04
/* SCU CPU Power Status Register */
#define SCU_PWR_STATUS 0x08
/* SCU Invalidate All Registers in Secure State */
#define SCU_INV_ALL 0x0C
/* SCU Filtering Start Address Register */
#define SCU_FILTER_START 0x40
/* SCU Filtering End Address Register */
#define SCU_FILTER_END 0x44
/* SCU Access Control Register */
#define SCU_SAC 0x50
/* SCU Non-secure Access Control Register */
#define SCU_SNSAC 0x54
/* Global Timer */
#define GLOBAL_TIMER_OFFSET 0x200
/* Global Timer Counter Registers */
#define GTIMER_CNT_L 0x00
#define GTIMER_CNT_H 0x04
/* Global Timer Control Register */
#define GTIMER_CTRL 0x08
/* Global Timer Interrupt Status Register */
#define GTIMER_STAT 0x0C
/* Comparator Value Registers */
#define GTIMER_CMP_L 0x10
#define GTIMER_CMP_H 0x14
/* Auto-increment Register */
#define GTIMER_INC 0x18
#endif /* ARCH_ARM_MPCORE_H */
@@ -0,0 +1,293 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2012-2014 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <cpu_func.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <asm/armv7.h>
#include <asm/processor.h>
#include "cache-uniphier.h"
/* control registers */
#define UNIPHIER_SSCC 0x500c0000 /* Control Register */
#define UNIPHIER_SSCC_BST (0x1 << 20) /* UCWG burst read */
#define UNIPHIER_SSCC_ACT (0x1 << 19) /* Inst-Data separate */
#define UNIPHIER_SSCC_WTG (0x1 << 18) /* WT gathering on */
#define UNIPHIER_SSCC_PRD (0x1 << 17) /* enable pre-fetch */
#define UNIPHIER_SSCC_ON (0x1 << 0) /* enable cache */
#define UNIPHIER_SSCLPDAWCR 0x500c0030 /* Unified/Data Active Way Control */
#define UNIPHIER_SSCLPIAWCR 0x500c0034 /* Instruction Active Way Control */
/* revision registers */
#define UNIPHIER_SSCID 0x503c0100 /* ID Register */
/* operation registers */
#define UNIPHIER_SSCOPE 0x506c0244 /* Cache Operation Primitive Entry */
#define UNIPHIER_SSCOPE_CM_INV 0x0 /* invalidate */
#define UNIPHIER_SSCOPE_CM_CLEAN 0x1 /* clean */
#define UNIPHIER_SSCOPE_CM_FLUSH 0x2 /* flush */
#define UNIPHIER_SSCOPE_CM_SYNC 0x8 /* sync (drain bufs) */
#define UNIPHIER_SSCOPE_CM_FLUSH_PREFETCH 0x9 /* flush p-fetch buf */
#define UNIPHIER_SSCOQM 0x506c0248
#define UNIPHIER_SSCOQM_TID_MASK (0x3 << 21)
#define UNIPHIER_SSCOQM_TID_LRU_DATA (0x0 << 21)
#define UNIPHIER_SSCOQM_TID_LRU_INST (0x1 << 21)
#define UNIPHIER_SSCOQM_TID_WAY (0x2 << 21)
#define UNIPHIER_SSCOQM_S_MASK (0x3 << 17)
#define UNIPHIER_SSCOQM_S_RANGE (0x0 << 17)
#define UNIPHIER_SSCOQM_S_ALL (0x1 << 17)
#define UNIPHIER_SSCOQM_S_WAY (0x2 << 17)
#define UNIPHIER_SSCOQM_CE (0x1 << 15) /* notify completion */
#define UNIPHIER_SSCOQM_CW (0x1 << 14)
#define UNIPHIER_SSCOQM_CM_MASK (0x7)
#define UNIPHIER_SSCOQM_CM_INV 0x0 /* invalidate */
#define UNIPHIER_SSCOQM_CM_CLEAN 0x1 /* clean */
#define UNIPHIER_SSCOQM_CM_FLUSH 0x2 /* flush */
#define UNIPHIER_SSCOQM_CM_PREFETCH 0x3 /* prefetch to cache */
#define UNIPHIER_SSCOQM_CM_PREFETCH_BUF 0x4 /* prefetch to pf-buf */
#define UNIPHIER_SSCOQM_CM_TOUCH 0x5 /* touch */
#define UNIPHIER_SSCOQM_CM_TOUCH_ZERO 0x6 /* touch to zero */
#define UNIPHIER_SSCOQM_CM_TOUCH_DIRTY 0x7 /* touch with dirty */
#define UNIPHIER_SSCOQAD 0x506c024c /* Cache Operation Queue Address */
#define UNIPHIER_SSCOQSZ 0x506c0250 /* Cache Operation Queue Size */
#define UNIPHIER_SSCOQMASK 0x506c0254 /* Cache Operation Queue Address Mask */
#define UNIPHIER_SSCOQWN 0x506c0258 /* Cache Operation Queue Way Number */
#define UNIPHIER_SSCOPPQSEF 0x506c025c /* Cache Operation Queue Set Complete */
#define UNIPHIER_SSCOPPQSEF_FE (0x1 << 1)
#define UNIPHIER_SSCOPPQSEF_OE (0x1 << 0)
#define UNIPHIER_SSCOLPQS 0x506c0260 /* Cache Operation Queue Status */
#define UNIPHIER_SSCOLPQS_EF (0x1 << 2)
#define UNIPHIER_SSCOLPQS_EST (0x1 << 1)
#define UNIPHIER_SSCOLPQS_QST (0x1 << 0)
#define UNIPHIER_SSC_LINE_SIZE 128
#define UNIPHIER_SSC_RANGE_OP_MAX_SIZE (0x00400000 - (UNIPHIER_SSC_LINE_SIZE))
#define UNIPHIER_SSCOQAD_IS_NEEDED(op) \
((op & UNIPHIER_SSCOQM_S_MASK) == UNIPHIER_SSCOQM_S_RANGE)
#define UNIPHIER_SSCOQWM_IS_NEEDED(op) \
(((op & UNIPHIER_SSCOQM_S_MASK) == UNIPHIER_SSCOQM_S_WAY) || \
((op & UNIPHIER_SSCOQM_TID_MASK) == UNIPHIER_SSCOQM_TID_WAY))
/* uniphier_cache_sync - perform a sync point for a particular cache level */
static void uniphier_cache_sync(void)
{
/* drain internal buffers */
writel(UNIPHIER_SSCOPE_CM_SYNC, UNIPHIER_SSCOPE);
/* need a read back to confirm */
readl(UNIPHIER_SSCOPE);
}
/**
* uniphier_cache_maint_common - run a queue operation
*
* @start: start address of range operation (don't care for "all" operation)
* @size: data size of range operation (don't care for "all" operation)
* @ways: target ways (don't care for operations other than pre-fetch, touch
* @operation: flags to specify the desired cache operation
*/
static void uniphier_cache_maint_common(u32 start, u32 size, u32 ways,
u32 operation)
{
/* clear the complete notification flag */
writel(UNIPHIER_SSCOLPQS_EF, UNIPHIER_SSCOLPQS);
do {
/* set cache operation */
writel(UNIPHIER_SSCOQM_CE | operation, UNIPHIER_SSCOQM);
/* set address range if needed */
if (likely(UNIPHIER_SSCOQAD_IS_NEEDED(operation))) {
writel(start, UNIPHIER_SSCOQAD);
writel(size, UNIPHIER_SSCOQSZ);
}
/* set target ways if needed */
if (unlikely(UNIPHIER_SSCOQWM_IS_NEEDED(operation)))
writel(ways, UNIPHIER_SSCOQWN);
} while (unlikely(readl(UNIPHIER_SSCOPPQSEF) &
(UNIPHIER_SSCOPPQSEF_FE | UNIPHIER_SSCOPPQSEF_OE)));
/* wait until the operation is completed */
while (likely(readl(UNIPHIER_SSCOLPQS) != UNIPHIER_SSCOLPQS_EF))
cpu_relax();
}
static void uniphier_cache_maint_all(u32 operation)
{
uniphier_cache_maint_common(0, 0, 0, UNIPHIER_SSCOQM_S_ALL | operation);
uniphier_cache_sync();
}
static void uniphier_cache_maint_range(u32 start, u32 end, u32 ways,
u32 operation)
{
u32 size;
/*
* If the start address is not aligned,
* perform a cache operation for the first cache-line
*/
start = start & ~(UNIPHIER_SSC_LINE_SIZE - 1);
size = end - start;
if (unlikely(size >= (u32)(-UNIPHIER_SSC_LINE_SIZE))) {
/* this means cache operation for all range */
uniphier_cache_maint_all(operation);
return;
}
/*
* If the end address is not aligned,
* perform a cache operation for the last cache-line
*/
size = ALIGN(size, UNIPHIER_SSC_LINE_SIZE);
while (size) {
u32 chunk_size = min_t(u32, size, UNIPHIER_SSC_RANGE_OP_MAX_SIZE);
uniphier_cache_maint_common(start, chunk_size, ways,
UNIPHIER_SSCOQM_S_RANGE | operation);
start += chunk_size;
size -= chunk_size;
}
uniphier_cache_sync();
}
void uniphier_cache_prefetch_range(u32 start, u32 end, u32 ways)
{
uniphier_cache_maint_range(start, end, ways,
UNIPHIER_SSCOQM_TID_WAY |
UNIPHIER_SSCOQM_CM_PREFETCH);
}
void uniphier_cache_touch_range(u32 start, u32 end, u32 ways)
{
uniphier_cache_maint_range(start, end, ways,
UNIPHIER_SSCOQM_TID_WAY |
UNIPHIER_SSCOQM_CM_TOUCH);
}
void uniphier_cache_touch_zero_range(u32 start, u32 end, u32 ways)
{
uniphier_cache_maint_range(start, end, ways,
UNIPHIER_SSCOQM_TID_WAY |
UNIPHIER_SSCOQM_CM_TOUCH_ZERO);
}
void uniphier_cache_inv_way(u32 ways)
{
uniphier_cache_maint_common(0, 0, ways,
UNIPHIER_SSCOQM_S_WAY |
UNIPHIER_SSCOQM_CM_INV);
}
void uniphier_cache_set_active_ways(int cpu, u32 active_ways)
{
void __iomem *base = (void __iomem *)UNIPHIER_SSCC + 0xc00;
switch (readl(UNIPHIER_SSCID)) { /* revision */
case 0x12: /* LD4 */
case 0x16: /* sld8 */
base = (void __iomem *)UNIPHIER_SSCC + 0x840;
break;
default:
base = (void __iomem *)UNIPHIER_SSCC + 0xc00;
break;
}
writel(active_ways, base + 4 * cpu);
}
static void uniphier_cache_endisable(int enable)
{
u32 tmp;
tmp = readl(UNIPHIER_SSCC);
if (enable)
tmp |= UNIPHIER_SSCC_ON;
else
tmp &= ~UNIPHIER_SSCC_ON;
writel(tmp, UNIPHIER_SSCC);
}
void uniphier_cache_enable(void)
{
uniphier_cache_endisable(1);
}
void uniphier_cache_disable(void)
{
uniphier_cache_endisable(0);
}
#ifdef CONFIG_CACHE_UNIPHIER
void v7_outer_cache_flush_all(void)
{
uniphier_cache_maint_all(UNIPHIER_SSCOQM_CM_FLUSH);
}
void v7_outer_cache_inval_all(void)
{
uniphier_cache_maint_all(UNIPHIER_SSCOQM_CM_INV);
}
void v7_outer_cache_flush_range(u32 start, u32 end)
{
uniphier_cache_maint_range(start, end, 0, UNIPHIER_SSCOQM_CM_FLUSH);
}
void v7_outer_cache_inval_range(u32 start, u32 end)
{
if (start & (UNIPHIER_SSC_LINE_SIZE - 1)) {
start &= ~(UNIPHIER_SSC_LINE_SIZE - 1);
uniphier_cache_maint_range(start, UNIPHIER_SSC_LINE_SIZE, 0,
UNIPHIER_SSCOQM_CM_FLUSH);
start += UNIPHIER_SSC_LINE_SIZE;
}
if (start >= end) {
uniphier_cache_sync();
return;
}
if (end & (UNIPHIER_SSC_LINE_SIZE - 1)) {
end &= ~(UNIPHIER_SSC_LINE_SIZE - 1);
uniphier_cache_maint_range(end, UNIPHIER_SSC_LINE_SIZE, 0,
UNIPHIER_SSCOQM_CM_FLUSH);
}
if (start >= end) {
uniphier_cache_sync();
return;
}
uniphier_cache_maint_range(start, end, 0, UNIPHIER_SSCOQM_CM_INV);
}
void v7_outer_cache_enable(void)
{
uniphier_cache_set_active_ways(0, U32_MAX); /* activate all ways */
uniphier_cache_enable();
}
void v7_outer_cache_disable(void)
{
uniphier_cache_disable();
}
#endif
void enable_caches(void)
{
dcache_enable();
}
@@ -0,0 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#ifndef __CACHE_UNIPHIER_H
#define __CACHE_UNIPHIER_H
#include <linux/types.h>
void uniphier_cache_prefetch_range(u32 start, u32 end, u32 ways);
void uniphier_cache_touch_range(u32 start, u32 end, u32 ways);
void uniphier_cache_touch_zero_range(u32 start, u32 end, u32 ways);
void uniphier_cache_inv_way(u32 ways);
void uniphier_cache_set_active_ways(int cpu, u32 active_ways);
void uniphier_cache_enable(void);
void uniphier_cache_disable(void);
#endif /* __CACHE_UNIPHIER_H */
@@ -0,0 +1,175 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* On-chip UART initializaion for low-level debugging
*
* Copyright (C) 2014-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <linux/serial_reg.h>
#include <linux/linkage.h>
#include "../bcu/bcu-regs.h"
#include "../sc-regs.h"
#include "../sg-regs.h"
#if !defined(CONFIG_DEBUG_SEMIHOSTING)
#include CONFIG_DEBUG_LL_INCLUDE
#endif
#define SG_REVISION_TYPE_SHIFT 16
#define SG_REVISION_TYPE_MASK (0xff << SG_REVISION_TYPE_SHIFT)
#define BAUDRATE 115200
#define DIV_ROUND(x, d) (((x) + ((d) / 2)) / (d))
.macro sg_set_pinsel, pin, muxval, mux_bits, reg_stride, ra, rd
ldr \ra, =(SG_BASE + SG_PINCTRL_BASE + \pin * \mux_bits / 32 * \reg_stride)
ldr \rd, [\ra]
and \rd, \rd, #~(((1 << \mux_bits) - 1) << (\pin * \mux_bits % 32))
orr \rd, \rd, #(\muxval << (\pin * \mux_bits % 32))
str \rd, [\ra]
.endm
ENTRY(debug_ll_init)
ldr r0, =(SG_BASE + SG_REVISION)
ldr r1, [r0]
and r1, r1, #SG_REVISION_TYPE_MASK
mov r1, r1, lsr #SG_REVISION_TYPE_SHIFT
#if defined(CONFIG_ARCH_UNIPHIER_LD4)
#define UNIPHIER_LD4_UART_CLK 36864000
cmp r1, #0x26
bne ld4_end
ldr r0, =(SG_BASE + SG_IECTRL)
ldr r1, [r0]
orr r1, r1, #1
str r1, [r0]
sg_set_pinsel 88, 1, 8, 4, r0, r1 @ HSDOUT6 -> TXD0
ldr r3, =DIV_ROUND(UNIPHIER_LD4_UART_CLK, 16 * BAUDRATE)
b init_uart
ld4_end:
#endif
#if defined(CONFIG_ARCH_UNIPHIER_PRO4)
#define UNIPHIER_PRO4_UART_CLK 73728000
cmp r1, #0x28
bne pro4_end
sg_set_pinsel 128, 0, 4, 8, r0, r1 @ TXD0 -> TXD0
ldr r0, =(SG_BASE + SG_LOADPINCTRL)
mov r1, #1
str r1, [r0]
ldr r0, =(SC_BASE + SC_CLKCTRL)
ldr r1, [r0]
orr r1, r1, #SC_CLKCTRL_CEN_PERI
str r1, [r0]
ldr r3, =DIV_ROUND(UNIPHIER_PRO4_UART_CLK, 16 * BAUDRATE)
b init_uart
pro4_end:
#endif
#if defined(CONFIG_ARCH_UNIPHIER_SLD8)
#define UNIPHIER_SLD8_UART_CLK 80000000
cmp r1, #0x29
bne sld8_end
ldr r0, =(SG_BASE + SG_IECTRL)
ldr r1, [r0]
orr r1, r1, #1
str r1, [r0]
sg_set_pinsel 70, 3, 8, 4, r0, r1 @ HSDOUT0 -> TXD0
ldr r3, =DIV_ROUND(UNIPHIER_SLD8_UART_CLK, 16 * BAUDRATE)
b init_uart
sld8_end:
#endif
#if defined(CONFIG_ARCH_UNIPHIER_PRO5)
#define UNIPHIER_PRO5_UART_CLK 73728000
cmp r1, #0x2A
bne pro5_end
sg_set_pinsel 47, 0, 4, 8, r0, r1 @ TXD0 -> TXD0
sg_set_pinsel 49, 0, 4, 8, r0, r1 @ TXD1 -> TXD1
sg_set_pinsel 51, 0, 4, 8, r0, r1 @ TXD2 -> TXD2
sg_set_pinsel 53, 0, 4, 8, r0, r1 @ TXD3 -> TXD3
ldr r0, =(SG_BASE + SG_LOADPINCTRL)
mov r1, #1
str r1, [r0]
ldr r0, =(SC_BASE + SC_CLKCTRL)
ldr r1, [r0]
orr r1, r1, #SC_CLKCTRL_CEN_PERI
str r1, [r0]
ldr r3, =DIV_ROUND(UNIPHIER_PRO5_UART_CLK, 16 * BAUDRATE)
b init_uart
pro5_end:
#endif
#if defined(CONFIG_ARCH_UNIPHIER_PXS2)
#define UNIPHIER_PXS2_UART_CLK 88900000
cmp r1, #0x2E
bne pxs2_end
ldr r0, =(SG_BASE + SG_IECTRL)
ldr r1, [r0]
orr r1, r1, #1
str r1, [r0]
sg_set_pinsel 217, 8, 8, 4, r0, r1 @ TXD0 -> TXD0
sg_set_pinsel 115, 8, 8, 4, r0, r1 @ TXD1 -> TXD1
sg_set_pinsel 113, 8, 8, 4, r0, r1 @ TXD2 -> TXD2
sg_set_pinsel 219, 8, 8, 4, r0, r1 @ TXD3 -> TXD3
ldr r0, =(SC_BASE + SC_CLKCTRL)
ldr r1, [r0]
orr r1, r1, #SC_CLKCTRL_CEN_PERI
str r1, [r0]
ldr r3, =DIV_ROUND(UNIPHIER_PXS2_UART_CLK, 16 * BAUDRATE)
b init_uart
pxs2_end:
#endif
#if defined(CONFIG_ARCH_UNIPHIER_LD6B)
#define UNIPHIER_LD6B_UART_CLK 88900000
cmp r1, #0x2F
bne ld6b_end
ldr r0, =(SG_BASE + SG_IECTRL)
ldr r1, [r0]
orr r1, r1, #1
str r1, [r0]
sg_set_pinsel 135, 3, 8, 4, r0, r1 @ PORT10 -> TXD0
sg_set_pinsel 115, 0, 8, 4, r0, r1 @ TXD1 -> TXD1
sg_set_pinsel 113, 2, 8, 4, r0, r1 @ SBO0 -> TXD2
ldr r0, =(SC_BASE + SC_CLKCTRL)
ldr r1, [r0]
orr r1, r1, #SC_CLKCTRL_CEN_PERI
str r1, [r0]
ldr r3, =DIV_ROUND(UNIPHIER_LD6B_UART_CLK, 16 * BAUDRATE)
b init_uart
ld6b_end:
#endif
mov pc, lr
init_uart:
addruart r0, r1, r2
mov r1, #UART_LCR_WLEN8 << 8
str r1, [r0, #0x10]
str r3, [r0, #0x24]
mov pc, lr
ENDPROC(debug_ll_init)
@@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2015 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <config.h>
#include <linux/linkage.h>
ENTRY(lowlevel_init)
ldr sp, = CONFIG_SYS_INIT_SP_ADDR
b uniphier_cache_disable
ENDPROC(lowlevel_init)
@@ -0,0 +1,138 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2012-2015 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <config.h>
#include <linux/linkage.h>
#include <linux/sizes.h>
#include <asm/system.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 Control Register)
orr r0, r0, #(CR_C | CR_M) @ enable MMU and Dcache
mcr p15, 0, r0, c1, c0, 0
#ifdef CONFIG_DEBUG_LL
bl debug_ll_init
#endif
bl setup_init_ram @ RAM area for stack and page table
/*
* Now we are using the page table embedded in the Boot ROM.
* What we need to do next is to create a page table and switch
* over to it.
*/
bl create_page_table
bl __v7_flush_dcache_all
/* Disable MMU and Dcache before switching Page Table */
mrc p15, 0, r0, c1, c0, 0 @ SCTLR (System Control Register)
bic r0, r0, #(CR_C | CR_M) @ disable MMU and Dcache
mcr p15, 0, r0, c1, c0, 0
bl enable_mmu
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, r12, #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 Control 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)
/*
* For PH1-Pro4 or older SoCs, the size of WAY is 32KB.
* It is large enough for tmp RAM.
*/
#define BOOT_RAM_SIZE (SZ_32K)
#define BOOT_RAM_BASE ((CONFIG_SPL_STACK) - (BOOT_RAM_SIZE))
#define BOOT_RAM_WAYS (0x00000100) @ way 8
#define SSCO_BASE 0x506c0000
#define SSCOPE 0x244
#define SSCOQM 0x248
#define SSCOQAD 0x24c
#define SSCOQSZ 0x250
#define SSCOQWN 0x258
#define SSCOPPQSEF 0x25c
#define SSCOLPQS 0x260
ENTRY(setup_init_ram)
ldr r1, = SSCO_BASE
/* Touch to zero for the boot way */
0: ldr r0, = 0x00408006 @ touch to zero with address range
str r0, [r1, #SSCOQM]
ldr r0, = BOOT_RAM_BASE
str r0, [r1, #SSCOQAD]
ldr r0, = BOOT_RAM_SIZE
str r0, [r1, #SSCOQSZ]
ldr r0, = BOOT_RAM_WAYS
str r0, [r1, #SSCOQWN]
ldr r0, [r1, #SSCOPPQSEF]
cmp r0, #0 @ check if the command is successfully set
bne 0b @ try again if an error occurs
1: ldr r0, [r1, #SSCOLPQS]
cmp r0, #0x4
bne 1b @ wait until the operation is completed
str r0, [r1, #SSCOLPQS] @ clear the complete notification flag
mov pc, lr
ENDPROC(setup_init_ram)
#define DEVICE 0x00002002 /* Non-shareable Device */
#define NORMAL 0x0000000e /* Normal Memory Write-Back, No Write-Allocate */
ENTRY(create_page_table)
ldr r0, = DEVICE
ldr r1, = BOOT_RAM_BASE
mov r12, r1 @ r12 is preserved during D-cache flush
0: str r0, [r1], #4 @ specify all the sections as Device
adds r0, r0, #0x00100000
bcc 0b
ldr r0, = NORMAL
str r0, [r12] @ mark the first section as Normal
add r0, r0, #0x00100000
str r0, [r12, #4] @ mark the second section as Normal
mov pc, lr
ENDPROC(create_page_table)
@@ -0,0 +1,162 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <cpu_func.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/printk.h>
#include <linux/psci.h>
#include <linux/sizes.h>
#include <asm/processor.h>
#include <asm/psci.h>
#include <asm/secure.h>
#include "../debug.h"
#include "../soc-info.h"
#include "arm-mpcore.h"
#include "cache-uniphier.h"
#define UNIPHIER_SMPCTRL_ROM_RSV2 0x59801208
void uniphier_smp_trampoline(void);
void uniphier_smp_trampoline_end(void);
u32 uniphier_smp_booted[CONFIG_ARMV7_PSCI_NR_CPUS];
static int uniphier_get_nr_cpus(void)
{
switch (uniphier_get_soc_id()) {
case UNIPHIER_PRO4_ID:
case UNIPHIER_PRO5_ID:
return 2;
case UNIPHIER_PXS2_ID:
case UNIPHIER_LD6B_ID:
return 4;
default:
return 1;
}
}
static void uniphier_smp_kick_all_cpus(void)
{
const u32 target_ways = BIT(0);
size_t trmp_size;
u32 trmp_src = (unsigned long)uniphier_smp_trampoline;
u32 trmp_src_end = (unsigned long)uniphier_smp_trampoline_end;
u32 trmp_dest, trmp_dest_end;
int nr_cpus, i;
int timeout = 1000;
nr_cpus = uniphier_get_nr_cpus();
if (nr_cpus == 1)
return;
for (i = 0; i < nr_cpus; i++) /* lock ways for all CPUs */
uniphier_cache_set_active_ways(i, 0);
uniphier_cache_inv_way(target_ways);
uniphier_cache_enable();
/* copy trampoline code */
uniphier_cache_prefetch_range(trmp_src, trmp_src_end, target_ways);
trmp_size = trmp_src_end - trmp_src;
trmp_dest = trmp_src & (SZ_64K - 1);
trmp_dest += SZ_1M - SZ_64K * 2;
trmp_dest_end = trmp_dest + trmp_size;
uniphier_cache_touch_range(trmp_dest, trmp_dest_end, target_ways);
writel(trmp_dest, UNIPHIER_SMPCTRL_ROM_RSV2);
asm("dsb ishst\n" /* Ensure the write to ROM_RSV2 is visible */
"sev"); /* Bring up all secondary CPUs from Boot ROM into U-Boot */
while (--timeout) {
int all_booted = 1;
for (i = 1; i < nr_cpus; i++)
if (!uniphier_smp_booted[i])
all_booted = 0;
if (all_booted)
break;
udelay(1);
/* barrier here because uniphier_smp_booted[] may be updated */
cpu_relax();
}
if (!timeout)
pr_warn("warning: some of secondary CPUs may not boot\n");
uniphier_cache_disable();
}
void psci_board_init(void)
{
unsigned long scu_base;
u32 scu_ctrl, tmp;
asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (scu_base));
scu_ctrl = readl(scu_base + 0x30);
if (!(scu_ctrl & 1))
writel(scu_ctrl | 0x1, scu_base + 0x30);
scu_ctrl = readl(scu_base + SCU_CTRL);
scu_ctrl |= SCU_ENABLE | SCU_STANDBY_ENABLE;
writel(scu_ctrl, scu_base + SCU_CTRL);
tmp = readl(scu_base + SCU_SNSAC);
tmp |= 0xfff;
writel(tmp, scu_base + SCU_SNSAC);
uniphier_smp_kick_all_cpus();
}
void psci_arch_init(void)
{
u32 actlr;
asm("mrc p15, 0, %0, c1, c0, 1" : "=r" (actlr));
actlr |= 0x41; /* set SMP and FW bits */
asm("mcr p15, 0, %0, c1, c0, 1" : : "r" (actlr));
}
u32 uniphier_psci_holding_pen_release __secure_data = 0xffffffff;
s32 __secure psci_cpu_on(u32 function_id, u32 cpuid, u32 entry_point,
u32 context_id)
{
u32 cpu = cpuid & 0xff;
debug_puts("[U-Boot PSCI] psci_cpu_on: cpuid=");
debug_puth(cpuid);
debug_puts(", entry_point=");
debug_puth(entry_point);
debug_puts(", context_id=");
debug_puth(context_id);
debug_puts("\n");
psci_save(cpu, entry_point, context_id);
/* We assume D-cache is off, so do not call flush_dcache() here */
uniphier_psci_holding_pen_release = cpu;
/* Send an event to wake up the secondary CPU. */
asm("dsb ishst\n"
"sev");
return PSCI_RET_SUCCESS;
}
void __secure psci_system_reset(void)
{
reset_cpu(0);
}
@@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <linux/linkage.h>
#include <asm/system.h>
.section ._secure.text, "ax"
ENTRY(uniphier_smp_trampoline)
ldr r0, 0f
mrc p15, 0, r1, c1, c0, 0 @ SCTLR (System Control Register)
orr r1, r1, #CR_I @ Enable ICache
bic r1, r1, #(CR_C | CR_M) @ Disable MMU and Dcache
mcr p15, 0, r1, c1, c0, 0
bx r0
0: .word uniphier_secondary_startup
.globl uniphier_smp_trampoline_end
uniphier_smp_trampoline_end:
ENDPROC(uniphier_smp_trampoline)
LENTRY(uniphier_secondary_startup)
mrc p15, 0, r1, c0, c0, 5 @ MPIDR (Multiprocessor Affinity Reg)
and r1, r1, #0xff
ldr r2, =uniphier_smp_booted
mov r0, #1
str r0, [r2, r1, lsl #2]
ldr r2, =uniphier_psci_holding_pen_release
pen: ldr r0, [r2]
cmp r0, r1
beq psci_cpu_entry
wfe
b pen
ENDPROC(uniphier_secondary_startup)
@@ -0,0 +1,38 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2012-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <linux/io.h>
#include "arm-mpcore.h"
#define PERIPHCLK (50 * 1000 * 1000) /* 50 MHz */
#define PRESCALER ((PERIPHCLK) / (CONFIG_SYS_TIMER_RATE) - 1)
static void *get_global_timer_base(void)
{
void *val;
asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (val) : : "memory");
return val + GLOBAL_TIMER_OFFSET;
}
unsigned long timer_read_counter(void)
{
/*
* ARM 64bit Global Timer is too much for our purpose.
* We use only lower 32 bit of the timer counter.
*/
return readl(get_global_timer_base() + GTIMER_CNT_L);
}
int timer_init(void)
{
/* enable timer */
writel(PRESCALER << 8 | 1, get_global_timer_base() + GTIMER_CTRL);
return 0;
}
@@ -0,0 +1,4 @@
# SPDX-License-Identifier: GPL-2.0+
obj-y += mem_map.o
obj-$(CONFIG_ARCH_UNIPHIER_LD20) += lowlevel_init.o
@@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2017 Socionext Inc.
*/
#include <linux/linkage.h>
ENTRY(lowlevel_init)
/* LD20 needs the following code to boot. I do not know why. */
mrs x0, sctlr_el1
msr sctlr_el1, x0
ret
ENDPROC(lowlevel_init)
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <linux/types.h>
#include <asm/armv8/mmu.h>
#include "../init.h"
static struct mm_region uniphier_mem_map[] = {
{
.virt = 0x00000000,
.phys = 0x00000000,
.size = 0x80000000,
.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
PTE_BLOCK_NON_SHARE |
PTE_BLOCK_PXN | PTE_BLOCK_UXN
},
{
.virt = 0x80000000,
.phys = 0x80000000,
.size = 0xc0000000,
.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
PTE_BLOCK_INNER_SHARE
},
{ /* sentinel */ }
};
struct mm_region *mem_map = uniphier_mem_map;
void uniphier_mem_map_init(unsigned long dram_base, unsigned long dram_size)
{
uniphier_mem_map[0].size = dram_base;
uniphier_mem_map[1].virt = dram_base;
uniphier_mem_map[1].phys = dram_base;
uniphier_mem_map[1].size = dram_size;
}
@@ -0,0 +1,67 @@
// SPDX-License-Identifier: GPL-2.0-only
//
// Copyright (C) 2019 Socionext Inc.
// Author: Masahiro Yamada <yamada.masahiro@socionext.com>
#include <common.h>
#include <dm/of.h>
#include <fdt_support.h>
#include <linux/io.h>
#include <linux/libfdt.h>
#include <linux/sizes.h>
#include <asm/global_data.h>
#include "base-address.h"
#include "sc64-regs.h"
#include "sg-regs.h"
/*
* Dummy initializers are needed to allocate these to .data section instead of
* .bss section. The .bss section is unusable before relocation because the
* .bss section and DT share the same address. Without the initializers,
* DT would be broken.
*/
void __iomem *sc_base = (void *)0xdeadbeef;
void __iomem *sg_base = (void *)0xdeadbeef;
static u64 uniphier_base_address_get(const char *compat_tail)
{
DECLARE_GLOBAL_DATA_PTR;
const void *fdt = gd->fdt_blob;
int offset, len, i;
const char *str;
for (offset = fdt_next_node(fdt, 0, NULL);
offset >= 0;
offset = fdt_next_node(fdt, offset, NULL)) {
for (i = 0;
(str = fdt_stringlist_get(fdt, offset, "compatible", i, &len));
i++) {
if (!memcmp(compat_tail,
str + len - strlen(compat_tail),
strlen(compat_tail)))
return fdt_get_base_address(fdt, offset);
}
}
return OF_BAD_ADDR;
}
int uniphier_base_address_init(void)
{
u64 base;
base = uniphier_base_address_get("-soc-glue");
if (base == OF_BAD_ADDR)
return -EINVAL;
sg_base = ioremap(base, SZ_8K);
base = uniphier_base_address_get("-sysctrl");
if (base == OF_BAD_ADDR)
return -EINVAL;
sc_base = ioremap(base, SZ_64K);
return 0;
}
@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2019 Socionext Inc.
*/
#ifndef __UNIPHIER_BASE_ADDRESS_H
#define __UNIPHIER_BASE_ADDRESS_H
#ifdef CONFIG_ARCH_UNIPHIER_V8_MULTI
int uniphier_base_address_init(void);
#else
static inline int uniphier_base_address_init(void)
{
return 0;
}
#endif
#endif /* __UNIPHIER_BASE_ADDRESS_H */
@@ -0,0 +1,4 @@
# SPDX-License-Identifier: GPL-2.0+
obj-$(CONFIG_ARCH_UNIPHIER_LD4) += bcu-ld4.o
obj-$(CONFIG_ARCH_UNIPHIER_SLD8) += bcu-ld4.o
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2011-2014 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <linux/io.h>
#include "../init.h"
#include "bcu-regs.h"
#define ch(x) ((x) >= 32 ? 0 : (x) < 0 ? 0x11111111 : 0x11111111 << (x))
void uniphier_ld4_bcu_init(const struct uniphier_board_data *bd)
{
int shift;
writel(0x44444444, BCSCR0); /* 0x20000000-0x3fffffff: ASM bus */
writel(0x11111111, BCSCR2); /* 0x80000000-0x9fffffff: IPPC/IPPD-bus */
writel(0x11111111, BCSCR3); /* 0xa0000000-0xbfffffff: IPPC/IPPD-bus */
writel(0x11111111, BCSCR4); /* 0xc0000000-0xdfffffff: IPPC/IPPD-bus */
writel(0x11111111, BCSCR5); /* 0xe0000000-0Xffffffff: IPPC/IPPD-bus */
/* Specify DDR channel */
shift = bd->dram_ch[0].size / 0x04000000 * 4;
writel(ch(shift), BCIPPCCHR2); /* 0x80000000-0x9fffffff */
shift -= 32;
writel(ch(shift), BCIPPCCHR3); /* 0xa0000000-0xbfffffff */
shift -= 32;
writel(ch(shift), BCIPPCCHR4); /* 0xc0000000-0xdfffffff */
}
@@ -0,0 +1,29 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* UniPhier BCU (Bus Control Unit) registers
*
* Copyright (C) 2011-2014 Panasonic Corporation
*/
#ifndef ARCH_BCU_REGS_H
#define ARCH_BCU_REGS_H
#define BCU_BASE 0x50080000
#define BCSCR(x) (BCU_BASE + 0x180 + (x) * 4)
#define BCSCR0 (BCSCR(0))
#define BCSCR1 (BCSCR(1))
#define BCSCR2 (BCSCR(2))
#define BCSCR3 (BCSCR(3))
#define BCSCR4 (BCSCR(4))
#define BCSCR5 (BCSCR(5))
#define BCIPPCCHR(x) (BCU_BASE + 0x0280 + (x) * 4)
#define BCIPPCCHR0 (BCIPPCCHR(0))
#define BCIPPCCHR1 (BCIPPCCHR(1))
#define BCIPPCCHR2 (BCIPPCCHR(2))
#define BCIPPCCHR3 (BCIPPCCHR(3))
#define BCIPPCCHR4 (BCIPPCCHR(4))
#define BCIPPCCHR5 (BCIPPCCHR(5))
#endif /* ARCH_BCU_REGS_H */
@@ -0,0 +1,149 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2012-2015 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/printk.h>
#include "init.h"
#include "micro-support-card.h"
#include "soc-info.h"
#ifdef CONFIG_ARCH_UNIPHIER_LD20
static void uniphier_ld20_misc_init(void)
{
/* ES1 errata: increase VDD09 supply to suppress VBO noise */
if (uniphier_get_soc_revision() == 1) {
writel(0x00000003, 0x6184e004);
writel(0x00000100, 0x6184e040);
writel(0x0000b500, 0x6184e024);
writel(0x00000001, 0x6184e000);
}
}
#endif
struct uniphier_initdata {
unsigned int soc_id;
void (*sbc_init)(void);
void (*pll_init)(void);
void (*clk_init)(void);
void (*misc_init)(void);
};
static const struct uniphier_initdata uniphier_initdata[] = {
#if defined(CONFIG_ARCH_UNIPHIER_LD4)
{
.soc_id = UNIPHIER_LD4_ID,
.sbc_init = uniphier_ld4_sbc_init,
.pll_init = uniphier_ld4_pll_init,
.clk_init = uniphier_ld4_clk_init,
},
#endif
#if defined(CONFIG_ARCH_UNIPHIER_PRO4)
{
.soc_id = UNIPHIER_PRO4_ID,
.sbc_init = uniphier_sbc_init_savepin,
.pll_init = uniphier_pro4_pll_init,
.clk_init = uniphier_pro4_clk_init,
},
#endif
#if defined(CONFIG_ARCH_UNIPHIER_SLD8)
{
.soc_id = UNIPHIER_SLD8_ID,
.sbc_init = uniphier_ld4_sbc_init,
.pll_init = uniphier_ld4_pll_init,
.clk_init = uniphier_ld4_clk_init,
},
#endif
#if defined(CONFIG_ARCH_UNIPHIER_PRO5)
{
.soc_id = UNIPHIER_PRO5_ID,
.sbc_init = uniphier_sbc_init_savepin,
.clk_init = uniphier_pro5_clk_init,
},
#endif
#if defined(CONFIG_ARCH_UNIPHIER_PXS2)
{
.soc_id = UNIPHIER_PXS2_ID,
.sbc_init = uniphier_pxs2_sbc_init,
.clk_init = uniphier_pxs2_clk_init,
},
#endif
#if defined(CONFIG_ARCH_UNIPHIER_LD6B)
{
.soc_id = UNIPHIER_LD6B_ID,
.sbc_init = uniphier_pxs2_sbc_init,
.clk_init = uniphier_pxs2_clk_init,
},
#endif
#if defined(CONFIG_ARCH_UNIPHIER_LD11)
{
.soc_id = UNIPHIER_LD11_ID,
.sbc_init = uniphier_ld11_sbc_init,
.pll_init = uniphier_ld11_pll_init,
.clk_init = uniphier_ld11_clk_init,
},
#endif
#if defined(CONFIG_ARCH_UNIPHIER_LD20)
{
.soc_id = UNIPHIER_LD20_ID,
.sbc_init = uniphier_ld11_sbc_init,
.pll_init = uniphier_ld20_pll_init,
.clk_init = uniphier_ld20_clk_init,
.misc_init = uniphier_ld20_misc_init,
},
#endif
#if defined(CONFIG_ARCH_UNIPHIER_PXS3)
{
.soc_id = UNIPHIER_PXS3_ID,
.sbc_init = uniphier_pxs2_sbc_init,
.pll_init = uniphier_pxs3_pll_init,
.clk_init = uniphier_pxs3_clk_init,
},
#endif
};
UNIPHIER_DEFINE_SOCDATA_FUNC(uniphier_get_initdata, uniphier_initdata)
int board_init(void)
{
const struct uniphier_initdata *initdata;
led_puts("U0");
initdata = uniphier_get_initdata();
if (!initdata) {
pr_err("unsupported SoC\n");
return -EINVAL;
}
initdata->sbc_init();
support_card_init();
led_puts("U0");
if (initdata->pll_init)
initdata->pll_init();
led_puts("U1");
if (initdata->clk_init)
initdata->clk_init();
led_puts("U2");
if (initdata->misc_init)
initdata->misc_init();
led_puts("U3");
support_card_late_init();
led_puts("Uboo");
return 0;
}
@@ -0,0 +1,149 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2014 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <env.h>
#include <init.h>
#include <spl.h>
#include <linux/libfdt.h>
#include <nand.h>
#include <stdio.h>
#include <linux/io.h>
#include <linux/printk.h>
#include <../drivers/mtd/nand/raw/denali.h>
#include "init.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 uniphier_set_env_fdt_file(void)
{
DECLARE_GLOBAL_DATA_PTR;
const char *compat;
char dtb_name[256];
int buf_len = sizeof(dtb_name);
int ret;
if (env_get("fdtfile"))
return; /* do nothing if it is already set */
compat = fdt_stringlist_get(gd->fdt_blob, 0, "compatible", 0, NULL);
if (!compat)
goto fail;
/* rip off the vendor prefix "socionext," */
compat = strchr(compat, ',');
if (!compat)
goto fail;
compat++;
strncpy(dtb_name, compat, buf_len);
buf_len -= strlen(compat);
strncat(dtb_name, ".dtb", buf_len);
ret = env_set("fdtfile", dtb_name);
if (ret)
goto fail;
return;
fail:
pr_warn("\"fdt_file\" environment variable was not set correctly\n");
}
static void uniphier_set_env_addr(const char *env, const char *offset_env)
{
unsigned long offset = 0;
const char *str;
char *end;
int ret;
if (env_get(env))
return; /* do nothing if it is already set */
if (offset_env) {
str = env_get(offset_env);
if (!str)
goto fail;
offset = simple_strtoul(str, &end, 16);
if (*end)
goto fail;
}
ret = env_set_hex(env, gd->ram_base + offset);
if (ret)
goto fail;
return;
fail:
pr_warn("\"%s\" environment variable was not set correctly\n", env);
}
int board_late_init(void)
{
puts("MODE: ");
switch (uniphier_boot_device_raw()) {
case BOOT_DEVICE_MMC1:
printf("eMMC Boot");
env_set("bootdev", "emmc");
break;
case BOOT_DEVICE_MMC2:
printf("SD Boot");
env_set("bootdev", "sd");
break;
case BOOT_DEVICE_NAND:
printf("NAND Boot");
env_set("bootdev", "nand");
nand_denali_wp_disable();
break;
case BOOT_DEVICE_NOR:
printf("NOR Boot");
env_set("bootdev", "nor");
break;
case BOOT_DEVICE_USB:
printf("USB Boot");
env_set("bootdev", "usb");
break;
default:
printf("Unknown");
break;
}
if (uniphier_have_internal_stm())
printf(" (STM: %s)",
uniphier_boot_from_backend() ? "OFF" : "ON");
printf("\n");
uniphier_set_env_fdt_file();
uniphier_set_env_addr("dram_base", NULL);
uniphier_set_env_addr("loadaddr", "loadaddr_offset");
uniphier_set_env_addr("kernel_addr_r", "kernel_addr_r_offset");
uniphier_set_env_addr("ramdisk_addr_r", "ramdisk_addr_r_offset");
uniphier_set_env_addr("fdt_addr_r", "fdt_addr_r_offset");
return 0;
}
@@ -0,0 +1,162 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2015-2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <linux/libfdt.h>
#include <linux/kernel.h>
#include "init.h"
DECLARE_GLOBAL_DATA_PTR;
#if defined(CONFIG_ARCH_UNIPHIER_LD4)
static const struct uniphier_board_data uniphier_ld4_data = {
.dram_freq = 1600,
.dram_ch[0] = {
.size = 0x10000000,
.width = 16,
},
.dram_ch[1] = {
.size = 0x10000000,
.width = 16,
},
.flags = UNIPHIER_BD_DDR3PLUS,
};
#endif
#if defined(CONFIG_ARCH_UNIPHIER_PRO4)
/* 1GB RAM board */
static const struct uniphier_board_data uniphier_pro4_data = {
.dram_freq = 1600,
.dram_ch[0] = {
.size = 0x20000000,
.width = 32,
},
.dram_ch[1] = {
.size = 0x20000000,
.width = 32,
},
};
/* 2GB RAM board */
static const struct uniphier_board_data uniphier_pro4_2g_data = {
.dram_freq = 1600,
.dram_ch[0] = {
.size = 0x40000000,
.width = 32,
},
.dram_ch[1] = {
.size = 0x40000000,
.width = 32,
},
};
#endif
#if defined(CONFIG_ARCH_UNIPHIER_SLD8)
static const struct uniphier_board_data uniphier_sld8_data = {
.dram_freq = 1333,
.dram_ch[0] = {
.size = 0x10000000,
.width = 16,
},
.dram_ch[1] = {
.size = 0x10000000,
.width = 16,
},
.flags = UNIPHIER_BD_DDR3PLUS,
};
#endif
#if defined(CONFIG_ARCH_UNIPHIER_PRO5)
static const struct uniphier_board_data uniphier_pro5_data = {
.dram_freq = 1866,
.dram_ch[0] = {
.size = 0x20000000,
.width = 32,
},
.dram_ch[1] = {
.size = 0x20000000,
.width = 32,
},
};
#endif
#if defined(CONFIG_ARCH_UNIPHIER_PXS2)
static const struct uniphier_board_data uniphier_pxs2_data = {
.dram_freq = 2133,
.dram_ch[0] = {
.size = 0x40000000,
.width = 32,
},
.dram_ch[1] = {
.size = 0x20000000,
.width = 32,
},
.dram_ch[2] = {
.size = 0x20000000,
.width = 16,
},
};
#endif
#if defined(CONFIG_ARCH_UNIPHIER_LD6B)
static const struct uniphier_board_data uniphier_ld6b_data = {
.dram_freq = 1866,
.dram_ch[0] = {
.size = 0x40000000,
.width = 32,
},
.dram_ch[1] = {
.size = 0x20000000,
.width = 32,
},
.dram_ch[2] = {
.size = 0x20000000,
.width = 16,
},
};
#endif
struct uniphier_board_id {
const char *compatible;
const struct uniphier_board_data *param;
};
static const struct uniphier_board_id uniphier_boards[] = {
#if defined(CONFIG_ARCH_UNIPHIER_LD4)
{ "socionext,uniphier-ld4", &uniphier_ld4_data, },
#endif
#if defined(CONFIG_ARCH_UNIPHIER_PRO4)
{ "socionext,uniphier-pro4-ace", &uniphier_pro4_2g_data, },
{ "socionext,uniphier-pro4-sanji", &uniphier_pro4_2g_data, },
{ "socionext,uniphier-pro4", &uniphier_pro4_data, },
#endif
#if defined(CONFIG_ARCH_UNIPHIER_SLD8)
{ "socionext,uniphier-sld8", &uniphier_sld8_data, },
#endif
#if defined(CONFIG_ARCH_UNIPHIER_PRO5)
{ "socionext,uniphier-pro5", &uniphier_pro5_data, },
#endif
#if defined(CONFIG_ARCH_UNIPHIER_PXS2)
{ "socionext,uniphier-pxs2", &uniphier_pxs2_data, },
#endif
#if defined(CONFIG_ARCH_UNIPHIER_LD6B)
{ "socionext,uniphier-ld6b", &uniphier_ld6b_data, },
#endif
};
const struct uniphier_board_data *uniphier_get_board_param(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(uniphier_boards); i++) {
if (!fdt_node_check_compatible(gd->fdt_blob, 0,
uniphier_boards[i].compatible))
return uniphier_boards[i].param;
}
return NULL;
}
@@ -0,0 +1,13 @@
# SPDX-License-Identifier: GPL-2.0+
obj-y += boot-device.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
obj-$(CONFIG_ARCH_UNIPHIER_PXS3) += boot-device-pxs3.o
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016-2017 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <spl.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include "boot-device.h"
const struct uniphier_boot_device uniphier_ld11_boot_device_table[] = {
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, EraseSize 128KB, Addr 4)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, EraseSize 128KB, Addr 4)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, EraseSize 128KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, EraseSize 128KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, EraseSize 256KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, EraseSize 256KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, EraseSize 512KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, EraseSize 512KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 8, EraseSize 128KB, Addr 4)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, EraseSize 128KB, Addr 4)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 8, EraseSize 128KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, EraseSize 128KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 8, EraseSize 256KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, EraseSize 256KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 8, EraseSize 512KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, EraseSize 512KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, ONFI, Addr 4)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, ONFI, Addr 4)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, ONFI, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, ONFI, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 8, ONFI Addr 4)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, ONFI Addr 4)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 8, ONFI Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, ONFI Addr 5)"},
{BOOT_DEVICE_MMC1, "eMMC (Legacy, 4bit, 1.8V, Training Off)"},
{BOOT_DEVICE_MMC1, "eMMC (Legacy, 4bit, 1.8V, Training On)"},
{BOOT_DEVICE_MMC1, "eMMC (Legacy, 8bit, 1.8V, Training Off)"},
{BOOT_DEVICE_MMC1, "eMMC (Legacy, 8bit, 1.8V, Training On)"},
{BOOT_DEVICE_MMC1, "eMMC (High Speed SDR, 8bit, 1.8V, Training Off)"},
{BOOT_DEVICE_MMC1, "eMMC (High Speed SDR, 8bit, 1.8V, Training On)"},
{BOOT_DEVICE_MMC1, "eMMC (Legacy, 4bit, 1.8V, Training Off)"},
{BOOT_DEVICE_NOR, "NOR (XECS1)"},
};
const unsigned uniphier_ld11_boot_device_count =
ARRAY_SIZE(uniphier_ld11_boot_device_table);
int uniphier_ld11_boot_device_is_usb(u32 pinmon)
{
return !!(~pinmon & 0x00000080);
}
int uniphier_ld20_boot_device_is_usb(u32 pinmon)
{
return !!(~pinmon & 0x00000780);
}
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2014 Panasonic Corporation
* Copyright (C) 2015-2017 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <spl.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include "boot-device.h"
const struct uniphier_boot_device uniphier_ld4_boot_device_table[] = {
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, EraseSize 128KB, Addr 4)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, EraseSize 128KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, EraseSize 128KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, EraseSize 256KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, EraseSize 256KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, EraseSize 512KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, EraseSize 512KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 24, EraseSize 1MB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 4, ECC 24, EraseSize 1MB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 8, EraseSize 128KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, EraseSize 128KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 8, EraseSize 256KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, EraseSize 256KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 8, EraseSize 512KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, EraseSize 512KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 24, EraseSize 512KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, ONFI, Addr 4)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, ONFI, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, ONFI, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 24, ONFI, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 4, ECC 24, ONFI, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 8, ONFI, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, ONFI, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 24, ONFI, Addr 5)"},
{BOOT_DEVICE_MMC1, "eMMC (3.3V)"},
{BOOT_DEVICE_MMC1, "eMMC (1.8V)"},
{BOOT_DEVICE_NONE, "Reserved"},
{BOOT_DEVICE_NONE, "Reserved"},
{BOOT_DEVICE_NONE, "Reserved"},
{BOOT_DEVICE_NONE, "Reserved"},
{BOOT_DEVICE_NONE, "Reserved"},
{BOOT_DEVICE_NOR, "NOR (XECS0)"},
};
const unsigned uniphier_ld4_boot_device_count =
ARRAY_SIZE(uniphier_ld4_boot_device_table);
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2015-2017 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <spl.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include "boot-device.h"
const struct uniphier_boot_device uniphier_pro5_boot_device_table[] = {
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 8, EraseSize 128KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, EraseSize 128KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 8, EraseSize 256KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, EraseSize 256KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 8, EraseSize 512KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, EraseSize 512KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 8, EraseSize 128KB, Addr 4)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, EraseSize 128MB, Addr 4)"},
{BOOT_DEVICE_NONE, "Reserved"},
{BOOT_DEVICE_NONE, "Reserved"},
{BOOT_DEVICE_NONE, "Reserved"},
{BOOT_DEVICE_NONE, "Reserved"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, EraseSize 512MB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, EraseSize 512KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, EraseSize 128KB, Addr 4)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, EraseSize 128KB, Addr 4)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 8, ONFI, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, ONFI, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 8, ONFI, Addr 4)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, ONFI, Addr 4)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, ONFI, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, ONFI, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, ONFI, Addr 4)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, ONFI, Addr 4)"},
{BOOT_DEVICE_NONE, "Reserved"},
{BOOT_DEVICE_MMC1, "eMMC (1.8V)"},
{BOOT_DEVICE_NONE, "Reserved"},
{BOOT_DEVICE_NONE, "Reserved"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, EraseSize 128MB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, EraseSize 128KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, EraseSize 256KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, EraseSize 256KB, Addr 5)"},
};
const unsigned uniphier_pro5_boot_device_count =
ARRAY_SIZE(uniphier_pro5_boot_device_table);
@@ -0,0 +1,63 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2015-2017 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <spl.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include "boot-device.h"
const struct uniphier_boot_device uniphier_pxs2_boot_device_table[] = {
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, EraseSize 128KB, Addr 4)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, EraseSize 128KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, EraseSize 128KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, EraseSize 256KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, EraseSize 256KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, EraseSize 512KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, EraseSize 512KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, EraseSize 128KB, Addr 4)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 8, EraseSize 128KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, EraseSize 128KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 8, EraseSize 256KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, EraseSize 256KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 8, EraseSize 512KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, EraseSize 512KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 8, EraseSize 128KB, Addr 4)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, EraseSize 128KB, Addr 4)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, ONFI, Addr 4)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, ONFI, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, ONFI, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, ONFI, Addr 4)"},
{BOOT_DEVICE_MMC1, "eMMC (1.8V)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 8, ONFI, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, ONFI, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 8, ONFI, Addr 4)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 1, ECC 16, ONFI, Addr 4)"},
{BOOT_DEVICE_SPI, "SPI (3Byte CS0)"},
{BOOT_DEVICE_SPI, "SPI (4Byte CS0)"},
{BOOT_DEVICE_SPI, "SPI (3Byte CS1)"},
{BOOT_DEVICE_SPI, "SPI (4Byte CS1)"},
{BOOT_DEVICE_SPI, "SPI (4Byte CS0)"},
{BOOT_DEVICE_SPI, "SPI (3Byte CS0)"},
{BOOT_DEVICE_NONE, "Reserved"},
};
const unsigned uniphier_pxs2_boot_device_count =
ARRAY_SIZE(uniphier_pxs2_boot_device_table);
int uniphier_pxs2_boot_device_is_usb(u32 pinmon)
{
return !!(pinmon & 0x00000040);
}
unsigned int uniphier_pxs2_boot_device_fixup(unsigned int mode)
{
if (mode == BOOT_DEVICE_USB)
return BOOT_DEVICE_NOR;
return mode;
}
@@ -0,0 +1,40 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2017 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <spl.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include "../sg-regs.h"
#include "boot-device.h"
const struct uniphier_boot_device uniphier_pxs3_boot_device_table[] = {
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, EraseSize 128KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, EraseSize 128KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, EraseSize 256KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, EraseSize 256KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, EraseSize 512KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, EraseSize 512KB, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, ONFI, Addr 5)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, ONFI, Addr 5)"},
{BOOT_DEVICE_MMC1, "eMMC (Legacy, 4bit, 1.8V, Training Off)"},
{BOOT_DEVICE_MMC1, "eMMC (Legacy, 4bit, 1.8V, Training On)"},
{BOOT_DEVICE_MMC1, "eMMC (Legacy, 8bit, 1.8V, Training Off)"},
{BOOT_DEVICE_MMC1, "eMMC (Legacy, 8bit, 1.8V, Training On)"},
{BOOT_DEVICE_MMC1, "eMMC (High Speed SDR, 8bit, 1.8V, Training Off)"},
{BOOT_DEVICE_MMC1, "eMMC (High Speed SDR, 8bit, 1.8V, Training On)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 8, ONFI, Addr 5, BBM Last Page)"},
{BOOT_DEVICE_NAND, "NAND (Mirror 8, ECC 16, ONFI, Addr 5, BBM Last Page)"},
};
const unsigned uniphier_pxs3_boot_device_count =
ARRAY_SIZE(uniphier_pxs3_boot_device_table);
int uniphier_pxs3_boot_device_is_usb(u32 pinmon)
{
return !!(readl(sg_base + SG_PINMON2) & BIT(31));
}
@@ -0,0 +1,258 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2015-2017 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <spl.h>
#include <stdio.h>
#include <linux/io.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_sd)(u32 pinmon);
int (*boot_device_is_usb)(u32 pinmon);
unsigned int (*boot_device_fixup)(unsigned int mode);
int (*boot_is_swapped)(void);
bool have_internal_stm;
};
static const struct uniphier_boot_device_info uniphier_boot_device_info[] = {
#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,
.boot_is_swapped = uniphier_sbc_boot_is_swapped,
.have_internal_stm = true,
},
#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,
.boot_is_swapped = uniphier_sbc_boot_is_swapped,
.have_internal_stm = false,
},
#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,
.boot_is_swapped = uniphier_sbc_boot_is_swapped,
.have_internal_stm = true,
},
#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,
.boot_is_swapped = uniphier_sbc_boot_is_swapped,
.have_internal_stm = false,
},
#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,
.boot_is_swapped = uniphier_sbc_boot_is_swapped,
.have_internal_stm = false,
},
#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,
.boot_is_swapped = uniphier_sbc_boot_is_swapped,
.have_internal_stm = true, /* STM on A-chip */
},
#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_is_swapped = uniphier_sbc_boot_is_swapped,
.have_internal_stm = true,
},
#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_is_swapped = uniphier_sbc_boot_is_swapped,
.have_internal_stm = true,
},
#endif
#if defined(CONFIG_ARCH_UNIPHIER_PXS3)
{
.soc_id = UNIPHIER_PXS3_ID,
.boot_device_sel_shift = 1,
.boot_device_table = uniphier_pxs3_boot_device_table,
.boot_device_count = &uniphier_pxs3_boot_device_count,
.boot_device_is_usb = uniphier_pxs3_boot_device_is_usb,
.boot_is_swapped = uniphier_sbc_boot_is_swapped,
.have_internal_stm = false,
},
#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 (info->boot_is_swapped && info->boot_is_swapped())
return BOOT_DEVICE_NOR;
pinmon = readl(sg_base + SG_PINMON0);
if (info->boot_device_is_sd && info->boot_device_is_sd(pinmon))
return BOOT_DEVICE_MMC2;
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;
}
int uniphier_have_internal_stm(void)
{
const struct uniphier_boot_device_info *info;
info = uniphier_get_boot_device_info();
if (!info) {
pr_err("unsupported SoC\n");
return -ENOTSUPP;
}
return info->have_internal_stm;
}
int uniphier_boot_from_backend(void)
{
return !!(readl(sg_base + SG_PINMON0) & BIT(27));
}
#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;
}
if (uniphier_have_internal_stm())
printf("STB Micon: %s\n",
uniphier_boot_from_backend() ? "OFF" : "ON");
if (info->boot_is_swapped)
printf("Boot Swap: %s\n",
info->boot_is_swapped() ? "ON" : "OFF");
pinmon = readl(sg_base + SG_PINMON0);
if (info->boot_device_is_sd)
printf("SD Boot: %s\n",
info->boot_device_is_sd(pinmon) ? "ON" : "OFF");
if (info->boot_device_is_usb)
printf("USB Boot: %s\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("\nBoot 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,34 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2017 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#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_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 struct uniphier_boot_device uniphier_pxs3_boot_device_table[];
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;
extern const unsigned int uniphier_pxs3_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);
int uniphier_pxs3_boot_device_is_usb(u32 pinmon);
unsigned int uniphier_pxs2_boot_device_fixup(unsigned int mode);
#endif /* _UNIPHIER_BOOT_DEVICE_H_ */
@@ -0,0 +1,24 @@
# SPDX-License-Identifier: GPL-2.0+
ifdef CONFIG_SPL_BUILD
obj-$(CONFIG_ARCH_UNIPHIER_LD4) += clk-early-ld4.o clk-dram-ld4.o dpll-ld4.o
obj-$(CONFIG_ARCH_UNIPHIER_PRO4) += clk-early-ld4.o clk-dram-ld4.o dpll-pro4.o
obj-$(CONFIG_ARCH_UNIPHIER_SLD8) += clk-early-ld4.o clk-dram-ld4.o dpll-sld8.o
obj-$(CONFIG_ARCH_UNIPHIER_PRO5) += clk-early-ld4.o clk-dram-pro5.o dpll-pro5.o
obj-$(CONFIG_ARCH_UNIPHIER_PXS2) += clk-early-ld4.o clk-dram-pxs2.o dpll-pxs2.o
obj-$(CONFIG_ARCH_UNIPHIER_LD6B) += clk-early-ld4.o clk-dram-pxs2.o dpll-pxs2.o
else
obj-$(CONFIG_ARCH_UNIPHIER_LD4) += clk-ld4.o pll-ld4.o dpll-tail.o
obj-$(CONFIG_ARCH_UNIPHIER_PRO4) += clk-pro4.o pll-pro4.o dpll-tail.o
obj-$(CONFIG_ARCH_UNIPHIER_SLD8) += clk-ld4.o pll-ld4.o dpll-tail.o
obj-$(CONFIG_ARCH_UNIPHIER_PRO5) += clk-pro5.o
obj-$(CONFIG_ARCH_UNIPHIER_PXS2) += clk-pxs2.o
obj-$(CONFIG_ARCH_UNIPHIER_LD6B) += clk-pxs2.o
obj-$(CONFIG_ARCH_UNIPHIER_LD11) += clk-ld11.o pll-base-ld20.o pll-ld11.o
obj-$(CONFIG_ARCH_UNIPHIER_LD20) += clk-ld20.o pll-base-ld20.o pll-ld20.o
obj-$(CONFIG_ARCH_UNIPHIER_PXS3) += clk-pxs3.o pll-base-ld20.o pll-pxs3.o
endif
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2011-2014 Panasonic Corporation
* Copyright (C) 2015-2017 Socionext Inc.
*/
#include <common.h>
#include <spl.h>
#include <linux/io.h>
#include "../init.h"
#include "../sc-regs.h"
void uniphier_ld4_dram_clk_init(void)
{
u32 tmp;
/* deassert reset */
tmp = readl(sc_base + SC_RSTCTRL);
tmp |= SC_RSTCTRL_NRST_UMC1 | SC_RSTCTRL_NRST_UMC0;
writel(tmp, sc_base + SC_RSTCTRL);
readl(sc_base + SC_RSTCTRL); /* dummy read */
/* provide clocks */
tmp = readl(sc_base + SC_CLKCTRL);
tmp |= SC_CLKCTRL_CEN_UMC;
writel(tmp, sc_base + SC_CLKCTRL);
readl(sc_base + SC_CLKCTRL); /* dummy read */
}
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2015-2017 Socionext Inc.
*/
#include <linux/io.h>
#include "../init.h"
#include "../sc-regs.h"
void uniphier_pro5_dram_clk_init(void)
{
u32 tmp;
/*
* deassert reset
* UMCA2: Ch1 (DDR3)
* UMCA1, UMC31: Ch0 (WIO1)
* UMCA0, UMC30: Ch0 (WIO0)
*/
tmp = readl(sc_base + SC_RSTCTRL4);
tmp |= SC_RSTCTRL4_NRST_UMCSB | SC_RSTCTRL4_NRST_UMCA2 |
SC_RSTCTRL4_NRST_UMCA1 | SC_RSTCTRL4_NRST_UMCA0 |
SC_RSTCTRL4_NRST_UMC31 | SC_RSTCTRL4_NRST_UMC30;
writel(tmp, sc_base + SC_RSTCTRL4);
readl(sc_base + SC_RSTCTRL4); /* dummy read */
/* provide clocks */
tmp = readl(sc_base + SC_CLKCTRL4);
tmp |= SC_CLKCTRL4_CEN_UMCSB | SC_CLKCTRL4_CEN_UMC1 |
SC_CLKCTRL4_CEN_UMC0;
writel(tmp, sc_base + SC_CLKCTRL4);
readl(sc_base + SC_CLKCTRL4); /* dummy read */
}
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016-2017 Socionext Inc.
*/
#include <common.h>
#include <spl.h>
#include <linux/io.h>
#include "../init.h"
#include "../sc-regs.h"
void uniphier_pxs2_dram_clk_init(void)
{
u32 tmp;
/* deassert reset */
tmp = readl(sc_base + SC_RSTCTRL4);
tmp |= SC_RSTCTRL4_NRST_UMCSB | SC_RSTCTRL4_NRST_UMCA2 |
SC_RSTCTRL4_NRST_UMCA1 | SC_RSTCTRL4_NRST_UMCA0 |
SC_RSTCTRL4_NRST_UMC32 | SC_RSTCTRL4_NRST_UMC31 |
SC_RSTCTRL4_NRST_UMC30;
writel(tmp, sc_base + SC_RSTCTRL4);
readl(sc_base + SC_RSTCTRL4); /* dummy read */
/* provide clocks */
tmp = readl(sc_base + SC_CLKCTRL4);
tmp |= SC_CLKCTRL4_CEN_UMCSB | SC_CLKCTRL4_CEN_UMC2 |
SC_CLKCTRL4_CEN_UMC1 | SC_CLKCTRL4_CEN_UMC0;
writel(tmp, sc_base + SC_CLKCTRL4);
readl(sc_base + SC_CLKCTRL4); /* dummy read */
}
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2011-2014 Panasonic Corporation
* Copyright (C) 2015-2017 Socionext Inc.
*/
#include <common.h>
#include <spl.h>
#include <linux/io.h>
#include "../init.h"
#include "../sc-regs.h"
void uniphier_ld4_early_clk_init(void)
{
u32 tmp;
/* deassert reset */
if (spl_boot_device() != BOOT_DEVICE_NAND) {
tmp = readl(sc_base + SC_RSTCTRL);
tmp &= ~SC_RSTCTRL_NRST_NAND;
writel(tmp, sc_base + SC_RSTCTRL);
};
/* provide clocks */
tmp = readl(sc_base + SC_CLKCTRL);
tmp |= SC_CLKCTRL_CEN_SBC | SC_CLKCTRL_CEN_PERI;
writel(tmp, sc_base + SC_CLKCTRL);
readl(sc_base + SC_CLKCTRL); /* dummy read */
}
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Socionext Inc.
*/
#include <common.h>
#include <spl.h>
#include <linux/bitops.h>
#include <linux/io.h>
#include "../init.h"
#include "../sc64-regs.h"
#include "../sg-regs.h"
#define SDCTRL_EMMC_HW_RESET 0x59810280
void uniphier_ld11_clk_init(void)
{
/* if booted from a device other than USB, without stand-by MPU */
if ((readl(sg_base + SG_PINMON0) & BIT(27)) &&
uniphier_boot_device_raw() != BOOT_DEVICE_USB) {
writel(1, sg_base + SG_ETPHYPSHUT);
writel(1, sg_base + SG_ETPHYCNT);
udelay(1); /* wait for regulator level 1.1V -> 2.5V */
writel(3, sg_base + SG_ETPHYCNT);
writel(3, sg_base + SG_ETPHYPSHUT);
writel(7, sg_base + SG_ETPHYCNT);
}
/* TODO: use "mmc-pwrseq-emmc" */
writel(1, SDCTRL_EMMC_HW_RESET);
#ifdef CONFIG_USB_EHCI_HCD
{
int ch;
for (ch = 0; ch < 3; ch++) {
void __iomem *phyctrl = sg_base + SG_USBPHYCTRL;
writel(0x82280600, phyctrl + 8 * ch);
writel(0x00000106, phyctrl + 8 * ch + 4);
}
}
#endif
}
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2017 Socionext Inc.
*/
#include <linux/bitops.h>
#include <linux/io.h>
#include "../init.h"
#include "../sc64-regs.h"
#define SDCTRL_EMMC_HW_RESET 0x59810280
void uniphier_ld20_clk_init(void)
{
u32 tmp;
tmp = readl(sc_base + SC_RSTCTRL6);
tmp |= BIT(8); /* Mali */
writel(tmp, sc_base + SC_RSTCTRL6);
tmp = readl(sc_base + SC_CLKCTRL6);
tmp |= BIT(8); /* Mali */
writel(tmp, sc_base + SC_CLKCTRL6);
/* TODO: use "mmc-pwrseq-emmc" */
writel(1, SDCTRL_EMMC_HW_RESET);
}
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2011-2015 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <linux/io.h>
#include "../init.h"
#include "../sc-regs.h"
void uniphier_ld4_clk_init(void)
{
u32 tmp;
/* deassert reset */
tmp = readl(sc_base + SC_RSTCTRL);
#ifdef CONFIG_NAND_DENALI
tmp |= SC_RSTCTRL_NRST_NAND;
#endif
writel(tmp, sc_base + SC_RSTCTRL);
readl(sc_base + SC_RSTCTRL); /* dummy read */
/* provide clocks */
tmp = readl(sc_base + SC_CLKCTRL);
#ifdef CONFIG_NAND_DENALI
tmp |= SC_CLKCTRL_CEN_NAND;
#endif
writel(tmp, sc_base + SC_CLKCTRL);
readl(sc_base + SC_CLKCTRL); /* dummy read */
}
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2011-2015 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <linux/io.h>
#include "../init.h"
#include "../sc-regs.h"
void uniphier_pro4_clk_init(void)
{
u32 tmp;
/* deassert reset */
tmp = readl(sc_base + SC_RSTCTRL);
#ifdef CONFIG_USB_DWC3_UNIPHIER
tmp |= SC_RSTCTRL_NRST_USB3B0 | SC_RSTCTRL_NRST_USB3C0 |
SC_RSTCTRL_NRST_GIO;
#endif
#ifdef CONFIG_NAND_DENALI
tmp |= SC_RSTCTRL_NRST_NAND;
#endif
writel(tmp, sc_base + SC_RSTCTRL);
readl(sc_base + SC_RSTCTRL); /* dummy read */
#ifdef CONFIG_USB_DWC3_UNIPHIER
tmp = readl(sc_base + SC_RSTCTRL2);
tmp |= SC_RSTCTRL2_NRST_USB3B1 | SC_RSTCTRL2_NRST_USB3C1;
writel(tmp, sc_base + SC_RSTCTRL2);
readl(sc_base + SC_RSTCTRL2); /* dummy read */
#endif
/* provide clocks */
tmp = readl(sc_base + SC_CLKCTRL);
#ifdef CONFIG_USB_DWC3_UNIPHIER
tmp |= SC_CLKCTRL_CEN_USB31 | SC_CLKCTRL_CEN_USB30 |
SC_CLKCTRL_CEN_GIO;
#endif
#ifdef CONFIG_NAND_DENALI
tmp |= SC_CLKCTRL_CEN_NAND;
#endif
writel(tmp, sc_base + SC_CLKCTRL);
readl(sc_base + SC_CLKCTRL); /* dummy read */
}
@@ -0,0 +1,44 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <linux/io.h>
#include "../init.h"
#include "../sc-regs.h"
void uniphier_pro5_clk_init(void)
{
u32 tmp;
/* deassert reset */
tmp = readl(sc_base + SC_RSTCTRL);
#ifdef CONFIG_USB_DWC3_UNIPHIER
tmp |= SC_RSTCTRL_NRST_USB3B0 | SC_RSTCTRL_NRST_GIO;
#endif
#ifdef CONFIG_NAND_DENALI
tmp |= SC_RSTCTRL_NRST_NAND;
#endif
writel(tmp, sc_base + SC_RSTCTRL);
readl(sc_base + SC_RSTCTRL); /* dummy read */
#ifdef CONFIG_USB_DWC3_UNIPHIER
tmp = readl(sc_base + SC_RSTCTRL2);
tmp |= SC_RSTCTRL2_NRST_USB3B1;
writel(tmp, sc_base + SC_RSTCTRL2);
readl(sc_base + SC_RSTCTRL2); /* dummy read */
#endif
/* provide clocks */
tmp = readl(sc_base + SC_CLKCTRL);
#ifdef CONFIG_USB_DWC3_UNIPHIER
tmp |= SC_CLKCTRL_CEN_USB31 | SC_CLKCTRL_CEN_USB30 |
SC_CLKCTRL_CEN_GIO;
#endif
#ifdef CONFIG_NAND_DENALI
tmp |= SC_CLKCTRL_CEN_NAND;
#endif
writel(tmp, sc_base + SC_CLKCTRL);
readl(sc_base + SC_CLKCTRL); /* dummy read */
}
@@ -0,0 +1,49 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <linux/bitops.h>
#include <linux/io.h>
#include "../init.h"
#include "../sc-regs.h"
void uniphier_pxs2_clk_init(void)
{
u32 tmp;
/* deassert reset */
tmp = readl(sc_base + SC_RSTCTRL);
#ifdef CONFIG_USB_DWC3_UNIPHIER
tmp |= SC_RSTCTRL_NRST_USB3B0 | SC_RSTCTRL_NRST_GIO;
#endif
#ifdef CONFIG_NAND_DENALI
tmp |= SC_RSTCTRL_NRST_NAND;
#endif
writel(tmp, sc_base + SC_RSTCTRL);
readl(sc_base + SC_RSTCTRL); /* dummy read */
#ifdef CONFIG_USB_DWC3_UNIPHIER
tmp = readl(sc_base + SC_RSTCTRL2);
tmp |= SC_RSTCTRL2_NRST_USB3B1;
writel(tmp, sc_base + SC_RSTCTRL2);
readl(sc_base + SC_RSTCTRL2); /* dummy read */
tmp = readl(sc_base + SC_RSTCTRL6);
tmp |= 0x37;
writel(tmp, sc_base + SC_RSTCTRL6);
#endif
/* provide clocks */
tmp = readl(sc_base + SC_CLKCTRL);
#ifdef CONFIG_USB_DWC3_UNIPHIER
tmp |= BIT(20) | BIT(19) | SC_CLKCTRL_CEN_USB31 | SC_CLKCTRL_CEN_USB30 |
SC_CLKCTRL_CEN_GIO;
#endif
#ifdef CONFIG_NAND_DENALI
tmp |= SC_CLKCTRL_CEN_NAND;
#endif
writel(tmp, sc_base + SC_CLKCTRL);
readl(sc_base + SC_CLKCTRL); /* dummy read */
}
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2017 Socionext Inc.
*/
#include <linux/bitops.h>
#include <linux/io.h>
#include "../init.h"
#include "../sc64-regs.h"
#define SDCTRL_EMMC_HW_RESET 0x59810280
void uniphier_pxs3_clk_init(void)
{
u32 tmp;
tmp = readl(sc_base + SC_RSTCTRL6);
tmp |= BIT(8); /* Mali */
writel(tmp, sc_base + SC_RSTCTRL6);
tmp = readl(sc_base + SC_CLKCTRL6);
tmp |= BIT(8); /* Mali */
writel(tmp, sc_base + SC_CLKCTRL6);
/* TODO: use "mmc-pwrseq-emmc" */
writel(1, SDCTRL_EMMC_HW_RESET);
}
@@ -0,0 +1,55 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2013-2014 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
*/
#include <common.h>
#include <linux/errno.h>
#include <linux/io.h>
#include "../init.h"
#include "../sc-regs.h"
#undef DPLL_SSC_RATE_1PER
int uniphier_ld4_dpll_init(const struct uniphier_board_data *bd)
{
unsigned int dram_freq = bd->dram_freq;
u32 tmp;
/*
* Set Frequency
* Set 0xc(1600MHz)/0xd(1333MHz)/0xe(1066MHz)
* to FOUT (DPLLCTRL.bit[29:20])
*/
tmp = readl(sc_base + SC_DPLLCTRL);
tmp &= ~0x000f0000;
switch (dram_freq) {
case 1333:
tmp |= 0x000d0000;
break;
case 1600:
tmp |= 0x000c0000;
break;
default:
pr_err("Unsupported frequency");
return -EINVAL;
}
#if defined(DPLL_SSC_RATE_1PER)
tmp &= ~SC_DPLLCTRL_SSC_RATE;
#else
tmp |= SC_DPLLCTRL_SSC_RATE;
#endif
writel(tmp, sc_base + SC_DPLLCTRL);
tmp = readl(sc_base + SC_DPLLCTRL2);
tmp |= SC_DPLLCTRL2_NRSTDS;
writel(tmp, sc_base + SC_DPLLCTRL2);
/* Wait 500 usec until dpll gets stable */
udelay(500);
return 0;
}
@@ -0,0 +1,59 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2013-2014 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
*/
#include <common.h>
#include <linux/errno.h>
#include <linux/io.h>
#include "../init.h"
#include "../sc-regs.h"
#undef DPLL_SSC_RATE_1PER
int uniphier_pro4_dpll_init(const struct uniphier_board_data *bd)
{
unsigned int dram_freq = bd->dram_freq;
u32 tmp;
/*
* Set Frequency
* Set 0xc(1600MHz)/0xd(1333MHz)/0xe(1066MHz)
* to FOUT ( DPLLCTRL.bit[29:20] )
*/
tmp = readl(sc_base + SC_DPLLCTRL);
tmp &= ~(0x000f0000);
switch (dram_freq) {
case 1333:
tmp |= 0x000d0000;
break;
case 1600:
tmp |= 0x000c0000;
break;
default:
pr_err("Unsupported frequency");
return -EINVAL;
}
/*
* Set Moduration rate
* Set 0x0(1%)/0x1(2%) to SSC_RATE(DPLLCTRL.bit[15])
*/
#if defined(DPLL_SSC_RATE_1PER)
tmp &= ~0x00008000;
#else
tmp |= 0x00008000;
#endif
writel(tmp, sc_base + SC_DPLLCTRL);
tmp = readl(sc_base + SC_DPLLCTRL2);
tmp |= SC_DPLLCTRL2_NRSTDS;
writel(tmp, sc_base + SC_DPLLCTRL2);
/* Wait until dpll gets stable */
udelay(500);
return 0;
}
@@ -0,0 +1,6 @@
#include "../init.h"
int uniphier_pro5_dpll_init(const struct uniphier_board_data *bd)
{
return 0;
}
@@ -0,0 +1,6 @@
#include "../init.h"
int uniphier_pxs2_dpll_init(const struct uniphier_board_data *bd)
{
return 0;
}
@@ -0,0 +1,61 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2013-2014 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
*/
#include <linux/delay.h>
#include <linux/io.h>
#include "../init.h"
#include "../sc-regs.h"
int uniphier_sld8_dpll_init(const struct uniphier_board_data *bd)
{
u32 tmp;
/*
* Set DPLL SSC parameters for DPLLCTRL3
* [23] DIVN_TEST 0x1
* [22:16] DIVN 0x50
* [10] FREFSEL_TEST 0x1
* [9:8] FREFSEL 0x2
* [4] ICPD_TEST 0x1
* [3:0] ICPD 0xb
*/
tmp = readl(sc_base + SC_DPLLCTRL3);
tmp &= ~0x00ff0717;
tmp |= 0x00d0061b;
writel(tmp, sc_base + SC_DPLLCTRL3);
/*
* Set DPLL SSC parameters for DPLLCTRL
* <-1%> <-2%>
* [29:20] SSC_UPCNT 132 (0x084) 132 (0x084)
* [14:0] SSC_dK 6335(0x18bf) 12710(0x31a6)
*/
tmp = readl(sc_base + SC_DPLLCTRL);
tmp &= ~0x3ff07fff;
#ifdef DPLL_SSC_RATE_1PER
tmp |= 0x084018bf;
#else
tmp |= 0x084031a6;
#endif
writel(tmp, sc_base + SC_DPLLCTRL);
/*
* Set DPLL SSC parameters for DPLLCTRL2
* [31:29] SSC_STEP 0
* [27] SSC_REG_REF 1
* [26:20] SSC_M 79 (0x4f)
* [19:0] SSC_K 964689 (0xeb851)
*/
tmp = readl(sc_base + SC_DPLLCTRL2);
tmp &= ~0xefffffff;
tmp |= 0x0cfeb851;
writel(tmp, sc_base + SC_DPLLCTRL2);
/* Wait 500 usec until dpll gets stable */
udelay(500);
return 0;
}
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2011-2014 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <linux/io.h>
#include "../sc-regs.h"
#include "pll.h"
void uniphier_ld4_dpll_ssc_en(void)
{
u32 tmp;
tmp = readl(sc_base + SC_DPLLCTRL);
tmp |= SC_DPLLCTRL_SSC_EN;
writel(tmp, sc_base + SC_DPLLCTRL);
}
@@ -0,0 +1,118 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/sizes.h>
#include "../sc64-regs.h"
#include "pll.h"
/* PLL type: SSC */
#define SC_PLLCTRL_SSC_DK_MASK GENMASK(14, 0)
#define SC_PLLCTRL_SSC_EN BIT(31)
#define SC_PLLCTRL2_NRSTDS BIT(28)
#define SC_PLLCTRL2_SSC_JK_MASK GENMASK(26, 0)
#define SC_PLLCTRL3_REGI_MASK GENMASK(19, 16)
/* PLL type: VPLL27 */
#define SC_VPLL27CTRL_WP BIT(0)
#define SC_VPLL27CTRL3_K_LD BIT(28)
/* PLL type: DSPLL */
#define SC_DSPLLCTRL2_K_LD BIT(28)
int uniphier_ld20_sscpll_init(unsigned long reg_base, unsigned int freq,
unsigned int ssc_rate, unsigned int divn)
{
void __iomem *base = sc_base + reg_base;
u32 tmp;
if (freq != UNIPHIER_PLL_FREQ_DEFAULT) {
tmp = readl(base); /* SSCPLLCTRL */
tmp &= ~SC_PLLCTRL_SSC_DK_MASK;
tmp |= FIELD_PREP(SC_PLLCTRL_SSC_DK_MASK,
DIV_ROUND_CLOSEST(487UL * freq * ssc_rate,
divn * 512));
writel(tmp, base);
tmp = readl(base + 4);
tmp &= ~SC_PLLCTRL2_SSC_JK_MASK;
tmp |= FIELD_PREP(SC_PLLCTRL2_SSC_JK_MASK,
DIV_ROUND_CLOSEST(21431887UL * freq,
divn * 512));
writel(tmp, base + 4);
udelay(50);
}
tmp = readl(base + 4); /* SSCPLLCTRL2 */
tmp |= SC_PLLCTRL2_NRSTDS;
writel(tmp, base + 4);
return 0;
}
int uniphier_ld20_sscpll_ssc_en(unsigned long reg_base)
{
void __iomem *base = sc_base + reg_base;
u32 tmp;
tmp = readl(base); /* SSCPLLCTRL */
tmp |= SC_PLLCTRL_SSC_EN;
writel(tmp, base);
return 0;
}
int uniphier_ld20_sscpll_set_regi(unsigned long reg_base, unsigned regi)
{
void __iomem *base = sc_base + reg_base;
u32 tmp;
tmp = readl(base + 8); /* SSCPLLCTRL3 */
tmp &= ~SC_PLLCTRL3_REGI_MASK;
tmp |= FIELD_PREP(SC_PLLCTRL3_REGI_MASK, regi);
writel(tmp, base + 8);
return 0;
}
int uniphier_ld20_vpll27_init(unsigned long reg_base)
{
void __iomem *base = sc_base + reg_base;
u32 tmp;
tmp = readl(base); /* VPLL27CTRL */
tmp |= SC_VPLL27CTRL_WP; /* write protect off */
writel(tmp, base);
tmp = readl(base + 8); /* VPLL27CTRL3 */
tmp |= SC_VPLL27CTRL3_K_LD;
writel(tmp, base + 8);
tmp = readl(base); /* VPLL27CTRL */
tmp &= ~SC_VPLL27CTRL_WP; /* write protect on */
writel(tmp, base);
return 0;
}
int uniphier_ld20_dspll_init(unsigned long reg_base)
{
void __iomem *base = sc_base + reg_base;
u32 tmp;
tmp = readl(base + 4); /* DSPLLCTRL2 */
tmp |= SC_DSPLLCTRL2_K_LD;
writel(tmp, base + 4);
return 0;
}
@@ -0,0 +1,45 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Socionext Inc.
*/
#include <linux/delay.h>
#include <linux/io.h>
#include "../init.h"
#include "../sc64-regs.h"
#include "pll.h"
/* PLL type: SSC */
#define SC_CPLLCTRL 0x1400 /* CPU/ARM */
#define SC_SPLLCTRL 0x1410 /* misc */
#define SC_MPLLCTRL 0x1430 /* DSP */
#define SC_VSPLLCTRL 0x1440 /* Video codec, VPE etc. */
#define SC_DPLLCTRL 0x1460 /* DDR memory */
/* PLL type: VPLL27 */
#define SC_VPLL27FCTRL 0x1500
#define SC_VPLL27ACTRL 0x1520
void uniphier_ld11_pll_init(void)
{
uniphier_ld20_sscpll_init(SC_CPLLCTRL, 1960, 1, 2); /* 2000MHz -> 1960MHz */
/* do nothing for SPLL */
uniphier_ld20_sscpll_init(SC_MPLLCTRL, 1600, 1, 2); /* 1500MHz -> 1600MHz */
uniphier_ld20_sscpll_init(SC_VSPLLCTRL, UNIPHIER_PLL_FREQ_DEFAULT, 0, 2);
uniphier_ld20_sscpll_set_regi(SC_MPLLCTRL, 5);
mdelay(1);
uniphier_ld20_sscpll_ssc_en(SC_CPLLCTRL);
uniphier_ld20_sscpll_ssc_en(SC_MPLLCTRL);
uniphier_ld20_sscpll_ssc_en(SC_VSPLLCTRL);
uniphier_ld20_sscpll_ssc_en(SC_DPLLCTRL);
uniphier_ld20_vpll27_init(SC_VPLL27FCTRL);
uniphier_ld20_vpll27_init(SC_VPLL27ACTRL);
writel(0, sc_base + SC_CA53_GEARSET); /* Gear0: CPLL/2 */
writel(SC_CA_GEARUPD, sc_base + SC_CA53_GEARUPD);
}
@@ -0,0 +1,57 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <linux/delay.h>
#include "../init.h"
#include "../sc64-regs.h"
#include "pll.h"
/* PLL type: SSC */
#define SC_CPLLCTRL 0x1400 /* CPU/ARM */
#define SC_SPLLCTRL 0x1410 /* misc */
#define SC_SPLL2CTRL 0x1420 /* DSP */
#define SC_MPLLCTRL 0x1430 /* Video codec */
#define SC_VPPLLCTRL 0x1440 /* VPE etc. */
#define SC_GPPLLCTRL 0x1450 /* GPU/Mali */
#define SC_DPLL0CTRL 0x1460 /* DDR memory 0 */
#define SC_DPLL1CTRL 0x1470 /* DDR memory 1 */
#define SC_DPLL2CTRL 0x1480 /* DDR memory 2 */
/* PLL type: VPLL27 */
#define SC_VPLL27FCTRL 0x1500
#define SC_VPLL27ACTRL 0x1520
/* PLL type: DSPLL */
#define SC_VPLL8KCTRL 0x1540
#define SC_A2PLLCTRL 0x15C0
void uniphier_ld20_pll_init(void)
{
uniphier_ld20_sscpll_init(SC_CPLLCTRL, UNIPHIER_PLL_FREQ_DEFAULT, 0, 4);
/* do nothing for SPLL */
uniphier_ld20_sscpll_init(SC_SPLL2CTRL, UNIPHIER_PLL_FREQ_DEFAULT, 0, 4);
uniphier_ld20_sscpll_init(SC_MPLLCTRL, UNIPHIER_PLL_FREQ_DEFAULT, 0, 2);
uniphier_ld20_sscpll_init(SC_VPPLLCTRL, UNIPHIER_PLL_FREQ_DEFAULT, 0, 4);
uniphier_ld20_sscpll_init(SC_GPPLLCTRL, UNIPHIER_PLL_FREQ_DEFAULT, 0, 2);
mdelay(1);
uniphier_ld20_sscpll_ssc_en(SC_CPLLCTRL);
uniphier_ld20_sscpll_ssc_en(SC_SPLL2CTRL);
uniphier_ld20_sscpll_ssc_en(SC_MPLLCTRL);
uniphier_ld20_sscpll_ssc_en(SC_VPPLLCTRL);
uniphier_ld20_sscpll_ssc_en(SC_GPPLLCTRL);
uniphier_ld20_sscpll_ssc_en(SC_DPLL0CTRL);
uniphier_ld20_sscpll_ssc_en(SC_DPLL1CTRL);
uniphier_ld20_sscpll_ssc_en(SC_DPLL2CTRL);
uniphier_ld20_vpll27_init(SC_VPLL27FCTRL);
uniphier_ld20_vpll27_init(SC_VPLL27ACTRL);
uniphier_ld20_dspll_init(SC_VPLL8KCTRL);
uniphier_ld20_dspll_init(SC_A2PLLCTRL);
}
@@ -0,0 +1,152 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2013-2014 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
*/
#include <linux/delay.h>
#include <linux/io.h>
#include "../init.h"
#include "../sc-regs.h"
#include "../sg-regs.h"
#include "pll.h"
static void upll_init(void)
{
u32 tmp, clk_mode_upll, clk_mode_axosel;
tmp = readl(sg_base + SG_PINMON0);
clk_mode_upll = tmp & SG_PINMON0_CLK_MODE_UPLLSRC_MASK;
clk_mode_axosel = tmp & SG_PINMON0_CLK_MODE_AXOSEL_MASK;
/* set 0 to SNRT(UPLLCTRL.bit28) and K_LD(UPLLCTRL.bit[27]) */
tmp = readl(sc_base + SC_UPLLCTRL);
tmp &= ~0x18000000;
writel(tmp, sc_base + SC_UPLLCTRL);
if (clk_mode_upll == SG_PINMON0_CLK_MODE_UPLLSRC_DEFAULT) {
if (clk_mode_axosel == SG_PINMON0_CLK_MODE_AXOSEL_25000KHZ_U ||
clk_mode_axosel == SG_PINMON0_CLK_MODE_AXOSEL_25000KHZ_A) {
/* AXO: 25MHz */
tmp &= ~0x07ffffff;
tmp |= 0x0228f5c0;
} else {
/* AXO: default 24.576MHz */
tmp &= ~0x07ffffff;
tmp |= 0x02328000;
}
}
writel(tmp, sc_base + SC_UPLLCTRL);
/* set 1 to K_LD(UPLLCTRL.bit[27]) */
tmp |= 0x08000000;
writel(tmp, sc_base + SC_UPLLCTRL);
/* wait 10 usec */
udelay(10);
/* set 1 to SNRT(UPLLCTRL.bit[28]) */
tmp |= 0x10000000;
writel(tmp, sc_base + SC_UPLLCTRL);
}
static void vpll_init(void)
{
u32 tmp, clk_mode_axosel;
tmp = readl(sg_base + SG_PINMON0);
clk_mode_axosel = tmp & SG_PINMON0_CLK_MODE_AXOSEL_MASK;
/* set 1 to VPLA27WP and VPLA27WP */
tmp = readl(sc_base + SC_VPLL27ACTRL);
tmp |= 0x00000001;
writel(tmp, sc_base + SC_VPLL27ACTRL);
tmp = readl(sc_base + SC_VPLL27BCTRL);
tmp |= 0x00000001;
writel(tmp, sc_base + SC_VPLL27BCTRL);
/* Set 0 to VPLA_K_LD and VPLB_K_LD */
tmp = readl(sc_base + SC_VPLL27ACTRL3);
tmp &= ~0x10000000;
writel(tmp, sc_base + SC_VPLL27ACTRL3);
tmp = readl(sc_base + SC_VPLL27BCTRL3);
tmp &= ~0x10000000;
writel(tmp, sc_base + SC_VPLL27BCTRL3);
/* Set 0 to VPLA_SNRST and VPLB_SNRST */
tmp = readl(sc_base + SC_VPLL27ACTRL2);
tmp &= ~0x10000000;
writel(tmp, sc_base + SC_VPLL27ACTRL2);
tmp = readl(sc_base + SC_VPLL27BCTRL2);
tmp &= ~0x10000000;
writel(tmp, sc_base + SC_VPLL27BCTRL2);
/* Set 0x20 to VPLA_SNRST and VPLB_SNRST */
tmp = readl(sc_base + SC_VPLL27ACTRL2);
tmp &= ~0x0000007f;
tmp |= 0x00000020;
writel(tmp, sc_base + SC_VPLL27ACTRL2);
tmp = readl(sc_base + SC_VPLL27BCTRL2);
tmp &= ~0x0000007f;
tmp |= 0x00000020;
writel(tmp, sc_base + SC_VPLL27BCTRL2);
if (clk_mode_axosel == SG_PINMON0_CLK_MODE_AXOSEL_25000KHZ_U ||
clk_mode_axosel == SG_PINMON0_CLK_MODE_AXOSEL_25000KHZ_A) {
/* AXO: 25MHz */
tmp = readl(sc_base + SC_VPLL27ACTRL3);
tmp &= ~0x000fffff;
tmp |= 0x00066664;
writel(tmp, sc_base + SC_VPLL27ACTRL3);
tmp = readl(sc_base + SC_VPLL27BCTRL3);
tmp &= ~0x000fffff;
tmp |= 0x00066664;
writel(tmp, sc_base + SC_VPLL27BCTRL3);
} else {
/* AXO: default 24.576MHz */
tmp = readl(sc_base + SC_VPLL27ACTRL3);
tmp &= ~0x000fffff;
tmp |= 0x000f5800;
writel(tmp, sc_base + SC_VPLL27ACTRL3);
tmp = readl(sc_base + SC_VPLL27BCTRL3);
tmp &= ~0x000fffff;
tmp |= 0x000f5800;
writel(tmp, sc_base + SC_VPLL27BCTRL3);
}
/* Set 1 to VPLA_K_LD and VPLB_K_LD */
tmp = readl(sc_base + SC_VPLL27ACTRL3);
tmp |= 0x10000000;
writel(tmp, sc_base + SC_VPLL27ACTRL3);
tmp = readl(sc_base + SC_VPLL27BCTRL3);
tmp |= 0x10000000;
writel(tmp, sc_base + SC_VPLL27BCTRL3);
/* wait 10 usec */
udelay(10);
/* Set 0 to VPLA_SNRST and VPLB_SNRST */
tmp = readl(sc_base + SC_VPLL27ACTRL2);
tmp |= 0x10000000;
writel(tmp, sc_base + SC_VPLL27ACTRL2);
tmp = readl(sc_base + SC_VPLL27BCTRL2);
tmp |= 0x10000000;
writel(tmp, sc_base + SC_VPLL27BCTRL2);
/* set 0 to VPLA27WP and VPLA27WP */
tmp = readl(sc_base + SC_VPLL27ACTRL);
tmp &= ~0x00000001;
writel(tmp, sc_base + SC_VPLL27ACTRL);
tmp = readl(sc_base + SC_VPLL27BCTRL);
tmp |= ~0x00000001;
writel(tmp, sc_base + SC_VPLL27BCTRL);
}
void uniphier_ld4_pll_init(void)
{
upll_init();
vpll_init();
uniphier_ld4_dpll_ssc_en();
}
@@ -0,0 +1,109 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2013-2014 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
*/
#include <linux/delay.h>
#include <linux/io.h>
#include "../init.h"
#include "../sc-regs.h"
#include "../sg-regs.h"
#include "pll.h"
static void vpll_init(void)
{
u32 tmp, clk_mode_axosel;
/* Set VPLL27A & VPLL27B */
tmp = readl(sg_base + SG_PINMON0);
clk_mode_axosel = tmp & SG_PINMON0_CLK_MODE_AXOSEL_MASK;
/* 25MHz or 6.25MHz is default for Pro4R, no need to set VPLLA/B */
if (clk_mode_axosel == SG_PINMON0_CLK_MODE_AXOSEL_25000KHZ ||
clk_mode_axosel == SG_PINMON0_CLK_MODE_AXOSEL_6250KHZ)
return;
/* Disable write protect of VPLL27ACTRL[2-7]*, VPLL27BCTRL[2-8] */
tmp = readl(sc_base + SC_VPLL27ACTRL);
tmp |= 0x00000001;
writel(tmp, sc_base + SC_VPLL27ACTRL);
tmp = readl(sc_base + SC_VPLL27BCTRL);
tmp |= 0x00000001;
writel(tmp, sc_base + SC_VPLL27BCTRL);
/* Unset VPLA_K_LD and VPLB_K_LD bit */
tmp = readl(sc_base + SC_VPLL27ACTRL3);
tmp &= ~0x10000000;
writel(tmp, sc_base + SC_VPLL27ACTRL3);
tmp = readl(sc_base + SC_VPLL27BCTRL3);
tmp &= ~0x10000000;
writel(tmp, sc_base + SC_VPLL27BCTRL3);
/* Set VPLA_M and VPLB_M to 0x20 */
tmp = readl(sc_base + SC_VPLL27ACTRL2);
tmp &= ~0x0000007f;
tmp |= 0x00000020;
writel(tmp, sc_base + SC_VPLL27ACTRL2);
tmp = readl(sc_base + SC_VPLL27BCTRL2);
tmp &= ~0x0000007f;
tmp |= 0x00000020;
writel(tmp, sc_base + SC_VPLL27BCTRL2);
if (clk_mode_axosel == SG_PINMON0_CLK_MODE_AXOSEL_25000KHZ ||
clk_mode_axosel == SG_PINMON0_CLK_MODE_AXOSEL_6250KHZ) {
/* Set VPLA_K and VPLB_K for AXO: 25MHz */
tmp = readl(sc_base + SC_VPLL27ACTRL3);
tmp &= ~0x000fffff;
tmp |= 0x00066666;
writel(tmp, sc_base + SC_VPLL27ACTRL3);
tmp = readl(sc_base + SC_VPLL27BCTRL3);
tmp &= ~0x000fffff;
tmp |= 0x00066666;
writel(tmp, sc_base + SC_VPLL27BCTRL3);
} else {
/* Set VPLA_K and VPLB_K for AXO: 24.576 MHz */
tmp = readl(sc_base + SC_VPLL27ACTRL3);
tmp &= ~0x000fffff;
tmp |= 0x000f5800;
writel(tmp, sc_base + SC_VPLL27ACTRL3);
tmp = readl(sc_base + SC_VPLL27BCTRL3);
tmp &= ~0x000fffff;
tmp |= 0x000f5800;
writel(tmp, sc_base + SC_VPLL27BCTRL3);
}
/* wait 1 usec */
udelay(1);
/* Set VPLA_K_LD and VPLB_K_LD to load K parameters */
tmp = readl(sc_base + SC_VPLL27ACTRL3);
tmp |= 0x10000000;
writel(tmp, sc_base + SC_VPLL27ACTRL3);
tmp = readl(sc_base + SC_VPLL27BCTRL3);
tmp |= 0x10000000;
writel(tmp, sc_base + SC_VPLL27BCTRL3);
/* Unset VPLA_SNRST and VPLB_SNRST bit */
tmp = readl(sc_base + SC_VPLL27ACTRL2);
tmp |= 0x10000000;
writel(tmp, sc_base + SC_VPLL27ACTRL2);
tmp = readl(sc_base + SC_VPLL27BCTRL2);
tmp |= 0x10000000;
writel(tmp, sc_base + SC_VPLL27BCTRL2);
/* Enable write protect of VPLL27ACTRL[2-7]*, VPLL27BCTRL[2-8] */
tmp = readl(sc_base + SC_VPLL27ACTRL);
tmp &= ~0x00000001;
writel(tmp, sc_base + SC_VPLL27ACTRL);
tmp = readl(sc_base + SC_VPLL27BCTRL);
tmp &= ~0x00000001;
writel(tmp, sc_base + SC_VPLL27BCTRL);
}
void uniphier_pro4_pll_init(void)
{
vpll_init();
uniphier_ld4_dpll_ssc_en();
}
@@ -0,0 +1,63 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2017 Socionext Inc.
*/
#include <linux/delay.h>
#include "../init.h"
#include "../sc64-regs.h"
#include "pll.h"
/* PLL type: SSC */
#define SC_CPLLCTRL 0x1400 /* CPU/ARM */
#define SC_SPLLCTRL 0x1410 /* misc */
#define SC_SPLL2CTRL 0x1420 /* DSP */
#define SC_VPPLLCTRL 0x1430 /* VPE */
#define SC_VGPLLCTRL 0x1440
#define SC_DECPLLCTRL 0x1450
#define SC_ENCPLLCTRL 0x1460
#define SC_PXFPLLCTRL 0x1470
#define SC_DPLL0CTRL 0x1480 /* DDR memory 0 */
#define SC_DPLL1CTRL 0x1490 /* DDR memory 1 */
#define SC_DPLL2CTRL 0x14a0 /* DDR memory 2 */
#define SC_VSPLLCTRL 0x14c0
/* PLL type: VPLL27 */
#define SC_VPLL27FCTRL 0x1500
#define SC_VPLL27ACTRL 0x1520
/* PLL type: DSPLL */
#define SC_VPLL8KCTRL 0x1540
void uniphier_pxs3_pll_init(void)
{
uniphier_ld20_sscpll_init(SC_CPLLCTRL, UNIPHIER_PLL_FREQ_DEFAULT, 0, 4);
/* do nothing for SPLL */
uniphier_ld20_sscpll_init(SC_SPLL2CTRL, UNIPHIER_PLL_FREQ_DEFAULT, 0, 4);
uniphier_ld20_sscpll_init(SC_VPPLLCTRL, UNIPHIER_PLL_FREQ_DEFAULT, 0, 2);
uniphier_ld20_sscpll_init(SC_VGPLLCTRL, UNIPHIER_PLL_FREQ_DEFAULT, 0, 2);
uniphier_ld20_sscpll_init(SC_DECPLLCTRL, UNIPHIER_PLL_FREQ_DEFAULT, 0, 2);
uniphier_ld20_sscpll_init(SC_ENCPLLCTRL, UNIPHIER_PLL_FREQ_DEFAULT, 0, 4);
uniphier_ld20_sscpll_init(SC_PXFPLLCTRL, UNIPHIER_PLL_FREQ_DEFAULT, 0, 2);
uniphier_ld20_sscpll_init(SC_VSPLLCTRL, UNIPHIER_PLL_FREQ_DEFAULT, 0, 2);
mdelay(1);
uniphier_ld20_sscpll_ssc_en(SC_CPLLCTRL);
uniphier_ld20_sscpll_ssc_en(SC_SPLL2CTRL);
uniphier_ld20_sscpll_ssc_en(SC_VPPLLCTRL);
uniphier_ld20_sscpll_ssc_en(SC_VGPLLCTRL);
uniphier_ld20_sscpll_ssc_en(SC_DECPLLCTRL);
uniphier_ld20_sscpll_ssc_en(SC_ENCPLLCTRL);
uniphier_ld20_sscpll_ssc_en(SC_PXFPLLCTRL);
uniphier_ld20_sscpll_ssc_en(SC_DPLL0CTRL);
uniphier_ld20_sscpll_ssc_en(SC_DPLL1CTRL);
uniphier_ld20_sscpll_ssc_en(SC_DPLL2CTRL);
uniphier_ld20_sscpll_ssc_en(SC_VSPLLCTRL);
uniphier_ld20_vpll27_init(SC_VPLL27FCTRL);
uniphier_ld20_vpll27_init(SC_VPLL27ACTRL);
uniphier_ld20_dspll_init(SC_VPLL8KCTRL);
}
@@ -0,0 +1,21 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#ifndef MACH_PLL_H
#define MACH_PLL_H
#define UNIPHIER_PLL_FREQ_DEFAULT (0)
void uniphier_ld4_dpll_ssc_en(void);
int uniphier_ld20_sscpll_init(unsigned long reg_base, unsigned int freq,
unsigned int ssc_rate, unsigned int divn);
int uniphier_ld20_sscpll_ssc_en(unsigned long reg_base);
int uniphier_ld20_sscpll_set_regi(unsigned long reg_base, unsigned regi);
int uniphier_ld20_vpll27_init(unsigned long reg_base);
int uniphier_ld20_dspll_init(unsigned long reg_base);
#endif /* MACH_PLL_H */
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2013-2014 Panasonic Corporation
* Copyright (C) 2015-2017 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <stdio.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/printk.h>
#include "base-address.h"
#include "soc-info.h"
int print_cpuinfo(void)
{
unsigned int id, model, rev, required_model = 1, required_rev = 1;
int ret;
ret = uniphier_base_address_init();
if (ret)
return ret;
id = uniphier_get_soc_id();
model = uniphier_get_soc_model();
rev = uniphier_get_soc_revision();
puts("SoC: ");
switch (id) {
case UNIPHIER_LD4_ID:
puts("LD4");
required_rev = 2;
break;
case UNIPHIER_PRO4_ID:
puts("Pro4");
break;
case UNIPHIER_SLD8_ID:
puts("sLD8");
break;
case UNIPHIER_PRO5_ID:
puts("Pro5");
break;
case UNIPHIER_PXS2_ID:
puts("PXs2");
break;
case UNIPHIER_LD6B_ID:
puts("LD6b");
break;
case UNIPHIER_LD11_ID:
puts("LD11");
break;
case UNIPHIER_LD20_ID:
puts("LD20");
break;
case UNIPHIER_PXS3_ID:
puts("PXs3");
break;
default:
printf("Unknown Processor ID (0x%x)\n", id);
return -ENOTSUPP;
}
printf(" (model %d, revision %d)\n", model, rev);
if (model < required_model) {
pr_err("Only model %d or newer is supported.\n",
required_model);
return -ENOTSUPP;
} else if (rev < required_rev) {
pr_err("Only revision %d or newer is supported.\n",
required_rev);
return -ENOTSUPP;
}
return 0;
}
@@ -0,0 +1,12 @@
# SPDX-License-Identifier: GPL-2.0+
ifdef CONFIG_SPL_BUILD
obj-$(CONFIG_ARCH_UNIPHIER_LD4) += debug-uart-ld4.o
obj-$(CONFIG_ARCH_UNIPHIER_PRO4) += debug-uart-pro4.o
obj-$(CONFIG_ARCH_UNIPHIER_SLD8) += debug-uart-sld8.o
obj-$(CONFIG_ARCH_UNIPHIER_PRO5) += debug-uart-pro5.o
obj-$(CONFIG_ARCH_UNIPHIER_PXS2) += debug-uart-pxs2.o
obj-$(CONFIG_ARCH_UNIPHIER_LD6B) += debug-uart-ld6b.o
endif
obj-y += debug-uart.o
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <config.h>
#include <linux/kernel.h>
#include "../sg-regs.h"
#include "debug-uart.h"
#define UNIPHIER_LD4_UART_CLK 36864000
unsigned int uniphier_ld4_debug_uart_init(void)
{
sg_set_iectrl(0);
sg_set_pinsel(88, 1, 8, 4); /* HSDOUT6 -> TXD0 */
return DIV_ROUND_CLOSEST(UNIPHIER_LD4_UART_CLK, 16 * CONFIG_BAUDRATE);
}
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <config.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include "../sc-regs.h"
#include "../sg-regs.h"
#include "debug-uart.h"
#define UNIPHIER_LD6B_UART_CLK 88888888
unsigned int uniphier_ld6b_debug_uart_init(void)
{
u32 tmp;
sg_set_iectrl(0);
sg_set_pinsel(135, 3, 8, 4); /* PORT10 -> TXD0 */
sg_set_pinsel(115, 0, 8, 4); /* TXD1 -> TXD1 */
sg_set_pinsel(113, 2, 8, 4); /* SBO0 -> TXD2 */
tmp = readl(sc_base + SC_CLKCTRL);
tmp |= SC_CLKCTRL_CEN_PERI;
writel(tmp, sc_base + SC_CLKCTRL);
return DIV_ROUND_CLOSEST(UNIPHIER_LD6B_UART_CLK, 16 * CONFIG_BAUDRATE);
}
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <config.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include "../sc-regs.h"
#include "../sg-regs.h"
#include "debug-uart.h"
#define UNIPHIER_PRO4_UART_CLK 73728000
unsigned int uniphier_pro4_debug_uart_init(void)
{
u32 tmp;
sg_set_iectrl(0);
sg_set_pinsel(128, 0, 4, 8); /* TXD0 -> TXD0 */
writel(1, sg_base + SG_LOADPINCTRL);
tmp = readl(sc_base + SC_CLKCTRL);
tmp |= SC_CLKCTRL_CEN_PERI;
writel(tmp, sc_base + SC_CLKCTRL);
return DIV_ROUND_CLOSEST(UNIPHIER_PRO4_UART_CLK, 16 * CONFIG_BAUDRATE);
}
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <config.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include "../sc-regs.h"
#include "../sg-regs.h"
#include "debug-uart.h"
#define UNIPHIER_PRO5_UART_CLK 73728000
unsigned int uniphier_pro5_debug_uart_init(void)
{
u32 tmp;
sg_set_iectrl(0);
sg_set_pinsel(47, 0, 4, 8); /* TXD0 -> TXD0 */
sg_set_pinsel(49, 0, 4, 8); /* TXD1 -> TXD1 */
sg_set_pinsel(51, 0, 4, 8); /* TXD2 -> TXD2 */
sg_set_pinsel(53, 0, 4, 8); /* TXD3 -> TXD3 */
writel(1, sg_base + SG_LOADPINCTRL);
tmp = readl(sc_base + SC_CLKCTRL);
tmp |= SC_CLKCTRL_CEN_PERI;
writel(tmp, sc_base + SC_CLKCTRL);
return DIV_ROUND_CLOSEST(UNIPHIER_PRO5_UART_CLK, 16 * CONFIG_BAUDRATE);
}
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <config.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include "../sc-regs.h"
#include "../sg-regs.h"
#include "debug-uart.h"
#define UNIPHIER_PXS2_UART_CLK 88888888
unsigned int uniphier_pxs2_debug_uart_init(void)
{
u32 tmp;
sg_set_iectrl(0);
sg_set_pinsel(217, 8, 8, 4); /* TXD0 -> TXD0 */
sg_set_pinsel(115, 8, 8, 4); /* TXD1 -> TXD1 */
sg_set_pinsel(113, 8, 8, 4); /* TXD2 -> TXD2 */
sg_set_pinsel(219, 8, 8, 4); /* TXD3 -> TXD3 */
tmp = readl(sc_base + SC_CLKCTRL);
tmp |= SC_CLKCTRL_CEN_PERI;
writel(tmp, sc_base + SC_CLKCTRL);
return DIV_ROUND_CLOSEST(UNIPHIER_PXS2_UART_CLK, 16 * CONFIG_BAUDRATE);
}
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <config.h>
#include <linux/kernel.h>
#include "../sg-regs.h"
#include "debug-uart.h"
#define UNIPHIER_SLD8_UART_CLK 80000000
unsigned int uniphier_sld8_debug_uart_init(void)
{
sg_set_iectrl(0);
sg_set_pinsel(70, 3, 8, 4); /* HSDOUT6 -> TXD0 */
return DIV_ROUND_CLOSEST(UNIPHIER_SLD8_UART_CLK, 16 * CONFIG_BAUDRATE);
}
@@ -0,0 +1,104 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <debug_uart.h>
#include <linux/io.h>
#include <linux/serial_reg.h>
#include "../sg-regs.h"
#include "../soc-info.h"
#include "debug-uart.h"
#define UNIPHIER_UART_TX 0x00
#define UNIPHIER_UART_LCR_MCR 0x10
#define UNIPHIER_UART_LSR 0x14
#define UNIPHIER_UART_LDR 0x24
static void _debug_uart_putc(int c)
{
void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
while (!(readl(base + UNIPHIER_UART_LSR) & UART_LSR_THRE))
;
writel(c, base + UNIPHIER_UART_TX);
}
#ifdef CONFIG_SPL_BUILD
void sg_set_pinsel(unsigned int pin, unsigned int muxval,
unsigned int mux_bits, unsigned int reg_stride)
{
unsigned int shift = pin * mux_bits % 32;
void __iomem *reg = sg_base + SG_PINCTRL_BASE +
pin * mux_bits / 32 * reg_stride;
u32 mask = (1U << mux_bits) - 1;
u32 tmp;
tmp = readl(reg);
tmp &= ~(mask << shift);
tmp |= (mask & muxval) << shift;
writel(tmp, reg);
}
void sg_set_iectrl(unsigned int pin)
{
unsigned int bit = pin % 32;
void __iomem *reg = sg_base + SG_IECTRL + pin / 32 * 4;
u32 tmp;
tmp = readl(reg);
tmp |= 1 << bit;
writel(tmp, reg);
}
#endif
void _debug_uart_init(void)
{
#ifdef CONFIG_SPL_BUILD
void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
unsigned int divisor;
switch (uniphier_get_soc_id()) {
#if defined(CONFIG_ARCH_UNIPHIER_LD4)
case UNIPHIER_LD4_ID:
divisor = uniphier_ld4_debug_uart_init();
break;
#endif
#if defined(CONFIG_ARCH_UNIPHIER_PRO4)
case UNIPHIER_PRO4_ID:
divisor = uniphier_pro4_debug_uart_init();
break;
#endif
#if defined(CONFIG_ARCH_UNIPHIER_SLD8)
case UNIPHIER_SLD8_ID:
divisor = uniphier_sld8_debug_uart_init();
break;
#endif
#if defined(CONFIG_ARCH_UNIPHIER_PRO5)
case UNIPHIER_PRO5_ID:
divisor = uniphier_pro5_debug_uart_init();
break;
#endif
#if defined(CONFIG_ARCH_UNIPHIER_PXS2)
case UNIPHIER_PXS2_ID:
divisor = uniphier_pxs2_debug_uart_init();
break;
#endif
#if defined(CONFIG_ARCH_UNIPHIER_LD6B)
case UNIPHIER_LD6B_ID:
divisor = uniphier_ld6b_debug_uart_init();
break;
#endif
default:
return;
}
writel(UART_LCR_WLEN8 << 8, base + UNIPHIER_UART_LCR_MCR);
writel(divisor, base + UNIPHIER_UART_LDR);
#endif
}
DEBUG_UART_FUNCS
@@ -0,0 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2016 Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#ifndef _MACH_DEBUG_UART_H
#define _MACH_DEBUG_UART_H
unsigned int uniphier_ld4_debug_uart_init(void);
unsigned int uniphier_pro4_debug_uart_init(void);
unsigned int uniphier_sld8_debug_uart_init(void);
unsigned int uniphier_pro5_debug_uart_init(void);
unsigned int uniphier_pxs2_debug_uart_init(void);
unsigned int uniphier_ld6b_debug_uart_init(void);
void sg_set_pinsel(unsigned int pin, unsigned int muxval,
unsigned int mux_bits, unsigned int reg_stride);
void sg_set_iectrl(unsigned int pin);
#endif /* _MACH_DEBUG_UART_H */
@@ -0,0 +1,67 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#ifndef __DEBUG_H__
#define __DEBUG_H__
#include <linux/io.h>
#include <linux/serial_reg.h>
#define DEBUG_UART_BASE 0x54006800
#define UART_SHIFT 2
#define UNIPHIER_UART_TX 0
#define UNIPHIER_UART_LSR (5 * 4)
/* All functions are inline so that they can be called from .secure section. */
#ifdef DEBUG
static inline void debug_putc(int c)
{
void __iomem *base = (void __iomem *)DEBUG_UART_BASE;
while (!(readl(base + UNIPHIER_UART_LSR) & UART_LSR_THRE))
;
writel(c, base + UNIPHIER_UART_TX);
}
static inline void debug_puts(const char *s)
{
while (*s) {
if (*s == '\n')
debug_putc('\r');
debug_putc(*s++);
}
}
static inline void debug_puth(unsigned long val)
{
int i;
unsigned char c;
for (i = 8; i--; ) {
c = ((val >> (i * 4)) & 0xf);
c += (c >= 10) ? 'a' - 10 : '0';
debug_putc(c);
}
}
#else
static inline void debug_putc(int c)
{
}
static inline void debug_puts(const char *s)
{
}
static inline void debug_puth(unsigned long val)
{
}
#endif
#endif /* __DEBUG_H__ */
@@ -0,0 +1,20 @@
# SPDX-License-Identifier: GPL-2.0+
ifdef CONFIG_SPL_BUILD
obj-$(CONFIG_ARCH_UNIPHIER_LD4) += umc-ld4.o \
ddrphy-training.o ddrphy-ld4.o
obj-$(CONFIG_ARCH_UNIPHIER_PRO4) += umc-pro4.o \
ddrphy-training.o ddrphy-ld4.o
obj-$(CONFIG_ARCH_UNIPHIER_SLD8) += umc-sld8.o \
ddrphy-training.o ddrphy-ld4.o
obj-$(CONFIG_ARCH_UNIPHIER_PRO5) += umc-pro5.o
obj-$(CONFIG_ARCH_UNIPHIER_PXS2) += umc-pxs2.o
obj-$(CONFIG_ARCH_UNIPHIER_LD6B) += umc-pxs2.o
else
obj-$(CONFIG_CMD_DDRPHY_DUMP) += cmd_ddrphy.o
obj-$(CONFIG_CMD_DDRMPHY_DUMP) += cmd_ddrmphy.o
endif
@@ -0,0 +1,345 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2015-2017 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <stdio.h>
#include <linux/io.h>
#include <linux/printk.h>
#include <linux/sizes.h>
#include "../soc-info.h"
#include "ddrmphy-regs.h"
/* Select either decimal or hexadecimal */
#if 1
#define PRINTF_FORMAT "%2d"
#else
#define PRINTF_FORMAT "%02x"
#endif
/* field separator */
#define FS " "
#define ptr_to_uint(p) ((unsigned int)(unsigned long)(p))
#define UNIPHIER_MAX_NR_DDRMPHY 3
struct uniphier_ddrmphy_param {
unsigned int soc_id;
unsigned int nr_phy;
struct {
resource_size_t base;
unsigned int nr_zq;
unsigned int nr_dx;
} phy[UNIPHIER_MAX_NR_DDRMPHY];
};
static const struct uniphier_ddrmphy_param uniphier_ddrmphy_param[] = {
{
.soc_id = UNIPHIER_PXS2_ID,
.nr_phy = 3,
.phy = {
{ .base = 0x5b830000, .nr_zq = 3, .nr_dx = 4, },
{ .base = 0x5ba30000, .nr_zq = 3, .nr_dx = 4, },
{ .base = 0x5bc30000, .nr_zq = 2, .nr_dx = 2, },
},
},
{
.soc_id = UNIPHIER_LD6B_ID,
.nr_phy = 3,
.phy = {
{ .base = 0x5b830000, .nr_zq = 3, .nr_dx = 4, },
{ .base = 0x5ba30000, .nr_zq = 3, .nr_dx = 4, },
{ .base = 0x5bc30000, .nr_zq = 2, .nr_dx = 2, },
},
},
};
UNIPHIER_DEFINE_SOCDATA_FUNC(uniphier_get_ddrmphy_param, uniphier_ddrmphy_param)
static void print_bdl(void __iomem *reg, int n)
{
u32 val = readl(reg);
int i;
for (i = 0; i < n; i++)
printf(FS PRINTF_FORMAT, (val >> i * 8) & 0x1f);
}
static void dump_loop(const struct uniphier_ddrmphy_param *param,
void (*callback)(void __iomem *))
{
void __iomem *phy_base, *dx_base;
int phy, dx;
for (phy = 0; phy < param->nr_phy; phy++) {
phy_base = ioremap(param->phy[phy].base, SZ_4K);
dx_base = phy_base + MPHY_DX_BASE;
for (dx = 0; dx < param->phy[phy].nr_dx; dx++) {
printf("PHY%dDX%d:", phy, dx);
(*callback)(dx_base);
dx_base += MPHY_DX_STRIDE;
printf("\n");
}
iounmap(phy_base);
}
}
static void zq_dump(const struct uniphier_ddrmphy_param *param)
{
void __iomem *phy_base, *zq_base;
u32 val;
int phy, zq, i;
printf("\n--- Impedance Data ---\n");
printf(" ZPD ZPU OPD OPU ZDV ODV\n");
for (phy = 0; phy < param->nr_phy; phy++) {
phy_base = ioremap(param->phy[phy].base, SZ_4K);
zq_base = phy_base + MPHY_ZQ_BASE;
for (zq = 0; zq < param->phy[phy].nr_zq; zq++) {
printf("PHY%dZQ%d:", phy, zq);
val = readl(zq_base + MPHY_ZQ_DR);
for (i = 0; i < 4; i++) {
printf(FS PRINTF_FORMAT, val & 0x7f);
val >>= 7;
}
val = readl(zq_base + MPHY_ZQ_PR);
for (i = 0; i < 2; i++) {
printf(FS PRINTF_FORMAT, val & 0xf);
val >>= 4;
}
zq_base += MPHY_ZQ_STRIDE;
printf("\n");
}
iounmap(phy_base);
}
}
static void __wbdl_dump(void __iomem *dx_base)
{
print_bdl(dx_base + MPHY_DX_BDLR0, 4);
print_bdl(dx_base + MPHY_DX_BDLR1, 4);
print_bdl(dx_base + MPHY_DX_BDLR2, 2);
printf(FS "(+" PRINTF_FORMAT ")",
readl(dx_base + MPHY_DX_LCDLR1) & 0xff);
}
static void wbdl_dump(const struct uniphier_ddrmphy_param *param)
{
printf("\n--- Write Bit Delay Line ---\n");
printf(" DQ0 DQ1 DQ2 DQ3 DQ4 DQ5 DQ6 DQ7 DM DQS (WDQD)\n");
dump_loop(param, &__wbdl_dump);
}
static void __rbdl_dump(void __iomem *dx_base)
{
print_bdl(dx_base + MPHY_DX_BDLR3, 4);
print_bdl(dx_base + MPHY_DX_BDLR4, 4);
print_bdl(dx_base + MPHY_DX_BDLR5, 1);
printf(FS "(+" PRINTF_FORMAT ")",
(readl(dx_base + MPHY_DX_LCDLR1) >> 8) & 0xff);
printf(FS "(+" PRINTF_FORMAT ")",
(readl(dx_base + MPHY_DX_LCDLR1) >> 16) & 0xff);
}
static void rbdl_dump(const struct uniphier_ddrmphy_param *param)
{
printf("\n--- Read Bit Delay Line ---\n");
printf(" DQ0 DQ1 DQ2 DQ3 DQ4 DQ5 DQ6 DQ7 DM (RDQSD) (RDQSND)\n");
dump_loop(param, &__rbdl_dump);
}
static void __wld_dump(void __iomem *dx_base)
{
int rank;
u32 lcdlr0 = readl(dx_base + MPHY_DX_LCDLR0);
u32 gtr = readl(dx_base + MPHY_DX_GTR);
for (rank = 0; rank < 4; rank++) {
u32 wld = (lcdlr0 >> (8 * rank)) & 0xff; /* Delay */
u32 wlsl = (gtr >> (12 + 2 * rank)) & 0x3; /* System Latency */
printf(FS PRINTF_FORMAT "%sT", wld,
wlsl == 0 ? "-1" : wlsl == 1 ? "+0" : "+1");
}
}
static void wld_dump(const struct uniphier_ddrmphy_param *param)
{
printf("\n--- Write Leveling Delay ---\n");
printf(" Rank0 Rank1 Rank2 Rank3\n");
dump_loop(param, &__wld_dump);
}
static void __dqsgd_dump(void __iomem *dx_base)
{
int rank;
u32 lcdlr2 = readl(dx_base + MPHY_DX_LCDLR2);
u32 gtr = readl(dx_base + MPHY_DX_GTR);
for (rank = 0; rank < 4; rank++) {
u32 dqsgd = (lcdlr2 >> (8 * rank)) & 0xff; /* Delay */
u32 dgsl = (gtr >> (3 * rank)) & 0x7; /* System Latency */
printf(FS PRINTF_FORMAT "+%dT", dqsgd, dgsl);
}
}
static void dqsgd_dump(const struct uniphier_ddrmphy_param *param)
{
printf("\n--- DQS Gating Delay ---\n");
printf(" Rank0 Rank1 Rank2 Rank3\n");
dump_loop(param, &__dqsgd_dump);
}
static void __mdl_dump(void __iomem *dx_base)
{
int i;
u32 mdl = readl(dx_base + MPHY_DX_MDLR);
for (i = 0; i < 3; i++)
printf(FS PRINTF_FORMAT, (mdl >> (8 * i)) & 0xff);
}
static void mdl_dump(const struct uniphier_ddrmphy_param *param)
{
printf("\n--- Master Delay Line ---\n");
printf(" IPRD TPRD MDLD\n");
dump_loop(param, &__mdl_dump);
}
#define REG_DUMP(x) \
{ int ofst = MPHY_ ## x; void __iomem *reg = phy_base + ofst; \
printf("%3d: %-10s: %p : %08x\n", \
ofst >> MPHY_SHIFT, #x, reg, readl(reg)); }
#define DX_REG_DUMP(dx, x) \
{ int ofst = MPHY_DX_BASE + MPHY_DX_STRIDE * (dx) + \
MPHY_DX_## x; \
void __iomem *reg = phy_base + ofst; \
printf("%3d: DX%d%-7s: %p : %08x\n", \
ofst >> MPHY_SHIFT, (dx), #x, reg, readl(reg)); }
static void reg_dump(const struct uniphier_ddrmphy_param *param)
{
void __iomem *phy_base;
int phy, dx;
printf("\n--- DDR Multi PHY registers ---\n");
for (phy = 0; phy < param->nr_phy; phy++) {
phy_base = ioremap(param->phy[phy].base, SZ_4K);
printf("== PHY%d (base: %08x) ==\n", phy,
ptr_to_uint(phy_base));
printf(" No: Name : Address : Data\n");
REG_DUMP(RIDR);
REG_DUMP(PIR);
REG_DUMP(PGCR0);
REG_DUMP(PGCR1);
REG_DUMP(PGCR2);
REG_DUMP(PGCR3);
REG_DUMP(PGSR0);
REG_DUMP(PGSR1);
REG_DUMP(PLLCR);
REG_DUMP(PTR0);
REG_DUMP(PTR1);
REG_DUMP(PTR2);
REG_DUMP(PTR3);
REG_DUMP(PTR4);
REG_DUMP(ACMDLR);
REG_DUMP(ACBDLR0);
REG_DUMP(DXCCR);
REG_DUMP(DSGCR);
REG_DUMP(DCR);
REG_DUMP(DTPR0);
REG_DUMP(DTPR1);
REG_DUMP(DTPR2);
REG_DUMP(DTPR3);
REG_DUMP(MR0);
REG_DUMP(MR1);
REG_DUMP(MR2);
REG_DUMP(MR3);
for (dx = 0; dx < param->phy[phy].nr_dx; dx++) {
DX_REG_DUMP(dx, GCR0);
DX_REG_DUMP(dx, GCR1);
DX_REG_DUMP(dx, GCR2);
DX_REG_DUMP(dx, GCR3);
DX_REG_DUMP(dx, GTR);
}
iounmap(phy_base);
}
}
static int do_ddrm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
const struct uniphier_ddrmphy_param *param;
char *cmd;
param = uniphier_get_ddrmphy_param();
if (!param) {
pr_err("unsupported SoC\n");
return CMD_RET_FAILURE;
}
if (argc == 1)
cmd = "all";
else
cmd = argv[1];
if (!strcmp(cmd, "zq") || !strcmp(cmd, "all"))
zq_dump(param);
if (!strcmp(cmd, "wbdl") || !strcmp(cmd, "all"))
wbdl_dump(param);
if (!strcmp(cmd, "rbdl") || !strcmp(cmd, "all"))
rbdl_dump(param);
if (!strcmp(cmd, "wld") || !strcmp(cmd, "all"))
wld_dump(param);
if (!strcmp(cmd, "dqsgd") || !strcmp(cmd, "all"))
dqsgd_dump(param);
if (!strcmp(cmd, "mdl") || !strcmp(cmd, "all"))
mdl_dump(param);
if (!strcmp(cmd, "reg") || !strcmp(cmd, "all"))
reg_dump(param);
return CMD_RET_SUCCESS;
}
U_BOOT_CMD(
ddrm, 2, 1, do_ddrm,
"UniPhier DDR Multi PHY parameters dumper",
"- dump all of the following\n"
"ddrm zq - dump Impedance Data\n"
"ddrm wbdl - dump Write Bit Delay\n"
"ddrm rbdl - dump Read Bit Delay\n"
"ddrm wld - dump Write Leveling\n"
"ddrm dqsgd - dump DQS Gating Delay\n"
"ddrm mdl - dump Master Delay Line\n"
"ddrm reg - dump registers\n"
);
@@ -0,0 +1,311 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2014 Panasonic Corporation
* Copyright (C) 2015-2017 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <stdio.h>
#include <linux/io.h>
#include <linux/printk.h>
#include <linux/sizes.h>
#include "../soc-info.h"
#include "ddrphy-regs.h"
/* Select either decimal or hexadecimal */
#if 1
#define PRINTF_FORMAT "%2d"
#else
#define PRINTF_FORMAT "%02x"
#endif
/* field separator */
#define FS " "
#define ptr_to_uint(p) ((unsigned int)(unsigned long)(p))
#define UNIPHIER_MAX_NR_DDRPHY 4
struct uniphier_ddrphy_param {
unsigned int soc_id;
unsigned int nr_phy;
struct {
resource_size_t base;
unsigned int nr_dx;
} phy[UNIPHIER_MAX_NR_DDRPHY];
};
static const struct uniphier_ddrphy_param uniphier_ddrphy_param[] = {
{
.soc_id = UNIPHIER_LD4_ID,
.nr_phy = 2,
.phy = {
{ .base = 0x5bc01000, .nr_dx = 2, },
{ .base = 0x5be01000, .nr_dx = 2, },
},
},
{
.soc_id = UNIPHIER_PRO4_ID,
.nr_phy = 4,
.phy = {
{ .base = 0x5bc01000, .nr_dx = 2, },
{ .base = 0x5bc02000, .nr_dx = 2, },
{ .base = 0x5be01000, .nr_dx = 2, },
{ .base = 0x5be02000, .nr_dx = 2, },
},
},
{
.soc_id = UNIPHIER_SLD8_ID,
.nr_phy = 2,
.phy = {
{ .base = 0x5bc01000, .nr_dx = 2, },
{ .base = 0x5be01000, .nr_dx = 2, },
},
},
{
.soc_id = UNIPHIER_LD11_ID,
.nr_phy = 1,
.phy = {
{ .base = 0x5bc01000, .nr_dx = 4, },
},
},
};
UNIPHIER_DEFINE_SOCDATA_FUNC(uniphier_get_ddrphy_param, uniphier_ddrphy_param)
static void print_bdl(void __iomem *reg, int n)
{
u32 val = readl(reg);
int i;
for (i = 0; i < n; i++)
printf(FS PRINTF_FORMAT, (val >> i * 6) & 0x3f);
}
static void dump_loop(const struct uniphier_ddrphy_param *param,
void (*callback)(void __iomem *))
{
void __iomem *phy_base, *dx_base;
int phy, dx;
for (phy = 0; phy < param->nr_phy; phy++) {
phy_base = ioremap(param->phy[phy].base, SZ_4K);
dx_base = phy_base + PHY_DX_BASE;
for (dx = 0; dx < param->phy[phy].nr_dx; dx++) {
printf("PHY%dDX%d:", phy, dx);
(*callback)(dx_base);
dx_base += PHY_DX_STRIDE;
printf("\n");
}
iounmap(phy_base);
}
}
static void __wbdl_dump(void __iomem *dx_base)
{
print_bdl(dx_base + PHY_DX_BDLR0, 5);
print_bdl(dx_base + PHY_DX_BDLR1, 5);
printf(FS "(+" PRINTF_FORMAT ")",
readl(dx_base + PHY_DX_LCDLR1) & 0xff);
}
static void wbdl_dump(const struct uniphier_ddrphy_param *param)
{
printf("\n--- Write Bit Delay Line ---\n");
printf(" DQ0 DQ1 DQ2 DQ3 DQ4 DQ5 DQ6 DQ7 DM DQS (WDQD)\n");
dump_loop(param, &__wbdl_dump);
}
static void __rbdl_dump(void __iomem *dx_base)
{
print_bdl(dx_base + PHY_DX_BDLR3, 5);
print_bdl(dx_base + PHY_DX_BDLR4, 4);
printf(FS "(+" PRINTF_FORMAT ")",
(readl(dx_base + PHY_DX_LCDLR1) >> 8) & 0xff);
}
static void rbdl_dump(const struct uniphier_ddrphy_param *param)
{
printf("\n--- Read Bit Delay Line ---\n");
printf(" DQ0 DQ1 DQ2 DQ3 DQ4 DQ5 DQ6 DQ7 DM (RDQSD)\n");
dump_loop(param, &__rbdl_dump);
}
static void __wld_dump(void __iomem *dx_base)
{
int rank;
u32 lcdlr0 = readl(dx_base + PHY_DX_LCDLR0);
u32 gtr = readl(dx_base + PHY_DX_GTR);
for (rank = 0; rank < 4; rank++) {
u32 wld = (lcdlr0 >> (8 * rank)) & 0xff; /* Delay */
u32 wlsl = (gtr >> (12 + 2 * rank)) & 0x3; /* System Latency */
printf(FS PRINTF_FORMAT "%sT", wld,
wlsl == 0 ? "-1" : wlsl == 1 ? "+0" : "+1");
}
}
static void wld_dump(const struct uniphier_ddrphy_param *param)
{
printf("\n--- Write Leveling Delay ---\n");
printf(" Rank0 Rank1 Rank2 Rank3\n");
dump_loop(param, &__wld_dump);
}
static void __dqsgd_dump(void __iomem *dx_base)
{
int rank;
u32 lcdlr2 = readl(dx_base + PHY_DX_LCDLR2);
u32 gtr = readl(dx_base + PHY_DX_GTR);
for (rank = 0; rank < 4; rank++) {
u32 dqsgd = (lcdlr2 >> (8 * rank)) & 0xff; /* Delay */
u32 dgsl = (gtr >> (3 * rank)) & 0x7; /* System Latency */
printf(FS PRINTF_FORMAT "+%dT", dqsgd, dgsl);
}
}
static void dqsgd_dump(const struct uniphier_ddrphy_param *param)
{
printf("\n--- DQS Gating Delay ---\n");
printf(" Rank0 Rank1 Rank2 Rank3\n");
dump_loop(param, &__dqsgd_dump);
}
static void __mdl_dump(void __iomem *dx_base)
{
int i;
u32 mdl = readl(dx_base + PHY_DX_MDLR);
for (i = 0; i < 3; i++)
printf(FS PRINTF_FORMAT, (mdl >> (8 * i)) & 0xff);
}
static void mdl_dump(const struct uniphier_ddrphy_param *param)
{
printf("\n--- Master Delay Line ---\n");
printf(" IPRD TPRD MDLD\n");
dump_loop(param, &__mdl_dump);
}
#define REG_DUMP(x) \
{ int ofst = PHY_ ## x; void __iomem *reg = phy_base + ofst; \
printf("%3d: %-10s: %08x : %08x\n", \
ofst >> PHY_REG_SHIFT, #x, \
ptr_to_uint(reg), readl(reg)); }
#define DX_REG_DUMP(dx, x) \
{ int ofst = PHY_DX_BASE + PHY_DX_STRIDE * (dx) + \
PHY_DX_## x; \
void __iomem *reg = phy_base + ofst; \
printf("%3d: DX%d%-7s: %08x : %08x\n", \
ofst >> PHY_REG_SHIFT, (dx), #x, \
ptr_to_uint(reg), readl(reg)); }
static void reg_dump(const struct uniphier_ddrphy_param *param)
{
void __iomem *phy_base;
int phy, dx;
printf("\n--- DDR PHY registers ---\n");
for (phy = 0; phy < param->nr_phy; phy++) {
phy_base = ioremap(param->phy[phy].base, SZ_4K);
printf("== PHY%d (base: %08x) ==\n",
phy, ptr_to_uint(phy_base));
printf(" No: Name : Address : Data\n");
REG_DUMP(RIDR);
REG_DUMP(PIR);
REG_DUMP(PGCR0);
REG_DUMP(PGCR1);
REG_DUMP(PGSR0);
REG_DUMP(PGSR1);
REG_DUMP(PLLCR);
REG_DUMP(PTR0);
REG_DUMP(PTR1);
REG_DUMP(PTR2);
REG_DUMP(PTR3);
REG_DUMP(PTR4);
REG_DUMP(ACMDLR);
REG_DUMP(ACBDLR);
REG_DUMP(DXCCR);
REG_DUMP(DSGCR);
REG_DUMP(DCR);
REG_DUMP(DTPR0);
REG_DUMP(DTPR1);
REG_DUMP(DTPR2);
REG_DUMP(MR0);
REG_DUMP(MR1);
REG_DUMP(MR2);
REG_DUMP(MR3);
for (dx = 0; dx < param->phy[phy].nr_dx; dx++) {
DX_REG_DUMP(dx, GCR);
DX_REG_DUMP(dx, GTR);
}
iounmap(phy_base);
}
}
static int do_ddr(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
const struct uniphier_ddrphy_param *param;
char *cmd;
param = uniphier_get_ddrphy_param();
if (!param) {
pr_err("unsupported SoC\n");
return CMD_RET_FAILURE;
}
if (argc == 1)
cmd = "all";
else
cmd = argv[1];
if (!strcmp(cmd, "wbdl") || !strcmp(cmd, "all"))
wbdl_dump(param);
if (!strcmp(cmd, "rbdl") || !strcmp(cmd, "all"))
rbdl_dump(param);
if (!strcmp(cmd, "wld") || !strcmp(cmd, "all"))
wld_dump(param);
if (!strcmp(cmd, "dqsgd") || !strcmp(cmd, "all"))
dqsgd_dump(param);
if (!strcmp(cmd, "mdl") || !strcmp(cmd, "all"))
mdl_dump(param);
if (!strcmp(cmd, "reg") || !strcmp(cmd, "all"))
reg_dump(param);
return CMD_RET_SUCCESS;
}
U_BOOT_CMD(
ddr, 2, 1, do_ddr,
"UniPhier DDR PHY parameters dumper",
"- dump all of the following\n"
"ddr wbdl - dump Write Bit Delay\n"
"ddr rbdl - dump Read Bit Delay\n"
"ddr wld - dump Write Leveling\n"
"ddr dqsgd - dump DQS Gating Delay\n"
"ddr mdl - dump Master Delay Line\n"
"ddr reg - dump registers\n"
);
@@ -0,0 +1,145 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* UniPhier DDR MultiPHY registers
*
* Copyright (C) 2015-2017 Socionext Inc.
*/
#ifndef UNIPHIER_DDRMPHY_REGS_H
#define UNIPHIER_DDRMPHY_REGS_H
#include <linux/bitops.h>
#define MPHY_SHIFT 2
#define MPHY_RIDR (0x000 << MPHY_SHIFT)
#define MPHY_PIR (0x001 << MPHY_SHIFT)
#define MPHY_PIR_INIT BIT(0) /* Initialization Trigger */
#define MPHY_PIR_ZCAL BIT(1) /* Impedance Calibration */
#define MPHY_PIR_PLLINIT BIT(4) /* PLL Initialization */
#define MPHY_PIR_DCAL BIT(5) /* DDL Calibration */
#define MPHY_PIR_PHYRST BIT(6) /* PHY Reset */
#define MPHY_PIR_DRAMRST BIT(7) /* DRAM Reset */
#define MPHY_PIR_DRAMINIT BIT(8) /* DRAM Initialization */
#define MPHY_PIR_WL BIT(9) /* Write Leveling */
#define MPHY_PIR_QSGATE BIT(10) /* Read DQS Gate Training */
#define MPHY_PIR_WLADJ BIT(11) /* Write Leveling Adjust */
#define MPHY_PIR_RDDSKW BIT(12) /* Read Data Bit Deskew */
#define MPHY_PIR_WRDSKW BIT(13) /* Write Data Bit Deskew */
#define MPHY_PIR_RDEYE BIT(14) /* Read Data Eye Training */
#define MPHY_PIR_WREYE BIT(15) /* Write Data Eye Training */
#define MPHY_PIR_ZCALBYP BIT(30) /* Impedance Calib Bypass */
#define MPHY_PIR_INITBYP BIT(31) /* Initialization Bypass */
#define MPHY_PGCR0 (0x002 << MPHY_SHIFT)
#define MPHY_PGCR0_PHYFRST BIT(26) /* PHY FIFO Reset */
#define MPHY_PGCR1 (0x003 << MPHY_SHIFT)
#define MPHY_PGCR1_INHVT BIT(26) /* VT Calculation Inhibit */
#define MPHY_PGCR2 (0x004 << MPHY_SHIFT)
#define MPHY_PGCR2_DUALCHN BIT(28) /* Dual Channel Configuration*/
#define MPHY_PGCR2_ACPDDC BIT(29) /* AC Power-Down with Dual Ch*/
#define MPHY_PGCR3 (0x005 << MPHY_SHIFT)
#define MPHY_PGSR0 (0x006 << MPHY_SHIFT)
#define MPHY_PGSR0_IDONE BIT(0) /* Initialization Done */
#define MPHY_PGSR0_PLDONE BIT(1) /* PLL Lock Done */
#define MPHY_PGSR0_DCDONE BIT(2) /* DDL Calibration Done */
#define MPHY_PGSR0_ZCDONE BIT(3) /* Impedance Calibration Done */
#define MPHY_PGSR0_DIDONE BIT(4) /* DRAM Initialization Done */
#define MPHY_PGSR0_WLDONE BIT(5) /* Write Leveling Done */
#define MPHY_PGSR0_QSGDONE BIT(6) /* DQS Gate Training Done */
#define MPHY_PGSR0_WLADONE BIT(7) /* Write Leveling Adjust Done */
#define MPHY_PGSR0_RDDONE BIT(8) /* Read Bit Deskew Done */
#define MPHY_PGSR0_WDDONE BIT(9) /* Write Bit Deskew Done */
#define MPHY_PGSR0_REDONE BIT(10) /* Read Eye Training Done */
#define MPHY_PGSR0_WEDONE BIT(11) /* Write Eye Training Done */
#define MPHY_PGSR0_ZCERR BIT(20) /* Impedance Calib Error */
#define MPHY_PGSR0_WLERR BIT(21) /* Write Leveling Error */
#define MPHY_PGSR0_QSGERR BIT(22) /* DQS Gate Training Error */
#define MPHY_PGSR0_WLAERR BIT(23) /* Write Leveling Adj Error */
#define MPHY_PGSR0_RDERR BIT(24) /* Read Bit Deskew Error */
#define MPHY_PGSR0_WDERR BIT(25) /* Write Bit Deskew Error */
#define MPHY_PGSR0_REERR BIT(26) /* Read Eye Training Error */
#define MPHY_PGSR0_WEERR BIT(27) /* Write Eye Training Error */
#define MPHY_PGSR1 (0x007 << MPHY_SHIFT)
#define MPHY_PGSR1_VTSTOP BIT(30) /* VT Stop */
#define MPHY_PLLCR (0x008 << MPHY_SHIFT)
#define MPHY_PTR0 (0x009 << MPHY_SHIFT)
#define MPHY_PTR1 (0x00A << MPHY_SHIFT)
#define MPHY_PTR2 (0x00B << MPHY_SHIFT)
#define MPHY_PTR3 (0x00C << MPHY_SHIFT)
#define MPHY_PTR4 (0x00D << MPHY_SHIFT)
#define MPHY_ACMDLR (0x00E << MPHY_SHIFT)
#define MPHY_ACLCDLR (0x00F << MPHY_SHIFT)
#define MPHY_ACBDLR0 (0x010 << MPHY_SHIFT)
#define MPHY_ACBDLR1 (0x011 << MPHY_SHIFT)
#define MPHY_ACBDLR2 (0x012 << MPHY_SHIFT)
#define MPHY_ACBDLR3 (0x013 << MPHY_SHIFT)
#define MPHY_ACBDLR4 (0x014 << MPHY_SHIFT)
#define MPHY_ACBDLR5 (0x015 << MPHY_SHIFT)
#define MPHY_ACBDLR6 (0x016 << MPHY_SHIFT)
#define MPHY_ACBDLR7 (0x017 << MPHY_SHIFT)
#define MPHY_ACBDLR8 (0x018 << MPHY_SHIFT)
#define MPHY_ACBDLR9 (0x019 << MPHY_SHIFT)
#define MPHY_ACIOCR0 (0x01A << MPHY_SHIFT)
#define MPHY_ACIOCR1 (0x01B << MPHY_SHIFT)
#define MPHY_ACIOCR2 (0x01C << MPHY_SHIFT)
#define MPHY_ACIOCR3 (0x01D << MPHY_SHIFT)
#define MPHY_ACIOCR4 (0x01E << MPHY_SHIFT)
#define MPHY_ACIOCR5 (0x01F << MPHY_SHIFT)
#define MPHY_DXCCR (0x020 << MPHY_SHIFT)
#define MPHY_DSGCR (0x021 << MPHY_SHIFT)
#define MPHY_DCR (0x022 << MPHY_SHIFT)
#define MPHY_DTPR0 (0x023 << MPHY_SHIFT)
#define MPHY_DTPR1 (0x024 << MPHY_SHIFT)
#define MPHY_DTPR2 (0x025 << MPHY_SHIFT)
#define MPHY_DTPR3 (0x026 << MPHY_SHIFT)
#define MPHY_MR0 (0x027 << MPHY_SHIFT)
#define MPHY_MR1 (0x028 << MPHY_SHIFT)
#define MPHY_MR2 (0x029 << MPHY_SHIFT)
#define MPHY_MR3 (0x02A << MPHY_SHIFT)
#define MPHY_ODTCR (0x02B << MPHY_SHIFT)
#define MPHY_DTCR (0x02C << MPHY_SHIFT)
#define MPHY_DTCR_RANKEN_SHIFT 24 /* Rank Enable */
#define MPHY_DTCR_RANKEN_MASK (0xf << (MPHY_DTCR_RANKEN_SHIFT))
#define MPHY_DTAR0 (0x02D << MPHY_SHIFT)
#define MPHY_DTAR1 (0x02E << MPHY_SHIFT)
#define MPHY_DTAR2 (0x02F << MPHY_SHIFT)
#define MPHY_DTAR3 (0x030 << MPHY_SHIFT)
#define MPHY_DTDR0 (0x031 << MPHY_SHIFT)
#define MPHY_DTDR1 (0x032 << MPHY_SHIFT)
#define MPHY_DTEDR0 (0x033 << MPHY_SHIFT)
#define MPHY_DTEDR1 (0x034 << MPHY_SHIFT)
#define MPHY_ZQCR (0x090 << MPHY_SHIFT)
#define MPHY_ZQCR_AVGEN BIT(16) /* Average Algorithm */
#define MPHY_ZQCR_FORCE_ZCAL_VT_UPDATE BIT(27) /* force VT update */
/* ZQ */
#define MPHY_ZQ_BASE (0x091 << MPHY_SHIFT)
#define MPHY_ZQ_STRIDE (0x004 << MPHY_SHIFT)
#define MPHY_ZQ_PR (0x000 << MPHY_SHIFT)
#define MPHY_ZQ_DR (0x001 << MPHY_SHIFT)
#define MPHY_ZQ_SR (0x002 << MPHY_SHIFT)
/* DATX8 */
#define MPHY_DX_BASE (0x0A0 << MPHY_SHIFT)
#define MPHY_DX_STRIDE (0x020 << MPHY_SHIFT)
#define MPHY_DX_GCR0 (0x000 << MPHY_SHIFT)
#define MPHY_DX_GCR0_WLRKEN_SHIFT 26 /* Write Level Rank Enable */
#define MPHY_DX_GCR0_WLRKEN_MASK (0xf << (MPHY_DX_GCR0_WLRKEN_SHIFT))
#define MPHY_DX_GCR1 (0x001 << MPHY_SHIFT)
#define MPHY_DX_GCR2 (0x002 << MPHY_SHIFT)
#define MPHY_DX_GCR3 (0x003 << MPHY_SHIFT)
#define MPHY_DX_GSR0 (0x004 << MPHY_SHIFT)
#define MPHY_DX_GSR1 (0x005 << MPHY_SHIFT)
#define MPHY_DX_GSR2 (0x006 << MPHY_SHIFT)
#define MPHY_DX_BDLR0 (0x007 << MPHY_SHIFT)
#define MPHY_DX_BDLR1 (0x008 << MPHY_SHIFT)
#define MPHY_DX_BDLR2 (0x009 << MPHY_SHIFT)
#define MPHY_DX_BDLR3 (0x00A << MPHY_SHIFT)
#define MPHY_DX_BDLR4 (0x00B << MPHY_SHIFT)
#define MPHY_DX_BDLR5 (0x00C << MPHY_SHIFT)
#define MPHY_DX_BDLR6 (0x00D << MPHY_SHIFT)
#define MPHY_DX_LCDLR0 (0x00E << MPHY_SHIFT)
#define MPHY_DX_LCDLR1 (0x00F << MPHY_SHIFT)
#define MPHY_DX_LCDLR2 (0x010 << MPHY_SHIFT)
#define MPHY_DX_MDLR (0x011 << MPHY_SHIFT)
#define MPHY_DX_GTR (0x012 << MPHY_SHIFT)
#endif /* UNIPHIER_DDRMPHY_REGS_H */
@@ -0,0 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2016 Socionext Inc.
*/
#ifndef ARCH_DDRPHY_INIT_H
#define ARCH_DDRPHY_INTT_H
#include <linux/compiler.h>
#include <linux/types.h>
int uniphier_ld4_ddrphy_init(void __iomem *phy_base, int freq, bool ddr3plus);
void ddrphy_prepare_training(void __iomem *phy_base, int rank);
int ddrphy_training(void __iomem *phy_base);
#endif /* ARCH_DDRPHY_INT_H */
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2014 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
*/
#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/printk.h>
#include "ddrphy-init.h"
#include "ddrphy-regs.h"
enum dram_freq {
DRAM_FREQ_1333M,
DRAM_FREQ_1600M,
DRAM_FREQ_NR,
};
static u32 ddrphy_ptr0[DRAM_FREQ_NR] = {0x0a806844, 0x0c807d04};
static u32 ddrphy_ptr1[DRAM_FREQ_NR] = {0x208e0124, 0x2710015E};
static u32 ddrphy_ptr3[DRAM_FREQ_NR] = {0x0f051616, 0x12061A80};
static u32 ddrphy_ptr4[DRAM_FREQ_NR] = {0x06ae08d6, 0x08027100};
static u32 ddrphy_dtpr0[DRAM_FREQ_NR] = {0x85589955, 0x999cbb66};
static u32 ddrphy_dtpr1[DRAM_FREQ_NR] = {0x1a8363c0, 0x1a878400};
static u32 ddrphy_dtpr2[DRAM_FREQ_NR] = {0x5002c200, 0xa00214f8};
static u32 ddrphy_mr0[DRAM_FREQ_NR] = {0x00000b51, 0x00000d71};
static u32 ddrphy_mr2[DRAM_FREQ_NR] = {0x00000290, 0x00000298};
int uniphier_ld4_ddrphy_init(void __iomem *phy_base, int freq, bool ddr3plus)
{
enum dram_freq freq_e;
u32 tmp;
switch (freq) {
case 1333:
freq_e = DRAM_FREQ_1333M;
break;
case 1600:
freq_e = DRAM_FREQ_1600M;
break;
default:
pr_err("unsupported DRAM frequency %d MHz\n", freq);
return -EINVAL;
}
writel(0x0300c473, phy_base + PHY_PGCR1);
writel(ddrphy_ptr0[freq_e], phy_base + PHY_PTR0);
writel(ddrphy_ptr1[freq_e], phy_base + PHY_PTR1);
writel(0x00083DEF, phy_base + PHY_PTR2);
writel(ddrphy_ptr3[freq_e], phy_base + PHY_PTR3);
writel(ddrphy_ptr4[freq_e], phy_base + PHY_PTR4);
writel(0xF004001A, phy_base + PHY_DSGCR);
/* change the value of the on-die pull-up/pull-down registors */
tmp = readl(phy_base + PHY_DXCCR);
tmp &= ~0x0ee0;
tmp |= PHY_DXCCR_DQSNRES_688_OHM | PHY_DXCCR_DQSRES_688_OHM;
writel(tmp, phy_base + PHY_DXCCR);
writel(0x0000040B, phy_base + PHY_DCR);
writel(ddrphy_dtpr0[freq_e], phy_base + PHY_DTPR0);
writel(ddrphy_dtpr1[freq_e], phy_base + PHY_DTPR1);
writel(ddrphy_dtpr2[freq_e], phy_base + PHY_DTPR2);
writel(ddrphy_mr0[freq_e], phy_base + PHY_MR0);
writel(0x00000006, phy_base + PHY_MR1);
writel(ddrphy_mr2[freq_e], phy_base + PHY_MR2);
writel(ddr3plus ? 0x00000800 : 0x00000000, phy_base + PHY_MR3);
while (!(readl(phy_base + PHY_PGSR0) & PHY_PGSR0_IDONE))
;
writel(0x0300C473, phy_base + PHY_PGCR1);
writel(0x0000005D, phy_base + PHY_ZQ_BASE + PHY_ZQ_CR1);
return 0;
}
@@ -0,0 +1,142 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* UniPhier DDR PHY registers
*
* Copyright (C) 2014 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
*/
#ifndef ARCH_DDRPHY_REGS_H
#define ARCH_DDRPHY_REGS_H
#define PHY_REG_SHIFT 2
#define PHY_RIDR (0x000 << PHY_REG_SHIFT)
#define PHY_PIR (0x001 << PHY_REG_SHIFT)
#define PHY_PIR_INIT BIT(0) /* Initialization Trigger */
#define PHY_PIR_ZCAL BIT(1) /* Impedance Calibration */
#define PHY_PIR_PLLINIT BIT(4) /* PLL Initialization */
#define PHY_PIR_DCAL BIT(5) /* DDL Calibration */
#define PHY_PIR_PHYRST BIT(6) /* PHY Reset */
#define PHY_PIR_DRAMRST BIT(7) /* DRAM Reset */
#define PHY_PIR_DRAMINIT BIT(8) /* DRAM Initialization */
#define PHY_PIR_WL BIT(9) /* Write Leveling */
#define PHY_PIR_QSGATE BIT(10) /* Read DQS Gate Training */
#define PHY_PIR_WLADJ BIT(11) /* Write Leveling Adjust */
#define PHY_PIR_RDDSKW BIT(12) /* Read Data Bit Deskew */
#define PHY_PIR_WRDSKW BIT(13) /* Write Data Bit Deskew */
#define PHY_PIR_RDEYE BIT(14) /* Read Data Eye Training */
#define PHY_PIR_WREYE BIT(15) /* Write Data Eye Training */
#define PHY_PIR_LOCKBYP BIT(28) /* PLL Lock Bypass */
#define PHY_PIR_DCALBYP BIT(29) /* DDL Calibration Bypass */
#define PHY_PIR_ZCALBYP BIT(30) /* Impedance Calib Bypass */
#define PHY_PIR_INITBYP BIT(31) /* Initialization Bypass */
#define PHY_PGCR0 (0x002 << PHY_REG_SHIFT)
#define PHY_PGCR1 (0x003 << PHY_REG_SHIFT)
#define PHY_PGCR1_INHVT BIT(26) /* VT Calculation Inhibit */
#define PHY_PGSR0 (0x004 << PHY_REG_SHIFT)
#define PHY_PGSR0_IDONE BIT(0) /* Initialization Done */
#define PHY_PGSR0_PLDONE BIT(1) /* PLL Lock Done */
#define PHY_PGSR0_DCDONE BIT(2) /* DDL Calibration Done */
#define PHY_PGSR0_ZCDONE BIT(3) /* Impedance Calibration Done */
#define PHY_PGSR0_DIDONE BIT(4) /* DRAM Initialization Done */
#define PHY_PGSR0_WLDONE BIT(5) /* Write Leveling Done */
#define PHY_PGSR0_QSGDONE BIT(6) /* DQS Gate Training Done */
#define PHY_PGSR0_WLADONE BIT(7) /* Write Leveling Adjust Done */
#define PHY_PGSR0_RDDONE BIT(8) /* Read Bit Deskew Done */
#define PHY_PGSR0_WDDONE BIT(9) /* Write Bit Deskew Done */
#define PHY_PGSR0_REDONE BIT(10) /* Read Eye Training Done */
#define PHY_PGSR0_WEDONE BIT(11) /* Write Eye Training Done */
#define PHY_PGSR0_DIERR BIT(20) /* DRAM Initialization Error */
#define PHY_PGSR0_WLERR BIT(21) /* Write Leveling Error */
#define PHY_PGSR0_QSGERR BIT(22) /* DQS Gate Training Error */
#define PHY_PGSR0_WLAERR BIT(23) /* Write Leveling Adj Error */
#define PHY_PGSR0_RDERR BIT(24) /* Read Bit Deskew Error */
#define PHY_PGSR0_WDERR BIT(25) /* Write Bit Deskew Error */
#define PHY_PGSR0_REERR BIT(26) /* Read Eye Training Error */
#define PHY_PGSR0_WEERR BIT(27) /* Write Eye Training Error */
#define PHY_PGSR0_DTERR_SHIFT 28 /* Data Training Error Status*/
#define PHY_PGSR0_DTERR (7 << (PHY_PGSR0_DTERR_SHIFT))
#define PHY_PGSR1 (0x005 << PHY_REG_SHIFT)
#define PHY_PGSR1_VTSTOP BIT(30) /* VT Stop (v3-) */
#define PHY_PLLCR (0x006 << PHY_REG_SHIFT)
#define PHY_PTR0 (0x007 << PHY_REG_SHIFT)
#define PHY_PTR1 (0x008 << PHY_REG_SHIFT)
#define PHY_PTR2 (0x009 << PHY_REG_SHIFT)
#define PHY_PTR3 (0x00A << PHY_REG_SHIFT)
#define PHY_PTR4 (0x00B << PHY_REG_SHIFT)
#define PHY_ACMDLR (0x00C << PHY_REG_SHIFT)
#define PHY_ACBDLR (0x00D << PHY_REG_SHIFT)
#define PHY_ACIOCR (0x00E << PHY_REG_SHIFT)
#define PHY_DXCCR (0x00F << PHY_REG_SHIFT)
#define PHY_DXCCR_DQSRES_OPEN (0 << 5)
#define PHY_DXCCR_DQSRES_688_OHM (1 << 5)
#define PHY_DXCCR_DQSRES_611_OHM (2 << 5)
#define PHY_DXCCR_DQSRES_550_OHM (3 << 5)
#define PHY_DXCCR_DQSRES_500_OHM (4 << 5)
#define PHY_DXCCR_DQSRES_458_OHM (5 << 5)
#define PHY_DXCCR_DQSRES_393_OHM (6 << 5)
#define PHY_DXCCR_DQSRES_344_OHM (7 << 5)
#define PHY_DXCCR_DQSNRES_OPEN (0 << 9)
#define PHY_DXCCR_DQSNRES_688_OHM (1 << 9)
#define PHY_DXCCR_DQSNRES_611_OHM (2 << 9)
#define PHY_DXCCR_DQSNRES_550_OHM (3 << 9)
#define PHY_DXCCR_DQSNRES_500_OHM (4 << 9)
#define PHY_DXCCR_DQSNRES_458_OHM (5 << 9)
#define PHY_DXCCR_DQSNRES_393_OHM (6 << 9)
#define PHY_DXCCR_DQSNRES_344_OHM (7 << 9)
#define PHY_DSGCR (0x010 << PHY_REG_SHIFT)
#define PHY_DCR (0x011 << PHY_REG_SHIFT)
#define PHY_DTPR0 (0x012 << PHY_REG_SHIFT)
#define PHY_DTPR1 (0x013 << PHY_REG_SHIFT)
#define PHY_DTPR2 (0x014 << PHY_REG_SHIFT)
#define PHY_MR0 (0x015 << PHY_REG_SHIFT)
#define PHY_MR1 (0x016 << PHY_REG_SHIFT)
#define PHY_MR2 (0x017 << PHY_REG_SHIFT)
#define PHY_MR3 (0x018 << PHY_REG_SHIFT)
#define PHY_ODTCR (0x019 << PHY_REG_SHIFT)
#define PHY_DTCR (0x01A << PHY_REG_SHIFT)
#define PHY_DTCR_DTRANK_SHIFT 4 /* Data Training Rank */
#define PHY_DTCR_DTRANK_MASK (0x3 << (PHY_DTCR_DTRANK_SHIFT))
#define PHY_DTCR_DTMPR BIT(6) /* Data Training using MPR */
#define PHY_DTCR_RANKEN_SHIFT 24 /* Rank Enable */
#define PHY_DTCR_RANKEN_MASK (0xf << (PHY_DTCR_RANKEN_SHIFT))
#define PHY_DTAR0 (0x01B << PHY_REG_SHIFT)
#define PHY_DTAR1 (0x01C << PHY_REG_SHIFT)
#define PHY_DTAR2 (0x01D << PHY_REG_SHIFT)
#define PHY_DTAR3 (0x01E << PHY_REG_SHIFT)
#define PHY_DTDR0 (0x01F << PHY_REG_SHIFT)
#define PHY_DTDR1 (0x020 << PHY_REG_SHIFT)
#define PHY_DTEDR0 (0x021 << PHY_REG_SHIFT)
#define PHY_DTEDR1 (0x022 << PHY_REG_SHIFT)
#define PHY_PGCR2 (0x023 << PHY_REG_SHIFT)
#define PHY_GPR0 (0x05E << PHY_REG_SHIFT)
#define PHY_GPR1 (0x05F << PHY_REG_SHIFT)
/* ZQ */
#define PHY_ZQ_BASE (0x060 << PHY_REG_SHIFT)
#define PHY_ZQ_STRIDE (0x004 << PHY_REG_SHIFT)
#define PHY_ZQ_CR0 (0x000 << PHY_REG_SHIFT)
#define PHY_ZQ_CR1 (0x001 << PHY_REG_SHIFT)
#define PHY_ZQ_SR0 (0x002 << PHY_REG_SHIFT)
#define PHY_ZQ_SR1 (0x003 << PHY_REG_SHIFT)
/* DATX8 */
#define PHY_DX_BASE (0x070 << PHY_REG_SHIFT)
#define PHY_DX_STRIDE (0x010 << PHY_REG_SHIFT)
#define PHY_DX_GCR (0x000 << PHY_REG_SHIFT)
#define PHY_DX_GCR_WLRKEN_SHIFT 26 /* Write Level Rank Enable */
#define PHY_DX_GCR_WLRKEN_MASK (0xf << (PHY_DX_GCR_WLRKEN_SHIFT))
#define PHY_DX_GSR0 (0x001 << PHY_REG_SHIFT)
#define PHY_DX_GSR1 (0x002 << PHY_REG_SHIFT)
#define PHY_DX_BDLR0 (0x003 << PHY_REG_SHIFT)
#define PHY_DX_BDLR1 (0x004 << PHY_REG_SHIFT)
#define PHY_DX_BDLR2 (0x005 << PHY_REG_SHIFT)
#define PHY_DX_BDLR3 (0x006 << PHY_REG_SHIFT)
#define PHY_DX_BDLR4 (0x007 << PHY_REG_SHIFT)
#define PHY_DX_LCDLR0 (0x008 << PHY_REG_SHIFT)
#define PHY_DX_LCDLR1 (0x009 << PHY_REG_SHIFT)
#define PHY_DX_LCDLR2 (0x00A << PHY_REG_SHIFT)
#define PHY_DX_MDLR (0x00B << PHY_REG_SHIFT)
#define PHY_DX_GTR (0x00C << PHY_REG_SHIFT)
#define PHY_DX_GSR2 (0x00D << PHY_REG_SHIFT)
#endif /* ARCH_DDRPHY_REGS_H */
@@ -0,0 +1,146 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2011-2014 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
*/
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/printk.h>
#include <time.h>
#include "ddrphy-init.h"
#include "ddrphy-regs.h"
/* for LD4, Pro4, sLD8 */
#define NR_DATX8_PER_DDRPHY 2
void ddrphy_prepare_training(void __iomem *phy_base, int rank)
{
void __iomem *dx_base = phy_base + PHY_DX_BASE;
int dx;
u32 tmp;
for (dx = 0; dx < NR_DATX8_PER_DDRPHY; dx++) {
tmp = readl(dx_base + PHY_DX_GCR);
/* Specify the rank that should be write leveled */
tmp &= ~PHY_DX_GCR_WLRKEN_MASK;
tmp |= (1 << (PHY_DX_GCR_WLRKEN_SHIFT + rank)) &
PHY_DX_GCR_WLRKEN_MASK;
writel(tmp, dx_base + PHY_DX_GCR);
dx_base += PHY_DX_STRIDE;
}
tmp = readl(phy_base + PHY_DTCR);
/* Specify the rank used during data bit deskew and eye centering */
tmp &= ~PHY_DTCR_DTRANK_MASK;
tmp |= (rank << PHY_DTCR_DTRANK_SHIFT) & PHY_DTCR_DTRANK_MASK;
/* Use Multi-Purpose Register for DQS gate training */
tmp |= PHY_DTCR_DTMPR;
/* Specify the rank enabled for data-training */
tmp &= ~PHY_DTCR_RANKEN_MASK;
tmp |= (1 << (PHY_DTCR_RANKEN_SHIFT + rank)) & PHY_DTCR_RANKEN_MASK;
writel(tmp, phy_base + PHY_DTCR);
}
struct ddrphy_init_sequence {
char *description;
u32 init_flag;
u32 done_flag;
u32 err_flag;
};
static const struct ddrphy_init_sequence init_sequence[] = {
{
"DRAM Initialization",
PHY_PIR_DRAMRST | PHY_PIR_DRAMINIT,
PHY_PGSR0_DIDONE,
PHY_PGSR0_DIERR
},
{
"Write Leveling",
PHY_PIR_WL,
PHY_PGSR0_WLDONE,
PHY_PGSR0_WLERR
},
{
"Read DQS Gate Training",
PHY_PIR_QSGATE,
PHY_PGSR0_QSGDONE,
PHY_PGSR0_QSGERR
},
{
"Write Leveling Adjustment",
PHY_PIR_WLADJ,
PHY_PGSR0_WLADONE,
PHY_PGSR0_WLAERR
},
{
"Read Bit Deskew",
PHY_PIR_RDDSKW,
PHY_PGSR0_RDDONE,
PHY_PGSR0_RDERR
},
{
"Write Bit Deskew",
PHY_PIR_WRDSKW,
PHY_PGSR0_WDDONE,
PHY_PGSR0_WDERR
},
{
"Read Eye Training",
PHY_PIR_RDEYE,
PHY_PGSR0_REDONE,
PHY_PGSR0_REERR
},
{
"Write Eye Training",
PHY_PIR_WREYE,
PHY_PGSR0_WEDONE,
PHY_PGSR0_WEERR
}
};
int ddrphy_training(void __iomem *phy_base)
{
int i;
u32 pgsr0;
u32 init_flag = PHY_PIR_INIT;
u32 done_flag = PHY_PGSR0_IDONE;
int timeout = 50000; /* 50 msec is long enough */
#ifdef DEBUG
ulong start = get_timer(0);
#endif
for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
init_flag |= init_sequence[i].init_flag;
done_flag |= init_sequence[i].done_flag;
}
writel(init_flag, phy_base + PHY_PIR);
do {
if (--timeout < 0) {
pr_err("timeout during DDR training\n");
return -ETIMEDOUT;
}
udelay(1);
pgsr0 = readl(phy_base + PHY_PGSR0);
} while ((pgsr0 & done_flag) != done_flag);
for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
if (pgsr0 & init_sequence[i].err_flag) {
pr_err("%s failed\n", init_sequence[i].description);
return -EIO;
}
}
#ifdef DEBUG
pr_debug("DDR training: elapsed time %ld msec\n", get_timer(start));
#endif
return 0;
}
@@ -0,0 +1,192 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2011-2014 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/sizes.h>
#include <asm/processor.h>
#include "../init.h"
#include "ddrphy-init.h"
#include "umc-regs.h"
#define DRAM_CH_NR 2
enum dram_freq {
DRAM_FREQ_1333M,
DRAM_FREQ_1600M,
DRAM_FREQ_NR,
};
enum dram_size {
DRAM_SZ_128M,
DRAM_SZ_256M,
DRAM_SZ_NR,
};
static u32 umc_cmdctla_plus[DRAM_FREQ_NR] = {0x45990b11, 0x36bb0f17};
static u32 umc_cmdctlb_plus[DRAM_FREQ_NR] = {0x16958924, 0x18c6aa24};
static u32 umc_spcctla[DRAM_FREQ_NR][DRAM_SZ_NR] = {
{0x00240512, 0x00350512},
{0x002b0617, 0x003f0617},
};
static u32 umc_spcctlb[DRAM_FREQ_NR] = {0x00ff0006, 0x00ff0008};
static u32 umc_rdatactl[DRAM_FREQ_NR] = {0x000a00ac, 0x000c00ae};
static int umc_get_rank(int ch)
{
return ch; /* ch0: rank0, ch1: rank1 for this SoC */
}
static void umc_start_ssif(void __iomem *ssif_base)
{
writel(0x00000000, ssif_base + 0x0000b004);
writel(0xffffffff, ssif_base + 0x0000c004);
writel(0x000fffcf, ssif_base + 0x0000c008);
writel(0x00000001, ssif_base + 0x0000b000);
writel(0x00000001, ssif_base + 0x0000c000);
writel(0x03010101, ssif_base + UMC_MDMCHSEL);
writel(0x03010100, ssif_base + UMC_DMDCHSEL);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_FETCH);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMQUE0);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMWC0);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMRC0);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMQUE1);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMWC1);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMRC1);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_WC);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_RC);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_DST);
writel(0x00000001, ssif_base + UMC_CPURST);
writel(0x00000001, ssif_base + UMC_IDSRST);
writel(0x00000001, ssif_base + UMC_IXMRST);
writel(0x00000001, ssif_base + UMC_MDMRST);
writel(0x00000001, ssif_base + UMC_MDDRST);
writel(0x00000001, ssif_base + UMC_SIORST);
writel(0x00000001, ssif_base + UMC_VIORST);
writel(0x00000001, ssif_base + UMC_FRCRST);
writel(0x00000001, ssif_base + UMC_RGLRST);
writel(0x00000001, ssif_base + UMC_AIORST);
writel(0x00000001, ssif_base + UMC_DMDRST);
}
static int umc_dramcont_init(void __iomem *dc_base, void __iomem *ca_base,
int freq, unsigned long size, bool ddr3plus)
{
enum dram_freq freq_e;
enum dram_size size_e;
if (!ddr3plus) {
pr_err("DDR3 standard is not supported\n");
return -EINVAL;
}
switch (freq) {
case 1333:
freq_e = DRAM_FREQ_1333M;
break;
case 1600:
freq_e = DRAM_FREQ_1600M;
break;
default:
pr_err("unsupported DRAM frequency %d MHz\n", freq);
return -EINVAL;
}
switch (size) {
case 0:
return 0;
case SZ_128M:
size_e = DRAM_SZ_128M;
break;
case SZ_256M:
size_e = DRAM_SZ_256M;
break;
default:
pr_err("unsupported DRAM size 0x%08lx\n", size);
return -EINVAL;
}
writel(umc_cmdctla_plus[freq_e], dc_base + UMC_CMDCTLA);
writel(umc_cmdctlb_plus[freq_e], dc_base + UMC_CMDCTLB);
writel(umc_spcctla[freq_e][size_e], dc_base + UMC_SPCCTLA);
writel(umc_spcctlb[freq_e], dc_base + UMC_SPCCTLB);
writel(umc_rdatactl[freq_e], dc_base + UMC_RDATACTL_D0);
writel(0x04060806, dc_base + UMC_WDATACTL_D0);
writel(0x04a02000, dc_base + UMC_DATASET);
writel(0x00000000, ca_base + 0x2300);
writel(0x00400020, dc_base + UMC_DCCGCTL);
writel(0x00000003, dc_base + 0x7000);
writel(0x0000000f, dc_base + 0x8000);
writel(0x000000c3, dc_base + 0x8004);
writel(0x00000071, dc_base + 0x8008);
writel(0x0000003b, dc_base + UMC_DICGCTLA);
writel(0x020a0808, dc_base + UMC_DICGCTLB);
writel(0x00000004, dc_base + UMC_FLOWCTLG);
writel(0x80000201, ca_base + 0xc20);
writel(0x0801e01e, dc_base + UMC_FLOWCTLA);
writel(0x00200000, dc_base + UMC_FLOWCTLB);
writel(0x00004444, dc_base + UMC_FLOWCTLC);
writel(0x200a0a00, dc_base + UMC_SPCSETB);
writel(0x00000000, dc_base + UMC_SPCSETD);
writel(0x00000520, dc_base + UMC_DFICUPDCTLA);
return 0;
}
static int umc_ch_init(void __iomem *dc_base, void __iomem *ca_base,
int freq, unsigned long size, bool ddr3plus, int ch)
{
void __iomem *phy_base = dc_base + 0x00001000;
int ret;
writel(UMC_INITSET_INIT1EN, dc_base + UMC_INITSET);
while (readl(dc_base + UMC_INITSTAT) & UMC_INITSTAT_INIT1ST)
cpu_relax();
writel(0x00000101, dc_base + UMC_DIOCTLA);
ret = uniphier_ld4_ddrphy_init(phy_base, freq, ddr3plus);
if (ret)
return ret;
ddrphy_prepare_training(phy_base, umc_get_rank(ch));
ret = ddrphy_training(phy_base);
if (ret)
return ret;
return umc_dramcont_init(dc_base, ca_base, freq, size, ddr3plus);
}
int uniphier_ld4_umc_init(const struct uniphier_board_data *bd)
{
void __iomem *umc_base = (void __iomem *)0x5b800000;
void __iomem *ca_base = umc_base + 0x00001000;
void __iomem *dc_base = umc_base + 0x00400000;
void __iomem *ssif_base = umc_base;
int ch, ret;
for (ch = 0; ch < DRAM_CH_NR; ch++) {
ret = umc_ch_init(dc_base, ca_base, bd->dram_freq,
bd->dram_ch[ch].size,
!!(bd->flags & UNIPHIER_BD_DDR3PLUS), ch);
if (ret) {
pr_err("failed to initialize UMC ch%d\n", ch);
return ret;
}
ca_base += 0x00001000;
dc_base += 0x00200000;
}
umc_start_ssif(ssif_base);
return 0;
}
@@ -0,0 +1,187 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2011-2014 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/sizes.h>
#include <asm/processor.h>
#include "../init.h"
#include "ddrphy-init.h"
#include "umc-regs.h"
#define DRAM_CH_NR 2
enum dram_size {
DRAM_SZ_128M,
DRAM_SZ_256M,
DRAM_SZ_512M,
DRAM_SZ_NR,
};
static u32 umc_spcctla[DRAM_SZ_NR] = {0x002b0617, 0x003f0617, 0x00770617};
static void umc_start_ssif(void __iomem *ssif_base)
{
writel(0x00000000, ssif_base + 0x0000b004);
writel(0xffffffff, ssif_base + 0x0000c004);
writel(0x000fffcf, ssif_base + 0x0000c008);
writel(0x00000001, ssif_base + 0x0000b000);
writel(0x00000001, ssif_base + 0x0000c000);
writel(0x03010100, ssif_base + UMC_HDMCHSEL);
writel(0x03010101, ssif_base + UMC_MDMCHSEL);
writel(0x03010100, ssif_base + UMC_DVCCHSEL);
writel(0x03010100, ssif_base + UMC_DMDCHSEL);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_FETCH);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMQUE0);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMWC0);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMRC0);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMQUE1);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMWC1);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMRC1);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_WC);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_RC);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_DST);
writel(0x00000000, ssif_base + 0x0000c044); /* DCGIV_SSIF_REG */
writel(0x00000001, ssif_base + UMC_CPURST);
writel(0x00000001, ssif_base + UMC_IDSRST);
writel(0x00000001, ssif_base + UMC_IXMRST);
writel(0x00000001, ssif_base + UMC_HDMRST);
writel(0x00000001, ssif_base + UMC_MDMRST);
writel(0x00000001, ssif_base + UMC_HDDRST);
writel(0x00000001, ssif_base + UMC_MDDRST);
writel(0x00000001, ssif_base + UMC_SIORST);
writel(0x00000001, ssif_base + UMC_GIORST);
writel(0x00000001, ssif_base + UMC_HD2RST);
writel(0x00000001, ssif_base + UMC_VIORST);
writel(0x00000001, ssif_base + UMC_DVCRST);
writel(0x00000001, ssif_base + UMC_RGLRST);
writel(0x00000001, ssif_base + UMC_VPERST);
writel(0x00000001, ssif_base + UMC_AIORST);
writel(0x00000001, ssif_base + UMC_DMDRST);
}
static int umc_dramcont_init(void __iomem *dc_base, void __iomem *ca_base,
int freq, unsigned long size, bool ddr3plus)
{
enum dram_size size_e;
if (freq != 1600) {
pr_err("Unsupported DDR frequency %d MHz\n", freq);
return -EINVAL;
}
if (ddr3plus) {
pr_err("DDR3+ is not supported\n");
return -EINVAL;
}
switch (size) {
case SZ_128M:
size_e = DRAM_SZ_128M;
break;
case SZ_256M:
size_e = DRAM_SZ_256M;
break;
case SZ_512M:
size_e = DRAM_SZ_512M;
break;
default:
pr_err("unsupported DRAM size 0x%08lx (per 16bit)\n", size);
return -EINVAL;
}
writel(0x66bb0f17, dc_base + UMC_CMDCTLA);
writel(0x18c6aa44, dc_base + UMC_CMDCTLB);
writel(umc_spcctla[size_e], dc_base + UMC_SPCCTLA);
writel(0x00ff0008, dc_base + UMC_SPCCTLB);
writel(0x000c00ae, dc_base + UMC_RDATACTL_D0);
writel(0x000c00ae, dc_base + UMC_RDATACTL_D1);
writel(0x04060802, dc_base + UMC_WDATACTL_D0);
writel(0x04060802, dc_base + UMC_WDATACTL_D1);
writel(0x04a02000, dc_base + UMC_DATASET);
writel(0x00000000, ca_base + 0x2300);
writel(0x00400020, dc_base + UMC_DCCGCTL);
writel(0x0000000f, dc_base + 0x7000);
writel(0x0000000f, dc_base + 0x8000);
writel(0x000000c3, dc_base + 0x8004);
writel(0x00000071, dc_base + 0x8008);
writel(0x00000004, dc_base + UMC_FLOWCTLG);
writel(0x00000000, dc_base + 0x0060);
writel(0x80000201, ca_base + 0xc20);
writel(0x0801e01e, dc_base + UMC_FLOWCTLA);
writel(0x00200000, dc_base + UMC_FLOWCTLB);
writel(0x00004444, dc_base + UMC_FLOWCTLC);
writel(0x200a0a00, dc_base + UMC_SPCSETB);
writel(0x00010000, dc_base + UMC_SPCSETD);
writel(0x80000020, dc_base + UMC_DFICUPDCTLA);
return 0;
}
static int umc_ch_init(void __iomem *dc_base, void __iomem *ca_base,
int freq, unsigned long size, unsigned int width,
bool ddr3plus)
{
void __iomem *phy_base = dc_base + 0x00001000;
int nr_phy = width / 16;
int phy, ret;
writel(UMC_INITSET_INIT1EN, dc_base + UMC_INITSET);
while (readl(dc_base + UMC_INITSTAT) & UMC_INITSTAT_INIT1ST)
cpu_relax();
for (phy = 0; phy < nr_phy; phy++) {
writel(0x00000100 | ((1 << (phy + 1)) - 1),
dc_base + UMC_DIOCTLA);
ret = uniphier_ld4_ddrphy_init(phy_base, freq, ddr3plus);
if (ret)
return ret;
ddrphy_prepare_training(phy_base, phy);
ret = ddrphy_training(phy_base);
if (ret)
return ret;
phy_base += 0x00001000;
}
return umc_dramcont_init(dc_base, ca_base, freq, size / (width / 16),
ddr3plus);
}
int uniphier_pro4_umc_init(const struct uniphier_board_data *bd)
{
void __iomem *umc_base = (void __iomem *)0x5b800000;
void __iomem *ca_base = umc_base + 0x00001000;
void __iomem *dc_base = umc_base + 0x00400000;
void __iomem *ssif_base = umc_base;
int ch, ret;
for (ch = 0; ch < DRAM_CH_NR; ch++) {
ret = umc_ch_init(dc_base, ca_base, bd->dram_freq,
bd->dram_ch[ch].size,
bd->dram_ch[ch].width,
!!(bd->flags & UNIPHIER_BD_DDR3PLUS));
if (ret) {
pr_err("failed to initialize UMC ch%d\n", ch);
return ret;
}
ca_base += 0x00001000;
dc_base += 0x00200000;
}
umc_start_ssif(ssif_base);
return 0;
}
@@ -0,0 +1,11 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Socionext Inc.
*/
#include "../init.h"
int uniphier_pro5_umc_init(const struct uniphier_board_data *bd)
{
return 0;
}
@@ -0,0 +1,642 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2015-2017 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*
* based on commit 21b6e480f92ccc38fe0502e3116411d6509d3bf2 of Diag by:
* Copyright (C) 2015 Socionext Inc.
*/
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/printk.h>
#include <linux/sizes.h>
#include <asm/processor.h>
#include <time.h>
#include "../init.h"
#include "../soc-info.h"
#include "ddrmphy-regs.h"
#include "umc-regs.h"
#define DRAM_CH_NR 3
enum dram_freq {
DRAM_FREQ_1866M,
DRAM_FREQ_2133M,
DRAM_FREQ_NR,
};
enum dram_size {
DRAM_SZ_256M,
DRAM_SZ_512M,
DRAM_SZ_NR,
};
/* PHY */
static u32 ddrphy_pgcr2[DRAM_FREQ_NR] = {0x00FC7E5D, 0x00FC90AB};
static u32 ddrphy_ptr0[DRAM_FREQ_NR] = {0x0EA09205, 0x10C0A6C6};
static u32 ddrphy_ptr1[DRAM_FREQ_NR] = {0x0DAC041B, 0x0FA104B1};
static u32 ddrphy_ptr3[DRAM_FREQ_NR] = {0x15171e45, 0x18182357};
static u32 ddrphy_ptr4[DRAM_FREQ_NR] = {0x0e9ad8e9, 0x10b34157};
static u32 ddrphy_dtpr0[DRAM_FREQ_NR] = {0x35a00d88, 0x39e40e88};
static u32 ddrphy_dtpr1[DRAM_FREQ_NR] = {0x2288cc2c, 0x228a04d0};
static u32 ddrphy_dtpr2[DRAM_FREQ_NR] = {0x50005e00, 0x50006a00};
static u32 ddrphy_dtpr3[DRAM_FREQ_NR] = {0x0010cb49, 0x0010ec89};
static u32 ddrphy_mr0[DRAM_FREQ_NR] = {0x00000115, 0x00000125};
static u32 ddrphy_mr2[DRAM_FREQ_NR] = {0x000002a0, 0x000002a8};
/* dependent on package and board design */
static u32 ddrphy_acbdlr0[DRAM_CH_NR] = {0x0000000c, 0x0000000c, 0x00000009};
/* DDR multiPHY */
static inline int ddrphy_get_rank(int dx)
{
return dx / 2;
}
static void ddrphy_fifo_reset(void __iomem *phy_base)
{
u32 tmp;
tmp = readl(phy_base + MPHY_PGCR0);
tmp &= ~MPHY_PGCR0_PHYFRST;
writel(tmp, phy_base + MPHY_PGCR0);
udelay(1);
tmp |= MPHY_PGCR0_PHYFRST;
writel(tmp, phy_base + MPHY_PGCR0);
udelay(1);
}
static void ddrphy_vt_ctrl(void __iomem *phy_base, int enable)
{
u32 tmp;
tmp = readl(phy_base + MPHY_PGCR1);
if (enable)
tmp &= ~MPHY_PGCR1_INHVT;
else
tmp |= MPHY_PGCR1_INHVT;
writel(tmp, phy_base + MPHY_PGCR1);
if (!enable) {
while (!(readl(phy_base + MPHY_PGSR1) & MPHY_PGSR1_VTSTOP))
cpu_relax();
}
}
static void ddrphy_dqs_delay_fixup(void __iomem *phy_base, int nr_dx, int step)
{
int dx;
u32 lcdlr1, rdqsd;
void __iomem *dx_base = phy_base + MPHY_DX_BASE;
ddrphy_vt_ctrl(phy_base, 0);
for (dx = 0; dx < nr_dx; dx++) {
lcdlr1 = readl(dx_base + MPHY_DX_LCDLR1);
rdqsd = (lcdlr1 >> 8) & 0xff;
rdqsd = clamp(rdqsd + step, 0U, 0xffU);
lcdlr1 = (lcdlr1 & ~(0xff << 8)) | (rdqsd << 8);
writel(lcdlr1, dx_base + MPHY_DX_LCDLR1);
readl(dx_base + MPHY_DX_LCDLR1); /* relax */
dx_base += MPHY_DX_STRIDE;
}
ddrphy_vt_ctrl(phy_base, 1);
}
static int ddrphy_get_system_latency(void __iomem *phy_base, int width)
{
void __iomem *dx_base = phy_base + MPHY_DX_BASE;
const int nr_dx = width / 8;
int dx, rank;
u32 gtr;
int dgsl, dgsl_min = INT_MAX, dgsl_max = 0;
for (dx = 0; dx < nr_dx; dx++) {
gtr = readl(dx_base + MPHY_DX_GTR);
for (rank = 0; rank < 4; rank++) {
dgsl = gtr & 0x7;
/* if dgsl is zero, this rank was not trained. skip. */
if (dgsl) {
dgsl_min = min(dgsl_min, dgsl);
dgsl_max = max(dgsl_max, dgsl);
}
gtr >>= 3;
}
dx_base += MPHY_DX_STRIDE;
}
if (dgsl_min != dgsl_max)
pr_warn("DQS Gateing System Latencies are not all leveled.\n");
return dgsl_max;
}
static void ddrphy_init(void __iomem *phy_base, enum dram_freq freq, int width,
int ch)
{
u32 tmp;
void __iomem *zq_base, *dx_base;
int zq, dx;
int nr_dx;
nr_dx = width / 8;
writel(MPHY_PIR_ZCALBYP, phy_base + MPHY_PIR);
/*
* Disable RGLVT bit (Read DQS Gating LCDL Delay VT Compensation)
* to avoid read error issue.
*/
writel(0x07d81e37, phy_base + MPHY_PGCR0);
writel(0x0200c4e0, phy_base + MPHY_PGCR1);
tmp = ddrphy_pgcr2[freq];
if (width >= 32)
tmp |= MPHY_PGCR2_DUALCHN | MPHY_PGCR2_ACPDDC;
writel(tmp, phy_base + MPHY_PGCR2);
writel(ddrphy_ptr0[freq], phy_base + MPHY_PTR0);
writel(ddrphy_ptr1[freq], phy_base + MPHY_PTR1);
writel(0x00083def, phy_base + MPHY_PTR2);
writel(ddrphy_ptr3[freq], phy_base + MPHY_PTR3);
writel(ddrphy_ptr4[freq], phy_base + MPHY_PTR4);
writel(ddrphy_acbdlr0[ch], phy_base + MPHY_ACBDLR0);
writel(0x55555555, phy_base + MPHY_ACIOCR1);
writel(0x00000000, phy_base + MPHY_ACIOCR2);
writel(0x55555555, phy_base + MPHY_ACIOCR3);
writel(0x00000000, phy_base + MPHY_ACIOCR4);
writel(0x00000055, phy_base + MPHY_ACIOCR5);
writel(0x00181aa4, phy_base + MPHY_DXCCR);
writel(0x0024641e, phy_base + MPHY_DSGCR);
writel(0x0000040b, phy_base + MPHY_DCR);
writel(ddrphy_dtpr0[freq], phy_base + MPHY_DTPR0);
writel(ddrphy_dtpr1[freq], phy_base + MPHY_DTPR1);
writel(ddrphy_dtpr2[freq], phy_base + MPHY_DTPR2);
writel(ddrphy_dtpr3[freq], phy_base + MPHY_DTPR3);
writel(ddrphy_mr0[freq], phy_base + MPHY_MR0);
writel(0x00000006, phy_base + MPHY_MR1);
writel(ddrphy_mr2[freq], phy_base + MPHY_MR2);
writel(0x00000000, phy_base + MPHY_MR3);
tmp = 0;
for (dx = 0; dx < nr_dx; dx++)
tmp |= BIT(MPHY_DTCR_RANKEN_SHIFT + ddrphy_get_rank(dx));
writel(0x90003087 | tmp, phy_base + MPHY_DTCR);
writel(0x00000000, phy_base + MPHY_DTAR0);
writel(0x00000008, phy_base + MPHY_DTAR1);
writel(0x00000010, phy_base + MPHY_DTAR2);
writel(0x00000018, phy_base + MPHY_DTAR3);
writel(0xdd22ee11, phy_base + MPHY_DTDR0);
writel(0x7788bb44, phy_base + MPHY_DTDR1);
/* impedance control settings */
writel(0x04048900, phy_base + MPHY_ZQCR);
zq_base = phy_base + MPHY_ZQ_BASE;
for (zq = 0; zq < 4; zq++) {
/*
* board-dependent
* PXS2: CH0ZQ0=0x5B, CH1ZQ0=0x5B, CH2ZQ0=0x59, others=0x5D
*/
writel(0x0007BB5D, zq_base + MPHY_ZQ_PR);
zq_base += MPHY_ZQ_STRIDE;
}
/* DATX8 settings */
dx_base = phy_base + MPHY_DX_BASE;
for (dx = 0; dx < 4; dx++) {
tmp = readl(dx_base + MPHY_DX_GCR0);
tmp &= ~MPHY_DX_GCR0_WLRKEN_MASK;
tmp |= BIT(MPHY_DX_GCR0_WLRKEN_SHIFT + ddrphy_get_rank(dx)) &
MPHY_DX_GCR0_WLRKEN_MASK;
writel(tmp, dx_base + MPHY_DX_GCR0);
writel(0x00000000, dx_base + MPHY_DX_GCR1);
writel(0x00000000, dx_base + MPHY_DX_GCR2);
writel(0x00000000, dx_base + MPHY_DX_GCR3);
dx_base += MPHY_DX_STRIDE;
}
while (!(readl(phy_base + MPHY_PGSR0) & MPHY_PGSR0_IDONE))
cpu_relax();
ddrphy_dqs_delay_fixup(phy_base, nr_dx, -4);
}
struct ddrphy_init_sequence {
char *description;
u32 init_flag;
u32 done_flag;
u32 err_flag;
};
static const struct ddrphy_init_sequence impedance_calibration_sequence[] = {
{
"Impedance Calibration",
MPHY_PIR_ZCAL,
MPHY_PGSR0_ZCDONE,
MPHY_PGSR0_ZCERR,
},
{ /* sentinel */ }
};
static const struct ddrphy_init_sequence dram_init_sequence[] = {
{
"DRAM Initialization",
MPHY_PIR_DRAMRST | MPHY_PIR_DRAMINIT,
MPHY_PGSR0_DIDONE,
0,
},
{ /* sentinel */ }
};
static const struct ddrphy_init_sequence training_sequence[] = {
{
"Write Leveling",
MPHY_PIR_WL,
MPHY_PGSR0_WLDONE,
MPHY_PGSR0_WLERR,
},
{
"Read DQS Gate Training",
MPHY_PIR_QSGATE,
MPHY_PGSR0_QSGDONE,
MPHY_PGSR0_QSGERR,
},
{
"Write Leveling Adjustment",
MPHY_PIR_WLADJ,
MPHY_PGSR0_WLADONE,
MPHY_PGSR0_WLAERR,
},
{
"Read Bit Deskew",
MPHY_PIR_RDDSKW,
MPHY_PGSR0_RDDONE,
MPHY_PGSR0_RDERR,
},
{
"Write Bit Deskew",
MPHY_PIR_WRDSKW,
MPHY_PGSR0_WDDONE,
MPHY_PGSR0_WDERR,
},
{
"Read Eye Training",
MPHY_PIR_RDEYE,
MPHY_PGSR0_REDONE,
MPHY_PGSR0_REERR,
},
{
"Write Eye Training",
MPHY_PIR_WREYE,
MPHY_PGSR0_WEDONE,
MPHY_PGSR0_WEERR,
},
{ /* sentinel */ }
};
static int __ddrphy_training(void __iomem *phy_base,
const struct ddrphy_init_sequence *seq)
{
const struct ddrphy_init_sequence *s;
u32 pgsr0;
u32 init_flag = MPHY_PIR_INIT;
u32 done_flag = MPHY_PGSR0_IDONE;
int timeout = 50000; /* 50 msec is long enough */
unsigned long start = 0;
#ifdef DEBUG
start = get_timer(0);
#endif
for (s = seq; s->description; s++) {
init_flag |= s->init_flag;
done_flag |= s->done_flag;
}
writel(init_flag, phy_base + MPHY_PIR);
do {
if (--timeout < 0) {
pr_err("%s: error: timeout during DDR training\n",
__func__);
return -ETIMEDOUT;
}
udelay(1);
pgsr0 = readl(phy_base + MPHY_PGSR0);
} while ((pgsr0 & done_flag) != done_flag);
for (s = seq; s->description; s++) {
if (pgsr0 & s->err_flag) {
pr_err("%s: error: %s failed\n", __func__,
s->description);
return -EIO;
}
}
pr_debug("DDRPHY training: elapsed time %ld msec\n", get_timer(start));
return 0;
}
static int ddrphy_impedance_calibration(void __iomem *phy_base)
{
int ret;
u32 tmp;
ret = __ddrphy_training(phy_base, impedance_calibration_sequence);
if (ret)
return ret;
/*
* Because of a hardware bug, IDONE flag is set when the first ZQ block
* is calibrated. The flag does not guarantee the completion for all
* the ZQ blocks. Wait a little more just in case.
*/
udelay(1);
/* reflect ZQ settings and enable average algorithm*/
tmp = readl(phy_base + MPHY_ZQCR);
tmp |= MPHY_ZQCR_FORCE_ZCAL_VT_UPDATE;
writel(tmp, phy_base + MPHY_ZQCR);
tmp &= ~MPHY_ZQCR_FORCE_ZCAL_VT_UPDATE;
tmp |= MPHY_ZQCR_AVGEN;
writel(tmp, phy_base + MPHY_ZQCR);
return 0;
}
static int ddrphy_dram_init(void __iomem *phy_base)
{
return __ddrphy_training(phy_base, dram_init_sequence);
}
static int ddrphy_training(void __iomem *phy_base)
{
return __ddrphy_training(phy_base, training_sequence);
}
/* UMC */
static u32 umc_cmdctla[DRAM_FREQ_NR] = {0x66DD131D, 0x77EE1722};
/*
* The ch2 is a different generation UMC core.
* The register spec is different, unfortunately.
*/
static u32 umc_cmdctlb_ch01[DRAM_FREQ_NR] = {0x13E87C44, 0x18F88C44};
static u32 umc_cmdctlb_ch2[DRAM_FREQ_NR] = {0x19E8DC44, 0x1EF8EC44};
static u32 umc_spcctla[DRAM_FREQ_NR][DRAM_SZ_NR] = {
{0x004A071D, 0x0078071D},
{0x0055081E, 0x0089081E},
};
static u32 umc_spcctlb[] = {0x00FF000A, 0x00FF000B};
/* The ch2 is different for some reason only hardware guys know... */
static u32 umc_flowctla_ch01[] = {0x0800001E, 0x08000022};
static u32 umc_flowctla_ch2[] = {0x0800001E, 0x0800001E};
static void umc_set_system_latency(void __iomem *dc_base, int phy_latency)
{
u32 val;
int latency;
val = readl(dc_base + UMC_RDATACTL_D0);
latency = (val & UMC_RDATACTL_RADLTY_MASK) >> UMC_RDATACTL_RADLTY_SHIFT;
latency += (val & UMC_RDATACTL_RAD2LTY_MASK) >>
UMC_RDATACTL_RAD2LTY_SHIFT;
/*
* UMC works at the half clock rate of the PHY.
* The LSB of latency is ignored
*/
latency += phy_latency & ~1;
val &= ~(UMC_RDATACTL_RADLTY_MASK | UMC_RDATACTL_RAD2LTY_MASK);
if (latency > 0xf) {
val |= 0xf << UMC_RDATACTL_RADLTY_SHIFT;
val |= (latency - 0xf) << UMC_RDATACTL_RAD2LTY_SHIFT;
} else {
val |= latency << UMC_RDATACTL_RADLTY_SHIFT;
}
writel(val, dc_base + UMC_RDATACTL_D0);
writel(val, dc_base + UMC_RDATACTL_D1);
readl(dc_base + UMC_RDATACTL_D1); /* relax */
}
/* enable/disable auto refresh */
static void umc_refresh_ctrl(void __iomem *dc_base, int enable)
{
u32 tmp;
tmp = readl(dc_base + UMC_SPCSETB);
tmp &= ~UMC_SPCSETB_AREFMD_MASK;
if (enable)
tmp |= UMC_SPCSETB_AREFMD_ARB;
else
tmp |= UMC_SPCSETB_AREFMD_REG;
writel(tmp, dc_base + UMC_SPCSETB);
udelay(1);
}
static void umc_ud_init(void __iomem *umc_base, int ch)
{
writel(0x00000003, umc_base + UMC_BITPERPIXELMODE_D0);
if (ch == 2)
writel(0x00000033, umc_base + UMC_PAIR1DOFF_D0);
}
static int umc_dc_init(void __iomem *dc_base, enum dram_freq freq,
unsigned long size, int width, int ch)
{
enum dram_size size_e;
int latency;
u32 val;
switch (size) {
case 0:
return 0;
case SZ_256M:
size_e = DRAM_SZ_256M;
break;
case SZ_512M:
size_e = DRAM_SZ_512M;
break;
default:
pr_err("unsupported DRAM size 0x%08lx (per 16bit) for ch%d\n",
size, ch);
return -EINVAL;
}
writel(umc_cmdctla[freq], dc_base + UMC_CMDCTLA);
writel(ch == 2 ? umc_cmdctlb_ch2[freq] : umc_cmdctlb_ch01[freq],
dc_base + UMC_CMDCTLB);
writel(umc_spcctla[freq][size_e], dc_base + UMC_SPCCTLA);
writel(umc_spcctlb[freq], dc_base + UMC_SPCCTLB);
val = 0x000e000e;
latency = 12;
/* ES2 inserted one more FF to the logic. */
if (uniphier_get_soc_model() >= 2)
latency += 2;
if (latency > 0xf) {
val |= 0xf << UMC_RDATACTL_RADLTY_SHIFT;
val |= (latency - 0xf) << UMC_RDATACTL_RAD2LTY_SHIFT;
} else {
val |= latency << UMC_RDATACTL_RADLTY_SHIFT;
}
writel(val, dc_base + UMC_RDATACTL_D0);
if (width >= 32)
writel(val, dc_base + UMC_RDATACTL_D1);
writel(0x04060A02, dc_base + UMC_WDATACTL_D0);
if (width >= 32)
writel(0x04060A02, dc_base + UMC_WDATACTL_D1);
writel(0x04000000, dc_base + UMC_DATASET);
writel(0x00400020, dc_base + UMC_DCCGCTL);
writel(0x00000084, dc_base + UMC_FLOWCTLG);
writel(0x00000000, dc_base + UMC_ACSSETA);
writel(ch == 2 ? umc_flowctla_ch2[freq] : umc_flowctla_ch01[freq],
dc_base + UMC_FLOWCTLA);
writel(0x00004400, dc_base + UMC_FLOWCTLC);
writel(0x200A0A00, dc_base + UMC_SPCSETB);
writel(0x00000520, dc_base + UMC_DFICUPDCTLA);
writel(0x0000000D, dc_base + UMC_RESPCTL);
if (ch != 2) {
writel(0x00202000, dc_base + UMC_FLOWCTLB);
writel(0xFDBFFFFF, dc_base + UMC_FLOWCTLOB0);
writel(0xFFFFFFFF, dc_base + UMC_FLOWCTLOB1);
writel(0x00080700, dc_base + UMC_BSICMAPSET);
} else {
writel(0x00200000, dc_base + UMC_FLOWCTLB);
writel(0x00000000, dc_base + UMC_BSICMAPSET);
}
writel(0x00000000, dc_base + UMC_ERRMASKA);
writel(0x00000000, dc_base + UMC_ERRMASKB);
return 0;
}
static int umc_ch_init(void __iomem *umc_ch_base, enum dram_freq freq,
unsigned long size, unsigned int width, int ch)
{
void __iomem *dc_base = umc_ch_base + 0x00011000;
void __iomem *phy_base = umc_ch_base + 0x00030000;
int ret;
writel(0x00000002, dc_base + UMC_INITSET);
while (readl(dc_base + UMC_INITSTAT) & BIT(2))
cpu_relax();
/* deassert PHY reset signals */
writel(UMC_DIOCTLA_CTL_NRST | UMC_DIOCTLA_CFG_NRST,
dc_base + UMC_DIOCTLA);
ddrphy_init(phy_base, freq, width, ch);
ret = ddrphy_impedance_calibration(phy_base);
if (ret)
return ret;
ddrphy_dram_init(phy_base);
if (ret)
return ret;
ret = umc_dc_init(dc_base, freq, size, width, ch);
if (ret)
return ret;
umc_ud_init(umc_ch_base, ch);
ret = ddrphy_training(phy_base);
if (ret)
return ret;
udelay(1);
/* match the system latency between UMC and PHY */
umc_set_system_latency(dc_base,
ddrphy_get_system_latency(phy_base, width));
udelay(1);
/* stop auto refresh before clearing FIFO in PHY */
umc_refresh_ctrl(dc_base, 0);
ddrphy_fifo_reset(phy_base);
umc_refresh_ctrl(dc_base, 1);
udelay(10);
return 0;
}
static void um_init(void __iomem *um_base)
{
writel(0x000000ff, um_base + UMC_MBUS0);
writel(0x000000ff, um_base + UMC_MBUS1);
writel(0x000000ff, um_base + UMC_MBUS2);
writel(0x000000ff, um_base + UMC_MBUS3);
}
int uniphier_pxs2_umc_init(const struct uniphier_board_data *bd)
{
void __iomem *um_base = (void __iomem *)0x5b600000;
void __iomem *umc_ch_base = (void __iomem *)0x5b800000;
enum dram_freq freq;
int ch, ret;
switch (bd->dram_freq) {
case 1866:
freq = DRAM_FREQ_1866M;
break;
case 2133:
freq = DRAM_FREQ_2133M;
break;
default:
pr_err("unsupported DRAM frequency %d MHz\n", bd->dram_freq);
return -EINVAL;
}
for (ch = 0; ch < DRAM_CH_NR; ch++) {
unsigned long size = bd->dram_ch[ch].size;
unsigned int width = bd->dram_ch[ch].width;
if (size) {
ret = umc_ch_init(umc_ch_base, freq,
size / (width / 16), width, ch);
if (ret) {
pr_err("failed to initialize UMC ch%d\n", ch);
return ret;
}
}
umc_ch_base += 0x00200000;
}
um_init(um_base);
return 0;
}
@@ -0,0 +1,106 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* UniPhier UMC (Universal Memory Controller) registers
*
* Copyright (C) 2011-2014 Panasonic Corporation
*/
#ifndef ARCH_UMC_REGS_H
#define ARCH_UMC_REGS_H
#include <linux/bitops.h>
#define UMC_CPURST 0x00000700
#define UMC_IDSRST 0x0000070C
#define UMC_IXMRST 0x00000714
#define UMC_HDMRST 0x00000718
#define UMC_MDMRST 0x0000071C
#define UMC_HDDRST 0x00000720
#define UMC_MDDRST 0x00000724
#define UMC_SIORST 0x00000728
#define UMC_GIORST 0x0000072C
#define UMC_HD2RST 0x00000734
#define UMC_VIORST 0x0000073C
#define UMC_FRCRST 0x00000748 /* LD4/sLD8 */
#define UMC_DVCRST 0x00000748 /* Pro4 */
#define UMC_RGLRST 0x00000750
#define UMC_VPERST 0x00000758
#define UMC_AIORST 0x00000764
#define UMC_DMDRST 0x00000770
#define UMC_HDMCHSEL 0x00000898
#define UMC_MDMCHSEL 0x0000089C
#define UMC_DVCCHSEL 0x000008C8
#define UMC_DMDCHSEL 0x000008F0
#define UMC_CLKEN_SSIF_FETCH 0x0000C060
#define UMC_CLKEN_SSIF_COMQUE0 0x0000C064
#define UMC_CLKEN_SSIF_COMWC0 0x0000C068
#define UMC_CLKEN_SSIF_COMRC0 0x0000C06C
#define UMC_CLKEN_SSIF_COMQUE1 0x0000C070
#define UMC_CLKEN_SSIF_COMWC1 0x0000C074
#define UMC_CLKEN_SSIF_COMRC1 0x0000C078
#define UMC_CLKEN_SSIF_WC 0x0000C07C
#define UMC_CLKEN_SSIF_RC 0x0000C080
#define UMC_CLKEN_SSIF_DST 0x0000C084
#define UMC_CMDCTLA 0x00000000
#define UMC_CMDCTLB 0x00000004
#define UMC_INITSET 0x00000014
#define UMC_INITSET_INIT1EN BIT(1) /* init without power-on wait */
#define UMC_INITSET_INIT0EN BIT(0) /* init with power-on wait */
#define UMC_INITSTAT 0x00000018
#define UMC_INITSTAT_INIT1ST BIT(1) /* init without power-on wait */
#define UMC_INITSTAT_INIT0ST BIT(0) /* init with power-on wait */
#define UMC_SPCCTLA 0x00000030
#define UMC_SPCCTLB 0x00000034
#define UMC_SPCSETA 0x00000038
#define UMC_SPCSETB 0x0000003C
#define UMC_SPCSETB_AREFMD_MASK (0x3) /* Auto Refresh Mode */
#define UMC_SPCSETB_AREFMD_ARB (0x0) /* control by arbitor */
#define UMC_SPCSETB_AREFMD_CONT (0x1) /* control by DRAMCONT */
#define UMC_SPCSETB_AREFMD_REG (0x2) /* control by register */
#define UMC_SPCSETC 0x00000040
#define UMC_SPCSETD 0x00000044
#define UMC_SPCSTATA 0x00000050
#define UMC_SPCSTATB 0x00000054
#define UMC_SPCSTATC 0x00000058
#define UMC_ACSSETA 0x00000060
#define UMC_FLOWCTLA 0x00000400
#define UMC_FLOWCTLB 0x00000404
#define UMC_FLOWCTLC 0x00000408
#define UMC_FLOWCTLG 0x00000508
#define UMC_FLOWCTLOB0 0x00000520
#define UMC_FLOWCTLOB1 0x00000524
#define UMC_RDATACTL_D0 0x00000600
#define UMC_RDATACTL_RADLTY_SHIFT 4
#define UMC_RDATACTL_RADLTY_MASK (0xf << (UMC_RDATACTL_RADLTY_SHIFT))
#define UMC_RDATACTL_RAD2LTY_SHIFT 8
#define UMC_RDATACTL_RAD2LTY_MASK (0xf << (UMC_RDATACTL_RAD2LTY_SHIFT))
#define UMC_WDATACTL_D0 0x00000604
#define UMC_RDATACTL_D1 0x00000608
#define UMC_WDATACTL_D1 0x0000060C
#define UMC_DATASET 0x00000610
#define UMC_RESPCTL 0x00000624
#define UMC_DCCGCTL 0x00000720
#define UMC_DICGCTLA 0x00000724
#define UMC_DICGCTLB 0x00000728
#define UMC_ERRMASKA 0x00000958
#define UMC_ERRMASKB 0x0000095c
#define UMC_BSICMAPSET 0x00000988
#define UMC_DIOCTLA 0x00000C00
#define UMC_DIOCTLA_CTL_NRST BIT(8) /* ctl_rst_n */
#define UMC_DIOCTLA_CFG_NRST BIT(0) /* cfg_rst_n */
#define UMC_DFICUPDCTLA 0x00000C20
/* UM registers */
#define UMC_MBUS0 0x00080004
#define UMC_MBUS1 0x00081004
#define UMC_MBUS2 0x00082004
#define UMC_MBUS3 0x00083004
/* UD registers */
#define UMC_BITPERPIXELMODE_D0 0x010
#define UMC_PAIR1DOFF_D0 0x054
#endif
@@ -0,0 +1,195 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2011-2014 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/sizes.h>
#include <asm/processor.h>
#include "../init.h"
#include "ddrphy-init.h"
#include "umc-regs.h"
#define DRAM_CH_NR 2
enum dram_freq {
DRAM_FREQ_1333M,
DRAM_FREQ_1600M,
DRAM_FREQ_NR,
};
enum dram_size {
DRAM_SZ_128M,
DRAM_SZ_256M,
DRAM_SZ_512M,
DRAM_SZ_NR,
};
static u32 umc_cmdctla[DRAM_FREQ_NR] = {0x55990b11, 0x66bb0f17};
static u32 umc_cmdctla_plus[DRAM_FREQ_NR] = {0x45990b11, 0x46bb0f17};
static u32 umc_cmdctlb[DRAM_FREQ_NR] = {0x16958944, 0x18c6ab44};
static u32 umc_cmdctlb_plus[DRAM_FREQ_NR] = {0x16958924, 0x18c6ab24};
static u32 umc_spcctla[DRAM_FREQ_NR][DRAM_SZ_NR] = {
{0x00240512, 0x00350512, 0x00000000}, /* no data for 1333MHz,128MB */
{0x002b0617, 0x003f0617, 0x00670617},
};
static u32 umc_spcctlb[DRAM_FREQ_NR] = {0x00ff0006, 0x00ff0008};
static u32 umc_rdatactl[DRAM_FREQ_NR] = {0x000a00ac, 0x000c00ac};
static int umc_get_rank(int ch)
{
return ch; /* ch0: rank0, ch1: rank1 for this SoC */
}
static void umc_start_ssif(void __iomem *ssif_base)
{
writel(0x00000000, ssif_base + 0x0000b004);
writel(0xffffffff, ssif_base + 0x0000c004);
writel(0x000fffcf, ssif_base + 0x0000c008);
writel(0x00000001, ssif_base + 0x0000b000);
writel(0x00000001, ssif_base + 0x0000c000);
writel(0x03010101, ssif_base + UMC_MDMCHSEL);
writel(0x03010100, ssif_base + UMC_DMDCHSEL);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_FETCH);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMQUE0);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMWC0);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMRC0);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMQUE1);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMWC1);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMRC1);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_WC);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_RC);
writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_DST);
writel(0x00000001, ssif_base + UMC_CPURST);
writel(0x00000001, ssif_base + UMC_IDSRST);
writel(0x00000001, ssif_base + UMC_IXMRST);
writel(0x00000001, ssif_base + UMC_MDMRST);
writel(0x00000001, ssif_base + UMC_MDDRST);
writel(0x00000001, ssif_base + UMC_SIORST);
writel(0x00000001, ssif_base + UMC_VIORST);
writel(0x00000001, ssif_base + UMC_FRCRST);
writel(0x00000001, ssif_base + UMC_RGLRST);
writel(0x00000001, ssif_base + UMC_AIORST);
writel(0x00000001, ssif_base + UMC_DMDRST);
}
static int umc_dramcont_init(void __iomem *dc_base, void __iomem *ca_base,
int freq, unsigned long size, bool ddr3plus)
{
enum dram_freq freq_e;
enum dram_size size_e;
switch (freq) {
case 1333:
freq_e = DRAM_FREQ_1333M;
break;
case 1600:
freq_e = DRAM_FREQ_1600M;
break;
default:
pr_err("unsupported DRAM frequency %d MHz\n", freq);
return -EINVAL;
}
switch (size) {
case 0:
return 0;
case SZ_128M:
size_e = DRAM_SZ_128M;
break;
case SZ_256M:
size_e = DRAM_SZ_256M;
break;
case SZ_512M:
size_e = DRAM_SZ_512M;
break;
default:
pr_err("unsupported DRAM size 0x%08lx\n", size);
return -EINVAL;
}
writel((ddr3plus ? umc_cmdctla_plus : umc_cmdctla)[freq_e],
dc_base + UMC_CMDCTLA);
writel((ddr3plus ? umc_cmdctlb_plus : umc_cmdctlb)[freq_e],
dc_base + UMC_CMDCTLB);
writel(umc_spcctla[freq_e][size_e], dc_base + UMC_SPCCTLA);
writel(umc_spcctlb[freq_e], dc_base + UMC_SPCCTLB);
writel(umc_rdatactl[freq_e], dc_base + UMC_RDATACTL_D0);
writel(0x04060806, dc_base + UMC_WDATACTL_D0);
writel(0x04a02000, dc_base + UMC_DATASET);
writel(0x00000000, ca_base + 0x2300);
writel(0x00400020, dc_base + UMC_DCCGCTL);
writel(0x00000003, dc_base + 0x7000);
writel(0x0000004f, dc_base + 0x8000);
writel(0x000000c3, dc_base + 0x8004);
writel(0x00000077, dc_base + 0x8008);
writel(0x0000003b, dc_base + UMC_DICGCTLA);
writel(0x020a0808, dc_base + UMC_DICGCTLB);
writel(0x00000004, dc_base + UMC_FLOWCTLG);
writel(0x80000201, ca_base + 0xc20);
writel(0x0801e01e, dc_base + UMC_FLOWCTLA);
writel(0x00200000, dc_base + UMC_FLOWCTLB);
writel(0x00004444, dc_base + UMC_FLOWCTLC);
writel(0x200a0a00, dc_base + UMC_SPCSETB);
writel(0x00000000, dc_base + UMC_SPCSETD);
writel(0x00000520, dc_base + UMC_DFICUPDCTLA);
return 0;
}
static int umc_ch_init(void __iomem *dc_base, void __iomem *ca_base,
int freq, unsigned long size, bool ddr3plus, int ch)
{
void __iomem *phy_base = dc_base + 0x00001000;
int ret;
writel(UMC_INITSET_INIT1EN, dc_base + UMC_INITSET);
while (readl(dc_base + UMC_INITSTAT) & UMC_INITSTAT_INIT1ST)
cpu_relax();
writel(0x00000101, dc_base + UMC_DIOCTLA);
ret = uniphier_ld4_ddrphy_init(phy_base, freq, ddr3plus);
if (ret)
return ret;
ddrphy_prepare_training(phy_base, umc_get_rank(ch));
ret = ddrphy_training(phy_base);
if (ret)
return ret;
return umc_dramcont_init(dc_base, ca_base, freq, size, ddr3plus);
}
int uniphier_sld8_umc_init(const struct uniphier_board_data *bd)
{
void __iomem *umc_base = (void __iomem *)0x5b800000;
void __iomem *ca_base = umc_base + 0x00001000;
void __iomem *dc_base = umc_base + 0x00400000;
void __iomem *ssif_base = umc_base;
int ch, ret;
for (ch = 0; ch < DRAM_CH_NR; ch++) {
ret = umc_ch_init(dc_base, ca_base, bd->dram_freq,
bd->dram_ch[ch].size,
!!(bd->flags & UNIPHIER_BD_DDR3PLUS), ch);
if (ret) {
pr_err("failed to initialize UMC ch%d\n", ch);
return ret;
}
ca_base += 0x00001000;
dc_base += 0x00200000;
}
umc_start_ssif(ssif_base);
return 0;
}
@@ -0,0 +1,308 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2012-2015 Panasonic Corporation
* Copyright (C) 2015-2017 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/printk.h>
#include <linux/sizes.h>
#include <asm/global_data.h>
#include "init.h"
#include "sg-regs.h"
#include "soc-info.h"
DECLARE_GLOBAL_DATA_PTR;
struct uniphier_dram_map {
unsigned long base;
unsigned long size;
};
static int uniphier_memconf_decode(struct uniphier_dram_map *dram_map,
unsigned long sparse_ch1_base, bool have_ch2)
{
unsigned long size;
u32 val;
val = readl(sg_base + SG_MEMCONF);
/* set up ch0 */
dram_map[0].base = 0x80000000;
switch (val & SG_MEMCONF_CH0_SZ_MASK) {
case SG_MEMCONF_CH0_SZ_64M:
size = SZ_64M;
break;
case SG_MEMCONF_CH0_SZ_128M:
size = SZ_128M;
break;
case SG_MEMCONF_CH0_SZ_256M:
size = SZ_256M;
break;
case SG_MEMCONF_CH0_SZ_512M:
size = SZ_512M;
break;
case SG_MEMCONF_CH0_SZ_1G:
size = SZ_1G;
break;
default:
pr_err("error: invalid value is set to MEMCONF ch0 size\n");
return -EINVAL;
}
if ((val & SG_MEMCONF_CH0_NUM_MASK) == SG_MEMCONF_CH0_NUM_2)
size *= 2;
dram_map[0].size = size;
/* set up ch1 */
dram_map[1].base = dram_map[0].base + size;
if (val & SG_MEMCONF_SPARSEMEM) {
if (dram_map[1].base > sparse_ch1_base) {
pr_warn("Sparse mem is enabled, but ch0 and ch1 overlap\n");
pr_warn("Only ch0 is available\n");
dram_map[1].base = 0;
return 0;
}
dram_map[1].base = sparse_ch1_base;
}
switch (val & SG_MEMCONF_CH1_SZ_MASK) {
case SG_MEMCONF_CH1_SZ_64M:
size = SZ_64M;
break;
case SG_MEMCONF_CH1_SZ_128M:
size = SZ_128M;
break;
case SG_MEMCONF_CH1_SZ_256M:
size = SZ_256M;
break;
case SG_MEMCONF_CH1_SZ_512M:
size = SZ_512M;
break;
case SG_MEMCONF_CH1_SZ_1G:
size = SZ_1G;
break;
default:
pr_err("error: invalid value is set to MEMCONF ch1 size\n");
return -EINVAL;
}
if ((val & SG_MEMCONF_CH1_NUM_MASK) == SG_MEMCONF_CH1_NUM_2)
size *= 2;
dram_map[1].size = size;
if (!have_ch2 || val & SG_MEMCONF_CH2_DISABLE)
return 0;
/* set up ch2 */
dram_map[2].base = dram_map[1].base + size;
switch (val & SG_MEMCONF_CH2_SZ_MASK) {
case SG_MEMCONF_CH2_SZ_64M:
size = SZ_64M;
break;
case SG_MEMCONF_CH2_SZ_128M:
size = SZ_128M;
break;
case SG_MEMCONF_CH2_SZ_256M:
size = SZ_256M;
break;
case SG_MEMCONF_CH2_SZ_512M:
size = SZ_512M;
break;
case SG_MEMCONF_CH2_SZ_1G:
size = SZ_1G;
break;
default:
pr_err("error: invalid value is set to MEMCONF ch2 size\n");
return -EINVAL;
}
if ((val & SG_MEMCONF_CH2_NUM_MASK) == SG_MEMCONF_CH2_NUM_2)
size *= 2;
dram_map[2].size = size;
return 0;
}
static int uniphier_ld4_dram_map_get(struct uniphier_dram_map dram_map[])
{
return uniphier_memconf_decode(dram_map, 0xc0000000, false);
}
static int uniphier_pro4_dram_map_get(struct uniphier_dram_map dram_map[])
{
return uniphier_memconf_decode(dram_map, 0xa0000000, false);
}
static int uniphier_pxs2_dram_map_get(struct uniphier_dram_map dram_map[])
{
return uniphier_memconf_decode(dram_map, 0xc0000000, true);
}
struct uniphier_dram_init_data {
unsigned int soc_id;
int (*dram_map_get)(struct uniphier_dram_map dram_map[]);
};
static const struct uniphier_dram_init_data uniphier_dram_init_data[] = {
{
.soc_id = UNIPHIER_LD4_ID,
.dram_map_get = uniphier_ld4_dram_map_get,
},
{
.soc_id = UNIPHIER_PRO4_ID,
.dram_map_get = uniphier_pro4_dram_map_get,
},
{
.soc_id = UNIPHIER_SLD8_ID,
.dram_map_get = uniphier_ld4_dram_map_get,
},
{
.soc_id = UNIPHIER_PRO5_ID,
.dram_map_get = uniphier_ld4_dram_map_get,
},
{
.soc_id = UNIPHIER_PXS2_ID,
.dram_map_get = uniphier_pxs2_dram_map_get,
},
{
.soc_id = UNIPHIER_LD6B_ID,
.dram_map_get = uniphier_pxs2_dram_map_get,
},
{
.soc_id = UNIPHIER_LD11_ID,
.dram_map_get = uniphier_ld4_dram_map_get,
},
{
.soc_id = UNIPHIER_LD20_ID,
.dram_map_get = uniphier_pxs2_dram_map_get,
},
{
.soc_id = UNIPHIER_PXS3_ID,
.dram_map_get = uniphier_pxs2_dram_map_get,
},
};
UNIPHIER_DEFINE_SOCDATA_FUNC(uniphier_get_dram_init_data,
uniphier_dram_init_data)
static int uniphier_dram_map_get(struct uniphier_dram_map *dram_map)
{
const struct uniphier_dram_init_data *data;
data = uniphier_get_dram_init_data();
if (!data) {
pr_err("unsupported SoC\n");
return -ENOTSUPP;
}
return data->dram_map_get(dram_map);
}
int dram_init(void)
{
struct uniphier_dram_map dram_map[3] = {};
bool valid_bank_found = false;
unsigned long prev_top;
int ret, i;
gd->ram_size = 0;
ret = uniphier_dram_map_get(dram_map);
if (ret)
return ret;
for (i = 0; i < ARRAY_SIZE(dram_map); i++) {
unsigned long max_size;
if (!dram_map[i].size)
continue;
/*
* U-Boot relocates itself to the tail of the memory region,
* but it does not expect sparse memory. We use the first
* contiguous chunk here.
*/
if (valid_bank_found && prev_top < dram_map[i].base)
break;
/*
* Do not use memory that exceeds 32bit address range. U-Boot
* relocates itself to the end of the effectively available RAM.
* This could be a problem for DMA engines that do not support
* 64bit address (SDMA of SDHCI, UniPhier AV-ether, etc.)
*/
if (dram_map[i].base >= 1ULL << 32)
break;
max_size = (1ULL << 32) - dram_map[i].base;
if (dram_map[i].size > max_size) {
gd->ram_size += max_size;
break;
}
gd->ram_size += dram_map[i].size;
if (!valid_bank_found)
gd->ram_base = dram_map[i].base;
prev_top = dram_map[i].base + dram_map[i].size;
valid_bank_found = true;
}
/*
* LD20 uses the last 64 byte for each channel for dynamic
* DDR PHY training
*/
if (uniphier_get_soc_id() == UNIPHIER_LD20_ID)
gd->ram_size -= 64;
return 0;
}
int dram_init_banksize(void)
{
struct uniphier_dram_map dram_map[3] = {};
unsigned long base, top;
bool valid_bank_found = false;
int ret, i;
ret = uniphier_dram_map_get(dram_map);
if (ret)
return ret;
for (i = 0; i < ARRAY_SIZE(dram_map); i++) {
if (i < ARRAY_SIZE(gd->bd->bi_dram)) {
gd->bd->bi_dram[i].start = dram_map[i].base;
gd->bd->bi_dram[i].size = dram_map[i].size;
}
if (!dram_map[i].size)
continue;
if (!valid_bank_found)
base = dram_map[i].base;
top = dram_map[i].base + dram_map[i].size;
valid_bank_found = true;
}
if (!valid_bank_found)
return -EINVAL;
/* map all the DRAM regions */
uniphier_mem_map_init(base, top - base);
return 0;
}
@@ -0,0 +1,64 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016-2018 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <fdt_support.h>
#include <fdtdec.h>
#include <jffs2/load_kernel.h>
#include <mtd_node.h>
#include <linux/kernel.h>
#include <linux/printk.h>
#include "soc-info.h"
/*
* The DRAM PHY requires 64 byte scratch area in each DRAM channel
* for its dynamic PHY training feature.
*/
static int uniphier_ld20_fdt_mem_rsv(void *fdt, bd_t *bd)
{
unsigned long rsv_addr;
const unsigned long rsv_size = 64;
int i, ret;
if (!IS_ENABLED(CONFIG_ARCH_UNIPHIER_LD20) ||
uniphier_get_soc_id() != UNIPHIER_LD20_ID)
return 0;
for (i = 0; i < ARRAY_SIZE(bd->bi_dram); i++) {
if (!bd->bi_dram[i].size)
continue;
rsv_addr = bd->bi_dram[i].start + bd->bi_dram[i].size;
rsv_addr -= rsv_size;
ret = fdt_add_mem_rsv(fdt, rsv_addr, rsv_size);
if (ret)
return -ENOSPC;
pr_notice(" Reserved memory region for DRAM PHY training: addr=%lx size=%lx\n",
rsv_addr, rsv_size);
}
return 0;
}
int ft_board_setup(void *fdt, bd_t *bd)
{
static const struct node_info nodes[] = {
{ "socionext,uniphier-denali-nand-v5a", MTD_DEV_TYPE_NAND },
{ "socionext,uniphier-denali-nand-v5b", MTD_DEV_TYPE_NAND },
};
int ret;
fdt_fixup_mtdparts(fdt, nodes, ARRAY_SIZE(nodes));
ret = uniphier_ld20_fdt_mem_rsv(fdt, bd);
if (ret)
return ret;
return 0;
}
@@ -0,0 +1,114 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2015-2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#ifndef __MACH_INIT_H
#define __MACH_INIT_H
#include <linux/types.h>
#define UNIPHIER_MAX_NR_DRAM_CH 3
struct uniphier_dram_ch {
unsigned long size;
unsigned int width;
};
struct uniphier_board_data {
unsigned int dram_freq;
struct uniphier_dram_ch dram_ch[UNIPHIER_MAX_NR_DRAM_CH];
unsigned int flags;
#define UNIPHIER_BD_DRAM_SPARSE BIT(9)
#define UNIPHIER_BD_DDR3PLUS BIT(8)
};
const struct uniphier_board_data *uniphier_get_board_param(void);
int uniphier_ld4_init(const struct uniphier_board_data *bd);
int uniphier_pro4_init(const struct uniphier_board_data *bd);
int uniphier_sld8_init(const struct uniphier_board_data *bd);
int uniphier_pro5_init(const struct uniphier_board_data *bd);
int uniphier_pxs2_init(const struct uniphier_board_data *bd);
#if defined(CONFIG_MICRO_SUPPORT_CARD)
void uniphier_sbc_init_admulti(void);
void uniphier_sbc_init_savepin(void);
void uniphier_ld4_sbc_init(void);
void uniphier_pxs2_sbc_init(void);
void uniphier_ld11_sbc_init(void);
#else
static inline void uniphier_sbc_init_admulti(void)
{
}
static inline void uniphier_sbc_init_savepin(void)
{
}
static inline void uniphier_ld4_sbc_init(void)
{
}
static inline void uniphier_pxs2_sbc_init(void)
{
}
static inline void uniphier_ld11_sbc_init(void)
{
}
#endif
void uniphier_ld4_bcu_init(const struct uniphier_board_data *bd);
int uniphier_memconf_2ch_init(const struct uniphier_board_data *bd);
int uniphier_memconf_3ch_init(const struct uniphier_board_data *bd);
int uniphier_ld4_dpll_init(const struct uniphier_board_data *bd);
int uniphier_pro4_dpll_init(const struct uniphier_board_data *bd);
int uniphier_sld8_dpll_init(const struct uniphier_board_data *bd);
int uniphier_pro5_dpll_init(const struct uniphier_board_data *bd);
int uniphier_pxs2_dpll_init(const struct uniphier_board_data *bd);
void uniphier_ld4_early_clk_init(void);
void uniphier_ld4_dram_clk_init(void);
void uniphier_pro5_dram_clk_init(void);
void uniphier_pxs2_dram_clk_init(void);
int uniphier_ld4_umc_init(const struct uniphier_board_data *bd);
int uniphier_pro4_umc_init(const struct uniphier_board_data *bd);
int uniphier_sld8_umc_init(const struct uniphier_board_data *bd);
int uniphier_pro5_umc_init(const struct uniphier_board_data *bd);
int uniphier_pxs2_umc_init(const struct uniphier_board_data *bd);
void uniphier_ld4_pll_init(void);
void uniphier_pro4_pll_init(void);
void uniphier_ld11_pll_init(void);
void uniphier_ld20_pll_init(void);
void uniphier_pxs3_pll_init(void);
void uniphier_ld4_clk_init(void);
void uniphier_pro4_clk_init(void);
void uniphier_pro5_clk_init(void);
void uniphier_pxs2_clk_init(void);
void uniphier_ld11_clk_init(void);
void uniphier_ld20_clk_init(void);
void uniphier_pxs3_clk_init(void);
unsigned int uniphier_boot_device_raw(void);
int uniphier_have_internal_stm(void);
int uniphier_boot_from_backend(void);
int uniphier_pin_init(const char *pinconfig_name);
#ifdef CONFIG_ARM64
void uniphier_mem_map_init(unsigned long dram_base, unsigned long dram_size);
#else
static inline void uniphier_mem_map_init(unsigned long dram_base,
unsigned long dram_size)
{
}
#endif
#endif /* __MACH_INIT_H */
@@ -0,0 +1,156 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2011-2015 Panasonic Corporation
* Copyright (C) 2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/sizes.h>
#include "sg-regs.h"
#include "init.h"
static int __uniphier_memconf_init(const struct uniphier_board_data *bd,
int have_ch2)
{
u32 val = 0;
unsigned long size_per_word;
/* set up ch0 */
switch (bd->dram_ch[0].width) {
case 16:
val |= SG_MEMCONF_CH0_NUM_1;
size_per_word = bd->dram_ch[0].size;
break;
case 32:
val |= SG_MEMCONF_CH0_NUM_2;
size_per_word = bd->dram_ch[0].size >> 1;
break;
default:
pr_err("error: unsupported DRAM ch0 width\n");
return -EINVAL;
}
switch (size_per_word) {
case SZ_64M:
val |= SG_MEMCONF_CH0_SZ_64M;
break;
case SZ_128M:
val |= SG_MEMCONF_CH0_SZ_128M;
break;
case SZ_256M:
val |= SG_MEMCONF_CH0_SZ_256M;
break;
case SZ_512M:
val |= SG_MEMCONF_CH0_SZ_512M;
break;
case SZ_1G:
val |= SG_MEMCONF_CH0_SZ_1G;
break;
default:
pr_err("error: unsupported DRAM ch0 size\n");
return -EINVAL;
}
/* set up ch1 */
switch (bd->dram_ch[1].width) {
case 16:
val |= SG_MEMCONF_CH1_NUM_1;
size_per_word = bd->dram_ch[1].size;
break;
case 32:
val |= SG_MEMCONF_CH1_NUM_2;
size_per_word = bd->dram_ch[1].size >> 1;
break;
default:
pr_err("error: unsupported DRAM ch1 width\n");
return -EINVAL;
}
switch (size_per_word) {
case SZ_64M:
val |= SG_MEMCONF_CH1_SZ_64M;
break;
case SZ_128M:
val |= SG_MEMCONF_CH1_SZ_128M;
break;
case SZ_256M:
val |= SG_MEMCONF_CH1_SZ_256M;
break;
case SZ_512M:
val |= SG_MEMCONF_CH1_SZ_512M;
break;
case SZ_1G:
val |= SG_MEMCONF_CH1_SZ_1G;
break;
default:
pr_err("error: unsupported DRAM ch1 size\n");
return -EINVAL;
}
/* is sparse mem? */
if (bd->flags & UNIPHIER_BD_DRAM_SPARSE)
val |= SG_MEMCONF_SPARSEMEM;
if (!have_ch2)
goto out;
if (!bd->dram_ch[2].size) {
val |= SG_MEMCONF_CH2_DISABLE;
goto out;
}
/* set up ch2 */
switch (bd->dram_ch[2].width) {
case 16:
val |= SG_MEMCONF_CH2_NUM_1;
size_per_word = bd->dram_ch[2].size;
break;
case 32:
val |= SG_MEMCONF_CH2_NUM_2;
size_per_word = bd->dram_ch[2].size >> 1;
break;
default:
pr_err("error: unsupported DRAM ch2 width\n");
return -EINVAL;
}
switch (size_per_word) {
case SZ_64M:
val |= SG_MEMCONF_CH2_SZ_64M;
break;
case SZ_128M:
val |= SG_MEMCONF_CH2_SZ_128M;
break;
case SZ_256M:
val |= SG_MEMCONF_CH2_SZ_256M;
break;
case SZ_512M:
val |= SG_MEMCONF_CH2_SZ_512M;
break;
case SZ_1G:
val |= SG_MEMCONF_CH2_SZ_1G;
break;
default:
pr_err("error: unsupported DRAM ch2 size\n");
return -EINVAL;
}
out:
writel(val, sg_base + SG_MEMCONF);
return 0;
}
int uniphier_memconf_2ch_init(const struct uniphier_board_data *bd)
{
return __uniphier_memconf_init(bd, 0);
}
int uniphier_memconf_3ch_init(const struct uniphier_board_data *bd)
{
return __uniphier_memconf_init(bd, 1);
}
@@ -0,0 +1,268 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2012-2015 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <linux/ctype.h>
#include <linux/io.h>
#include "micro-support-card.h"
#define MICRO_SUPPORT_CARD_BASE 0x43f00000
#define SMC911X_BASE ((MICRO_SUPPORT_CARD_BASE) + 0x00000)
#define LED_BASE ((MICRO_SUPPORT_CARD_BASE) + 0x90000)
#define NS16550A_BASE ((MICRO_SUPPORT_CARD_BASE) + 0xb0000)
#define MICRO_SUPPORT_CARD_RESET ((MICRO_SUPPORT_CARD_BASE) + 0xd0034)
#define MICRO_SUPPORT_CARD_REVISION ((MICRO_SUPPORT_CARD_BASE) + 0xd00E0)
static bool support_card_found;
static void support_card_detect(void)
{
DECLARE_GLOBAL_DATA_PTR;
const void *fdt = gd->fdt_blob;
int offset;
offset = fdt_node_offset_by_compatible(fdt, 0, "smsc,lan9118");
if (offset < 0)
return;
offset = fdt_node_offset_by_compatible(fdt, 0, "ns16550a");
if (offset < 0)
return;
support_card_found = true;
}
/*
* 0: reset deassert, 1: reset
*
* bit[0]: LAN, I2C, LED
* bit[1]: UART
*/
static void support_card_reset_deassert(void)
{
writel(0x00010000, MICRO_SUPPORT_CARD_RESET);
}
static void support_card_reset(void)
{
writel(0x00020003, MICRO_SUPPORT_CARD_RESET);
}
static int support_card_show_revision(void)
{
u32 revision;
revision = readl(MICRO_SUPPORT_CARD_REVISION);
revision &= 0xff;
/* revision 3.6.x card changed the revision format */
printf("SC: Micro Support Card (CPLD version %s%d.%d)\n",
revision >> 4 == 6 ? "3." : "",
revision >> 4, revision & 0xf);
return 0;
}
void support_card_init(void)
{
support_card_detect();
if (!support_card_found)
return;
support_card_reset();
/*
* After power on, we need to keep the LAN controller in reset state
* for a while. (200 usec)
*/
udelay(200);
support_card_reset_deassert();
support_card_show_revision();
}
#if defined(CONFIG_SMC911X)
#include <netdev.h>
int board_eth_init(bd_t *bis)
{
if (!support_card_found)
return 0;
return smc911x_initialize(0, SMC911X_BASE);
}
#endif
#if defined(CONFIG_MTD_NOR_FLASH)
#include <mtd/cfi_flash.h>
struct memory_bank {
phys_addr_t base;
unsigned long size;
};
static int mem_is_flash(const struct memory_bank *mem)
{
const int loop = 128;
u32 *scratch_addr;
u32 saved_value;
int ret = 1;
int i;
/* just in case, use the tail of the memory bank */
scratch_addr = map_physmem(mem->base + mem->size - sizeof(u32) * loop,
sizeof(u32) * loop, MAP_NOCACHE);
for (i = 0; i < loop; i++, scratch_addr++) {
saved_value = readl(scratch_addr);
writel(~saved_value, scratch_addr);
if (readl(scratch_addr) != saved_value) {
/* We assume no memory or SRAM here. */
writel(saved_value, scratch_addr);
ret = 0;
break;
}
}
unmap_physmem(scratch_addr, MAP_NOCACHE);
return ret;
}
/* {address, size} */
static const struct memory_bank memory_banks[] = {
{0x42000000, 0x01f00000},
};
static const struct memory_bank
*flash_banks_list[CONFIG_SYS_MAX_FLASH_BANKS_DETECT];
phys_addr_t cfi_flash_bank_addr(int i)
{
return flash_banks_list[i]->base;
}
unsigned long cfi_flash_bank_size(int i)
{
return flash_banks_list[i]->size;
}
static void detect_num_flash_banks(void)
{
const struct memory_bank *memory_bank, *end;
cfi_flash_num_flash_banks = 0;
memory_bank = memory_banks;
end = memory_bank + ARRAY_SIZE(memory_banks);
for (; memory_bank < end; memory_bank++) {
if (cfi_flash_num_flash_banks >=
CONFIG_SYS_MAX_FLASH_BANKS_DETECT)
break;
if (mem_is_flash(memory_bank)) {
flash_banks_list[cfi_flash_num_flash_banks] =
memory_bank;
debug("flash bank found: base = 0x%lx, size = 0x%lx\n",
(unsigned long)memory_bank->base,
(unsigned long)memory_bank->size);
cfi_flash_num_flash_banks++;
}
}
debug("number of flash banks: %d\n", cfi_flash_num_flash_banks);
}
#else /* CONFIG_MTD_NOR_FLASH */
static void detect_num_flash_banks(void)
{
};
#endif /* CONFIG_MTD_NOR_FLASH */
void support_card_late_init(void)
{
if (!support_card_found)
return;
detect_num_flash_banks();
}
static const u8 ledval_num[] = {
0x7e, /* 0 */
0x0c, /* 1 */
0xb6, /* 2 */
0x9e, /* 3 */
0xcc, /* 4 */
0xda, /* 5 */
0xfa, /* 6 */
0x4e, /* 7 */
0xfe, /* 8 */
0xde, /* 9 */
};
static const u8 ledval_alpha[] = {
0xee, /* A */
0xf8, /* B */
0x72, /* C */
0xbc, /* D */
0xf2, /* E */
0xe2, /* F */
0x7a, /* G */
0xe8, /* H */
0x08, /* I */
0x3c, /* J */
0xea, /* K */
0x70, /* L */
0x6e, /* M */
0xa8, /* N */
0xb8, /* O */
0xe6, /* P */
0xce, /* Q */
0xa0, /* R */
0xc8, /* S */
0x8c, /* T */
0x7c, /* U */
0x54, /* V */
0xfc, /* W */
0xec, /* X */
0xdc, /* Y */
0xa4, /* Z */
};
static u8 char2ledval(char c)
{
if (isdigit(c))
return ledval_num[c - '0'];
else if (isalpha(c))
return ledval_alpha[toupper(c) - 'A'];
return 0;
}
void led_puts(const char *s)
{
int i;
u32 val = 0;
if (!support_card_found)
return;
if (!s)
return;
for (i = 0; i < 4; i++) {
val <<= 8;
val |= char2ledval(*s);
if (*s != '\0')
s++;
}
writel(~val, LED_BASE);
}
@@ -0,0 +1,29 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2012-2014 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#ifndef MICRO_SUPPORT_CARD_H
#define MICRO_SUPPORT_CARD_H
#if defined(CONFIG_MICRO_SUPPORT_CARD)
void support_card_init(void);
void support_card_late_init(void);
void led_puts(const char *s);
#else
static inline void support_card_init(void)
{
}
static inline void support_card_late_init(void)
{
}
static inline void led_puts(const char *s)
{
}
#endif
#endif /* MICRO_SUPPORT_CARD_H */
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#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 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 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <env.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;
env_set_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",
""
);
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <linux/errno.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include "init.h"
int uniphier_pin_init(const char *pinconfig_name)
{
struct udevice *pctldev, *config;
int ret;
ret = uclass_first_device(UCLASS_PINCTRL, &pctldev);
if (ret)
return ret;
device_foreach_child(config, pctldev) {
if (strcmp(config->name, pinconfig_name))
continue;
return pinctrl_generic_set_state(pctldev, config);
}
return -ENODEV;
}
@@ -0,0 +1,35 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2012-2014 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <linux/io.h>
#include <asm/secure.h>
#include "sc-regs.h"
/* If PSCI is enabled, this is used for SYSTEM_RESET function */
#ifdef CONFIG_ARMV7_PSCI
#define __SECURE __secure
#else
#define __SECURE
#endif
void __SECURE reset_cpu(unsigned long ignored)
{
u32 tmp;
writel(5, sc_base + SC_IRQTIMSET); /* default value */
tmp = readl(sc_base + SC_SLFRSTSEL);
tmp &= ~0x3; /* mask [1:0] */
tmp |= 0x0; /* XRST reboot */
writel(tmp, sc_base + SC_SLFRSTSEL);
tmp = readl(sc_base + SC_SLFRSTCTL);
tmp |= 0x1;
writel(tmp, sc_base + SC_SLFRSTCTL);
}
@@ -0,0 +1,15 @@
# SPDX-License-Identifier: GPL-2.0+
obj-y += sbc-boot.o
ifndef CONFIG_SPL_BUILD
obj-y += sbc.o
obj-$(CONFIG_ARCH_UNIPHIER_LD4) += sbc-ld4.o
obj-$(CONFIG_ARCH_UNIPHIER_SLD8) += sbc-ld4.o
obj-$(CONFIG_ARCH_UNIPHIER_PXS2) += sbc-pxs2.o
obj-$(CONFIG_ARCH_UNIPHIER_LD6B) += sbc-pxs2.o
obj-$(CONFIG_ARCH_UNIPHIER_LD11) += sbc-ld11.o
obj-$(CONFIG_ARCH_UNIPHIER_LD20) += sbc-ld11.o
obj-$(CONFIG_ARCH_UNIPHIER_PXS3) += sbc-pxs2.o
endif
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: GPL-2.0+
//
// Copyright (C) 2011-2014 Panasonic Corporation
// Copyright (C) 2015-2019 Socionext Inc.
#include <linux/io.h>
#include "sbc-regs.h"
int uniphier_sbc_boot_is_swapped(void)
{
return !(readl(SBBASE0) & SBBASE_BANK_ENABLE);
}
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016-2017 Socionext Inc.
*/
#include <common.h>
#include <spl.h>
#include <linux/io.h>
#include "../init.h"
#include "sbc-regs.h"
void uniphier_ld11_sbc_init(void)
{
if (!uniphier_sbc_is_enabled())
return;
uniphier_sbc_init_savepin();
/* necessary for ROM boot ?? */
/* system bus output enable */
writel(0x17, PC0CTRL);
/* pins for NAND and System Bus are multiplexed */
if (spl_boot_device() != BOOT_DEVICE_NAND)
uniphier_pin_init("system-bus");
}
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2011-2015 Panasonic Corporation
* Copyright (C) 2015-2017 Socionext Inc.
*/
#include <linux/io.h>
#include "../init.h"
#include "sbc-regs.h"
void uniphier_ld4_sbc_init(void)
{
u32 tmp;
if (!uniphier_sbc_is_enabled())
return;
uniphier_sbc_init_savepin();
/* system bus output enable */
tmp = readl(PC0CTRL);
tmp &= 0xfffffcff;
writel(tmp, PC0CTRL);
}
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016-2017 Socionext Inc.
*/
#include <linux/io.h>
#include "../init.h"
#include "sbc-regs.h"
void uniphier_pxs2_sbc_init(void)
{
if (!uniphier_sbc_is_enabled())
return;
uniphier_sbc_init_savepin();
/* necessary for ROM boot ?? */
/* system bus output enable */
writel(0x17, PC0CTRL);
uniphier_pin_init("system-bus"); /* PXs3 */
}
@@ -0,0 +1,82 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* UniPhier SBC (System Bus Controller) registers
*
* Copyright (C) 2011-2014 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
*/
#ifndef ARCH_SBC_REGS_H
#define ARCH_SBC_REGS_H
#define SBBASE_BASE 0x58c00100
#define SBBASE(x) (SBBASE_BASE + (x) * 0x10)
#define SBBASE0 (SBBASE(0))
#define SBBASE1 (SBBASE(1))
#define SBBASE2 (SBBASE(2))
#define SBBASE3 (SBBASE(3))
#define SBBASE4 (SBBASE(4))
#define SBBASE5 (SBBASE(5))
#define SBBASE6 (SBBASE(6))
#define SBBASE7 (SBBASE(7))
#define SBBASE_BANK_ENABLE (0x00000001)
#define SBCTRL_BASE 0x58c00200
#define SBCTRL(x, y) (SBCTRL_BASE + (x) * 0x10 + (y) * 4)
#define SBCTRL00 SBCTRL(0, 0)
#define SBCTRL01 SBCTRL(0, 1)
#define SBCTRL02 SBCTRL(0, 2)
#define SBCTRL03 SBCTRL(0, 3)
#define SBCTRL04 (SBCTRL_BASE + 0x100)
#define SBCTRL10 SBCTRL(1, 0)
#define SBCTRL11 SBCTRL(1, 1)
#define SBCTRL12 SBCTRL(1, 2)
#define SBCTRL13 SBCTRL(1, 3)
#define SBCTRL14 (SBCTRL_BASE + 0x110)
#define SBCTRL20 SBCTRL(2, 0)
#define SBCTRL21 SBCTRL(2, 1)
#define SBCTRL22 SBCTRL(2, 2)
#define SBCTRL23 SBCTRL(2, 3)
#define SBCTRL24 (SBCTRL_BASE + 0x120)
#define SBCTRL30 SBCTRL(3, 0)
#define SBCTRL31 SBCTRL(3, 1)
#define SBCTRL32 SBCTRL(3, 2)
#define SBCTRL33 SBCTRL(3, 3)
#define SBCTRL34 (SBCTRL_BASE + 0x130)
#define SBCTRL40 SBCTRL(4, 0)
#define SBCTRL41 SBCTRL(4, 1)
#define SBCTRL42 SBCTRL(4, 2)
#define SBCTRL43 SBCTRL(4, 3)
#define SBCTRL44 (SBCTRL_BASE + 0x140)
#define SBCTRL50 SBCTRL(5, 0)
#define SBCTRL51 SBCTRL(5, 1)
#define SBCTRL52 SBCTRL(5, 2)
#define SBCTRL53 SBCTRL(5, 3)
#define SBCTRL54 (SBCTRL_BASE + 0x150)
#define SBCTRL60 SBCTRL(6, 0)
#define SBCTRL61 SBCTRL(6, 1)
#define SBCTRL62 SBCTRL(6, 2)
#define SBCTRL63 SBCTRL(6, 3)
#define SBCTRL64 (SBCTRL_BASE + 0x160)
#define SBCTRL70 SBCTRL(7, 0)
#define SBCTRL71 SBCTRL(7, 1)
#define SBCTRL72 SBCTRL(7, 2)
#define SBCTRL73 SBCTRL(7, 3)
#define SBCTRL74 (SBCTRL_BASE + 0x170)
#define PC0CTRL 0x598000c0
int uniphier_sbc_boot_is_swapped(void);
int uniphier_sbc_is_enabled(void);
#endif /* ARCH_SBC_REGS_H */
@@ -0,0 +1,96 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2011-2015 Panasonic Corporation
* Copyright (C) 2015-2017 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <common.h>
#include <linux/io.h>
#include <asm/global_data.h>
#include "../init.h"
#include "sbc-regs.h"
#define SBCTRL0_ADMULTIPLX_PERI_VALUE 0x33120000
#define SBCTRL1_ADMULTIPLX_PERI_VALUE 0x03005500
#define SBCTRL2_ADMULTIPLX_PERI_VALUE 0x14000020
#define SBCTRL0_ADMULTIPLX_MEM_VALUE 0x33120000
#define SBCTRL1_ADMULTIPLX_MEM_VALUE 0x03005500
#define SBCTRL2_ADMULTIPLX_MEM_VALUE 0x14000010
/* slower but LED works */
#define SBCTRL0_SAVEPIN_PERI_VALUE 0x55450000
#define SBCTRL1_SAVEPIN_PERI_VALUE 0x07168d00
#define SBCTRL2_SAVEPIN_PERI_VALUE 0x34000009
#define SBCTRL4_SAVEPIN_PERI_VALUE 0x02110110
/* faster but LED does not work */
#define SBCTRL0_SAVEPIN_MEM_VALUE 0x55450000
#define SBCTRL1_SAVEPIN_MEM_VALUE 0x06057700
/* NOR flash needs more wait counts than SRAM */
#define SBCTRL2_SAVEPIN_MEM_VALUE 0x34000009
#define SBCTRL4_SAVEPIN_MEM_VALUE 0x02110210
int uniphier_sbc_is_enabled(void)
{
DECLARE_GLOBAL_DATA_PTR;
const void *fdt = gd->fdt_blob;
int offset;
offset = fdt_node_offset_by_compatible(fdt, 0,
"socionext,uniphier-system-bus");
if (offset < 0)
return 0;
return fdtdec_get_is_enabled(fdt, offset);
}
static void __uniphier_sbc_init(int savepin)
{
/*
* Only CS1 is connected to support card.
* BKSZ[1:0] should be set to "01".
*/
if (savepin) {
writel(SBCTRL0_SAVEPIN_PERI_VALUE, SBCTRL10);
writel(SBCTRL1_SAVEPIN_PERI_VALUE, SBCTRL11);
writel(SBCTRL2_SAVEPIN_PERI_VALUE, SBCTRL12);
writel(SBCTRL4_SAVEPIN_PERI_VALUE, SBCTRL14);
} else {
writel(SBCTRL0_ADMULTIPLX_MEM_VALUE, SBCTRL10);
writel(SBCTRL1_ADMULTIPLX_MEM_VALUE, SBCTRL11);
writel(SBCTRL2_ADMULTIPLX_MEM_VALUE, SBCTRL12);
}
if (uniphier_sbc_boot_is_swapped()) {
/*
* Boot Swap On: boot from external NOR/SRAM
* 0x42000000-0x43ffffff is a mirror of 0x40000000-0x41ffffff.
*
* 0x40000000-0x41efffff, 0x42000000-0x43efffff: memory bank
* 0x41f00000-0x41ffffff, 0x43f00000-0x43ffffff: peripherals
*/
writel(0x0000bc01, SBBASE0);
} else {
/*
* Boot Swap Off: boot from mask ROM
* 0x40000000-0x41ffffff: mask ROM
* 0x42000000-0x43efffff: memory bank (31MB)
* 0x43f00000-0x43ffffff: peripherals (1MB)
*/
writel(0x0000be01, SBBASE0); /* dummy */
writel(0x0200be01, SBBASE1);
}
}
void uniphier_sbc_init_admulti(void)
{
__uniphier_sbc_init(0);
}
void uniphier_sbc_init_savepin(void)
{
__uniphier_sbc_init(1);
}
@@ -0,0 +1,95 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* UniPhier SC (System Control) block registers
*
* Copyright (C) 2011-2015 Panasonic Corporation
* Copyright (C) 2015-2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#ifndef ARCH_SC_REGS_H
#define ARCH_SC_REGS_H
#ifndef __ASSEMBLY__
#include <linux/compiler.h>
#define sc_base ((void __iomem *)SC_BASE)
#endif
#define SC_BASE 0x61840000
#define SC_DPLLCTRL 0x1200
#define SC_DPLLCTRL_SSC_EN (0x1 << 31)
#define SC_DPLLCTRL_FOUTMODE_MASK (0xf << 16)
#define SC_DPLLCTRL_SSC_RATE (0x1 << 15)
#define SC_DPLLCTRL2 0x1204
#define SC_DPLLCTRL2_NRSTDS (0x1 << 28)
#define SC_DPLLCTRL3 0x1208
#define SC_DPLLCTRL3_LPFSEL_COEF2 (0x0 << 31)
#define SC_DPLLCTRL3_LPFSEL_COEF3 (0x1 << 31)
#define SC_UPLLCTRL 0x1210
#define SC_VPLL27ACTRL 0x1270
#define SC_VPLL27ACTRL2 0x1274
#define SC_VPLL27ACTRL3 0x1278
#define SC_VPLL27BCTRL 0x1290
#define SC_VPLL27BCTRL2 0x1294
#define SC_VPLL27BCTRL3 0x1298
#define SC_RSTCTRL 0x2000
#define SC_RSTCTRL_NRST_USB3B0 (0x1 << 17) /* USB3 #0 bus */
#define SC_RSTCTRL_NRST_USB3C0 (0x1 << 16) /* USB3 #0 core */
#define SC_RSTCTRL_NRST_ETHER (0x1 << 12)
#define SC_RSTCTRL_NRST_GIO (0x1 << 6)
/* Pro4 or older */
#define SC_RSTCTRL_NRST_UMC1 (0x1 << 5)
#define SC_RSTCTRL_NRST_UMC0 (0x1 << 4)
#define SC_RSTCTRL_NRST_NAND (0x1 << 2)
#define SC_RSTCTRL2 0x2004
#define SC_RSTCTRL2_NRST_USB3B1 (0x1 << 17) /* USB3 #1 bus */
#define SC_RSTCTRL2_NRST_USB3C1 (0x1 << 16) /* USB3 #1 core */
#define SC_RSTCTRL3 0x2008
/* Pro5 or newer */
#define SC_RSTCTRL4 0x200c
#define SC_RSTCTRL4_NRST_UMCSB (0x1 << 12) /* UMC system bus */
#define SC_RSTCTRL4_NRST_UMCA2 (0x1 << 10) /* UMC ch2 standby */
#define SC_RSTCTRL4_NRST_UMCA1 (0x1 << 9) /* UMC ch1 standby */
#define SC_RSTCTRL4_NRST_UMCA0 (0x1 << 8) /* UMC ch0 standby */
#define SC_RSTCTRL4_NRST_UMC32 (0x1 << 6) /* UMC ch2 */
#define SC_RSTCTRL4_NRST_UMC31 (0x1 << 5) /* UMC ch1 */
#define SC_RSTCTRL4_NRST_UMC30 (0x1 << 4) /* UMC ch0 */
#define SC_RSTCTRL5 0x2010
#define SC_RSTCTRL6 0x2014
#define SC_CLKCTRL 0x2104
#define SC_CLKCTRL_CEN_USB31 (0x1 << 17) /* USB3 #1 */
#define SC_CLKCTRL_CEN_USB30 (0x1 << 16) /* USB3 #0 */
#define SC_CLKCTRL_CEN_ETHER (0x1 << 12)
#define SC_CLKCTRL_CEN_GIO (0x1 << 6)
/* Pro4 or older */
#define SC_CLKCTRL_CEN_UMC (0x1 << 4)
#define SC_CLKCTRL_CEN_NAND (0x1 << 2)
#define SC_CLKCTRL_CEN_SBC (0x1 << 1)
#define SC_CLKCTRL_CEN_PERI (0x1 << 0)
/* Pro5 or newer */
#define SC_CLKCTRL4 0x210c
#define SC_CLKCTRL4_CEN_UMCSB (0x1 << 12) /* UMC system bus */
#define SC_CLKCTRL4_CEN_UMC2 (0x1 << 2) /* UMC ch2 */
#define SC_CLKCTRL4_CEN_UMC1 (0x1 << 1) /* UMC ch1 */
#define SC_CLKCTRL4_CEN_UMC0 (0x1 << 0) /* UMC ch0 */
/* System reset control register */
#define SC_IRQTIMSET 0x3000
#define SC_SLFRSTSEL 0x3010
#define SC_SLFRSTCTL 0x3014
#endif /* ARCH_SC_REGS_H */
@@ -0,0 +1,41 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* UniPhier SC (System Control) block registers for ARMv8 SoCs
*
* Copyright (C) 2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#ifndef SC64_REGS_H
#define SC64_REGS_H
#ifndef __ASSEMBLY__
#include <linux/compiler.h>
extern void __iomem *sc_base;
#endif
#define SC_BASE 0x61840000
#define SC_RSTCTRL 0x2000
#define SC_RSTCTRL3 0x2008
#define SC_RSTCTRL4 0x200c
#define SC_RSTCTRL5 0x2010
#define SC_RSTCTRL6 0x2014
#define SC_RSTCTRL7 0x2018
#define SC_CLKCTRL 0x2100
#define SC_CLKCTRL3 0x2108
#define SC_CLKCTRL4 0x210c
#define SC_CLKCTRL5 0x2110
#define SC_CLKCTRL6 0x2114
#define SC_CLKCTRL7 0x2118
#define SC_CA72_GEARST 0x8000
#define SC_CA72_GEARSET 0x8004
#define SC_CA72_GEARUPD 0x8008
#define SC_CA53_GEARST 0x8080
#define SC_CA53_GEARSET 0x8084
#define SC_CA53_GEARUPD 0x8088
#define SC_CA_GEARUPD (1 << 0)
#endif /* SC64_REGS_H */

Some files were not shown because too many files have changed in this diff Show More