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