avionic design with actual uboot and tooling

submodule of avionic design uboot bootloader and with included tools to
get you started , read readme.md and readme-tk1-loader.md
This commit is contained in:
2026-03-03 21:46:32 +02:00
parent fe3ba02c96
commit 68d74d3181
11967 changed files with 2221897 additions and 0 deletions

View File

@@ -0,0 +1,90 @@
if ARCH_MVEBU
config ARMADA_375
bool
config ARMADA_38X
bool
config ARMADA_XP
bool
config MV78230
bool
select ARMADA_XP
config MV78260
bool
select ARMADA_XP
config MV78460
bool
select ARMADA_XP
config DB_88F6820_GP
bool
select ARMADA_38X
choice
prompt "Marvell MVEBU (Armada XP/375/38x) board select"
optional
config TARGET_CLEARFOG
bool "Support ClearFog"
select DB_88F6820_GP
config TARGET_DB_88F6720
bool "Support DB-88F6720 Armada 375"
select ARMADA_375
config TARGET_DB_88F6820_GP
bool "Support DB-88F6820-GP"
select DB_88F6820_GP
config TARGET_DB_MV784MP_GP
bool "Support db-mv784mp-gp"
select MV78460
config TARGET_DS414
bool "Support Synology DS414"
select MV78230
config TARGET_MAXBCM
bool "Support maxbcm"
select MV78460
config TARGET_THEADORABLE
bool "Support theadorable Armada XP"
select MV78260
endchoice
config SYS_BOARD
default "clearfog" if TARGET_CLEARFOG
default "db-88f6720" if TARGET_DB_88F6720
default "db-88f6820-gp" if TARGET_DB_88F6820_GP
default "db-mv784mp-gp" if TARGET_DB_MV784MP_GP
default "ds414" if TARGET_DS414
default "maxbcm" if TARGET_MAXBCM
default "theadorable" if TARGET_THEADORABLE
config SYS_CONFIG_NAME
default "clearfog" if TARGET_CLEARFOG
default "db-88f6720" if TARGET_DB_88F6720
default "db-88f6820-gp" if TARGET_DB_88F6820_GP
default "db-mv784mp-gp" if TARGET_DB_MV784MP_GP
default "ds414" if TARGET_DS414
default "maxbcm" if TARGET_MAXBCM
default "theadorable" if TARGET_THEADORABLE
config SYS_VENDOR
default "Marvell" if TARGET_DB_MV784MP_GP
default "Marvell" if TARGET_DB_88F6720
default "Marvell" if TARGET_DB_88F6820_GP
default "solidrun" if TARGET_CLEARFOG
default "Synology" if TARGET_DS414
config SYS_SOC
default "mvebu"
endif

View File

@@ -0,0 +1,31 @@
#
# Copyright (C) 2014-2015 Stefan Roese <sr@denx.de>
#
# SPDX-License-Identifier: GPL-2.0+
#
ifdef CONFIG_KIRKWOOD
obj-y = dram.o
obj-y += gpio.o
obj-y += timer.o
else
obj-y = cpu.o
obj-y += dram.o
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_ARMADA_375) += ../../../drivers/ddr/marvell/axp/xor.o
obj-$(CONFIG_ARMADA_38X) += ../../../drivers/ddr/marvell/a38x/xor.o
obj-$(CONFIG_ARMADA_XP) += ../../../drivers/ddr/marvell/axp/xor.o
endif
obj-y += gpio.o
obj-y += mbus.o
obj-y += timer.o
obj-$(CONFIG_SPL_BUILD) += spl.o
obj-$(CONFIG_SPL_BUILD) += lowlevel_spl.o
obj-$(CONFIG_ARMADA_38X) += serdes/a38x/
obj-$(CONFIG_ARMADA_XP) += serdes/axp/
endif

View File

@@ -0,0 +1,580 @@
/*
* Copyright (C) 2014-2016 Stefan Roese <sr@denx.de>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <ahci.h>
#include <linux/mbus.h>
#include <asm/io.h>
#include <asm/pl310.h>
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>
#include <sdhci.h>
#define DDR_BASE_CS_OFF(n) (0x0000 + ((n) << 3))
#define DDR_SIZE_CS_OFF(n) (0x0004 + ((n) << 3))
static struct mbus_win windows[] = {
/* SPI */
{ MBUS_SPI_BASE, MBUS_SPI_SIZE,
CPU_TARGET_DEVICEBUS_BOOTROM_SPI, CPU_ATTR_SPIFLASH },
/* NOR */
{ MBUS_BOOTROM_BASE, MBUS_BOOTROM_SIZE,
CPU_TARGET_DEVICEBUS_BOOTROM_SPI, CPU_ATTR_BOOTROM },
};
void lowlevel_init(void)
{
/*
* Dummy implementation, we only need LOWLEVEL_INIT
* on Armada to configure CP15 in start.S / cpu_init_cp15()
*/
}
void reset_cpu(unsigned long ignored)
{
struct mvebu_system_registers *reg =
(struct mvebu_system_registers *)MVEBU_SYSTEM_REG_BASE;
writel(readl(&reg->rstoutn_mask) | 1, &reg->rstoutn_mask);
writel(readl(&reg->sys_soft_rst) | 1, &reg->sys_soft_rst);
while (1)
;
}
int mvebu_soc_family(void)
{
u16 devid = (readl(MVEBU_REG_PCIE_DEVID) >> 16) & 0xffff;
switch (devid) {
case SOC_MV78230_ID:
case SOC_MV78260_ID:
case SOC_MV78460_ID:
return MVEBU_SOC_AXP;
case SOC_88F6720_ID:
return MVEBU_SOC_A375;
case SOC_88F6810_ID:
case SOC_88F6820_ID:
case SOC_88F6828_ID:
return MVEBU_SOC_A38X;
}
return MVEBU_SOC_UNKNOWN;
}
#if defined(CONFIG_DISPLAY_CPUINFO)
#if defined(CONFIG_ARMADA_375)
/* SAR frequency values for Armada 375 */
static const struct sar_freq_modes sar_freq_tab[] = {
{ 0, 0x0, 266, 133, 266 },
{ 1, 0x0, 333, 167, 167 },
{ 2, 0x0, 333, 167, 222 },
{ 3, 0x0, 333, 167, 333 },
{ 4, 0x0, 400, 200, 200 },
{ 5, 0x0, 400, 200, 267 },
{ 6, 0x0, 400, 200, 400 },
{ 7, 0x0, 500, 250, 250 },
{ 8, 0x0, 500, 250, 334 },
{ 9, 0x0, 500, 250, 500 },
{ 10, 0x0, 533, 267, 267 },
{ 11, 0x0, 533, 267, 356 },
{ 12, 0x0, 533, 267, 533 },
{ 13, 0x0, 600, 300, 300 },
{ 14, 0x0, 600, 300, 400 },
{ 15, 0x0, 600, 300, 600 },
{ 16, 0x0, 666, 333, 333 },
{ 17, 0x0, 666, 333, 444 },
{ 18, 0x0, 666, 333, 666 },
{ 19, 0x0, 800, 400, 267 },
{ 20, 0x0, 800, 400, 400 },
{ 21, 0x0, 800, 400, 534 },
{ 22, 0x0, 900, 450, 300 },
{ 23, 0x0, 900, 450, 450 },
{ 24, 0x0, 900, 450, 600 },
{ 25, 0x0, 1000, 500, 500 },
{ 26, 0x0, 1000, 500, 667 },
{ 27, 0x0, 1000, 333, 500 },
{ 28, 0x0, 400, 400, 400 },
{ 29, 0x0, 1100, 550, 550 },
{ 0xff, 0xff, 0, 0, 0 } /* 0xff marks end of array */
};
#elif defined(CONFIG_ARMADA_38X)
/* SAR frequency values for Armada 38x */
static const struct sar_freq_modes sar_freq_tab[] = {
{ 0x0, 0x0, 666, 333, 333 },
{ 0x2, 0x0, 800, 400, 400 },
{ 0x4, 0x0, 1066, 533, 533 },
{ 0x6, 0x0, 1200, 600, 600 },
{ 0x8, 0x0, 1332, 666, 666 },
{ 0xc, 0x0, 1600, 800, 800 },
{ 0xff, 0xff, 0, 0, 0 } /* 0xff marks end of array */
};
#else
/* SAR frequency values for Armada XP */
static const struct sar_freq_modes sar_freq_tab[] = {
{ 0xa, 0x5, 800, 400, 400 },
{ 0x1, 0x5, 1066, 533, 533 },
{ 0x2, 0x5, 1200, 600, 600 },
{ 0x2, 0x9, 1200, 600, 400 },
{ 0x3, 0x5, 1333, 667, 667 },
{ 0x4, 0x5, 1500, 750, 750 },
{ 0x4, 0x9, 1500, 750, 500 },
{ 0xb, 0x9, 1600, 800, 533 },
{ 0xb, 0xa, 1600, 800, 640 },
{ 0xb, 0x5, 1600, 800, 800 },
{ 0xff, 0xff, 0, 0, 0 } /* 0xff marks end of array */
};
#endif
void get_sar_freq(struct sar_freq_modes *sar_freq)
{
u32 val;
u32 freq;
int i;
#if defined(CONFIG_ARMADA_375)
val = readl(CONFIG_SAR2_REG); /* SAR - Sample At Reset */
#else
val = readl(CONFIG_SAR_REG); /* SAR - Sample At Reset */
#endif
freq = (val & SAR_CPU_FREQ_MASK) >> SAR_CPU_FREQ_OFFS;
#if defined(SAR2_CPU_FREQ_MASK)
/*
* Shift CPU0 clock frequency select bit from SAR2 register
* into correct position
*/
freq |= ((readl(CONFIG_SAR2_REG) & SAR2_CPU_FREQ_MASK)
>> SAR2_CPU_FREQ_OFFS) << 3;
#endif
for (i = 0; sar_freq_tab[i].val != 0xff; i++) {
if (sar_freq_tab[i].val == freq) {
#if defined(CONFIG_ARMADA_375) || defined(CONFIG_ARMADA_38X)
*sar_freq = sar_freq_tab[i];
return;
#else
int k;
u8 ffc;
ffc = (val & SAR_FFC_FREQ_MASK) >>
SAR_FFC_FREQ_OFFS;
for (k = i; sar_freq_tab[k].ffc != 0xff; k++) {
if (sar_freq_tab[k].ffc == ffc) {
*sar_freq = sar_freq_tab[k];
return;
}
}
i = k;
#endif
}
}
/* SAR value not found, return 0 for frequencies */
*sar_freq = sar_freq_tab[i - 1];
}
int print_cpuinfo(void)
{
u16 devid = (readl(MVEBU_REG_PCIE_DEVID) >> 16) & 0xffff;
u8 revid = readl(MVEBU_REG_PCIE_REVID) & 0xff;
struct sar_freq_modes sar_freq;
puts("SoC: ");
switch (devid) {
case SOC_MV78230_ID:
puts("MV78230-");
break;
case SOC_MV78260_ID:
puts("MV78260-");
break;
case SOC_MV78460_ID:
puts("MV78460-");
break;
case SOC_88F6720_ID:
puts("MV88F6720-");
break;
case SOC_88F6810_ID:
puts("MV88F6810-");
break;
case SOC_88F6820_ID:
puts("MV88F6820-");
break;
case SOC_88F6828_ID:
puts("MV88F6828-");
break;
default:
puts("Unknown-");
break;
}
if (mvebu_soc_family() == MVEBU_SOC_AXP) {
switch (revid) {
case 1:
puts("A0");
break;
case 2:
puts("B0");
break;
default:
printf("?? (%x)", revid);
break;
}
}
if (mvebu_soc_family() == MVEBU_SOC_A375) {
switch (revid) {
case MV_88F67XX_A0_ID:
puts("A0");
break;
default:
printf("?? (%x)", revid);
break;
}
}
if (mvebu_soc_family() == MVEBU_SOC_A38X) {
switch (revid) {
case MV_88F68XX_Z1_ID:
puts("Z1");
break;
case MV_88F68XX_A0_ID:
puts("A0");
break;
default:
printf("?? (%x)", revid);
break;
}
}
get_sar_freq(&sar_freq);
printf(" at %d MHz\n", sar_freq.p_clk);
return 0;
}
#endif /* CONFIG_DISPLAY_CPUINFO */
/*
* This function initialize Controller DRAM Fastpath windows.
* It takes the CS size information from the 0x1500 scratch registers
* and sets the correct windows sizes and base addresses accordingly.
*
* These values are set in the scratch registers by the Marvell
* DDR3 training code, which is executed by the BootROM before the
* main payload (U-Boot) is executed. This training code is currently
* only available in the Marvell U-Boot version. It needs to be
* ported to mainline U-Boot SPL at some point.
*/
static void update_sdram_window_sizes(void)
{
u64 base = 0;
u32 size, temp;
int i;
for (i = 0; i < SDRAM_MAX_CS; i++) {
size = readl((MVEBU_SDRAM_SCRATCH + (i * 8))) & SDRAM_ADDR_MASK;
if (size != 0) {
size |= ~(SDRAM_ADDR_MASK);
/* Set Base Address */
temp = (base & 0xFF000000ll) | ((base >> 32) & 0xF);
writel(temp, MVEBU_SDRAM_BASE + DDR_BASE_CS_OFF(i));
/*
* Check if out of max window size and resize
* the window
*/
temp = (readl(MVEBU_SDRAM_BASE + DDR_SIZE_CS_OFF(i)) &
~(SDRAM_ADDR_MASK)) | 1;
temp |= (size & SDRAM_ADDR_MASK);
writel(temp, MVEBU_SDRAM_BASE + DDR_SIZE_CS_OFF(i));
base += ((u64)size + 1);
} else {
/*
* Disable window if not used, otherwise this
* leads to overlapping enabled windows with
* pretty strange results
*/
clrbits_le32(MVEBU_SDRAM_BASE + DDR_SIZE_CS_OFF(i), 1);
}
}
}
void mmu_disable(void)
{
asm volatile(
"mrc p15, 0, r0, c1, c0, 0\n"
"bic r0, #1\n"
"mcr p15, 0, r0, c1, c0, 0\n");
}
#ifdef CONFIG_ARCH_CPU_INIT
static void set_cbar(u32 addr)
{
asm("mcr p15, 4, %0, c15, c0" : : "r" (addr));
}
#define MV_USB_PHY_BASE (MVEBU_AXP_USB_BASE + 0x800)
#define MV_USB_PHY_PLL_REG(reg) (MV_USB_PHY_BASE | (((reg) & 0xF) << 2))
#define MV_USB_X3_BASE(addr) (MVEBU_AXP_USB_BASE | BIT(11) | \
(((addr) & 0xF) << 6))
#define MV_USB_X3_PHY_CHANNEL(dev, reg) (MV_USB_X3_BASE((dev) + 1) | \
(((reg) & 0xF) << 2))
static void setup_usb_phys(void)
{
int dev;
/*
* USB PLL init
*/
/* Setup PLL frequency */
/* USB REF frequency = 25 MHz */
clrsetbits_le32(MV_USB_PHY_PLL_REG(1), 0x3ff, 0x605);
/* Power up PLL and PHY channel */
setbits_le32(MV_USB_PHY_PLL_REG(2), BIT(9));
/* Assert VCOCAL_START */
setbits_le32(MV_USB_PHY_PLL_REG(1), BIT(21));
mdelay(1);
/*
* USB PHY init (change from defaults) specific for 40nm (78X30 78X60)
*/
for (dev = 0; dev < 3; dev++) {
setbits_le32(MV_USB_X3_PHY_CHANNEL(dev, 3), BIT(15));
/* Assert REG_RCAL_START in channel REG 1 */
setbits_le32(MV_USB_X3_PHY_CHANNEL(dev, 1), BIT(12));
udelay(40);
clrbits_le32(MV_USB_X3_PHY_CHANNEL(dev, 1), BIT(12));
}
}
/*
* This function is not called from the SPL U-Boot version
*/
int arch_cpu_init(void)
{
struct pl310_regs *const pl310 =
(struct pl310_regs *)CONFIG_SYS_PL310_BASE;
/*
* Only with disabled MMU its possible to switch the base
* register address on Armada 38x. Without this the SDRAM
* located at >= 0x4000.0000 is also not accessible, as its
* still locked to cache.
*/
mmu_disable();
/* Linux expects the internal registers to be at 0xf1000000 */
writel(SOC_REGS_PHY_BASE, INTREG_BASE_ADDR_REG);
set_cbar(SOC_REGS_PHY_BASE + 0xC000);
/*
* From this stage on, the SoC detection is working. As we have
* configured the internal register base to the value used
* in the macros / defines in the U-Boot header (soc.h).
*/
if (mvebu_soc_family() == MVEBU_SOC_A38X) {
/*
* To fully release / unlock this area from cache, we need
* to flush all caches and disable the L2 cache.
*/
icache_disable();
dcache_disable();
clrbits_le32(&pl310->pl310_ctrl, L2X0_CTRL_EN);
}
/*
* We need to call mvebu_mbus_probe() before calling
* update_sdram_window_sizes() as it disables all previously
* configured mbus windows and then configures them as
* required for U-Boot. Calling update_sdram_window_sizes()
* without this configuration will not work, as the internal
* registers can't be accessed reliably because of potenial
* double mapping.
* After updating the SDRAM access windows we need to call
* mvebu_mbus_probe() again, as this now correctly configures
* the SDRAM areas that are later used by the MVEBU drivers
* (e.g. USB, NETA).
*/
/*
* First disable all windows
*/
mvebu_mbus_probe(NULL, 0);
if (mvebu_soc_family() == MVEBU_SOC_AXP) {
/*
* Now the SDRAM access windows can be reconfigured using
* the information in the SDRAM scratch pad registers
*/
update_sdram_window_sizes();
}
/*
* Finally the mbus windows can be configured with the
* updated SDRAM sizes
*/
mvebu_mbus_probe(windows, ARRAY_SIZE(windows));
if (mvebu_soc_family() == MVEBU_SOC_AXP) {
/* Enable GBE0, GBE1, LCD and NFC PUP */
clrsetbits_le32(ARMADA_XP_PUP_ENABLE, 0,
GE0_PUP_EN | GE1_PUP_EN | LCD_PUP_EN |
NAND_PUP_EN | SPI_PUP_EN);
/* Configure USB PLL and PHYs on AXP */
setup_usb_phys();
}
/* Enable NAND and NAND arbiter */
clrsetbits_le32(MVEBU_SOC_DEV_MUX_REG, 0, NAND_EN | NAND_ARBITER_EN);
/* Disable MBUS error propagation */
clrsetbits_le32(SOC_COHERENCY_FABRIC_CTRL_REG, MBUS_ERR_PROP_EN, 0);
return 0;
}
#endif /* CONFIG_ARCH_CPU_INIT */
u32 mvebu_get_nand_clock(void)
{
return CONFIG_SYS_MVEBU_PLL_CLOCK /
((readl(MVEBU_CORE_DIV_CLK_CTRL(1)) &
NAND_ECC_DIVCKL_RATIO_MASK) >> NAND_ECC_DIVCKL_RATIO_OFFS);
}
/*
* SOC specific misc init
*/
#if defined(CONFIG_ARCH_MISC_INIT)
int arch_misc_init(void)
{
/* Nothing yet, perhaps we need something here later */
return 0;
}
#endif /* CONFIG_ARCH_MISC_INIT */
#ifdef CONFIG_MV_SDHCI
int board_mmc_init(bd_t *bis)
{
mv_sdh_init(MVEBU_SDIO_BASE, 0, 0,
SDHCI_QUIRK_32BIT_DMA_ADDR | SDHCI_QUIRK_WAIT_SEND_CMD);
return 0;
}
#endif
#ifdef CONFIG_SCSI_AHCI_PLAT
#define AHCI_VENDOR_SPECIFIC_0_ADDR 0xa0
#define AHCI_VENDOR_SPECIFIC_0_DATA 0xa4
#define AHCI_WINDOW_CTRL(win) (0x60 + ((win) << 4))
#define AHCI_WINDOW_BASE(win) (0x64 + ((win) << 4))
#define AHCI_WINDOW_SIZE(win) (0x68 + ((win) << 4))
static void ahci_mvebu_mbus_config(void __iomem *base)
{
const struct mbus_dram_target_info *dram;
int i;
dram = mvebu_mbus_dram_info();
for (i = 0; i < 4; i++) {
writel(0, base + AHCI_WINDOW_CTRL(i));
writel(0, base + AHCI_WINDOW_BASE(i));
writel(0, base + AHCI_WINDOW_SIZE(i));
}
for (i = 0; i < dram->num_cs; i++) {
const struct mbus_dram_window *cs = dram->cs + i;
writel((cs->mbus_attr << 8) |
(dram->mbus_dram_target_id << 4) | 1,
base + AHCI_WINDOW_CTRL(i));
writel(cs->base >> 16, base + AHCI_WINDOW_BASE(i));
writel(((cs->size - 1) & 0xffff0000),
base + AHCI_WINDOW_SIZE(i));
}
}
static void ahci_mvebu_regret_option(void __iomem *base)
{
/*
* Enable the regret bit to allow the SATA unit to regret a
* request that didn't receive an acknowlegde and avoid a
* deadlock
*/
writel(0x4, base + AHCI_VENDOR_SPECIFIC_0_ADDR);
writel(0x80, base + AHCI_VENDOR_SPECIFIC_0_DATA);
}
void scsi_init(void)
{
printf("MVEBU SATA INIT\n");
ahci_mvebu_mbus_config((void __iomem *)MVEBU_SATA0_BASE);
ahci_mvebu_regret_option((void __iomem *)MVEBU_SATA0_BASE);
ahci_init((void __iomem *)MVEBU_SATA0_BASE);
}
#endif
void enable_caches(void)
{
/* Avoid problem with e.g. neta ethernet driver */
invalidate_dcache_all();
/*
* Armada 375 still has some problems with d-cache enabled in the
* ethernet driver (mvpp2). So lets keep the d-cache disabled
* until this is solved.
*/
if (mvebu_soc_family() != MVEBU_SOC_A375) {
/* Enable D-cache. I-cache is already enabled in start.S */
dcache_enable();
}
}
void v7_outer_cache_enable(void)
{
if (mvebu_soc_family() == MVEBU_SOC_AXP) {
struct pl310_regs *const pl310 =
(struct pl310_regs *)CONFIG_SYS_PL310_BASE;
u32 u;
/* The L2 cache is already disabled at this point */
/*
* For Aurora cache in no outer mode, enable via the CP15
* coprocessor broadcasting of cache commands to L2.
*/
asm volatile("mrc p15, 1, %0, c15, c2, 0" : "=r" (u));
u |= BIT(8); /* Set the FW bit */
asm volatile("mcr p15, 1, %0, c15, c2, 0" : : "r" (u));
isb();
/* Enable the L2 cache */
setbits_le32(&pl310->pl310_ctrl, L2X0_CTRL_EN);
}
}
void v7_outer_cache_disable(void)
{
struct pl310_regs *const pl310 =
(struct pl310_regs *)CONFIG_SYS_PL310_BASE;
clrbits_le32(&pl310->pl310_ctrl, L2X0_CTRL_EN);
}

