marvell: drivers: Add address decoding units drivers

Add address decoding unit drivers for Marvell SoCs.

Address decoding flow and address translation units chart
are located at docs/marvell/misc/mvebu-a8k-addr-map.txt

Change-Id: Id6ce311fa1f4f112df3adfac5d20449f495f71ed
Signed-off-by: Hanna Hawa <hannah@marvell.com>
Signed-off-by: Konstantin Porotchkin <kostap@marvell.com>
This commit is contained in:
Konstantin Porotchkin 2018-02-26 15:51:11 +02:00
parent 752faf8fce
commit c0474d5843
16 changed files with 1575 additions and 0 deletions

View File

@ -0,0 +1,47 @@
Address decoding flow and address translation units of Marvell Armada 8K SoC family
+--------------------------------------------------------------------------------------------------+
| +-------------+ +--------------+ |
| | Memory +----- DRAM CS | |
|+------------+ +-----------+ +-----------+ | Controller | +--------------+ |
|| AP DMA | | | | | +-------------+ |
|| SD/eMMC | | CA72 CPUs | | AP MSS | +-------------+ |
|| MCI-0/1 | | | | | | Memory | |
|+------+-----+ +--+--------+ +--------+--+ +------------+ | Controller | +-------------+ |
| | | | | +----- Translaton | |AP | |
| | | | | | +-------------+ |Configuration| |
| | | +-----+ +-------------------------Space | |
| | | +-------------+ | CCU | +-------------+ |
| | | | MMU +---------+ Windows | +-----------+ +-------------+ |
| | +-| translation | | Lookup +---- +--------- AP SPI | |
| | +-------------+ | | | | +-------------+ |
| | +-------------+ | | | IO | +-------------+ |
| +------------| SMMU +---------+ | | Windows +--------- AP MCI0/1 | |
| | translation | +------------+ | Lookup | +-------------+ |
| +---------+---+ | | +-------------+ |
| - | | +--------- AP STM | |
| +----------------- | | +-------------+ |
| AP | | +-+---------+ |
+---------------------------------------------------------------|----------------------------------+
+-------------|-------------------------------------------------|----------------------------------+
| CP | +-------------+ +------+-----+ +-------------------+ |
| | | | | +------- SB CFG Space | |
| | | DIOB | | | +-------------------+ |
| | | Windows ----------------- IOB | +-------------------+ |
| | | Control | | Windows +------| SB PCIe-0 - PCIe2 | |
| | | | | Lookup | +-------------------+ |
| | +------+------+ | | +-------------------+ |
| | | | +------+ SB NAND | |
| | | +------+-----+ +-------------------+ |
| | | | |
| | | | |
| +------------------+ +------------+ +------+-----+ +-------------------+ |
| | Network Engine | | | | +------- SB SPI-0/SPI-1 | |
| | Security Engine | | PCIe, MSS | | RUNIT | +-------------------+ |
| | SATA, USB | | DMA | | Windows | +-------------------+ |
| | SD/eMMC | | | | Lookup +------- SB Device Bus | |
| | TDM, I2C | | | | | +-------------------+ |
| +------------------+ +------------+ +------------+ |
| |
+--------------------------------------------------------------------------------------------------+

View File

@ -0,0 +1,45 @@
AMB - AXI MBUS address decoding
-------------------------------
AXI to M-bridge decoding unit driver for Marvell Armada 8K and 8K+ SoCs.
- The Runit offers a second level of address windows lookup. It is used to map transaction towards
the CD BootROM, SPI0, SPI1 and Device bus (NOR).
- The Runit contains eight configurable windows. Each window defines a contiguous,
address space and the properties associated with that address space.
Unit Bank ATTR
Device-Bus DEV_BOOT_CS 0x2F
DEV_CS0 0x3E
DEV_CS1 0x3D
DEV_CS2 0x3B
DEV_CS3 0x37
SPI-0 SPI_A_CS0 0x1E
SPI_A_CS1 0x5E
SPI_A_CS2 0x9E
SPI_A_CS3 0xDE
SPI_A_CS4 0x1F
SPI_A_CS5 0x5F
SPI_A_CS6 0x9F
SPI_A_CS7 0xDF
SPI1 SPI_B_CS0 0x1A
SPI_B_CS1 0x5A
SPI_B_CS2 0x9A
SPI_B_CS3 0xDA
BOOT_ROM BOOT_ROM 0x1D
UART UART 0x01
Mandatory functions:
- marvell_get_amb_memory_map
returns the AMB windows configuration and the number of windows
Mandatory structures:
amb_memory_map - Array that include the configuration of the windows
every window/entry is a struct which has 2 parameters:
- base address of the window
- Attribute of the window
Examples:
struct addr_map_win amb_memory_map[] = {
{0xf900, AMB_DEV_CS0_ID},
};

View File

@ -0,0 +1,23 @@
Marvell CCU address decoding bindings
=====================================
CCU configration driver (1st stage address translation) for Marvell Armada 8K and 8K+ SoCs.
The CCU node includes a description of the address decoding configuration.
Mandatory functions:
- marvell_get_ccu_memory_map
return the CCU windows configuration and the number of windows
of the specific AP.
Mandatory structures:
ccu_memory_map - Array that includes the configuration of the windows
every window/entry is a struct which has 3 parameters:
- Base address of the window
- Size of the window
- Target-ID of the window
Example:
struct addr_map_win ccu_memory_map[] = {
{0x00000000f2000000, 0x00000000e000000, IO_0_TID}, /* IO window */
};

View File

