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