diff --git a/docs/marvell/misc/mvebu-a8k-addr-map.txt b/docs/marvell/misc/mvebu-a8k-addr-map.txt new file mode 100644 index 0000000..586e8b7 --- /dev/null +++ b/docs/marvell/misc/mvebu-a8k-addr-map.txt @@ -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 | | | | | +-------------------+ | +| +------------------+ +------------+ +------------+ | +| | ++--------------------------------------------------------------------------------------------------+ + diff --git a/docs/marvell/misc/mvebu-amb.txt b/docs/marvell/misc/mvebu-amb.txt new file mode 100644 index 0000000..2a7a41e --- /dev/null +++ b/docs/marvell/misc/mvebu-amb.txt @@ -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}, + }; diff --git a/docs/marvell/misc/mvebu-ccu.txt b/docs/marvell/misc/mvebu-ccu.txt new file mode 100644 index 0000000..9764027 --- /dev/null +++ b/docs/marvell/misc/mvebu-ccu.txt @@ -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 */ + }; diff --git a/docs/marvell/misc/mvebu-io-win.txt b/docs/marvell/misc/mvebu-io-win.txt new file mode 100644 index 0000000..c83ad1f --- /dev/null +++ b/docs/marvell/misc/mvebu-io-win.txt @@ -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*/ + }; diff --git a/docs/marvell/misc/mvebu-iob.txt b/docs/marvell/misc/mvebu-iob.txt new file mode 100644 index 0000000..97ec09d --- /dev/null +++ b/docs/marvell/misc/mvebu-iob.txt @@ -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 */ + }; diff --git a/drivers/marvell/amb_adec.c b/drivers/marvell/amb_adec.c new file mode 100644 index 0000000..06a1957 --- /dev/null +++ b/drivers/marvell/amb_adec.c @@ -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 +#include +#include +#include +#include + +#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; +} diff --git a/drivers/marvell/ccu.c b/drivers/marvell/ccu.c new file mode 100644 index 0000000..e478d63 --- /dev/null +++ b/drivers/marvell/ccu.c @@ -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 +#include +#include +#include +#include +#include + +#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],20’h0} */ +#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; +} diff --git a/drivers/marvell/gwin.c b/drivers/marvell/gwin.c new file mode 100644 index 0000000..2b17f35 --- /dev/null +++ b/drivers/marvell/gwin.c @@ -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 +#include +#include +#include +#include +#include + +#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; +} diff --git a/drivers/marvell/io_win.c b/drivers/marvell/io_win.c new file mode 100644 index 0000000..701dbb8 --- /dev/null +++ b/drivers/marvell/io_win.c @@ -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 +#include +#include +#include +#include +#include + +#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; +} diff --git a/drivers/marvell/iob.c b/drivers/marvell/iob.c new file mode 100644 index 0000000..9f9d047 --- /dev/null +++ b/drivers/marvell/iob.c @@ -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 +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/include/drivers/marvell/addr_map.h b/include/drivers/marvell/addr_map.h new file mode 100644 index 0000000..6b957a1 --- /dev/null +++ b/include/drivers/marvell/addr_map.h @@ -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 + +struct addr_map_win { + uint64_t base_addr; + uint64_t win_size; + uint32_t target_id; +}; + +#endif /* _ADDR_MAP_H_ */ diff --git a/include/drivers/marvell/amb_adec.h b/include/drivers/marvell/amb_adec.h new file mode 100644 index 0000000..087864a --- /dev/null +++ b/include/drivers/marvell/amb_adec.h @@ -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 + +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_ */ diff --git a/include/drivers/marvell/ccu.h b/include/drivers/marvell/ccu.h new file mode 100644 index 0000000..ff30a76 --- /dev/null +++ b/include/drivers/marvell/ccu.h @@ -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 +#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_ */ diff --git a/include/drivers/marvell/gwin.h b/include/drivers/marvell/gwin.h new file mode 100644 index 0000000..5dc9f24 --- /dev/null +++ b/include/drivers/marvell/gwin.h @@ -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 + +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_ */ diff --git a/include/drivers/marvell/io_win.h b/include/drivers/marvell/io_win.h new file mode 100644 index 0000000..4102a11 --- /dev/null +++ b/include/drivers/marvell/io_win.h @@ -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 + +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_ */ diff --git a/include/drivers/marvell/iob.h b/include/drivers/marvell/iob.h new file mode 100644 index 0000000..9848c0a --- /dev/null +++ b/include/drivers/marvell/iob.h @@ -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 + +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_ */