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

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
@@ -0,0 +1,91 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <arch_helpers.h>
#include <common/debug.h>
#include <mv_ddr_if.h>
#include <plat_marvell.h>
/*
* This function may modify the default DRAM parameters
* based on information received from SPD or bootloader
* configuration located on non volatile storage
*/
void plat_marvell_dram_update_topology(void)
{
}
/*
* This struct provides the DRAM training code with
* the appropriate board DRAM configuration
*/
static struct mv_ddr_topology_map board_topology_map = {
/* FIXME: MISL board 2CS 4Gb x8 devices of micron - 2133P */
DEBUG_LEVEL_ERROR,
0x1, /* active interfaces */
/* cs_mask, mirror, dqs_swap, ck_swap X subphys */
{ { { {0x3, 0x2, 0, 0},
{0x3, 0x2, 0, 0},
{0x3, 0x2, 0, 0},
{0x3, 0x2, 0, 0},
{0x3, 0x2, 0, 0},
{0x3, 0x2, 0, 0},
{0x3, 0x2, 0, 0},
{0x3, 0x2, 0, 0},
{0x3, 0x2, 0, 0} },
SPEED_BIN_DDR_2133P, /* speed_bin */
MV_DDR_DEV_WIDTH_8BIT, /* sdram device width */
MV_DDR_DIE_CAP_4GBIT, /* die capacity */
MV_DDR_FREQ_SAR, /* frequency */
0, 0, /* cas_l, cas_wl */
MV_DDR_TEMP_LOW} }, /* temperature */
MV_DDR_32BIT_ECC_PUP8_BUS_MASK, /* subphys mask */
MV_DDR_CFG_DEFAULT, /* ddr configuration data source */
NOT_COMBINED, /* ddr twin-die combined*/
{ {0} }, /* raw spd data */
{0}, /* timing parameters */
{ /* electrical configuration */
{ /* memory electrical configuration */
MV_DDR_RTT_NOM_PARK_RZQ_DISABLE, /* rtt_nom */
{
MV_DDR_RTT_NOM_PARK_RZQ_DIV4, /* rtt_park 1cs */
MV_DDR_RTT_NOM_PARK_RZQ_DIV1 /* rtt_park 2cs */
},
{
MV_DDR_RTT_WR_DYN_ODT_OFF, /* rtt_wr 1cs */
MV_DDR_RTT_WR_RZQ_DIV2 /* rtt_wr 2cs */
},
MV_DDR_DIC_RZQ_DIV7 /* dic */
},
{ /* phy electrical configuration */
MV_DDR_OHM_30, /* data_drv_p */
MV_DDR_OHM_30, /* data_drv_n */
MV_DDR_OHM_30, /* ctrl_drv_p */
MV_DDR_OHM_30, /* ctrl_drv_n */
{
MV_DDR_OHM_60, /* odt_p 1cs */
MV_DDR_OHM_120 /* odt_p 2cs */
},
{
MV_DDR_OHM_60, /* odt_n 1cs */
MV_DDR_OHM_120 /* odt_n 2cs */
},
},
{ /* mac electrical configuration */
MV_DDR_ODT_CFG_NORMAL, /* odtcfg_pattern */
MV_DDR_ODT_CFG_ALWAYS_ON, /* odtcfg_write */
MV_DDR_ODT_CFG_NORMAL, /* odtcfg_read */
},
}
};
struct mv_ddr_topology_map *mv_ddr_topology_map_get(void)
{
/* Return the board topology as defined in the board code */
return &board_topology_map;
}
@@ -0,0 +1,151 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <armada_common.h>
/*
* If bootrom is currently at BLE there's no need to include the memory
* maps structure at this point
*/
#include <mvebu_def.h>
#ifndef IMAGE_BLE
/*****************************************************************************
* AMB Configuration
*****************************************************************************
*/
struct addr_map_win amb_memory_map[] = {
/* CP0 SPI1 CS0 Direct Mode access */
{0xf900, 0x1000000, AMB_SPI1_CS0_ID},
};
int marvell_get_amb_memory_map(struct addr_map_win **win,
uint32_t *size, uintptr_t base)
{
*win = amb_memory_map;
if (*win == NULL)
*size = 0;
else
*size = ARRAY_SIZE(amb_memory_map);
return 0;
}
#endif
/*****************************************************************************
* IO_WIN Configuration
*****************************************************************************
*/
struct addr_map_win io_win_memory_map[] = {
#ifndef IMAGE_BLE
/* MCI 0 indirect window */
{MVEBU_MCI_REG_BASE_REMAP(0), 0x100000, MCI_0_TID},
/* MCI 1 indirect window */
{MVEBU_MCI_REG_BASE_REMAP(1), 0x100000, MCI_1_TID},
#endif
};
uint32_t marvell_get_io_win_gcr_target(int ap_index)
{
return PIDI_TID;
}
int marvell_get_io_win_memory_map(int ap_index, struct addr_map_win **win,
uint32_t *size)
{
*win = io_win_memory_map;
if (*win == NULL)
*size = 0;
else
*size = ARRAY_SIZE(io_win_memory_map);
return 0;
}
#ifndef IMAGE_BLE
/*****************************************************************************
* IOB Configuration
*****************************************************************************
*/
struct addr_map_win iob_memory_map[] = {
/* PEX1_X1 window */
{0x00000000f7000000, 0x1000000, PEX1_TID},
/* PEX2_X1 window */
{0x00000000f8000000, 0x1000000, PEX2_TID},
{0x00000000c0000000, 0x30000000, PEX2_TID},
{0x0000000800000000, 0x100000000, PEX2_TID},
/* PEX0_X4 window */
{0x00000000f6000000, 0x1000000, PEX0_TID},
/* SPI1_CS0 (RUNIT) window */
{0x00000000f9000000, 0x1000000, RUNIT_TID},
};
int marvell_get_iob_memory_map(struct addr_map_win **win, uint32_t *size,
uintptr_t base)
{
*win = iob_memory_map;
*size = ARRAY_SIZE(iob_memory_map);
return 0;
}
#endif
/*****************************************************************************
* CCU Configuration
*****************************************************************************
*/
struct addr_map_win ccu_memory_map[] = { /* IO window */
#ifdef IMAGE_BLE
{0x00000000f2000000, 0x4000000, IO_0_TID}, /* IO window */
#else
#if LLC_SRAM
/* This entry is prepared for OP-TEE OS that enables the LLC SRAM
* and changes the window target to SRAM_TID.
*/
{PLAT_MARVELL_LLC_SRAM_BASE, PLAT_MARVELL_LLC_SRAM_SIZE, DRAM_0_TID},
#endif
{0x00000000f2000000, 0xe000000, IO_0_TID},
{0x00000000c0000000, 0x30000000, IO_0_TID}, /* IO window */
{0x0000000800000000, 0x100000000, IO_0_TID}, /* IO window */
#endif
};
uint32_t marvell_get_ccu_gcr_target(int ap)
{
return DRAM_0_TID;
}
int marvell_get_ccu_memory_map(int ap_index, struct addr_map_win **win,
uint32_t *size)
{
*win = ccu_memory_map;
*size = ARRAY_SIZE(ccu_memory_map);
return 0;
}
#ifdef IMAGE_BLE
/*****************************************************************************
* SKIP IMAGE Configuration
*****************************************************************************
*/
#if PLAT_RECOVERY_IMAGE_ENABLE
struct skip_image skip_im = {
.detection_method = GPIO,
.info.gpio.num = 33,
.info.gpio.button_state = HIGH,
.info.test.cp_ap = CP,
.info.test.cp_index = 0,
};
void *plat_marvell_get_skip_image_data(void)
{
/* Return the skip_image configurations */
return &skip_im;
}
#endif
#endif
@@ -0,0 +1,15 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef MVEBU_DEF_H
#define MVEBU_DEF_H
#include <a8k_plat_def.h>
#define CP_COUNT 1 /* A70x0 has single CP0 */
#endif /* MVEBU_DEF_H */
@@ -0,0 +1,20 @@
#
# Copyright (C) 2018 Marvell International Ltd.
#
# SPDX-License-Identifier: BSD-3-Clause
# https://spdx.org/licenses
#
PCI_EP_SUPPORT := 0
CP_NUM := 1
$(eval $(call add_define,CP_NUM))
DOIMAGE_SEC := tools/doimage/secure/sec_img_7K.cfg
MARVELL_MOCHI_DRV := drivers/marvell/mochi/apn806_setup.c
BOARD_DIR := $(shell dirname $(lastword $(MAKEFILE_LIST)))
include plat/marvell/armada/a8k/common/a8k_common.mk
include plat/marvell/armada/common/marvell_common.mk
@@ -0,0 +1,91 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <arch_helpers.h>
#include <common/debug.h>
#include <mv_ddr_if.h>
#include <plat_marvell.h>
/*
* This function may modify the default DRAM parameters
* based on information received from SPD or bootloader
* configuration located on non volatile storage
*/
void plat_marvell_dram_update_topology(void)
{
}
/*
* This struct provides the DRAM training code with
* the appropriate board DRAM configuration
*/
static struct mv_ddr_topology_map board_topology_map = {
/* FIXME: MISL board 2CS 8Gb x8 devices of micron - 2133P */
DEBUG_LEVEL_ERROR,
0x1, /* active interfaces */
/* cs_mask, mirror, dqs_swap, ck_swap X subphys */
{ { { {0x3, 0x2, 0, 0},
{0x3, 0x2, 0, 0},
{0x3, 0x2, 0, 0},
{0x3, 0x2, 0, 0},
{0x3, 0x2, 0, 0},
{0x3, 0x2, 0, 0},
{0x3, 0x2, 0, 0},
{0x3, 0x2, 0, 0},
{0x3, 0x2, 0, 0} },
SPEED_BIN_DDR_2400T, /* speed_bin */
MV_DDR_DEV_WIDTH_8BIT, /* sdram device width */
MV_DDR_DIE_CAP_8GBIT, /* die capacity */
MV_DDR_FREQ_SAR, /* frequency */
0, 0, /* cas_l, cas_wl */
MV_DDR_TEMP_LOW} }, /* temperature */
MV_DDR_32BIT_ECC_PUP8_BUS_MASK, /* subphys mask */
MV_DDR_CFG_DEFAULT, /* ddr configuration data source */
NOT_COMBINED, /* ddr twin-die combined*/
{ {0} }, /* raw spd data */
{0}, /* timing parameters */
{ /* electrical configuration */
{ /* memory electrical configuration */
MV_DDR_RTT_NOM_PARK_RZQ_DISABLE, /* rtt_nom */
{
MV_DDR_RTT_NOM_PARK_RZQ_DIV4, /* rtt_park 1cs */
MV_DDR_RTT_NOM_PARK_RZQ_DIV1 /* rtt_park 2cs */
},
{
MV_DDR_RTT_WR_DYN_ODT_OFF, /* rtt_wr 1cs */
MV_DDR_RTT_WR_RZQ_DIV2 /* rtt_wr 2cs */
},
MV_DDR_DIC_RZQ_DIV7 /* dic */
},
{ /* phy electrical configuration */
MV_DDR_OHM_30, /* data_drv_p */
MV_DDR_OHM_30, /* data_drv_n */
MV_DDR_OHM_30, /* ctrl_drv_p */
MV_DDR_OHM_30, /* ctrl_drv_n */
{
MV_DDR_OHM_60, /* odt_p 1cs */
MV_DDR_OHM_120 /* odt_p 2cs */
},
{
MV_DDR_OHM_60, /* odt_n 1cs */
MV_DDR_OHM_120 /* odt_n 2cs */
},
},
{ /* mac electrical configuration */
MV_DDR_ODT_CFG_NORMAL, /* odtcfg_pattern */
MV_DDR_ODT_CFG_ALWAYS_ON, /* odtcfg_write */
MV_DDR_ODT_CFG_NORMAL, /* odtcfg_read */
},
}
};
struct mv_ddr_topology_map *mv_ddr_topology_map_get(void)
{
/* Return the board topology as defined in the board code */
return &board_topology_map;
}
@@ -0,0 +1,148 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <armada_common.h>
/*
* If bootrom is currently at BLE there's no need to include the memory
* maps structure at this point
*/
#include <mvebu_def.h>
#ifndef IMAGE_BLE
/*****************************************************************************
* AMB Configuration
*****************************************************************************
*/
struct addr_map_win *amb_memory_map;
int marvell_get_amb_memory_map(struct addr_map_win **win, uint32_t *size,
uintptr_t base)
{
*win = amb_memory_map;
if (*win == NULL)
*size = 0;
else
*size = ARRAY_SIZE(amb_memory_map);
return 0;
}
#endif
/*****************************************************************************
* IO WIN Configuration
*****************************************************************************
*/
struct addr_map_win io_win_memory_map[] = {
#ifndef IMAGE_BLE
/* MCI 0 indirect window */
{MVEBU_MCI_REG_BASE_REMAP(0), 0x100000, MCI_0_TID},
/* MCI 1 indirect window */
{MVEBU_MCI_REG_BASE_REMAP(1), 0x100000, MCI_1_TID},
#endif
};
uint32_t marvell_get_io_win_gcr_target(int ap_index)
{
return PIDI_TID;
}
int marvell_get_io_win_memory_map(int ap_index, struct addr_map_win **win,
uint32_t *size)
{
*win = io_win_memory_map;
if (*win == NULL)
*size = 0;
else
*size = ARRAY_SIZE(io_win_memory_map);
return 0;
}
#ifndef IMAGE_BLE
/*****************************************************************************
* IOB Configuration
*****************************************************************************
*/
struct addr_map_win iob_memory_map[] = {
/* PEX0_X4 window */
{0x00000000f6000000, 0x6000000, PEX0_TID},
{0x00000000c0000000, 0x30000000, PEX0_TID},
{0x0000000800000000, 0x200000000, PEX0_TID},
};
int marvell_get_iob_memory_map(struct addr_map_win **win, uint32_t *size,
uintptr_t base)
{
*win = iob_memory_map;
*size = ARRAY_SIZE(iob_memory_map);
return 0;
}
#endif
/*****************************************************************************
* CCU Configuration
*****************************************************************************
*/
struct addr_map_win ccu_memory_map[] = {
#ifdef IMAGE_BLE
{0x00000000f2000000, 0x4000000, IO_0_TID}, /* IO window */
#else
#if LLC_SRAM
/* This entry is prepared for OP-TEE OS that enables the LLC SRAM
* and changes the window target to SRAM_TID.
*/
{PLAT_MARVELL_LLC_SRAM_BASE, PLAT_MARVELL_LLC_SRAM_SIZE, DRAM_0_TID},
#endif
{0x00000000f2000000, 0xe000000, IO_0_TID},
{0x00000000c0000000, 0x30000000, IO_0_TID}, /* IO window */
{0x0000000800000000, 0x200000000, IO_0_TID}, /* IO window */
#endif
};
uint32_t marvell_get_ccu_gcr_target(int ap)
{
return DRAM_0_TID;
}
int marvell_get_ccu_memory_map(int ap_index, struct addr_map_win **win,
uint32_t *size)
{
*win = ccu_memory_map;
*size = ARRAY_SIZE(ccu_memory_map);
return 0;
}
#ifdef IMAGE_BLE
struct pci_hw_cfg *plat_get_pcie_hw_data(void)
{
return NULL;
}
/*****************************************************************************
* SKIP IMAGE Configuration
*****************************************************************************
*/
#if PLAT_RECOVERY_IMAGE_ENABLE
struct skip_image skip_im = {
.detection_method = GPIO,
.info.gpio.num = 33,
.info.gpio.button_state = HIGH,
.info.test.cp_ap = CP,
.info.test.cp_index = 0,
};
void *plat_marvell_get_skip_image_data(void)
{
/* Return the skip_image configurations */
return &skip_im;
}
#endif
#endif
@@ -0,0 +1,31 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef MVEBU_DEF_H
#define MVEBU_DEF_H
#include <a8k_plat_def.h>
#define CP_COUNT 1 /* A70x0 has single CP0 */
/***********************************************************************
* Required platform porting definitions common to all
* Management Compute SubSystems (MSS)
***********************************************************************
*/
/*
* Load address of SCP_BL2
* SCP_BL2 is loaded to the same place as BL31.
* Once SCP_BL2 is transferred to the SCP,
* it is discarded and BL31 is loaded over the top.
*/
#ifdef SCP_IMAGE
#define SCP_BL2_BASE BL31_BASE
#endif
#endif /* MVEBU_DEF_H */
@@ -0,0 +1,20 @@
#
# Copyright (C) 2018 Marvell International Ltd.
#
# SPDX-License-Identifier: BSD-3-Clause
# https://spdx.org/licenses
#
PCI_EP_SUPPORT := 0
CP_NUM := 1
$(eval $(call add_define,CP_NUM))
DOIMAGE_SEC := tools/doimage/secure/sec_img_7K.cfg
MARVELL_MOCHI_DRV := drivers/marvell/mochi/apn806_setup.c
BOARD_DIR := $(shell dirname $(lastword $(MAKEFILE_LIST)))
include plat/marvell/armada/a8k/common/a8k_common.mk
include plat/marvell/armada/common/marvell_common.mk
@@ -0,0 +1,227 @@
/*
* Copyright (C) 2021 Sartura Ltd.
* Copyright (C) 2021 Globalscale technologies, Inc.
* Copyright (C) 2021 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <arch_helpers.h>
#include <common/debug.h>
#include <mv_ddr_if.h>
#include <plat_marvell.h>
/*
* This function may modify the default DRAM parameters
* based on information received from SPD or bootloader
* configuration located on non volatile storage
*/
void plat_marvell_dram_update_topology(void)
{
}
/*
* This struct provides the DRAM training code with
* the appropriate board DRAM configuration
*/
#if DDR_TOPOLOGY == 0
static struct mv_ddr_topology_map board_topology_map_2g = {
/* 1CS 4Gb x4 devices of Samsung K4A4G085WF */
DEBUG_LEVEL_ERROR,
0x1, /* active interfaces */
/* cs_mask, mirror, dqs_swap, ck_swap X subphys */
{ { { {0x1, 0x2, 0, 0},
{0x1, 0x2, 0, 0},
{0x1, 0x2, 0, 0},
{0x1, 0x2, 0, 0},
{0x1, 0x2, 0, 0},
{0x1, 0x2, 0, 0},
{0x1, 0x2, 0, 0},
{0x1, 0x2, 0, 0},
{0x1, 0x2, 0, 0} },
SPEED_BIN_DDR_2400R, /* speed_bin */
MV_DDR_DEV_WIDTH_8BIT, /* sdram device width */
MV_DDR_DIE_CAP_4GBIT, /* die capacity */
MV_DDR_FREQ_SAR, /* frequency */
0, 0, /* cas_l, cas_wl */
MV_DDR_TEMP_LOW} }, /* temperature */
BUS_MASK_32BIT, /* subphys mask */
MV_DDR_CFG_DEFAULT, /* ddr configuration data source */
NOT_COMBINED, /* ddr twin-die combined*/
{ {0} }, /* raw spd data */
{0}, /* timing parameters */
{ /* electrical configuration */
{ /* memory electrical configuration */
MV_DDR_RTT_NOM_PARK_RZQ_DISABLE, /* rtt_nom */
{
MV_DDR_RTT_NOM_PARK_RZQ_DIV4, /* rtt_park 1cs */
MV_DDR_RTT_NOM_PARK_RZQ_DIV1 /* rtt_park 2cs */
},
{
MV_DDR_RTT_WR_DYN_ODT_OFF, /* rtt_wr 1cs */
MV_DDR_RTT_WR_RZQ_DIV2 /* rtt_wr 2cs */
},
MV_DDR_DIC_RZQ_DIV7 /* dic */
},
{ /* phy electrical configuration */
MV_DDR_OHM_30, /* data_drv_p */
MV_DDR_OHM_30, /* data_drv_n */
MV_DDR_OHM_30, /* ctrl_drv_p */
MV_DDR_OHM_30, /* ctrl_drv_n */
{
MV_DDR_OHM_60, /* odt_p 1cs */
MV_DDR_OHM_120 /* odt_p 2cs */
},
{
MV_DDR_OHM_60, /* odt_n 1cs */
MV_DDR_OHM_120 /* odt_n 2cs */
},
},
{ /* mac electrical configuration */
MV_DDR_ODT_CFG_NORMAL, /* odtcfg_pattern */
MV_DDR_ODT_CFG_ALWAYS_ON, /* odtcfg_write */
MV_DDR_ODT_CFG_NORMAL, /* odtcfg_read */
},
}
};
#endif
#if DDR_TOPOLOGY == 1
static struct mv_ddr_topology_map board_topology_map_4g = {
/* 1CS 8Gb x4 devices of Samsung K4A8G085WC-BCTD */
DEBUG_LEVEL_ERROR,
0x1, /* active interfaces */
/* cs_mask, mirror, dqs_swap, ck_swap X subphys */
{ { { {0x1, 0x2, 0, 0},
{0x1, 0x2, 0, 0},
{0x1, 0x2, 0, 0},
{0x1, 0x2, 0, 0},
{0x1, 0x2, 0, 0},
{0x1, 0x2, 0, 0},
{0x1, 0x2, 0, 0},
{0x1, 0x2, 0, 0},
{0x1, 0x2, 0, 0} },
SPEED_BIN_DDR_2400R, /* speed_bin */
MV_DDR_DEV_WIDTH_8BIT, /* sdram device width */
MV_DDR_DIE_CAP_8GBIT, /* die capacity */
MV_DDR_FREQ_SAR, /* frequency */
0, 0, /* cas_l, cas_wl */
MV_DDR_TEMP_LOW} }, /* temperature */
BUS_MASK_32BIT, /* subphys mask */
MV_DDR_CFG_DEFAULT, /* ddr configuration data source */
NOT_COMBINED, /* ddr twin-die combined*/
{ {0} }, /* raw spd data */
{0}, /* timing parameters */
{ /* electrical configuration */
{ /* memory electrical configuration */
MV_DDR_RTT_NOM_PARK_RZQ_DISABLE, /* rtt_nom */
{
MV_DDR_RTT_NOM_PARK_RZQ_DIV4, /* rtt_park 1cs */
MV_DDR_RTT_NOM_PARK_RZQ_DIV1 /* rtt_park 2cs */
},
{
MV_DDR_RTT_WR_DYN_ODT_OFF, /* rtt_wr 1cs */
MV_DDR_RTT_WR_RZQ_DIV2 /* rtt_wr 2cs */
},
MV_DDR_DIC_RZQ_DIV7 /* dic */
},
{ /* phy electrical configuration */
MV_DDR_OHM_30, /* data_drv_p */
MV_DDR_OHM_30, /* data_drv_n */
MV_DDR_OHM_30, /* ctrl_drv_p */
MV_DDR_OHM_30, /* ctrl_drv_n */
{
MV_DDR_OHM_60, /* odt_p 1cs */
MV_DDR_OHM_120 /* odt_p 2cs */
},
{
MV_DDR_OHM_60, /* odt_n 1cs */
MV_DDR_OHM_120 /* odt_n 2cs */
},
},
{ /* mac electrical configuration */
MV_DDR_ODT_CFG_NORMAL, /* odtcfg_pattern */
MV_DDR_ODT_CFG_ALWAYS_ON, /* odtcfg_write */
MV_DDR_ODT_CFG_NORMAL, /* odtcfg_read */
},
}
};
#endif
#if DDR_TOPOLOGY == 2
static struct mv_ddr_topology_map board_topology_map_8g = {
/* 2CS 8Gb x8 devices of Micron MT40A1G8WE-083E IT */
DEBUG_LEVEL_ERROR,
0x1, /* active interfaces */
/* cs_mask, mirror, dqs_swap, ck_swap X subphys */
{ { { {0x3, 0x2, 0, 0},
{0x3, 0x2, 0, 0},
{0x3, 0x2, 0, 0},
{0x3, 0x2, 0, 0},
{0x3, 0x2, 0, 0},
{0x3, 0x2, 0, 0},
{0x3, 0x2, 0, 0},
{0x3, 0x2, 0, 0},
{0x3, 0x2, 0, 0} },
SPEED_BIN_DDR_2400R, /* speed_bin */
MV_DDR_DEV_WIDTH_8BIT, /* sdram device width */
MV_DDR_DIE_CAP_8GBIT, /* die capacity */
MV_DDR_FREQ_SAR, /* frequency */
0, 0, /* cas_l, cas_wl */
MV_DDR_TEMP_LOW} }, /* temperature */
BUS_MASK_32BIT, /* subphys mask */
MV_DDR_CFG_DEFAULT, /* ddr configuration data source */
NOT_COMBINED, /* ddr twin-die combined*/
{ {0} }, /* raw spd data */
{0}, /* timing parameters */
{ /* electrical configuration */
{ /* memory electrical configuration */
MV_DDR_RTT_NOM_PARK_RZQ_DISABLE, /* rtt_nom */
{
MV_DDR_RTT_NOM_PARK_RZQ_DIV4, /* rtt_park 1cs */
MV_DDR_RTT_NOM_PARK_RZQ_DIV1 /* rtt_park 2cs */
},
{
MV_DDR_RTT_WR_DYN_ODT_OFF, /* rtt_wr 1cs */
MV_DDR_RTT_WR_RZQ_DIV2 /* rtt_wr 2cs */
},
MV_DDR_DIC_RZQ_DIV7 /* dic */
},
{ /* phy electrical configuration */
MV_DDR_OHM_30, /* data_drv_p */
MV_DDR_OHM_30, /* data_drv_n */
MV_DDR_OHM_30, /* ctrl_drv_p */
MV_DDR_OHM_30, /* ctrl_drv_n */
{
MV_DDR_OHM_60, /* odt_p 1cs */
MV_DDR_OHM_120 /* odt_p 2cs */
},
{
MV_DDR_OHM_60, /* odt_n 1cs */
MV_DDR_OHM_120 /* odt_n 2cs */
},
},
{ /* mac electrical configuration */
MV_DDR_ODT_CFG_NORMAL, /* odtcfg_pattern */
MV_DDR_ODT_CFG_ALWAYS_ON, /* odtcfg_write */
MV_DDR_ODT_CFG_NORMAL, /* odtcfg_read */
},
}
};
#endif
struct mv_ddr_topology_map *mv_ddr_topology_map_get(void)
{
/* a70x0_mochabin board supports 3 DDR4 models (2G/1CS, 4G/1CS, 8G/2CS) */
#if DDR_TOPOLOGY == 0
return &board_topology_map_2g;
#elif DDR_TOPOLOGY == 1
return &board_topology_map_4g;
#elif DDR_TOPOLOGY == 2
return &board_topology_map_8g;
#else
#error "Unknown DDR topology"
#endif
}
@@ -0,0 +1,145 @@
/*
* Copyright (C) 2021 Sartura Ltd.
* Copyright (C) 2021 Globalscale technologies, Inc.
* Copyright (C) 2021 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <armada_common.h>
/*
* If bootrom is currently at BLE there's no need to include the memory
* maps structure at this point
*/
#include <mvebu_def.h>
#ifndef IMAGE_BLE
/*****************************************************************************
* AMB Configuration
*****************************************************************************
*/
struct addr_map_win amb_memory_map[] = {
/* CP0 SPI1 CS0 Direct Mode access */
{0xf900, 0x1000000, AMB_SPI1_CS0_ID},
};
int marvell_get_amb_memory_map(struct addr_map_win **win,
uint32_t *size, uintptr_t base)
{
*win = amb_memory_map;
if (*win == NULL)
*size = 0;
else
*size = ARRAY_SIZE(amb_memory_map);
return 0;
}
#endif
/*****************************************************************************
* IO_WIN Configuration
*****************************************************************************
*/
struct addr_map_win io_win_memory_map[] = {
#ifndef IMAGE_BLE
/* MCI 0 indirect window */
{MVEBU_MCI_REG_BASE_REMAP(0), 0x100000, MCI_0_TID},
/* MCI 1 indirect window */
{MVEBU_MCI_REG_BASE_REMAP(1), 0x100000, MCI_1_TID},
#endif
};
uint32_t marvell_get_io_win_gcr_target(int ap_index)
{
return PIDI_TID;
}
int marvell_get_io_win_memory_map(int ap_index, struct addr_map_win **win,
uint32_t *size)
{
*win = io_win_memory_map;
if (*win == NULL)
*size = 0;
else
*size = ARRAY_SIZE(io_win_memory_map);
return 0;
}
#ifndef IMAGE_BLE
/*****************************************************************************
* IOB Configuration
*****************************************************************************
*/
struct addr_map_win iob_memory_map[] = {
/* PEX1_X1 window */
{0x00000000f7000000, 0x1000000, PEX1_TID},
/* PEX2_X1 window */
{0x00000000f8000000, 0x1000000, PEX2_TID},
{0x00000000c0000000, 0x30000000, PEX2_TID},
{0x0000000800000000, 0x100000000, PEX2_TID},
/* PEX0_X4 window */
{0x00000000f6000000, 0x1000000, PEX0_TID},
/* SPI1_CS0 (RUNIT) window */
{0x00000000f9000000, 0x1000000, RUNIT_TID},
};
int marvell_get_iob_memory_map(struct addr_map_win **win, uint32_t *size,
uintptr_t base)
{
*win = iob_memory_map;
*size = ARRAY_SIZE(iob_memory_map);
return 0;
}
#endif
/*****************************************************************************
* CCU Configuration
*****************************************************************************
*/
struct addr_map_win ccu_memory_map[] = { /* IO window */
#ifdef IMAGE_BLE
{0x00000000f2000000, 0x4000000, IO_0_TID}, /* IO window */
#else
#if LLC_SRAM
/* This entry is prepared for OP-TEE OS that enables the LLC SRAM
* and changes the window target to SRAM_TID.
*/
{PLAT_MARVELL_LLC_SRAM_BASE, PLAT_MARVELL_LLC_SRAM_SIZE, DRAM_0_TID},
#endif
{0x00000000f2000000, 0xe000000, IO_0_TID},
{0x00000000c0000000, 0x30000000, IO_0_TID}, /* IO window */
{0x0000000800000000, 0x100000000, IO_0_TID}, /* IO window */
#endif
};
uint32_t marvell_get_ccu_gcr_target(int ap)
{
return DRAM_0_TID;
}
int marvell_get_ccu_memory_map(int ap_index, struct addr_map_win **win,
uint32_t *size)
{
*win = ccu_memory_map;
*size = ARRAY_SIZE(ccu_memory_map);
return 0;
}
#ifdef IMAGE_BLE
/*****************************************************************************
* SKIP IMAGE Configuration
*****************************************************************************
*/
#if PLAT_RECOVERY_IMAGE_ENABLE
void *plat_marvell_get_skip_image_data(void)
{
/* No recovery button on a70x0_mochabin board */
return NULL;
}
#endif
#endif
@@ -0,0 +1,87 @@
/*
* Copyright (C) 2021 Sartura Ltd.
* Copyright (C) 2021 Globalscale technologies, Inc.
* Copyright (C) 2021 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef __PHY_PORTING_LAYER_H
#define __PHY_PORTING_LAYER_H
#define MAX_LANE_NR 6
static const struct xfi_params
xfi_static_values_tab[AP_NUM][CP_NUM][MAX_LANE_NR] = {
/* AP0 */
{
/* CP 0 */
{
{ 0 }, /* Comphy0 */
{ 0 }, /* Comphy1 */
{ 0 }, /* Comphy2 */
{ 0 }, /* Comphy3 */
{ .g1_ffe_res_sel = 0x3, .g1_ffe_cap_sel = 0xf, .align90 = 0x60,
.g1_dfe_res = 0x1, .g1_amp = 0x1c, .g1_emph = 0xe,
.g1_emph_en = 0x1, .g1_tx_amp_adj = 0x1, .g1_tx_emph_en = 0x1,
.g1_tx_emph = 0x0, .g1_rx_selmuff = 0x1, .g1_rx_selmufi = 0x0,
.g1_rx_selmupf = 0x2, .g1_rx_selmupi = 0x2,
.valid = 1 }, /* Comphy4 */
{ 0 }, /* Comphy5 */
},
},
};
static const struct sata_params
sata_static_values_tab[AP_NUM][CP_NUM][MAX_LANE_NR] = {
/* AP0 */
{
/* CP 0 */
{
{ 0 }, /* Comphy0 */
{ 0 }, /* Comphy1 */
{ .g1_amp = 0x8, .g2_amp = 0xa, .g3_amp = 0x1e,
.g1_emph = 0x1, .g2_emph = 0x2, .g3_emph = 0xe,
.g1_emph_en = 0x1, .g2_emph_en = 0x1, .g3_emph_en = 0x1,
.g1_tx_amp_adj = 0x1, .g2_tx_amp_adj = 0x1, .g3_tx_amp_adj = 0x1,
.g1_tx_emph_en = 0x0, .g2_tx_emph_en = 0x0, .g3_tx_emph_en = 0x0,
.g1_tx_emph = 0x1, .g2_tx_emph = 0x1, .g3_tx_emph = 0x1,
.g3_dfe_res = 0x1, .g3_ffe_res_sel = 0x4, .g3_ffe_cap_sel = 0xf,
.align90 = 0x61,
.g1_rx_selmuff = 0x3, .g2_rx_selmuff = 0x3, .g3_rx_selmuff = 0x3,
.g1_rx_selmufi = 0x0, .g2_rx_selmufi = 0x0, .g3_rx_selmufi = 0x3,
.g1_rx_selmupf = 0x1, .g2_rx_selmupf = 0x1, .g3_rx_selmupf = 0x2,
.g1_rx_selmupi = 0x0, .g2_rx_selmupi = 0x0, .g3_rx_selmupi = 0x2,
.polarity_invert = COMPHY_POLARITY_NO_INVERT,
.valid = 0x1
}, /* Comphy2 */
{ .g1_amp = 0x8, .g2_amp = 0xa, .g3_amp = 0x1e,
.g1_emph = 0x1, .g2_emph = 0x2, .g3_emph = 0xe,
.g1_emph_en = 0x1, .g2_emph_en = 0x1, .g3_emph_en = 0x1,
.g1_tx_amp_adj = 0x1, .g2_tx_amp_adj = 0x1, .g3_tx_amp_adj = 0x1,
.g1_tx_emph_en = 0x0, .g2_tx_emph_en = 0x0, .g3_tx_emph_en = 0x0,
.g1_tx_emph = 0x1, .g2_tx_emph = 0x1, .g3_tx_emph = 0x1,
.g3_dfe_res = 0x1, .g3_ffe_res_sel = 0x4, .g3_ffe_cap_sel = 0xf,
.align90 = 0x61,
.g1_rx_selmuff = 0x3, .g2_rx_selmuff = 0x3, .g3_rx_selmuff = 0x3,
.g1_rx_selmufi = 0x0, .g2_rx_selmufi = 0x0, .g3_rx_selmufi = 0x3,
.g1_rx_selmupf = 0x1, .g2_rx_selmupf = 0x1, .g3_rx_selmupf = 0x2,
.g1_rx_selmupi = 0x0, .g2_rx_selmupi = 0x0, .g3_rx_selmupi = 0x2,
.polarity_invert = COMPHY_POLARITY_NO_INVERT,
.valid = 0x1
}, /* Comphy3 */
{ 0 }, /* Comphy4 */
{ 0 }, /* Comphy5 */
},
},
};
static const struct usb_params
usb_static_values_tab[AP_NUM][CP_NUM][MAX_LANE_NR] = {
[0 ... AP_NUM-1][0 ... CP_NUM-1][0 ... MAX_LANE_NR-1] = {
.polarity_invert = COMPHY_POLARITY_NO_INVERT
},
};
#endif /* __PHY_PORTING_LAYER_H */
@@ -0,0 +1,15 @@
/*
* Copyright (C) 2021 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef MVEBU_DEF_H
#define MVEBU_DEF_H
#include <a8k_plat_def.h>
#define CP_COUNT 1 /* A70x0 has single CP0 */
#endif /* MVEBU_DEF_H */
@@ -0,0 +1,20 @@
#
# Copyright (C) 2021 Marvell International Ltd.
#
# SPDX-License-Identifier: BSD-3-Clause
# https://spdx.org/licenses
#
PCI_EP_SUPPORT := 0
CP_NUM := 1
$(eval $(call add_define,CP_NUM))
DOIMAGE_SEC := tools/doimage/secure/sec_img_7K.cfg
MARVELL_MOCHI_DRV := drivers/marvell/mochi/apn806_setup.c
BOARD_DIR := $(shell dirname $(lastword $(MAKEFILE_LIST)))
include plat/marvell/armada/a8k/common/a8k_common.mk
include plat/marvell/armada/common/marvell_common.mk
@@ -0,0 +1,147 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/mentor/mi2cv.h>
#include <lib/mmio.h>
#include <mv_ddr_if.h>
#include <mvebu_def.h>
#include <plat_marvell.h>
#define MVEBU_AP_MPP_CTRL0_7_REG MVEBU_AP_MPP_REGS(0)
#define MVEBU_AP_MPP_CTRL4_OFFS 16
#define MVEBU_AP_MPP_CTRL5_OFFS 20
#define MVEBU_AP_MPP_CTRL4_I2C0_SDA_ENA 0x3
#define MVEBU_AP_MPP_CTRL5_I2C0_SCK_ENA 0x3
#define MVEBU_CP_MPP_CTRL37_OFFS 20
#define MVEBU_CP_MPP_CTRL38_OFFS 24
#define MVEBU_CP_MPP_CTRL37_I2C0_SCK_ENA 0x2
#define MVEBU_CP_MPP_CTRL38_I2C0_SDA_ENA 0x2
#define MVEBU_MPP_CTRL_MASK 0xf
/*
* This struct provides the DRAM training code with
* the appropriate board DRAM configuration
*/
static struct mv_ddr_topology_map board_topology_map = {
/* MISL board with 1CS 8Gb x4 devices of Micron 2400T */
DEBUG_LEVEL_ERROR,
0x1, /* active interfaces */
/* cs_mask, mirror, dqs_swap, ck_swap X subphys */
{ { { {0x1, 0x0, 0, 0}, /* FIXME: change the cs mask for all 64 bit */
{0x1, 0x0, 0, 0},
{0x1, 0x0, 0, 0},
{0x1, 0x0, 0, 0},
{0x1, 0x0, 0, 0},
{0x1, 0x0, 0, 0},
{0x1, 0x0, 0, 0},
{0x1, 0x0, 0, 0},
{0x1, 0x0, 0, 0} },
/* TODO: double check if the speed bin is 2400T */
SPEED_BIN_DDR_2400T, /* speed_bin */
MV_DDR_DEV_WIDTH_8BIT, /* sdram device width */
MV_DDR_DIE_CAP_8GBIT, /* die capacity */
MV_DDR_FREQ_SAR, /* frequency */
0, 0, /* cas_l, cas_wl */
MV_DDR_TEMP_LOW} }, /* temperature */
#if DDR32
MV_DDR_32BIT_ECC_PUP8_BUS_MASK, /* subphys mask */
#else
MV_DDR_64BIT_ECC_PUP8_BUS_MASK, /* subphys mask */
#endif
MV_DDR_CFG_SPD, /* ddr configuration data source */
NOT_COMBINED, /* ddr twin-die combined*/
{ {0} }, /* raw spd data */
{0}, /* timing parameters */
{ /* electrical configuration */
{ /* memory electrical configuration */
MV_DDR_RTT_NOM_PARK_RZQ_DISABLE, /* rtt_nom */
{
MV_DDR_RTT_NOM_PARK_RZQ_DIV4, /* rtt_park 1cs */
MV_DDR_RTT_NOM_PARK_RZQ_DIV1 /* rtt_park 2cs */
},
{
MV_DDR_RTT_WR_DYN_ODT_OFF, /* rtt_wr 1cs */
MV_DDR_RTT_WR_RZQ_DIV2 /* rtt_wr 2cs */
},
MV_DDR_DIC_RZQ_DIV7 /* dic */
},
{ /* phy electrical configuration */
MV_DDR_OHM_30, /* data_drv_p */
MV_DDR_OHM_30, /* data_drv_n */
MV_DDR_OHM_30, /* ctrl_drv_p */
MV_DDR_OHM_30, /* ctrl_drv_n */
{
MV_DDR_OHM_60, /* odt_p 1cs */
MV_DDR_OHM_120 /* odt_p 2cs */
},
{
MV_DDR_OHM_60, /* odt_n 1cs */
MV_DDR_OHM_120 /* odt_n 2cs */
},
},
{ /* mac electrical configuration */
MV_DDR_ODT_CFG_NORMAL, /* odtcfg_pattern */
MV_DDR_ODT_CFG_ALWAYS_ON, /* odtcfg_write */
MV_DDR_ODT_CFG_NORMAL, /* odtcfg_read */
},
}
};
struct mv_ddr_topology_map *mv_ddr_topology_map_get(void)
{
/* Return the board topology as defined in the board code */
return &board_topology_map;
}
static void mpp_config(void)
{
uintptr_t reg;
uint32_t val;
reg = MVEBU_CP_MPP_REGS(0, 4);
/* configure CP0 MPP 37 and 38 to i2c */
val = mmio_read_32(reg);
val &= ~((MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL37_OFFS) |
(MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL38_OFFS));
val |= (MVEBU_CP_MPP_CTRL37_I2C0_SCK_ENA <<
MVEBU_CP_MPP_CTRL37_OFFS) |
(MVEBU_CP_MPP_CTRL38_I2C0_SDA_ENA <<
MVEBU_CP_MPP_CTRL38_OFFS);
mmio_write_32(reg, val);
}
/*
* This function may modify the default DRAM parameters
* based on information received from SPD or bootloader
* configuration located on non volatile storage
*/
void plat_marvell_dram_update_topology(void)
{
struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get();
INFO("Gathering DRAM information\n");
if (tm->cfg_src == MV_DDR_CFG_SPD) {
/* configure MPPs to enable i2c */
mpp_config();
/* initialize i2c */
i2c_init((void *)MVEBU_CP0_I2C_BASE);
/* select SPD memory page 0 to access DRAM configuration */
i2c_write(I2C_SPD_P0_ADDR, 0x0, 1, tm->spd_data.all_bytes, 0);
/* read data from spd */
i2c_read(I2C_SPD_ADDR, 0x0, 1, tm->spd_data.all_bytes,
sizeof(tm->spd_data.all_bytes));
}
}
@@ -0,0 +1,202 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <armada_common.h>
/*
* If bootrom is currently at BLE there's no need to include the memory
* maps structure at this point
*/
#include <mvebu_def.h>
#ifndef IMAGE_BLE
/*****************************************************************************
* AMB Configuration
*****************************************************************************
*/
struct addr_map_win amb_memory_map[] = {
/* CP1 SPI1 CS0 Direct Mode access */
{0xf900, 0x1000000, AMB_SPI1_CS0_ID},
};
int marvell_get_amb_memory_map(struct addr_map_win **win, uint32_t *size,
uintptr_t base)
{
*win = amb_memory_map;
if (*win == NULL)
*size = 0;
else
*size = ARRAY_SIZE(amb_memory_map);
return 0;
}
#endif
/*****************************************************************************
* IO WIN Configuration
*****************************************************************************
*/
struct addr_map_win io_win_memory_map[] = {
/* CP1 (MCI0) internal regs */
{0x00000000f4000000, 0x2000000, MCI_0_TID},
#ifndef IMAGE_BLE
/* PCIe0 and SPI1_CS0 (RUNIT) on CP1*/
{0x00000000f9000000, 0x2000000, MCI_0_TID},
/* PCIe1 on CP1*/
{0x00000000fb000000, 0x1000000, MCI_0_TID},
/* PCIe2 on CP1*/
{0x00000000fc000000, 0x1000000, MCI_0_TID},
/* MCI 0 indirect window */
{MVEBU_MCI_REG_BASE_REMAP(0), 0x100000, MCI_0_TID},
/* MCI 1 indirect window */
{MVEBU_MCI_REG_BASE_REMAP(1), 0x100000, MCI_1_TID},
#endif
};
uint32_t marvell_get_io_win_gcr_target(int ap_index)
{
return PIDI_TID;
}
int marvell_get_io_win_memory_map(int ap_index, struct addr_map_win **win,
uint32_t *size)
{
*win = io_win_memory_map;
if (*win == NULL)
*size = 0;
else
*size = ARRAY_SIZE(io_win_memory_map);
return 0;
}
#ifndef IMAGE_BLE
/*****************************************************************************
* IOB Configuration
*****************************************************************************
*/
struct addr_map_win iob_memory_map_cp0[] = {
/* CP0 */
/* PEX1_X1 window */
{0x00000000f7000000, 0x1000000, PEX1_TID},
/* PEX2_X1 window */
{0x00000000f8000000, 0x1000000, PEX2_TID},
/* PEX0_X4 window */
{0x00000000f6000000, 0x1000000, PEX0_TID},
{0x00000000c0000000, 0x30000000, PEX0_TID},
{0x0000000800000000, 0x100000000, PEX0_TID},
};
struct addr_map_win iob_memory_map_cp1[] = {
/* CP1 */
/* SPI1_CS0 (RUNIT) window */
{0x00000000f9000000, 0x1000000, RUNIT_TID},
/* PEX1_X1 window */
{0x00000000fb000000, 0x1000000, PEX1_TID},
/* PEX2_X1 window */
{0x00000000fc000000, 0x1000000, PEX2_TID},
/* PEX0_X4 window */
{0x00000000fa000000, 0x1000000, PEX0_TID}
};
int marvell_get_iob_memory_map(struct addr_map_win **win, uint32_t *size,
uintptr_t base)
{
switch (base) {
case MVEBU_CP_REGS_BASE(0):
*win = iob_memory_map_cp0;
*size = ARRAY_SIZE(iob_memory_map_cp0);
return 0;
case MVEBU_CP_REGS_BASE(1):
*win = iob_memory_map_cp1;
*size = ARRAY_SIZE(iob_memory_map_cp1);
return 0;
default:
*size = 0;
*win = 0;
return 1;
}
}
#endif
/*****************************************************************************
* CCU Configuration
*****************************************************************************
*/
struct addr_map_win ccu_memory_map[] = {
#ifdef IMAGE_BLE
{0x00000000f2000000, 0x4000000, IO_0_TID}, /* IO window */
#else
#if LLC_SRAM
/* This entry is prepared for OP-TEE OS that enables the LLC SRAM
* and changes the window target to SRAM_TID.
*/
{PLAT_MARVELL_LLC_SRAM_BASE, PLAT_MARVELL_LLC_SRAM_SIZE, DRAM_0_TID},
#endif
{0x00000000f2000000, 0xe000000, IO_0_TID}, /* IO window */
{0x00000000c0000000, 0x30000000, IO_0_TID}, /* IO window */
{0x0000000800000000, 0x100000000, IO_0_TID}, /* IO window */
#endif
};
uint32_t marvell_get_ccu_gcr_target(int ap)
{
return DRAM_0_TID;
}
int marvell_get_ccu_memory_map(int ap, struct addr_map_win **win,
uint32_t *size)
{
*win = ccu_memory_map;
*size = ARRAY_SIZE(ccu_memory_map);
return 0;
}
#ifndef IMAGE_BLE
/*****************************************************************************
* SoC PM configuration
*****************************************************************************
*/
/* CP GPIO should be used and the GPIOs should be within same GPIO register */
struct power_off_method pm_cfg = {
.type = PMIC_GPIO,
.cfg.gpio.pin_count = 1,
.cfg.gpio.info = {{0, 35} },
.cfg.gpio.step_count = 7,
.cfg.gpio.seq = {1, 0, 1, 0, 1, 0, 1},
.cfg.gpio.delay_ms = 10,
};
void *plat_marvell_get_pm_cfg(void)
{
/* Return the PM configurations */
return &pm_cfg;
}
/* In reference to #ifndef IMAGE_BLE, this part is used for BLE only. */
#else
/*****************************************************************************
* SKIP IMAGE Configuration
*****************************************************************************
*/
#if PLAT_RECOVERY_IMAGE_ENABLE
struct skip_image skip_im = {
.detection_method = GPIO,
.info.gpio.num = 33,
.info.gpio.button_state = HIGH,
.info.test.cp_ap = CP,
.info.test.cp_index = 0,
};
void *plat_marvell_get_skip_image_data(void)
{
/* Return the skip_image configurations */
return &skip_im;
}
#endif
#endif
@@ -0,0 +1,192 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef PHY_PORTING_LAYER_H
#define PHY_PORTING_LAYER_H
#define MAX_LANE_NR 6
static const struct xfi_params
xfi_static_values_tab[AP_NUM][CP_NUM][MAX_LANE_NR] = {
/* AP0 */
{
/* CP 0 */
{
{ 0 }, /* Comphy0 */
{ 0 }, /* Comphy1 */
{ .g1_ffe_res_sel = 0x3, .g1_ffe_cap_sel = 0xf,
.align90 = 0x5f,
.g1_dfe_res = 0x2, .g1_amp = 0x1c, .g1_emph = 0xe,
.g1_emph_en = 0x1, .g1_tx_amp_adj = 0x1,
.g1_tx_emph_en = 0x1, .g1_tx_emph = 0x0,
.g1_rx_selmuff = 0x1, .g1_rx_selmufi = 0x0,
.g1_rx_selmupf = 0x2, .g1_rx_selmupi = 0x2,
.valid = 0x1 }, /* Comphy2 */
{ 0 }, /* Comphy3 */
{ .g1_ffe_res_sel = 0x3, .g1_ffe_cap_sel = 0xf,
.align90 = 0x5f,
.g1_dfe_res = 0x2, .g1_amp = 0x1c, .g1_emph = 0xe,
.g1_emph_en = 0x1, .g1_tx_amp_adj = 0x1,
.g1_tx_emph_en = 0x1, .g1_tx_emph = 0x0,
.g1_rx_selmuff = 0x1, .g1_rx_selmufi = 0x0,
.g1_rx_selmupf = 0x2, .g1_rx_selmupi = 0x2,
.valid = 0x1 }, /* Comphy4 */
{ 0 }, /* Comphy5 */
},
/* CP 1 */
{
{ 0 }, /* Comphy0 */
{ 0 }, /* Comphy1 */
{ .g1_ffe_res_sel = 0x3, .g1_ffe_cap_sel = 0xf,
.align90 = 0x5f,
.g1_dfe_res = 0x2, .g1_amp = 0x1c, .g1_emph = 0xe,
.g1_emph_en = 0x1, .g1_tx_amp_adj = 0x1,
.g1_tx_emph_en = 0x1, .g1_tx_emph = 0x0,
.g1_rx_selmuff = 0x1, .g1_rx_selmufi = 0x0,
.g1_rx_selmupf = 0x2, .g1_rx_selmupi = 0x2,
.valid = 0x1 }, /* Comphy2 */
{ 0 }, /* Comphy3 */
{ .g1_ffe_res_sel = 0x3, .g1_ffe_cap_sel = 0xf,
.align90 = 0x5f,
.g1_dfe_res = 0x2, .g1_amp = 0x1c, .g1_emph = 0xe,
.g1_emph_en = 0x1, .g1_tx_amp_adj = 0x1,
.g1_tx_emph_en = 0x1, .g1_tx_emph = 0x0,
.g1_rx_selmuff = 0x1, .g1_rx_selmufi = 0x0,
.g1_rx_selmupf = 0x2, .g1_rx_selmupi = 0x2,
.valid = 0x1 }, /* Comphy4 */
{ 0 }, /* Comphy5 */
},
},
};
static const struct sata_params
sata_static_values_tab[AP_NUM][CP_NUM][MAX_LANE_NR] = {
/* AP0 */
{
/* CP 0 */
{
{ 0 }, /* Comphy0 */
{ .g1_amp = 0x8, .g2_amp = 0xa, .g3_amp = 0x1e,
.g1_emph = 0x1, .g2_emph = 0x2, .g3_emph = 0xe,
.g1_emph_en = 0x1, .g2_emph_en = 0x1,
.g3_emph_en = 0x1,
.g1_tx_amp_adj = 0x1, .g2_tx_amp_adj = 0x1,
.g3_tx_amp_adj = 0x1,
.g1_tx_emph_en = 0x0, .g2_tx_emph_en = 0x0,
.g3_tx_emph_en = 0x0,
.g1_tx_emph = 0x1, .g2_tx_emph = 0x1,
.g3_tx_emph = 0x1,
.g3_dfe_res = 0x1, .g3_ffe_res_sel = 0x4,
.g3_ffe_cap_sel = 0xf,
.align90 = 0x61,
.g1_rx_selmuff = 0x3, .g2_rx_selmuff = 0x3,
.g3_rx_selmuff = 0x3,
.g1_rx_selmufi = 0x0, .g2_rx_selmufi = 0x0,
.g3_rx_selmufi = 0x3,
.g1_rx_selmupf = 0x1, .g2_rx_selmupf = 0x1,
.g3_rx_selmupf = 0x2,
.g1_rx_selmupi = 0x0, .g2_rx_selmupi = 0x0,
.g3_rx_selmupi = 0x2,
.polarity_invert = COMPHY_POLARITY_NO_INVERT,
.valid = 0x1
}, /* Comphy1 */
{ 0 }, /* Comphy2 */
{ .g1_amp = 0x8, .g2_amp = 0xa, .g3_amp = 0x1e,
.g1_emph = 0x1, .g2_emph = 0x2, .g3_emph = 0xe,
.g1_emph_en = 0x1, .g2_emph_en = 0x1,
.g3_emph_en = 0x1,
.g1_tx_amp_adj = 0x1, .g2_tx_amp_adj = 0x1,
.g3_tx_amp_adj = 0x1,
.g1_tx_emph_en = 0x0, .g2_tx_emph_en = 0x0,
.g3_tx_emph_en = 0x0,
.g1_tx_emph = 0x1, .g2_tx_emph = 0x1,
.g3_tx_emph = 0x1,
.g3_dfe_res = 0x1, .g3_ffe_res_sel = 0x4,
.g3_ffe_cap_sel = 0xf,
.align90 = 0x61,
.g1_rx_selmuff = 0x3, .g2_rx_selmuff = 0x3,
.g3_rx_selmuff = 0x3,
.g1_rx_selmufi = 0x0, .g2_rx_selmufi = 0x0,
.g3_rx_selmufi = 0x3,
.g1_rx_selmupf = 0x1, .g2_rx_selmupf = 0x1,
.g3_rx_selmupf = 0x2,
.g1_rx_selmupi = 0x0, .g2_rx_selmupi = 0x0,
.g3_rx_selmupi = 0x2,
.polarity_invert = COMPHY_POLARITY_NO_INVERT,
.valid = 0x1
}, /* Comphy3 */
{ 0 }, /* Comphy4 */
{ 0 }, /* Comphy5 */
},
/* CP 1 */
{
{ 0 }, /* Comphy0 */
{ .g1_amp = 0x8, .g2_amp = 0xa, .g3_amp = 0x1e,
.g1_emph = 0x1, .g2_emph = 0x2, .g3_emph = 0xe,
.g1_emph_en = 0x1, .g2_emph_en = 0x1,
.g3_emph_en = 0x1,
.g1_tx_amp_adj = 0x1, .g2_tx_amp_adj = 0x1,
.g3_tx_amp_adj = 0x1,
.g1_tx_emph_en = 0x0, .g2_tx_emph_en = 0x0,
.g3_tx_emph_en = 0x0,
.g1_tx_emph = 0x1, .g2_tx_emph = 0x1,
.g3_tx_emph = 0x1,
.g3_dfe_res = 0x1, .g3_ffe_res_sel = 0x4,
.g3_ffe_cap_sel = 0xf,
.align90 = 0x61,
.g1_rx_selmuff = 0x3, .g2_rx_selmuff = 0x3,
.g3_rx_selmuff = 0x3,
.g1_rx_selmufi = 0x0, .g2_rx_selmufi = 0x0,
.g3_rx_selmufi = 0x3,
.g1_rx_selmupf = 0x1, .g2_rx_selmupf = 0x1,
.g3_rx_selmupf = 0x2,
.g1_rx_selmupi = 0x0, .g2_rx_selmupi = 0x0,
.g3_rx_selmupi = 0x2,
.polarity_invert = COMPHY_POLARITY_NO_INVERT,
.valid = 0x1
}, /* Comphy1 */
{ 0 }, /* Comphy2 */
{ .g1_amp = 0x8, .g2_amp = 0xa, .g3_amp = 0x1e,
.g1_emph = 0x1, .g2_emph = 0x2, .g3_emph = 0xe,
.g1_emph_en = 0x1, .g2_emph_en = 0x1,
.g3_emph_en = 0x1,
.g1_tx_amp_adj = 0x1, .g2_tx_amp_adj = 0x1,
.g3_tx_amp_adj = 0x1,
.g1_tx_emph_en = 0x0, .g2_tx_emph_en = 0x0,
.g3_tx_emph_en = 0x0,
.g1_tx_emph = 0x1, .g2_tx_emph = 0x1,
.g3_tx_emph = 0x1,
.g3_dfe_res = 0x1, .g3_ffe_res_sel = 0x4,
.g3_ffe_cap_sel = 0xf,
.align90 = 0x61,
.g1_rx_selmuff = 0x3, .g2_rx_selmuff = 0x3,
.g3_rx_selmuff = 0x3,
.g1_rx_selmufi = 0x0, .g2_rx_selmufi = 0x0,
.g3_rx_selmufi = 0x3,
.g1_rx_selmupf = 0x1, .g2_rx_selmupf = 0x1,
.g3_rx_selmupf = 0x2,
.g1_rx_selmupi = 0x0, .g2_rx_selmupi = 0x0,
.g3_rx_selmupi = 0x2,
.polarity_invert = COMPHY_POLARITY_NO_INVERT,
.valid = 0x1
}, /* Comphy3 */
{ 0 }, /* Comphy4 */
{ 0 }, /* Comphy5 */
},
},
};
static const struct usb_params
usb_static_values_tab[AP_NUM][CP_NUM][MAX_LANE_NR] = {
[0 ... AP_NUM-1][0 ... CP_NUM-1][0 ... MAX_LANE_NR-1] = {
.polarity_invert = COMPHY_POLARITY_NO_INVERT
},
};
#endif /* PHY_PORTING_LAYER_H */
@@ -0,0 +1,17 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef MVEBU_DEF_H
#define MVEBU_DEF_H
#include <a8k_plat_def.h>
#define CP_COUNT 2 /* A80x0 has both CP0 & CP1 */
#define I2C_SPD_ADDR 0x53 /* Access SPD data */
#define I2C_SPD_P0_ADDR 0x36 /* Select SPD data page 0 */
#endif /* MVEBU_DEF_H */
@@ -0,0 +1,20 @@
#
# Copyright (C) 2018 Marvell International Ltd.
#
# SPDX-License-Identifier: BSD-3-Clause
# https://spdx.org/licenses
#
PCI_EP_SUPPORT := 0
CP_NUM := 2
$(eval $(call add_define,CP_NUM))
DOIMAGE_SEC := tools/doimage/secure/sec_img_8K.cfg
MARVELL_MOCHI_DRV := drivers/marvell/mochi/apn806_setup.c
BOARD_DIR := $(shell dirname $(lastword $(MAKEFILE_LIST)))
include plat/marvell/armada/a8k/common/a8k_common.mk
include plat/marvell/armada/common/marvell_common.mk
@@ -0,0 +1,131 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/mentor/mi2cv.h>
#include <lib/mmio.h>
#include <mv_ddr_if.h>
#include <mvebu_def.h>
#include <plat_marvell.h>
#define MVEBU_CP_MPP_CTRL37_OFFS 20
#define MVEBU_CP_MPP_CTRL38_OFFS 24
#define MVEBU_CP_MPP_CTRL37_I2C0_SCK_ENA 0x2
#define MVEBU_CP_MPP_CTRL38_I2C0_SDA_ENA 0x2
#define MVEBU_MPP_CTRL_MASK 0xf
/*
* This struct provides the DRAM training code with
* the appropriate board DRAM configuration
*/
static struct mv_ddr_topology_map board_topology_map = {
/* Board with 1CS 8Gb x4 devices of Micron 2400T */
DEBUG_LEVEL_ERROR,
0x1, /* active interfaces */
/* cs_mask, mirror, dqs_swap, ck_swap X subphys */
{ { { {0x1, 0x0, 0, 0}, /* FIXME: change the cs mask for all 64 bit */
{0x1, 0x0, 0, 0},
{0x1, 0x0, 0, 0},
{0x1, 0x0, 0, 0},
{0x1, 0x0, 0, 0},
{0x1, 0x0, 0, 0},
{0x1, 0x0, 0, 0},
{0x1, 0x0, 0, 0},
{0x1, 0x0, 0, 0} },
/* TODO: double check if the speed bin is 2400T */
SPEED_BIN_DDR_2400T, /* speed_bin */
MV_DDR_DEV_WIDTH_8BIT, /* sdram device width */
MV_DDR_DIE_CAP_8GBIT, /* die capacity */
MV_DDR_FREQ_SAR, /* frequency */
0, 0, /* cas_l, cas_wl */
MV_DDR_TEMP_LOW} }, /* temperature */
MV_DDR_64BIT_BUS_MASK, /* subphys mask */
MV_DDR_CFG_SPD, /* ddr configuration data source */
NOT_COMBINED, /* ddr twin-die combined*/
{ {0} }, /* raw spd data */
{0}, /* timing parameters */
{ /* electrical configuration */
{ /* memory electrical configuration */
MV_DDR_RTT_NOM_PARK_RZQ_DISABLE, /* rtt_nom */
{
MV_DDR_RTT_NOM_PARK_RZQ_DIV4, /* rtt_park 1cs */
MV_DDR_RTT_NOM_PARK_RZQ_DIV1 /* rtt_park 2cs */
},
{
MV_DDR_RTT_WR_DYN_ODT_OFF, /* rtt_wr 1cs */
MV_DDR_RTT_WR_RZQ_DIV2 /* rtt_wr 2cs */
},
MV_DDR_DIC_RZQ_DIV7 /* dic */
},
{ /* phy electrical configuration */
MV_DDR_OHM_30, /* data_drv_p */
MV_DDR_OHM_30, /* data_drv_n */
MV_DDR_OHM_30, /* ctrl_drv_p */
MV_DDR_OHM_30, /* ctrl_drv_n */
{
MV_DDR_OHM_60, /* odt_p 1cs */
MV_DDR_OHM_120 /* odt_p 2cs */
},
{
MV_DDR_OHM_60, /* odt_n 1cs */
MV_DDR_OHM_120 /* odt_n 2cs */
},
},
{ /* mac electrical configuration */
MV_DDR_ODT_CFG_NORMAL, /* odtcfg_pattern */
MV_DDR_ODT_CFG_ALWAYS_ON, /* odtcfg_write */
MV_DDR_ODT_CFG_NORMAL, /* odtcfg_read */
},
}
};
struct mv_ddr_topology_map *mv_ddr_topology_map_get(void)
{
/* Return the board topology as defined in the board code */
return &board_topology_map;
}
static void mpp_config(void)
{
uint32_t val;
uintptr_t reg = MVEBU_CP_MPP_REGS(0, 4);
/* configure CP0 MPP 37 and 38 to i2c */
val = mmio_read_32(reg);
val &= ~((MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL37_OFFS) |
(MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL38_OFFS));
val |= (MVEBU_CP_MPP_CTRL37_I2C0_SCK_ENA << MVEBU_CP_MPP_CTRL37_OFFS) |
(MVEBU_CP_MPP_CTRL38_I2C0_SDA_ENA << MVEBU_CP_MPP_CTRL38_OFFS);
mmio_write_32(reg, val);
}
/*
* This function may modify the default DRAM parameters
* based on information received from SPD or bootloader
* configuration located on non volatile storage
*/
void plat_marvell_dram_update_topology(void)
{
struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get();
INFO("Gathering DRAM information\n");
if (tm->cfg_src == MV_DDR_CFG_SPD) {
/* configure MPPs to enable i2c */
mpp_config();
/* initialize the i2c */
i2c_init((void *)MVEBU_CP0_I2C_BASE);
/* select SPD memory page 0 to access DRAM configuration */
i2c_write(I2C_SPD_P0_ADDR, 0x0, 1, tm->spd_data.all_bytes, 0);
/* read data from spd */
i2c_read(I2C_SPD_ADDR, 0x0, 1, tm->spd_data.all_bytes,
sizeof(tm->spd_data.all_bytes));
}
}
@@ -0,0 +1,200 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <armada_common.h>
/*
* If bootrom is currently at BLE there's no need to include the memory
* maps structure at this point
*/
#include <mvebu_def.h>
#ifndef IMAGE_BLE
/*****************************************************************************
* GPIO Configuration
*****************************************************************************
*/
#define MPP_CONTROL_REGISTER 0xf2440018
#define MPP_CONTROL_MPP_SEL_52_MASK 0xf0000
#define GPIO_DATA_OUT1_REGISTER 0xf2440140
#define GPIO_DATA_OUT_EN_CTRL1_REGISTER 0xf2440144
#define GPIO52_MASK 0x100000
/* Reset PCIe via GPIO number 52 */
int marvell_gpio_config(void)
{
uint32_t reg;
reg = mmio_read_32(MPP_CONTROL_REGISTER);
reg |= MPP_CONTROL_MPP_SEL_52_MASK;
mmio_write_32(MPP_CONTROL_REGISTER, reg);
reg = mmio_read_32(GPIO_DATA_OUT1_REGISTER);
reg |= GPIO52_MASK;
mmio_write_32(GPIO_DATA_OUT1_REGISTER, reg);
reg = mmio_read_32(GPIO_DATA_OUT_EN_CTRL1_REGISTER);
reg &= ~GPIO52_MASK;
mmio_write_32(GPIO_DATA_OUT_EN_CTRL1_REGISTER, reg);
udelay(100);
return 0;
}
/*****************************************************************************
* AMB Configuration
*****************************************************************************
*/
struct addr_map_win amb_memory_map[] = {
/* CP1 SPI1 CS0 Direct Mode access */
{0xf900, 0x1000000, AMB_SPI1_CS0_ID},
};
int marvell_get_amb_memory_map(struct addr_map_win **win, uint32_t *size,
uintptr_t base)
{
*win = amb_memory_map;
if (*win == NULL)
*size = 0;
else
*size = ARRAY_SIZE(amb_memory_map);
return 0;
}
#endif
/*****************************************************************************
* IO WIN Configuration
*****************************************************************************
*/
struct addr_map_win io_win_memory_map[] = {
/* CP1 (MCI0) internal regs */
{0x00000000f4000000, 0x2000000, MCI_0_TID},
#ifndef IMAGE_BLE
/* PCIe0-2 and SPI1_CS0 (RUNIT) on CP1*/
{0x00000000f9000000, 0x4000000, MCI_0_TID},
/* MCI 0 indirect window */
{MVEBU_MCI_REG_BASE_REMAP(0), 0x100000, MCI_0_TID},
/* MCI 1 indirect window */
{MVEBU_MCI_REG_BASE_REMAP(1), 0x100000, MCI_1_TID},
#endif
};
uint32_t marvell_get_io_win_gcr_target(int ap_index)
{
return PIDI_TID;
}
int marvell_get_io_win_memory_map(int ap_index, struct addr_map_win **win,
uint32_t *size)
{
*win = io_win_memory_map;
if (*win == NULL)
*size = 0;
else
*size = ARRAY_SIZE(io_win_memory_map);
return 0;
}
#ifndef IMAGE_BLE
/*****************************************************************************
* IOB Configuration
*****************************************************************************
*/
struct addr_map_win iob_memory_map_cp0[] = {
/* CP0 */
/* PEX1_X1 window */
{0x00000000f7000000, 0x1000000, PEX1_TID},
/* PEX2_X1 window */
{0x00000000f8000000, 0x1000000, PEX2_TID},
/* PEX0_X4 window */
{0x00000000f6000000, 0x1000000, PEX0_TID},
{0x00000000c0000000, 0x30000000, PEX0_TID},
{0x0000000800000000, 0x100000000, PEX0_TID},
};
struct addr_map_win iob_memory_map_cp1[] = {
/* CP1 */
/* SPI1_CS0 (RUNIT) window */
{0x00000000f9000000, 0x1000000, RUNIT_TID},
/* PEX1_X1 window */
{0x00000000fb000000, 0x1000000, PEX1_TID},
/* PEX2_X1 window */
{0x00000000fc000000, 0x1000000, PEX2_TID},
/* PEX0_X4 window */
{0x00000000fa000000, 0x1000000, PEX0_TID}
};
int marvell_get_iob_memory_map(struct addr_map_win **win, uint32_t *size,
uintptr_t base)
{
switch (base) {
case MVEBU_CP_REGS_BASE(0):
*win = iob_memory_map_cp0;
*size = ARRAY_SIZE(iob_memory_map_cp0);
return 0;
case MVEBU_CP_REGS_BASE(1):
*win = iob_memory_map_cp1;
*size = ARRAY_SIZE(iob_memory_map_cp1);
return 0;
default:
*size = 0;
*win = 0;
return 1;
}
}
#endif
/*****************************************************************************
* CCU Configuration
*****************************************************************************
*/
struct addr_map_win ccu_memory_map[] = {
#ifdef IMAGE_BLE
{0x00000000f2000000, 0x4000000, IO_0_TID}, /* IO window */
#else
#if LLC_SRAM
/* This entry is prepared for OP-TEE OS that enables the LLC SRAM
* and changes the window target to SRAM_TID.
*/
{PLAT_MARVELL_LLC_SRAM_BASE, PLAT_MARVELL_LLC_SRAM_SIZE, DRAM_0_TID},
#endif
{0x00000000f2000000, 0xe000000, IO_0_TID}, /* IO window */
{0x00000000c0000000, 0x30000000, IO_0_TID}, /* IO window */
{0x0000000800000000, 0x100000000, IO_0_TID}, /* IO window */
#endif
};
uint32_t marvell_get_ccu_gcr_target(int ap)
{
return DRAM_0_TID;
}
int marvell_get_ccu_memory_map(int ap_index, struct addr_map_win **win,
uint32_t *size)
{
*win = ccu_memory_map;
*size = ARRAY_SIZE(ccu_memory_map);
return 0;
}
/* In reference to #ifndef IMAGE_BLE, this part is used for BLE only. */
/*****************************************************************************
* SKIP IMAGE Configuration
*****************************************************************************
*/
void *plat_marvell_get_skip_image_data(void)
{
/* No recovery button on A8k-MCBIN board */
return NULL;
}
@@ -0,0 +1,17 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef MVEBU_DEF_H
#define MVEBU_DEF_H
#include <a8k_plat_def.h>
#define CP_COUNT 2 /* A80x0 has both CP0 & CP1 */
#define I2C_SPD_ADDR 0x53 /* Access SPD data */
#define I2C_SPD_P0_ADDR 0x36 /* Select SPD data page 0 */
#endif /* MVEBU_DEF_H */
@@ -0,0 +1,20 @@
#
# Copyright (C) 2018 Marvell International Ltd.
#
# SPDX-License-Identifier: BSD-3-Clause
# https://spdx.org/licenses
#
PCI_EP_SUPPORT := 0
CP_NUM := 2
$(eval $(call add_define,CP_NUM))
DOIMAGE_SEC := tools/doimage/secure/sec_img_8K.cfg
MARVELL_MOCHI_DRV := drivers/marvell/mochi/apn806_setup.c
BOARD_DIR := $(shell dirname $(lastword $(MAKEFILE_LIST)))
include plat/marvell/armada/a8k/common/a8k_common.mk
include plat/marvell/armada/common/marvell_common.mk
@@ -0,0 +1,140 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/mentor/mi2cv.h>
#include <lib/mmio.h>
#include <mv_ddr_if.h>
#include <mvebu_def.h>
#include <plat_marvell.h>
#define MVEBU_AP_MPP_CTRL0_7_REG MVEBU_AP_MPP_REGS(0)
#define MVEBU_AP_MPP_CTRL4_OFFS 16
#define MVEBU_AP_MPP_CTRL5_OFFS 20
#define MVEBU_AP_MPP_CTRL4_I2C0_SDA_ENA 0x3
#define MVEBU_AP_MPP_CTRL5_I2C0_SCK_ENA 0x3
#define MVEBU_CP_MPP_CTRL37_OFFS 20
#define MVEBU_CP_MPP_CTRL38_OFFS 24
#define MVEBU_CP_MPP_CTRL37_I2C0_SCK_ENA 0x2
#define MVEBU_CP_MPP_CTRL38_I2C0_SDA_ENA 0x2
#define MVEBU_MPP_CTRL_MASK 0xf
/*
* This struct provides the DRAM training code with
* the appropriate board DRAM configuration
*/
static struct mv_ddr_topology_map board_topology_map = {
/* Board with 1CS 8Gb x4 devices of Micron 2400T */
DEBUG_LEVEL_ERROR,
0x1, /* active interfaces */
/* cs_mask, mirror, dqs_swap, ck_swap X subphys */
{ { { {0x1, 0x0, 0, 0}, /* FIXME: change the cs mask for all 64 bit */
{0x1, 0x0, 0, 0},
{0x1, 0x0, 0, 0},
{0x1, 0x0, 0, 0},
{0x1, 0x0, 0, 0},
{0x1, 0x0, 0, 0},
{0x1, 0x0, 0, 0},
{0x1, 0x0, 0, 0},
{0x1, 0x0, 0, 0} },
/* TODO: double check if the speed bin is 2400T */
SPEED_BIN_DDR_2400T, /* speed_bin */
MV_DDR_DEV_WIDTH_8BIT, /* sdram device width */
MV_DDR_DIE_CAP_8GBIT, /* die capacity */
MV_DDR_FREQ_SAR, /* frequency */
0, 0, /* cas_l, cas_wl */
MV_DDR_TEMP_LOW} }, /* temperature */
MV_DDR_64BIT_BUS_MASK, /* subphys mask */
MV_DDR_CFG_SPD, /* ddr configuration data source */
NOT_COMBINED, /* ddr twin-die combined*/
{ {0} }, /* raw spd data */
{0}, /* timing parameters */
{ /* electrical configuration */
{ /* memory electrical configuration */
MV_DDR_RTT_NOM_PARK_RZQ_DISABLE, /* rtt_nom */
{
MV_DDR_RTT_NOM_PARK_RZQ_DIV4, /* rtt_park 1cs */
MV_DDR_RTT_NOM_PARK_RZQ_DIV1 /* rtt_park 2cs */
},
{
MV_DDR_RTT_WR_DYN_ODT_OFF, /* rtt_wr 1cs */
MV_DDR_RTT_WR_RZQ_DIV2 /* rtt_wr 2cs */
},
MV_DDR_DIC_RZQ_DIV7 /* dic */
},
{ /* phy electrical configuration */
MV_DDR_OHM_30, /* data_drv_p */
MV_DDR_OHM_30, /* data_drv_n */
MV_DDR_OHM_30, /* ctrl_drv_p */
MV_DDR_OHM_30, /* ctrl_drv_n */
{
MV_DDR_OHM_60, /* odt_p 1cs */
MV_DDR_OHM_120 /* odt_p 2cs */
},
{
MV_DDR_OHM_60, /* odt_n 1cs */
MV_DDR_OHM_120 /* odt_n 2cs */
},
},
{ /* mac electrical configuration */
MV_DDR_ODT_CFG_NORMAL, /* odtcfg_pattern */
MV_DDR_ODT_CFG_ALWAYS_ON, /* odtcfg_write */
MV_DDR_ODT_CFG_NORMAL, /* odtcfg_read */
},
}
};
struct mv_ddr_topology_map *mv_ddr_topology_map_get(void)
{
/* Return the board topology as defined in the board code */
return &board_topology_map;
}
static void mpp_config(void)
{
uint32_t val;
uintptr_t reg;
/* configure ap mmps 4, 5 to I2C */
reg = MVEBU_AP_MPP_CTRL0_7_REG;
val = mmio_read_32(reg);
val &= ~((MVEBU_MPP_CTRL_MASK << MVEBU_AP_MPP_CTRL4_OFFS) |
(MVEBU_MPP_CTRL_MASK << MVEBU_AP_MPP_CTRL5_OFFS));
val |= ((MVEBU_AP_MPP_CTRL4_I2C0_SDA_ENA << MVEBU_AP_MPP_CTRL4_OFFS) |
(MVEBU_AP_MPP_CTRL5_I2C0_SCK_ENA << MVEBU_AP_MPP_CTRL5_OFFS));
mmio_write_32(reg, val);
}
/*
* This function may modify the default DRAM parameters
* based on information received from SPD or bootloader
* configuration located on non volatile storage
*/
void plat_marvell_dram_update_topology(void)
{
struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get();
INFO("Gathering DRAM information\n");
if (tm->cfg_src == MV_DDR_CFG_SPD) {
/* configure MPPs to enable i2c */
mpp_config();
/* initialize the MVEBU_AP_I2C_BASE I2C bus */
i2c_init((void *)MVEBU_AP_I2C_BASE);
/* select SPD memory page 0 to access DRAM configuration */
i2c_write(I2C_SPD_P0_ADDR, 0x0, 1, tm->spd_data.all_bytes, 0);
/* read data from spd */
i2c_read(I2C_SPD_ADDR, 0x0, 1, tm->spd_data.all_bytes,
sizeof(tm->spd_data.all_bytes));
}
}
@@ -0,0 +1,201 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <armada_common.h>
/*
* If bootrom is currently at BLE there's no need to include the memory
* maps structure at this point
*/
#include <mvebu_def.h>
#ifndef IMAGE_BLE
/*****************************************************************************
* GPIO Configuration
*****************************************************************************
*/
#define MPP_CONTROL_REGISTER 0xf2440018
#define MPP_CONTROL_MPP_SEL_52_MASK 0xf0000
#define GPIO_DATA_OUT1_REGISTER 0xf2440140
#define GPIO_DATA_OUT_EN_CTRL1_REGISTER 0xf2440144
#define GPIO52_MASK 0x100000
/* Reset PCIe via GPIO number 52 */
int marvell_gpio_config(void)
{
uint32_t reg;
reg = mmio_read_32(MPP_CONTROL_REGISTER);
reg |= MPP_CONTROL_MPP_SEL_52_MASK;
mmio_write_32(MPP_CONTROL_REGISTER, reg);
reg = mmio_read_32(GPIO_DATA_OUT1_REGISTER);
reg |= GPIO52_MASK;
mmio_write_32(GPIO_DATA_OUT1_REGISTER, reg);
reg = mmio_read_32(GPIO_DATA_OUT_EN_CTRL1_REGISTER);
reg &= ~GPIO52_MASK;
mmio_write_32(GPIO_DATA_OUT_EN_CTRL1_REGISTER, reg);
udelay(100);
return 0;
}
/*****************************************************************************
* AMB Configuration
*****************************************************************************
*/
struct addr_map_win amb_memory_map[] = {
/* CP1 SPI1 CS0 Direct Mode access */
{0xf900, 0x1000000, AMB_SPI1_CS0_ID},
};
int marvell_get_amb_memory_map(struct addr_map_win **win, uint32_t *size,
uintptr_t base)
{
*win = amb_memory_map;
if (*win == NULL)
*size = 0;
else
*size = ARRAY_SIZE(amb_memory_map);
return 0;
}
#endif
/*****************************************************************************
* IO WIN Configuration
*****************************************************************************
*/
struct addr_map_win io_win_memory_map[] = {
/* CP1 (MCI0) internal regs */
{0x00000000f4000000, 0x2000000, MCI_0_TID},
#ifndef IMAGE_BLE
/* PCIe0 and SPI1_CS0 (RUNIT) on CP1*/
{0x00000000f9000000, 0x2000000, MCI_0_TID},
/* PCIe1 on CP1*/
{0x00000000fb000000, 0x1000000, MCI_0_TID},
/* PCIe2 on CP1*/
{0x00000000fc000000, 0x1000000, MCI_0_TID},
/* MCI 0 indirect window */
{MVEBU_MCI_REG_BASE_REMAP(0), 0x100000, MCI_0_TID},
/* MCI 1 indirect window */
{MVEBU_MCI_REG_BASE_REMAP(1), 0x100000, MCI_1_TID},
#endif
};
uint32_t marvell_get_io_win_gcr_target(int ap_index)
{
return PIDI_TID;
}
int marvell_get_io_win_memory_map(int ap_index, struct addr_map_win **win,
uint32_t *size)
{
*win = io_win_memory_map;
if (*win == NULL)
*size = 0;
else
*size = ARRAY_SIZE(io_win_memory_map);
return 0;
}
#ifndef IMAGE_BLE
/*****************************************************************************
* IOB Configuration
*****************************************************************************
*/
struct addr_map_win iob_memory_map_cp0[] = {
/* CP0 */
/* PEX1_X1 window */
{0x00000000f7000000, 0x1000000, PEX1_TID},
/* PEX2_X1 window */
{0x00000000f8000000, 0x1000000, PEX2_TID},
/* PEX0_X4 window */
{0x00000000f6000000, 0x1000000, PEX0_TID},
{0x00000000c0000000, 0x30000000, PEX0_TID},
{0x0000000800000000, 0x100000000, PEX0_TID},
};
struct addr_map_win iob_memory_map_cp1[] = {
/* CP1 */
/* SPI1_CS0 (RUNIT) window */
{0x00000000f9000000, 0x1000000, RUNIT_TID},
/* PEX1_X1 window */
{0x00000000fb000000, 0x1000000, PEX1_TID},
/* PEX2_X1 window */
{0x00000000fc000000, 0x1000000, PEX2_TID},
/* PEX0_X4 window */
{0x00000000fa000000, 0x1000000, PEX0_TID}
};
int marvell_get_iob_memory_map(struct addr_map_win **win, uint32_t *size,
uintptr_t base)
{
switch (base) {
case MVEBU_CP_REGS_BASE(0):
*win = iob_memory_map_cp0;
*size = ARRAY_SIZE(iob_memory_map_cp0);
return 0;
case MVEBU_CP_REGS_BASE(1):
*win = iob_memory_map_cp1;
*size = ARRAY_SIZE(iob_memory_map_cp1);
return 0;
default:
*size = 0;
*win = 0;
return 1;
}
}
#endif
/*****************************************************************************
* CCU Configuration
*****************************************************************************
*/
struct addr_map_win ccu_memory_map[] = {
#ifdef IMAGE_BLE
{0x00000000f2000000, 0x4000000, IO_0_TID}, /* IO window */
#else
#if LLC_SRAM
{PLAT_MARVELL_LLC_SRAM_BASE, PLAT_MARVELL_LLC_SRAM_SIZE, SRAM_TID},
#endif
{0x00000000f2000000, 0xe000000, IO_0_TID}, /* IO window */
{0x00000000c0000000, 0x30000000, IO_0_TID}, /* IO window */
{0x0000000800000000, 0x100000000, IO_0_TID}, /* IO window */
#endif
};
uint32_t marvell_get_ccu_gcr_target(int ap)
{
return DRAM_0_TID;
}
int marvell_get_ccu_memory_map(int ap_index, struct addr_map_win **win,
uint32_t *size)
{
*win = ccu_memory_map;
*size = ARRAY_SIZE(ccu_memory_map);
return 0;
}
/* In reference to #ifndef IMAGE_BLE, this part is used for BLE only. */
/*****************************************************************************
* SKIP IMAGE Configuration
*****************************************************************************
*/
void *plat_marvell_get_skip_image_data(void)
{
/* No recovery button on A8k-MCBIN board */
return NULL;
}
@@ -0,0 +1,59 @@
/*
* Copyright (C) 2020 Sartura Ltd.
* Author: Luka Kovacic <luka.kovacic@sartura.hr>
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <armada_common.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <drivers/ti/uart/uart_16550.h>
#include <drivers/console.h>
#include <plat_marvell.h>
/*****************************************************************************
* Platform specific power off functions
* Power off PSU / Send command to power management MCU / ...
*****************************************************************************
*/
unsigned char add_xor_checksum(unsigned char *buf, unsigned char xor_len)
{
unsigned char xor_sum = 0;
unsigned int i;
for (i = 0; i < xor_len; i++)
xor_sum ^= buf[i];
return xor_sum;
}
int system_power_off(void)
{
static console_t console;
/* WT61P803 MCU system_off_now command */
unsigned char system_off_now[4] = { '@', 'C', '0' };
int i, len;
len = sizeof(system_off_now);
system_off_now[len - 1] = add_xor_checksum(system_off_now, len);
console_16550_register(PLAT_MARVELL_UART_BASE + 0x100,
PLAT_MARVELL_UART_CLK_IN_HZ, 115200, &console);
/* Send system_off_now to console */
for (i = 0; i < len; i++) {
console.putc(system_off_now[i], &console);
udelay(1000);
}
console.flush(&console);
(void)console_unregister(&console);
mdelay(100);
return 0;
}
@@ -0,0 +1,17 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef MVEBU_DEF_H
#define MVEBU_DEF_H
#include <a8k_plat_def.h>
#define CP_COUNT 2 /* A80x0 has both CP0 & CP1 */
#define I2C_SPD_ADDR 0x53 /* Access SPD data */
#define I2C_SPD_P0_ADDR 0x36 /* Select SPD data page 0 */
#endif /* MVEBU_DEF_H */
@@ -0,0 +1,20 @@
#
# Copyright (C) 2018 Marvell International Ltd.
#
# SPDX-License-Identifier: BSD-3-Clause
# https://spdx.org/licenses
#
PCI_EP_SUPPORT := 0
CP_NUM := 2
$(eval $(call add_define,CP_NUM))
DOIMAGE_SEC := tools/doimage/secure/sec_img_8K.cfg
MARVELL_MOCHI_DRV := drivers/marvell/mochi/apn806_setup.c
BOARD_DIR := $(shell dirname $(lastword $(MAKEFILE_LIST)))
include plat/marvell/armada/a8k/common/a8k_common.mk
include plat/marvell/armada/common/marvell_common.mk
@@ -0,0 +1,192 @@
#
# Copyright (C) 2016 - 2020 Marvell International Ltd.
#
# SPDX-License-Identifier: BSD-3-Clause
# https://spdx.org/licenses
PLAT_FAMILY := a8k
PLAT_INCLUDE_BASE := include/plat/marvell/armada/$(PLAT_FAMILY)
PLAT_COMMON_BASE := plat/marvell/armada/a8k/common
MARVELL_DRV_BASE := drivers/marvell
MARVELL_COMMON_BASE := plat/marvell/armada/common
MARVELL_SVC_TEST := 0
$(eval $(call add_define,MARVELL_SVC_TEST))
ERRATA_A72_859971 := 1
# Enable MSS support for a8k family
MSS_SUPPORT := 1
$(eval $(call add_define,MSS_SUPPORT))
# Disable EL3 cache for power management
BL31_CACHE_DISABLE := 0
$(eval $(call add_define,BL31_CACHE_DISABLE))
$(eval $(call add_define,PCI_EP_SUPPORT))
$(eval $(call assert_boolean,PCI_EP_SUPPORT))
AP_NUM := 1
$(eval $(call add_define,AP_NUM))
DOIMAGEPATH ?= tools/marvell/doimage
DOIMAGETOOL ?= ${DOIMAGEPATH}/doimage
include plat/marvell/marvell.mk
include tools/marvell/doimage/doimage.mk
ifeq (${MARVELL_SECURE_BOOT},1)
DOIMAGE_SEC_FLAGS := -c $(DOIMAGE_SEC)
DOIMAGE_LIBS_CHECK = \
if ! [ -d "/usr/include/mbedtls" ]; then \
echo "****************************************" >&2; \
echo "Missing mbedTLS installation! " >&2; \
echo "Please download it from \"tls.mbed.org\"" >&2; \
echo "Alternatively on Debian/Ubuntu system install" >&2; \
echo "\"libmbedtls-dev\" package" >&2; \
echo "Make sure to use version 2.1.0 or later" >&2; \
echo "****************************************" >&2; \
exit 1; \
else if ! [ -f "/usr/include/libconfig.h" ]; then \
echo "********************************************************" >&2; \
echo "Missing Libconfig installation!" >&2; \
echo "Please download it from \"www.hyperrealm.com/libconfig/\"" >&2; \
echo "Alternatively on Debian/Ubuntu system install packages" >&2; \
echo "\"libconfig8\" and \"libconfig8-dev\"" >&2; \
echo "********************************************************" >&2; \
exit 1; \
fi \
fi
else #MARVELL_SECURE_BOOT
DOIMAGE_LIBS_CHECK =
DOIMAGE_SEC_FLAGS =
endif #MARVELL_SECURE_BOOT
ROM_BIN_EXT ?= $(BUILD_PLAT)/ble.bin
DOIMAGE_FLAGS += -b $(ROM_BIN_EXT) $(NAND_DOIMAGE_FLAGS) $(DOIMAGE_SEC_FLAGS)
# Check whether to build system_power.c for the platform
ifneq ("$(wildcard $(BOARD_DIR)/board/system_power.c)","")
SYSTEM_POWER_SUPPORT = 1
else
SYSTEM_POWER_SUPPORT = 0
endif
# This define specifies DDR type for BLE
$(eval $(call add_define,CONFIG_DDR4))
# This define specifies DDR topology for BLE
DDR_TOPOLOGY ?= 0
$(eval $(call add_define,DDR_TOPOLOGY))
MARVELL_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \
drivers/arm/gic/v2/gicv2_main.c \
drivers/arm/gic/v2/gicv2_helpers.c \
plat/common/plat_gicv2.c
PLAT_INCLUDES += -I$(BOARD_DIR) \
-I$(BOARD_DIR)/board \
-I$(CURDIR)/drivers/marvell \
-I$(PLAT_COMMON_BASE)/include \
-I$(PLAT_INCLUDE_BASE)/common
PLAT_BL_COMMON_SOURCES := $(PLAT_COMMON_BASE)/aarch64/a8k_common.c \
drivers/ti/uart/aarch64/16550_console.S
ifndef BLE_PORTING_SOURCES
BLE_PORTING_SOURCES := $(BOARD_DIR)/board/dram_port.c \
$(BOARD_DIR)/board/marvell_plat_config.c
endif
MARVELL_MOCHI_DRV += $(MARVELL_DRV_BASE)/mochi/cp110_setup.c
BLE_SOURCES := drivers/mentor/i2c/mi2cv.c \
$(PLAT_COMMON_BASE)/plat_ble_setup.c \
$(MARVELL_MOCHI_DRV) \
$(PLAT_COMMON_BASE)/plat_pm.c \
$(MARVELL_DRV_BASE)/ap807_clocks_init.c \
$(MARVELL_DRV_BASE)/thermal.c \
$(PLAT_COMMON_BASE)/plat_thermal.c \
$(BLE_PORTING_SOURCES) \
$(MARVELL_DRV_BASE)/ccu.c \
$(MARVELL_DRV_BASE)/io_win.c
BL1_SOURCES += $(PLAT_COMMON_BASE)/aarch64/plat_helpers.S \
lib/cpus/aarch64/cortex_a72.S
MARVELL_DRV := $(MARVELL_DRV_BASE)/io_win.c \
$(MARVELL_DRV_BASE)/iob.c \
$(MARVELL_DRV_BASE)/mci.c \
$(MARVELL_DRV_BASE)/amb_adec.c \
$(MARVELL_DRV_BASE)/ccu.c \
$(MARVELL_DRV_BASE)/cache_llc.c \
$(MARVELL_DRV_BASE)/comphy/phy-comphy-cp110.c \
$(MARVELL_DRV_BASE)/mc_trustzone/mc_trustzone.c \
$(MARVELL_DRV_BASE)/secure_dfx_access/armada_thermal.c \
$(MARVELL_DRV_BASE)/secure_dfx_access/misc_dfx.c \
$(MARVELL_DRV_BASE)/ddr_phy_access.c \
drivers/rambus/trng_ip_76.c
ifeq (${MSS_SUPPORT}, 1)
MARVELL_DRV += $(MARVELL_DRV_BASE)/mg_conf_cm3/mg_conf_cm3.c
endif
ifndef BL31_PORTING_SOURCES
BL31_PORTING_SOURCES := $(BOARD_DIR)/board/marvell_plat_config.c
endif
ifeq ($(SYSTEM_POWER_SUPPORT),1)
BL31_PORTING_SOURCES += $(BOARD_DIR)/board/system_power.c
endif
BL31_SOURCES += lib/cpus/aarch64/cortex_a72.S \
$(PLAT_COMMON_BASE)/aarch64/plat_helpers.S \
$(PLAT_COMMON_BASE)/aarch64/plat_arch_config.c \
$(PLAT_COMMON_BASE)/plat_pm.c \
$(PLAT_COMMON_BASE)/plat_bl31_setup.c \
$(MARVELL_COMMON_BASE)/marvell_gicv2.c \
$(MARVELL_COMMON_BASE)/mrvl_sip_svc.c \
$(MARVELL_COMMON_BASE)/marvell_ddr_info.c \
$(BL31_PORTING_SOURCES) \
$(MARVELL_DRV) \
$(MARVELL_MOCHI_DRV) \
$(MARVELL_GIC_SOURCES)
# Add trace functionality for PM
BL31_SOURCES += $(PLAT_COMMON_BASE)/plat_pm_trace.c
ifeq (${MSS_SUPPORT}, 1)
# Force builds with BL2 image on a80x0 platforms
ifndef SCP_BL2
$(error "Error: SCP_BL2 image is mandatory for a8k family")
endif
# MSS (SCP) build
include $(PLAT_COMMON_BASE)/mss/mss_a8k.mk
endif
# BLE (ROM context execution code, AKA binary extension)
BLE_PATH ?= $(PLAT_COMMON_BASE)/ble
include ${BLE_PATH}/ble.mk
$(eval $(call MAKE_BL,ble))
clean realclean distclean: mrvl_clean
.PHONY: mrvl_clean
mrvl_clean:
@echo " Doimage CLEAN"
${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${DOIMAGEPATH} clean
${DOIMAGETOOL}: FORCE
@$(DOIMAGE_LIBS_CHECK)
${Q}${MAKE} --no-print-directory -C ${DOIMAGEPATH}
${BUILD_PLAT}/${FLASH_IMAGE}: ${ROM_BIN_EXT} ${BUILD_PLAT}/${BOOT_IMAGE} ${DOIMAGETOOL}
@${ECHO_BLANK_LINE}
@echo "Building flash image"
${Q}${DOIMAGETOOL} ${DOIMAGE_FLAGS} ${BUILD_PLAT}/${BOOT_IMAGE} ${BUILD_PLAT}/${FLASH_IMAGE}
@${ECHO_BLANK_LINE}
@echo "Built $@ successfully"
@${ECHO_BLANK_LINE}
@@ -0,0 +1,70 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <plat_marvell.h>
/* MMU entry for internal (register) space access */
#define MAP_DEVICE0 MAP_REGION_FLAT(DEVICE0_BASE, \
DEVICE0_SIZE, \
MT_DEVICE | MT_RW | MT_SECURE)
/*
* Table of regions for various BL stages to map using the MMU.
*/
#if IMAGE_BL1
const mmap_region_t plat_marvell_mmap[] = {
MARVELL_MAP_SECURE_RAM,
MAP_DEVICE0,
{0}
};
#endif
#if IMAGE_BL2
const mmap_region_t plat_marvell_mmap[] = {
MARVELL_MAP_SECURE_RAM,
MAP_DEVICE0,
MARVELL_MAP_DRAM,
#ifdef SPD_opteed
MARVELL_MAP_OPTEE_CORE_MEM,
MARVELL_OPTEE_PAGEABLE_LOAD_MEM,
#endif
{0}
};
#endif
#if IMAGE_BL2U
const mmap_region_t plat_marvell_mmap[] = {
MARVELL_MAP_SECURE_RAM,
MAP_DEVICE0,
{0}
};
#endif
#if IMAGE_BLE
const mmap_region_t plat_marvell_mmap[] = {
MAP_DEVICE0,
{0}
};
#endif
#if IMAGE_BL31
const mmap_region_t plat_marvell_mmap[] = {
MARVELL_MAP_SECURE_RAM,
MAP_DEVICE0,
MARVELL_MAP_DRAM,
{0}
};
#endif
#if IMAGE_BL32
const mmap_region_t plat_marvell_mmap[] = {
MARVELL_MAP_SECURE_RAM,
MAP_DEVICE0,
{0}
};
#endif
MARVELL_CASSERT_MMAP;
@@ -0,0 +1,95 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/marvell/cache_llc.h>
#include <lib/mmio.h>
#include <plat/common/platform.h>
#define CCU_HTC_ASET (MVEBU_CCU_BASE(MVEBU_AP0) + 0x264)
#define MVEBU_IO_AFFINITY (0xF00)
#define MVEBU_SF_REG (MVEBU_REGS_BASE + 0x40)
#define MVEBU_SF_EN BIT(8)
#define MVEBU_DFX_REG(cluster_id) (MVEBU_REGS_BASE + 0x6F82A0 + \
(cluster_id) * 0x4)
#define MVEBU_DFX_CLK_EN_POS 0x3
#define MVEBU_DFX_CL0_CLK_OFFS 16
#define MVEBU_DFX_CL0_CLK_MASK (0xF << MVEBU_DFX_CL0_CLK_OFFS)
#define MVEBU_DFX_CL1_CLK_OFFS 8
#define MVEBU_DFX_CL1_CLK_MASK (0xF << MVEBU_DFX_CL1_CLK_OFFS)
#ifdef MVEBU_SOC_AP807
static void plat_enable_snoop_filter(void)
{
int cpu_id = plat_my_core_pos();
/* Snoop filter needs to be enabled once per cluster */
if (cpu_id % 2)
return;
mmio_setbits_32(MVEBU_SF_REG, MVEBU_SF_EN);
}
#endif
#ifndef MVEBU_SOC_AP807
static void plat_config_dfx_clock(void)
{
int cluster_id = plat_my_core_pos();
uint32_t val;
/* DFX clock needs to be configured once per cluster */
if ((cluster_id % PLAT_MAX_CPUS_PER_CLUSTER) != 0) {
return;
}
val = mmio_read_32(MVEBU_DFX_REG(cluster_id / PLAT_MAX_CPUS_PER_CLUSTER));
if (cluster_id == 0) {
val &= ~MVEBU_DFX_CL0_CLK_MASK;
val |= (MVEBU_DFX_CLK_EN_POS << MVEBU_DFX_CL0_CLK_OFFS);
} else {
val &= ~MVEBU_DFX_CL1_CLK_MASK;
val |= (MVEBU_DFX_CLK_EN_POS << MVEBU_DFX_CL1_CLK_OFFS);
}
mmio_write_32(MVEBU_DFX_REG(cluster_id / PLAT_MAX_CPUS_PER_CLUSTER), val);
}
#endif
static void plat_enable_affinity(void)
{
int cluster_id;
int affinity;
/* set CPU Affinity */
cluster_id = plat_my_core_pos() / PLAT_MARVELL_CLUSTER_CORE_COUNT;
affinity = (MVEBU_IO_AFFINITY | (1 << cluster_id));
mmio_write_32(CCU_HTC_ASET, affinity);
/* set barier */
isb();
}
void marvell_psci_arch_init(int die_index)
{
#if LLC_ENABLE
/* check if LLC is in exclusive mode
* as L2 is configured to UniqueClean eviction
* (in a8k reset handler)
*/
if (llc_is_exclusive(0) == 0)
ERROR("LLC should be configured to exclusice mode\n");
#endif
/* Enable Affinity */
plat_enable_affinity();
#ifdef MVEBU_SOC_AP807
plat_enable_snoop_filter();
#else
plat_config_dfx_clock();
#endif
}
@@ -0,0 +1,112 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <asm_macros.S>
#include <platform_def.h>
#include <marvell_pm.h>
.globl plat_secondary_cold_boot_setup
.globl plat_get_my_entrypoint
.globl plat_is_my_cpu_primary
.globl plat_reset_handler
/* -----------------------------------------------------
* void plat_secondary_cold_boot_setup (void);
*
* This function performs any platform specific actions
* needed for a secondary cpu after a cold reset. Right
* now this is a stub function.
* -----------------------------------------------------
*/
func plat_secondary_cold_boot_setup
mov x0, #0
ret
endfunc plat_secondary_cold_boot_setup
/* ---------------------------------------------------------------------
* unsigned long plat_get_my_entrypoint (void);
*
* Main job of this routine is to distinguish
* between a cold and warm boot
* For a cold boot, return 0.
* For a warm boot, read the mailbox and return the address it contains.
*
* ---------------------------------------------------------------------
*/
func plat_get_my_entrypoint
/* Read first word and compare it with magic num */
mov_imm x0, PLAT_MARVELL_MAILBOX_BASE
ldr x1, [x0]
mov_imm x2, MVEBU_MAILBOX_MAGIC_NUM
cmp x1, x2
beq warm_boot /* If compare failed, return 0, i.e. cold boot */
mov x0, #0
ret
warm_boot:
mov_imm x1, MBOX_IDX_SEC_ADDR /* Get the jump address */
subs x1, x1, #1
mov x2, #(MBOX_IDX_SEC_ADDR * 8)
lsl x3, x2, x1
add x0, x0, x3
ldr x0, [x0]
ret
endfunc plat_get_my_entrypoint
/* -----------------------------------------------------
* unsigned int plat_is_my_cpu_primary (void);
*
* Find out whether the current cpu is the primary
* cpu.
* -----------------------------------------------------
*/
func plat_is_my_cpu_primary
mrs x0, mpidr_el1
and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
cmp x0, #MVEBU_PRIMARY_CPU
cset w0, eq
ret
endfunc plat_is_my_cpu_primary
/* -----------------------------------------------------
* void plat_reset_handler (void);
*
* Platform specific configuration right after cpu is
* is our of reset.
*
* The plat_reset_handler can clobber x0 - x18, x30.
* -----------------------------------------------------
*/
func plat_reset_handler
/*
* Note: the configurations below should be done before MMU,
* I Cache and L2are enabled.
* The reset handler is executed right after reset
* and before Caches are enabled.
*/
/* Enable L1/L2 ECC and Parity */
mrs x5, s3_1_c11_c0_2 /* L2 Ctrl */
orr x5, x5, #(1 << 21) /* Enable L1/L2 cache ECC & Parity */
msr s3_1_c11_c0_2, x5 /* L2 Ctrl */
#if LLC_ENABLE
/*
* Enable L2 UniqueClean evictions
* Note: this configuration assumes that LLC is configured
* in exclusive mode.
* Later on in the code this assumption will be validated
*/
mrs x5, s3_1_c15_c0_0 /* L2 Ctrl */
orr x5, x5, #(1 << 14) /* Enable UniqueClean evictions with data */
msr s3_1_c15_c0_0, x5 /* L2 Ctrl */
#endif
/* Instruction Barrier to allow msr command completion */
isb
ret
endfunc plat_reset_handler
@@ -0,0 +1,76 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <platform_def.h>
OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
ENTRY(ble_main)
MEMORY {
RAM (rwx): ORIGIN = BLE_BASE, LENGTH = BLE_LIMIT - BLE_BASE
}
SECTIONS
{
. = BLE_BASE;
ro . : {
__RO_START__ = .;
*ble_main.o(.entry*)
*(.text*)
*(.rodata*)
__RO_END_UNALIGNED__ = .;
__RO_END__ = .;
} >RAM
/*
* Define a linker symbol to mark start of the RW memory area for this
* image.
*/
__RW_START__ = . ;
.data . : {
__DATA_START__ = .;
*(.data*)
__DATA_END__ = .;
} >RAM
stacks . (NOLOAD) : {
__STACKS_START__ = .;
*(tzfw_normal_stacks)
__STACKS_END__ = .;
} >RAM
.bss : {
__BSS_START__ = .;
*(.bss*)
__BSS_END__ = .;
} >RAM
/*
* Extend the BLE binary to the maximum size allocated for it in platform
* definition files and prevent overlapping between BLE BSS section and
* additional extensions that can follow the BLE in flash image preamble.
* This situation happens for instance when secure extension is added to
* the image preamble.
*/
.fill LOADADDR(.bss) + SIZEOF(.bss) : {
FILL(0xDEADC0DE);
. = ORIGIN(RAM) + LENGTH(RAM) - 1;
BYTE(0x00)
} >RAM
/*
* Define a linker symbol to mark end of the RW memory area for this
* image.
*/
__RW_END__ = .;
__BLE_END__ = .;
__BSS_SIZE__ = SIZEOF(.bss);
}
@@ -0,0 +1,35 @@
# Copyright (C) 2018 Marvell International Ltd.
#
# SPDX-License-Identifier: BSD-3-Clause
# https://spdx.org/licenses
MV_DDR_LIB = $(BUILD_PLAT)/ble/mv_ddr_lib.a
LIBC_LIB = $(BUILD_PLAT)/lib/libc.a
BLE_LIBS = $(MV_DDR_LIB) $(LIBC_LIB)
PLAT_MARVELL = plat/marvell/armada
BLE_SOURCES += $(BLE_PATH)/ble_main.c \
$(BLE_PATH)/ble_mem.S \
drivers/delay_timer/delay_timer.c \
drivers/marvell/iob.c \
$(PLAT_MARVELL)/common/aarch64/marvell_helpers.S \
$(PLAT_MARVELL)/common/plat_delay_timer.c \
$(PLAT_MARVELL)/common/marvell_console.c
MV_DDR_INCLUDES := -I$(CURDIR)/include \
-I$(CURDIR)/include/arch/aarch64 \
-I$(CURDIR)/include/lib/libc \
-I$(CURDIR)/include/lib/libc/aarch64
BLE_LINKERFILE := $(BLE_PATH)/ble.ld.S
BLE_OBJS := $(addprefix $(BUILD_PLAT)/ble/,$(call SOURCES_TO_OBJS,$(BLE_SOURCES)))
$(BLE_OBJS): PLAT_INCLUDES += -I$(MV_DDR_PATH)
$(BLE_OBJS): $(MV_DDR_LIB)
$(MV_DDR_LIB): FORCE
# Do not remove! Following checks are required to ensure correct TF-A builds, removing these checks leads to broken TF-A builds
$(if $(value MV_DDR_PATH),,$(error "Platform '$(PLAT)' for BLE requires MV_DDR_PATH. Please set MV_DDR_PATH to point to the right directory"))
$(if $(wildcard $(value MV_DDR_PATH)/*),,$(error "'MV_DDR_PATH=$(value MV_DDR_PATH)' was specified, but '$(value MV_DDR_PATH)' directory does not exist"))
$(if $(shell git -C $(value MV_DDR_PATH) rev-parse --show-cdup 2>&1),$(error "'MV_DDR_PATH=$(value MV_DDR_PATH)' was specified, but '$(value MV_DDR_PATH)' does not contain valid mv-ddr-marvell git repository"))
@+make -C $(MV_DDR_PATH) --no-print-directory PLAT_INCLUDES="$(MV_DDR_INCLUDES)" PLATFORM=$(PLAT) ARCH=AARCH64 OBJ_DIR=$(BUILD_PLAT)/ble
@@ -0,0 +1,99 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <string.h>
#include <platform_def.h>
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/console.h>
#include <marvell_plat_priv.h>
#include <marvell_pm.h>
#include <plat_marvell.h>
#define BR_FLAG_SILENT 0x1
#define SKIP_IMAGE_CODE 0xDEADB002
void mailbox_clean(void)
{
uintptr_t *mailbox = (void *)PLAT_MARVELL_MAILBOX_BASE;
memset(mailbox, 0, PLAT_MARVELL_MAILBOX_SIZE);
}
int exec_ble_main(int bootrom_flags)
{
int skip = 0;
uintptr_t *mailbox = (void *)PLAT_MARVELL_MAILBOX_BASE;
/*
* In some situations, like boot from UART, bootrom will
* request to avoid printing to console. in that case don't
* initialize the console and prints will be ignored
*/
if ((bootrom_flags & BR_FLAG_SILENT) == 0)
marvell_console_boot_init();
NOTICE("Starting binary extension\n");
/* initialize time (for delay functionality) */
plat_delay_timer_init();
ble_plat_setup(&skip);
/* if there's skip image request, bootrom will load from the image
* saved on the next address of the flash
*/
if (skip)
return SKIP_IMAGE_CODE;
/*
* Check if the mailbox magic number is stored at index MBOX_IDX_MAGIC
* and the suspend to RAM magic number at index MBOX_IDX_SUSPEND_MAGIC.
* If the above is true, this is the recovery from suspend to RAM state.
* In such case the mailbox should remain intact, since it stores the
* warm boot jump address to be used by the TF-A in BL31.
* Othervise the mailbox should be cleaned from a garbage data.
*/
if (mailbox[MBOX_IDX_MAGIC] != MVEBU_MAILBOX_MAGIC_NUM ||
mailbox[MBOX_IDX_SUSPEND_MAGIC] != MVEBU_MAILBOX_SUSPEND_STATE) {
NOTICE("Cold boot\n");
mailbox_clean();
} else {
void (*bootrom_exit)(void) =
(void (*)(void))mailbox[MBOX_IDX_ROM_EXIT_ADDR];
INFO("Recovery...\n");
/*
* If this is recovery from suspend, two things has to be done:
* 1. Define the DRAM region as executable memory for preparing
* jump to TF-A
* 2. Instead of returning control to the BootROM, invalidate
* and flush caches, and continue execution at address stored
* in the mailbox.
* This should be done until the BootROM have a native support
* for the system restore flow.
*/
marvell_ble_prepare_exit();
bootrom_exit();
}
return 0;
}
/* NOTE: don't notify this function, all code must be added to exec_ble_main
* in order to keep the end of ble_main as a fixed address.
*/
int __attribute__ ((section(".entry"))) ble_main(int bootrom_flags)
{
volatile int ret;
ret = exec_ble_main(bootrom_flags);
return ret;
}
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <asm_macros.S>
#include <marvell_def.h>
#include <platform_def.h>
#define PTE_NON_EXEC_OFF 54 /* XN - eXecute Never bit offset - see VMSAv8-64 */
.globl marvell_ble_prepare_exit
func marvell_ble_prepare_exit
/*
* Read the page table base and set the first page to be executable.
* This is required for jumping to DRAM for further execution.
*/
mrs x0, ttbr0_el3
ldr x1, [x0]
mov x2, #1
bic x1, x1, x2, lsl #PTE_NON_EXEC_OFF
str x1, [x0]
tlbi alle3
dsb sy
isb
ret
endfunc marvell_ble_prepare_exit
@@ -0,0 +1,195 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef A8K_PLAT_DEF_H
#define A8K_PLAT_DEF_H
#include <marvell_def.h>
#define MVEBU_PRIMARY_CPU 0x0
#define MVEBU_AP0 0x0
/* APN806 revision ID */
#define MVEBU_CSS_GWD_CTRL_IIDR2_REG (MVEBU_REGS_BASE + 0x610FCC)
#define GWD_IIDR2_REV_ID_OFFSET 12
#define GWD_IIDR2_REV_ID_MASK 0xF
#define GWD_IIDR2_CHIP_ID_OFFSET 20
#define GWD_IIDR2_CHIP_ID_MASK (0xFFFu << GWD_IIDR2_CHIP_ID_OFFSET)
#define CHIP_ID_AP806 0x806
#define CHIP_ID_AP807 0x807
#define COUNTER_FREQUENCY 25000000
#define MVEBU_REGS_BASE 0xF0000000
#define MVEBU_REGS_BASE_MASK 0xF0000000
#define MVEBU_REGS_BASE_AP(ap) MVEBU_REGS_BASE
#define MVEBU_AP_IO_BASE(ap) 0xF2000000
#define MVEBU_CP_OFFSET 0x2000000
#define MVEBU_CP_REGS_BASE(cp_index) (MVEBU_AP_IO_BASE(0) + \
(cp_index) * MVEBU_CP_OFFSET)
#define MVEBU_RFU_BASE (MVEBU_REGS_BASE + 0x6F0000)
#define MVEBU_IO_WIN_BASE(ap_index) (MVEBU_RFU_BASE)
#define MVEBU_IO_WIN_GCR_OFFSET (0x70)
#define MVEBU_IO_WIN_MAX_WINS (7)
/* Misc SoC configurations Base */
#define MVEBU_MISC_SOC_BASE (MVEBU_REGS_BASE + 0x6F4300)
#define MVEBU_CCU_BASE(ap_index) (MVEBU_REGS_BASE + 0x4000)
#define MVEBU_CCU_MAX_WINS (8)
#define MVEBU_LLC_BASE(ap_index) (MVEBU_REGS_BASE + 0x8000)
#define MVEBU_DRAM_MAC_BASE (MVEBU_REGS_BASE + 0x20000)
#define MVEBU_DRAM_PHY_BASE (MVEBU_REGS_BASE + 0x20000)
#define MVEBU_SMMU_BASE (MVEBU_REGS_BASE + 0x100000)
#define MVEBU_CP_MPP_REGS(cp_index, n) (MVEBU_CP_REGS_BASE(cp_index) + \
0x440000 + ((n) << 2))
#define MVEBU_PM_MPP_REGS(cp_index, n) (MVEBU_CP_REGS_BASE(cp_index) + \
0x440000 + ((n / 8) << 2))
#define MVEBU_CP_GPIO_DATA_OUT(cp_index, n) \
(MVEBU_CP_REGS_BASE(cp_index) + \
0x440100 + ((n > 31) ? 0x40 : 0x00))
#define MVEBU_CP_GPIO_DATA_OUT_EN(cp_index, n) \
(MVEBU_CP_REGS_BASE(cp_index) + \
0x440104 + ((n > 31) ? 0x40 : 0x00))
#define MVEBU_CP_GPIO_DATA_IN(cp_index, n) (MVEBU_CP_REGS_BASE(cp_index) + \
0x440110 + ((n > 31) ? 0x40 : 0x00))
#define MVEBU_AP_MPP_REGS(n) (MVEBU_RFU_BASE + 0x4000 + ((n) << 2))
#define MVEBU_AP_GPIO_REGS (MVEBU_RFU_BASE + 0x5040)
#define MVEBU_AP_GPIO_DATA_IN (MVEBU_AP_GPIO_REGS + 0x10)
#define MVEBU_AP_I2C_BASE (MVEBU_REGS_BASE + 0x511000)
#define MVEBU_CP0_I2C_BASE (MVEBU_CP_REGS_BASE(0) + 0x701000)
#define MVEBU_AP_GEN_MGMT_BASE (MVEBU_RFU_BASE + 0x8000)
#define MVEBU_AP_EXT_TSEN_BASE (MVEBU_AP_GEN_MGMT_BASE + 0x84)
#define MVEBU_AP_MC_TRUSTZONE_REG_LOW(ap, win) (MVEBU_REGS_BASE_AP(ap) + \
0x20080 + ((win) * 0x8))
#define MVEBU_AP_MC_TRUSTZONE_REG_HIGH(ap, win) (MVEBU_REGS_BASE_AP(ap) + \
0x20084 + ((win) * 0x8))
/* MCI indirect access definitions */
#define MCI_MAX_UNIT_ID 2
/* SoC RFU / IHBx4 Control */
#define MCIX4_REG_START_ADDRESS_REG(unit_id) (MVEBU_RFU_BASE + \
0x4218 + (unit_id * 0x20))
#define MCI_REMAP_OFF_SHIFT 8
#define MVEBU_MCI_REG_BASE_REMAP(index) (0xFD000000 + \
((index) * 0x1000000))
#define MVEBU_PCIE_X4_MAC_BASE(x) (MVEBU_CP_REGS_BASE(x) + 0x600000)
#define MVEBU_COMPHY_BASE(x) (MVEBU_CP_REGS_BASE(x) + 0x441000)
#define MVEBU_HPIPE_BASE(x) (MVEBU_CP_REGS_BASE(x) + 0x120000)
#define MVEBU_CP_DFX_OFFSET (0x400200)
/*****************************************************************************
* MVEBU memory map related constants
*****************************************************************************
*/
/* Aggregate of all devices in the first GB */
#define DEVICE0_BASE MVEBU_REGS_BASE
#define DEVICE0_SIZE 0x10000000
/*****************************************************************************
* GIC-400 & interrupt handling related constants
*****************************************************************************
*/
/* Base MVEBU compatible GIC memory map */
#define MVEBU_GICD_BASE 0x210000
#define MVEBU_GICC_BASE 0x220000
/*****************************************************************************
* AXI Configuration
*****************************************************************************
*/
#define MVEBU_AXI_ATTR_ARCACHE_OFFSET 4
#define MVEBU_AXI_ATTR_ARCACHE_MASK (0xF << \
MVEBU_AXI_ATTR_ARCACHE_OFFSET)
#define MVEBU_AXI_ATTR_ARDOMAIN_OFFSET 12
#define MVEBU_AXI_ATTR_ARDOMAIN_MASK (0x3 << \
MVEBU_AXI_ATTR_ARDOMAIN_OFFSET)
#define MVEBU_AXI_ATTR_AWCACHE_OFFSET 20
#define MVEBU_AXI_ATTR_AWCACHE_MASK (0xF << \
MVEBU_AXI_ATTR_AWCACHE_OFFSET)
#define MVEBU_AXI_ATTR_AWDOMAIN_OFFSET 28
#define MVEBU_AXI_ATTR_AWDOMAIN_MASK (0x3 << \
MVEBU_AXI_ATTR_AWDOMAIN_OFFSET)
/* SATA MBUS to AXI configuration */
#define MVEBU_SATA_M2A_AXI_ARCACHE_OFFSET 1
#define MVEBU_SATA_M2A_AXI_ARCACHE_MASK (0xF << \
MVEBU_SATA_M2A_AXI_ARCACHE_OFFSET)
#define MVEBU_SATA_M2A_AXI_AWCACHE_OFFSET 5
#define MVEBU_SATA_M2A_AXI_AWCACHE_MASK (0xF << \
MVEBU_SATA_M2A_AXI_AWCACHE_OFFSET)
/* ARM cache attributes */
#define CACHE_ATTR_BUFFERABLE 0x1
#define CACHE_ATTR_CACHEABLE 0x2
#define CACHE_ATTR_READ_ALLOC 0x4
#define CACHE_ATTR_WRITE_ALLOC 0x8
/* Domain */
#define DOMAIN_NON_SHAREABLE 0x0
#define DOMAIN_INNER_SHAREABLE 0x1
#define DOMAIN_OUTER_SHAREABLE 0x2
#define DOMAIN_SYSTEM_SHAREABLE 0x3
/************************************************************************
* Required platform porting definitions common to all
* Management Compute SubSystems (MSS)
************************************************************************
*/
/*
* Load address of SCP_BL2
* SCP_BL2 is loaded to the same place as BL31.
* Once SCP_BL2 is transferred to the SCP,
* it is discarded and BL31 is loaded over the top.
*/
#ifdef SCP_IMAGE
#define SCP_BL2_BASE BL31_BASE
#define SCP_BL2_SIZE BL31_LIMIT
#endif
#ifndef __ASSEMBLER__
enum ap806_sar_target_dev {
SAR_PIDI_MCIX2 = 0x0,
SAR_MCIX4 = 0x1,
SAR_SPI = 0x2,
SAR_SD = 0x3,
SAR_PIDI_MCIX2_BD = 0x4, /* BootRom disabled */
SAR_MCIX4_DB = 0x5, /* BootRom disabled */
SAR_SPI_DB = 0x6, /* BootRom disabled */
SAR_EMMC = 0x7
};
enum io_win_target_ids {
MCI_0_TID = 0x0,
MCI_1_TID = 0x1,
MCI_2_TID = 0x2,
PIDI_TID = 0x3,
SPI_TID = 0x4,
STM_TID = 0x5,
BOOTROM_TID = 0x6,
IO_WIN_MAX_TID
};
enum ccu_target_ids {
IO_0_TID = 0x00,
DRAM_0_TID = 0x03,
IO_1_TID = 0x0F,
CFG_REG_TID = 0x10,
RAR_TID = 0x20,
SRAM_TID = 0x40,
DRAM_1_TID = 0xC0,
CCU_MAX_TID,
INVALID_TID = 0xFF
};
#endif /* __ASSEMBLER__ */
#endif /* A8K_PLAT_DEF_H */
@@ -0,0 +1,9 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#define DRAM_MAX_IFACE 1
#define DRAM_CH0_MMAP_LOW_OFFSET 0x20200
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
/* This driver provides I2C support for Marvell A8K and compatible SoCs */
#ifndef MENTOR_I2C_PLAT_H
#define MENTOR_I2C_PLAT_H
#define CONFIG_SYS_TCLK 250000000
#define CONFIG_SYS_I2C_SPEED 100000
#define CONFIG_SYS_I2C_SLAVE 0x0
#define I2C_CAN_UNSTUCK
struct mentor_i2c_regs {
uint32_t slave_address;
uint32_t data;
uint32_t control;
union {
uint32_t status; /* when reading */
uint32_t baudrate; /* when writing */
};
uint32_t xtnd_slave_addr;
uint32_t reserved[2];
uint32_t soft_reset;
uint8_t reserved2[0xa0 - 0x20];
uint32_t unstuck;
};
#endif /* MENTOR_I2C_PLAT_H */
@@ -0,0 +1,20 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef PLAT_MACROS_S
#define PLAT_MACROS_S
#include <marvell_macros.S>
/*
* Required platform porting macros
* (Provided by included headers)
*/
.macro plat_crash_print_regs
.endm
#endif /* PLAT_MACROS_S */
@@ -0,0 +1,196 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef PLATFORM_DEF_H
#define PLATFORM_DEF_H
#ifndef __ASSEMBLER__
#include <stdio.h>
#endif /* __ASSEMBLER__ */
#include <common/interrupt_props.h>
#include <drivers/arm/gic_common.h>
#include <board_marvell_def.h>
#include <mvebu_def.h>
/*
* Most platform porting definitions provided by included headers
*/
/*
* DRAM Memory layout:
* +-----------------------+
* : :
* : Linux :
* 0x04X00000-->+-----------------------+
* | BL3-3(u-boot) |>>}>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
* |-----------------------| } |
* | BL3-[0,1, 2] | }---------------------------------> |
* |-----------------------| } || |
* | BL2 | }->FIP (loaded by || |
* |-----------------------| } BootROM to DRAM) || |
* | FIP_TOC | } || |
* 0x04120000-->|-----------------------| || |
* | BL1 (RO) | || |
* 0x04100000-->+-----------------------+ || |
* : : || |
* : Trusted SRAM section : \/ |
* 0x04040000-->+-----------------------+ Replaced by BL2 +----------------+ |
* | BL1 (RW) | <<<<<<<<<<<<<<<< | BL3-1 NOBITS | |
* 0x04037000-->|-----------------------| <<<<<<<<<<<<<<<< |----------------| |
* | | <<<<<<<<<<<<<<<< | BL3-1 PROGBITS | |
* 0x04023000-->|-----------------------| +----------------+ |
* | BL2 | |
* |-----------------------| |
* | | |
* 0x04001000-->|-----------------------| |
* | Shared | |
* 0x04000000-->+-----------------------+ |
* : : |
* : Linux : |
* : : |
* |-----------------------| |
* | | U-Boot(BL3-3) Loaded by BL2 |
* | U-Boot | <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
* 0x00000000-->+-----------------------+
*
* Trusted SRAM section 0x4000000..0x4200000:
* ----------------------------------------
* SRAM_BASE = 0x4001000
* BL2_BASE = 0x4006000
* BL2_LIMIT = BL31_BASE
* BL31_BASE = 0x4023000 = (64MB + 256KB - 0x1D000)
* BL31_PROGBITS_LIMIT = BL1_RW_BASE
* BL1_RW_BASE = 0x4037000 = (64MB + 256KB - 0x9000)
* BL1_RW_LIMIT = BL31_LIMIT = 0x4040000
*
*
* PLAT_MARVELL_FIP_BASE = 0x4120000
*/
#define PLAT_MARVELL_SRAM_BASE 0xFFE1C048
#define PLAT_MARVELL_SRAM_END 0xFFE78000
#define PLAT_MARVELL_ATF_BASE 0x4000000
#define PLAT_MARVELL_ATF_LOAD_ADDR (PLAT_MARVELL_ATF_BASE + \
0x100000)
#define PLAT_MARVELL_FIP_BASE (PLAT_MARVELL_ATF_LOAD_ADDR + \
0x20000)
#define PLAT_MARVELL_FIP_MAX_SIZE 0x4000000
#define PLAT_MARVELL_NORTHB_COUNT 1
#define PLAT_MARVELL_CLUSTER_COUNT U(2)
#define PLAT_MARVELL_CLUSTER_CORE_COUNT U(2)
#define PLAT_MARVELL_CORE_COUNT (PLAT_MARVELL_CLUSTER_COUNT * \
PLAT_MARVELL_CLUSTER_CORE_COUNT)
#define PLAT_MAX_CPUS_PER_CLUSTER PLAT_MARVELL_CLUSTER_CORE_COUNT
/* Part of DRAM that is used as Trusted ROM */
#define PLAT_MARVELL_TRUSTED_ROM_BASE PLAT_MARVELL_ATF_LOAD_ADDR
/* 4 MB for FIP image */
#define PLAT_MARVELL_TRUSTED_ROM_SIZE 0x00400000
/* Reserve 12MB for SCP (Secure PayLoad) Trusted RAM
* OP-TEE 4MB SHMEM follows this region
*/
#define PLAT_MARVELL_TRUSTED_RAM_BASE 0x04400000
#define PLAT_MARVELL_TRUSTED_RAM_SIZE 0x00C00000 /* 12 MB DRAM */
#define PLAT_MARVELL_LLC_SRAM_BASE 0x05400000
#define PLAT_MARVELL_LLC_SRAM_SIZE 0x00100000 /* 1 MB SRAM */
/*
* PLAT_ARM_MAX_BL1_RW_SIZE is calculated using the current BL1 RW debug size
* plus a little space for growth.
*/
#define PLAT_MARVELL_MAX_BL1_RW_SIZE 0xA000
/*
* PLAT_ARM_MAX_BL2_SIZE is calculated using the current BL2 debug size plus a
* little space for growth.
*/
#define PLAT_MARVELL_MAX_BL2_SIZE 0xF000
/*
* PLAT_ARM_MAX_BL31_SIZE is calculated using the current BL31 debug size plus a
* little space for growth.
*/
#define PLAT_MARVEL_MAX_BL31_SIZE 0x5D000
#define PLAT_MARVELL_CPU_ENTRY_ADDR BL1_RO_BASE
/* GIC related definitions */
#define PLAT_MARVELL_GICD_BASE (MVEBU_REGS_BASE + MVEBU_GICD_BASE)
#define PLAT_MARVELL_GICC_BASE (MVEBU_REGS_BASE + MVEBU_GICC_BASE)
#define PLAT_MARVELL_G0_IRQ_PROPS(grp) \
INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_LEVEL), \
INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_LEVEL), \
INTR_PROP_DESC(MARVELL_IRQ_PIC0, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_LEVEL)
#define PLAT_MARVELL_G1S_IRQ_PROPS(grp) \
INTR_PROP_DESC(MARVELL_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, \
grp, GIC_INTR_CFG_LEVEL), \
INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_LEVEL), \
INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_LEVEL), \
INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_LEVEL), \
INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_LEVEL), \
INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_LEVEL), \
INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_LEVEL)
#define PLAT_MARVELL_SHARED_RAM_CACHED 1
/*
* Load address of BL3-3 for this platform port
*/
#define PLAT_MARVELL_NS_IMAGE_OFFSET 0x0
/* System Reference Clock*/
#define PLAT_REF_CLK_IN_HZ COUNTER_FREQUENCY
/*
* PL011 related constants
*/
#define PLAT_MARVELL_UART_BASE (MVEBU_REGS_BASE + 0x512000)
#define PLAT_MARVELL_UART_CLK_IN_HZ 200000000
/* Recovery image enable */
#define PLAT_RECOVERY_IMAGE_ENABLE 0
/* Required platform porting definitions */
#define PLAT_MAX_PWR_LVL MPIDR_AFFLVL1
/* System timer related constants */
#define PLAT_MARVELL_NSTIMER_FRAME_ID 1
/* Mailbox base address (note the lower memory space
* is reserved for BLE data)
*/
#define PLAT_MARVELL_MAILBOX_BASE (MARVELL_SHARED_RAM_BASE \
+ 0x400)
#define PLAT_MARVELL_MAILBOX_SIZE 0x100
#define PLAT_MARVELL_MAILBOX_MAGIC_NUM 0x6D72766C /* mrvl */
/* Securities */
#define IRQ_SEC_OS_TICK_INT MARVELL_IRQ_SEC_PHY_TIMER
#define MVEBU_PMU_IRQ_WA
#endif /* PLATFORM_DEF_H */
@@ -0,0 +1,22 @@
#
# Copyright (C) 2018 Marvell International Ltd.
#
# SPDX-License-Identifier: BSD-3-Clause
# https://spdx.org/licenses
#
PLAT_MARVELL := plat/marvell/armada
A8K_MSS_SOURCE := $(PLAT_MARVELL)/a8k/common/mss
BL2_SOURCES += $(A8K_MSS_SOURCE)/mss_bl2_setup.c \
$(MARVELL_MOCHI_DRV)
BL31_SOURCES += $(A8K_MSS_SOURCE)/mss_pm_ipc.c \
$(A8K_MSS_SOURCE)/mss_bl31_setup.c
PLAT_INCLUDES += -I$(A8K_MSS_SOURCE)
ifneq (${SCP_BL2},)
# This define is used to inidcate the SCP image is present
$(eval $(call add_define,SCP_IMAGE))
endif
@@ -0,0 +1,165 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <platform_def.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <drivers/marvell/ccu.h>
#include <drivers/marvell/mochi/ap_setup.h>
#include <drivers/marvell/mochi/cp110_setup.h>
#include <lib/mmio.h>
#include <armada_common.h>
#include <marvell_plat_priv.h> /* timer functionality */
#include "mss_defs.h"
#include "mss_scp_bootloader.h"
/* MSS windows configuration */
#define MSS_AEBR(base) (base + 0x160)
#define MSS_AIBR(base) (base + 0x164)
#define MSS_AEBR_MASK 0xFFF
#define MSS_AIBR_MASK 0xFFF
#define MSS_EXTERNAL_SPACE 0x50000000
#define MSS_EXTERNAL_ACCESS_BIT 28
#define MSS_EXTERNAL_ADDR_MASK 0xfffffff
#define MSS_INTERNAL_ACCESS_BIT 28
struct addr_map_win ccu_mem_map[] = {
{MVEBU_CP_REGS_BASE(0), 0x4000000, IO_0_TID}
};
/* Since the scp_bl2 image can contain firmware for cp1 and cp0 coprocessors,
* the access to cp0 and cp1 need to be provided. More precisely it is
* required to:
* - get the information about device id which is stored in CP0 registers
* (to distinguish between cases where we have cp0 and cp1 or standalone cp0)
* - get the access to cp which is needed for loading fw for cp0/cp1
* coprocessors
* This function configures ccu windows accordingly.
*
* Note: there is no need to restore previous ccu configuration, since in next
* phase (BL31) the init_ccu will be called (via apn806_init/
* bl31_plat_arch_setu) and therefore the ccu configuration will be overwritten.
*/
static int bl2_plat_mmap_init(void)
{
int cfg_num, win_id, cfg_idx, cp;
cfg_num = ARRAY_SIZE(ccu_mem_map);
/* CCU window-0 should not be counted - it's already used */
if (cfg_num > (MVEBU_CCU_MAX_WINS - 1)) {
ERROR("BL2: %s: trying to open too many windows\n", __func__);
return -1;
}
/* Enable required CCU windows
* Do not touch CCU window 0,
* it's used for the internal registers access
*/
for (cfg_idx = 0, win_id = 1;
(win_id < MVEBU_CCU_MAX_WINS) && (cfg_idx < cfg_num); win_id++) {
/* Skip already enabled CCU windows */
if (ccu_is_win_enabled(MVEBU_AP0, win_id))
continue;
/* Enable required CCU windows */
ccu_win_check(&ccu_mem_map[cfg_idx]);
ccu_enable_win(MVEBU_AP0, &ccu_mem_map[cfg_idx], win_id);
cfg_idx++;
}
/* Config address for each cp other than cp0 */
for (cp = 1; cp < CP_COUNT; cp++)
update_cp110_default_win(cp);
/* There is need to configure IO_WIN windows again to overwrite
* temporary configuration done during update_cp110_default_win
*/
init_io_win(MVEBU_AP0);
/* Open AMB bridge required for MG access */
for (cp = 0; cp < CP_COUNT; cp++)
cp110_amb_init(MVEBU_CP_REGS_BASE(cp));
return 0;
}
/*****************************************************************************
* Transfer SCP_BL2 from Trusted RAM using the SCP Download protocol.
* Return 0 on success, -1 otherwise.
*****************************************************************************
*/
int bl2_plat_handle_scp_bl2(image_info_t *scp_bl2_image_info)
{
int ret;
INFO("BL2: Initiating SCP_BL2 transfer to SCP\n");
/* initialize time (for delay functionality) */
plat_delay_timer_init();
ret = bl2_plat_mmap_init();
if (ret != 0)
return ret;
ret = scp_bootloader_transfer((void *)scp_bl2_image_info->image_base,
scp_bl2_image_info->image_size);
if (ret == 0)
INFO("BL2: SCP_BL2 transferred to SCP\n");
else
ERROR("BL2: SCP_BL2 transfer failure\n");
return ret;
}
uintptr_t bl2_plat_get_cp_mss_regs(int ap_idx, int cp_idx)
{
return MVEBU_CP_REGS_BASE(cp_idx) + MSS_CP_REGS_OFFSET;
}
uintptr_t bl2_plat_get_cp_mss_sram(int ap_idx, int cp_idx)
{
return MVEBU_CP_REGS_BASE(cp_idx) + MSS_CP_SRAM_OFFSET;
}
uintptr_t bl2_plat_get_ap_mss_regs(int ap_idx)
{
return MVEBU_REGS_BASE + MSS_AP_REGS_OFFSET;
}
uint32_t bl2_plat_get_cp_count(int ap_idx)
{
uint32_t revision = cp110_device_id_get(MVEBU_CP_REGS_BASE(0));
/* A8040: two CPs.
* A7040: one CP.
*/
if (revision == MVEBU_80X0_DEV_ID ||
revision == MVEBU_80X0_CP115_DEV_ID)
return 2;
else if (revision == MVEBU_CN9130_DEV_ID)
return CP_COUNT;
else
return 1;
}
uint32_t bl2_plat_get_ap_count(void)
{
/* A8040 and A7040 have only one AP */
return 1;
}
void bl2_plat_configure_mss_windows(uintptr_t mss_regs)
{
/* set AXI External and Internal Address Bus extension */
mmio_write_32(MSS_AEBR(mss_regs),
((0x0 >> MSS_EXTERNAL_ACCESS_BIT) & MSS_AEBR_MASK));
mmio_write_32(MSS_AIBR(mss_regs),
((mss_regs >> MSS_INTERNAL_ACCESS_BIT) & MSS_AIBR_MASK));
}
@@ -0,0 +1,37 @@
/*
* Copyright (C) 2021 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <platform_def.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <armada_common.h>
#include "mss_defs.h"
void mss_start_cp_cm3(int cp)
{
uint32_t magic;
uintptr_t sram = MVEBU_CP_REGS_BASE(cp) + MSS_CP_SRAM_OFFSET;
uintptr_t regs = MVEBU_CP_REGS_BASE(cp) + MSS_CP_REGS_OFFSET;
magic = mmio_read_32(sram);
/* Make sure the FW was loaded */
if (magic != MSS_FW_READY_MAGIC) {
return;
}
NOTICE("Starting CP%d MSS CPU\n", cp);
/* remove the magic */
mmio_write_32(sram, 0);
/* Release M3 from reset */
mmio_write_32(MSS_M3_RSTCR(regs),
(MSS_M3_RSTCR_RST_OFF << MSS_M3_RSTCR_RST_OFFSET));
}
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2021 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef MSS_DEFS_H
#define MSS_DEFS_H
#define MSS_DMA_SRCBR(base) (base + 0xC0)
#define MSS_DMA_DSTBR(base) (base + 0xC4)
#define MSS_DMA_CTRLR(base) (base + 0xC8)
#define MSS_M3_RSTCR(base) (base + 0xFC)
#define MSS_DMA_CTRLR_SIZE_OFFSET (0)
#define MSS_DMA_CTRLR_REQ_OFFSET (15)
#define MSS_DMA_CTRLR_REQ_SET (1)
#define MSS_DMA_CTRLR_ACK_OFFSET (12)
#define MSS_DMA_CTRLR_ACK_MASK (0x1)
#define MSS_DMA_CTRLR_ACK_READY (1)
#define MSS_M3_RSTCR_RST_OFFSET (0)
#define MSS_M3_RSTCR_RST_OFF (1)
#define MSS_FW_READY_MAGIC 0x46575144 /* FWRD */
#define MSS_AP_REGS_OFFSET 0x00580000
#define MSS_CP_SRAM_OFFSET 0x00220000
#define MSS_CP_REGS_OFFSET 0x00280000
void mss_start_cp_cm3(int cp);
#endif /* MSS_DEFS_H */
@@ -0,0 +1,85 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <string.h>
#include <common/debug.h>
#include <lib/psci/psci.h>
#include <lib/mmio.h>
#include <mss_pm_ipc.h>
/*
* SISR is 32 bit interrupt register representing 32 interrupts
*
* +======+=============+=============+
* + Bits + 31 + 30 - 00 +
* +======+=============+=============+
* + Desc + MSS Msg Int + Reserved +
* +======+=============+=============+
*/
#define MSS_SISR (MVEBU_REGS_BASE + 0x5800D0)
#define MSS_SISTR (MVEBU_REGS_BASE + 0x5800D8)
#define MSS_MSG_INT_MASK (0x80000000)
#define MSS_TIMER_BASE (MVEBU_REGS_BASE_MASK + 0x580110)
#define MSS_TRIGGER_TIMEOUT (2000)
/*****************************************************************************
* mss_pm_ipc_msg_send
*
* DESCRIPTION: create and transmit IPC message
*****************************************************************************
*/
int mss_pm_ipc_msg_send(unsigned int channel_id, unsigned int msg_id,
const psci_power_state_t *target_state)
{
/* Transmit IPC message */
#ifndef DISABLE_CLUSTER_LEVEL
mv_pm_ipc_msg_tx(channel_id, msg_id,
(unsigned int)target_state->pwr_domain_state[
MPIDR_AFFLVL1]);
#else
mv_pm_ipc_msg_tx(channel_id, msg_id, 0);
#endif
return 0;
}
/*****************************************************************************
* mss_pm_ipc_msg_trigger
*
* DESCRIPTION: Trigger IPC message interrupt to MSS
*****************************************************************************
*/
int mss_pm_ipc_msg_trigger(void)
{
unsigned int timeout;
unsigned int t_end;
unsigned int t_start = mmio_read_32(MSS_TIMER_BASE);
mmio_write_32(MSS_SISR, MSS_MSG_INT_MASK);
do {
/* wait while SCP process incoming interrupt */
if (mmio_read_32(MSS_SISTR) != MSS_MSG_INT_MASK)
break;
/* check timeout */
t_end = mmio_read_32(MSS_TIMER_BASE);
timeout = ((t_start > t_end) ?
(t_start - t_end) : (t_end - t_start));
if (timeout > MSS_TRIGGER_TIMEOUT) {
ERROR("PM MSG Trigger Timeout\n");
break;
}
} while (1);
return 0;
}
@@ -0,0 +1,35 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef MSS_PM_IPC_H
#define MSS_PM_IPC_H
#include <mss_ipc_drv.h>
/* Currently MSS does not support Cluster level Power Down */
#define DISABLE_CLUSTER_LEVEL
/*****************************************************************************
* mss_pm_ipc_msg_send
*
* DESCRIPTION: create and transmit IPC message
*****************************************************************************
*/
int mss_pm_ipc_msg_send(unsigned int channel_id, unsigned int msg_id,
const psci_power_state_t *target_state);
/*****************************************************************************
* mss_pm_ipc_msg_trigger
*
* DESCRIPTION: Trigger IPC message interrupt to MSS
*****************************************************************************
*/
int mss_pm_ipc_msg_trigger(void);
#endif /* MSS_PM_IPC_H */
@@ -0,0 +1,19 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <lib/mmio.h>
#include <plat_marvell.h>
void marvell_bl1_setup_mpps(void)
{
/* Enable UART MPPs.
** In a normal system, this is done by Bootrom.
*/
mmio_write_32(MVEBU_AP_MPP_REGS(1), 0x3000);
mmio_write_32(MVEBU_AP_MPP_REGS(2), 0x3000);
}
@@ -0,0 +1,148 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <common/debug.h>
#include <drivers/marvell/mci.h>
#include <drivers/marvell/mochi/ap_setup.h>
#include <drivers/marvell/mochi/cp110_setup.h>
#include <lib/mmio.h>
#include <armada_common.h>
#include <marvell_plat_priv.h>
#include <marvell_pm.h>
#include <mc_trustzone/mc_trustzone.h>
#include <plat_marvell.h>
#if MSS_SUPPORT
#include <mss_ipc_drv.h>
#include <mss_mem.h>
#include <mss_defs.h>
#endif
/* In Armada-8k family AP806/AP807, CP0 connected to PIDI
* and CP1 connected to IHB via MCI #0
*/
#define MVEBU_MCI0 0
static _Bool pm_fw_running;
/* Set a weak stub for platforms that don't need to configure GPIO */
#pragma weak marvell_gpio_config
int marvell_gpio_config(void)
{
return 0;
}
static void marvell_bl31_mpp_init(int cp)
{
uint32_t reg;
/* need to do for CP#0 only */
if (cp)
return;
/*
* Enable CP0 I2C MPPs (MPP: 37-38)
* U-Boot rely on proper MPP settings for I2C EEPROM usage
* (only for CP0)
*/
reg = mmio_read_32(MVEBU_CP_MPP_REGS(0, 4));
mmio_write_32(MVEBU_CP_MPP_REGS(0, 4), reg | 0x2200000);
}
#if MSS_SUPPORT
void marvell_bl31_mss_init(void)
{
struct mss_pm_ctrl_block *mss_pm_crtl =
(struct mss_pm_ctrl_block *)MSS_SRAM_PM_CONTROL_BASE;
/* Check that the image was loaded successfully */
if (mss_pm_crtl->handshake != HOST_ACKNOWLEDGMENT) {
NOTICE("MSS PM is not supported in this build\n");
return;
}
/* If we got here it means that the PM firmware is running */
pm_fw_running = 1;
INFO("MSS IPC init\n");
if (mss_pm_crtl->ipc_state == IPC_INITIALIZED)
mv_pm_ipc_init(mss_pm_crtl->ipc_base_address | MVEBU_REGS_BASE);
}
#endif
_Bool is_pm_fw_running(void)
{
return pm_fw_running;
}
/* For TrusTzone we treat the "target" field of addr_map_win
* struct as attribute
*/
static const struct addr_map_win tz_map[] = {
{PLAT_MARVELL_ATF_BASE, 0x200000, TZ_PERM_ABORT}
};
/* Configure MC TrustZone regions */
static void marvell_bl31_security_setup(void)
{
int tz_nr, win_id;
tz_nr = ARRAY_SIZE(tz_map);
for (win_id = 0; win_id < tz_nr; win_id++)
tz_enable_win(MVEBU_AP0, tz_map, win_id);
}
/* This function overruns the same function in marvell_bl31_setup.c */
void bl31_plat_arch_setup(void)
{
int cp;
uintptr_t *mailbox = (void *)PLAT_MARVELL_MAILBOX_BASE;
/* initialize the timer for mdelay/udelay functionality */
plat_delay_timer_init();
/* configure apn806 */
ap_init();
/* In marvell_bl31_plat_arch_setup, el3 mmu is configured.
* el3 mmu configuration MUST be called after apn806_init, if not,
* this will cause an hang in init_io_win
* (after setting the IO windows GCR values).
*/
if (mailbox[MBOX_IDX_MAGIC] != MVEBU_MAILBOX_MAGIC_NUM ||
mailbox[MBOX_IDX_SUSPEND_MAGIC] != MVEBU_MAILBOX_SUSPEND_STATE)
marvell_bl31_plat_arch_setup();
for (cp = 0; cp < CP_COUNT; cp++) {
cp110_init(MVEBU_CP_REGS_BASE(cp),
STREAM_ID_BASE + (cp * MAX_STREAM_ID_PER_CP));
marvell_bl31_mpp_init(cp);
#if MSS_SUPPORT
/* Release CP MSS CPU from reset once the CP init is done */
mss_start_cp_cm3(cp);
#endif
}
for (cp = 1; cp < CP_COUNT; cp++)
mci_link_tune(cp - 1);
#if MSS_SUPPORT
/* initialize IPC between MSS and ATF */
if (mailbox[MBOX_IDX_MAGIC] != MVEBU_MAILBOX_MAGIC_NUM ||
mailbox[MBOX_IDX_SUSPEND_MAGIC] != MVEBU_MAILBOX_SUSPEND_STATE)
marvell_bl31_mss_init();
#endif
/* Configure GPIO */
marvell_gpio_config();
marvell_bl31_security_setup();
}
@@ -0,0 +1,765 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <common/debug.h>
#include <drivers/marvell/ap807_clocks_init.h>
#include <drivers/marvell/aro.h>
#include <drivers/marvell/ccu.h>
#include <drivers/marvell/io_win.h>
#include <drivers/marvell/mochi/ap_setup.h>
#include <drivers/marvell/mochi/cp110_setup.h>
#include <armada_common.h>
#include <efuse_def.h>
#include <mv_ddr_if.h>
#include <mvebu_def.h>
#include <plat_marvell.h>
/* Register for skip image use */
#define SCRATCH_PAD_REG2 0xF06F00A8
#define SCRATCH_PAD_SKIP_VAL 0x01
#define NUM_OF_GPIO_PER_REG 32
#define MMAP_SAVE_AND_CONFIG 0
#define MMAP_RESTORE_SAVED 1
/* SAR clock settings */
#define MVEBU_AP_SAR_REG_BASE(r) (MVEBU_AP_GEN_MGMT_BASE + 0x200 +\
((r) << 2))
#define SAR_CLOCK_FREQ_MODE_OFFSET (0)
#define SAR_CLOCK_FREQ_MODE_MASK (0x1f << SAR_CLOCK_FREQ_MODE_OFFSET)
#define SAR_PIDI_LOW_SPEED_OFFSET (20)
#define SAR_PIDI_LOW_SPEED_MASK (1 << SAR_PIDI_LOW_SPEED_OFFSET)
#define SAR_PIDI_LOW_SPEED_SHIFT (15)
#define SAR_PIDI_LOW_SPEED_SET (1 << SAR_PIDI_LOW_SPEED_SHIFT)
#define FREQ_MODE_AP_SAR_REG_NUM (0)
#define SAR_CLOCK_FREQ_MODE(v) (((v) & SAR_CLOCK_FREQ_MODE_MASK) >> \
SAR_CLOCK_FREQ_MODE_OFFSET)
#define AVS_I2C_EEPROM_ADDR 0x57 /* EEPROM */
#define AVS_EN_CTRL_REG (MVEBU_AP_GEN_MGMT_BASE + 0x130)
#define AVS_ENABLE_OFFSET (0)
#define AVS_SOFT_RESET_OFFSET (2)
#define AVS_TARGET_DELTA_OFFSET (21)
#ifndef MVEBU_SOC_AP807
/* AP806 SVC bits */
#define AVS_LOW_VDD_LIMIT_OFFSET (4)
#define AVS_HIGH_VDD_LIMIT_OFFSET (12)
#define AVS_VDD_LOW_LIMIT_MASK (0xFF << AVS_LOW_VDD_LIMIT_OFFSET)
#define AVS_VDD_HIGH_LIMIT_MASK (0xFF << AVS_HIGH_VDD_LIMIT_OFFSET)
#else
/* AP807 SVC bits */
#define AVS_LOW_VDD_LIMIT_OFFSET (3)
#define AVS_HIGH_VDD_LIMIT_OFFSET (13)
#define AVS_VDD_LOW_LIMIT_MASK (0x3FF << AVS_LOW_VDD_LIMIT_OFFSET)
#define AVS_VDD_HIGH_LIMIT_MASK (0x3FF << AVS_HIGH_VDD_LIMIT_OFFSET)
#endif
/* VDD limit is 0.9V for A70x0 @ CPU frequency < 1600MHz */
#define AVS_A7K_LOW_CLK_VALUE ((0x80 << AVS_TARGET_DELTA_OFFSET) | \
(0x1A << AVS_HIGH_VDD_LIMIT_OFFSET) | \
(0x1A << AVS_LOW_VDD_LIMIT_OFFSET) | \
(0x1 << AVS_SOFT_RESET_OFFSET) | \
(0x1 << AVS_ENABLE_OFFSET))
/* VDD limit is 1.0V for all A80x0 devices */
#define AVS_A8K_CLK_VALUE ((0x80 << AVS_TARGET_DELTA_OFFSET) | \
(0x24 << AVS_HIGH_VDD_LIMIT_OFFSET) | \
(0x24 << AVS_LOW_VDD_LIMIT_OFFSET) | \
(0x1 << AVS_SOFT_RESET_OFFSET) | \
(0x1 << AVS_ENABLE_OFFSET))
/* VDD is 0.88V for 2GHz clock on CN913x devices */
#define AVS_AP807_CLK_VALUE ((0x80UL << 24) | \
(0x2dc << 13) | \
(0x2dc << 3) | \
(0x1 << AVS_SOFT_RESET_OFFSET) | \
(0x1 << AVS_ENABLE_OFFSET))
/*
* - Identification information in the LD-0 eFuse:
* DRO: LD0[74:65] - Not used by the SW
* Revision: LD0[78:75] - Not used by the SW
* Bin: LD0[80:79] - Not used by the SW
* SW Revision: LD0[115:113]
* Cluster 1 PWR: LD0[193] - if set to 1, power down CPU Cluster-1
* resulting in 2 CPUs active only (7020)
*/
/* Offsets for 2 efuse fields combined into single 64-bit value [125:63] */
#define EFUSE_AP_LD0_DRO_OFFS 2 /* LD0[74:65] */
#define EFUSE_AP_LD0_DRO_MASK 0x3FF
#define EFUSE_AP_LD0_REVID_OFFS 12 /* LD0[78:75] */
#define EFUSE_AP_LD0_REVID_MASK 0xF
#define EFUSE_AP_LD0_BIN_OFFS 16 /* LD0[80:79] */
#define EFUSE_AP_LD0_BIN_MASK 0x3
#define EFUSE_AP_LD0_SWREV_MASK 0x7
#ifndef MVEBU_SOC_AP807
/* AP806 AVS work points in the LD0 eFuse
* SVC1 work point: LD0[88:81]
* SVC2 work point: LD0[96:89]
* SVC3 work point: LD0[104:97]
* SVC4 work point: LD0[112:105]
*/
#define EFUSE_AP_LD0_SVC1_OFFS 18 /* LD0[88:81] */
#define EFUSE_AP_LD0_SVC2_OFFS 26 /* LD0[96:89] */
#define EFUSE_AP_LD0_SVC3_OFFS 34 /* LD0[104:97] */
#define EFUSE_AP_LD0_WP_MASK 0xFF
#define EFUSE_AP_LD0_SWREV_OFFS 50 /* LD0[115:113] */
#else
/* AP807 AVS work points in the LD0 eFuse
* SVC1 work point: LD0[91:81]
* SVC2 work point: LD0[102:92]
* SVC3 work point: LD0[113:103]
*/
#define EFUSE_AP_LD0_SVC1_OFFS 18 /* LD0[91:81] */
#define EFUSE_AP_LD0_SVC2_OFFS 29 /* LD0[102:92] */
#define EFUSE_AP_LD0_SVC3_OFFS 40 /* LD0[113:103] */
#define EFUSE_AP_LD0_WP_MASK 0x7FF /* 10 data,1 parity */
#define EFUSE_AP_LD0_SWREV_OFFS 51 /* LD0[116:114] */
#endif
#define EFUSE_AP_LD0_SVC4_OFFS 42 /* LD0[112:105] */
#define EFUSE_AP_LD0_CLUSTER_DOWN_OFFS 4
#if MARVELL_SVC_TEST
#define MVEBU_CP_MPP_CTRL37_OFFS 20
#define MVEBU_CP_MPP_CTRL38_OFFS 24
#define MVEBU_CP_MPP_I2C_FUNC 2
#define MVEBU_MPP_CTRL_MASK 0xf
#endif
/* Return the AP revision of the chip */
static unsigned int ble_get_ap_type(void)
{
unsigned int chip_rev_id;
chip_rev_id = mmio_read_32(MVEBU_CSS_GWD_CTRL_IIDR2_REG);
chip_rev_id = ((chip_rev_id & GWD_IIDR2_CHIP_ID_MASK) >>
GWD_IIDR2_CHIP_ID_OFFSET);
return chip_rev_id;
}
/******************************************************************************
* The routine allows to save the CCU and IO windows configuration during DRAM
* setup and restore them afterwards before exiting the BLE stage.
* Such window configuration is required since not all default settings coming
* from the HW and the BootROM allow access to peripherals connected to
* all available CPn components.
* For instance, when the boot device is located on CP0, the IO window to CP1
* is not opened automatically by the HW and if the DRAM SPD is located on CP1
* i2c channel, it cannot be read at BLE stage.
* Therefore the DRAM init procedure have to provide access to all available
* CPn peripherals during the BLE stage by setting the CCU IO window to all
* CPnph addresses and by enabling the IO windows accordingly.
* Additionally this function configures the CCU GCR to DRAM, which allows
* usage or more than 4GB DRAM as it configured by the default CCU DRAM window.
*
* IN:
* MMAP_SAVE_AND_CONFIG - save the existing configuration and update it
* MMAP_RESTORE_SAVED - restore saved configuration
* OUT:
* NONE
****************************************************************************
*/
static void ble_plat_mmap_config(int restore)
{
if (restore == MMAP_RESTORE_SAVED) {
/* Restore all orig. settings that were modified by BLE stage */
ccu_restore_win_all(MVEBU_AP0);
/* Restore CCU */
iow_restore_win_all(MVEBU_AP0);
return;
}
/* Store original values */
ccu_save_win_all(MVEBU_AP0);
/* Save CCU */
iow_save_win_all(MVEBU_AP0);
init_ccu(MVEBU_AP0);
/* The configuration saved, now all the changes can be done */
init_io_win(MVEBU_AP0);
}
/****************************************************************************
* Setup Adaptive Voltage Switching - this is required for some platforms
****************************************************************************
*/
#if !MARVELL_SVC_TEST
static void ble_plat_avs_config(void)
{
uint32_t freq_mode, device_id;
uint32_t avs_val = 0;
freq_mode =
SAR_CLOCK_FREQ_MODE(mmio_read_32(MVEBU_AP_SAR_REG_BASE(
FREQ_MODE_AP_SAR_REG_NUM)));
/* Check which SoC is running and act accordingly */
if (ble_get_ap_type() == CHIP_ID_AP807) {
avs_val = AVS_AP807_CLK_VALUE;
} else {
/* Check which SoC is running and act accordingly */
device_id = cp110_device_id_get(MVEBU_CP_REGS_BASE(0));
switch (device_id) {
case MVEBU_80X0_DEV_ID:
case MVEBU_80X0_CP115_DEV_ID:
/* Always fix the default AVS value on A80x0 */
avs_val = AVS_A8K_CLK_VALUE;
break;
case MVEBU_70X0_DEV_ID:
case MVEBU_70X0_CP115_DEV_ID:
/* Fix AVS for CPU clocks lower than 1600MHz on A70x0 */
if ((freq_mode > CPU_1600_DDR_900_RCLK_900_2) &&
(freq_mode < CPU_DDR_RCLK_INVALID))
avs_val = AVS_A7K_LOW_CLK_VALUE;
break;
default:
ERROR("Unsupported Device ID 0x%x\n", device_id);
return;
}
}
if (avs_val) {
VERBOSE("AVS: Setting AVS CTRL to 0x%x\n", avs_val);
mmio_write_32(AVS_EN_CTRL_REG, avs_val);
}
}
#endif
/******************************************************************************
* Update or override current AVS work point value using data stored in EEPROM
* This is only required by QA/validation flows and activated by
* MARVELL_SVC_TEST flag.
*
* The function is expected to be called twice.
*
* First time with AVS value of 0 for testing if the EEPROM requests completely
* override the AVS value and bypass the eFuse test
*
* Second time - with non-zero AVS value obtained from eFuses as an input.
* In this case the EEPROM may contain AVS correction value (either positive
* or negative) that is added to the input AVS value and returned back for
* further processing.
******************************************************************************
*/
static uint32_t avs_update_from_eeprom(uint32_t avs_workpoint)
{
uint32_t new_wp = avs_workpoint;
#if MARVELL_SVC_TEST
/* ---------------------------------------------------------------------
* EEPROM | Data description (avs_step)
* address |
* ---------------------------------------------------------------------
* 0x120 | AVS workpoint correction value
* | if not 0 and not 0xff, correct the AVS taken from eFuse
* | by the number of steps indicated by bit[6:0]
* | bit[7] defines correction direction.
* | If bit[7]=1, add the value from bit[6:0] to AVS workpoint,
* | othervise substruct this value from AVS workpoint.
* ---------------------------------------------------------------------
* 0x121 | AVS workpoint override value
* | Override the AVS workpoint with the value stored in this
* | byte. When running on AP806, the AVS workpoint is 7 bits
* | wide and override value is valid when bit[6:0] holds
* | value greater than zero and smaller than 0x33.
* | When running on AP807, the AVS workpoint is 10 bits wide.
* | Additional 2 MSB bits are supplied by EEPROM byte 0x122.
* | AVS override value is valid when byte @ 0x121 and bit[1:0]
* | of byte @ 0x122 combined have non-zero value.
* ---------------------------------------------------------------------
* 0x122 | Extended AVS workpoint override value
* | Valid only for AP807 platforms and must be less than 0x4
* ---------------------------------------------------------------------
*/
static uint8_t avs_step[3] = {0};
uintptr_t reg;
uint32_t val;
unsigned int ap_type = ble_get_ap_type();
/* Always happens on second call to this function */
if (avs_workpoint != 0) {
/* Get correction steps from the EEPROM */
if ((avs_step[0] != 0) && (avs_step[0] != 0xff)) {
NOTICE("AVS request to step %s by 0x%x from old 0x%x\n",
avs_step[0] & 0x80 ? "DOWN" : "UP",
avs_step[0] & 0x7f, new_wp);
if (avs_step[0] & 0x80)
new_wp -= avs_step[0] & 0x7f;
else
new_wp += avs_step[0] & 0x7f;
}
return new_wp;
}
/* AVS values are located in EEPROM
* at CP0 i2c bus #0, device 0x57 offset 0x120
* The SDA and SCK pins of CP0 i2c-0: MPP[38:37], i2c function 0x2.
*/
reg = MVEBU_CP_MPP_REGS(0, 4);
val = mmio_read_32(reg);
val &= ~((MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL37_OFFS) |
(MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL38_OFFS));
val |= (MVEBU_CP_MPP_I2C_FUNC << MVEBU_CP_MPP_CTRL37_OFFS) |
(MVEBU_CP_MPP_I2C_FUNC << MVEBU_CP_MPP_CTRL38_OFFS);
mmio_write_32(reg, val);
/* Init CP0 i2c-0 */
i2c_init((void *)(MVEBU_CP0_I2C_BASE));
/* Read EEPROM only once at the fist call! */
i2c_read(AVS_I2C_EEPROM_ADDR, 0x120, 2, avs_step, 3);
NOTICE("== SVC test build ==\n");
NOTICE("EEPROM holds values 0x%x, 0x%x and 0x%x\n",
avs_step[0], avs_step[1], avs_step[2]);
/* Override the AVS value? */
if ((ap_type != CHIP_ID_AP807) && (avs_step[1] < 0x33)) {
/* AP806 - AVS is 7 bits */
new_wp = avs_step[1];
} else if (ap_type == CHIP_ID_AP807 && (avs_step[2] < 0x4)) {
/* AP807 - AVS is 10 bits */
new_wp = avs_step[2];
new_wp <<= 8;
new_wp |= avs_step[1];
}
if (new_wp == 0)
NOTICE("Ignore BAD AVS Override value in EEPROM!\n");
else
NOTICE("Override AVS by EEPROM value 0x%x\n", new_wp);
#endif /* MARVELL_SVC_TEST */
return new_wp;
}
/****************************************************************************
* SVC flow - v0.10
* The feature is intended to configure AVS value according to eFuse values
* that are burned individually for each SoC during the test process.
* Primary AVS value is stored in HD efuse and processed on power on
* by the HW engine
* Secondary AVS value is located in LD efuse and contains 4 work points for
* various CPU frequencies.
* The Secondary AVS value is only taken into account if the SW Revision stored
* in the efuse is greater than 0 and the CPU is running in a certain speed.
****************************************************************************
*/
static void ble_plat_svc_config(void)
{
uint32_t reg_val, avs_workpoint, freq_pidi_mode;
uint64_t efuse;
uint32_t device_id, single_cluster;
uint16_t svc[4], perr[4], i, sw_ver;
uint8_t avs_data_bits, min_sw_ver, svc_fields;
unsigned int ap_type;
/* Get test EERPOM data */
avs_workpoint = avs_update_from_eeprom(0);
if (avs_workpoint)
goto set_aws_wp;
/* Set access to LD0 */
reg_val = mmio_read_32(MVEBU_AP_EFUSE_SRV_CTRL_REG);
reg_val &= ~EFUSE_SRV_CTRL_LD_SELECT_MASK;
mmio_write_32(MVEBU_AP_EFUSE_SRV_CTRL_REG, reg_val);
/* Obtain the value of LD0[125:63] */
efuse = mmio_read_32(MVEBU_AP_LDX_125_95_EFUSE_OFFS);
efuse <<= 32;
efuse |= mmio_read_32(MVEBU_AP_LDX_94_63_EFUSE_OFFS);
/* SW Revision:
* Starting from SW revision 1 the SVC flow is supported.
* SW version 0 (efuse not programmed) should follow the
* regular AVS update flow.
*/
sw_ver = (efuse >> EFUSE_AP_LD0_SWREV_OFFS) & EFUSE_AP_LD0_SWREV_MASK;
if (sw_ver < 1) {
NOTICE("SVC: SW Revision 0x%x. SVC is not supported\n", sw_ver);
#if MARVELL_SVC_TEST
NOTICE("SVC_TEST: AVS bypassed\n");
#else
ble_plat_avs_config();
#endif
return;
}
/* Frequency mode from SAR */
freq_pidi_mode = SAR_CLOCK_FREQ_MODE(
mmio_read_32(
MVEBU_AP_SAR_REG_BASE(
FREQ_MODE_AP_SAR_REG_NUM)));
/* Decode all SVC work points */
svc[0] = (efuse >> EFUSE_AP_LD0_SVC1_OFFS) & EFUSE_AP_LD0_WP_MASK;
svc[1] = (efuse >> EFUSE_AP_LD0_SVC2_OFFS) & EFUSE_AP_LD0_WP_MASK;
svc[2] = (efuse >> EFUSE_AP_LD0_SVC3_OFFS) & EFUSE_AP_LD0_WP_MASK;
/* Fetch AP type to distinguish between AP806 and AP807 */
ap_type = ble_get_ap_type();
if (ap_type != CHIP_ID_AP807) {
svc[3] = (efuse >> EFUSE_AP_LD0_SVC4_OFFS)
& EFUSE_AP_LD0_WP_MASK;
INFO("SVC: Efuse WP: [0]=0x%x, [1]=0x%x, [2]=0x%x, [3]=0x%x\n",
svc[0], svc[1], svc[2], svc[3]);
avs_data_bits = 7;
min_sw_ver = 2; /* parity check from sw revision 2 */
svc_fields = 4;
} else {
INFO("SVC: Efuse WP: [0]=0x%x, [1]=0x%x, [2]=0x%x\n",
svc[0], svc[1], svc[2]);
avs_data_bits = 10;
min_sw_ver = 1; /* parity check required from sw revision 1 */
svc_fields = 3;
}
/* Validate parity of SVC workpoint values */
for (i = 0; i < svc_fields; i++) {
uint8_t parity, bit;
perr[i] = 0;
for (bit = 1, parity = (svc[i] & 1); bit < avs_data_bits; bit++)
parity ^= (svc[i] >> bit) & 1;
/* From SW version 1 or 2 (AP806/AP807), check parity */
if ((sw_ver >= min_sw_ver) &&
(parity != ((svc[i] >> avs_data_bits) & 1)))
perr[i] = 1; /* register the error */
}
single_cluster = mmio_read_32(MVEBU_AP_LDX_220_189_EFUSE_OFFS);
single_cluster = (single_cluster >> EFUSE_AP_LD0_CLUSTER_DOWN_OFFS) & 1;
device_id = cp110_device_id_get(MVEBU_CP_REGS_BASE(0));
if (device_id == MVEBU_80X0_DEV_ID ||
device_id == MVEBU_80X0_CP115_DEV_ID) {
/* A8040/A8020 */
NOTICE("SVC: DEV ID: %s, FREQ Mode: 0x%x\n",
single_cluster == 0 ? "8040" : "8020", freq_pidi_mode);
switch (freq_pidi_mode) {
case CPU_1800_DDR_1050_RCLK_1050:
if (perr[1])
goto perror;
avs_workpoint = svc[1];
break;
case CPU_1600_DDR_1050_RCLK_1050:
case CPU_1600_DDR_900_RCLK_900_2:
if (perr[2])
goto perror;
avs_workpoint = svc[2];
break;
case CPU_1300_DDR_800_RCLK_800:
case CPU_1300_DDR_650_RCLK_650:
if (perr[3])
goto perror;
avs_workpoint = svc[3];
break;
case CPU_2000_DDR_1200_RCLK_1200:
case CPU_2000_DDR_1050_RCLK_1050:
default:
if (perr[0])
goto perror;
avs_workpoint = svc[0];
break;
}
} else if (device_id == MVEBU_70X0_DEV_ID ||
device_id == MVEBU_70X0_CP115_DEV_ID) {
/* A7040/A7020/A6040 */
NOTICE("SVC: DEV ID: %s, FREQ Mode: 0x%x\n",
single_cluster == 0 ? "7040" : "7020", freq_pidi_mode);
switch (freq_pidi_mode) {
case CPU_1400_DDR_800_RCLK_800:
if (single_cluster) {/* 7020 */
if (perr[1])
goto perror;
avs_workpoint = svc[1];
} else {
if (perr[0])
goto perror;
avs_workpoint = svc[0];
}
break;
case CPU_1200_DDR_800_RCLK_800:
if (single_cluster) {/* 7020 */
if (perr[2])
goto perror;
avs_workpoint = svc[2];
} else {
if (perr[1])
goto perror;
avs_workpoint = svc[1];
}
break;
case CPU_800_DDR_800_RCLK_800:
case CPU_1000_DDR_800_RCLK_800:
if (single_cluster) {/* 7020 */
if (perr[3])
goto perror;
avs_workpoint = svc[3];
} else {
if (perr[2])
goto perror;
avs_workpoint = svc[2];
}
break;
case CPU_600_DDR_800_RCLK_800:
if (perr[3])
goto perror;
avs_workpoint = svc[3]; /* Same for 6040 and 7020 */
break;
case CPU_1600_DDR_800_RCLK_800: /* 7020 only */
default:
if (single_cluster) {/* 7020 */
if (perr[0])
goto perror;
avs_workpoint = svc[0];
} else {
#if MARVELL_SVC_TEST
reg_val = mmio_read_32(AVS_EN_CTRL_REG);
avs_workpoint = (reg_val &
AVS_VDD_LOW_LIMIT_MASK) >>
AVS_LOW_VDD_LIMIT_OFFSET;
NOTICE("7040 1600Mhz, avs = 0x%x\n",
avs_workpoint);
#else
NOTICE("SVC: AVS work point not changed\n");
return;
#endif
}
break;
}
} else if (device_id == MVEBU_3900_DEV_ID) {
NOTICE("SVC: DEV ID: %s, FREQ Mode: 0x%x\n",
"3900", freq_pidi_mode);
switch (freq_pidi_mode) {
case CPU_1600_DDR_1200_RCLK_1200:
if (perr[0])
goto perror;
avs_workpoint = svc[0];
break;
case CPU_1300_DDR_800_RCLK_800:
if (perr[1])
goto perror;
avs_workpoint = svc[1];
break;
default:
if (perr[0])
goto perror;
avs_workpoint = svc[0];
break;
}
} else if (device_id == MVEBU_CN9130_DEV_ID) {
NOTICE("SVC: DEV ID: %s, FREQ Mode: 0x%x\n",
"CN913x", freq_pidi_mode);
switch (freq_pidi_mode) {
case CPU_2200_DDR_1200_RCLK_1200:
if (perr[0])
goto perror;
avs_workpoint = svc[0];
break;
case CPU_2000_DDR_1200_RCLK_1200:
if (perr[1])
goto perror;
avs_workpoint = svc[1];
break;
case CPU_1600_DDR_1200_RCLK_1200:
if (perr[2])
goto perror;
avs_workpoint = svc[2];
break;
default:
ERROR("SVC: Unsupported Frequency 0x%x\n",
freq_pidi_mode);
return;
}
} else {
ERROR("SVC: Unsupported Device ID 0x%x\n", device_id);
return;
}
/* Set AVS control if needed */
if (avs_workpoint == 0) {
ERROR("SVC: You are using a frequency setup which is\n");
ERROR("Not supported by this device\n");
ERROR("This may result in malfunction of the device\n");
return;
}
/* Remove parity bit */
if (ap_type != CHIP_ID_AP807)
avs_workpoint &= 0x7F;
else
avs_workpoint &= 0x3FF;
/* Update WP from EEPROM if needed */
avs_workpoint = avs_update_from_eeprom(avs_workpoint);
set_aws_wp:
reg_val = mmio_read_32(AVS_EN_CTRL_REG);
NOTICE("SVC: AVS work point changed from 0x%x to 0x%x\n",
(reg_val & AVS_VDD_LOW_LIMIT_MASK) >> AVS_LOW_VDD_LIMIT_OFFSET,
avs_workpoint);
reg_val &= ~(AVS_VDD_LOW_LIMIT_MASK | AVS_VDD_HIGH_LIMIT_MASK);
reg_val |= 0x1 << AVS_ENABLE_OFFSET;
reg_val |= avs_workpoint << AVS_HIGH_VDD_LIMIT_OFFSET;
reg_val |= avs_workpoint << AVS_LOW_VDD_LIMIT_OFFSET;
mmio_write_32(AVS_EN_CTRL_REG, reg_val);
return;
perror:
ERROR("Failed SVC WP[%d] parity check!\n", i);
ERROR("Ignoring the WP values\n");
}
#if PLAT_RECOVERY_IMAGE_ENABLE
static int ble_skip_image_i2c(struct skip_image *skip_im)
{
ERROR("skipping image using i2c is not supported\n");
/* not supported */
return 0;
}
static int ble_skip_image_other(struct skip_image *skip_im)
{
ERROR("implementation missing for skip image request\n");
/* not supported, make your own implementation */
return 0;
}
static int ble_skip_image_gpio(struct skip_image *skip_im)
{
unsigned int val;
unsigned int mpp_address = 0;
unsigned int offset = 0;
switch (skip_im->info.test.cp_ap) {
case(CP):
mpp_address = MVEBU_CP_GPIO_DATA_IN(skip_im->info.test.cp_index,
skip_im->info.gpio.num);
if (skip_im->info.gpio.num > NUM_OF_GPIO_PER_REG)
offset = skip_im->info.gpio.num - NUM_OF_GPIO_PER_REG;
else
offset = skip_im->info.gpio.num;
break;
case(AP):
mpp_address = MVEBU_AP_GPIO_DATA_IN;
offset = skip_im->info.gpio.num;
break;
}
val = mmio_read_32(mpp_address);
val &= (1 << offset);
if ((!val && skip_im->info.gpio.button_state == HIGH) ||
(val && skip_im->info.gpio.button_state == LOW)) {
mmio_write_32(SCRATCH_PAD_REG2, SCRATCH_PAD_SKIP_VAL);
return 1;
}
return 0;
}
/*
* This function checks if there's a skip image request:
* return values:
* 1: (true) images request been made.
* 0: (false) no image request been made.
*/
static int ble_skip_current_image(void)
{
struct skip_image *skip_im;
/*fetching skip image info*/
skip_im = (struct skip_image *)plat_marvell_get_skip_image_data();
if (skip_im == NULL)
return 0;
/* check if skipping image request has already been made */
if (mmio_read_32(SCRATCH_PAD_REG2) == SCRATCH_PAD_SKIP_VAL)
return 0;
switch (skip_im->detection_method) {
case GPIO:
return ble_skip_image_gpio(skip_im);
case I2C:
return ble_skip_image_i2c(skip_im);
case USER_DEFINED:
return ble_skip_image_other(skip_im);
}
return 0;
}
#endif
int ble_plat_setup(int *skip)
{
int ret, cp;
unsigned int freq_mode;
/* Power down unused CPUs */
plat_marvell_early_cpu_powerdown();
/*
* Save the current CCU configuration and make required changes:
* - Allow access to DRAM larger than 4GB
* - Open memory access to all CPn peripherals
*/
ble_plat_mmap_config(MMAP_SAVE_AND_CONFIG);
#if PLAT_RECOVERY_IMAGE_ENABLE
/* Check if there's a skip request to bootRom recovery Image */
if (ble_skip_current_image()) {
/* close memory access to all CPn peripherals. */
ble_plat_mmap_config(MMAP_RESTORE_SAVED);
*skip = 1;
return 0;
}
#endif
/* Do required CP-110 setups for BLE stage */
cp110_ble_init(MVEBU_CP_REGS_BASE(0));
/* Config address for each cp other than cp0 */
for (cp = 1; cp < CP_COUNT; cp++)
update_cp110_default_win(cp);
/* Setup AVS */
ble_plat_svc_config();
/* read clk option from sampled-at-reset register */
freq_mode =
SAR_CLOCK_FREQ_MODE(mmio_read_32(MVEBU_AP_SAR_REG_BASE(
FREQ_MODE_AP_SAR_REG_NUM)));
/* work with PLL clock driver in AP807 */
if (ble_get_ap_type() == CHIP_ID_AP807)
ap807_clocks_init(freq_mode);
/* Do required AP setups for BLE stage */
ap_ble_init();
/* Update DRAM topology (scan DIMM SPDs) */
plat_marvell_dram_update_topology();
/* Kick it in */
ret = dram_init();
/* Restore the original CCU configuration before exit from BLE */
ble_plat_mmap_config(MMAP_RESTORE_SAVED);
return ret;
}
@@ -0,0 +1,853 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <assert.h>
#include <common/debug.h>
#include <drivers/arm/gicv2.h>
#include <drivers/console.h>
#include <drivers/delay_timer.h>
#include <drivers/marvell/cache_llc.h>
#include <lib/bakery_lock.h>
#include <lib/mmio.h>
#include <plat/common/platform.h>
#include <armada_common.h>
#include <marvell_pm.h>
#if MSS_SUPPORT
#include <mss_pm_ipc.h>
#endif
#include <plat_marvell.h>
#include <plat_pm_trace.h>
#define MVEBU_PRIVATE_UID_REG 0x30
#define MVEBU_RFU_GLOBL_SW_RST 0x84
#define MVEBU_CCU_RVBAR(cpu) (MVEBU_REGS_BASE + 0x640 + (cpu * 4))
#define MVEBU_CCU_CPU_UN_RESET(cpu) (MVEBU_REGS_BASE + 0x650 + (cpu * 4))
#define MPIDR_CPU_GET(mpidr) ((mpidr) & MPIDR_CPU_MASK)
#define MPIDR_CLUSTER_GET(mpidr) MPIDR_AFFLVL1_VAL((mpidr))
#define MVEBU_GPIO_MASK(index) (1 << (index % 32))
#define MVEBU_MPP_MASK(index) (0xF << (4 * (index % 8)))
#define MVEBU_GPIO_VALUE(index, value) (value << (index % 32))
#define MVEBU_USER_CMD_0_REG (MVEBU_DRAM_MAC_BASE + 0x20)
#define MVEBU_USER_CMD_CH0_OFFSET 28
#define MVEBU_USER_CMD_CH0_MASK (1 << MVEBU_USER_CMD_CH0_OFFSET)
#define MVEBU_USER_CMD_CH0_EN (1 << MVEBU_USER_CMD_CH0_OFFSET)
#define MVEBU_USER_CMD_CS_OFFSET 24
#define MVEBU_USER_CMD_CS_MASK (0xF << MVEBU_USER_CMD_CS_OFFSET)
#define MVEBU_USER_CMD_CS_ALL (0xF << MVEBU_USER_CMD_CS_OFFSET)
#define MVEBU_USER_CMD_SR_OFFSET 6
#define MVEBU_USER_CMD_SR_MASK (0x3 << MVEBU_USER_CMD_SR_OFFSET)
#define MVEBU_USER_CMD_SR_ENTER (0x1 << MVEBU_USER_CMD_SR_OFFSET)
#define MVEBU_MC_PWR_CTRL_REG (MVEBU_DRAM_MAC_BASE + 0x54)
#define MVEBU_MC_AC_ON_DLY_OFFSET 8
#define MVEBU_MC_AC_ON_DLY_MASK (0xF << MVEBU_MC_AC_ON_DLY_OFFSET)
#define MVEBU_MC_AC_ON_DLY_DEF_VAR (8 << MVEBU_MC_AC_ON_DLY_OFFSET)
#define MVEBU_MC_AC_OFF_DLY_OFFSET 4
#define MVEBU_MC_AC_OFF_DLY_MASK (0xF << MVEBU_MC_AC_OFF_DLY_OFFSET)
#define MVEBU_MC_AC_OFF_DLY_DEF_VAR (0xC << MVEBU_MC_AC_OFF_DLY_OFFSET)
#define MVEBU_MC_PHY_AUTO_OFF_OFFSET 0
#define MVEBU_MC_PHY_AUTO_OFF_MASK (1 << MVEBU_MC_PHY_AUTO_OFF_OFFSET)
#define MVEBU_MC_PHY_AUTO_OFF_EN (1 << MVEBU_MC_PHY_AUTO_OFF_OFFSET)
/* this lock synchronize AP multiple cores execution with MSS */
DEFINE_BAKERY_LOCK(pm_sys_lock);
/* Weak definitions may be overridden in specific board */
#pragma weak plat_marvell_get_pm_cfg
/* AP806 CPU power down /power up definitions */
enum CPU_ID {
CPU0,
CPU1,
CPU2,
CPU3
};
#define REG_WR_VALIDATE_TIMEOUT (2000)
#define FEATURE_DISABLE_STATUS_REG \
(MVEBU_REGS_BASE + 0x6F8230)
#define FEATURE_DISABLE_STATUS_CPU_CLUSTER_OFFSET 4
#define FEATURE_DISABLE_STATUS_CPU_CLUSTER_MASK \
(0x1 << FEATURE_DISABLE_STATUS_CPU_CLUSTER_OFFSET)
#ifdef MVEBU_SOC_AP807
#define PWRC_CPUN_CR_PWR_DN_RQ_OFFSET 1
#define PWRC_CPUN_CR_LDO_BYPASS_RDY_OFFSET 0
#else
#define PWRC_CPUN_CR_PWR_DN_RQ_OFFSET 0
#define PWRC_CPUN_CR_LDO_BYPASS_RDY_OFFSET 31
#endif
#define PWRC_CPUN_CR_REG(cpu_id) \
(MVEBU_REGS_BASE + 0x680000 + (cpu_id * 0x10))
#define PWRC_CPUN_CR_PWR_DN_RQ_MASK \
(0x1 << PWRC_CPUN_CR_PWR_DN_RQ_OFFSET)
#define PWRC_CPUN_CR_ISO_ENABLE_OFFSET 16
#define PWRC_CPUN_CR_ISO_ENABLE_MASK \
(0x1 << PWRC_CPUN_CR_ISO_ENABLE_OFFSET)
#define PWRC_CPUN_CR_LDO_BYPASS_RDY_MASK \
(0x1U << PWRC_CPUN_CR_LDO_BYPASS_RDY_OFFSET)
#define CCU_B_PRCRN_REG(cpu_id) \
(MVEBU_REGS_BASE + 0x1A50 + \
((cpu_id / 2) * (0x400)) + ((cpu_id % 2) * 4))
#define CCU_B_PRCRN_CPUPORESET_STATIC_OFFSET 0
#define CCU_B_PRCRN_CPUPORESET_STATIC_MASK \
(0x1 << CCU_B_PRCRN_CPUPORESET_STATIC_OFFSET)
/* power switch fingers */
#define AP807_PWRC_LDO_CR0_REG \
(MVEBU_REGS_BASE + 0x680000 + 0x100)
#define AP807_PWRC_LDO_CR0_OFFSET 16
#define AP807_PWRC_LDO_CR0_MASK \
(0xff << AP807_PWRC_LDO_CR0_OFFSET)
#define AP807_PWRC_LDO_CR0_VAL 0xfc
/*
* Power down CPU:
* Used to reduce power consumption, and avoid SoC unnecessary temperature rise.
*/
static int plat_marvell_cpu_powerdown(int cpu_id)
{
uint32_t reg_val;
int exit_loop = REG_WR_VALIDATE_TIMEOUT;
INFO("Powering down CPU%d\n", cpu_id);
/* 1. Isolation enable */
reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
reg_val |= 0x1 << PWRC_CPUN_CR_ISO_ENABLE_OFFSET;
mmio_write_32(PWRC_CPUN_CR_REG(cpu_id), reg_val);
/* 2. Read and check Isolation enabled - verify bit set to 1 */
do {
reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
exit_loop--;
} while (!(reg_val & (0x1 << PWRC_CPUN_CR_ISO_ENABLE_OFFSET)) &&
exit_loop > 0);
/* 3. Switch off CPU power */
reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
reg_val &= ~PWRC_CPUN_CR_PWR_DN_RQ_MASK;
mmio_write_32(PWRC_CPUN_CR_REG(cpu_id), reg_val);
/* 4. Read and check Switch Off - verify bit set to 0 */
exit_loop = REG_WR_VALIDATE_TIMEOUT;
do {
reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
exit_loop--;
} while (reg_val & PWRC_CPUN_CR_PWR_DN_RQ_MASK && exit_loop > 0);
if (exit_loop <= 0)
goto cpu_poweroff_error;
/* 5. De-Assert power ready */
reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
reg_val &= ~PWRC_CPUN_CR_LDO_BYPASS_RDY_MASK;
mmio_write_32(PWRC_CPUN_CR_REG(cpu_id), reg_val);
/* 6. Assert CPU POR reset */
reg_val = mmio_read_32(CCU_B_PRCRN_REG(cpu_id));
reg_val &= ~CCU_B_PRCRN_CPUPORESET_STATIC_MASK;
mmio_write_32(CCU_B_PRCRN_REG(cpu_id), reg_val);
/* 7. Read and poll on Validate the CPU is out of reset */
exit_loop = REG_WR_VALIDATE_TIMEOUT;
do {
reg_val = mmio_read_32(CCU_B_PRCRN_REG(cpu_id));
exit_loop--;
} while (reg_val & CCU_B_PRCRN_CPUPORESET_STATIC_MASK && exit_loop > 0);
if (exit_loop <= 0)
goto cpu_poweroff_error;
INFO("Successfully powered down CPU%d\n", cpu_id);
return 0;
cpu_poweroff_error:
ERROR("ERROR: Can't power down CPU%d\n", cpu_id);
return -1;
}
/*
* Power down CPUs 1-3 at early boot stage,
* to reduce power consumption and SoC temperature.
* This is triggered by BLE prior to DDR initialization.
*
* Note:
* All CPUs will be powered up by plat_marvell_cpu_powerup on Linux boot stage,
* which is triggered by PSCI ops (pwr_domain_on).
*/
int plat_marvell_early_cpu_powerdown(void)
{
uint32_t cpu_cluster_status =
mmio_read_32(FEATURE_DISABLE_STATUS_REG) &
FEATURE_DISABLE_STATUS_CPU_CLUSTER_MASK;
/* if cpu_cluster_status bit is set,
* that means we have only single cluster
*/
int cluster_count = cpu_cluster_status ? 1 : 2;
INFO("Powering off unused CPUs\n");
/* CPU1 is in AP806 cluster-0, which always exists, so power it down */
if (plat_marvell_cpu_powerdown(CPU1) == -1)
return -1;
/*
* CPU2-3 are in AP806 2nd cluster (cluster-1),
* which doesn't exists in dual-core systems.
* so need to check if we have dual-core (single cluster)
* or quad-code (2 clusters)
*/
if (cluster_count == 2) {
/* CPU2-3 are part of 2nd cluster */
if (plat_marvell_cpu_powerdown(CPU2) == -1)
return -1;
if (plat_marvell_cpu_powerdown(CPU3) == -1)
return -1;
}
return 0;
}
/*
* Power up CPU - part of Linux boot stage
*/
static int plat_marvell_cpu_powerup(u_register_t mpidr)
{
uint32_t reg_val;
int cpu_id = MPIDR_CPU_GET(mpidr),
cluster = MPIDR_CLUSTER_GET(mpidr);
int exit_loop = REG_WR_VALIDATE_TIMEOUT;
/* calculate absolute CPU ID */
cpu_id = cluster * PLAT_MARVELL_CLUSTER_CORE_COUNT + cpu_id;
INFO("Powering on CPU%d\n", cpu_id);
#ifdef MVEBU_SOC_AP807
/* Activate 2 power switch fingers */
reg_val = mmio_read_32(AP807_PWRC_LDO_CR0_REG);
reg_val &= ~(AP807_PWRC_LDO_CR0_MASK);
reg_val |= (AP807_PWRC_LDO_CR0_VAL << AP807_PWRC_LDO_CR0_OFFSET);
mmio_write_32(AP807_PWRC_LDO_CR0_REG, reg_val);
udelay(100);
#endif
/* 1. Switch CPU power ON */
reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
reg_val |= 0x1 << PWRC_CPUN_CR_PWR_DN_RQ_OFFSET;
mmio_write_32(PWRC_CPUN_CR_REG(cpu_id), reg_val);
/* 2. Wait for CPU on, up to 100 uSec: */
udelay(100);
/* 3. Assert power ready */
reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
reg_val |= 0x1U << PWRC_CPUN_CR_LDO_BYPASS_RDY_OFFSET;
mmio_write_32(PWRC_CPUN_CR_REG(cpu_id), reg_val);
/* 4. Read & Validate power ready
* used in order to generate 16 Host CPU cycles
*/
do {
reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
exit_loop--;
} while (!(reg_val & (0x1U << PWRC_CPUN_CR_LDO_BYPASS_RDY_OFFSET)) &&
exit_loop > 0);
if (exit_loop <= 0)
goto cpu_poweron_error;
/* 5. Isolation disable */
reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
reg_val &= ~PWRC_CPUN_CR_ISO_ENABLE_MASK;
mmio_write_32(PWRC_CPUN_CR_REG(cpu_id), reg_val);
/* 6. Read and check Isolation enabled - verify bit set to 1 */
exit_loop = REG_WR_VALIDATE_TIMEOUT;
do {
reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
exit_loop--;
} while ((reg_val & (0x1 << PWRC_CPUN_CR_ISO_ENABLE_OFFSET)) &&
exit_loop > 0);
/* 7. De Assert CPU POR reset & Core reset */
reg_val = mmio_read_32(CCU_B_PRCRN_REG(cpu_id));
reg_val |= 0x1 << CCU_B_PRCRN_CPUPORESET_STATIC_OFFSET;
mmio_write_32(CCU_B_PRCRN_REG(cpu_id), reg_val);
/* 8. Read & Validate CPU POR reset */
exit_loop = REG_WR_VALIDATE_TIMEOUT;
do {
reg_val = mmio_read_32(CCU_B_PRCRN_REG(cpu_id));
exit_loop--;
} while (!(reg_val & (0x1 << CCU_B_PRCRN_CPUPORESET_STATIC_OFFSET)) &&
exit_loop > 0);
if (exit_loop <= 0)
goto cpu_poweron_error;
INFO("Successfully powered on CPU%d\n", cpu_id);
return 0;
cpu_poweron_error:
ERROR("ERROR: Can't power up CPU%d\n", cpu_id);
return -1;
}
static int plat_marvell_cpu_on(u_register_t mpidr)
{
int cpu_id;
int cluster;
/* Set barierr */
dsbsy();
/* Get cpu number - use CPU ID */
cpu_id = MPIDR_CPU_GET(mpidr);
/* Get cluster number - use affinity level 1 */
cluster = MPIDR_CLUSTER_GET(mpidr);
/* Set CPU private UID */
mmio_write_32(MVEBU_REGS_BASE + MVEBU_PRIVATE_UID_REG, cluster + 0x4);
/* Set the cpu start address to BL1 entry point (align to 0x10000) */
mmio_write_32(MVEBU_CCU_RVBAR(cpu_id),
PLAT_MARVELL_CPU_ENTRY_ADDR >> 16);
/* Get the cpu out of reset */
mmio_write_32(MVEBU_CCU_CPU_UN_RESET(cpu_id), 0x10001);
return 0;
}
/*****************************************************************************
* A8K handler called to check the validity of the power state
* parameter.
*****************************************************************************
*/
static int a8k_validate_power_state(unsigned int power_state,
psci_power_state_t *req_state)
{
int pstate = psci_get_pstate_type(power_state);
int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
int i;
if (pwr_lvl > PLAT_MAX_PWR_LVL)
return PSCI_E_INVALID_PARAMS;
/* Sanity check the requested state */
if (pstate == PSTATE_TYPE_STANDBY) {
/*
* It's possible to enter standby only on power level 0
* Ignore any other power level.
*/
if (pwr_lvl != MARVELL_PWR_LVL0)
return PSCI_E_INVALID_PARAMS;
req_state->pwr_domain_state[MARVELL_PWR_LVL0] =
MARVELL_LOCAL_STATE_RET;
} else {
for (i = MARVELL_PWR_LVL0; i <= pwr_lvl; i++)
req_state->pwr_domain_state[i] =
MARVELL_LOCAL_STATE_OFF;
}
/*
* We expect the 'state id' to be zero.
*/
if (psci_get_pstate_id(power_state))
return PSCI_E_INVALID_PARAMS;
return PSCI_E_SUCCESS;
}
/*****************************************************************************
* A8K handler called when a CPU is about to enter standby.
*****************************************************************************
*/
static void a8k_cpu_standby(plat_local_state_t cpu_state)
{
if (!is_pm_fw_running()) {
ERROR("%s: needs to be implemented\n", __func__);
panic();
}
}
/*****************************************************************************
* A8K handler called when a power domain is about to be turned on. The
* mpidr determines the CPU to be turned on.
*****************************************************************************
*/
static int a8k_pwr_domain_on(u_register_t mpidr)
{
/* Power up CPU (CPUs 1-3 are powered off at start of BLE) */
plat_marvell_cpu_powerup(mpidr);
#if MSS_SUPPORT
if (is_pm_fw_running()) {
unsigned int target =
((mpidr & 0xFF) + (((mpidr >> 8) & 0xFF) * 2));
/*
* pm system synchronization - used to synchronize
* multiple core access to MSS
*/
bakery_lock_get(&pm_sys_lock);
/* send CPU ON IPC Message to MSS */
mss_pm_ipc_msg_send(target, PM_IPC_MSG_CPU_ON, 0);
/* trigger IPC message to MSS */
mss_pm_ipc_msg_trigger();
/* pm system synchronization */
bakery_lock_release(&pm_sys_lock);
/* trace message */
PM_TRACE(TRACE_PWR_DOMAIN_ON | target);
} else
#endif
{
/* proprietary CPU ON exection flow */
plat_marvell_cpu_on(mpidr);
}
return 0;
}
/*****************************************************************************
* A8K handler called to validate the entry point.
*****************************************************************************
*/
static int a8k_validate_ns_entrypoint(uintptr_t entrypoint)
{
return PSCI_E_SUCCESS;
}
/*****************************************************************************
* A8K handler called when a power domain is about to be turned off. The
* target_state encodes the power state that each level should transition to.
*****************************************************************************
*/
static void a8k_pwr_domain_off(const psci_power_state_t *target_state)
{
#if MSS_SUPPORT
if (is_pm_fw_running()) {
unsigned int idx = plat_my_core_pos();
/* Prevent interrupts from spuriously waking up this cpu */
gicv2_cpuif_disable();
/* pm system synchronization - used to synchronize multiple
* core access to MSS
*/
bakery_lock_get(&pm_sys_lock);
/* send CPU OFF IPC Message to MSS */
mss_pm_ipc_msg_send(idx, PM_IPC_MSG_CPU_OFF, target_state);
/* trigger IPC message to MSS */
mss_pm_ipc_msg_trigger();
/* pm system synchronization */
bakery_lock_release(&pm_sys_lock);
/* trace message */
PM_TRACE(TRACE_PWR_DOMAIN_OFF);
} else {
INFO("%s: is not supported without SCP\n", __func__);
}
#endif
}
/* Get PM config to power off the SoC */
void *plat_marvell_get_pm_cfg(void)
{
return NULL;
}
/*
* This function should be called on restore from
* "suspend to RAM" state when the execution flow
* has to bypass BootROM image to RAM copy and speed up
* the system recovery
*
*/
static void plat_marvell_exit_bootrom(void)
{
marvell_exit_bootrom(PLAT_MARVELL_TRUSTED_ROM_BASE);
}
/*
* Prepare for the power off of the system via GPIO
*/
static void plat_marvell_power_off_gpio(struct power_off_method *pm_cfg,
register_t *gpio_addr,
register_t *gpio_data)
{
unsigned int gpio;
unsigned int idx;
unsigned int shift;
unsigned int reg;
unsigned int addr;
gpio_info_t *info;
unsigned int tog_bits;
assert((pm_cfg->cfg.gpio.pin_count < PMIC_GPIO_MAX_NUMBER) &&
(pm_cfg->cfg.gpio.step_count < PMIC_GPIO_MAX_TOGGLE_STEP));
/* Prepare GPIOs for PMIC */
for (gpio = 0; gpio < pm_cfg->cfg.gpio.pin_count; gpio++) {
info = &pm_cfg->cfg.gpio.info[gpio];
/* Set PMIC GPIO to output mode */
reg = mmio_read_32(MVEBU_CP_GPIO_DATA_OUT_EN(
info->cp_index, info->gpio_index));
mmio_write_32(MVEBU_CP_GPIO_DATA_OUT_EN(
info->cp_index, info->gpio_index),
reg & ~MVEBU_GPIO_MASK(info->gpio_index));
/* Set the appropriate MPP to GPIO mode */
reg = mmio_read_32(MVEBU_PM_MPP_REGS(info->cp_index,
info->gpio_index));
mmio_write_32(MVEBU_PM_MPP_REGS(info->cp_index,
info->gpio_index),
reg & ~MVEBU_MPP_MASK(info->gpio_index));
}
/* Wait for MPP & GPIO pre-configurations done */
mdelay(pm_cfg->cfg.gpio.delay_ms);
/* Toggle the GPIO values, and leave final step to be triggered
* after DDR self-refresh is enabled
*/
for (idx = 0; idx < pm_cfg->cfg.gpio.step_count; idx++) {
tog_bits = pm_cfg->cfg.gpio.seq[idx];
/* The GPIOs must be within same GPIO register,
* thus could get the original value by first GPIO
*/
info = &pm_cfg->cfg.gpio.info[0];
reg = mmio_read_32(MVEBU_CP_GPIO_DATA_OUT(
info->cp_index, info->gpio_index));
addr = MVEBU_CP_GPIO_DATA_OUT(info->cp_index, info->gpio_index);
for (gpio = 0; gpio < pm_cfg->cfg.gpio.pin_count; gpio++) {
shift = pm_cfg->cfg.gpio.info[gpio].gpio_index % 32;
if (GPIO_LOW == (tog_bits & (1 << gpio)))
reg &= ~(1 << shift);
else
reg |= (1 << shift);
}
/* Set the GPIO register, for last step just store
* register address and values to system registers
*/
if (idx < pm_cfg->cfg.gpio.step_count - 1) {
mmio_write_32(MVEBU_CP_GPIO_DATA_OUT(
info->cp_index, info->gpio_index), reg);
mdelay(pm_cfg->cfg.gpio.delay_ms);
} else {
/* Save GPIO register and address values for
* finishing the power down operation later
*/
*gpio_addr = addr;
*gpio_data = reg;
}
}
}
/*
* Prepare for the power off of the system
*/
static void plat_marvell_power_off_prepare(struct power_off_method *pm_cfg,
register_t *addr, register_t *data)
{
switch (pm_cfg->type) {
case PMIC_GPIO:
plat_marvell_power_off_gpio(pm_cfg, addr, data);
break;
default:
break;
}
}
/*****************************************************************************
* A8K handler called when a power domain is about to be suspended. The
* target_state encodes the power state that each level should transition to.
*****************************************************************************
*/
static void a8k_pwr_domain_suspend(const psci_power_state_t *target_state)
{
#if MSS_SUPPORT
if (is_pm_fw_running()) {
unsigned int idx;
/* Prevent interrupts from spuriously waking up this cpu */
gicv2_cpuif_disable();
idx = plat_my_core_pos();
/* pm system synchronization - used to synchronize multiple
* core access to MSS
*/
bakery_lock_get(&pm_sys_lock);
/* send CPU Suspend IPC Message to MSS */
mss_pm_ipc_msg_send(idx, PM_IPC_MSG_CPU_SUSPEND, target_state);
/* trigger IPC message to MSS */
mss_pm_ipc_msg_trigger();
/* pm system synchronization */
bakery_lock_release(&pm_sys_lock);
/* trace message */
PM_TRACE(TRACE_PWR_DOMAIN_SUSPEND);
} else
#endif
{
uintptr_t *mailbox = (void *)PLAT_MARVELL_MAILBOX_BASE;
INFO("Suspending to RAM\n");
marvell_console_runtime_end();
/* Prevent interrupts from spuriously waking up this cpu */
gicv2_cpuif_disable();
mailbox[MBOX_IDX_SUSPEND_MAGIC] = MVEBU_MAILBOX_SUSPEND_STATE;
mailbox[MBOX_IDX_ROM_EXIT_ADDR] = (uintptr_t)&plat_marvell_exit_bootrom;
#if PLAT_MARVELL_SHARED_RAM_CACHED
flush_dcache_range(PLAT_MARVELL_MAILBOX_BASE +
MBOX_IDX_SUSPEND_MAGIC * sizeof(uintptr_t),
2 * sizeof(uintptr_t));
#endif
/* Flush and disable LLC before going off-power */
llc_disable(0);
isb();
/*
* Do not halt here!
* The function must return for allowing the caller function
* psci_power_up_finish() to do the proper context saving and
* to release the CPU lock.
*/
}
}
/*****************************************************************************
* A8K handler called when a power domain has just been powered on after
* being turned off earlier. The target_state encodes the low power state that
* each level has woken up from.
*****************************************************************************
*/
static void a8k_pwr_domain_on_finish(const psci_power_state_t *target_state)
{
/* arch specific configuration */
marvell_psci_arch_init(0);
/* Interrupt initialization */
gicv2_pcpu_distif_init();
gicv2_cpuif_enable();
if (is_pm_fw_running()) {
/* trace message */
PM_TRACE(TRACE_PWR_DOMAIN_ON_FINISH);
}
}
/*****************************************************************************
* A8K handler called when a power domain has just been powered on after
* having been suspended earlier. The target_state encodes the low power state
* that each level has woken up from.
* TODO: At the moment we reuse the on finisher and reinitialize the secure
* context. Need to implement a separate suspend finisher.
*****************************************************************************
*/
static void a8k_pwr_domain_suspend_finish(
const psci_power_state_t *target_state)
{
if (is_pm_fw_running()) {
/* arch specific configuration */
marvell_psci_arch_init(0);
/* Interrupt initialization */
gicv2_cpuif_enable();
/* trace message */
PM_TRACE(TRACE_PWR_DOMAIN_SUSPEND_FINISH);
} else {
uintptr_t *mailbox = (void *)PLAT_MARVELL_MAILBOX_BASE;
/* Only primary CPU requres platform init */
if (!plat_my_core_pos()) {
/* Initialize the console to provide
* early debug support
*/
marvell_console_runtime_init();
bl31_plat_arch_setup();
marvell_bl31_platform_setup();
/*
* Remove suspend to RAM marker from the mailbox
* for treating a regular reset as a cold boot
*/
mailbox[MBOX_IDX_SUSPEND_MAGIC] = 0;
mailbox[MBOX_IDX_ROM_EXIT_ADDR] = 0;
#if PLAT_MARVELL_SHARED_RAM_CACHED
flush_dcache_range(PLAT_MARVELL_MAILBOX_BASE +
MBOX_IDX_SUSPEND_MAGIC * sizeof(uintptr_t),
2 * sizeof(uintptr_t));
#endif
}
}
}
/*****************************************************************************
* This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND`
* call to get the `power_state` parameter. This allows the platform to encode
* the appropriate State-ID field within the `power_state` parameter which can
* be utilized in `pwr_domain_suspend()` to suspend to system affinity level.
*****************************************************************************
*/
static void a8k_get_sys_suspend_power_state(psci_power_state_t *req_state)
{
/* lower affinities use PLAT_MAX_OFF_STATE */
for (int i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
}
static void
__dead2 a8k_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
{
struct power_off_method *pm_cfg;
unsigned int srcmd;
unsigned int sdram_reg;
register_t gpio_data = 0, gpio_addr = 0;
if (is_pm_fw_running()) {
psci_power_down_wfi();
panic();
}
pm_cfg = (struct power_off_method *)plat_marvell_get_pm_cfg();
/* Prepare for power off */
plat_marvell_power_off_prepare(pm_cfg, &gpio_addr, &gpio_data);
/* First step to enable DDR self-refresh
* to keep the data during suspend
*/
mmio_write_32(MVEBU_MC_PWR_CTRL_REG, 0x8C1);
/* Save DDR self-refresh second step register
* and value to be issued later
*/
sdram_reg = MVEBU_USER_CMD_0_REG;
srcmd = mmio_read_32(sdram_reg);
srcmd &= ~(MVEBU_USER_CMD_CH0_MASK | MVEBU_USER_CMD_CS_MASK |
MVEBU_USER_CMD_SR_MASK);
srcmd |= (MVEBU_USER_CMD_CH0_EN | MVEBU_USER_CMD_CS_ALL |
MVEBU_USER_CMD_SR_ENTER);
/*
* Wait for DRAM is done using registers access only.
* At this stage any access to DRAM (procedure call) will
* release it from the self-refresh mode
*/
__asm__ volatile (
/* Align to a cache line */
" .balign 64\n\t"
/* Enter self refresh */
" str %[srcmd], [%[sdram_reg]]\n\t"
/*
* Wait 100 cycles for DDR to enter self refresh, by
* doing 50 times two instructions.
*/
" mov x1, #50\n\t"
"1: subs x1, x1, #1\n\t"
" bne 1b\n\t"
/* Issue the command to trigger the SoC power off */
" str %[gpio_data], [%[gpio_addr]]\n\t"
/* Trap the processor */
" b .\n\t"
: : [srcmd] "r" (srcmd), [sdram_reg] "r" (sdram_reg),
[gpio_addr] "r" (gpio_addr), [gpio_data] "r" (gpio_data)
: "x1");
panic();
}
/*****************************************************************************
* A8K handlers to shutdown/reboot the system
*****************************************************************************
*/
/* Set a weak stub for platforms that don't configure system power off */
#pragma weak system_power_off
int system_power_off(void)
{
return 0;
}
static void __dead2 a8k_system_off(void)
{
/* Call the platform specific system power off function */
system_power_off();
/* board doesn't have a system off implementation */
ERROR("%s: needs to be implemented\n", __func__);
panic();
}
void plat_marvell_system_reset(void)
{
mmio_write_32(MVEBU_RFU_BASE + MVEBU_RFU_GLOBL_SW_RST, 0x0);
}
static void __dead2 a8k_system_reset(void)
{
plat_marvell_system_reset();
/* we shouldn't get to this point */
panic();
}
/*****************************************************************************
* Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
* platform layer will take care of registering the handlers with PSCI.
*****************************************************************************
*/
const plat_psci_ops_t plat_arm_psci_pm_ops = {
.cpu_standby = a8k_cpu_standby,
.pwr_domain_on = a8k_pwr_domain_on,
.pwr_domain_off = a8k_pwr_domain_off,
.pwr_domain_suspend = a8k_pwr_domain_suspend,
.pwr_domain_on_finish = a8k_pwr_domain_on_finish,
.get_sys_suspend_power_state = a8k_get_sys_suspend_power_state,
.pwr_domain_suspend_finish = a8k_pwr_domain_suspend_finish,
.pwr_domain_pwr_down_wfi = a8k_pwr_domain_pwr_down_wfi,
.system_off = a8k_system_off,
.system_reset = a8k_system_reset,
.validate_power_state = a8k_validate_power_state,
.validate_ns_entrypoint = a8k_validate_ns_entrypoint
};
@@ -0,0 +1,94 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <lib/mmio.h>
#include <plat/common/platform.h>
#if MSS_SUPPORT
#include <mss_mem.h>
#ifdef PM_TRACE_ENABLE
#include <plat_pm_trace.h>
/* core trace APIs */
core_trace_func funcTbl[PLATFORM_CORE_COUNT] = {
pm_core_0_trace,
pm_core_1_trace,
pm_core_2_trace,
pm_core_3_trace};
/*****************************************************************************
* pm_core0_trace
* pm_core1_trace
* pm_core2_trace
* pm_core_3trace
*
* This functions set trace info into core cyclic trace queue in MSS SRAM
* memory space
*****************************************************************************
*/
void pm_core_0_trace(unsigned int trace)
{
unsigned int current_position_core_0 =
mmio_read_32(AP_MSS_ATF_CORE_0_CTRL_BASE);
mmio_write_32((AP_MSS_ATF_CORE_0_INFO_BASE +
(current_position_core_0 * AP_MSS_ATF_CORE_ENTRY_SIZE)),
mmio_read_32(AP_MSS_TIMER_BASE));
mmio_write_32((AP_MSS_ATF_CORE_0_INFO_TRACE +
(current_position_core_0 * AP_MSS_ATF_CORE_ENTRY_SIZE)),
trace);
mmio_write_32(AP_MSS_ATF_CORE_0_CTRL_BASE,
((current_position_core_0 + 1) &
AP_MSS_ATF_TRACE_SIZE_MASK));
}
void pm_core_1_trace(unsigned int trace)
{
unsigned int current_position_core_1 =
mmio_read_32(AP_MSS_ATF_CORE_1_CTRL_BASE);
mmio_write_32((AP_MSS_ATF_CORE_1_INFO_BASE +
(current_position_core_1 * AP_MSS_ATF_CORE_ENTRY_SIZE)),
mmio_read_32(AP_MSS_TIMER_BASE));
mmio_write_32((AP_MSS_ATF_CORE_1_INFO_TRACE +
(current_position_core_1 * AP_MSS_ATF_CORE_ENTRY_SIZE)),
trace);
mmio_write_32(AP_MSS_ATF_CORE_1_CTRL_BASE,
((current_position_core_1 + 1) &
AP_MSS_ATF_TRACE_SIZE_MASK));
}
void pm_core_2_trace(unsigned int trace)
{
unsigned int current_position_core_2 =
mmio_read_32(AP_MSS_ATF_CORE_2_CTRL_BASE);
mmio_write_32((AP_MSS_ATF_CORE_2_INFO_BASE +
(current_position_core_2 * AP_MSS_ATF_CORE_ENTRY_SIZE)),
mmio_read_32(AP_MSS_TIMER_BASE));
mmio_write_32((AP_MSS_ATF_CORE_2_INFO_TRACE +
(current_position_core_2 * AP_MSS_ATF_CORE_ENTRY_SIZE)),
trace);
mmio_write_32(AP_MSS_ATF_CORE_2_CTRL_BASE,
((current_position_core_2 + 1) &
AP_MSS_ATF_TRACE_SIZE_MASK));
}
void pm_core_3_trace(unsigned int trace)
{
unsigned int current_position_core_3 =
mmio_read_32(AP_MSS_ATF_CORE_3_CTRL_BASE);
mmio_write_32((AP_MSS_ATF_CORE_3_INFO_BASE +
(current_position_core_3 * AP_MSS_ATF_CORE_ENTRY_SIZE)),
mmio_read_32(AP_MSS_TIMER_BASE));
mmio_write_32((AP_MSS_ATF_CORE_3_INFO_TRACE +
(current_position_core_3 * AP_MSS_ATF_CORE_ENTRY_SIZE)),
trace);
mmio_write_32(AP_MSS_ATF_CORE_3_CTRL_BASE,
((current_position_core_3 + 1) &
AP_MSS_ATF_TRACE_SIZE_MASK));
}
#endif /* PM_TRACE_ENABLE */
#endif /* MSS_SUPPORT */
@@ -0,0 +1,130 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <drivers/marvell/thermal.h>
#include <lib/mmio.h>
#include <mvebu_def.h>
#define THERMAL_TIMEOUT 1200
#define THERMAL_SEN_CTRL_LSB_STRT_OFFSET 0
#define THERMAL_SEN_CTRL_LSB_STRT_MASK \
(0x1 << THERMAL_SEN_CTRL_LSB_STRT_OFFSET)
#define THERMAL_SEN_CTRL_LSB_RST_OFFSET 1
#define THERMAL_SEN_CTRL_LSB_RST_MASK \
(0x1 << THERMAL_SEN_CTRL_LSB_RST_OFFSET)
#define THERMAL_SEN_CTRL_LSB_EN_OFFSET 2
#define THERMAL_SEN_CTRL_LSB_EN_MASK \
(0x1 << THERMAL_SEN_CTRL_LSB_EN_OFFSET)
#define THERMAL_SEN_CTRL_STATS_VALID_OFFSET 16
#define THERMAL_SEN_CTRL_STATS_VALID_MASK \
(0x1 << THERMAL_SEN_CTRL_STATS_VALID_OFFSET)
#define THERMAL_SEN_CTRL_STATS_TEMP_OUT_OFFSET 0
#define THERMAL_SEN_CTRL_STATS_TEMP_OUT_MASK \
(0x3FF << THERMAL_SEN_CTRL_STATS_TEMP_OUT_OFFSET)
#define THERMAL_SEN_OUTPUT_MSB 512
#define THERMAL_SEN_OUTPUT_COMP 1024
struct tsen_regs {
uint32_t ext_tsen_ctrl_lsb;
uint32_t ext_tsen_ctrl_msb;
uint32_t ext_tsen_status;
};
static int ext_tsen_probe(struct tsen_config *tsen_cfg)
{
uint32_t reg, timeout = 0;
struct tsen_regs *base;
if (tsen_cfg == NULL && tsen_cfg->regs_base == NULL) {
ERROR("initial thermal sensor configuration is missing\n");
return -1;
}
base = (struct tsen_regs *)tsen_cfg->regs_base;
INFO("initializing thermal sensor\n");
/* initialize thermal sensor hardware reset once */
reg = mmio_read_32((uintptr_t)&base->ext_tsen_ctrl_lsb);
reg &= ~THERMAL_SEN_CTRL_LSB_RST_OFFSET; /* de-assert TSEN_RESET */
reg |= THERMAL_SEN_CTRL_LSB_EN_MASK; /* set TSEN_EN to 1 */
reg |= THERMAL_SEN_CTRL_LSB_STRT_MASK; /* set TSEN_START to 1 */
mmio_write_32((uintptr_t)&base->ext_tsen_ctrl_lsb, reg);
reg = mmio_read_32((uintptr_t)&base->ext_tsen_status);
while ((reg & THERMAL_SEN_CTRL_STATS_VALID_MASK) == 0 &&
timeout < THERMAL_TIMEOUT) {
udelay(100);
reg = mmio_read_32((uintptr_t)&base->ext_tsen_status);
timeout++;
}
if ((reg & THERMAL_SEN_CTRL_STATS_VALID_MASK) == 0) {
ERROR("thermal sensor is not ready\n");
return -1;
}
tsen_cfg->tsen_ready = 1;
VERBOSE("thermal sensor was initialized\n");
return 0;
}
static int ext_tsen_read(struct tsen_config *tsen_cfg, int *temp)
{
uint32_t reg;
struct tsen_regs *base;
if (tsen_cfg == NULL && !tsen_cfg->tsen_ready) {
ERROR("thermal sensor was not initialized\n");
return -1;
}
base = (struct tsen_regs *)tsen_cfg->regs_base;
reg = mmio_read_32((uintptr_t)&base->ext_tsen_status);
reg = ((reg & THERMAL_SEN_CTRL_STATS_TEMP_OUT_MASK) >>
THERMAL_SEN_CTRL_STATS_TEMP_OUT_OFFSET);
/*
* TSEN output format is signed as a 2s complement number
* ranging from-512 to +511. when MSB is set, need to
* calculate the complement number
*/
if (reg >= THERMAL_SEN_OUTPUT_MSB)
reg -= THERMAL_SEN_OUTPUT_COMP;
if (tsen_cfg->tsen_divisor == 0) {
ERROR("thermal sensor divisor cannot be zero\n");
return -1;
}
*temp = ((tsen_cfg->tsen_gain * ((int)reg)) +
tsen_cfg->tsen_offset) / tsen_cfg->tsen_divisor;
return 0;
}
static struct tsen_config tsen_cfg = {
.tsen_offset = 153400,
.tsen_gain = 425,
.tsen_divisor = 1000,
.tsen_ready = 0,
.regs_base = (void *)MVEBU_AP_EXT_TSEN_BASE,
.ptr_tsen_probe = ext_tsen_probe,
.ptr_tsen_read = ext_tsen_read
};
struct tsen_config *marvell_thermal_config_get(void)
{
return &tsen_cfg;
}