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