@ -0,0 +1,35 @@
Marvell IO WIN address decoding bindings
=====================================
IO Window configration driver (2nd stage address translation) for Marvell Armada 8K and 8K+ SoCs.
The IO WIN includes a description of the address decoding configuration.
Transactions that are decoded by CCU windows as IO peripheral, have an additional
layer of decoding. This additional address decoding layer defines one of the
following targets:
0x0 = BootRom
0x1 = STM (Serial Trace Macro-cell, a programmer's port into trace stream)
0x2 = SPI direct access
0x3 = PCIe registers
0x4 = MCI Port
0x5 = PCIe port
Mandatory functions:
- marvell_get_io_win_memory_map
returns the IO windows configuration and the number of windows
of the specific AP.
Mandatory structures:
io_win_memory_map - Array that include the configuration of the windows
every window/entry is a struct which has 3 parameters:
- Base address of the window
- Size of the window
- Target-ID of the window
Example:
struct addr_map_win io_win_memory_map[] = {
{0x00000000fe000000, 0x000000001f00000, PCIE_PORT_TID}, /* PCIe window 31Mb for PCIe port*/
{0x00000000ffe00000, 0x000000000100000, PCIE_REGS_TID}, /* PCI-REG window 64Kb for PCIe-reg*/
{0x00000000f6000000, 0x000000000100000, MCIPHY_TID}, /* MCI window 1Mb for PHY-reg*/
};

View File

@ -0,0 +1,40 @@
Marvell IOB address decoding bindings
=====================================
IO bridge configration driver (3rd stage address translation) for Marvell Armada 8K and 8K+ SoCs.
The IOB includes a description of the address decoding configuration.
IOB supports up to n (in CP110 n=24) windows for external memory transaction.
When a transaction passes through the IOB, its address is compared to each of
the enabled windows. If there is a hit and it passes the security checks, it is
advanced to the target port.
Mandatory functions:
- marvell_get_iob_memory_map
returns the IOB windows configuration and the number of windows
Mandatory structures:
iob_memory_map - Array that include the configuration of the windows
every window/entry is a struct which has 3 parameters:
- Base address of the window
- Size of the window
- Target-ID of the window
Target ID options:
- 0x0 = Internal configuration space
- 0x1 = MCI0
- 0x2 = PEX1_X1
- 0x3 = PEX2_X1
- 0x4 = PEX0_X4
- 0x5 = NAND flash
- 0x6 = RUNIT (NOR/SPI/BootRoom)
- 0x7 = MCI1
Example:
struct addr_map_win iob_memory_map[] = {
{0x00000000f7000000, 0x0000000001000000, PEX1_TID}, /* PEX1_X1 window */
{0x00000000f8000000, 0x0000000001000000, PEX2_TID}, /* PEX2_X1 window */
{0x00000000f6000000, 0x0000000001000000, PEX0_TID}, /* PEX0_X4 window */
{0x00000000f9000000, 0x0000000001000000, NAND_TID} /* NAND window */
};

156
drivers/marvell/amb_adec.c Normal file
View File

@ -0,0 +1,156 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
/* AXI to M-Bridge decoding unit driver for Marvell Armada 8K and 8K+ SoCs */
#include <a8k_common.h>
#include <debug.h>
#include <mmio.h>
#include <mvebu.h>
#include <mvebu_def.h>
#if LOG_LEVEL >= LOG_LEVEL_INFO
#define DEBUG_ADDR_MAP
#endif
/* common defines */
#define WIN_ENABLE_BIT (0x1)
#define MVEBU_AMB_ADEC_OFFSET (0x70ff00)
#define AMB_WIN_CR_OFFSET(win) (amb_base + 0x0 + (0x8 * win))
#define AMB_ATTR_OFFSET 8
#define AMB_ATTR_MASK 0xFF
#define AMB_SIZE_OFFSET 16
#define AMB_SIZE_MASK 0xFF
#define AMB_WIN_BASE_OFFSET(win) (amb_base + 0x4 + (0x8 * win))
#define AMB_BASE_OFFSET 16
#define AMB_BASE_ADDR_MASK ((1 << (32 - AMB_BASE_OFFSET)) - 1)
#define AMB_WIN_ALIGNMENT_64K (0x10000)
#define AMB_WIN_ALIGNMENT_1M (0x100000)
uintptr_t amb_base;
static void amb_check_win(struct addr_map_win *win, uint32_t win_num)
{
uint32_t base_addr;
/* make sure the base address is in 16-bit range */
if (win->base_addr > AMB_BASE_ADDR_MASK) {
WARN("Window %d: base address is too big 0x%llx\n",
win_num, win->base_addr);
win->base_addr = AMB_BASE_ADDR_MASK;
WARN("Set the base address to 0x%llx\n", win->base_addr);
}
base_addr = win->base_addr << AMB_BASE_OFFSET;
/* for AMB The base is always 1M aligned */
/* check if address is aligned to 1M */
if (IS_NOT_ALIGN(base_addr, AMB_WIN_ALIGNMENT_1M)) {
win->base_addr = ALIGN_UP(base_addr, AMB_WIN_ALIGNMENT_1M);
WARN("Window %d: base address unaligned to 0x%x\n",
win_num, AMB_WIN_ALIGNMENT_1M);
WARN("Align up the base address to 0x%llx\n", win->base_addr);
}
/* size parameter validity check */
if (!IS_POWER_OF_2(win->win_size)) {
WARN("Window %d: window size is not power of 2 (0x%llx)\n",
win_num, win->win_size);
win->win_size = ROUND_UP_TO_POW_OF_2(win->win_size);
WARN("Rounding size to 0x%llx\n", win->win_size);
}
}
static void amb_enable_win(struct addr_map_win *win, uint32_t win_num)
{
uint32_t ctrl, base, size;
/*
* size is 64KB granularity.
* The number of ones specifies the size of the
* window in 64 KB granularity. 0 is 64KB
*/
size = (win->win_size / AMB_WIN_ALIGNMENT_64K) - 1;
ctrl = (size << AMB_SIZE_OFFSET) | (win->target_id << AMB_ATTR_OFFSET);
base = win->base_addr << AMB_BASE_OFFSET;
mmio_write_32(AMB_WIN_BASE_OFFSET(win_num), base);
mmio_write_32(AMB_WIN_CR_OFFSET(win_num), ctrl);
/* enable window after configuring window size (and attributes) */
ctrl |= WIN_ENABLE_BIT;
mmio_write_32(AMB_WIN_CR_OFFSET(win_num), ctrl);
}
#ifdef DEBUG_ADDR_MAP
static void dump_amb_adec(void)
{
uint32_t ctrl, base, win_id, attr;
uint32_t size, size_count;
/* Dump all AMB windows */
tf_printf("bank attribute base size\n");
tf_printf("--------------------------------------------\n");
for (win_id = 0; win_id < AMB_MAX_WIN_ID; win_id++) {
ctrl = mmio_read_32(AMB_WIN_CR_OFFSET(win_id));
if (ctrl & WIN_ENABLE_BIT) {
base = mmio_read_32(AMB_WIN_BASE_OFFSET(win_id));
attr = (ctrl >> AMB_ATTR_OFFSET) & AMB_ATTR_MASK;
size_count = (ctrl >> AMB_SIZE_OFFSET) & AMB_SIZE_MASK;
size = (size_count + 1) * AMB_WIN_ALIGNMENT_64K;
tf_printf("amb 0x%04x 0x%08x 0x%08x\n",
attr, base, size);
}
}
}
#endif
int init_amb_adec(uintptr_t base)
{
struct addr_map_win *win;
uint32_t win_id, win_reg;
uint32_t win_count;
INFO("Initializing AXI to MBus Bridge Address decoding\n");
/* Get the base address of the AMB address decoding */
amb_base = base + MVEBU_AMB_ADEC_OFFSET;
/* Get the array of the windows and its size */
marvell_get_amb_memory_map(&win, &win_count, base);
if (win_count <= 0)
INFO("no windows configurations found\n");
if (win_count > AMB_MAX_WIN_ID) {
INFO("number of windows is bigger than %d\n", AMB_MAX_WIN_ID);
return 0;
}
/* disable all AMB windows */
for (win_id = 0; win_id < AMB_MAX_WIN_ID; win_id++) {
win_reg = mmio_read_32(AMB_WIN_CR_OFFSET(win_id));
win_reg &= ~WIN_ENABLE_BIT;
mmio_write_32(AMB_WIN_CR_OFFSET(win_id), win_reg);
}
/* enable relevant windows */
for (win_id = 0; win_id < win_count; win_id++, win++) {
amb_check_win(win, win_id);
amb_enable_win(win, win_id);
}
#ifdef DEBUG_ADDR_MAP
dump_amb_adec();
#endif
INFO("Done AXI to MBus Bridge Address decoding Initializing\n");
return 0;
}

361
drivers/marvell/ccu.c Normal file
View File

@ -0,0 +1,361 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
/* CCU unit device driver for Marvell AP807, AP807 and AP810 SoCs */
#include <a8k_common.h>
#include <ccu.h>
#include <debug.h>
#include <mmio.h>
#include <mvebu.h>
#include <mvebu_def.h>
#if LOG_LEVEL >= LOG_LEVEL_INFO
#define DEBUG_ADDR_MAP
#endif
/* common defines */
#define WIN_ENABLE_BIT (0x1)
/* Physical address of the base of the window = {AddrLow[19:0],20h0} */
#define ADDRESS_SHIFT (20 - 4)
#define ADDRESS_MASK (0xFFFFFFF0)
#define CCU_WIN_ALIGNMENT (0x100000)
#define IS_DRAM_TARGET(tgt) ((((tgt) == DRAM_0_TID) || \
((tgt) == DRAM_1_TID) || \
((tgt) == RAR_TID)) ? 1 : 0)
/* For storage of CR, SCR, ALR, AHR abd GCR */
static uint32_t ccu_regs_save[MVEBU_CCU_MAX_WINS * 4 + 1];
#ifdef DEBUG_ADDR_MAP
static void dump_ccu(int ap_index)
{
uint32_t win_id, win_cr, alr, ahr;
uint8_t target_id;
uint64_t start, end;
/* Dump all AP windows */
tf_printf("\tbank target start end\n");
tf_printf("\t----------------------------------------------------\n");
for (win_id = 0; win_id < MVEBU_CCU_MAX_WINS; win_id++) {
win_cr = mmio_read_32(CCU_WIN_CR_OFFSET(ap_index, win_id));
if (win_cr & WIN_ENABLE_BIT) {
target_id = (win_cr >> CCU_TARGET_ID_OFFSET) &
CCU_TARGET_ID_MASK;
alr = mmio_read_32(CCU_WIN_ALR_OFFSET(ap_index,
win_id));
ahr = mmio_read_32(CCU_WIN_AHR_OFFSET(ap_index,
win_id));
start = ((uint64_t)alr << ADDRESS_SHIFT);
end = (((uint64_t)ahr + 0x10) << ADDRESS_SHIFT);
tf_printf("\tccu %02x 0x%016llx 0x%016llx\n",
target_id, start, end);
}
}
win_cr = mmio_read_32(CCU_WIN_GCR_OFFSET(ap_index));
target_id = (win_cr >> CCU_GCR_TARGET_OFFSET) & CCU_GCR_TARGET_MASK;
tf_printf("\tccu GCR %d - all other transactions\n", target_id);
}
#endif
void ccu_win_check(struct addr_map_win *win)
{
/* check if address is aligned to 1M */
if (IS_NOT_ALIGN(win->base_addr, CCU_WIN_ALIGNMENT)) {
win->base_addr = ALIGN_UP(win->base_addr, CCU_WIN_ALIGNMENT);
NOTICE("%s: Align up the base address to 0x%llx\n",
__func__, win->base_addr);
}
/* size parameter validity check */
if (IS_NOT_ALIGN(win->win_size, CCU_WIN_ALIGNMENT)) {
win->win_size = ALIGN_UP(win->win_size, CCU_WIN_ALIGNMENT);
NOTICE("%s: Aligning size to 0x%llx\n",
__func__, win->win_size);
}
}
void ccu_enable_win(int ap_index, struct addr_map_win *win, uint32_t win_id)
{
uint32_t ccu_win_reg;
uint32_t alr, ahr;
uint64_t end_addr;
if ((win_id == 0) || (win_id > MVEBU_CCU_MAX_WINS)) {
ERROR("Enabling wrong CCU window %d!\n", win_id);
return;
}
end_addr = (win->base_addr + win->win_size - 1);
alr = (uint32_t)((win->base_addr >> ADDRESS_SHIFT) & ADDRESS_MASK);
ahr = (uint32_t)((end_addr >> ADDRESS_SHIFT) & ADDRESS_MASK);
mmio_write_32(CCU_WIN_ALR_OFFSET(ap_index, win_id), alr);
mmio_write_32(CCU_WIN_AHR_OFFSET(ap_index, win_id), ahr);
ccu_win_reg = WIN_ENABLE_BIT;
ccu_win_reg |= (win->target_id & CCU_TARGET_ID_MASK)
<< CCU_TARGET_ID_OFFSET;
mmio_write_32(CCU_WIN_CR_OFFSET(ap_index, win_id), ccu_win_reg);
}
static void ccu_disable_win(int ap_index, uint32_t win_id)
{
uint32_t win_reg;
if ((win_id == 0) || (win_id > MVEBU_CCU_MAX_WINS)) {
ERROR("Disabling wrong CCU window %d!\n", win_id);
return;
}
win_reg = mmio_read_32(CCU_WIN_CR_OFFSET(ap_index, win_id));
win_reg &= ~WIN_ENABLE_BIT;
mmio_write_32(CCU_WIN_CR_OFFSET(ap_index, win_id), win_reg);
}
/* Insert/Remove temporary window for using the out-of reset default
* CPx base address to access the CP configuration space prior to
* the further base address update in accordance with address mapping
* design.
*
* NOTE: Use the same window array for insertion and removal of
* temporary windows.
*/
void ccu_temp_win_insert(int ap_index, struct addr_map_win *win, int size)
{
uint32_t win_id;
for (int i = 0; i < size; i++) {
win_id = MVEBU_CCU_MAX_WINS - 1 - i;
ccu_win_check(win);
ccu_enable_win(ap_index, win, win_id);
win++;
}
}
/*
* NOTE: Use the same window array for insertion and removal of
* temporary windows.
*/
void ccu_temp_win_remove(int ap_index, struct addr_map_win *win, int size)
{
uint32_t win_id;
for (int i = 0; i < size; i++) {
uint64_t base;
uint32_t target;
win_id = MVEBU_CCU_MAX_WINS - 1 - i;
target = mmio_read_32(CCU_WIN_CR_OFFSET(ap_index, win_id));
target >>= CCU_TARGET_ID_OFFSET;
target &= CCU_TARGET_ID_MASK;
base = mmio_read_32(CCU_WIN_ALR_OFFSET(ap_index, win_id));
base <<= ADDRESS_SHIFT;
if ((win->target_id != target) || (win->base_addr != base)) {
ERROR("%s: Trying to remove bad window-%d!\n",
__func__, win_id);
continue;
}
ccu_disable_win(ap_index, win_id);
win++;
}
}
/* Returns current DRAM window target (DRAM_0_TID, DRAM_1_TID, RAR_TID)
* NOTE: Call only once for each AP.
* The AP0 DRAM window is located at index 2 only at the BL31 execution start.
* Then it relocated to index 1 for matching the rest of APs DRAM settings.
* Calling this function after relocation will produce wrong results on AP0
*/
static uint32_t ccu_dram_target_get(int ap_index)
{
/* On BLE stage the AP0 DRAM window is opened by the BootROM at index 2.
* All the rest of detected APs will use window at index 1.
* The AP0 DRAM window is moved from index 2 to 1 during
* init_ccu() execution.
*/
const uint32_t win_id = (ap_index == 0) ? 2 : 1;
uint32_t target;
target = mmio_read_32(CCU_WIN_CR_OFFSET(ap_index, win_id));
target >>= CCU_TARGET_ID_OFFSET;
target &= CCU_TARGET_ID_MASK;
return target;
}
void ccu_dram_target_set(int ap_index, uint32_t target)
{
/* On BLE stage the AP0 DRAM window is opened by the BootROM at index 2.
* All the rest of detected APs will use window at index 1.
* The AP0 DRAM window is moved from index 2 to 1
* during init_ccu() execution.
*/
const uint32_t win_id = (ap_index == 0) ? 2 : 1;
uint32_t dram_cr;
dram_cr = mmio_read_32(CCU_WIN_CR_OFFSET(ap_index, win_id));
dram_cr &= ~(CCU_TARGET_ID_MASK << CCU_TARGET_ID_OFFSET);
dram_cr |= (target & CCU_TARGET_ID_MASK) << CCU_TARGET_ID_OFFSET;
mmio_write_32(CCU_WIN_CR_OFFSET(ap_index, win_id), dram_cr);
}
/* Setup CCU DRAM window and enable it */
void ccu_dram_win_config(int ap_index, struct addr_map_win *win)
{
#if IMAGE_BLE /* BLE */
/* On BLE stage the AP0 DRAM window is opened by the BootROM at index 2.
* Since the BootROM is not accessing DRAM at BLE stage,
* the DRAM window can be temporarely disabled.
*/
const uint32_t win_id = (ap_index == 0) ? 2 : 1;
#else /* end of BLE */
/* At the ccu_init() execution stage, DRAM windows of all APs
* are arranged at index 1.
* The AP0 still has the old window BootROM DRAM at index 2, so
* the window-1 can be safely disabled without breaking the DRAM access.
*/
const uint32_t win_id = 1;
#endif
ccu_disable_win(ap_index, win_id);
/* enable write secure (and clear read secure) */
mmio_write_32(CCU_WIN_SCR_OFFSET(ap_index, win_id),
CCU_WIN_ENA_WRITE_SECURE);
ccu_win_check(win);
ccu_enable_win(ap_index, win, win_id);
}
/* Save content of CCU window + GCR */
static void ccu_save_win_range(int ap_id, int win_first,
int win_last, uint32_t *buffer)
{
int win_id, idx;
/* Save CCU */
for (idx = 0, win_id = win_first; win_id <= win_last; win_id++) {
buffer[idx++] = mmio_read_32(CCU_WIN_CR_OFFSET(ap_id, win_id));
buffer[idx++] = mmio_read_32(CCU_WIN_SCR_OFFSET(ap_id, win_id));
buffer[idx++] = mmio_read_32(CCU_WIN_ALR_OFFSET(ap_id, win_id));
buffer[idx++] = mmio_read_32(CCU_WIN_AHR_OFFSET(ap_id, win_id));
}
buffer[idx] = mmio_read_32(CCU_WIN_GCR_OFFSET(ap_id));
}
/* Restore content of CCU window + GCR */
static void ccu_restore_win_range(int ap_id, int win_first,
int win_last, uint32_t *buffer)
{
int win_id, idx;
/* Restore CCU */
for (idx = 0, win_id = win_first; win_id <= win_last; win_id++) {
mmio_write_32(CCU_WIN_CR_OFFSET(ap_id, win_id), buffer[idx++]);
mmio_write_32(CCU_WIN_SCR_OFFSET(ap_id, win_id), buffer[idx++]);
mmio_write_32(CCU_WIN_ALR_OFFSET(ap_id, win_id), buffer[idx++]);
mmio_write_32(CCU_WIN_AHR_OFFSET(ap_id, win_id), buffer[idx++]);
}
mmio_write_32(CCU_WIN_GCR_OFFSET(ap_id), buffer[idx]);
}
void ccu_save_win_all(int ap_id)
{
ccu_save_win_range(ap_id, 0, MVEBU_CCU_MAX_WINS - 1, ccu_regs_save);
}
void ccu_restore_win_all(int ap_id)
{
ccu_restore_win_range(ap_id, 0, MVEBU_CCU_MAX_WINS - 1, ccu_regs_save);
}
int init_ccu(int ap_index)
{
struct addr_map_win *win, *dram_win;
uint32_t win_id, win_reg;
uint32_t win_count, array_id;
uint32_t dram_target;
#if IMAGE_BLE
/* In BootROM context CCU Window-1
* has SRAM_TID target and should not be disabled
*/
const uint32_t win_start = 2;
#else
const uint32_t win_start = 1;
#endif
INFO("Initializing CCU Address decoding\n");
/* Get the array of the windows and fill the map data */
marvell_get_ccu_memory_map(ap_index, &win, &win_count);
if (win_count <= 0) {
INFO("No windows configurations found\n");
} else if (win_count > (MVEBU_CCU_MAX_WINS - 1)) {
ERROR("CCU mem map array > than max available windows (%d)\n",
MVEBU_CCU_MAX_WINS);
win_count = MVEBU_CCU_MAX_WINS;
}
/* Need to set GCR to DRAM before all CCU windows are disabled for
* securing the normal access to DRAM location, which the ATF is running
* from. Once all CCU windows are set, which have to include the
* dedicated DRAM window as well, the GCR can be switched to the target
* defined by the platform configuration.
*/
dram_target = ccu_dram_target_get(ap_index);
win_reg = (dram_target & CCU_GCR_TARGET_MASK) << CCU_GCR_TARGET_OFFSET;
mmio_write_32(CCU_WIN_GCR_OFFSET(ap_index), win_reg);
/* If the DRAM window was already configured at the BLE stage,
* only the window target considered valid, the address range should be
* updated according to the platform configuration.
*/
for (dram_win = win, array_id = 0; array_id < win_count;
array_id++, dram_win++) {
if (IS_DRAM_TARGET(dram_win->target_id)) {
dram_win->target_id = dram_target;
break;
}
}
/* Disable all AP CCU windows
* Window-0 is always bypassed since it already contains
* data allowing the internal configuration space access
*/
for (win_id = win_start; win_id < MVEBU_CCU_MAX_WINS; win_id++) {
ccu_disable_win(ap_index, win_id);
/* enable write secure (and clear read secure) */
mmio_write_32(CCU_WIN_SCR_OFFSET(ap_index, win_id),
CCU_WIN_ENA_WRITE_SECURE);
}
/* win_id is the index of the current ccu window
* array_id is the index of the current memory map window entry
*/
for (win_id = win_start, array_id = 0;
((win_id < MVEBU_CCU_MAX_WINS) && (array_id < win_count));
win_id++) {
ccu_win_check(win);
ccu_enable_win(ap_index, win, win_id);
win++;
array_id++;
}
/* Get & set the default target according to board topology */
win_reg = (marvell_get_ccu_gcr_target(ap_index) & CCU_GCR_TARGET_MASK)
<< CCU_GCR_TARGET_OFFSET;
mmio_write_32(CCU_WIN_GCR_OFFSET(ap_index), win_reg);
#ifdef DEBUG_ADDR_MAP
dump_ccu(ap_index);
#endif
INFO("Done CCU Address decoding Initializing\n");
return 0;
}