View File

@@ -0,0 +1,306 @@
/*
* (C) Copyright 2009
* Marvell Semiconductor <www.marvell.com>
* Written-by: Prafulla Wadaskar <prafulla@marvell.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <config.h>
#include <common.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>
#if defined(CONFIG_ARCH_MVEBU)
/* Use common XOR definitions for A3x and AXP */
#include "../../../drivers/ddr/marvell/axp/xor.h"
#include "../../../drivers/ddr/marvell/axp/xor_regs.h"
#endif
DECLARE_GLOBAL_DATA_PTR;
struct sdram_bank {
u32 win_bar;
u32 win_sz;
};
struct sdram_addr_dec {
struct sdram_bank sdram_bank[4];
};
#define REG_CPUCS_WIN_ENABLE (1 << 0)
#define REG_CPUCS_WIN_WR_PROTECT (1 << 1)
#define REG_CPUCS_WIN_WIN0_CS(x) (((x) & 0x3) << 2)
#define REG_CPUCS_WIN_SIZE(x) (((x) & 0xff) << 24)
#define SDRAM_SIZE_MAX 0xc0000000
#define SCRUB_MAGIC 0xbeefdead
#define SCRB_XOR_UNIT 0
#define SCRB_XOR_CHAN 1
#define SCRB_XOR_WIN 0
#define XEBARX_BASE_OFFS 16
/*
* mvebu_sdram_bar - reads SDRAM Base Address Register
*/
u32 mvebu_sdram_bar(enum memory_bank bank)
{
struct sdram_addr_dec *base =
(struct sdram_addr_dec *)MVEBU_SDRAM_BASE;
u32 result = 0;
u32 enable = 0x01 & readl(&base->sdram_bank[bank].win_sz);
if ((!enable) || (bank > BANK3))
return 0;
result = readl(&base->sdram_bank[bank].win_bar);
return result;
}
/*
* mvebu_sdram_bs_set - writes SDRAM Bank size
*/
static void mvebu_sdram_bs_set(enum memory_bank bank, u32 size)
{
struct sdram_addr_dec *base =
(struct sdram_addr_dec *)MVEBU_SDRAM_BASE;
/* Read current register value */
u32 reg = readl(&base->sdram_bank[bank].win_sz);
/* Clear window size */
reg &= ~REG_CPUCS_WIN_SIZE(0xFF);
/* Set new window size */
reg |= REG_CPUCS_WIN_SIZE((size - 1) >> 24);
writel(reg, &base->sdram_bank[bank].win_sz);
}
/*
* mvebu_sdram_bs - reads SDRAM Bank size
*/
u32 mvebu_sdram_bs(enum memory_bank bank)
{
struct sdram_addr_dec *base =
(struct sdram_addr_dec *)MVEBU_SDRAM_BASE;
u32 result = 0;
u32 enable = 0x01 & readl(&base->sdram_bank[bank].win_sz);
if ((!enable) || (bank > BANK3))
return 0;
result = 0xff000000 & readl(&base->sdram_bank[bank].win_sz);
result += 0x01000000;
return result;
}
void mvebu_sdram_size_adjust(enum memory_bank bank)
{
u32 size;
/* probe currently equipped RAM size */
size = get_ram_size((void *)mvebu_sdram_bar(bank),
mvebu_sdram_bs(bank));
/* adjust SDRAM window size accordingly */
mvebu_sdram_bs_set(bank, size);
}
#if defined(CONFIG_ARCH_MVEBU)
static u32 xor_ctrl_save;
static u32 xor_base_save;
static u32 xor_mask_save;
static void mv_xor_init2(u32 cs)
{
u32 reg, base, size, base2;
u32 bank_attr[4] = { 0xe00, 0xd00, 0xb00, 0x700 };
xor_ctrl_save = reg_read(XOR_WINDOW_CTRL_REG(SCRB_XOR_UNIT,
SCRB_XOR_CHAN));
xor_base_save = reg_read(XOR_BASE_ADDR_REG(SCRB_XOR_UNIT,
SCRB_XOR_WIN));
xor_mask_save = reg_read(XOR_SIZE_MASK_REG(SCRB_XOR_UNIT,
SCRB_XOR_WIN));
/* Enable Window x for each CS */
reg = 0x1;
reg |= (0x3 << 16);
reg_write(XOR_WINDOW_CTRL_REG(SCRB_XOR_UNIT, SCRB_XOR_CHAN), reg);
base = 0;
size = mvebu_sdram_bs(cs) - 1;
if (size) {
base2 = ((base / (64 << 10)) << XEBARX_BASE_OFFS) |
bank_attr[cs];
reg_write(XOR_BASE_ADDR_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN),
base2);
base += size + 1;
size = (size / (64 << 10)) << 16;
/* Window x - size - 256 MB */
reg_write(XOR_SIZE_MASK_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN), size);
}
mv_xor_hal_init(0);
return;
}
static void mv_xor_finish2(void)
{
reg_write(XOR_WINDOW_CTRL_REG(SCRB_XOR_UNIT, SCRB_XOR_CHAN),
xor_ctrl_save);
reg_write(XOR_BASE_ADDR_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN),
xor_base_save);
reg_write(XOR_SIZE_MASK_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN),
xor_mask_save);
}
static void dram_ecc_scrubbing(void)
{
int cs;
u32 size, temp;
u32 total_mem = 0;
u64 total;
u32 start_addr;
/*
* The DDR training code from the bin_hdr / SPL already
* scrubbed the DDR till 0x1000000. And the main U-Boot
* is loaded to an address < 0x1000000. So we need to
* skip this range to not re-scrub this area again.
*/
temp = reg_read(REG_SDRAM_CONFIG_ADDR);
temp |= (1 << REG_SDRAM_CONFIG_IERR_OFFS);
reg_write(REG_SDRAM_CONFIG_ADDR, temp);
for (cs = 0; cs < CONFIG_NR_DRAM_BANKS; cs++) {
size = mvebu_sdram_bs(cs) - 1;
if (size == 0)
continue;
total = (u64)size + 1;
total_mem += (u32)(total / (1 << 30));
start_addr = 0;
mv_xor_init2(cs);
/* Skip first 16 MiB */
if (0 == cs) {
start_addr = 0x1000000;
size -= start_addr;
}
mv_xor_mem_init(SCRB_XOR_CHAN, start_addr, size,
SCRUB_MAGIC, SCRUB_MAGIC);
/* Wait for previous transfer completion */
while (mv_xor_state_get(SCRB_XOR_CHAN) != MV_IDLE)
;
mv_xor_finish2();
}
temp = reg_read(REG_SDRAM_CONFIG_ADDR);
temp &= ~(1 << REG_SDRAM_CONFIG_IERR_OFFS);
reg_write(REG_SDRAM_CONFIG_ADDR, temp);
}
static int ecc_enabled(void)
{
if (reg_read(REG_SDRAM_CONFIG_ADDR) & (1 << REG_SDRAM_CONFIG_ECC_OFFS))
return 1;
return 0;
}
#else
static void dram_ecc_scrubbing(void)
{
}
static int ecc_enabled(void)
{
return 0;
}
#endif
int dram_init(void)
{
u64 size = 0;
int i;
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
/*
* It is assumed that all memory banks are consecutive
* and without gaps.
* If the gap is found, ram_size will be reported for
* consecutive memory only
*/
if (mvebu_sdram_bar(i) != size)
break;
/*
* Don't report more than 3GiB of SDRAM, otherwise there is no
* address space left for the internal registers etc.
*/
size += mvebu_sdram_bs(i);
if (size > SDRAM_SIZE_MAX)
size = SDRAM_SIZE_MAX;
}
for (; i < CONFIG_NR_DRAM_BANKS; i++) {
/* If above loop terminated prematurely, we need to set
* remaining banks' start address & size as 0. Otherwise other
* u-boot functions and Linux kernel gets wrong values which
* could result in crash */
gd->bd->bi_dram[i].start = 0;
gd->bd->bi_dram[i].size = 0;
}
if (ecc_enabled())
dram_ecc_scrubbing();
gd->ram_size = size;
return 0;
}
/*
* If this function is not defined here,
* board.c alters dram bank zero configuration defined above.
*/
void dram_init_banksize(void)
{
u64 size = 0;
int i;
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
gd->bd->bi_dram[i].start = mvebu_sdram_bar(i);
gd->bd->bi_dram[i].size = mvebu_sdram_bs(i);
/* Clip the banksize to 1GiB if it exceeds the max size */
size += gd->bd->bi_dram[i].size;
if (size > SDRAM_SIZE_MAX)
mvebu_sdram_bs_set(i, 0x40000000);
}
}
#if defined(CONFIG_ARCH_MVEBU)
void board_add_ram_info(int use_default)
{
struct sar_freq_modes sar_freq;
get_sar_freq(&sar_freq);
printf(" (%d MHz, ", sar_freq.d_clk);
if (ecc_enabled())
printf("ECC");
else
printf("ECC not");
printf(" enabled)");
}
#endif

View File

@@ -0,0 +1,30 @@
/*
* (C) Copyright 2009
* Marvell Semiconductor <www.marvell.com>
* Written-by: Prafulla Wadaskar <prafulla@marvell.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>
/*
* mvebu_config_gpio - GPIO configuration
*/
void mvebu_config_gpio(u32 gpp0_oe_val, u32 gpp1_oe_val,
u32 gpp0_oe, u32 gpp1_oe)
{
struct kwgpio_registers *gpio0reg =
(struct kwgpio_registers *)MVEBU_GPIO0_BASE;
struct kwgpio_registers *gpio1reg =
(struct kwgpio_registers *)MVEBU_GPIO1_BASE;
/* Init GPIOS to default values as per board requirement */
writel(gpp0_oe_val, &gpio0reg->dout);
writel(gpp1_oe_val, &gpio1reg->dout);
writel(gpp0_oe, &gpio0reg->oe);
writel(gpp1_oe, &gpio1reg->oe);
}

View File

@@ -0,0 +1,107 @@
/*
* (C) Copyright 2011
* Marvell Semiconductor <www.marvell.com>
* Written-by: Lei Wen <leiwen@marvell.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
/*
* This file should be included in board config header file.
*
* It supports common definitions for MVEBU platforms
*/
#ifndef _MVEBU_CONFIG_H
#define _MVEBU_CONFIG_H
#include <asm/arch/soc.h>
#if defined(CONFIG_ARMADA_XP) || defined(CONFIG_ARMADA_375) \
|| defined(CONFIG_ARMADA_38X)
/*
* Set this for the common xor register definitions needed in dram.c
* for A38x as well here.
*/
#define MV88F78X60 /* for the DDR training bin_hdr code */
#endif
#define CONFIG_SYS_CACHELINE_SIZE 32
#define CONFIG_SYS_L2_PL310
#ifdef CONFIG_SPL_BUILD
#define CONFIG_SKIP_LOWLEVEL_INIT /* disable board lowlevel_init */
#endif
/*
* By default kwbimage.cfg from board specific folder is used
* If for some board, different configuration file need to be used,
* CONFIG_SYS_KWD_CONFIG should be defined in board specific header file
*/
#ifndef CONFIG_SYS_KWD_CONFIG
#define CONFIG_SYS_KWD_CONFIG $(CONFIG_BOARDDIR)/kwbimage.cfg
#endif /* CONFIG_SYS_KWD_CONFIG */
/* Add target to build it automatically upon "make" */
#ifdef CONFIG_SPL
#define CONFIG_BUILD_TARGET "u-boot-spl.kwb"
#endif
/* end of 16M scrubbed by training in bootrom */
#define CONFIG_SYS_INIT_SP_ADDR 0x00FF0000
#define CONFIG_NR_DRAM_BANKS_MAX 2
#define MV_UART_CONSOLE_BASE MVEBU_UART0_BASE
/*
* SPI Flash configuration
*/
#ifdef CONFIG_CMD_SF
#define CONFIG_KIRKWOOD_SPI
#ifndef CONFIG_ENV_SPI_BUS
# define CONFIG_ENV_SPI_BUS 0
#endif
#ifndef CONFIG_ENV_SPI_CS
# define CONFIG_ENV_SPI_CS 0
#endif
#ifndef CONFIG_ENV_SPI_MAX_HZ
# define CONFIG_ENV_SPI_MAX_HZ 50000000
#endif
#endif
/* Needed for SPI NOR booting in SPL */
#define CONFIG_DM_SEQ_ALIAS 1
/*
* Ethernet Driver configuration
*/
#ifdef CONFIG_CMD_NET
#define CONFIG_MII /* expose smi ove miiphy interface */
#if !defined(CONFIG_ARMADA_375)
#define CONFIG_MVNETA /* Enable Marvell Gbe Controller Driver */
#define CONFIG_PHYLIB
#endif
#define CONFIG_ENV_OVERWRITE /* ethaddr can be reprogrammed */
#define CONFIG_PHY_GIGE /* GbE speed/duplex detect */
#define CONFIG_ARP_TIMEOUT 200
#define CONFIG_NET_RETRY_COUNT 50
#endif /* CONFIG_CMD_NET */
/*
* I2C related stuff
*/
#ifdef CONFIG_CMD_I2C
#ifndef CONFIG_SYS_I2C_SOFT
#define CONFIG_I2C_MVTWSI
#endif
#define CONFIG_SYS_I2C_SLAVE 0x0
#define CONFIG_SYS_I2C_SPEED 100000
#endif
/* Use common timer */
#define CONFIG_SYS_TIMER_COUNTS_DOWN
#define CONFIG_SYS_TIMER_COUNTER (MVEBU_TIMER_BASE + 0x14)
#define CONFIG_SYS_TIMER_RATE 25000000
#endif /* __MVEBU_CONFIG_H */

View File

@@ -0,0 +1,170 @@
/*
* (C) Copyright 2009
* Marvell Semiconductor <www.marvell.com>
* Written-by: Prafulla Wadaskar <prafulla@marvell.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _MVEBU_CPU_H
#define _MVEBU_CPU_H
#include <asm/system.h>
#ifndef __ASSEMBLY__
#define MVEBU_REG_PCIE_DEVID (MVEBU_REG_PCIE_BASE + 0x00)
#define MVEBU_REG_PCIE_REVID (MVEBU_REG_PCIE_BASE + 0x08)
enum memory_bank {
BANK0,
BANK1,
BANK2,
BANK3
};
enum cpu_winen {
CPU_WIN_DISABLE,
CPU_WIN_ENABLE
};
enum cpu_target {
CPU_TARGET_DRAM = 0x0,
CPU_TARGET_DEVICEBUS_BOOTROM_SPI = 0x1,
CPU_TARGET_ETH23 = 0x3,
CPU_TARGET_PCIE02 = 0x4,
CPU_TARGET_ETH01 = 0x7,
CPU_TARGET_PCIE13 = 0x8,
CPU_TARGET_SASRAM = 0x9,
CPU_TARGET_NAND = 0xd,
};
enum cpu_attrib {
CPU_ATTR_SASRAM = 0x01,
CPU_ATTR_DRAM_CS0 = 0x0e,
CPU_ATTR_DRAM_CS1 = 0x0d,
CPU_ATTR_DRAM_CS2 = 0x0b,
CPU_ATTR_DRAM_CS3 = 0x07,
CPU_ATTR_NANDFLASH = 0x2f,
CPU_ATTR_SPIFLASH = 0x1e,
CPU_ATTR_SPI0_CS0 = 0x1e,
CPU_ATTR_SPI0_CS1 = 0x5e,
CPU_ATTR_SPI1_CS2 = 0x9a,
CPU_ATTR_BOOTROM = 0x1d,
CPU_ATTR_PCIE_IO = 0xe0,
CPU_ATTR_PCIE_MEM = 0xe8,
CPU_ATTR_DEV_CS0 = 0x3e,
CPU_ATTR_DEV_CS1 = 0x3d,
CPU_ATTR_DEV_CS2 = 0x3b,
CPU_ATTR_DEV_CS3 = 0x37,
};
enum {
MVEBU_SOC_AXP,
MVEBU_SOC_A375,
MVEBU_SOC_A38X,
MVEBU_SOC_UNKNOWN,
};
/*
* Default Device Address MAP BAR values
*/
#define MBUS_PCI_MEM_BASE 0xE8000000
#define MBUS_PCI_MEM_SIZE (128 << 20)
#define MBUS_PCI_IO_BASE 0xF1100000
#define MBUS_PCI_IO_SIZE (64 << 10)
#define MBUS_SPI_BASE 0xF4000000
#define MBUS_SPI_SIZE (8 << 20)
#define MBUS_BOOTROM_BASE 0xF8000000
#define MBUS_BOOTROM_SIZE (8 << 20)
struct mbus_win {
u32 base;
u32 size;
u8 target;
u8 attr;
};
/*
* System registers
* Ref: Datasheet sec:A.28
*/
struct mvebu_system_registers {
#if defined(CONFIG_ARMADA_375)
u8 pad1[0x54];
#else
u8 pad1[0x60];
#endif
u32 rstoutn_mask; /* 0x60 */
u32 sys_soft_rst; /* 0x64 */
};
/*
* GPIO Registers
* Ref: Datasheet sec:A.19
*/
struct kwgpio_registers {
u32 dout;
u32 oe;
u32 blink_en;
u32 din_pol;
u32 din;
u32 irq_cause;
u32 irq_mask;
u32 irq_level;
};
struct sar_freq_modes {
u8 val;
u8 ffc; /* Fabric Frequency Configuration */
u32 p_clk;
u32 nb_clk;
u32 d_clk;
};
/* Needed for dynamic (board-specific) mbus configuration */
extern struct mvebu_mbus_state mbus_state;
/*
* functions
*/
unsigned int mvebu_sdram_bar(enum memory_bank bank);
unsigned int mvebu_sdram_bs(enum memory_bank bank);
void mvebu_sdram_size_adjust(enum memory_bank bank);
int mvebu_mbus_probe(struct mbus_win windows[], int count);
int mvebu_soc_family(void);
u32 mvebu_get_nand_clock(void);
void return_to_bootrom(void);
int mv_sdh_init(unsigned long regbase, u32 max_clk, u32 min_clk, u32 quirks);
void get_sar_freq(struct sar_freq_modes *sar_freq);
/*
* Highspeed SERDES PHY config init, ported from bin_hdr
* to mainline U-Boot
*/
int serdes_phy_config(void);
/*
* DDR3 init / training code ported from Marvell bin_hdr. Now
* available in mainline U-Boot in:
* drivers/ddr/marvell
*/
int ddr3_init(void);
struct mvebu_lcd_info {
u32 fb_base;
int x_res;
int y_res;
int x_fp; /* frontporch */
int y_fp;
int x_bp; /* backporch */
int y_bp;
};
int mvebu_lcd_register_init(struct mvebu_lcd_info *lcd_info);
#endif /* __ASSEMBLY__ */
#endif /* _MVEBU_CPU_H */

View File

@@ -0,0 +1,10 @@
/*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __MACH_MVEBU_GPIO_H
#define __MACH_MVEBU_GPIO_H
/* Empty file - sdhci requires this. */
#endif

View File

