1 /* 2 * Copyright (C) 2018-2021 Marvell International Ltd. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 * https://spdx.org/licenses 6 */ 7 8 #include <string.h> 9 10 #include <lib/mmio.h> 11 12 #include <dram_win.h> 13 #include <marvell_plat_priv.h> 14 #include <mvebu.h> 15 #include <plat_marvell.h> 16 17 /* Armada 3700 has 5 configurable windows */ 18 #define MV_CPU_WIN_NUM 5 19 20 #define CPU_WIN_DISABLED 0 21 #define CPU_WIN_ENABLED 1 22 23 /* 24 * There are 2 different cpu decode window configuration cases: 25 * - DRAM size is not over 2GB; 26 * - DRAM size is 4GB. 27 */ 28 enum cpu_win_config_num { 29 CPU_WIN_CONFIG_DRAM_NOT_OVER_2GB = 0, 30 CPU_WIN_CONFIG_DRAM_4GB, 31 CPU_WIN_CONFIG_MAX 32 }; 33 34 enum cpu_win_target { 35 CPU_WIN_TARGET_DRAM = 0, 36 CPU_WIN_TARGET_INTERNAL_REG, 37 CPU_WIN_TARGET_PCIE, 38 CPU_WIN_TARGET_PCIE_OVER_MCI, 39 CPU_WIN_TARGET_BOOT_ROM, 40 CPU_WIN_TARGET_MCI_EXTERNAL, 41 CPU_WIN_TARGET_RWTM_RAM = 7, 42 CPU_WIN_TARGET_CCI400_REG 43 }; 44 45 struct cpu_win_configuration { 46 uint32_t enabled; 47 enum cpu_win_target target; 48 uint64_t base_addr; 49 uint64_t size; 50 uint64_t remap_addr; 51 }; 52 53 struct cpu_win_configuration mv_cpu_wins[CPU_WIN_CONFIG_MAX][MV_CPU_WIN_NUM] = { 54 /* 55 * When total dram size is not over 2GB: 56 * DDR window 0 is configured in tim header, its size may be not 512MB, 57 * but the actual dram size, no need to configure it again; 58 * other cpu windows are kept as default. 59 */ 60 { 61 /* enabled 62 * target 63 * base 64 * size 65 * remap 66 */ 67 {CPU_WIN_ENABLED, 68 CPU_WIN_TARGET_DRAM, 69 0x0, 70 0x08000000, 71 0x0}, 72 {CPU_WIN_ENABLED, 73 CPU_WIN_TARGET_MCI_EXTERNAL, 74 0xe0000000, 75 0x08000000, 76 0xe0000000}, 77 {CPU_WIN_ENABLED, 78 CPU_WIN_TARGET_PCIE, 79 0xe8000000, 80 0x08000000, 81 0xe8000000}, 82 {CPU_WIN_ENABLED, 83 CPU_WIN_TARGET_RWTM_RAM, 84 0xf0000000, 85 0x00020000, 86 0x1fff0000}, 87 {CPU_WIN_ENABLED, 88 CPU_WIN_TARGET_PCIE_OVER_MCI, 89 0x80000000, 90 0x10000000, 91 0x80000000}, 92 }, 93 94 /* 95 * If total DRAM size is more than 2GB, now there is only one case: 96 * 4GB of DRAM; to better utilize address space (for maximization of 97 * DRAM usage), we will use the configuration of CPU windows below: 98 * - Internal Regs and Boot ROM windows are kept as default; 99 * - CCI-400 is moved from its default address to another address 100 * (this is actually done even if DRAM size is not more than 2 GB, 101 * because the firmware is compiled with that address as a 102 * constant); 103 * - PCIe window is moved to another address; 104 * - Use 4 CPU decode windows for DRAM, which cover 3.75GB DRAM; 105 * DDR window 0 is configured in tim header with 2G B size, no need 106 * to configure it again here; 107 * 108 * 0xFFFFFFFF ---> +-----------------------+ 109 * | Boot ROM | 1 MB 110 * | AP Boot ROM - 16 KB: | 111 * | 0xFFFF0000-0xFFFF4000 | 112 * 0xFFF00000 ---> +-----------------------+ 113 * : : 114 * 0xFE010000 ---> +-----------------------+ 115 * | CCI Regs | 64 KB 116 * 0xFE000000 ---> +-----------------------+ 117 * : : 118 * 0xFA000000 ---> +-----------------------+ 119 * | PCIE | 128 MB 120 * 0xF2000000 ---> +-----------------------+ 121 * | DDR window 3 | 512 MB 122 * 0xD2000000 ---> +-----------------------+ 123 * | Internal Regs | 32 MB 124 * 0xD0000000 ---> |-----------------------| 125 * | DDR window 2 | 256 MB 126 * 0xC0000000 ---> |-----------------------| 127 * | | 128 * | DDR window 1 | 1 GB 129 * | | 130 * 0x80000000 ---> |-----------------------| 131 * | | 132 * | | 133 * | DDR window 0 | 2 GB 134 * | | 135 * | | 136 * 0x00000000 ---> +-----------------------+ 137 */ 138 { 139 /* win_id 140 * target 141 * base 142 * size 143 * remap 144 */ 145 {CPU_WIN_ENABLED, 146 CPU_WIN_TARGET_DRAM, 147 0x0, 148 0x80000000, 149 0x0}, 150 {CPU_WIN_ENABLED, 151 CPU_WIN_TARGET_DRAM, 152 0x80000000, 153 0x40000000, 154 0x80000000}, 155 {CPU_WIN_ENABLED, 156 CPU_WIN_TARGET_DRAM, 157 0xc0000000, 158 0x10000000, 159 0xc0000000}, 160 {CPU_WIN_ENABLED, 161 CPU_WIN_TARGET_DRAM, 162 0xd2000000, 163 0x20000000, 164 0xd2000000}, 165 {CPU_WIN_ENABLED, 166 CPU_WIN_TARGET_PCIE, 167 0xf2000000, 168 0x08000000, 169 0xf2000000}, 170 }, 171 }; 172 173 /* 174 * dram_win_map_build 175 * 176 * This function builds cpu dram windows mapping 177 * which includes base address and window size by 178 * reading cpu dram decode windows registers. 179 * 180 * @input: N/A 181 * 182 * @output: 183 * - win_map: cpu dram windows mapping 184 * 185 * @return: N/A 186 */ 187 void dram_win_map_build(struct dram_win_map *win_map) 188 { 189 int32_t win_id; 190 struct dram_win *win; 191 uint32_t base_reg, ctrl_reg, size_reg, enabled, target; 192 193 memset(win_map, 0, sizeof(struct dram_win_map)); 194 for (win_id = 0; win_id < DRAM_WIN_MAP_NUM_MAX; win_id++) { 195 ctrl_reg = mmio_read_32(CPU_DEC_WIN_CTRL_REG(win_id)); 196 target = (ctrl_reg & CPU_DEC_CR_WIN_TARGET_MASK) >> 197 CPU_DEC_CR_WIN_TARGET_OFFS; 198 enabled = ctrl_reg & CPU_DEC_CR_WIN_ENABLE; 199 /* Ignore invalid and non-dram windows*/ 200 if ((enabled == 0) || (target != DRAM_CPU_DEC_TARGET_NUM)) 201 continue; 202 203 win = win_map->dram_windows + win_map->dram_win_num; 204 base_reg = mmio_read_32(CPU_DEC_WIN_BASE_REG(win_id)); 205 size_reg = mmio_read_32(CPU_DEC_WIN_SIZE_REG(win_id)); 206 /* Base reg [15:0] corresponds to transaction address [39:16] */ 207 win->base_addr = (base_reg & CPU_DEC_BR_BASE_MASK) >> 208 CPU_DEC_BR_BASE_OFFS; 209 win->base_addr *= CPU_DEC_CR_WIN_SIZE_ALIGNMENT; 210 /* 211 * Size reg [15:0] is programmed from LSB to MSB as a sequence 212 * of 1s followed by a sequence of 0s and the number of 1s 213 * specifies the size of the window in 64 KB granularity, 214 * for example, a value of 00FFh specifies 256 x 64 KB = 16 MB 215 */ 216 win->win_size = (size_reg & CPU_DEC_CR_WIN_SIZE_MASK) >> 217 CPU_DEC_CR_WIN_SIZE_OFFS; 218 win->win_size = (win->win_size + 1) * 219 CPU_DEC_CR_WIN_SIZE_ALIGNMENT; 220 221 win_map->dram_win_num++; 222 } 223 } 224 225 static void cpu_win_set(uint32_t win_id, struct cpu_win_configuration *win_cfg) 226 { 227 uint32_t base_reg, ctrl_reg, size_reg, remap_reg; 228 229 /* Disable window */ 230 ctrl_reg = mmio_read_32(CPU_DEC_WIN_CTRL_REG(win_id)); 231 ctrl_reg &= ~CPU_DEC_CR_WIN_ENABLE; 232 mmio_write_32(CPU_DEC_WIN_CTRL_REG(win_id), ctrl_reg); 233 234 /* For an disabled window, only disable it. */ 235 if (!win_cfg->enabled) 236 return; 237 238 /* Set Base Register */ 239 base_reg = (uint32_t)(win_cfg->base_addr / 240 CPU_DEC_CR_WIN_SIZE_ALIGNMENT); 241 base_reg <<= CPU_DEC_BR_BASE_OFFS; 242 base_reg &= CPU_DEC_BR_BASE_MASK; 243 mmio_write_32(CPU_DEC_WIN_BASE_REG(win_id), base_reg); 244 245 /* Set Remap Register with the same value 246 * as the <Base> field in Base Register 247 */ 248 remap_reg = (uint32_t)(win_cfg->remap_addr / 249 CPU_DEC_CR_WIN_SIZE_ALIGNMENT); 250 remap_reg <<= CPU_DEC_RLR_REMAP_LOW_OFFS; 251 remap_reg &= CPU_DEC_RLR_REMAP_LOW_MASK; 252 mmio_write_32(CPU_DEC_REMAP_LOW_REG(win_id), remap_reg); 253 254 /* Set Size Register */ 255 size_reg = (win_cfg->size / CPU_DEC_CR_WIN_SIZE_ALIGNMENT) - 1; 256 size_reg <<= CPU_DEC_CR_WIN_SIZE_OFFS; 257 size_reg &= CPU_DEC_CR_WIN_SIZE_MASK; 258 mmio_write_32(CPU_DEC_WIN_SIZE_REG(win_id), size_reg); 259 260 /* Set Control Register - set target id and enable window */ 261 ctrl_reg &= ~CPU_DEC_CR_WIN_TARGET_MASK; 262 ctrl_reg |= (win_cfg->target << CPU_DEC_CR_WIN_TARGET_OFFS); 263 ctrl_reg |= CPU_DEC_CR_WIN_ENABLE; 264 mmio_write_32(CPU_DEC_WIN_CTRL_REG(win_id), ctrl_reg); 265 } 266 267 void cpu_wins_init(void) 268 { 269 uint32_t cfg_idx, win_id; 270 271 if (mvebu_get_dram_size(MVEBU_REGS_BASE) <= _2GB_) 272 cfg_idx = CPU_WIN_CONFIG_DRAM_NOT_OVER_2GB; 273 else 274 cfg_idx = CPU_WIN_CONFIG_DRAM_4GB; 275 276 /* Window 0 is configured always for DRAM in tim header 277 * already, no need to configure it again here 278 */ 279 for (win_id = 1; win_id < MV_CPU_WIN_NUM; win_id++) 280 cpu_win_set(win_id, &mv_cpu_wins[cfg_idx][win_id]); 281 } 282 283