227
drivers/marvell/gwin.c Normal file
View File

@ -0,0 +1,227 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
/* GWIN unit device driver for Marvell AP810 SoC */
#include <a8k_common.h>
#include <debug.h>
#include <gwin.h>
#include <mmio.h>
#include <mvebu.h>
#include <mvebu_def.h>
#if LOG_LEVEL >= LOG_LEVEL_INFO
#define DEBUG_ADDR_MAP
#endif
/* common defines */
#define WIN_ENABLE_BIT (0x1)
#define WIN_TARGET_MASK (0xF)
#define WIN_TARGET_SHIFT (0x8)
#define WIN_TARGET(tgt) (((tgt) & WIN_TARGET_MASK) \
<< WIN_TARGET_SHIFT)
/* Bits[43:26] of the physical address are the window base,
* which is aligned to 64MB
*/
#define ADDRESS_RSHIFT (26)
#define ADDRESS_LSHIFT (10)
#define GWIN_ALIGNMENT_64M (0x4000000)
/* AP registers */
#define GWIN_CR_OFFSET(ap, win) (MVEBU_GWIN_BASE(ap) + 0x0 + \
(0x10 * (win)))
#define GWIN_ALR_OFFSET(ap, win) (MVEBU_GWIN_BASE(ap) + 0x8 + \
(0x10 * (win)))
#define GWIN_AHR_OFFSET(ap, win) (MVEBU_GWIN_BASE(ap) + 0xc + \
(0x10 * (win)))
#define CCU_GRU_CR_OFFSET(ap) (MVEBU_CCU_GRU_BASE(ap))
#define CCR_GRU_CR_GWIN_MBYPASS (1 << 1)
static void gwin_check(struct addr_map_win *win)
{
/* The base is always 64M aligned */
if (IS_NOT_ALIGN(win->base_addr, GWIN_ALIGNMENT_64M)) {
win->base_addr &= ~(GWIN_ALIGNMENT_64M - 1);
NOTICE("%s: Align the base address to 0x%llx\n",
__func__, win->base_addr);
}
/* size parameter validity check */
if (IS_NOT_ALIGN(win->win_size, GWIN_ALIGNMENT_64M)) {
win->win_size = ALIGN_UP(win->win_size, GWIN_ALIGNMENT_64M);
NOTICE("%s: Aligning window size to 0x%llx\n",
__func__, win->win_size);
}
}
static void gwin_enable_window(int ap_index, struct addr_map_win *win,
uint32_t win_num)
{
uint32_t alr, ahr;
uint64_t end_addr;
if ((win->target_id & WIN_TARGET_MASK) != win->target_id) {
ERROR("target ID = %d, is invalid\n", win->target_id);
return;
}
/* calculate 64bit end-address */
end_addr = (win->base_addr + win->win_size - 1);
alr = (uint32_t)((win->base_addr >> ADDRESS_RSHIFT) << ADDRESS_LSHIFT);
ahr = (uint32_t)((end_addr >> ADDRESS_RSHIFT) << ADDRESS_LSHIFT);
/* write start address and end address for GWIN */
mmio_write_32(GWIN_ALR_OFFSET(ap_index, win_num), alr);
mmio_write_32(GWIN_AHR_OFFSET(ap_index, win_num), ahr);
/* write the target ID and enable the window */
mmio_write_32(GWIN_CR_OFFSET(ap_index, win_num),
WIN_TARGET(win->target_id) | WIN_ENABLE_BIT);
}
static void gwin_disable_window(int ap_index, uint32_t win_num)
{
uint32_t win_reg;
win_reg = mmio_read_32(GWIN_CR_OFFSET(ap_index, win_num));
win_reg &= ~WIN_ENABLE_BIT;
mmio_write_32(GWIN_CR_OFFSET(ap_index, win_num), win_reg);
}
/* Insert/Remove temporary window for using the out-of reset default
* CPx base address to access the CP configuration space prior to
* the further base address update in accordance with address mapping
* design.
*
* NOTE: Use the same window array for insertion and removal of
* temporary windows.
*/
void gwin_temp_win_insert(int ap_index, struct addr_map_win *win, int size)
{
uint32_t win_id;
for (int i = 0; i < size; i++) {
win_id = MVEBU_GWIN_MAX_WINS - i - 1;
gwin_check(win);
gwin_enable_window(ap_index, win, win_id);
win++;
}
}
/*
* NOTE: Use the same window array for insertion and removal of
* temporary windows.
*/
void gwin_temp_win_remove(int ap_index, struct addr_map_win *win, int size)
{
uint32_t win_id;
for (int i = 0; i < size; i++) {
uint64_t base;
uint32_t target;
win_id = MVEBU_GWIN_MAX_WINS - i - 1;
target = mmio_read_32(GWIN_CR_OFFSET(ap_index, win_id));
target >>= WIN_TARGET_SHIFT;
target &= WIN_TARGET_MASK;
base = mmio_read_32(GWIN_ALR_OFFSET(ap_index, win_id));
base >>= ADDRESS_LSHIFT;
base <<= ADDRESS_RSHIFT;
if (win->target_id != target) {
ERROR("%s: Trying to remove bad window-%d!\n",
__func__, win_id);
continue;
}
gwin_disable_window(ap_index, win_id);
win++;
}
}
#ifdef DEBUG_ADDR_MAP
static void dump_gwin(int ap_index)
{
uint32_t win_num;
/* Dump all GWIN windows */
tf_printf("\tbank target start end\n");
tf_printf("\t----------------------------------------------------\n");
for (win_num = 0; win_num < MVEBU_GWIN_MAX_WINS; win_num++) {
uint32_t cr;
uint64_t alr, ahr;
cr = mmio_read_32(GWIN_CR_OFFSET(ap_index, win_num));
/* Window enabled */
if (cr & WIN_ENABLE_BIT) {
alr = mmio_read_32(GWIN_ALR_OFFSET(ap_index, win_num));
alr = (alr >> ADDRESS_LSHIFT) << ADDRESS_RSHIFT;
ahr = mmio_read_32(GWIN_AHR_OFFSET(ap_index, win_num));
ahr = (ahr >> ADDRESS_LSHIFT) << ADDRESS_RSHIFT;
tf_printf("\tgwin %d 0x%016llx 0x%016llx\n",
(cr >> 8) & 0xF, alr, ahr);
}
}
}
#endif
int init_gwin(int ap_index)
{
struct addr_map_win *win;
uint32_t win_id;
uint32_t win_count;
uint32_t win_reg;
INFO("Initializing GWIN Address decoding\n");
/* Get the array of the windows and its size */
marvell_get_gwin_memory_map(ap_index, &win, &win_count);
if (win_count <= 0) {
INFO("no windows configurations found\n");
return 0;
}
if (win_count > MVEBU_GWIN_MAX_WINS) {
ERROR("number of windows is bigger than %d\n",
MVEBU_GWIN_MAX_WINS);
return 0;
}
/* disable all windows */
for (win_id = 0; win_id < MVEBU_GWIN_MAX_WINS; win_id++)
gwin_disable_window(ap_index, win_id);
/* enable relevant windows */
for (win_id = 0; win_id < win_count; win_id++, win++) {
gwin_check(win);
gwin_enable_window(ap_index, win, win_id);
}
/* GWIN Miss feature has not verified, therefore any access towards
* remote AP should be accompanied with proper configuration to
* GWIN registers group and therefore the GWIN Miss feature
* should be set into Bypass mode, need to make sure all GWIN regions
* are defined correctly that will assure no GWIN miss occurrance
* JIRA-AURORA2-1630
*/
INFO("Update GWIN miss bypass\n");
win_reg = mmio_read_32(CCU_GRU_CR_OFFSET(ap_index));
win_reg |= CCR_GRU_CR_GWIN_MBYPASS;
mmio_write_32(CCU_GRU_CR_OFFSET(ap_index), win_reg);
#ifdef DEBUG_ADDR_MAP
dump_gwin(ap_index);
#endif
INFO("Done GWIN Address decoding Initializing\n");
return 0;
}