@@ -0,0 +1,164 @@
/*
* (C) Copyright 2009
* Marvell Semiconductor <www.marvell.com>
* Written-by: Prafulla Wadaskar <prafulla@marvell.com>
*
* Header file for the Marvell's Feroceon CPU core.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _MVEBU_SOC_H
#define _MVEBU_SOC_H
#define SOC_MV78230_ID 0x7823
#define SOC_MV78260_ID 0x7826
#define SOC_MV78460_ID 0x7846
#define SOC_88F6720_ID 0x6720
#define SOC_88F6810_ID 0x6810
#define SOC_88F6820_ID 0x6820
#define SOC_88F6828_ID 0x6828
/* A375 revisions */
#define MV_88F67XX_A0_ID 0x3
/* A38x revisions */
#define MV_88F68XX_Z1_ID 0x0
#define MV_88F68XX_A0_ID 0x4
/* TCLK Core Clock definition */
#ifndef CONFIG_SYS_TCLK
#define CONFIG_SYS_TCLK 250000000 /* 250MHz */
#endif
/* Armada XP PLL frequency (used for NAND clock generation) */
#define CONFIG_SYS_MVEBU_PLL_CLOCK 2000000000
/* SOC specific definations */
#define INTREG_BASE 0xd0000000
#define INTREG_BASE_ADDR_REG (INTREG_BASE + 0x20080)
#if defined(CONFIG_SPL_BUILD)
/*
* The SPL U-Boot version still runs with the default
* address for the internal registers, configured by
* the BootROM. Only the main U-Boot version uses the
* new internal register base address, that also is
* required for the Linux kernel.
*/
#define SOC_REGS_PHY_BASE 0xd0000000
#else
#define SOC_REGS_PHY_BASE 0xf1000000
#endif
#define MVEBU_REGISTER(x) (SOC_REGS_PHY_BASE + x)
#define MVEBU_SDRAM_SCRATCH (MVEBU_REGISTER(0x01504))
#define MVEBU_L2_CACHE_BASE (MVEBU_REGISTER(0x08000))
#define CONFIG_SYS_PL310_BASE MVEBU_L2_CACHE_BASE
#define MVEBU_TWSI_BASE (MVEBU_REGISTER(0x11000))
#define MVEBU_TWSI1_BASE (MVEBU_REGISTER(0x11100))
#define MVEBU_MPP_BASE (MVEBU_REGISTER(0x18000))
#define MVEBU_GPIO0_BASE (MVEBU_REGISTER(0x18100))
#define MVEBU_GPIO1_BASE (MVEBU_REGISTER(0x18140))
#define MVEBU_GPIO2_BASE (MVEBU_REGISTER(0x18180))
#define MVEBU_SYSTEM_REG_BASE (MVEBU_REGISTER(0x18200))
#define MVEBU_CLOCK_BASE (MVEBU_REGISTER(0x18700))
#define MVEBU_CPU_WIN_BASE (MVEBU_REGISTER(0x20000))
#define MVEBU_SDRAM_BASE (MVEBU_REGISTER(0x20180))
#define MVEBU_TIMER_BASE (MVEBU_REGISTER(0x20300))
#define MVEBU_REG_PCIE_BASE (MVEBU_REGISTER(0x40000))
#define MVEBU_AXP_USB_BASE (MVEBU_REGISTER(0x50000))
#define MVEBU_USB20_BASE (MVEBU_REGISTER(0x58000))
#define MVEBU_AXP_SATA_BASE (MVEBU_REGISTER(0xa0000))
#define MVEBU_SATA0_BASE (MVEBU_REGISTER(0xa8000))
#define MVEBU_NAND_BASE (MVEBU_REGISTER(0xd0000))
#define MVEBU_SDIO_BASE (MVEBU_REGISTER(0xd8000))
#define MVEBU_LCD_BASE (MVEBU_REGISTER(0xe0000))
#define SOC_COHERENCY_FABRIC_CTRL_REG (MVEBU_REGISTER(0x20200))
#define MBUS_ERR_PROP_EN (1 << 8)
#define MBUS_BRIDGE_WIN_CTRL_REG (MVEBU_REGISTER(0x20250))
#define MBUS_BRIDGE_WIN_BASE_REG (MVEBU_REGISTER(0x20254))
#define MVEBU_SOC_DEV_MUX_REG (MVEBU_SYSTEM_REG_BASE + 0x08)
#define NAND_EN BIT(0)
#define NAND_ARBITER_EN BIT(27)
#define ARMADA_XP_PUP_ENABLE (MVEBU_SYSTEM_REG_BASE + 0x44c)
#define GE0_PUP_EN BIT(0)
#define GE1_PUP_EN BIT(1)
#define LCD_PUP_EN BIT(2)
#define NAND_PUP_EN BIT(4)
#define SPI_PUP_EN BIT(5)
#define MVEBU_CORE_DIV_CLK_CTRL(i) (MVEBU_CLOCK_BASE + ((i) * 0x8))
#define NAND_ECC_DIVCKL_RATIO_OFFS 8
#define NAND_ECC_DIVCKL_RATIO_MASK (0x3F << NAND_ECC_DIVCKL_RATIO_OFFS)
#define SDRAM_MAX_CS 4
#define SDRAM_ADDR_MASK 0xFF000000
/* MVEBU CPU memory windows */
#define MVCPU_WIN_CTRL_DATA CPU_WIN_CTRL_DATA
#define MVCPU_WIN_ENABLE CPU_WIN_ENABLE
#define MVCPU_WIN_DISABLE CPU_WIN_DISABLE
#define COMPHY_REFCLK_ALIGNMENT (MVEBU_REGISTER(0x182f8))
/* BootROM error register (also includes some status infos) */
#define CONFIG_BOOTROM_ERR_REG (MVEBU_REGISTER(0x182d0))
#define BOOTROM_ERR_MODE_OFFS 28
#define BOOTROM_ERR_MODE_MASK (0xf << BOOTROM_ERR_MODE_OFFS)
#define BOOTROM_ERR_MODE_UART 0x6
#if defined(CONFIG_ARMADA_375)
/* SAR values for Armada 375 */
#define CONFIG_SAR_REG (MVEBU_REGISTER(0xe8200))
#define CONFIG_SAR2_REG (MVEBU_REGISTER(0xe8204))
#define SAR_CPU_FREQ_OFFS 17
#define SAR_CPU_FREQ_MASK (0x1f << SAR_CPU_FREQ_OFFS)
#define BOOT_DEV_SEL_OFFS 3
#define BOOT_DEV_SEL_MASK (0x3f << BOOT_DEV_SEL_OFFS)
#define BOOT_FROM_UART 0x30
#define BOOT_FROM_SPI 0x38
#elif defined(CONFIG_ARMADA_38X)
/* SAR values for Armada 38x */
#define CONFIG_SAR_REG (MVEBU_REGISTER(0x18600))
#define SAR_CPU_FREQ_OFFS 10
#define SAR_CPU_FREQ_MASK (0x1f << SAR_CPU_FREQ_OFFS)
#define SAR_BOOT_DEVICE_OFFS 4
#define SAR_BOOT_DEVICE_MASK (0x1f << SAR_BOOT_DEVICE_OFFS)
#define BOOT_DEV_SEL_OFFS 4
#define BOOT_DEV_SEL_MASK (0x3f << BOOT_DEV_SEL_OFFS)
#define BOOT_FROM_UART 0x28
#define BOOT_FROM_SPI 0x32
#define BOOT_FROM_MMC 0x30
#define BOOT_FROM_MMC_ALT 0x31
#else
/* SAR values for Armada XP */
#define CONFIG_SAR_REG (MVEBU_REGISTER(0x18230))
#define CONFIG_SAR2_REG (MVEBU_REGISTER(0x18234))
#define SAR_CPU_FREQ_OFFS 21
#define SAR_CPU_FREQ_MASK (0x7 << SAR_CPU_FREQ_OFFS)
#define SAR_FFC_FREQ_OFFS 24
#define SAR_FFC_FREQ_MASK (0xf << SAR_FFC_FREQ_OFFS)
#define SAR2_CPU_FREQ_OFFS 20
#define SAR2_CPU_FREQ_MASK (0x1 << SAR2_CPU_FREQ_OFFS)
#define SAR_BOOT_DEVICE_OFFS 5
#define SAR_BOOT_DEVICE_MASK (0xf << SAR_BOOT_DEVICE_OFFS)
#define BOOT_DEV_SEL_OFFS 5
#define BOOT_DEV_SEL_MASK (0xf << BOOT_DEV_SEL_OFFS)
#define BOOT_FROM_UART 0x2
#define BOOT_FROM_SPI 0x3
#endif
#endif /* _MVEBU_SOC_H */

View File

@@ -0,0 +1,71 @@
/*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <config.h>
#include <linux/linkage.h>
ENTRY(save_boot_params)
stmfd sp!, {r0 - r12, lr} /* @ save registers on stack */
ldr r12, =CONFIG_SPL_BOOTROM_SAVE
str sp, [r12]
b save_boot_params_ret
ENDPROC(save_boot_params)
ENTRY(return_to_bootrom)
ldr r12, =CONFIG_SPL_BOOTROM_SAVE
ldr sp, [r12]
mov r0, #0x0 /* @ return value: 0x0 NO_ERR */
ldmfd sp!, {r0 - r12, pc} /* @ restore regs and return */
ENDPROC(return_to_bootrom)
/*
* cache_inv - invalidate Cache line
* r0 - dest
*/
.global cache_inv
.type cache_inv, %function
cache_inv:
stmfd sp!, {r1-r12}
mcr p15, 0, r0, c7, c6, 1
ldmfd sp!, {r1-r12}
bx lr
/*
* flush_l1_v6 - l1 cache clean invalidate
* r0 - dest
*/
.global flush_l1_v6
.type flush_l1_v6, %function
flush_l1_v6:
stmfd sp!, {r1-r12}
mcr p15, 0, r0, c7, c10, 5 /* @ data memory barrier */
mcr p15, 0, r0, c7, c14, 1 /* @ clean & invalidate D line */
mcr p15, 0, r0, c7, c10, 4 /* @ data sync barrier */
ldmfd sp!, {r1-r12}
bx lr
/*
* flush_l1_v7 - l1 cache clean invalidate
* r0 - dest
*/
.global flush_l1_v7
.type flush_l1_v7, %function
flush_l1_v7:
stmfd sp!, {r1-r12}
dmb /* @data memory barrier */
mcr p15, 0, r0, c7, c14, 1 /* @ clean & invalidate D line */
dsb /* @data sync barrier */
ldmfd sp!, {r1-r12}
bx lr

View File

@@ -0,0 +1,521 @@
/*
* Address map functions for Marvell EBU SoCs (Kirkwood, Armada
* 370/XP, Dove, Orion5x and MV78xx0)
*
* Ported from the Barebox version to U-Boot by:
* Stefan Roese <sr@denx.de>
*
* The Barebox version is:
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
*
* based on mbus driver from Linux
* (C) Copyright 2008 Marvell Semiconductor
*
* SPDX-License-Identifier: GPL-2.0
*
* The Marvell EBU SoCs have a configurable physical address space:
* the physical address at which certain devices (PCIe, NOR, NAND,
* etc.) sit can be configured. The configuration takes place through
* two sets of registers:
*
* - One to configure the access of the CPU to the devices. Depending
* on the families, there are between 8 and 20 configurable windows,
* each can be use to create a physical memory window that maps to a
* specific device. Devices are identified by a tuple (target,
* attribute).
*
* - One to configure the access to the CPU to the SDRAM. There are
* either 2 (for Dove) or 4 (for other families) windows to map the
* SDRAM into the physical address space.
*
* This driver:
*
* - Reads out the SDRAM address decoding windows at initialization
* time, and fills the mbus_dram_info structure with these
* informations. The exported function mv_mbus_dram_info() allow
* device drivers to get those informations related to the SDRAM
* address decoding windows. This is because devices also have their
* own windows (configured through registers that are part of each
* device register space), and therefore the drivers for Marvell
* devices have to configure those device -> SDRAM windows to ensure
* that DMA works properly.
*
* - Provides an API for platform code or device drivers to
* dynamically add or remove address decoding windows for the CPU ->
* device accesses. This API is mvebu_mbus_add_window_by_id(),
* mvebu_mbus_add_window_remap_by_id() and
* mvebu_mbus_del_window().
*/
#include <common.h>
#include <asm/errno.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>
#include <linux/log2.h>
#include <linux/mbus.h>
/* DDR target is the same on all platforms */
#define TARGET_DDR 0
/* CPU Address Decode Windows registers */
#define WIN_CTRL_OFF 0x0000
#define WIN_CTRL_ENABLE BIT(0)
#define WIN_CTRL_TGT_MASK 0xf0
#define WIN_CTRL_TGT_SHIFT 4
#define WIN_CTRL_ATTR_MASK 0xff00
#define WIN_CTRL_ATTR_SHIFT 8
#define WIN_CTRL_SIZE_MASK 0xffff0000
#define WIN_CTRL_SIZE_SHIFT 16
#define WIN_BASE_OFF 0x0004
#define WIN_BASE_LOW 0xffff0000
#define WIN_BASE_HIGH 0xf
#define WIN_REMAP_LO_OFF 0x0008
#define WIN_REMAP_LOW 0xffff0000
#define WIN_REMAP_HI_OFF 0x000c
#define ATTR_HW_COHERENCY (0x1 << 4)
#define DDR_BASE_CS_OFF(n) (0x0000 + ((n) << 3))
#define DDR_BASE_CS_HIGH_MASK 0xf
#define DDR_BASE_CS_LOW_MASK 0xff000000
#define DDR_SIZE_CS_OFF(n) (0x0004 + ((n) << 3))
#define DDR_SIZE_ENABLED BIT(0)
#define DDR_SIZE_CS_MASK 0x1c
#define DDR_SIZE_CS_SHIFT 2
#define DDR_SIZE_MASK 0xff000000
#define DOVE_DDR_BASE_CS_OFF(n) ((n) << 4)
struct mvebu_mbus_state;
struct mvebu_mbus_soc_data {
unsigned int num_wins;
unsigned int num_remappable_wins;
unsigned int (*win_cfg_offset)(const int win);
void (*setup_cpu_target)(struct mvebu_mbus_state *s);
};
struct mvebu_mbus_state mbus_state
__attribute__ ((section(".data")));
static struct mbus_dram_target_info mbus_dram_info
__attribute__ ((section(".data")));
/*
* Functions to manipulate the address decoding windows
*/
static void mvebu_mbus_read_window(struct mvebu_mbus_state *mbus,
int win, int *enabled, u64 *base,
u32 *size, u8 *target, u8 *attr,
u64 *remap)
{
void __iomem *addr = mbus->mbuswins_base +
mbus->soc->win_cfg_offset(win);
u32 basereg = readl(addr + WIN_BASE_OFF);
u32 ctrlreg = readl(addr + WIN_CTRL_OFF);
if (!(ctrlreg & WIN_CTRL_ENABLE)) {
*enabled = 0;
return;
}
*enabled = 1;
*base = ((u64)basereg & WIN_BASE_HIGH) << 32;
*base |= (basereg & WIN_BASE_LOW);
*size = (ctrlreg | ~WIN_CTRL_SIZE_MASK) + 1;
if (target)
*target = (ctrlreg & WIN_CTRL_TGT_MASK) >> WIN_CTRL_TGT_SHIFT;
if (attr)
*attr = (ctrlreg & WIN_CTRL_ATTR_MASK) >> WIN_CTRL_ATTR_SHIFT;
if (remap) {
if (win < mbus->soc->num_remappable_wins) {
u32 remap_low = readl(addr + WIN_REMAP_LO_OFF);
u32 remap_hi = readl(addr + WIN_REMAP_HI_OFF);
*remap = ((u64)remap_hi << 32) | remap_low;
} else {
*remap = 0;
}
}
}
static void mvebu_mbus_disable_window(struct mvebu_mbus_state *mbus,
int win)
{
void __iomem *addr;
addr = mbus->mbuswins_base + mbus->soc->win_cfg_offset(win);
writel(0, addr + WIN_BASE_OFF);
writel(0, addr + WIN_CTRL_OFF);
if (win < mbus->soc->num_remappable_wins) {
writel(0, addr + WIN_REMAP_LO_OFF);
writel(0, addr + WIN_REMAP_HI_OFF);
}
}
/* Checks whether the given window number is available */
static int mvebu_mbus_window_is_free(struct mvebu_mbus_state *mbus,
const int win)
{
void __iomem *addr = mbus->mbuswins_base +
mbus->soc->win_cfg_offset(win);
u32 ctrl = readl(addr + WIN_CTRL_OFF);
return !(ctrl & WIN_CTRL_ENABLE);
}
/*
* Checks whether the given (base, base+size) area doesn't overlap an
* existing region
*/
static int mvebu_mbus_window_conflicts(struct mvebu_mbus_state *mbus,
phys_addr_t base, size_t size,
u8 target, u8 attr)
{
u64 end = (u64)base + size;
int win;
for (win = 0; win < mbus->soc->num_wins; win++) {
u64 wbase, wend;
u32 wsize;
u8 wtarget, wattr;
int enabled;
mvebu_mbus_read_window(mbus, win,
&enabled, &wbase, &wsize,
&wtarget, &wattr, NULL);
if (!enabled)
continue;
wend = wbase + wsize;
/*
* Check if the current window overlaps with the
* proposed physical range
*/
if ((u64)base < wend && end > wbase)
return 0;
/*
* Check if target/attribute conflicts
*/
if (target == wtarget && attr == wattr)
return 0;
}
return 1;
}
static int mvebu_mbus_find_window(struct mvebu_mbus_state *mbus,
phys_addr_t base, size_t size)
{
int win;
for (win = 0; win < mbus->soc->num_wins; win++) {
u64 wbase;
u32 wsize;
int enabled;
mvebu_mbus_read_window(mbus, win,
&enabled, &wbase, &wsize,
NULL, NULL, NULL);
if (!enabled)
continue;
if (base == wbase && size == wsize)
return win;
}
return -ENODEV;
}
static int mvebu_mbus_setup_window(struct mvebu_mbus_state *mbus,
int win, phys_addr_t base, size_t size,
phys_addr_t remap, u8 target,
u8 attr)
{
void __iomem *addr = mbus->mbuswins_base +
mbus->soc->win_cfg_offset(win);
u32 ctrl, remap_addr;
ctrl = ((size - 1) & WIN_CTRL_SIZE_MASK) |
(attr << WIN_CTRL_ATTR_SHIFT) |
(target << WIN_CTRL_TGT_SHIFT) |
WIN_CTRL_ENABLE;
writel(base & WIN_BASE_LOW, addr + WIN_BASE_OFF);
writel(ctrl, addr + WIN_CTRL_OFF);
if (win < mbus->soc->num_remappable_wins) {
if (remap == MVEBU_MBUS_NO_REMAP)
remap_addr = base;
else
remap_addr = remap;
writel(remap_addr & WIN_REMAP_LOW, addr + WIN_REMAP_LO_OFF);
writel(0, addr + WIN_REMAP_HI_OFF);
}
return 0;
}
static int mvebu_mbus_alloc_window(struct mvebu_mbus_state *mbus,
phys_addr_t base, size_t size,
phys_addr_t remap, u8 target,
u8 attr)
{
int win;
if (remap == MVEBU_MBUS_NO_REMAP) {
for (win = mbus->soc->num_remappable_wins;
win < mbus->soc->num_wins; win++)
if (mvebu_mbus_window_is_free(mbus, win))
return mvebu_mbus_setup_window(mbus, win, base,
size, remap,
target, attr);
}
for (win = 0; win < mbus->soc->num_wins; win++)
if (mvebu_mbus_window_is_free(mbus, win))
return mvebu_mbus_setup_window(mbus, win, base, size,
remap, target, attr);
return -ENOMEM;
}
/*
* SoC-specific functions and definitions
*/
static unsigned int armada_370_xp_mbus_win_offset(int win)
{
/* The register layout is a bit annoying and the below code
* tries to cope with it.
* - At offset 0x0, there are the registers for the first 8
* windows, with 4 registers of 32 bits per window (ctrl,
* base, remap low, remap high)
* - Then at offset 0x80, there is a hole of 0x10 bytes for
* the internal registers base address and internal units
* sync barrier register.
* - Then at offset 0x90, there the registers for 12
* windows, with only 2 registers of 32 bits per window
* (ctrl, base).
*/
if (win < 8)
return win << 4;
else
return 0x90 + ((win - 8) << 3);
}
static unsigned int orion5x_mbus_win_offset(int win)
{
return win << 4;
}
static void mvebu_mbus_default_setup_cpu_target(struct mvebu_mbus_state *mbus)
{
int i;
int cs;
mbus_dram_info.mbus_dram_target_id = TARGET_DDR;
for (i = 0, cs = 0; i < 4; i++) {
u32 base = readl(mbus->sdramwins_base + DDR_BASE_CS_OFF(i));
u32 size = readl(mbus->sdramwins_base + DDR_SIZE_CS_OFF(i));
/*
* We only take care of entries for which the chip
* select is enabled, and that don't have high base
* address bits set (devices can only access the first
* 32 bits of the memory).
*/
if ((size & DDR_SIZE_ENABLED) &&
!(base & DDR_BASE_CS_HIGH_MASK)) {
struct mbus_dram_window *w;
w = &mbus_dram_info.cs[cs++];
w->cs_index = i;
w->mbus_attr = 0xf & ~(1 << i);
w->base = base & DDR_BASE_CS_LOW_MASK;
w->size = (size | ~DDR_SIZE_MASK) + 1;
}
}
mbus_dram_info.num_cs = cs;
}
static const struct mvebu_mbus_soc_data
armada_370_xp_mbus_data __maybe_unused = {
.num_wins = 20,
.num_remappable_wins = 8,
.win_cfg_offset = armada_370_xp_mbus_win_offset,
.setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
};
static const struct mvebu_mbus_soc_data
kirkwood_mbus_data __maybe_unused = {
.num_wins = 8,
.num_remappable_wins = 4,
.win_cfg_offset = orion5x_mbus_win_offset,
.setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
};
/*
* Public API of the driver
*/
const struct mbus_dram_target_info *mvebu_mbus_dram_info(void)
{
return &mbus_dram_info;
}
int mvebu_mbus_add_window_remap_by_id(unsigned int target,
unsigned int attribute,
phys_addr_t base, size_t size,
phys_addr_t remap)
{
struct mvebu_mbus_state *s = &mbus_state;
if (!mvebu_mbus_window_conflicts(s, base, size, target, attribute)) {
printf("Cannot add window '%x:%x', conflicts with another window\n",
target, attribute);
return -EINVAL;
}
return mvebu_mbus_alloc_window(s, base, size, remap, target, attribute);
}
int mvebu_mbus_add_window_by_id(unsigned int target, unsigned int attribute,
phys_addr_t base, size_t size)
{
return mvebu_mbus_add_window_remap_by_id(target, attribute, base,
size, MVEBU_MBUS_NO_REMAP);
}
int mvebu_mbus_del_window(phys_addr_t base, size_t size)
{
int win;
win = mvebu_mbus_find_window(&mbus_state, base, size);
if (win < 0)
return win;
mvebu_mbus_disable_window(&mbus_state, win);
return 0;
}
static void mvebu_mbus_get_lowest_base(struct mvebu_mbus_state *mbus,
phys_addr_t *base)
{
int win;
*base = 0xffffffff;
for (win = 0; win < mbus->soc->num_wins; win++) {
u64 wbase;
u32 wsize;
u8 wtarget, wattr;
int enabled;
mvebu_mbus_read_window(mbus, win,
&enabled, &wbase, &wsize,
&wtarget, &wattr, NULL);
if (!enabled)
continue;
if (wbase < *base)
*base = wbase;
}
}
static void mvebu_config_mbus_bridge(struct mvebu_mbus_state *mbus)
{
phys_addr_t base;
u32 val;
u32 size;
/* Set MBUS bridge base/ctrl */
mvebu_mbus_get_lowest_base(&mbus_state, &base);
size = 0xffffffff - base + 1;
if (!is_power_of_2(size)) {
/* Round up to next power of 2 */
size = 1 << (ffs(base) + 1);
base = 0xffffffff - size + 1;
}
/* Now write base and size */
writel(base, MBUS_BRIDGE_WIN_BASE_REG);
/* Align window size to 64KiB */
val = (size / (64 << 10)) - 1;
writel((val << 16) | 0x1, MBUS_BRIDGE_WIN_CTRL_REG);
}
int mbus_dt_setup_win(struct mvebu_mbus_state *mbus,
u32 base, u32 size, u8 target, u8 attr)
{
if (!mvebu_mbus_window_conflicts(mbus, base, size, target, attr)) {
printf("Cannot add window '%04x:%04x', conflicts with another window\n",
target, attr);
return -EBUSY;
}
/*
* In U-Boot we first try to add the mbus window to the remap windows.
* If this fails, lets try to add the windows to the non-remap windows.
*/
if (mvebu_mbus_alloc_window(mbus, base, size, base, target, attr)) {
if (mvebu_mbus_alloc_window(mbus, base, size,
MVEBU_MBUS_NO_REMAP, target, attr))
return -ENOMEM;
}
/*
* Re-configure the mbus bridge registers each time this function
* is called. Since it may get called from the board code in
* later boot stages as well.
*/
mvebu_config_mbus_bridge(mbus);
return 0;
}
int mvebu_mbus_probe(struct mbus_win windows[], int count)
{
int win;
int ret;
int i;
#if defined(CONFIG_KIRKWOOD)
mbus_state.soc = &kirkwood_mbus_data;
#endif
#if defined(CONFIG_ARCH_MVEBU)
mbus_state.soc = &armada_370_xp_mbus_data;
#endif
mbus_state.mbuswins_base = (void __iomem *)MVEBU_CPU_WIN_BASE;
mbus_state.sdramwins_base = (void __iomem *)MVEBU_SDRAM_BASE;
for (win = 0; win < mbus_state.soc->num_wins; win++)
mvebu_mbus_disable_window(&mbus_state, win);
mbus_state.soc->setup_cpu_target(&mbus_state);
/* Setup statically declared windows in the DT */
for (i = 0; i < count; i++) {
u32 base, size;
u8 target, attr;
target = windows[i].target;
attr = windows[i].attr;
base = windows[i].base;
size = windows[i].size;
ret = mbus_dt_setup_win(&mbus_state, base, size, target, attr);
if (ret < 0)
return ret;
}
return 0;
}

