diff options
author | Konstantin Porotchkin <kostap@marvell.com> | 2018-02-26 15:51:11 +0200 |
---|---|---|
committer | Konstantin Porotchkin <kostap@marvell.com> | 2018-07-18 18:48:30 +0300 |
commit | c0474d5843321392172356f79efb6ec6140c4e48 (patch) | |
tree | 503e19e85375bc048e8f2a291751d122a72b2bfb /drivers/marvell/iob.c | |
parent | 752faf8fce02d9d254a83e686bc8e71d69a7af95 (diff) | |
download | platform_external_arm-trusted-firmware-c0474d5843321392172356f79efb6ec6140c4e48.tar.gz platform_external_arm-trusted-firmware-c0474d5843321392172356f79efb6ec6140c4e48.tar.bz2 platform_external_arm-trusted-firmware-c0474d5843321392172356f79efb6ec6140c4e48.zip |
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>
Diffstat (limited to 'drivers/marvell/iob.c')
-rw-r--r-- | drivers/marvell/iob.c | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/drivers/marvell/iob.c b/drivers/marvell/iob.c new file mode 100644 index 000000000..9f9d04797 --- /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 <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; +} |