267
drivers/marvell/io_win.c Normal file
View File

@ -0,0 +1,267 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
/* IO Window unit device driver for Marvell AP807, AP807 and AP810 SoCs */
#include <a8k_common.h>
#include <debug.h>
#include <io_win.h>
#include <mmio.h>
#include <mvebu.h>
#include <mvebu_def.h>
#if LOG_LEVEL >= LOG_LEVEL_INFO
#define DEBUG_ADDR_MAP
#endif
/* common defines */
#define WIN_ENABLE_BIT (0x1)
/* Physical address of the base of the window = {Addr[19:0],20`h0} */
#define ADDRESS_SHIFT (20 - 4)
#define ADDRESS_MASK (0xFFFFFFF0)
#define IO_WIN_ALIGNMENT_1M (0x100000)
#define IO_WIN_ALIGNMENT_64K (0x10000)
/* AP registers */
#define IO_WIN_ALR_OFFSET(ap, win) (MVEBU_IO_WIN_BASE(ap) + 0x0 + \
(0x10 * win))
#define IO_WIN_AHR_OFFSET(ap, win) (MVEBU_IO_WIN_BASE(ap) + 0x8 + \
(0x10 * win))
#define IO_WIN_CR_OFFSET(ap, win) (MVEBU_IO_WIN_BASE(ap) + 0xC + \
(0x10 * win))
/* For storage of CR, ALR, AHR abd GCR */
static uint32_t io_win_regs_save[MVEBU_IO_WIN_MAX_WINS * 3 + 1];
static void io_win_check(struct addr_map_win *win)
{
/* for IO The base is always 1M aligned */
/* check if address is aligned to 1M */
if (IS_NOT_ALIGN(win->base_addr, IO_WIN_ALIGNMENT_1M)) {
win->base_addr = ALIGN_UP(win->base_addr, IO_WIN_ALIGNMENT_1M);
NOTICE("%s: Align up the base address to 0x%llx\n",
__func__, win->base_addr);
}
/* size parameter validity check */
if (IS_NOT_ALIGN(win->win_size, IO_WIN_ALIGNMENT_1M)) {
win->win_size = ALIGN_UP(win->win_size, IO_WIN_ALIGNMENT_1M);
NOTICE("%s: Aligning size to 0x%llx\n",
__func__, win->win_size);
}
}
static void io_win_enable_window(int ap_index, struct addr_map_win *win,
uint32_t win_num)
{
uint32_t alr, ahr;
uint64_t end_addr;
if (win->target_id < 0 || win->target_id >= MVEBU_IO_WIN_MAX_WINS) {
ERROR("target ID = %d, is invalid\n", win->target_id);
return;
}
if ((win_num == 0) || (win_num > MVEBU_IO_WIN_MAX_WINS)) {
ERROR("Enabling wrong IOW window %d!\n", win_num);
return;
}
/* calculate the end-address */
end_addr = (win->base_addr + win->win_size - 1);
alr = (uint32_t)((win->base_addr >> ADDRESS_SHIFT) & ADDRESS_MASK);
alr |= WIN_ENABLE_BIT;
ahr = (uint32_t)((end_addr >> ADDRESS_SHIFT) & ADDRESS_MASK);
/* write start address and end address for IO window */
mmio_write_32(IO_WIN_ALR_OFFSET(ap_index, win_num), alr);
mmio_write_32(IO_WIN_AHR_OFFSET(ap_index, win_num), ahr);
/* write window target */
mmio_write_32(IO_WIN_CR_OFFSET(ap_index, win_num), win->target_id);
}
static void io_win_disable_window(int ap_index, uint32_t win_num)
{
uint32_t win_reg;
if ((win_num == 0) || (win_num > MVEBU_IO_WIN_MAX_WINS)) {
ERROR("Disabling wrong IOW window %d!\n", win_num);
return;
}
win_reg = mmio_read_32(IO_WIN_ALR_OFFSET(ap_index, win_num));
win_reg &= ~WIN_ENABLE_BIT;
mmio_write_32(IO_WIN_ALR_OFFSET(ap_index, win_num), win_reg);
}
/* Insert/Remove temporary window for using the out-of reset default
* CPx base address to access the CP configuration space prior to
* the further base address update in accordance with address mapping
* design.
*
* NOTE: Use the same window array for insertion and removal of
* temporary windows.
*/
void iow_temp_win_insert(int ap_index, struct addr_map_win *win, int size)
{
uint32_t win_id;
for (int i = 0; i < size; i++) {
win_id = MVEBU_IO_WIN_MAX_WINS - i - 1;
io_win_check(win);
io_win_enable_window(ap_index, win, win_id);
win++;
}
}
/*
* NOTE: Use the same window array for insertion and removal of
* temporary windows.
*/
void iow_temp_win_remove(int ap_index, struct addr_map_win *win, int size)
{
uint32_t win_id;
/* Start from the last window and do not touch Win0 */
for (int i = 0; i < size; i++) {
uint64_t base;
uint32_t target;
win_id = MVEBU_IO_WIN_MAX_WINS - i - 1;
target = mmio_read_32(IO_WIN_CR_OFFSET(ap_index, win_id));
base = mmio_read_32(IO_WIN_ALR_OFFSET(ap_index, win_id));
base &= ~WIN_ENABLE_BIT;
base <<= ADDRESS_SHIFT;
if ((win->target_id != target) || (win->base_addr != base)) {
ERROR("%s: Trying to remove bad window-%d!\n",
__func__, win_id);
continue;
}
io_win_disable_window(ap_index, win_id);
win++;
}
}
#ifdef DEBUG_ADDR_MAP
static void dump_io_win(int ap_index)
{
uint32_t trgt_id, win_id;
uint32_t alr, ahr;
uint64_t start, end;
/* Dump all IO windows */
tf_printf("\tbank target start end\n");
tf_printf("\t----------------------------------------------------\n");
for (win_id = 0; win_id < MVEBU_IO_WIN_MAX_WINS; win_id++) {
alr = mmio_read_32(IO_WIN_ALR_OFFSET(ap_index, win_id));
if (alr & WIN_ENABLE_BIT) {
alr &= ~WIN_ENABLE_BIT;
ahr = mmio_read_32(IO_WIN_AHR_OFFSET(ap_index, win_id));
trgt_id = mmio_read_32(IO_WIN_CR_OFFSET(ap_index,
win_id));
start = ((uint64_t)alr << ADDRESS_SHIFT);
end = (((uint64_t)ahr + 0x10) << ADDRESS_SHIFT);
tf_printf("\tio-win %d 0x%016llx 0x%016llx\n",
trgt_id, start, end);
}
}
tf_printf("\tio-win gcr is %x\n",
mmio_read_32(MVEBU_IO_WIN_BASE(ap_index) +
MVEBU_IO_WIN_GCR_OFFSET));
}
#endif
static void iow_save_win_range(int ap_id, int win_first, int win_last,
uint32_t *buffer)
{
int win_id, idx;
/* Save IOW */
for (idx = 0, win_id = win_first; win_id <= win_last; win_id++) {
buffer[idx++] = mmio_read_32(IO_WIN_CR_OFFSET(ap_id, win_id));
buffer[idx++] = mmio_read_32(IO_WIN_ALR_OFFSET(ap_id, win_id));
buffer[idx++] = mmio_read_32(IO_WIN_AHR_OFFSET(ap_id, win_id));
}
buffer[idx] = mmio_read_32(MVEBU_IO_WIN_BASE(ap_id) +
MVEBU_IO_WIN_GCR_OFFSET);
}
static void iow_restore_win_range(int ap_id, int win_first, int win_last,
uint32_t *buffer)
{
int win_id, idx;
/* Restore IOW */
for (idx = 0, win_id = win_first; win_id <= win_last; win_id++) {
mmio_write_32(IO_WIN_CR_OFFSET(ap_id, win_id), buffer[idx++]);
mmio_write_32(IO_WIN_ALR_OFFSET(ap_id, win_id), buffer[idx++]);
mmio_write_32(IO_WIN_AHR_OFFSET(ap_id, win_id), buffer[idx++]);
}
mmio_write_32(MVEBU_IO_WIN_BASE(ap_id) + MVEBU_IO_WIN_GCR_OFFSET,
buffer[idx++]);
}
void iow_save_win_all(int ap_id)
{
iow_save_win_range(ap_id, 0, MVEBU_IO_WIN_MAX_WINS - 1,
io_win_regs_save);
}
void iow_restore_win_all(int ap_id)
{
iow_restore_win_range(ap_id, 0, MVEBU_IO_WIN_MAX_WINS - 1,
io_win_regs_save);
}
int init_io_win(int ap_index)
{
struct addr_map_win *win;
uint32_t win_id, win_reg;
uint32_t win_count;
INFO("Initializing IO WIN Address decoding\n");
/* Get the array of the windows and its size */
marvell_get_io_win_memory_map(ap_index, &win, &win_count);
if (win_count <= 0)
INFO("no windows configurations found\n");
if (win_count > MVEBU_IO_WIN_MAX_WINS) {
INFO("number of windows is bigger than %d\n",
MVEBU_IO_WIN_MAX_WINS);
return 0;
}
/* Get the default target id to set the GCR */
win_reg = marvell_get_io_win_gcr_target(ap_index);
mmio_write_32(MVEBU_IO_WIN_BASE(ap_index) + MVEBU_IO_WIN_GCR_OFFSET,
win_reg);
/* disable all IO windows */
for (win_id = 1; win_id < MVEBU_IO_WIN_MAX_WINS; win_id++)
io_win_disable_window(ap_index, win_id);
/* enable relevant windows, starting from win_id = 1 because
* index 0 dedicated for BootROM
*/
for (win_id = 1; win_id <= win_count; win_id++, win++) {
io_win_check(win);
io_win_enable_window(ap_index, win, win_id);
}
#ifdef DEBUG_ADDR_MAP
dump_io_win(ap_index);
#endif
INFO("Done IO WIN Address decoding Initializing\n");
return 0;
}

