1 /* 2 * Copyright (C) 2018 Marvell International Ltd. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 * https://spdx.org/licenses 6 */ 7 8 /* IO Window unit device driver for Marvell AP807, AP807 and AP810 SoCs */ 9 10 #include <a8k_common.h> 11 #include <debug.h> 12 #include <io_win.h> 13 #include <mmio.h> 14 #include <mvebu.h> 15 #include <mvebu_def.h> 16 17 #if LOG_LEVEL >= LOG_LEVEL_INFO 18 #define DEBUG_ADDR_MAP 19 #endif 20 21 /* common defines */ 22 #define WIN_ENABLE_BIT (0x1) 23 /* Physical address of the base of the window = {Addr[19:0],20`h0} */ 24 #define ADDRESS_SHIFT (20 - 4) 25 #define ADDRESS_MASK (0xFFFFFFF0) 26 #define IO_WIN_ALIGNMENT_1M (0x100000) 27 #define IO_WIN_ALIGNMENT_64K (0x10000) 28 29 /* AP registers */ 30 #define IO_WIN_ALR_OFFSET(ap, win) (MVEBU_IO_WIN_BASE(ap) + 0x0 + \ 31 (0x10 * win)) 32 #define IO_WIN_AHR_OFFSET(ap, win) (MVEBU_IO_WIN_BASE(ap) + 0x8 + \ 33 (0x10 * win)) 34 #define IO_WIN_CR_OFFSET(ap, win) (MVEBU_IO_WIN_BASE(ap) + 0xC + \ 35 (0x10 * win)) 36 37 /* For storage of CR, ALR, AHR abd GCR */ 38 static uint32_t io_win_regs_save[MVEBU_IO_WIN_MAX_WINS * 3 + 1]; 39 40 static void io_win_check(struct addr_map_win *win) 41 { 42 /* for IO The base is always 1M aligned */ 43 /* check if address is aligned to 1M */ 44 if (IS_NOT_ALIGN(win->base_addr, IO_WIN_ALIGNMENT_1M)) { 45 win->base_addr = ALIGN_UP(win->base_addr, IO_WIN_ALIGNMENT_1M); 46 NOTICE("%s: Align up the base address to 0x%llx\n", 47 __func__, win->base_addr); 48 } 49 50 /* size parameter validity check */ 51 if (IS_NOT_ALIGN(win->win_size, IO_WIN_ALIGNMENT_1M)) { 52 win->win_size = ALIGN_UP(win->win_size, IO_WIN_ALIGNMENT_1M); 53 NOTICE("%s: Aligning size to 0x%llx\n", 54 __func__, win->win_size); 55 } 56 } 57 58 static void io_win_enable_window(int ap_index, struct addr_map_win *win, 59 uint32_t win_num) 60 { 61 uint32_t alr, ahr; 62 uint64_t end_addr; 63 64 if (win->target_id < 0 || win->target_id >= MVEBU_IO_WIN_MAX_WINS) { 65 ERROR("target ID = %d, is invalid\n", win->target_id); 66 return; 67 } 68 69 if ((win_num == 0) || (win_num > MVEBU_IO_WIN_MAX_WINS)) { 70 ERROR("Enabling wrong IOW window %d!\n", win_num); 71 return; 72 } 73 74 /* calculate the end-address */ 75 end_addr = (win->base_addr + win->win_size - 1); 76 77 alr = (uint32_t)((win->base_addr >> ADDRESS_SHIFT) & ADDRESS_MASK); 78 alr |= WIN_ENABLE_BIT; 79 ahr = (uint32_t)((end_addr >> ADDRESS_SHIFT) & ADDRESS_MASK); 80 81 /* write start address and end address for IO window */ 82 mmio_write_32(IO_WIN_ALR_OFFSET(ap_index, win_num), alr); 83 mmio_write_32(IO_WIN_AHR_OFFSET(ap_index, win_num), ahr); 84 85 /* write window target */ 86 mmio_write_32(IO_WIN_CR_OFFSET(ap_index, win_num), win->target_id); 87 } 88 89 static void io_win_disable_window(int ap_index, uint32_t win_num) 90 { 91 uint32_t win_reg; 92 93 if ((win_num == 0) || (win_num > MVEBU_IO_WIN_MAX_WINS)) { 94 ERROR("Disabling wrong IOW window %d!\n", win_num); 95 return; 96 } 97 98 win_reg = mmio_read_32(IO_WIN_ALR_OFFSET(ap_index, win_num)); 99 win_reg &= ~WIN_ENABLE_BIT; 100 mmio_write_32(IO_WIN_ALR_OFFSET(ap_index, win_num), win_reg); 101 } 102 103 /* Insert/Remove temporary window for using the out-of reset default 104 * CPx base address to access the CP configuration space prior to 105 * the further base address update in accordance with address mapping 106 * design. 107 * 108 * NOTE: Use the same window array for insertion and removal of 109 * temporary windows. 110 */ 111 void iow_temp_win_insert(int ap_index, struct addr_map_win *win, int size) 112 { 113 uint32_t win_id; 114 115 for (int i = 0; i < size; i++) { 116 win_id = MVEBU_IO_WIN_MAX_WINS - i - 1; 117 io_win_check(win); 118 io_win_enable_window(ap_index, win, win_id); 119 win++; 120 } 121 } 122 123 /* 124 * NOTE: Use the same window array for insertion and removal of 125 * temporary windows. 126 */ 127 void iow_temp_win_remove(int ap_index, struct addr_map_win *win, int size) 128 { 129 uint32_t win_id; 130 131 /* Start from the last window and do not touch Win0 */ 132 for (int i = 0; i < size; i++) { 133 uint64_t base; 134 uint32_t target; 135 136 win_id = MVEBU_IO_WIN_MAX_WINS - i - 1; 137 138 target = mmio_read_32(IO_WIN_CR_OFFSET(ap_index, win_id)); 139 base = mmio_read_32(IO_WIN_ALR_OFFSET(ap_index, win_id)); 140 base &= ~WIN_ENABLE_BIT; 141 base <<= ADDRESS_SHIFT; 142 143 if ((win->target_id != target) || (win->base_addr != base)) { 144 ERROR("%s: Trying to remove bad window-%d!\n", 145 __func__, win_id); 146 continue; 147 } 148 io_win_disable_window(ap_index, win_id); 149 win++; 150 } 151 } 152 153 #ifdef DEBUG_ADDR_MAP 154 static void dump_io_win(int ap_index) 155 { 156 uint32_t trgt_id, win_id; 157 uint32_t alr, ahr; 158 uint64_t start, end; 159 160 /* Dump all IO windows */ 161 tf_printf("\tbank target start end\n"); 162 tf_printf("\t----------------------------------------------------\n"); 163 for (win_id = 0; win_id < MVEBU_IO_WIN_MAX_WINS; win_id++) { 164 alr = mmio_read_32(IO_WIN_ALR_OFFSET(ap_index, win_id)); 165 if (alr & WIN_ENABLE_BIT) { 166 alr &= ~WIN_ENABLE_BIT; 167 ahr = mmio_read_32(IO_WIN_AHR_OFFSET(ap_index, win_id)); 168 trgt_id = mmio_read_32(IO_WIN_CR_OFFSET(ap_index, 169 win_id)); 170 start = ((uint64_t)alr << ADDRESS_SHIFT); 171 end = (((uint64_t)ahr + 0x10) << ADDRESS_SHIFT); 172 tf_printf("\tio-win %d 0x%016llx 0x%016llx\n", 173 trgt_id, start, end); 174 } 175 } 176 tf_printf("\tio-win gcr is %x\n", 177 mmio_read_32(MVEBU_IO_WIN_BASE(ap_index) + 178 MVEBU_IO_WIN_GCR_OFFSET)); 179 } 180 #endif 181 182 static void iow_save_win_range(int ap_id, int win_first, int win_last, 183 uint32_t *buffer) 184 { 185 int win_id, idx; 186 187 /* Save IOW */ 188 for (idx = 0, win_id = win_first; win_id <= win_last; win_id++) { 189 buffer[idx++] = mmio_read_32(IO_WIN_CR_OFFSET(ap_id, win_id)); 190 buffer[idx++] = mmio_read_32(IO_WIN_ALR_OFFSET(ap_id, win_id)); 191 buffer[idx++] = mmio_read_32(IO_WIN_AHR_OFFSET(ap_id, win_id)); 192 } 193 buffer[idx] = mmio_read_32(MVEBU_IO_WIN_BASE(ap_id) + 194 MVEBU_IO_WIN_GCR_OFFSET); 195 } 196 197 static void iow_restore_win_range(int ap_id, int win_first, int win_last, 198 uint32_t *buffer) 199 { 200 int win_id, idx; 201 202 /* Restore IOW */ 203 for (idx = 0, win_id = win_first; win_id <= win_last; win_id++) { 204 mmio_write_32(IO_WIN_CR_OFFSET(ap_id, win_id), buffer[idx++]); 205 mmio_write_32(IO_WIN_ALR_OFFSET(ap_id, win_id), buffer[idx++]); 206 mmio_write_32(IO_WIN_AHR_OFFSET(ap_id, win_id), buffer[idx++]); 207 } 208 mmio_write_32(MVEBU_IO_WIN_BASE(ap_id) + MVEBU_IO_WIN_GCR_OFFSET, 209 buffer[idx++]); 210 } 211 212 void iow_save_win_all(int ap_id) 213 { 214 iow_save_win_range(ap_id, 0, MVEBU_IO_WIN_MAX_WINS - 1, 215 io_win_regs_save); 216 } 217 218 void iow_restore_win_all(int ap_id) 219 { 220 iow_restore_win_range(ap_id, 0, MVEBU_IO_WIN_MAX_WINS - 1, 221 io_win_regs_save); 222 } 223 224 int init_io_win(int ap_index) 225 { 226 struct addr_map_win *win; 227 uint32_t win_id, win_reg; 228 uint32_t win_count; 229 230 INFO("Initializing IO WIN Address decoding\n"); 231 232 /* Get the array of the windows and its size */ 233 marvell_get_io_win_memory_map(ap_index, &win, &win_count); 234 if (win_count <= 0) 235 INFO("no windows configurations found\n"); 236 237 if (win_count > MVEBU_IO_WIN_MAX_WINS) { 238 INFO("number of windows is bigger than %d\n", 239 MVEBU_IO_WIN_MAX_WINS); 240 return 0; 241 } 242 243 /* Get the default target id to set the GCR */ 244 win_reg = marvell_get_io_win_gcr_target(ap_index); 245 mmio_write_32(MVEBU_IO_WIN_BASE(ap_index) + MVEBU_IO_WIN_GCR_OFFSET, 246 win_reg); 247 248 /* disable all IO windows */ 249 for (win_id = 1; win_id < MVEBU_IO_WIN_MAX_WINS; win_id++) 250 io_win_disable_window(ap_index, win_id); 251 252 /* enable relevant windows, starting from win_id = 1 because 253 * index 0 dedicated for BootROM 254 */ 255 for (win_id = 1; win_id <= win_count; win_id++, win++) { 256 io_win_check(win); 257 io_win_enable_window(ap_index, win, win_id); 258 } 259 260 #ifdef DEBUG_ADDR_MAP 261 dump_io_win(ap_index); 262 #endif 263 264 INFO("Done IO WIN Address decoding Initializing\n"); 265 266 return 0; 267 } 268