| /* |
| * Copyright (C) 2018 Marvell International Ltd. |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| * https://spdx.org/licenses |
| */ |
| |
| #include <dram_win.h> |
| #include <marvell_plat_priv.h> |
| #include <mmio.h> |
| #include <mvebu.h> |
| #include <plat_marvell.h> |
| #include <string.h> |
| |
| /* Armada 3700 has 5 configurable windows */ |
| #define MV_CPU_WIN_NUM 5 |
| |
| #define CPU_WIN_DISABLED 0 |
| #define CPU_WIN_ENABLED 1 |
| |
| /* |
| * There are 2 different cpu decode window configuration cases: |
| * - DRAM size is not over 2GB; |
| * - DRAM size is 4GB. |
| */ |
| enum cpu_win_config_num { |
| CPU_WIN_CONFIG_DRAM_NOT_OVER_2GB = 0, |
| CPU_WIN_CONFIG_DRAM_4GB, |
| CPU_WIN_CONFIG_MAX |
| }; |
| |
| enum cpu_win_target { |
| CPU_WIN_TARGET_DRAM = 0, |
| CPU_WIN_TARGET_INTERNAL_REG, |
| CPU_WIN_TARGET_PCIE, |
| CPU_WIN_TARGET_PCIE_OVER_MCI, |
| CPU_WIN_TARGET_BOOT_ROM, |
| CPU_WIN_TARGET_MCI_EXTERNAL, |
| CPU_WIN_TARGET_RWTM_RAM = 7, |
| CPU_WIN_TARGET_CCI400_REG |
| }; |
| |
| struct cpu_win_configuration { |
| uint32_t enabled; |
| enum cpu_win_target target; |
| uint64_t base_addr; |
| uint64_t size; |
| uint64_t remap_addr; |
| }; |
| |
| struct cpu_win_configuration mv_cpu_wins[CPU_WIN_CONFIG_MAX][MV_CPU_WIN_NUM] = { |
| /* |
| * When total dram size is not over 2GB: |
| * DDR window 0 is configured in tim header, its size may be not 512MB, |
| * but the actual dram size, no need to configure it again; |
| * other cpu windows are kept as default. |
| */ |
| { |
| /* enabled |
| * target |
| * base |
| * size |
| * remap |
| */ |
| {CPU_WIN_ENABLED, |
| CPU_WIN_TARGET_DRAM, |
| 0x0, |
| 0x08000000, |
| 0x0}, |
| {CPU_WIN_ENABLED, |
| CPU_WIN_TARGET_MCI_EXTERNAL, |
| 0xe0000000, |
| 0x08000000, |
| 0xe0000000}, |
| {CPU_WIN_ENABLED, |
| CPU_WIN_TARGET_PCIE, |
| 0xe8000000, |
| 0x08000000, |
| 0xe8000000}, |
| {CPU_WIN_ENABLED, |
| CPU_WIN_TARGET_RWTM_RAM, |
| 0xf0000000, |
| 0x00020000, |
| 0x1fff0000}, |
| {CPU_WIN_ENABLED, |
| CPU_WIN_TARGET_PCIE_OVER_MCI, |
| 0x80000000, |
| 0x10000000, |
| 0x80000000}, |
| }, |
| |
| /* |
| * If total dram size is more than 2GB, now there is only one case - 4GB |
| * dram; we will use below cpu windows configurations: |
| * - Internal Regs, CCI-400, Boot Rom and PCIe windows are kept as |
| * default; |
| * - Use 4 CPU decode windows for DRAM, which cover 3.375GB DRAM; |
| * DDR window 0 is configured in tim header with 2GB size, no need to |
| * configure it again here; |
| * |
| * 0xFFFFFFFF ---> |-----------------------| |
| * | Boot ROM | 64KB |
| * 0xFFF00000 ---> +-----------------------+ |
| * : : |
| * 0xF0000000 ---> |-----------------------| |
| * | PCIE | 128 MB |
| * 0xE8000000 ---> |-----------------------| |
| * | DDR window 3 | 128 MB |
| * 0xE0000000 ---> +-----------------------+ |
| * : : |
| * 0xD8010000 ---> |-----------------------| |
| * | CCI Regs | 64 KB |
| * 0xD8000000 ---> +-----------------------+ |
| * : : |
| * : : |
| * 0xD2000000 ---> +-----------------------+ |
| * | Internal Regs | 32MB |
| * 0xD0000000 ---> |-----------------------| |
| * | DDR window 2 | 256 MB |
| * 0xC0000000 ---> |-----------------------| |
| * | | |
| * | DDR window 1 | 1 GB |
| * | | |
| * 0x80000000 ---> |-----------------------| |
| * | | |
| * | | |
| * | DDR window 0 | 2 GB |
| * | | |
| * | | |
| * 0x00000000 ---> +-----------------------+ |
| */ |
| { |
| /* win_id |
| * target |
| * base |
| * size |
| * remap |
| */ |
| {CPU_WIN_ENABLED, |
| CPU_WIN_TARGET_DRAM, |
| 0x0, |
| 0x80000000, |
| 0x0}, |
| {CPU_WIN_ENABLED, |
| CPU_WIN_TARGET_DRAM, |
| 0x80000000, |
| 0x40000000, |
| 0x80000000}, |
| {CPU_WIN_ENABLED, |
| CPU_WIN_TARGET_DRAM, |
| 0xc0000000, |
| 0x10000000, |
| 0xc0000000}, |
| {CPU_WIN_ENABLED, |
| CPU_WIN_TARGET_DRAM, |
| 0xe0000000, |
| 0x08000000, |
| 0xe0000000}, |
| {CPU_WIN_ENABLED, |
| CPU_WIN_TARGET_PCIE, |
| 0xe8000000, |
| 0x08000000, |
| 0xe8000000}, |
| }, |
| }; |
| |
| /* |
| * dram_win_map_build |
| * |
| * This function builds cpu dram windows mapping |
| * which includes base address and window size by |
| * reading cpu dram decode windows registers. |
| * |
| * @input: N/A |
| * |
| * @output: |
| * - win_map: cpu dram windows mapping |
| * |
| * @return: N/A |
| */ |
| void dram_win_map_build(struct dram_win_map *win_map) |
| { |
| int32_t win_id; |
| struct dram_win *win; |
| uint32_t base_reg, ctrl_reg, size_reg, enabled, target; |
| |
| memset(win_map, 0, sizeof(struct dram_win_map)); |
| for (win_id = 0; win_id < DRAM_WIN_MAP_NUM_MAX; win_id++) { |
| ctrl_reg = mmio_read_32(CPU_DEC_WIN_CTRL_REG(win_id)); |
| target = (ctrl_reg & CPU_DEC_CR_WIN_TARGET_MASK) >> |
| CPU_DEC_CR_WIN_TARGET_OFFS; |
| enabled = ctrl_reg & CPU_DEC_CR_WIN_ENABLE; |
| /* Ignore invalid and non-dram windows*/ |
| if ((enabled == 0) || (target != DRAM_CPU_DEC_TARGET_NUM)) |
| continue; |
| |
| win = win_map->dram_windows + win_map->dram_win_num; |
| base_reg = mmio_read_32(CPU_DEC_WIN_BASE_REG(win_id)); |
| size_reg = mmio_read_32(CPU_DEC_WIN_SIZE_REG(win_id)); |
| /* Base reg [15:0] corresponds to transaction address [39:16] */ |
| win->base_addr = (base_reg & CPU_DEC_BR_BASE_MASK) >> |
| CPU_DEC_BR_BASE_OFFS; |
| win->base_addr *= CPU_DEC_CR_WIN_SIZE_ALIGNMENT; |
| /* |
| * Size reg [15:0] is programmed from LSB to MSB as a sequence |
| * of 1s followed by a sequence of 0s and the number of 1s |
| * specifies the size of the window in 64 KB granularity, |
| * for example, a value of 00FFh specifies 256 x 64 KB = 16 MB |
| */ |
| win->win_size = (size_reg & CPU_DEC_CR_WIN_SIZE_MASK) >> |
| CPU_DEC_CR_WIN_SIZE_OFFS; |
| win->win_size = (win->win_size + 1) * |
| CPU_DEC_CR_WIN_SIZE_ALIGNMENT; |
| |
| win_map->dram_win_num++; |
| } |
| } |
| |
| static void cpu_win_set(uint32_t win_id, struct cpu_win_configuration *win_cfg) |
| { |
| uint32_t base_reg, ctrl_reg, size_reg, remap_reg; |
| |
| /* Disable window */ |
| ctrl_reg = mmio_read_32(CPU_DEC_WIN_CTRL_REG(win_id)); |
| ctrl_reg &= ~CPU_DEC_CR_WIN_ENABLE; |
| mmio_write_32(CPU_DEC_WIN_CTRL_REG(win_id), ctrl_reg); |
| |
| /* For an disabled window, only disable it. */ |
| if (!win_cfg->enabled) |
| return; |
| |
| /* Set Base Register */ |
| base_reg = (uint32_t)(win_cfg->base_addr / |
| CPU_DEC_CR_WIN_SIZE_ALIGNMENT); |
| base_reg <<= CPU_DEC_BR_BASE_OFFS; |
| base_reg &= CPU_DEC_BR_BASE_MASK; |
| mmio_write_32(CPU_DEC_WIN_BASE_REG(win_id), base_reg); |
| |
| /* Set Remap Register with the same value |
| * as the <Base> field in Base Register |
| */ |
| remap_reg = (uint32_t)(win_cfg->remap_addr / |
| CPU_DEC_CR_WIN_SIZE_ALIGNMENT); |
| remap_reg <<= CPU_DEC_RLR_REMAP_LOW_OFFS; |
| remap_reg &= CPU_DEC_RLR_REMAP_LOW_MASK; |
| mmio_write_32(CPU_DEC_REMAP_LOW_REG(win_id), remap_reg); |
| |
| /* Set Size Register */ |
| size_reg = (win_cfg->size / CPU_DEC_CR_WIN_SIZE_ALIGNMENT) - 1; |
| size_reg <<= CPU_DEC_CR_WIN_SIZE_OFFS; |
| size_reg &= CPU_DEC_CR_WIN_SIZE_MASK; |
| mmio_write_32(CPU_DEC_WIN_SIZE_REG(win_id), size_reg); |
| |
| /* Set Control Register - set target id and enable window */ |
| ctrl_reg &= ~CPU_DEC_CR_WIN_TARGET_MASK; |
| ctrl_reg |= (win_cfg->target << CPU_DEC_CR_WIN_TARGET_OFFS); |
| ctrl_reg |= CPU_DEC_CR_WIN_ENABLE; |
| mmio_write_32(CPU_DEC_WIN_CTRL_REG(win_id), ctrl_reg); |
| } |
| |
| void cpu_wins_init(void) |
| { |
| uint32_t cfg_idx, win_id; |
| |
| if (mvebu_get_dram_size(MVEBU_REGS_BASE) <= _2GB_) |
| cfg_idx = CPU_WIN_CONFIG_DRAM_NOT_OVER_2GB; |
| else |
| cfg_idx = CPU_WIN_CONFIG_DRAM_4GB; |
| |
| /* Window 0 is configured always for DRAM in tim header |
| * already, no need to configure it again here |
| */ |
| for (win_id = 1; win_id < MV_CPU_WIN_NUM; win_id++) |
| cpu_win_set(win_id, &mv_cpu_wins[cfg_idx][win_id]); |
| } |
| |