195
drivers/marvell/iob.c Normal file
View File

@ -0,0 +1,195 @@
/*
* Copyright (C) 2016 - 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
/* IOW unit device driver for Marvell CP110 and CP115 SoCs */
#include <a8k_common.h>
#include <arch_helpers.h>
#include <debug.h>
#include <iob.h>
#include <mmio.h>
#include <mvebu.h>
#include <mvebu_def.h>
#if LOG_LEVEL >= LOG_LEVEL_INFO
#define DEBUG_ADDR_MAP
#endif
#define MVEBU_IOB_OFFSET (0x190000)
#define MVEBU_IOB_MAX_WINS 16
/* common defines */
#define WIN_ENABLE_BIT (0x1)
/* Physical address of the base of the window = {AddrLow[19:0],20`h0} */
#define ADDRESS_SHIFT (20 - 4)
#define ADDRESS_MASK (0xFFFFFFF0)
#define IOB_WIN_ALIGNMENT (0x100000)
/* IOB registers */
#define IOB_WIN_CR_OFFSET(win) (iob_base + 0x0 + (0x20 * win))
#define IOB_TARGET_ID_OFFSET (8)
#define IOB_TARGET_ID_MASK (0xF)
#define IOB_WIN_SCR_OFFSET(win) (iob_base + 0x4 + (0x20 * win))
#define IOB_WIN_ENA_CTRL_WRITE_SECURE (0x1)
#define IOB_WIN_ENA_CTRL_READ_SECURE (0x2)
#define IOB_WIN_ENA_WRITE_SECURE (0x4)
#define IOB_WIN_ENA_READ_SECURE (0x8)
#define IOB_WIN_ALR_OFFSET(win) (iob_base + 0x8 + (0x20 * win))
#define IOB_WIN_AHR_OFFSET(win) (iob_base + 0xC + (0x20 * win))
uintptr_t iob_base;
static void iob_win_check(struct addr_map_win *win, uint32_t win_num)
{
/* check if address is aligned to the size */
if (IS_NOT_ALIGN(win->base_addr, IOB_WIN_ALIGNMENT)) {
win->base_addr = ALIGN_UP(win->base_addr, IOB_WIN_ALIGNMENT);
ERROR("Window %d: base address unaligned to 0x%x\n",
win_num, IOB_WIN_ALIGNMENT);
tf_printf("Align up the base address to 0x%llx\n",
win->base_addr);
}
/* size parameter validity check */
if (IS_NOT_ALIGN(win->win_size, IOB_WIN_ALIGNMENT)) {
win->win_size = ALIGN_UP(win->win_size, IOB_WIN_ALIGNMENT);
ERROR("Window %d: window size unaligned to 0x%x\n", win_num,
IOB_WIN_ALIGNMENT);
tf_printf("Aligning size to 0x%llx\n", win->win_size);
}
}
static void iob_enable_win(struct addr_map_win *win, uint32_t win_id)
{
uint32_t iob_win_reg;
uint32_t alr, ahr;
uint64_t end_addr;
end_addr = (win->base_addr + win->win_size - 1);
alr = (uint32_t)((win->base_addr >> ADDRESS_SHIFT) & ADDRESS_MASK);
ahr = (uint32_t)((end_addr >> ADDRESS_SHIFT) & ADDRESS_MASK);
mmio_write_32(IOB_WIN_ALR_OFFSET(win_id), alr);
mmio_write_32(IOB_WIN_AHR_OFFSET(win_id), ahr);
iob_win_reg = WIN_ENABLE_BIT;
iob_win_reg |= (win->target_id & IOB_TARGET_ID_MASK)
<< IOB_TARGET_ID_OFFSET;
mmio_write_32(IOB_WIN_CR_OFFSET(win_id), iob_win_reg);
}
#ifdef DEBUG_ADDR_MAP
static void dump_iob(void)
{
uint32_t win_id, win_cr, alr, ahr;
uint8_t target_id;
uint64_t start, end;
char *iob_target_name[IOB_MAX_TID] = {
"CFG ", "MCI0 ", "PEX1 ", "PEX2 ",
"PEX0 ", "NAND ", "RUNIT", "MCI1 " };
/* Dump all IOB windows */
tf_printf("bank id target start end\n");
tf_printf("----------------------------------------------------\n");
for (win_id = 0; win_id < MVEBU_IOB_MAX_WINS; win_id++) {
win_cr = mmio_read_32(IOB_WIN_CR_OFFSET(win_id));
if (win_cr & WIN_ENABLE_BIT) {
target_id = (win_cr >> IOB_TARGET_ID_OFFSET) &
IOB_TARGET_ID_MASK;
alr = mmio_read_32(IOB_WIN_ALR_OFFSET(win_id));
start = ((uint64_t)alr << ADDRESS_SHIFT);
if (win_id != 0) {
ahr = mmio_read_32(IOB_WIN_AHR_OFFSET(win_id));
end = (((uint64_t)ahr + 0x10) << ADDRESS_SHIFT);
} else {
/* Window #0 size is hardcoded to 16MB, as it's
* reserved for CP configuration space.
*/
end = start + (16 << 20);
}
tf_printf("iob %02d %s 0x%016llx 0x%016llx\n",
win_id, iob_target_name[target_id],
start, end);
}
}
}
#endif
void iob_cfg_space_update(int ap_idx, int cp_idx, uintptr_t base,
uintptr_t new_base)
{
debug_enter();
iob_base = base + MVEBU_IOB_OFFSET;
NOTICE("Change the base address of AP%d-CP%d to %lx\n",
ap_idx, cp_idx, new_base);
mmio_write_32(IOB_WIN_ALR_OFFSET(0), new_base >> ADDRESS_SHIFT);
iob_base = new_base + MVEBU_IOB_OFFSET;
/* Make sure the address was configured by the CPU before
* any possible access to the CP.
*/
dsb();
debug_exit();
}
int init_iob(uintptr_t base)
{
struct addr_map_win *win;
uint32_t win_id, win_reg;
uint32_t win_count;
INFO("Initializing IOB Address decoding\n");
/* Get the base address of the address decoding MBUS */
iob_base = base + MVEBU_IOB_OFFSET;
/* Get the array of the windows and fill the map data */
marvell_get_iob_memory_map(&win, &win_count, base);
if (win_count <= 0) {
INFO("no windows configurations found\n");
return 0;
} else if (win_count > (MVEBU_IOB_MAX_WINS - 1)) {
ERROR("IOB mem map array > than max available windows (%d)\n",
MVEBU_IOB_MAX_WINS);
win_count = MVEBU_IOB_MAX_WINS;
}
/* disable all IOB windows, start from win_id = 1
* because can't disable internal register window
*/
for (win_id = 1; win_id < MVEBU_IOB_MAX_WINS; win_id++) {
win_reg = mmio_read_32(IOB_WIN_CR_OFFSET(win_id));
win_reg &= ~WIN_ENABLE_BIT;
mmio_write_32(IOB_WIN_CR_OFFSET(win_id), win_reg);
win_reg = ~IOB_WIN_ENA_CTRL_WRITE_SECURE;
win_reg &= ~IOB_WIN_ENA_CTRL_READ_SECURE;
win_reg &= ~IOB_WIN_ENA_WRITE_SECURE;
win_reg &= ~IOB_WIN_ENA_READ_SECURE;
mmio_write_32(IOB_WIN_SCR_OFFSET(win_id), win_reg);
}
for (win_id = 1; win_id < win_count + 1; win_id++, win++) {
iob_win_check(win, win_id);
iob_enable_win(win, win_id);
}
#ifdef DEBUG_ADDR_MAP
dump_iob();
#endif
INFO("Done IOB Address decoding Initializing\n");
return 0;
}