View File

@@ -0,0 +1,9 @@
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-$(CONFIG_SPL_BUILD) = ctrl_pex.o
obj-$(CONFIG_SPL_BUILD) += high_speed_env_spec.o
obj-$(CONFIG_SPL_BUILD) += high_speed_env_spec-38x.o
obj-$(CONFIG_SPL_BUILD) += seq_exec.o
obj-$(CONFIG_SPL_BUILD) += sys_env_lib.o

View File

@@ -0,0 +1,346 @@
/*
* Copyright (C) Marvell International Ltd. and its affiliates
*
* SPDX-License-Identifier: GPL-2.0
*/
#include <common.h>
#include <spl.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>
#include "ctrl_pex.h"
#include "sys_env_lib.h"
int hws_pex_config(const struct serdes_map *serdes_map, u8 count)
{
u32 pex_idx, tmp, next_busno, first_busno, temp_pex_reg,
temp_reg, addr, dev_id, ctrl_mode;
enum serdes_type serdes_type;
u32 idx;
DEBUG_INIT_FULL_S("\n### hws_pex_config ###\n");
for (idx = 0; idx < count; idx++) {
serdes_type = serdes_map[idx].serdes_type;
/* configuration for PEX only */
if ((serdes_type != PEX0) && (serdes_type != PEX1) &&
(serdes_type != PEX2) && (serdes_type != PEX3))
continue;
if ((serdes_type != PEX0) &&
((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) ||
(serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) {
/* for PEX by4 - relevant for the first port only */
continue;
}
pex_idx = serdes_type - PEX0;
tmp = reg_read(PEX_CAPABILITIES_REG(pex_idx));
tmp &= ~(0xf << 20);
tmp |= (0x4 << 20);
reg_write(PEX_CAPABILITIES_REG(pex_idx), tmp);
}
tmp = reg_read(SOC_CTRL_REG);
tmp &= ~0x03;
for (idx = 0; idx < count; idx++) {
serdes_type = serdes_map[idx].serdes_type;
if ((serdes_type != PEX0) &&
((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) ||
(serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) {
/* for PEX by4 - relevant for the first port only */
continue;
}
switch (serdes_type) {
case PEX0:
tmp |= 0x1 << PCIE0_ENABLE_OFFS;
break;
case PEX1:
tmp |= 0x1 << PCIE1_ENABLE_OFFS;
break;
case PEX2:
tmp |= 0x1 << PCIE2_ENABLE_OFFS;
break;
case PEX3:
tmp |= 0x1 << PCIE3_ENABLE_OFFS;
break;
default:
break;
}
}
reg_write(SOC_CTRL_REG, tmp);
/* Support gen1/gen2 */
DEBUG_INIT_FULL_S("Support gen1/gen2\n");
next_busno = 0;
mdelay(150);
for (idx = 0; idx < count; idx++) {
serdes_type = serdes_map[idx].serdes_type;
DEBUG_INIT_FULL_S(" serdes_type=0x");
DEBUG_INIT_FULL_D(serdes_type, 8);
DEBUG_INIT_FULL_S("\n");
DEBUG_INIT_FULL_S(" idx=0x");
DEBUG_INIT_FULL_D(idx, 8);
DEBUG_INIT_FULL_S("\n");
/* Configuration for PEX only */
if ((serdes_type != PEX0) && (serdes_type != PEX1) &&
(serdes_type != PEX2) && (serdes_type != PEX3))
continue;
if ((serdes_type != PEX0) &&
((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) ||
(serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) {
/* for PEX by4 - relevant for the first port only */
continue;
}
pex_idx = serdes_type - PEX0;
tmp = reg_read(PEX_DBG_STATUS_REG(pex_idx));
first_busno = next_busno;
if ((tmp & 0x7f) != 0x7e) {
DEBUG_INIT_S("PCIe, Idx ");
DEBUG_INIT_D(pex_idx, 1);
DEBUG_INIT_S(": detected no link\n");
continue;
}
next_busno++;
temp_pex_reg = reg_read((PEX_CFG_DIRECT_ACCESS
(pex_idx, PEX_LINK_CAPABILITY_REG)));
temp_pex_reg &= 0xf;
if (temp_pex_reg != 0x2)
continue;
temp_reg = (reg_read(PEX_CFG_DIRECT_ACCESS(
pex_idx,
PEX_LINK_CTRL_STAT_REG)) &
0xf0000) >> 16;
/* Check if the link established is GEN1 */
DEBUG_INIT_FULL_S
("Checking if the link established is gen1\n");
if (temp_reg != 0x1)
continue;
pex_local_bus_num_set(pex_idx, first_busno);
pex_local_dev_num_set(pex_idx, 1);
DEBUG_INIT_FULL_S("PCIe, Idx ");
DEBUG_INIT_FULL_D(pex_idx, 1);
DEBUG_INIT_S(":** Link is Gen1, check the EP capability\n");
/* link is Gen1, check the EP capability */
addr = pex_config_read(pex_idx, first_busno, 0, 0, 0x34) & 0xff;
DEBUG_INIT_FULL_C("pex_config_read: return addr=0x%x", addr, 4);
if (addr == 0xff) {
DEBUG_INIT_FULL_C
("pex_config_read: return 0xff -->PCIe (%d): Detected No Link.",
pex_idx, 1);
continue;
}
while ((pex_config_read(pex_idx, first_busno, 0, 0, addr)
& 0xff) != 0x10) {
addr = (pex_config_read(pex_idx, first_busno, 0,
0, addr) & 0xff00) >> 8;
}
/* Check for Gen2 and above */
if ((pex_config_read(pex_idx, first_busno, 0, 0,
addr + 0xc) & 0xf) < 0x2) {
DEBUG_INIT_S("PCIe, Idx ");
DEBUG_INIT_D(pex_idx, 1);
DEBUG_INIT_S(": remains Gen1\n");
continue;
}
tmp = reg_read(PEX_LINK_CTRL_STATUS2_REG(pex_idx));
DEBUG_RD_REG(PEX_LINK_CTRL_STATUS2_REG(pex_idx), tmp);
tmp &= ~(BIT(0) | BIT(1));
tmp |= BIT(1);
tmp |= BIT(6); /* Select Deemphasize (-3.5d_b) */
reg_write(PEX_LINK_CTRL_STATUS2_REG(pex_idx), tmp);
DEBUG_WR_REG(PEX_LINK_CTRL_STATUS2_REG(pex_idx), tmp);
tmp = reg_read(PEX_CTRL_REG(pex_idx));
DEBUG_RD_REG(PEX_CTRL_REG(pex_idx), tmp);
tmp |= BIT(10);
reg_write(PEX_CTRL_REG(pex_idx), tmp);
DEBUG_WR_REG(PEX_CTRL_REG(pex_idx), tmp);
/*
* We need to wait 10ms before reading the PEX_DBG_STATUS_REG
* in order not to read the status of the former state
*/
mdelay(10);
DEBUG_INIT_S("PCIe, Idx ");
DEBUG_INIT_D(pex_idx, 1);
DEBUG_INIT_S
(": Link upgraded to Gen2 based on client cpabilities\n");
}
/* Update pex DEVICE ID */
ctrl_mode = sys_env_model_get();
for (idx = 0; idx < count; idx++) {
serdes_type = serdes_map[idx].serdes_type;
/* configuration for PEX only */
if ((serdes_type != PEX0) && (serdes_type != PEX1) &&
(serdes_type != PEX2) && (serdes_type != PEX3))
continue;
if ((serdes_type != PEX0) &&
((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) ||
(serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) {
/* for PEX by4 - relevant for the first port only */
continue;
}
pex_idx = serdes_type - PEX0;
dev_id = reg_read(PEX_CFG_DIRECT_ACCESS
(pex_idx, PEX_DEVICE_AND_VENDOR_ID));
dev_id &= 0xffff;
dev_id |= ((ctrl_mode << 16) & 0xffff0000);
reg_write(PEX_CFG_DIRECT_ACCESS
(pex_idx, PEX_DEVICE_AND_VENDOR_ID), dev_id);
}
DEBUG_INIT_FULL_C("Update PEX Device ID ", ctrl_mode, 4);
return MV_OK;
}
int pex_local_bus_num_set(u32 pex_if, u32 bus_num)
{
u32 pex_status;
DEBUG_INIT_FULL_S("\n### pex_local_bus_num_set ###\n");
if (bus_num >= MAX_PEX_BUSSES) {
DEBUG_INIT_C("pex_local_bus_num_set: Illegal bus number %d\n",
bus_num, 4);
return MV_BAD_PARAM;
}
pex_status = reg_read(PEX_STATUS_REG(pex_if));
pex_status &= ~PXSR_PEX_BUS_NUM_MASK;
pex_status |=
(bus_num << PXSR_PEX_BUS_NUM_OFFS) & PXSR_PEX_BUS_NUM_MASK;
reg_write(PEX_STATUS_REG(pex_if), pex_status);
return MV_OK;
}
int pex_local_dev_num_set(u32 pex_if, u32 dev_num)
{
u32 pex_status;
DEBUG_INIT_FULL_S("\n### pex_local_dev_num_set ###\n");
pex_status = reg_read(PEX_STATUS_REG(pex_if));
pex_status &= ~PXSR_PEX_DEV_NUM_MASK;
pex_status |=
(dev_num << PXSR_PEX_DEV_NUM_OFFS) & PXSR_PEX_DEV_NUM_MASK;
reg_write(PEX_STATUS_REG(pex_if), pex_status);
return MV_OK;
}
/*
* pex_config_read - Read from configuration space
*
* DESCRIPTION:
* This function performs a 32 bit read from PEX configuration space.
* It supports both type 0 and type 1 of Configuration Transactions
* (local and over bridge). In order to read from local bus segment, use
* bus number retrieved from pex_local_bus_num_get(). Other bus numbers
* will result configuration transaction of type 1 (over bridge).
*
* INPUT:
* pex_if - PEX interface number.
* bus - PEX segment bus number.
* dev - PEX device number.
* func - Function number.
* reg_offs - Register offset.
*
* OUTPUT:
* None.
*
* RETURN:
* 32bit register data, 0xffffffff on error
*/
u32 pex_config_read(u32 pex_if, u32 bus, u32 dev, u32 func, u32 reg_off)
{
u32 pex_data = 0;
u32 local_dev, local_bus;
u32 pex_status;
pex_status = reg_read(PEX_STATUS_REG(pex_if));
local_dev =
((pex_status & PXSR_PEX_DEV_NUM_MASK) >> PXSR_PEX_DEV_NUM_OFFS);
local_bus =
((pex_status & PXSR_PEX_BUS_NUM_MASK) >> PXSR_PEX_BUS_NUM_OFFS);
/*
* In PCI Express we have only one device number
* and this number is the first number we encounter
* else that the local_dev
* spec pex define return on config read/write on any device
*/
if (bus == local_bus) {
if (local_dev == 0) {
/*
* if local dev is 0 then the first number we encounter
* after 0 is 1
*/
if ((dev != 1) && (dev != local_dev))
return MV_ERROR;
} else {
/*
* if local dev is not 0 then the first number we
* encounter is 0
*/
if ((dev != 0) && (dev != local_dev))
return MV_ERROR;
}
}
/* Creating PEX address to be passed */
pex_data = (bus << PXCAR_BUS_NUM_OFFS);
pex_data |= (dev << PXCAR_DEVICE_NUM_OFFS);
pex_data |= (func << PXCAR_FUNC_NUM_OFFS);
/* Legacy register space */
pex_data |= (reg_off & PXCAR_REG_NUM_MASK);
/* Extended register space */
pex_data |= (((reg_off & PXCAR_REAL_EXT_REG_NUM_MASK) >>
PXCAR_REAL_EXT_REG_NUM_OFFS) << PXCAR_EXT_REG_NUM_OFFS);
pex_data |= PXCAR_CONFIG_EN;
/* Write the address to the PEX configuration address register */
reg_write(PEX_CFG_ADDR_REG(pex_if), pex_data);
/*
* In order to let the PEX controller absorbed the address
* of the read transaction we perform a validity check that
* the address was written
*/
if (pex_data != reg_read(PEX_CFG_ADDR_REG(pex_if)))
return MV_ERROR;
/* Cleaning Master Abort */
reg_bit_set(PEX_CFG_DIRECT_ACCESS(pex_if, PEX_STATUS_AND_COMMAND),
PXSAC_MABORT);
/* Read the Data returned in the PEX Data register */
pex_data = reg_read(PEX_CFG_DATA_REG(pex_if));
DEBUG_INIT_FULL_C(" --> ", pex_data, 4);
return pex_data;
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (C) Marvell International Ltd. and its affiliates
*
* SPDX-License-Identifier: GPL-2.0
*/
#ifndef _CTRL_PEX_H
#define _CTRL_PEX_H
#include "high_speed_env_spec.h"
/* Sample at Reset */
#define MPP_SAMPLE_AT_RESET(id) (0xe4200 + (id * 4))
/* PCI Express Control and Status Registers */
#define MAX_PEX_BUSSES 256
#define MISC_REGS_OFFSET 0x18200
#define MV_MISC_REGS_BASE MISC_REGS_OFFSET
#define SOC_CTRL_REG (MV_MISC_REGS_BASE + 0x4)
#define PEX_IF_REGS_OFFSET(if) ((if) > 0 ? \
(0x40000 + ((if) - 1) * 0x4000) : \
0x80000)
#define PEX_IF_REGS_BASE(if) (PEX_IF_REGS_OFFSET(if))
#define PEX_CAPABILITIES_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x60)
#define PEX_LINK_CTRL_STATUS2_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x90)
#define PEX_CTRL_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x1a00)
#define PEX_STATUS_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x1a04)
#define PEX_DBG_STATUS_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x1a64)
#define PEX_LINK_CAPABILITY_REG 0x6c
#define PEX_LINK_CTRL_STAT_REG 0x70
#define PXSR_PEX_DEV_NUM_OFFS 16 /* Device Number Indication */
#define PXSR_PEX_DEV_NUM_MASK (0x1f << PXSR_PEX_DEV_NUM_OFFS)
#define PXSR_PEX_BUS_NUM_OFFS 8 /* Bus Number Indication */
#define PXSR_PEX_BUS_NUM_MASK (0xff << PXSR_PEX_BUS_NUM_OFFS)
/* PEX_CAPABILITIES_REG fields */
#define PCIE0_ENABLE_OFFS 0
#define PCIE0_ENABLE_MASK (0x1 << PCIE0_ENABLE_OFFS)
#define PCIE1_ENABLE_OFFS 1
#define PCIE1_ENABLE_MASK (0x1 << PCIE1_ENABLE_OFFS)
#define PCIE2_ENABLE_OFFS 2
#define PCIE2_ENABLE_MASK (0x1 << PCIE2_ENABLE_OFFS)
#define PCIE3_ENABLE_OFFS 3
#define PCIE4_ENABLE_MASK (0x1 << PCIE3_ENABLE_OFFS)
/* Controller revision info */
#define PEX_DEVICE_AND_VENDOR_ID 0x000
/* PCI Express Configuration Address Register */
#define PXCAR_REG_NUM_OFFS 2
#define PXCAR_REG_NUM_MAX 0x3f
#define PXCAR_REG_NUM_MASK (PXCAR_REG_NUM_MAX << \
PXCAR_REG_NUM_OFFS)
#define PXCAR_FUNC_NUM_OFFS 8
#define PXCAR_FUNC_NUM_MAX 0x7
#define PXCAR_FUNC_NUM_MASK (PXCAR_FUNC_NUM_MAX << \
PXCAR_FUNC_NUM_OFFS)
#define PXCAR_DEVICE_NUM_OFFS 11
#define PXCAR_DEVICE_NUM_MAX 0x1f
#define PXCAR_DEVICE_NUM_MASK (PXCAR_DEVICE_NUM_MAX << \
PXCAR_DEVICE_NUM_OFFS)
#define PXCAR_BUS_NUM_OFFS 16
#define PXCAR_BUS_NUM_MAX 0xff
#define PXCAR_BUS_NUM_MASK (PXCAR_BUS_NUM_MAX << \
PXCAR_BUS_NUM_OFFS)
#define PXCAR_EXT_REG_NUM_OFFS 24
#define PXCAR_EXT_REG_NUM_MAX 0xf
#define PEX_CFG_ADDR_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x18f8)
#define PEX_CFG_DATA_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x18fc)
#define PXCAR_REAL_EXT_REG_NUM_OFFS 8
#define PXCAR_REAL_EXT_REG_NUM_MASK (0xf << PXCAR_REAL_EXT_REG_NUM_OFFS)
#define PXCAR_CONFIG_EN BIT(31)
#define PEX_STATUS_AND_COMMAND 0x004
#define PXSAC_MABORT BIT(29) /* Recieved Master Abort */
int hws_pex_config(const struct serdes_map *serdes_map, u8 count);
int pex_local_bus_num_set(u32 pex_if, u32 bus_num);
int pex_local_dev_num_set(u32 pex_if, u32 dev_num);
u32 pex_config_read(u32 pex_if, u32 bus, u32 dev, u32 func, u32 reg_off);
#endif

View File

@@ -0,0 +1,157 @@
/*
* Copyright (C) Marvell International Ltd. and its affiliates
*
* SPDX-License-Identifier: GPL-2.0
*/
#include <common.h>
#include <spl.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>
#include "high_speed_env_spec.h"
#include "sys_env_lib.h"
#define SERDES_VERION "2.0"
u8 selectors_serdes_rev1_map[LAST_SERDES_TYPE][MAX_SERDES_LANES] = {
/* 0 1 2 3 4 5 */
{0x1, 0x1, NA, NA, NA, NA}, /* PEX0 */
{NA, 0x2, 0x1, NA, 0x1, NA}, /* PEX1 */
{NA, NA, 0x2, NA, NA, 0x1}, /* PEX2 */
{NA, NA, NA, 0x1, NA, NA}, /* PEX3 */
{0x2, 0x3, NA, NA, NA, NA}, /* SATA0 */
{NA, NA, 0x3, NA, 0x2, NA}, /* SATA1 */
{NA, NA, NA, NA, 0x6, 0x2}, /* SATA2 */
{NA, NA, NA, 0x3, NA, NA}, /* SATA3 */
{0x3, 0x4, NA, NA, NA, NA}, /* SGMII0 */
{NA, 0x5, 0x4, NA, 0x3, NA}, /* SGMII1 */
{NA, NA, NA, 0x4, NA, 0x3}, /* SGMII2 */
{NA, 0x7, NA, NA, NA, NA}, /* QSGMII */
{NA, 0x6, NA, NA, 0x4, NA}, /* USB3_HOST0 */
{NA, NA, NA, 0x5, NA, 0x4}, /* USB3_HOST1 */
{NA, NA, NA, 0x6, 0x5, 0x5}, /* USB3_DEVICE */
{0x0, 0x0, 0x0, 0x0, 0x0, 0x0} /* DEFAULT_SERDES */
};
int hws_serdes_seq_init(void)
{
DEBUG_INIT_FULL_S("\n### serdes_seq_init ###\n");
if (hws_serdes_seq_db_init() != MV_OK) {
printf("hws_serdes_seq_init: Error: Serdes initialization fail\n");
return MV_FAIL;
}
return MV_OK;
}
int serdes_power_up_ctrl_ext(u32 serdes_num, int serdes_power_up,
enum serdes_type serdes_type,
enum serdes_speed baud_rate,
enum serdes_mode serdes_mode,
enum ref_clock ref_clock)
{
return MV_NOT_SUPPORTED;
}
u32 hws_serdes_silicon_ref_clock_get(void)
{
DEBUG_INIT_FULL_S("\n### hws_serdes_silicon_ref_clock_get ###\n");
return REF_CLOCK_25MHZ;
}
u32 hws_serdes_get_max_lane(void)
{
switch (sys_env_device_id_get()) {
case MV_6811: /* A381/A3282: 6811/6821: single/dual cpu */
return 4;
case MV_6810:
return 5;
case MV_6820:
case MV_6828:
return 6;
default: /* not the right module */
printf("%s: Device ID Error, using 4 SerDes lanes\n",
__func__);
return 4;
}
return 6;
}
int hws_is_serdes_active(u8 lane_num)
{
int ret = 1;
/* Maximum lane count for A388 (6828) is 6 */
if (lane_num > 6)
ret = 0;
/* 4th Lane (#4 on Device 6810 is not Active */
if (sys_env_device_id_get() == MV_6810 && lane_num == 4) {
printf("%s: Error: Lane#4 on Device 6810 is not Active.\n",
__func__);
return 0;
}
/*
* 6th Lane (#5) on Device 6810 is Active, even though 6810
* has only 5 lanes
*/
if (sys_env_device_id_get() == MV_6810 && lane_num == 5)
return 1;
if (lane_num >= hws_serdes_get_max_lane())
ret = 0;
return ret;
}
int hws_get_ext_base_addr(u32 serdes_num, u32 base_addr, u32 unit_base_offset,
u32 *unit_base_reg, u32 *unit_offset)
{
*unit_base_reg = base_addr;
*unit_offset = unit_base_offset;
return MV_OK;
}
/*
* hws_serdes_get_phy_selector_val
*
* DESCRIPTION: Get the mapping of Serdes Selector values according to the
* Serdes revision number
* INPUT: serdes_num - Serdes number
* serdes_type - Serdes type
* OUTPUT: None
* RETURN:
* Mapping of Serdes Selector values
*/
u32 hws_serdes_get_phy_selector_val(int serdes_num,
enum serdes_type serdes_type)
{
if (serdes_type >= LAST_SERDES_TYPE)
return 0xff;
if (hws_ctrl_serdes_rev_get() == MV_SERDES_REV_1_2) {
return selectors_serdes_rev1_map
[serdes_type][serdes_num];
} else
return selectors_serdes_rev2_map
[serdes_type][serdes_num];
}
u32 hws_get_physical_serdes_num(u32 serdes_num)
{
if ((serdes_num == 4) && (sys_env_device_id_get() == MV_6810)) {
/*
* For 6810, there are 5 Serdes and Serdes Num 4 doesn't
* exist. Instead Serdes Num 5 is connected.
*/
return 5;
} else {
return serdes_num;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,251 @@
/*
* Copyright (C) Marvell International Ltd. and its affiliates
*
* SPDX-License-Identifier: GPL-2.0
*/
#ifndef _HIGH_SPEED_ENV_SPEC_H
#define _HIGH_SPEED_ENV_SPEC_H
#include "seq_exec.h"
/*
* For setting or clearing a certain bit (bit is a number between 0 and 31)
* in the data
*/
#define SET_BIT(data, bit) ((data) | (0x1 << (bit)))
#define CLEAR_BIT(data, bit) ((data) & (~(0x1 << (bit))))
#define MAX_SERDES_LANES 7 /* as in a39x */
/* Serdes revision */
/* Serdes revision 1.2 (for A38x-Z1) */
#define MV_SERDES_REV_1_2 0x0
/* Serdes revision 2.1 (for A39x-Z1, A38x-A0) */
#define MV_SERDES_REV_2_1 0x1
#define MV_SERDES_REV_NA 0xff
#define SERDES_REGS_LANE_BASE_OFFSET(lane) (0x800 * (lane))
#define PEX_X4_ENABLE_OFFS \
(hws_ctrl_serdes_rev_get() == MV_SERDES_REV_1_2 ? 18 : 31)
/* Serdes lane types */
enum serdes_type {
PEX0,
PEX1,
PEX2,
PEX3,
SATA0,
SATA1,
SATA2,
SATA3,
SGMII0,
SGMII1,
SGMII2,
QSGMII,
USB3_HOST0,
USB3_HOST1,
USB3_DEVICE,
SGMII3,
XAUI,
RXAUI,
DEFAULT_SERDES,
LAST_SERDES_TYPE
};
/* Serdes baud rates */
enum serdes_speed {
SERDES_SPEED_1_25_GBPS,
SERDES_SPEED_1_5_GBPS,
SERDES_SPEED_2_5_GBPS,
SERDES_SPEED_3_GBPS,
SERDES_SPEED_3_125_GBPS,
SERDES_SPEED_5_GBPS,
SERDES_SPEED_6_GBPS,
SERDES_SPEED_6_25_GBPS,
LAST_SERDES_SPEED
};
/* Serdes modes */
enum serdes_mode {
PEX_ROOT_COMPLEX_X1,
PEX_ROOT_COMPLEX_X4,
PEX_END_POINT_X1,
PEX_END_POINT_X4,
SERDES_DEFAULT_MODE, /* not pex */
SERDES_LAST_MODE
};
struct serdes_map {
enum serdes_type serdes_type;
enum serdes_speed serdes_speed;
enum serdes_mode serdes_mode;
int swap_rx;
int swap_tx;
};
/* Serdes ref clock options */
enum ref_clock {
REF_CLOCK_25MHZ,
REF_CLOCK_100MHZ,
REF_CLOCK_40MHZ,
REF_CLOCK_UNSUPPORTED
};
/* Serdes sequences */
enum serdes_seq {
SATA_PORT_0_ONLY_POWER_UP_SEQ,
SATA_PORT_1_ONLY_POWER_UP_SEQ,
SATA_POWER_UP_SEQ,
SATA_1_5_SPEED_CONFIG_SEQ,
SATA_3_SPEED_CONFIG_SEQ,
SATA_6_SPEED_CONFIG_SEQ,
SATA_ELECTRICAL_CONFIG_SEQ,
SATA_TX_CONFIG_SEQ1,
SATA_PORT_0_ONLY_TX_CONFIG_SEQ,
SATA_PORT_1_ONLY_TX_CONFIG_SEQ,
SATA_TX_CONFIG_SEQ2,
SGMII_POWER_UP_SEQ,
SGMII_1_25_SPEED_CONFIG_SEQ,
SGMII_3_125_SPEED_CONFIG_SEQ,
SGMII_ELECTRICAL_CONFIG_SEQ,
SGMII_TX_CONFIG_SEQ1,
SGMII_TX_CONFIG_SEQ2,
PEX_POWER_UP_SEQ,
PEX_2_5_SPEED_CONFIG_SEQ,
PEX_5_SPEED_CONFIG_SEQ,
PEX_ELECTRICAL_CONFIG_SEQ,
PEX_TX_CONFIG_SEQ1,
PEX_TX_CONFIG_SEQ2,
PEX_TX_CONFIG_SEQ3,
PEX_BY_4_CONFIG_SEQ,
PEX_CONFIG_REF_CLOCK_25MHZ_SEQ,
PEX_CONFIG_REF_CLOCK_100MHZ_SEQ,
PEX_CONFIG_REF_CLOCK_40MHZ_SEQ,
USB3_POWER_UP_SEQ,
USB3_HOST_SPEED_CONFIG_SEQ,
USB3_DEVICE_SPEED_CONFIG_SEQ,
USB3_ELECTRICAL_CONFIG_SEQ,
USB3_TX_CONFIG_SEQ1,
USB3_TX_CONFIG_SEQ2,
USB3_TX_CONFIG_SEQ3,
USB3_DEVICE_CONFIG_SEQ,
USB2_POWER_UP_SEQ,
SERDES_POWER_DOWN_SEQ,
SGMII3_POWER_UP_SEQ,
SGMII3_1_25_SPEED_CONFIG_SEQ,
SGMII3_TX_CONFIG_SEQ1,
SGMII3_TX_CONFIG_SEQ2,
QSGMII_POWER_UP_SEQ,
QSGMII_5_SPEED_CONFIG_SEQ,
QSGMII_ELECTRICAL_CONFIG_SEQ,
QSGMII_TX_CONFIG_SEQ1,
QSGMII_TX_CONFIG_SEQ2,
XAUI_POWER_UP_SEQ,
XAUI_3_125_SPEED_CONFIG_SEQ,
XAUI_ELECTRICAL_CONFIG_SEQ,
XAUI_TX_CONFIG_SEQ1,
XAUI_TX_CONFIG_SEQ2,
RXAUI_POWER_UP_SEQ,
RXAUI_6_25_SPEED_CONFIG_SEQ,
RXAUI_ELECTRICAL_CONFIG_SEQ,
RXAUI_TX_CONFIG_SEQ1,
RXAUI_TX_CONFIG_SEQ2,
SERDES_LAST_SEQ
};
/* The different sequence types for PEX and USB3 */
enum {
PEX,
USB3,
LAST_PEX_USB_SEQ_TYPE
};
enum {
PEXSERDES_SPEED_2_5_GBPS,
PEXSERDES_SPEED_5_GBPS,
USB3SERDES_SPEED_5_GBPS_HOST,
USB3SERDES_SPEED_5_GBPS_DEVICE,
LAST_PEX_USB_SPEED_SEQ_TYPE
};
/* The different sequence types for SATA and SGMII */
enum {
SATA,
SGMII,
SGMII_3_125,
LAST_SATA_SGMII_SEQ_TYPE
};
enum {
QSGMII_SEQ_IDX,
LAST_QSGMII_SEQ_TYPE
};
enum {
XAUI_SEQ_IDX,
RXAUI_SEQ_IDX,
LAST_XAUI_RXAUI_SEQ_TYPE
};
enum {
SATASERDES_SPEED_1_5_GBPS,
SATASERDES_SPEED_3_GBPS,
SATASERDES_SPEED_6_GBPS,
SGMIISERDES_SPEED_1_25_GBPS,
SGMIISERDES_SPEED_3_125_GBPS,
LAST_SATA_SGMII_SPEED_SEQ_TYPE
};
extern u8 selectors_serdes_rev1_map[LAST_SERDES_TYPE][MAX_SERDES_LANES];
extern u8 selectors_serdes_rev2_map[LAST_SERDES_TYPE][MAX_SERDES_LANES];
u8 hws_ctrl_serdes_rev_get(void);
int mv_update_serdes_select_phy_mode_seq(void);
int hws_board_topology_load(struct serdes_map **serdes_map, u8 *count);
enum serdes_seq serdes_type_and_speed_to_speed_seq(enum serdes_type serdes_type,
enum serdes_speed baud_rate);
int hws_serdes_seq_init(void);
int hws_serdes_seq_db_init(void);
int hws_power_up_serdes_lanes(struct serdes_map *serdes_map, u8 count);
int hws_ctrl_high_speed_serdes_phy_config(void);
int serdes_power_up_ctrl(u32 serdes_num, int serdes_power_up,
enum serdes_type serdes_type,
enum serdes_speed baud_rate,
enum serdes_mode serdes_mode,
enum ref_clock ref_clock);
int serdes_power_up_ctrl_ext(u32 serdes_num, int serdes_power_up,
enum serdes_type serdes_type,
enum serdes_speed baud_rate,
enum serdes_mode serdes_mode,
enum ref_clock ref_clock);
u32 hws_serdes_silicon_ref_clock_get(void);
int hws_serdes_pex_ref_clock_get(enum serdes_type serdes_type,
enum ref_clock *ref_clock);
int hws_ref_clock_set(u32 serdes_num, enum serdes_type serdes_type,
enum ref_clock ref_clock);
int hws_update_serdes_phy_selectors(struct serdes_map *serdes_map, u8 count);
u32 hws_serdes_get_phy_selector_val(int serdes_num,
enum serdes_type serdes_type);
u32 hws_serdes_get_ref_clock_val(enum serdes_type serdes_type);
u32 hws_serdes_get_max_lane(void);
int hws_get_ext_base_addr(u32 serdes_num, u32 base_addr, u32 unit_base_offset,
u32 *unit_base_reg, u32 *unit_offset);
int hws_pex_tx_config_seq(const struct serdes_map *serdes_map, u8 count);
u32 hws_get_physical_serdes_num(u32 serdes_num);
int hws_is_serdes_active(u8 lane_num);
#endif /* _HIGH_SPEED_ENV_SPEC_H */

View File

@@ -0,0 +1,169 @@
/*
* Copyright (C) Marvell International Ltd. and its affiliates
*
* SPDX-License-Identifier: GPL-2.0
*/
#include <common.h>
#include <spl.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>
#include "seq_exec.h"
#include "high_speed_env_spec.h"
#include "../../../drivers/ddr/marvell/a38x/ddr3_init.h"
#if defined(MV_DEBUG_INIT_FULL) || defined(MV_DEBUG)
#define DB(x) x
#else
#define DB(x)
#endif
/* Array for mapping the operation (write, poll or delay) functions */
op_execute_func_ptr op_execute_func_arr[] = {
write_op_execute,
delay_op_execute,
poll_op_execute
};
int write_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx)
{
u32 unit_base_reg, unit_offset, data, mask, reg_data, reg_addr;
/* Getting write op params from the input parameter */
data = params->data[data_arr_idx];
mask = params->mask;
/* an empty operation */
if (data == NO_DATA)
return MV_OK;
/* get updated base address since it can be different between Serdes */
CHECK_STATUS(hws_get_ext_base_addr(serdes_num, params->unit_base_reg,
params->unit_offset,
&unit_base_reg, &unit_offset));
/* Address calculation */
reg_addr = unit_base_reg + unit_offset * serdes_num;
#ifdef SEQ_DEBUG
printf("Write: 0x%x: 0x%x (mask 0x%x) - ", reg_addr, data, mask);
#endif
/* Reading old value */
reg_data = reg_read(reg_addr);
reg_data &= (~mask);
/* Writing new data */
data &= mask;
reg_data |= data;
reg_write(reg_addr, reg_data);
#ifdef SEQ_DEBUG
printf(" - 0x%x\n", reg_data);
#endif
return MV_OK;
}
int delay_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx)
{
u32 delay;
/* Getting delay op params from the input parameter */
delay = params->wait_time;
#ifdef SEQ_DEBUG
printf("Delay: %d\n", delay);
#endif
mdelay(delay);
return MV_OK;
}
int poll_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx)
{
u32 unit_base_reg, unit_offset, data, mask, num_of_loops, wait_time;
u32 poll_counter = 0;
u32 reg_addr, reg_data;
/* Getting poll op params from the input parameter */
data = params->data[data_arr_idx];
mask = params->mask;
num_of_loops = params->num_of_loops;
wait_time = params->wait_time;
/* an empty operation */
if (data == NO_DATA)
return MV_OK;
/* get updated base address since it can be different between Serdes */
CHECK_STATUS(hws_get_ext_base_addr(serdes_num, params->unit_base_reg,
params->unit_offset,
&unit_base_reg, &unit_offset));
/* Address calculation */
reg_addr = unit_base_reg + unit_offset * serdes_num;
/* Polling */
#ifdef SEQ_DEBUG
printf("Poll: 0x%x: 0x%x (mask 0x%x)\n", reg_addr, data, mask);
#endif
do {
reg_data = reg_read(reg_addr) & mask;
poll_counter++;
udelay(wait_time);
} while ((reg_data != data) && (poll_counter < num_of_loops));
if ((poll_counter >= num_of_loops) && (reg_data != data)) {
DEBUG_INIT_S("poll_op_execute: TIMEOUT\n");
return MV_TIMEOUT;
}
return MV_OK;
}
enum mv_op get_cfg_seq_op(struct op_params *params)
{
if (params->wait_time == 0)
return WRITE_OP;
else if (params->num_of_loops == 0)
return DELAY_OP;
return POLL_OP;
}
int mv_seq_exec(u32 serdes_num, u32 seq_id)
{
u32 seq_idx;
struct op_params *seq_arr;
u32 seq_size;
u32 data_arr_idx;
enum mv_op curr_op;
DB(printf("\n### mv_seq_exec ###\n"));
DB(printf("seq id: %d\n", seq_id));
if (hws_is_serdes_active(serdes_num) != 1) {
printf("mv_seq_exec_ext:Error: SerDes lane %d is not valid\n",
serdes_num);
return MV_BAD_PARAM;
}
seq_arr = serdes_seq_db[seq_id].op_params_ptr;
seq_size = serdes_seq_db[seq_id].cfg_seq_size;
data_arr_idx = serdes_seq_db[seq_id].data_arr_idx;
DB(printf("seq_size: %d\n", seq_size));
DB(printf("data_arr_idx: %d\n", data_arr_idx));
/* Executing the sequence operations */
for (seq_idx = 0; seq_idx < seq_size; seq_idx++) {
curr_op = get_cfg_seq_op(&seq_arr[seq_idx]);
op_execute_func_arr[curr_op](serdes_num, &seq_arr[seq_idx],
data_arr_idx);
}
return MV_OK;
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright (C) Marvell International Ltd. and its affiliates
*
* SPDX-License-Identifier: GPL-2.0
*/
#ifndef _SEQ_EXEC_H
#define _SEQ_EXEC_H
#define NA 0xff
#define DEFAULT_PARAM 0
#define MV_BOARD_TCLK_ERROR 0xffffffff
#define NO_DATA 0xffffffff
#define MAX_DATA_ARRAY 5
#define FIRST_CELL 0
/* Operation types */
enum mv_op {
WRITE_OP,
DELAY_OP,
POLL_OP,
};
/* Operation parameters */
struct op_params {
u32 unit_base_reg;
u32 unit_offset;
u32 mask;
u32 data[MAX_DATA_ARRAY]; /* data array */
u8 wait_time; /* msec */
u16 num_of_loops; /* for polling only */
};
/*
* Sequence parameters. Each sequence contains:
* 1. Sequence id.
* 2. Sequence size (total amount of operations during the sequence)
* 3. a series of operations. operations can be write, poll or delay
* 4. index in the data array (the entry where the relevant data sits)
*/
struct cfg_seq {
struct op_params *op_params_ptr;
u8 cfg_seq_size;
u8 data_arr_idx;
};
extern struct cfg_seq serdes_seq_db[];
/*
* A generic function type for executing an operation (write, poll or delay)
*/
typedef int (*op_execute_func_ptr)(u32 serdes_num, struct op_params *params,
u32 data_arr_idx);
/* Specific functions for executing each operation */
int write_op_execute(u32 serdes_num, struct op_params *params,
u32 data_arr_idx);
int delay_op_execute(u32 serdes_num, struct op_params *params,
u32 data_arr_idx);
int poll_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx);
enum mv_op get_cfg_seq_op(struct op_params *params);
int mv_seq_exec(u32 serdes_num, u32 seq_id);
#endif /*_SEQ_EXEC_H*/

View File

@@ -0,0 +1,237 @@
/*
* Copyright (C) Marvell International Ltd. and its affiliates
*
* SPDX-License-Identifier: GPL-2.0
*/
#include <common.h>
#include <spl.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>
#include "seq_exec.h"
#include "sys_env_lib.h"
#include "../../../drivers/ddr/marvell/a38x/ddr3_a38x.h"
#ifdef CONFIG_ARMADA_38X
enum unit_id sys_env_soc_unit_nums[MAX_UNITS_ID][MAX_DEV_ID_NUM] = {
/* 6820 6810 6811 6828 */
/* PEX_UNIT_ID */ { 4, 3, 3, 4},
/* ETH_GIG_UNIT_ID */ { 3, 2, 3, 3},
/* USB3H_UNIT_ID */ { 2, 2, 2, 2},
/* USB3D_UNIT_ID */ { 1, 1, 1, 1},
/* SATA_UNIT_ID */ { 2, 2, 2, 4},
/* QSGMII_UNIT_ID */ { 1, 0, 0, 1},
/* XAUI_UNIT_ID */ { 0, 0, 0, 0},
/* RXAUI_UNIT_ID */ { 0, 0, 0, 0}
};
#else /* if (CONFIG_ARMADA_39X) */
enum unit_id sys_env_soc_unit_nums[MAX_UNITS_ID][MAX_DEV_ID_NUM] = {
/* 6920 6928 */
/* PEX_UNIT_ID */ { 4, 4},
/* ETH_GIG_UNIT_ID */ { 3, 4},
/* USB3H_UNIT_ID */ { 1, 2},
/* USB3D_UNIT_ID */ { 0, 1},
/* SATA_UNIT_ID */ { 0, 4},
/* QSGMII_UNIT_ID */ { 0, 1},
/* XAUI_UNIT_ID */ { 1, 1},
/* RXAUI_UNIT_ID */ { 1, 1}
};
#endif
u32 g_dev_id = -1;
u32 mv_board_id_get(void)
{
#if defined(CONFIG_DB_88F6820_GP)
return DB_GP_68XX_ID;
#else
/*
* Return 0 here for custom board as this should not be used
* for custom boards.
*/
return 0;
#endif
}
u32 mv_board_tclk_get(void)
{
u32 value;
value = (reg_read(DEVICE_SAMPLE_AT_RESET1_REG) >> 15) & 0x1;
switch (value) {
case (0x0):
return 250000000;
case (0x1):
return 200000000;
default:
return 0xffffffff;
}
}
u32 mv_board_id_index_get(u32 board_id)
{
/*
* Marvell Boards use 0x10 as base for Board ID:
* mask MSB to receive index for board ID
*/
return board_id & (MARVELL_BOARD_ID_MASK - 1);
}
/*
* sys_env_suspend_wakeup_check
* DESCRIPTION: Reads GPIO input for suspend-wakeup indication.
* INPUT: None.
* OUTPUT:
* RETURNS: u32 indicating suspend wakeup status:
* 0 - Not supported,
* 1 - supported: read magic word detect wakeup,
* 2 - detected wakeup from GPIO.
*/
enum suspend_wakeup_status sys_env_suspend_wakeup_check(void)
{
u32 reg, board_id_index, gpio;
struct board_wakeup_gpio board_gpio[] = MV_BOARD_WAKEUP_GPIO_INFO;
board_id_index = mv_board_id_index_get(mv_board_id_get());
if (!(sizeof(board_gpio) / sizeof(struct board_wakeup_gpio) >
board_id_index)) {
printf("\n_failed loading Suspend-Wakeup information (invalid board ID)\n");
return SUSPEND_WAKEUP_DISABLED;
}
/*
* - Detect if Suspend-Wakeup is supported on current board
* - Fetch the GPIO number for wakeup status input indication
*/
if (board_gpio[board_id_index].gpio_num == -1) {
/* Suspend to RAM is not supported */
return SUSPEND_WAKEUP_DISABLED;
} else if (board_gpio[board_id_index].gpio_num == -2) {
/*
* Suspend to RAM is supported but GPIO indication is
* not implemented - Skip
*/
return SUSPEND_WAKEUP_ENABLED;
} else {
gpio = board_gpio[board_id_index].gpio_num;
}
/* Initialize MPP for GPIO (set MPP = 0x0) */
reg = reg_read(MPP_CONTROL_REG(MPP_REG_NUM(gpio)));
/* reset MPP21 to 0x0, keep rest of MPP settings*/
reg &= ~MPP_MASK(gpio);
reg_write(MPP_CONTROL_REG(MPP_REG_NUM(gpio)), reg);
/* Initialize GPIO as input */
reg = reg_read(GPP_DATA_OUT_EN_REG(GPP_REG_NUM(gpio)));
reg |= GPP_MASK(gpio);
reg_write(GPP_DATA_OUT_EN_REG(GPP_REG_NUM(gpio)), reg);
/*
* Check GPP for input status from PIC: 0 - regular init,
* 1 - suspend wakeup
*/
reg = reg_read(GPP_DATA_IN_REG(GPP_REG_NUM(gpio)));
/* if GPIO is ON: wakeup from S2RAM indication detected */
return (reg & GPP_MASK(gpio)) ? SUSPEND_WAKEUP_ENABLED_GPIO_DETECTED :
SUSPEND_WAKEUP_DISABLED;
}
/*
* mv_ctrl_dev_id_index_get
*
* DESCRIPTION: return SOC device index
* INPUT: None
* OUTPUT: None
* RETURN:
* return SOC device index
*/
u32 sys_env_id_index_get(u32 ctrl_model)
{
switch (ctrl_model) {
case MV_6820_DEV_ID:
return MV_6820_INDEX;
case MV_6810_DEV_ID:
return MV_6810_INDEX;
case MV_6811_DEV_ID:
return MV_6811_INDEX;
case MV_6828_DEV_ID:
return MV_6828_INDEX;
case MV_6920_DEV_ID:
return MV_6920_INDEX;
case MV_6928_DEV_ID:
return MV_6928_INDEX;
default:
return MV_6820_INDEX;
}
}
u32 sys_env_unit_max_num_get(enum unit_id unit)
{
u32 dev_id_index;
if (unit >= MAX_UNITS_ID) {
printf("%s: Error: Wrong unit type (%u)\n", __func__, unit);
return 0;
}
dev_id_index = sys_env_id_index_get(sys_env_model_get());
return sys_env_soc_unit_nums[unit][dev_id_index];
}
/*
* sys_env_model_get
* DESCRIPTION: Returns 16bit describing the device model (ID) as defined
* in Vendor ID configuration register
*/
u16 sys_env_model_get(void)
{
u32 default_ctrl_id, ctrl_id = reg_read(DEV_ID_REG);
ctrl_id = (ctrl_id & (DEV_ID_REG_DEVICE_ID_MASK)) >>
DEV_ID_REG_DEVICE_ID_OFFS;
switch (ctrl_id) {
case MV_6820_DEV_ID:
case MV_6810_DEV_ID:
case MV_6811_DEV_ID:
case MV_6828_DEV_ID:
case MV_6920_DEV_ID:
case MV_6928_DEV_ID:
return ctrl_id;
default:
/* Device ID Default for A38x: 6820 , for A39x: 6920 */
#ifdef CONFIG_ARMADA_38X
default_ctrl_id = MV_6820_DEV_ID;
#else
default_ctrl_id = MV_6920_DEV_ID;
#endif
printf("%s: Error retrieving device ID (%x), using default ID = %x\n",
__func__, ctrl_id, default_ctrl_id);
return default_ctrl_id;
}
}
/*
* sys_env_device_id_get
* DESCRIPTION: Returns enum (0..7) index of the device model (ID)
*/
u32 sys_env_device_id_get(void)
{
char *device_id_str[7] = {
"6810", "6820", "6811", "6828", "NONE", "6920", "6928"
};
if (g_dev_id != -1)
return g_dev_id;
g_dev_id = reg_read(DEVICE_SAMPLE_AT_RESET1_REG);
g_dev_id = g_dev_id >> SAR_DEV_ID_OFFS & SAR_DEV_ID_MASK;
printf("Detected Device ID %s\n", device_id_str[g_dev_id]);
return g_dev_id;
}

View File

@@ -0,0 +1,369 @@
/*
* Copyright (C) Marvell International Ltd. and its affiliates
*
* SPDX-License-Identifier: GPL-2.0
*/
#ifndef _SYS_ENV_LIB_H
#define _SYS_ENV_LIB_H
#include "../../../drivers/ddr/marvell/a38x/ddr3_init.h"
#include "../../../drivers/ddr/marvell/a38x/ddr3_hws_hw_training.h"
/* Serdes definitions */
#define COMMON_PHY_BASE_ADDR 0x18300
#define DEVICE_CONFIGURATION_REG0 0x18284
#define DEVICE_CONFIGURATION_REG1 0x18288
#define COMMON_PHY_CONFIGURATION1_REG 0x18300
#define COMMON_PHY_CONFIGURATION2_REG 0x18304
#define COMMON_PHY_CONFIGURATION4_REG 0x1830c
#define COMMON_PHY_STATUS1_REG 0x18318
#define COMMON_PHYS_SELECTORS_REG 0x183fc
#define SOC_CONTROL_REG1 0x18204
#define GENERAL_PURPOSE_RESERVED0_REG 0x182e0
#define GBE_CONFIGURATION_REG 0x18460
#define DEVICE_SAMPLE_AT_RESET1_REG 0x18600
#define DEVICE_SAMPLE_AT_RESET2_REG 0x18604
#define DEV_ID_REG 0x18238
#define CORE_PLL_PARAMETERS_REG 0xe42e0
#define CORE_PLL_CONFIG_REG 0xe42e4
#define QSGMII_CONTROL_REG1 0x18494
#define DEV_ID_REG_DEVICE_ID_OFFS 16
#define DEV_ID_REG_DEVICE_ID_MASK 0xffff0000
#define SAR_DEV_ID_OFFS 27
#define SAR_DEV_ID_MASK 0x7
#define POWER_AND_PLL_CTRL_REG 0xa0004
#define CALIBRATION_CTRL_REG 0xa0008
#define DFE_REG0 0xa001c
#define DFE_REG3 0xa0028
#define RESET_DFE_REG 0xa0148
#define LOOPBACK_REG 0xa008c
#define SYNC_PATTERN_REG 0xa0090
#define INTERFACE_REG 0xa0094
#define ISOLATE_REG 0xa0098
#define MISC_REG 0xa013c
#define GLUE_REG 0xa0140
#define GENERATION_DIVIDER_FORCE_REG 0xa0144
#define PCIE_REG0 0xa0120
#define LANE_ALIGN_REG0 0xa0124
#define SQUELCH_FFE_SETTING_REG 0xa0018
#define G1_SETTINGS_0_REG 0xa0034
#define G1_SETTINGS_1_REG 0xa0038
#define G1_SETTINGS_3_REG 0xa0440
#define G1_SETTINGS_4_REG 0xa0444
#define G2_SETTINGS_0_REG 0xa003c
#define G2_SETTINGS_1_REG 0xa0040
#define G2_SETTINGS_2_REG 0xa00f8
#define G2_SETTINGS_3_REG 0xa0448
#define G2_SETTINGS_4_REG 0xa044c
#define G3_SETTINGS_0_REG 0xa0044
#define G3_SETTINGS_1_REG 0xa0048
#define G3_SETTINGS_3_REG 0xa0450
#define G3_SETTINGS_4_REG 0xa0454
#define VTHIMPCAL_CTRL_REG 0xa0104
#define REF_REG0 0xa0134
#define CAL_REG6 0xa0168
#define RX_REG2 0xa0184
#define RX_REG3 0xa0188
#define PCIE_REG1 0xa0288
#define PCIE_REG3 0xa0290
#define LANE_CFG1_REG 0xa0604
#define LANE_CFG4_REG 0xa0620
#define LANE_CFG5_REG 0xa0624
#define GLOBAL_CLK_CTRL 0xa0704
#define GLOBAL_MISC_CTRL 0xa0718
#define GLOBAL_CLK_SRC_HI 0xa0710
#define GLOBAL_CLK_CTRL 0xa0704
#define GLOBAL_MISC_CTRL 0xa0718
#define GLOBAL_PM_CTRL 0xa0740
/* SATA registers */
#define SATA_CTRL_REG_IND_ADDR 0xa80a0
#define SATA_CTRL_REG_IND_DATA 0xa80a4
#define SATA_VENDOR_PORT_0_REG_ADDR 0xa8178
#define SATA_VENDOR_PORT_1_REG_ADDR 0xa81f8
#define SATA_VENDOR_PORT_0_REG_DATA 0xa817c
#define SATA_VENDOR_PORT_1_REG_DATA 0xa81fc
/* Reference clock values and mask */
#define POWER_AND_PLL_CTRL_REG_100MHZ_VAL 0x0
#define POWER_AND_PLL_CTRL_REG_25MHZ_VAL_1 0x1
#define POWER_AND_PLL_CTRL_REG_25MHZ_VAL_2 0x2
#define POWER_AND_PLL_CTRL_REG_40MHZ_VAL 0x3
#define GLOBAL_PM_CTRL_REG_25MHZ_VAL 0x7
#define GLOBAL_PM_CTRL_REG_40MHZ_VAL 0xc
#define LANE_CFG4_REG_25MHZ_VAL 0x200
#define LANE_CFG4_REG_40MHZ_VAL 0x300
#define POWER_AND_PLL_CTRL_REG_MASK (~(0x1f))
#define GLOBAL_PM_CTRL_REG_MASK (~(0xff))
#define LANE_CFG4_REG_MASK (~(0x1f00))
#define REF_CLK_SELECTOR_VAL_PEX0(reg_val) (reg_val >> 2) & 0x1
#define REF_CLK_SELECTOR_VAL_PEX1(reg_val) (reg_val >> 3) & 0x1
#define REF_CLK_SELECTOR_VAL_PEX2(reg_val) (reg_val >> 30) & 0x1
#define REF_CLK_SELECTOR_VAL_PEX3(reg_val) (reg_val >> 31) & 0x1
#define REF_CLK_SELECTOR_VAL(reg_val) (reg_val & 0x1)
#define MAX_SELECTOR_VAL 10
/* TWSI addresses */
/* starting from A38x A0, i2c address of EEPROM is 0x57 */
#ifdef CONFIG_ARMADA_39X
#define EEPROM_I2C_ADDR 0x50
#else
#define EEPROM_I2C_ADDR (sys_env_device_rev_get() == \
MV_88F68XX_Z1_ID ? 0x50 : 0x57)
#endif
#define RD_GET_MODE_ADDR 0x4c
#define DB_GET_MODE_SLM1363_ADDR 0x25
#define DB_GET_MODE_SLM1364_ADDR 0x24
#define DB381_GET_MODE_SLM1426_1427_ADDR 0x56
/* DB-BP Board 'SatR' mapping */
#define SATR_DB_LANE1_MAX_OPTIONS 7
#define SATR_DB_LANE1_CFG_MASK 0x7
#define SATR_DB_LANE1_CFG_OFFSET 0
#define SATR_DB_LANE2_MAX_OPTIONS 4
#define SATR_DB_LANE2_CFG_MASK 0x38
#define SATR_DB_LANE2_CFG_OFFSET 3
/* GP Board 'SatR' mapping */
#define SATR_GP_LANE1_CFG_MASK 0x4
#define SATR_GP_LANE1_CFG_OFFSET 2
#define SATR_GP_LANE2_CFG_MASK 0x8
#define SATR_GP_LANE2_CFG_OFFSET 3
/* For setting MPP2 and MPP3 to be TWSI mode and MPP 0,1 to UART mode */
#define MPP_CTRL_REG 0x18000
#define MPP_SET_MASK (~(0xffff))
#define MPP_SET_DATA (0x1111)
#define MPP_UART1_SET_MASK (~(0xff000))
#define MPP_UART1_SET_DATA (0x66000)
#define AVS_DEBUG_CNTR_REG 0xe4124
#define AVS_DEBUG_CNTR_DEFAULT_VALUE 0x08008073
#define AVS_ENABLED_CONTROL 0xe4130
#define AVS_LOW_VDD_LIMIT_OFFS 4
#define AVS_LOW_VDD_LIMIT_MASK (0xff << AVS_LOW_VDD_LIMIT_OFFS)
#define AVS_LOW_VDD_LIMIT_VAL (0x27 << AVS_LOW_VDD_LIMIT_OFFS)
#define AVS_HIGH_VDD_LIMIT_OFFS 12
#define AVS_HIGH_VDD_LIMIT_MASK (0xff << AVS_HIGH_VDD_LIMIT_OFFS)
#define AVS_HIGH_VDD_LIMIT_VAL (0x27 << AVS_HIGH_VDD_LIMIT_OFFS)
/* Board ID numbers */
#define MARVELL_BOARD_ID_MASK 0x10
/* Customer boards for A38x */
#define A38X_CUSTOMER_BOARD_ID_BASE 0x0
#define A38X_CUSTOMER_BOARD_ID0 (A38X_CUSTOMER_BOARD_ID_BASE + 0)
#define A38X_CUSTOMER_BOARD_ID1 (A38X_CUSTOMER_BOARD_ID_BASE + 1)
#define A38X_MV_MAX_CUSTOMER_BOARD_ID (A38X_CUSTOMER_BOARD_ID_BASE + 2)
#define A38X_MV_CUSTOMER_BOARD_NUM (A38X_MV_MAX_CUSTOMER_BOARD_ID - \
A38X_CUSTOMER_BOARD_ID_BASE)
/* Marvell boards for A38x */
#define A38X_MARVELL_BOARD_ID_BASE 0x10
#define RD_NAS_68XX_ID (A38X_MARVELL_BOARD_ID_BASE + 0)
#define DB_68XX_ID (A38X_MARVELL_BOARD_ID_BASE + 1)
#define RD_AP_68XX_ID (A38X_MARVELL_BOARD_ID_BASE + 2)
#define DB_AP_68XX_ID (A38X_MARVELL_BOARD_ID_BASE + 3)
#define DB_GP_68XX_ID (A38X_MARVELL_BOARD_ID_BASE + 4)
#define DB_BP_6821_ID (A38X_MARVELL_BOARD_ID_BASE + 5)
#define DB_AMC_6820_ID (A38X_MARVELL_BOARD_ID_BASE + 6)
#define A38X_MV_MAX_MARVELL_BOARD_ID (A38X_MARVELL_BOARD_ID_BASE + 7)
#define A38X_MV_MARVELL_BOARD_NUM (A38X_MV_MAX_MARVELL_BOARD_ID - \
A38X_MARVELL_BOARD_ID_BASE)
/* Customer boards for A39x */
#define A39X_CUSTOMER_BOARD_ID_BASE 0x20
#define A39X_CUSTOMER_BOARD_ID0 (A39X_CUSTOMER_BOARD_ID_BASE + 0)
#define A39X_CUSTOMER_BOARD_ID1 (A39X_CUSTOMER_BOARD_ID_BASE + 1)
#define A39X_MV_MAX_CUSTOMER_BOARD_ID (A39X_CUSTOMER_BOARD_ID_BASE + 2)
#define A39X_MV_CUSTOMER_BOARD_NUM (A39X_MV_MAX_CUSTOMER_BOARD_ID - \
A39X_CUSTOMER_BOARD_ID_BASE)
/* Marvell boards for A39x */
#define A39X_MARVELL_BOARD_ID_BASE 0x30
#define A39X_DB_69XX_ID (A39X_MARVELL_BOARD_ID_BASE + 0)
#define A39X_RD_69XX_ID (A39X_MARVELL_BOARD_ID_BASE + 1)
#define A39X_MV_MAX_MARVELL_BOARD_ID (A39X_MARVELL_BOARD_ID_BASE + 2)
#define A39X_MV_MARVELL_BOARD_NUM (A39X_MV_MAX_MARVELL_BOARD_ID - \
A39X_MARVELL_BOARD_ID_BASE)
#ifdef CONFIG_ARMADA_38X
#define CUTOMER_BOARD_ID_BASE A38X_CUSTOMER_BOARD_ID_BASE
#define CUSTOMER_BOARD_ID0 A38X_CUSTOMER_BOARD_ID0
#define CUSTOMER_BOARD_ID1 A38X_CUSTOMER_BOARD_ID1
#define MV_MAX_CUSTOMER_BOARD_ID A38X_MV_MAX_CUSTOMER_BOARD_ID
#define MV_CUSTOMER_BOARD_NUM A38X_MV_CUSTOMER_BOARD_NUM
#define MARVELL_BOARD_ID_BASE A38X_MARVELL_BOARD_ID_BASE
#define MV_MAX_MARVELL_BOARD_ID A38X_MV_MAX_MARVELL_BOARD_ID
#define MV_MARVELL_BOARD_NUM A38X_MV_MARVELL_BOARD_NUM
#define MV_DEFAULT_BOARD_ID DB_68XX_ID
#define MV_DEFAULT_DEVICE_ID MV_6811
#elif defined(CONFIG_ARMADA_39X)
#define CUTOMER_BOARD_ID_BASE A39X_CUSTOMER_BOARD_ID_BASE
#define CUSTOMER_BOARD_ID0 A39X_CUSTOMER_BOARD_ID0
#define CUSTOMER_BOARD_ID1 A39X_CUSTOMER_BOARD_ID1
#define MV_MAX_CUSTOMER_BOARD_ID A39X_MV_MAX_CUSTOMER_BOARD_ID
#define MV_CUSTOMER_BOARD_NUM A39X_MV_CUSTOMER_BOARD_NUM
#define MARVELL_BOARD_ID_BASE A39X_MARVELL_BOARD_ID_BASE
#define MV_MAX_MARVELL_BOARD_ID A39X_MV_MAX_MARVELL_BOARD_ID
#define MV_MARVELL_BOARD_NUM A39X_MV_MARVELL_BOARD_NUM
#define MV_DEFAULT_BOARD_ID A39X_DB_69XX_ID
#define MV_DEFAULT_DEVICE_ID MV_6920
#endif
#define MV_INVALID_BOARD_ID 0xffffffff
/* device revesion */
#define DEV_VERSION_ID_REG 0x1823c
#define REVISON_ID_OFFS 8
#define REVISON_ID_MASK 0xf00
/* A38x revisions */
#define MV_88F68XX_Z1_ID 0x0
#define MV_88F68XX_A0_ID 0x4
/* A39x revisions */
#define MV_88F69XX_Z1_ID 0x2
#define MPP_CONTROL_REG(id) (0x18000 + (id * 4))
#define GPP_DATA_OUT_REG(grp) (MV_GPP_REGS_BASE(grp) + 0x00)
#define GPP_DATA_OUT_EN_REG(grp) (MV_GPP_REGS_BASE(grp) + 0x04)
#define GPP_DATA_IN_REG(grp) (MV_GPP_REGS_BASE(grp) + 0x10)
#define MV_GPP_REGS_BASE(unit) (0x18100 + ((unit) * 0x40))
#define MPP_REG_NUM(GPIO_NUM) (GPIO_NUM / 8)
#define MPP_MASK(GPIO_NUM) (0xf << 4 * (GPIO_NUM - \
(MPP_REG_NUM(GPIO_NUM) * 8)));
#define GPP_REG_NUM(GPIO_NUM) (GPIO_NUM / 32)
#define GPP_MASK(GPIO_NUM) (1 << GPIO_NUM % 32)
/* device ID */
/* Armada 38x Family */
#define MV_6810_DEV_ID 0x6810
#define MV_6811_DEV_ID 0x6811
#define MV_6820_DEV_ID 0x6820
#define MV_6828_DEV_ID 0x6828
/* Armada 39x Family */
#define MV_6920_DEV_ID 0x6920
#define MV_6928_DEV_ID 0x6928
enum {
MV_6810,
MV_6820,
MV_6811,
MV_6828,
MV_NONE,
MV_6920,
MV_6928,
MV_MAX_DEV_ID,
};
#define MV_6820_INDEX 0
#define MV_6810_INDEX 1
#define MV_6811_INDEX 2
#define MV_6828_INDEX 3
#define MV_6920_INDEX 0
#define MV_6928_INDEX 1
#ifdef CONFIG_ARMADA_38X
#define MAX_DEV_ID_NUM 4
#else
#define MAX_DEV_ID_NUM 2
#endif
#define MV_6820_INDEX 0
#define MV_6810_INDEX 1
#define MV_6811_INDEX 2
#define MV_6828_INDEX 3
#define MV_6920_INDEX 0
#define MV_6928_INDEX 1
enum unit_id {
PEX_UNIT_ID,
ETH_GIG_UNIT_ID,
USB3H_UNIT_ID,
USB3D_UNIT_ID,
SATA_UNIT_ID,
QSGMII_UNIT_ID,
XAUI_UNIT_ID,
RXAUI_UNIT_ID,
MAX_UNITS_ID
};
struct board_wakeup_gpio {
u32 board_id;
int gpio_num;
};
enum suspend_wakeup_status {
SUSPEND_WAKEUP_DISABLED,
SUSPEND_WAKEUP_ENABLED,
SUSPEND_WAKEUP_ENABLED_GPIO_DETECTED,
};
/*
* GPIO status indication for Suspend Wakeup:
* If suspend to RAM is supported and GPIO inidcation is implemented,
* set the gpio number
* If suspend to RAM is supported but GPIO indication is not implemented
* set '-2'
* If suspend to RAM is not supported set '-1'
*/
#ifdef CONFIG_CUSTOMER_BOARD_SUPPORT
#ifdef CONFIG_ARMADA_38X
#define MV_BOARD_WAKEUP_GPIO_INFO { \
{A38X_CUSTOMER_BOARD_ID0, -1 }, \
{A38X_CUSTOMER_BOARD_ID0, -1 }, \
};
#else
#define MV_BOARD_WAKEUP_GPIO_INFO { \
{A39X_CUSTOMER_BOARD_ID0, -1 }, \
{A39X_CUSTOMER_BOARD_ID0, -1 }, \
};
#endif /* CONFIG_ARMADA_38X */
#else
#ifdef CONFIG_ARMADA_38X
#define MV_BOARD_WAKEUP_GPIO_INFO { \
{RD_NAS_68XX_ID, -2 }, \
{DB_68XX_ID, -1 }, \
{RD_AP_68XX_ID, -2 }, \
{DB_AP_68XX_ID, -2 }, \
{DB_GP_68XX_ID, -2 }, \
{DB_BP_6821_ID, -2 }, \
{DB_AMC_6820_ID, -2 }, \
};
#else
#define MV_BOARD_WAKEUP_GPIO_INFO { \
{A39X_RD_69XX_ID, -1 }, \
{A39X_DB_69XX_ID, -1 }, \
};
#endif /* CONFIG_ARMADA_38X */
#endif /* CONFIG_CUSTOMER_BOARD_SUPPORT */
u32 mv_board_tclk_get(void);
u32 mv_board_id_get(void);
u32 mv_board_id_index_get(u32 board_id);
u32 sys_env_unit_max_num_get(enum unit_id unit);
enum suspend_wakeup_status sys_env_suspend_wakeup_check(void);
u8 sys_env_device_rev_get(void);
u32 sys_env_device_id_get(void);
u16 sys_env_model_get(void);
struct dlb_config *sys_env_dlb_config_ptr_get(void);
u32 sys_env_get_cs_ena_from_reg(void);
#endif /* _SYS_ENV_LIB_H */