View File

@ -0,0 +1,21 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
/* Address map types for Marvell address translation unit drivers */
#ifndef _ADDR_MAP_H_
#define _ADDR_MAP_H_
#include <stdint.h>
struct addr_map_win {
uint64_t base_addr;
uint64_t win_size;
uint32_t target_id;
};
#endif /* _ADDR_MAP_H_ */

View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
/* AXI to M-Bridge decoding unit driver for Marvell Armada 8K and 8K+ SoCs */
#ifndef _AMB_ADEC_H_
#define _AMB_ADEC_H_
#include <stdint.h>
enum amb_attribute_ids {
AMB_SPI0_CS0_ID = 0x1E,
AMB_SPI0_CS1_ID = 0x5E,
AMB_SPI0_CS2_ID = 0x9E,
AMB_SPI0_CS3_ID = 0xDE,
AMB_SPI1_CS0_ID = 0x1A,
AMB_SPI1_CS1_ID = 0x5A,
AMB_SPI1_CS2_ID = 0x9A,
AMB_SPI1_CS3_ID = 0xDA,
AMB_DEV_CS0_ID = 0x3E,
AMB_DEV_CS1_ID = 0x3D,
AMB_DEV_CS2_ID = 0x3B,
AMB_DEV_CS3_ID = 0x37,
AMB_BOOT_CS_ID = 0x2f,
AMB_BOOT_ROM_ID = 0x1D,
};
#define AMB_MAX_WIN_ID 7
int init_amb_adec(uintptr_t base);
#endif /* _AMB_ADEC_H_ */

View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
/* CCU unit device driver for Marvell AP807, AP807 and AP810 SoCs */
#ifndef _CCU_H_
#define _CCU_H_
#ifndef __ASSEMBLY__
#include <addr_map.h>
#endif
/* CCU registers definitions */
#define CCU_WIN_CR_OFFSET(ap, win) (MVEBU_CCU_BASE(ap) + 0x0 + \
(0x10 * win))
#define CCU_TARGET_ID_OFFSET (8)
#define CCU_TARGET_ID_MASK (0x7F)
#define CCU_WIN_SCR_OFFSET(ap, win) (MVEBU_CCU_BASE(ap) + 0x4 + \
(0x10 * win))
#define CCU_WIN_ENA_WRITE_SECURE (0x1)
#define CCU_WIN_ENA_READ_SECURE (0x2)
#define CCU_WIN_ALR_OFFSET(ap, win) (MVEBU_CCU_BASE(ap) + 0x8 + \
(0x10 * win))
#define CCU_WIN_AHR_OFFSET(ap, win) (MVEBU_CCU_BASE(ap) + 0xC + \
(0x10 * win))
#define CCU_WIN_GCR_OFFSET(ap) (MVEBU_CCU_BASE(ap) + 0xD0)
#define CCU_GCR_TARGET_OFFSET (8)
#define CCU_GCR_TARGET_MASK (0xFF)
#define CCU_SRAM_WIN_CR CCU_WIN_CR_OFFSET(MVEBU_AP0, 1)
#ifndef __ASSEMBLY__
int init_ccu(int);
void ccu_win_check(struct addr_map_win *win);
void ccu_enable_win(int ap_index, struct addr_map_win *win, uint32_t win_id);
void ccu_temp_win_insert(int ap_index, struct addr_map_win *win, int size);
void ccu_temp_win_remove(int ap_index, struct addr_map_win *win, int size);
void ccu_dram_win_config(int ap_index, struct addr_map_win *win);
void ccu_dram_target_set(int ap_index, uint32_t target);
void ccu_save_win_all(int ap_id);
void ccu_restore_win_all(int ap_id);
#endif
#endif /* _CCU_H_ */

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
/* GWIN unit device driver for Marvell AP810 SoC */
#ifndef _GWIN_H_
#define _GWIN_H_
#include <addr_map.h>
int init_gwin(int ap_index);
void gwin_temp_win_insert(int ap_index, struct addr_map_win *win, int size);
void gwin_temp_win_remove(int ap_index, struct addr_map_win *win, int size);
#endif /* _GWIN_H_ */