View File

@@ -0,0 +1,6 @@
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-$(CONFIG_SPL_BUILD) = high_speed_env_lib.o
obj-$(CONFIG_SPL_BUILD) += high_speed_env_spec.o

View File

@@ -0,0 +1,262 @@
/*
* Copyright (C) Marvell International Ltd. and its affiliates
*
* SPDX-License-Identifier: GPL-2.0
*/
#ifndef __BOARD_ENV_SPEC
#define __BOARD_ENV_SPEC
/* Board specific configuration */
/* KW40 */
#define MV_6710_DEV_ID 0x6710
#define MV_6710_Z1_REV 0x0
#define MV_6710_Z1_ID ((MV_6710_DEV_ID << 16) | MV_6710_Z1_REV)
#define MV_6710_Z1_NAME "MV6710 Z1"
/* Armada XP Family */
#define MV_78130_DEV_ID 0x7813
#define MV_78160_DEV_ID 0x7816
#define MV_78230_DEV_ID 0x7823
#define MV_78260_DEV_ID 0x7826
#define MV_78460_DEV_ID 0x7846
#define MV_78000_DEV_ID 0x7888
#define MV_FPGA_DEV_ID 0x2107
#define MV_78XX0_Z1_REV 0x0
/* boards ID numbers */
#define BOARD_ID_BASE 0x0
/* New board ID numbers */
#define DB_88F78XX0_BP_ID (BOARD_ID_BASE + 1)
#define RD_78460_SERVER_ID (DB_88F78XX0_BP_ID + 1)
#define DB_78X60_PCAC_ID (RD_78460_SERVER_ID + 1)
#define FPGA_88F78XX0_ID (DB_78X60_PCAC_ID + 1)
#define DB_88F78XX0_BP_REV2_ID (FPGA_88F78XX0_ID + 1)
#define RD_78460_NAS_ID (DB_88F78XX0_BP_REV2_ID + 1)
#define DB_78X60_AMC_ID (RD_78460_NAS_ID + 1)
#define DB_78X60_PCAC_REV2_ID (DB_78X60_AMC_ID + 1)
#define RD_78460_SERVER_REV2_ID (DB_78X60_PCAC_REV2_ID + 1)
#define DB_784MP_GP_ID (RD_78460_SERVER_REV2_ID + 1)
#define RD_78460_CUSTOMER_ID (DB_784MP_GP_ID + 1)
#define MV_MAX_BOARD_ID (RD_78460_CUSTOMER_ID + 1)
#define INVALID_BOARD_ID 0xFFFFFFFF
/* Sample at Reset */
#define MPP_SAMPLE_AT_RESET(id) (0x18230 + (id * 4))
/* BIOS Modes related defines */
#define SAR0_BOOTWIDTH_OFFSET 3
#define SAR0_BOOTWIDTH_MASK (0x3 << SAR0_BOOTWIDTH_OFFSET)
#define SAR0_BOOTSRC_OFFSET 5
#define SAR0_BOOTSRC_MASK (0xF << SAR0_BOOTSRC_OFFSET)
#define SAR0_L2_SIZE_OFFSET 19
#define SAR0_L2_SIZE_MASK (0x3 << SAR0_L2_SIZE_OFFSET)
#define SAR0_CPU_FREQ_OFFSET 21
#define SAR0_CPU_FREQ_MASK (0x7 << SAR0_CPU_FREQ_OFFSET)
#define SAR0_FABRIC_FREQ_OFFSET 24
#define SAR0_FABRIC_FREQ_MASK (0xF << SAR0_FABRIC_FREQ_OFFSET)
#define SAR0_CPU0CORE_OFFSET 31
#define SAR0_CPU0CORE_MASK (0x1 << SAR0_CPU0CORE_OFFSET)
#define SAR1_CPU0CORE_OFFSET 0
#define SAR1_CPU0CORE_MASK (0x1 << SAR1_CPU0CORE_OFFSET)
#define PEX_CLK_100MHZ_OFFSET 2
#define PEX_CLK_100MHZ_MASK (0x1 << PEX_CLK_100MHZ_OFFSET)
#define SAR1_FABRIC_MODE_OFFSET 19
#define SAR1_FABRIC_MODE_MASK (0x1 << SAR1_FABRIC_MODE_OFFSET)
#define SAR1_CPU_MODE_OFFSET 20
#define SAR1_CPU_MODE_MASK (0x1 << SAR1_CPU_MODE_OFFSET)
#define SAR_CPU_FAB_GET(cpu, fab) (((cpu & 0x7) << 21) | ((fab & 0xF) << 24))
#define CORE_AVS_CONTROL_0REG 0x18300
#define CORE_AVS_CONTROL_2REG 0x18308
#define CPU_AVS_CONTROL2_REG 0x20868
#define CPU_AVS_CONTROL0_REG 0x20860
#define GENERAL_PURPOSE_RESERVED0_REG 0x182E0
#define MSAR_TCLK_OFFS 28
#define MSAR_TCLK_MASK (0x1 << MSAR_TCLK_OFFS)
/* Controler environment registers offsets */
#define GEN_PURP_RES_1_REG 0x182F4
#define GEN_PURP_RES_2_REG 0x182F8
/* registers offsets */
#define MV_GPP_REGS_OFFSET(unit) (0x18100 + ((unit) * 0x40))
#define MPP_CONTROL_REG(id) (0x18000 + (id * 4))
#define MV_GPP_REGS_BASE(unit) (MV_GPP_REGS_OFFSET(unit))
#define MV_GPP_REGS_BASE_0 (MV_GPP_REGS_OFFSET_0)
#define GPP_DATA_OUT_REG(grp) (MV_GPP_REGS_BASE(grp) + 0x00)
#define GPP_DATA_OUT_REG_0 (MV_GPP_REGS_BASE_0 + 0x00) /* Used in .S files */
#define GPP_DATA_OUT_EN_REG(grp) (MV_GPP_REGS_BASE(grp) + 0x04)
#define GPP_BLINK_EN_REG(grp) (MV_GPP_REGS_BASE(grp) + 0x08)
#define GPP_DATA_IN_POL_REG(grp) (MV_GPP_REGS_BASE(grp) + 0x0C)
#define GPP_DATA_IN_REG(grp) (MV_GPP_REGS_BASE(grp) + 0x10)
#define GPP_INT_CAUSE_REG(grp) (MV_GPP_REGS_BASE(grp) + 0x14)
#define GPP_INT_MASK_REG(grp) (MV_GPP_REGS_BASE(grp) + 0x18)
#define GPP_INT_LVL_REG(grp) (MV_GPP_REGS_BASE(grp) + 0x1C)
#define GPP_OUT_SET_REG(grp) (0x18130 + ((grp) * 0x40))
#define GPP_64_66_DATA_OUT_SET_REG 0x181A4
#define GPP_OUT_CLEAR_REG(grp) (0x18134 + ((grp) * 0x40))
#define GPP_64_66_DATA_OUT_CLEAR_REG 0x181B0
#define GPP_FUNC_SELECT_REG (MV_GPP_REGS_BASE(0) + 0x40)
#define MV_GPP66 (1 << 2)
/* Relevant for MV78XX0 */
#define GPP_DATA_OUT_SET_REG (MV_GPP_REGS_BASE(0) + 0x20)
#define GPP_DATA_OUT_CLEAR_REG (MV_GPP_REGS_BASE(0) + 0x24)
/* This define describes the maximum number of supported PEX Interfaces */
#define MV_PEX_MAX_IF 10
#define MV_PEX_MAX_UNIT 4
#define MV_SERDES_NUM_TO_PEX_NUM(num) ((num < 8) ? (num) : (8 + (num / 12)))
#define PEX_PHY_ACCESS_REG(unit) (0x40000 + ((unit) % 2 * 0x40000) + \
((unit)/2 * 0x2000) + 0x1B00)
#define SATA_BASE_REG(port) (0xA2000 + (port)*0x2000)
#define SATA_PWR_PLL_CTRL_REG(port) (SATA_BASE_REG(port) + 0x804)
#define SATA_DIG_LP_ENA_REG(port) (SATA_BASE_REG(port) + 0x88C)
#define SATA_REF_CLK_SEL_REG(port) (SATA_BASE_REG(port) + 0x918)
#define SATA_COMPHY_CTRL_REG(port) (SATA_BASE_REG(port) + 0x920)
#define SATA_LP_PHY_EXT_CTRL_REG(port) (SATA_BASE_REG(port) + 0x058)
#define SATA_LP_PHY_EXT_STAT_REG(port) (SATA_BASE_REG(port) + 0x05C)
#define SATA_IMP_TX_SSC_CTRL_REG(port) (SATA_BASE_REG(port) + 0x810)
#define SATA_GEN_1_SET_0_REG(port) (SATA_BASE_REG(port) + 0x834)
#define SATA_GEN_1_SET_1_REG(port) (SATA_BASE_REG(port) + 0x838)
#define SATA_GEN_2_SET_0_REG(port) (SATA_BASE_REG(port) + 0x83C)
#define SATA_GEN_2_SET_1_REG(port) (SATA_BASE_REG(port) + 0x840)
#define MV_ETH_BASE_ADDR (0x72000)
#define MV_ETH_REGS_OFFSET(port) (MV_ETH_BASE_ADDR - ((port) / 2) * \
0x40000 + ((port) % 2) * 0x4000)
#define MV_ETH_REGS_BASE(port) MV_ETH_REGS_OFFSET(port)
#define SGMII_PWR_PLL_CTRL_REG(port) (MV_ETH_REGS_BASE(port) + 0xE04)
#define SGMII_DIG_LP_ENA_REG(port) (MV_ETH_REGS_BASE(port) + 0xE8C)
#define SGMII_REF_CLK_SEL_REG(port) (MV_ETH_REGS_BASE(port) + 0xF18)
#define SGMII_SERDES_CFG_REG(port) (MV_ETH_REGS_BASE(port) + 0x4A0)
#define SGMII_SERDES_STAT_REG(port) (MV_ETH_REGS_BASE(port) + 0x4A4)
#define SGMII_COMPHY_CTRL_REG(port) (MV_ETH_REGS_BASE(port) + 0xF20)
#define QSGMII_GEN_1_SETTING_REG(port) (MV_ETH_REGS_BASE(port) + 0xE38)
#define QSGMII_SERDES_CFG_REG(port) (MV_ETH_REGS_BASE(port) + 0x4a0)
#define SERDES_LINE_MUX_REG_0_7 0x18270
#define SERDES_LINE_MUX_REG_8_15 0x18274
#define QSGMII_CONTROL_1_REG 0x18404
/* SOC_CTRL_REG fields */
#define SCR_PEX_ENA_OFFS(pex) ((pex) & 0x3)
#define SCR_PEX_ENA_MASK(pex) (1 << pex)
#define PCIE0_QUADX1_EN (1<<7)
#define PCIE1_QUADX1_EN (1<<8)
#define SCR_PEX_4BY1_OFFS(pex) ((pex) + 7)
#define SCR_PEX_4BY1_MASK(pex) (1 << SCR_PEX_4BY1_OFFS(pex))
#define PCIE1_CLK_OUT_EN_OFF 5
#define PCIE1_CLK_OUT_EN_MASK (1 << PCIE1_CLK_OUT_EN_OFF)
#define PCIE0_CLK_OUT_EN_OFF 4
#define PCIE0_CLK_OUT_EN_MASK (1 << PCIE0_CLK_OUT_EN_OFF)
#define SCR_PEX0_4BY1_OFFS 7
#define SCR_PEX0_4BY1_MASK (1 << SCR_PEX0_4BY1_OFFS)
#define SCR_PEX1_4BY1_OFFS 8
#define SCR_PEX1_4BY1_MASK (1 << SCR_PEX1_4BY1_OFFS)
#define MV_MISC_REGS_OFFSET (0x18200)
#define MV_MISC_REGS_BASE (MV_MISC_REGS_OFFSET)
#define SOC_CTRL_REG (MV_MISC_REGS_BASE + 0x4)
/*
* PCI Express Control and Status Registers
*/
#define MAX_PEX_DEVICES 32
#define MAX_PEX_FUNCS 8
#define MAX_PEX_BUSSES 256
#define PXSR_PEX_BUS_NUM_OFFS 8 /* Bus Number Indication */
#define PXSR_PEX_BUS_NUM_MASK (0xff << PXSR_PEX_BUS_NUM_OFFS)
#define PXSR_PEX_DEV_NUM_OFFS 16 /* Device Number Indication */
#define PXSR_PEX_DEV_NUM_MASK (0x1f << PXSR_PEX_DEV_NUM_OFFS)
#define PXSR_DL_DOWN 0x1 /* DL_Down indication. */
#define PXCAR_CONFIG_EN (1 << 31)
#define PEX_STATUS_AND_COMMAND 0x004
#define PXSAC_MABORT (1 << 29) /* Recieved Master Abort */
/* PCI Express Configuration Address Register */
/* PEX_CFG_ADDR_REG (PXCAR) */
#define PXCAR_REG_NUM_OFFS 2
#define PXCAR_REG_NUM_MAX 0x3F
#define PXCAR_REG_NUM_MASK (PXCAR_REG_NUM_MAX << PXCAR_REG_NUM_OFFS)
#define PXCAR_FUNC_NUM_OFFS 8
#define PXCAR_FUNC_NUM_MAX 0x7
#define PXCAR_FUNC_NUM_MASK (PXCAR_FUNC_NUM_MAX << PXCAR_FUNC_NUM_OFFS)
#define PXCAR_DEVICE_NUM_OFFS 11
#define PXCAR_DEVICE_NUM_MAX 0x1F
#define PXCAR_DEVICE_NUM_MASK (PXCAR_DEVICE_NUM_MAX << PXCAR_DEVICE_NUM_OFFS)
#define PXCAR_BUS_NUM_OFFS 16
#define PXCAR_BUS_NUM_MAX 0xFF
#define PXCAR_BUS_NUM_MASK (PXCAR_BUS_NUM_MAX << PXCAR_BUS_NUM_OFFS)
#define PXCAR_EXT_REG_NUM_OFFS 24
#define PXCAR_EXT_REG_NUM_MAX 0xF
#define PXCAR_REAL_EXT_REG_NUM_OFFS 8
#define PXCAR_REAL_EXT_REG_NUM_MASK (0xF << PXCAR_REAL_EXT_REG_NUM_OFFS)
#define PEX_CAPABILITIES_REG(if) ((MV_PEX_IF_REGS_BASE(if)) + 0x60)
#define PEX_LINK_CAPABILITIES_REG(if) ((MV_PEX_IF_REGS_BASE(if)) + 0x6C)
#define PEX_LINK_CTRL_STATUS_REG(if) ((MV_PEX_IF_REGS_BASE(if)) + 0x70)
#define PEX_LINK_CTRL_STATUS2_REG(if) ((MV_PEX_IF_REGS_BASE(if)) + 0x90)
#define PEX_CTRL_REG(if) ((MV_PEX_IF_REGS_BASE(if)) + 0x1A00)
#define PEX_STATUS_REG(if) ((MV_PEX_IF_REGS_BASE(if)) + 0x1A04)
#define PEX_COMPLT_TMEOUT_REG(if) ((MV_PEX_IF_REGS_BASE(if)) + 0x1A10)
#define PEX_PWR_MNG_EXT_REG(if) ((MV_PEX_IF_REGS_BASE(if)) + 0x1A18)
#define PEX_FLOW_CTRL_REG(if) ((MV_PEX_IF_REGS_BASE(if)) + 0x1A20)
#define PEX_DYNMC_WIDTH_MNG_REG(if) ((MV_PEX_IF_REGS_BASE(if)) + 0x1A30)
#define PEX_ROOT_CMPLX_SSPL_REG(if) ((MV_PEX_IF_REGS_BASE(if)) + 0x1A0C)
#define PEX_RAM_PARITY_CTRL_REG(if) ((MV_PEX_IF_REGS_BASE(if)) + 0x1A50)
#define PEX_DBG_CTRL_REG(if) ((MV_PEX_IF_REGS_BASE(if)) + 0x1A60)
#define PEX_DBG_STATUS_REG(if) ((MV_PEX_IF_REGS_BASE(if)) + 0x1A64)
#define PXLCSR_NEG_LNK_GEN_OFFS 16 /* Negotiated Link GEN */
#define PXLCSR_NEG_LNK_GEN_MASK (0xf << PXLCSR_NEG_LNK_GEN_OFFS)
#define PXLCSR_NEG_LNK_GEN_1_1 (0x1 << PXLCSR_NEG_LNK_GEN_OFFS)
#define PXLCSR_NEG_LNK_GEN_2_0 (0x2 << PXLCSR_NEG_LNK_GEN_OFFS)
#define PEX_CFG_ADDR_REG(if) ((MV_PEX_IF_REGS_BASE(if)) + 0x18F8)
#define PEX_CFG_DATA_REG(if) ((MV_PEX_IF_REGS_BASE(if)) + 0x18FC)
#define PEX_CAUSE_REG(if) ((MV_PEX_IF_REGS_BASE(if)) + 0x1900)
#define PEX_CAPABILITY_REG 0x60
#define PEX_DEV_CAPABILITY_REG 0x64
#define PEX_DEV_CTRL_STAT_REG 0x68
#define PEX_LINK_CAPABILITY_REG 0x6C
#define PEX_LINK_CTRL_STAT_REG 0x70
#define PEX_LINK_CTRL_STAT_2_REG 0x90
#endif /* __BOARD_ENV_SPEC */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,185 @@
/*
* Copyright (C) Marvell International Ltd. and its affiliates
*
* SPDX-License-Identifier: GPL-2.0
*/
#include <common.h>
#include <i2c.h>
#include <spl.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>
#include "high_speed_env_spec.h"
MV_SERDES_CHANGE_M_PHY serdes_change_m_phy[] = {
/* SERDES TYPE, Low REG OFFS, Low REG VALUE, Hi REG OFS, Hi REG VALUE */
{
/* PEX: Change of Slew Rate port0 */
SERDES_UNIT_PEX, 0x0,
(0x0F << 16) | 0x2a21, 0x0, (0x0F << 16) | 0x2a21
}, {
/* PEX: Change PLL BW port0 */
SERDES_UNIT_PEX, 0x0,
(0x4F << 16) | 0x6219, 0x0, (0x4F << 16) | 0x6219
}, {
/* SATA: Slew rate change port 0 */
SERDES_UNIT_SATA, 0x0083C, 0x8a31, 0x0083C, 0x8a31
}, {
/* SATA: Slew rate change port 0 */
SERDES_UNIT_SATA, 0x00834, 0xc928, 0x00834, 0xc928
}, {
/* SATA: Slew rate change port 0 */
SERDES_UNIT_SATA, 0x00838, 0x30f0, 0x00838, 0x30f0
}, {
/* SATA: Slew rate change port 0 */
SERDES_UNIT_SATA, 0x00840, 0x30f5, 0x00840, 0x30f5
}, {
/* SGMII: FFE setting Port0 */
SERDES_UNIT_SGMII0, 0x00E18, 0x989F, 0x00E18, 0x989F
}, {
/* SGMII: SELMUP and SELMUF Port0 */
SERDES_UNIT_SGMII0, 0x00E38, 0x10FA, 0x00E38, 0x10FA
}, {
/* SGMII: Amplitude new setting gen2 Port3 */
SERDES_UNIT_SGMII0, 0x00E34, 0xC968, 0x00E34, 0xC66C
}, {
/* QSGMII: Amplitude and slew rate change */
SERDES_UNIT_QSGMII, 0x72E34, 0xaa58, 0x72E34, 0xaa58
}, {
/* QSGMII: SELMUP and SELMUF */
SERDES_UNIT_QSGMII, 0x72e38, 0x10aF, 0x72e38, 0x10aF
}, {
/* QSGMII: 0x72e18 */
SERDES_UNIT_QSGMII, 0x72e18, 0x98AC, 0x72e18, 0x98AC
}, {
/* Null terminated */
SERDES_UNIT_UNCONNECTED, 0, 0
}
};
MV_BIN_SERDES_CFG db88f78xx0_serdes_cfg[] = {
/* Z1B */
{MV_PEX_ROOT_COMPLEX, 0x32221111, 0x11111111,
{PEX_BUS_MODE_X1, PEX_BUS_DISABLED, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
0x0030, serdes_change_m_phy}, /* Default */
{MV_PEX_ROOT_COMPLEX, 0x31211111, 0x11111111,
{PEX_BUS_MODE_X1, PEX_BUS_MODE_X1, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
0x0030, serdes_change_m_phy}, /* PEX module */
/* Z1A */
{MV_PEX_ROOT_COMPLEX, 0x32220000, 0x00000000,
{PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED,
PEX_BUS_DISABLED}, 0x0030, serdes_change_m_phy}, /* Default - Z1A */
{MV_PEX_ROOT_COMPLEX, 0x31210000, 0x00000000,
{PEX_BUS_DISABLED, PEX_BUS_MODE_X1, PEX_BUS_DISABLED, PEX_BUS_DISABLED},
0x0030, serdes_change_m_phy} /* PEX module - Z1A */
};
MV_BIN_SERDES_CFG db88f78xx0rev2_serdes_cfg[] = {
/* A0 */
{MV_PEX_ROOT_COMPLEX, 0x33221111, 0x11111111,
{PEX_BUS_MODE_X1, PEX_BUS_DISABLED, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
0x0030, serdes_change_m_phy}, /* Default: No Pex module, PEX0 x1, disabled */
{MV_PEX_ROOT_COMPLEX, 0x33211111, 0x11111111,
{PEX_BUS_MODE_X1, PEX_BUS_MODE_X1, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
0x0030, serdes_change_m_phy}, /* Pex module, PEX0 x1, PEX1 x1 */
{MV_PEX_ROOT_COMPLEX, 0x33221111, 0x11111111,
{PEX_BUS_MODE_X4, PEX_BUS_DISABLED, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
0x0030, serdes_change_m_phy}, /* no Pex module, PEX0 x4, PEX1 disabled */
{MV_PEX_ROOT_COMPLEX, 0x33211111, 0x11111111,
{PEX_BUS_MODE_X4, PEX_BUS_MODE_X1, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
0x0030, serdes_change_m_phy}, /* Pex module, PEX0 x4, PEX1 x1 */
{MV_PEX_ROOT_COMPLEX, 0x11111111, 0x11111111,
{PEX_BUS_MODE_X1, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
0x0030, serdes_change_m_phy}, /* Pex module, PEX0 x1, PEX1 x4 */
{MV_PEX_ROOT_COMPLEX, 0x11111111, 0x11111111,
{PEX_BUS_MODE_X4, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
0x0030, serdes_change_m_phy}, /* Pex module, PEX0 x4, PEX1 x4 */
};
MV_BIN_SERDES_CFG rd78460nas_serdes_cfg[] = {
{MV_PEX_ROOT_COMPLEX, 0x00223001, 0x11111111,
{PEX_BUS_MODE_X1, PEX_BUS_DISABLED, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
0x0030, serdes_change_m_phy}, /* Default */
{MV_PEX_ROOT_COMPLEX, 0x33320201, 0x11111111,
{PEX_BUS_MODE_X1, PEX_BUS_DISABLED, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
0x00f4, serdes_change_m_phy}, /* Switch module */
};
MV_BIN_SERDES_CFG rd78460_serdes_cfg[] = {
{MV_PEX_ROOT_COMPLEX, 0x22321111, 0x00000000,
{PEX_BUS_MODE_X4, PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED},
0x0010, serdes_change_m_phy}, /* CPU0 */
{MV_PEX_ROOT_COMPLEX, 0x00321111, 0x00000000,
{PEX_BUS_MODE_X4, PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED},
0x0010, serdes_change_m_phy} /* CPU1-3 */
};
MV_BIN_SERDES_CFG rd78460server_rev2_serdes_cfg[] = {
{MV_PEX_ROOT_COMPLEX, 0x00321111, 0x00000000,
{PEX_BUS_MODE_X4, PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED},
0x0010, serdes_change_m_phy}, /* CPU0 */
{MV_PEX_ROOT_COMPLEX, 0x00321111, 0x00000000,
{PEX_BUS_MODE_X4, PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED},
0x0010, serdes_change_m_phy} /* CPU1-3 */
};
MV_BIN_SERDES_CFG db78X60pcac_serdes_cfg[] = {
{MV_PEX_END_POINT, 0x22321111, 0x00000000,
{PEX_BUS_MODE_X4, PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED},
0x0010, serdes_change_m_phy} /* Default */
};
MV_BIN_SERDES_CFG db78X60pcacrev2_serdes_cfg[] = {
{MV_PEX_END_POINT, 0x23321111, 0x00000000,
{PEX_BUS_MODE_X4, PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED},
0x0010, serdes_change_m_phy} /* Default */
};
MV_BIN_SERDES_CFG fpga88f78xx0_serdes_cfg[] = {
{MV_PEX_ROOT_COMPLEX, 0x00000000, 0x00000000,
{PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED, PEX_BUS_DISABLED},
0x0000, serdes_change_m_phy} /* No PEX in FPGA */
};
MV_BIN_SERDES_CFG db78X60amc_serdes_cfg[] = {
{MV_PEX_ROOT_COMPLEX, 0x33111111, 0x00010001,
{PEX_BUS_MODE_X4, PEX_BUS_MODE_X1, PEX_BUS_MODE_X1, PEX_BUS_MODE_X1},
0x0030, serdes_change_m_phy} /* Default */
};
/*
* ARMADA-XP CUSTOMER BOARD
*/
MV_BIN_SERDES_CFG rd78460customer_serdes_cfg[] = {
{MV_PEX_ROOT_COMPLEX, 0x00223001, 0x11111111,
{PEX_BUS_MODE_X1, PEX_BUS_DISABLED, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
0x00000030, serdes_change_m_phy}, /* Default */
{MV_PEX_ROOT_COMPLEX, 0x33320201, 0x11111111,
{PEX_BUS_MODE_X1, PEX_BUS_DISABLED, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
0x00000030, serdes_change_m_phy}, /* Switch module */
};
MV_BIN_SERDES_CFG rd78460AXP_GP_serdes_cfg[] = {
{MV_PEX_ROOT_COMPLEX, 0x00223001, 0x11111111,
{PEX_BUS_MODE_X1, PEX_BUS_DISABLED, PEX_BUS_MODE_X4, PEX_BUS_MODE_X4},
0x0030, serdes_change_m_phy} /* Default */
};
MV_BIN_SERDES_CFG *serdes_info_tbl[] = {
db88f78xx0_serdes_cfg,
rd78460_serdes_cfg,
db78X60pcac_serdes_cfg,
fpga88f78xx0_serdes_cfg,
db88f78xx0rev2_serdes_cfg,
rd78460nas_serdes_cfg,
db78X60amc_serdes_cfg,
db78X60pcacrev2_serdes_cfg,
rd78460server_rev2_serdes_cfg,
rd78460AXP_GP_serdes_cfg,
rd78460customer_serdes_cfg
};
u8 rd78460gp_twsi_dev[] = { 0x4C, 0x4D, 0x4E };
u8 db88f78xx0rev2_twsi_dev[] = { 0x4C, 0x4D, 0x4E, 0x4F };

View File

@@ -0,0 +1,87 @@
/*
* Copyright (C) Marvell International Ltd. and its affiliates
*
* SPDX-License-Identifier: GPL-2.0
*/
#ifndef __HIGHSPEED_ENV_SPEC_H
#define __HIGHSPEED_ENV_SPEC_H
#include "../../../drivers/ddr/marvell/axp/ddr3_hw_training.h"
typedef enum {
SERDES_UNIT_UNCONNECTED = 0x0,
SERDES_UNIT_PEX = 0x1,
SERDES_UNIT_SATA = 0x2,
SERDES_UNIT_SGMII0 = 0x3,
SERDES_UNIT_SGMII1 = 0x4,
SERDES_UNIT_SGMII2 = 0x5,
SERDES_UNIT_SGMII3 = 0x6,
SERDES_UNIT_QSGMII = 0x7,
SERDES_UNIT_SETM = 0x8,
SERDES_LAST_UNIT
} MV_BIN_SERDES_UNIT_INDX;
typedef enum {
PEX_BUS_DISABLED = 0,
PEX_BUS_MODE_X1 = 1,
PEX_BUS_MODE_X4 = 2,
PEX_BUS_MODE_X8 = 3
} MV_PEX_UNIT_CFG;
typedef enum pex_type {
MV_PEX_ROOT_COMPLEX, /* root complex device */
MV_PEX_END_POINT /* end point device */
} MV_PEX_TYPE;
typedef struct serdes_change_m_phy {
MV_BIN_SERDES_UNIT_INDX type;
u32 reg_low_speed;
u32 val_low_speed;
u32 reg_hi_speed;
u32 val_hi_speed;
} MV_SERDES_CHANGE_M_PHY;
/*
* Configuration per SERDES line. Each nibble is MV_SERDES_LINE_TYPE
*/
typedef struct board_serdes_conf {
MV_PEX_TYPE pex_type; /* MV_PEX_ROOT_COMPLEX MV_PEX_END_POINT */
u32 line0_7; /* Lines 0 to 7 SERDES MUX one nibble per line */
u32 line8_15; /* Lines 8 to 15 SERDES MUX one nibble per line */
MV_PEX_UNIT_CFG pex_mode[4];
/*
* Bus speed - one bit per SERDES line:
* Low speed (0) High speed (1)
* PEX 2.5 G (10 bit) 5 G (20 bit)
* SATA 1.5 G 3 G
* SGMII 1.25 Gbps 3.125 Gbps
*/
u32 bus_speed;
MV_SERDES_CHANGE_M_PHY *serdes_m_phy_change;
} MV_BIN_SERDES_CFG;
#define BIN_SERDES_CFG { \
{0, 1, -1 , -1, -1, -1, -1, -1, -1}, /* Lane 0 */ \
{0, 1, -1 , -1, -1, -1, -1, -1, 2}, /* Lane 1 */ \
{0, 1, -1 , 2, -1, -1, -1, -1, 3}, /* Lane 2 */ \
{0, 1, -1 , -1, 2, -1, -1, 3, -1}, /* Lane 3 */ \
{0, 1, 2 , -1, -1, 3, -1, -1, 4}, /* Lane 4 */ \
{0, 1, 2 , -1, 3, -1, -1, 4, -1}, /* Lane 5 */ \
{0, 1, 2 , 4, -1, 3, -1, -1, -1}, /* Lane 6 */ \
{0, 1, -1 , 2, -1, -1, 3, -1, 4}, /* Lane 7*/ \
{0, 1, -1 , -1, -1, -1, -1, -1, -1}, /* Lane 8 */ \
{0, 1, -1 , -1, -1, -1, -1, -1, -1}, /* Lane 9 */ \
{0, 1, -1 , -1, -1, -1, -1, -1, -1}, /* Lane 10 */ \
{0, 1, -1 , -1, -1, -1, -1, -1, -1}, /* Lane 11 */ \
{0, 1, -1 , -1, -1, -1, -1, -1, -1}, /* Lane 12 */ \
{0, 1, -1 , -1, -1, -1, -1, -1, -1}, /* Lane 13 */ \
{0, 1, -1 , -1, -1, -1, -1, -1, -1}, /* Lane 14 */ \
{0, 1, -1 , -1, -1, -1, -1, -1, -1}, /* Lane 15 */ \
}
#endif /* __HIGHSPEED_ENV_SPEC_H */

View File

@@ -0,0 +1,124 @@
/*
* Copyright (C) 2014-2016 Stefan Roese <sr@denx.de>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <debug_uart.h>
#include <fdtdec.h>
#include <spl.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>
DECLARE_GLOBAL_DATA_PTR;
static u32 get_boot_device(void)
{
u32 val;
u32 boot_device;
/*
* First check, if UART boot-mode is active. This can only
* be done, via the bootrom error register. Here the
* MSB marks if the UART mode is active.
*/
val = readl(CONFIG_BOOTROM_ERR_REG);
boot_device = (val & BOOTROM_ERR_MODE_MASK) >> BOOTROM_ERR_MODE_OFFS;
debug("BOOTROM_REG=0x%08x boot_device=0x%x\n", val, boot_device);
if (boot_device == BOOTROM_ERR_MODE_UART)
return BOOT_DEVICE_UART;
/*
* Now check the SAR register for the strapped boot-device
*/
val = readl(CONFIG_SAR_REG); /* SAR - Sample At Reset */
boot_device = (val & BOOT_DEV_SEL_MASK) >> BOOT_DEV_SEL_OFFS;
debug("SAR_REG=0x%08x boot_device=0x%x\n", val, boot_device);
switch (boot_device) {
#ifdef CONFIG_SPL_MMC_SUPPORT
case BOOT_FROM_MMC:
case BOOT_FROM_MMC_ALT:
return BOOT_DEVICE_MMC1;
#endif
case BOOT_FROM_UART:
return BOOT_DEVICE_UART;
case BOOT_FROM_SPI:
default:
return BOOT_DEVICE_SPI;
};
}
u32 spl_boot_device(void)
{
return get_boot_device();
}
#ifdef CONFIG_SPL_MMC_SUPPORT
u32 spl_boot_mode(const u32 boot_device)
{
return MMCSD_MODE_RAW;
}
#endif
void board_init_f(ulong dummy)
{
int ret;
/*
* Pin muxing needs to be done before UART output, since
* on A38x the UART pins need some re-muxing for output
* to work.
*/
board_early_init_f();
/* Example code showing how to enable the debug UART on MVEBU */
#ifdef EARLY_UART
/*
* Debug UART can be used from here if required:
*
* debug_uart_init();
* printch('a');
* printhex8(0x1234);
* printascii("string");
*/
#endif
ret = spl_init();
if (ret) {
debug("spl_init() failed: %d\n", ret);
hang();
}
/* Use special translation offset for SPL */
dm_set_translation_offset(0xd0000000 - 0xf1000000);
preloader_console_init();
timer_init();
/* Armada 375 does not support SerDes and DDR3 init yet */
#if !defined(CONFIG_ARMADA_375)
/* First init the serdes PHY's */
serdes_phy_config();
/* Setup DDR */
ddr3_init();
#endif
/*
* Return to the BootROM to continue the Marvell xmodem
* UART boot protocol. As initiated by the kwboot tool.
*
* This can only be done by the BootROM and not by the
* U-Boot SPL infrastructure, since the beginning of the
* image is already read and interpreted by the BootROM.
* SPL has no chance to receive this information. So we
* need to return to the BootROM to enable this xmodem
* UART download.
*/
if (get_boot_device() == BOOT_DEVICE_UART)
return_to_bootrom();
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) Marvell International Ltd. and its affiliates
* Written-by: Prafulla Wadaskar <prafulla@marvell.com>
*
* Copyright (C) 2015 Stefan Roese <sr@denx.de>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/io.h>
#include <asm/arch/soc.h>
DECLARE_GLOBAL_DATA_PTR;
#define TIMER_LOAD_VAL 0xffffffff
static int init_done __attribute__((section(".data"))) = 0;
/*
* Timer initialization
*/
int timer_init(void)
{
/* Only init the timer once */
if (init_done)
return 0;
init_done = 1;
/* load value into timer */
writel(TIMER_LOAD_VAL, MVEBU_TIMER_BASE + 0x10);
writel(TIMER_LOAD_VAL, MVEBU_TIMER_BASE + 0x14);
#if defined(CONFIG_ARCH_MVEBU)
/* On Armada XP / 38x ..., the 25MHz clock source needs to be enabled */
setbits_le32(MVEBU_TIMER_BASE + 0x00, BIT(11));
#endif
/* enable timer in auto reload mode */
setbits_le32(MVEBU_TIMER_BASE + 0x00, 0x3);
return 0;
}