View File

@ -0,0 +1,21 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
/* IO Window unit device driver for Marvell AP807, AP807 and AP810 SoCs */
#ifndef _IO_WIN_H_
#define _IO_WIN_H_
#include <addr_map.h>
int init_io_win(int ap_index);
void iow_temp_win_insert(int ap_index, struct addr_map_win *win, int size);
void iow_temp_win_remove(int ap_index, struct addr_map_win *win, int size);
void iow_save_win_all(int ap_id);
void iow_restore_win_all(int ap_id);
#endif /* _IO_WIN_H_ */

View File

@ -0,0 +1,31 @@
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
/* IOW unit device driver for Marvell CP110 and CP115 SoCs */
#ifndef _IOB_H_
#define _IOB_H_
#include <addr_map.h>
enum target_ids_iob {
INTERNAL_TID = 0x0,
MCI0_TID = 0x1,
PEX1_TID = 0x2,
PEX2_TID = 0x3,
PEX0_TID = 0x4,
NAND_TID = 0x5,
RUNIT_TID = 0x6,
MCI1_TID = 0x7,
IOB_MAX_TID
};
int init_iob(uintptr_t base);
void iob_cfg_space_update(int ap_idx, int cp_idx,
uintptr_t base, uintptr_t new_base);
#endif /* _IOB_H_ */