1*c0474d58SKonstantin Porotchkin /* 2*c0474d58SKonstantin Porotchkin * Copyright (C) 2016 - 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 /* IOW unit device driver for Marvell CP110 and CP115 SoCs */ 9*c0474d58SKonstantin Porotchkin 10*c0474d58SKonstantin Porotchkin #include <a8k_common.h> 11*c0474d58SKonstantin Porotchkin #include <arch_helpers.h> 12*c0474d58SKonstantin Porotchkin #include <debug.h> 13*c0474d58SKonstantin Porotchkin #include <iob.h> 14*c0474d58SKonstantin Porotchkin #include <mmio.h> 15*c0474d58SKonstantin Porotchkin #include <mvebu.h> 16*c0474d58SKonstantin Porotchkin #include <mvebu_def.h> 17*c0474d58SKonstantin Porotchkin 18*c0474d58SKonstantin Porotchkin #if LOG_LEVEL >= LOG_LEVEL_INFO 19*c0474d58SKonstantin Porotchkin #define DEBUG_ADDR_MAP 20*c0474d58SKonstantin Porotchkin #endif 21*c0474d58SKonstantin Porotchkin 22*c0474d58SKonstantin Porotchkin #define MVEBU_IOB_OFFSET (0x190000) 23*c0474d58SKonstantin Porotchkin #define MVEBU_IOB_MAX_WINS 16 24*c0474d58SKonstantin Porotchkin 25*c0474d58SKonstantin Porotchkin /* common defines */ 26*c0474d58SKonstantin Porotchkin #define WIN_ENABLE_BIT (0x1) 27*c0474d58SKonstantin Porotchkin /* Physical address of the base of the window = {AddrLow[19:0],20`h0} */ 28*c0474d58SKonstantin Porotchkin #define ADDRESS_SHIFT (20 - 4) 29*c0474d58SKonstantin Porotchkin #define ADDRESS_MASK (0xFFFFFFF0) 30*c0474d58SKonstantin Porotchkin #define IOB_WIN_ALIGNMENT (0x100000) 31*c0474d58SKonstantin Porotchkin 32*c0474d58SKonstantin Porotchkin /* IOB registers */ 33*c0474d58SKonstantin Porotchkin #define IOB_WIN_CR_OFFSET(win) (iob_base + 0x0 + (0x20 * win)) 34*c0474d58SKonstantin Porotchkin #define IOB_TARGET_ID_OFFSET (8) 35*c0474d58SKonstantin Porotchkin #define IOB_TARGET_ID_MASK (0xF) 36*c0474d58SKonstantin Porotchkin 37*c0474d58SKonstantin Porotchkin #define IOB_WIN_SCR_OFFSET(win) (iob_base + 0x4 + (0x20 * win)) 38*c0474d58SKonstantin Porotchkin #define IOB_WIN_ENA_CTRL_WRITE_SECURE (0x1) 39*c0474d58SKonstantin Porotchkin #define IOB_WIN_ENA_CTRL_READ_SECURE (0x2) 40*c0474d58SKonstantin Porotchkin #define IOB_WIN_ENA_WRITE_SECURE (0x4) 41*c0474d58SKonstantin Porotchkin #define IOB_WIN_ENA_READ_SECURE (0x8) 42*c0474d58SKonstantin Porotchkin 43*c0474d58SKonstantin Porotchkin #define IOB_WIN_ALR_OFFSET(win) (iob_base + 0x8 + (0x20 * win)) 44*c0474d58SKonstantin Porotchkin #define IOB_WIN_AHR_OFFSET(win) (iob_base + 0xC + (0x20 * win)) 45*c0474d58SKonstantin Porotchkin 46*c0474d58SKonstantin Porotchkin uintptr_t iob_base; 47*c0474d58SKonstantin Porotchkin 48*c0474d58SKonstantin Porotchkin static void iob_win_check(struct addr_map_win *win, uint32_t win_num) 49*c0474d58SKonstantin Porotchkin { 50*c0474d58SKonstantin Porotchkin /* check if address is aligned to the size */ 51*c0474d58SKonstantin Porotchkin if (IS_NOT_ALIGN(win->base_addr, IOB_WIN_ALIGNMENT)) { 52*c0474d58SKonstantin Porotchkin win->base_addr = ALIGN_UP(win->base_addr, IOB_WIN_ALIGNMENT); 53*c0474d58SKonstantin Porotchkin ERROR("Window %d: base address unaligned to 0x%x\n", 54*c0474d58SKonstantin Porotchkin win_num, IOB_WIN_ALIGNMENT); 55*c0474d58SKonstantin Porotchkin tf_printf("Align up the base address to 0x%llx\n", 56*c0474d58SKonstantin Porotchkin win->base_addr); 57*c0474d58SKonstantin Porotchkin } 58*c0474d58SKonstantin Porotchkin 59*c0474d58SKonstantin Porotchkin /* size parameter validity check */ 60*c0474d58SKonstantin Porotchkin if (IS_NOT_ALIGN(win->win_size, IOB_WIN_ALIGNMENT)) { 61*c0474d58SKonstantin Porotchkin win->win_size = ALIGN_UP(win->win_size, IOB_WIN_ALIGNMENT); 62*c0474d58SKonstantin Porotchkin ERROR("Window %d: window size unaligned to 0x%x\n", win_num, 63*c0474d58SKonstantin Porotchkin IOB_WIN_ALIGNMENT); 64*c0474d58SKonstantin Porotchkin tf_printf("Aligning size to 0x%llx\n", win->win_size); 65*c0474d58SKonstantin Porotchkin } 66*c0474d58SKonstantin Porotchkin } 67*c0474d58SKonstantin Porotchkin 68*c0474d58SKonstantin Porotchkin static void iob_enable_win(struct addr_map_win *win, uint32_t win_id) 69*c0474d58SKonstantin Porotchkin { 70*c0474d58SKonstantin Porotchkin uint32_t iob_win_reg; 71*c0474d58SKonstantin Porotchkin uint32_t alr, ahr; 72*c0474d58SKonstantin Porotchkin uint64_t end_addr; 73*c0474d58SKonstantin Porotchkin 74*c0474d58SKonstantin Porotchkin end_addr = (win->base_addr + win->win_size - 1); 75*c0474d58SKonstantin Porotchkin alr = (uint32_t)((win->base_addr >> ADDRESS_SHIFT) & ADDRESS_MASK); 76*c0474d58SKonstantin Porotchkin ahr = (uint32_t)((end_addr >> ADDRESS_SHIFT) & ADDRESS_MASK); 77*c0474d58SKonstantin Porotchkin 78*c0474d58SKonstantin Porotchkin mmio_write_32(IOB_WIN_ALR_OFFSET(win_id), alr); 79*c0474d58SKonstantin Porotchkin mmio_write_32(IOB_WIN_AHR_OFFSET(win_id), ahr); 80*c0474d58SKonstantin Porotchkin 81*c0474d58SKonstantin Porotchkin iob_win_reg = WIN_ENABLE_BIT; 82*c0474d58SKonstantin Porotchkin iob_win_reg |= (win->target_id & IOB_TARGET_ID_MASK) 83*c0474d58SKonstantin Porotchkin << IOB_TARGET_ID_OFFSET; 84*c0474d58SKonstantin Porotchkin mmio_write_32(IOB_WIN_CR_OFFSET(win_id), iob_win_reg); 85*c0474d58SKonstantin Porotchkin 86*c0474d58SKonstantin Porotchkin } 87*c0474d58SKonstantin Porotchkin 88*c0474d58SKonstantin Porotchkin #ifdef DEBUG_ADDR_MAP 89*c0474d58SKonstantin Porotchkin static void dump_iob(void) 90*c0474d58SKonstantin Porotchkin { 91*c0474d58SKonstantin Porotchkin uint32_t win_id, win_cr, alr, ahr; 92*c0474d58SKonstantin Porotchkin uint8_t target_id; 93*c0474d58SKonstantin Porotchkin uint64_t start, end; 94*c0474d58SKonstantin Porotchkin char *iob_target_name[IOB_MAX_TID] = { 95*c0474d58SKonstantin Porotchkin "CFG ", "MCI0 ", "PEX1 ", "PEX2 ", 96*c0474d58SKonstantin Porotchkin "PEX0 ", "NAND ", "RUNIT", "MCI1 " }; 97*c0474d58SKonstantin Porotchkin 98*c0474d58SKonstantin Porotchkin /* Dump all IOB windows */ 99*c0474d58SKonstantin Porotchkin tf_printf("bank id target start end\n"); 100*c0474d58SKonstantin Porotchkin tf_printf("----------------------------------------------------\n"); 101*c0474d58SKonstantin Porotchkin for (win_id = 0; win_id < MVEBU_IOB_MAX_WINS; win_id++) { 102*c0474d58SKonstantin Porotchkin win_cr = mmio_read_32(IOB_WIN_CR_OFFSET(win_id)); 103*c0474d58SKonstantin Porotchkin if (win_cr & WIN_ENABLE_BIT) { 104*c0474d58SKonstantin Porotchkin target_id = (win_cr >> IOB_TARGET_ID_OFFSET) & 105*c0474d58SKonstantin Porotchkin IOB_TARGET_ID_MASK; 106*c0474d58SKonstantin Porotchkin alr = mmio_read_32(IOB_WIN_ALR_OFFSET(win_id)); 107*c0474d58SKonstantin Porotchkin start = ((uint64_t)alr << ADDRESS_SHIFT); 108*c0474d58SKonstantin Porotchkin if (win_id != 0) { 109*c0474d58SKonstantin Porotchkin ahr = mmio_read_32(IOB_WIN_AHR_OFFSET(win_id)); 110*c0474d58SKonstantin Porotchkin end = (((uint64_t)ahr + 0x10) << ADDRESS_SHIFT); 111*c0474d58SKonstantin Porotchkin } else { 112*c0474d58SKonstantin Porotchkin /* Window #0 size is hardcoded to 16MB, as it's 113*c0474d58SKonstantin Porotchkin * reserved for CP configuration space. 114*c0474d58SKonstantin Porotchkin */ 115*c0474d58SKonstantin Porotchkin end = start + (16 << 20); 116*c0474d58SKonstantin Porotchkin } 117*c0474d58SKonstantin Porotchkin tf_printf("iob %02d %s 0x%016llx 0x%016llx\n", 118*c0474d58SKonstantin Porotchkin win_id, iob_target_name[target_id], 119*c0474d58SKonstantin Porotchkin start, end); 120*c0474d58SKonstantin Porotchkin } 121*c0474d58SKonstantin Porotchkin } 122*c0474d58SKonstantin Porotchkin } 123*c0474d58SKonstantin Porotchkin #endif 124*c0474d58SKonstantin Porotchkin 125*c0474d58SKonstantin Porotchkin void iob_cfg_space_update(int ap_idx, int cp_idx, uintptr_t base, 126*c0474d58SKonstantin Porotchkin uintptr_t new_base) 127*c0474d58SKonstantin Porotchkin { 128*c0474d58SKonstantin Porotchkin debug_enter(); 129*c0474d58SKonstantin Porotchkin 130*c0474d58SKonstantin Porotchkin iob_base = base + MVEBU_IOB_OFFSET; 131*c0474d58SKonstantin Porotchkin 132*c0474d58SKonstantin Porotchkin NOTICE("Change the base address of AP%d-CP%d to %lx\n", 133*c0474d58SKonstantin Porotchkin ap_idx, cp_idx, new_base); 134*c0474d58SKonstantin Porotchkin mmio_write_32(IOB_WIN_ALR_OFFSET(0), new_base >> ADDRESS_SHIFT); 135*c0474d58SKonstantin Porotchkin 136*c0474d58SKonstantin Porotchkin iob_base = new_base + MVEBU_IOB_OFFSET; 137*c0474d58SKonstantin Porotchkin 138*c0474d58SKonstantin Porotchkin /* Make sure the address was configured by the CPU before 139*c0474d58SKonstantin Porotchkin * any possible access to the CP. 140*c0474d58SKonstantin Porotchkin */ 141*c0474d58SKonstantin Porotchkin dsb(); 142*c0474d58SKonstantin Porotchkin 143*c0474d58SKonstantin Porotchkin debug_exit(); 144*c0474d58SKonstantin Porotchkin } 145*c0474d58SKonstantin Porotchkin 146*c0474d58SKonstantin Porotchkin int init_iob(uintptr_t base) 147*c0474d58SKonstantin Porotchkin { 148*c0474d58SKonstantin Porotchkin struct addr_map_win *win; 149*c0474d58SKonstantin Porotchkin uint32_t win_id, win_reg; 150*c0474d58SKonstantin Porotchkin uint32_t win_count; 151*c0474d58SKonstantin Porotchkin 152*c0474d58SKonstantin Porotchkin INFO("Initializing IOB Address decoding\n"); 153*c0474d58SKonstantin Porotchkin 154*c0474d58SKonstantin Porotchkin /* Get the base address of the address decoding MBUS */ 155*c0474d58SKonstantin Porotchkin iob_base = base + MVEBU_IOB_OFFSET; 156*c0474d58SKonstantin Porotchkin 157*c0474d58SKonstantin Porotchkin /* Get the array of the windows and fill the map data */ 158*c0474d58SKonstantin Porotchkin marvell_get_iob_memory_map(&win, &win_count, base); 159*c0474d58SKonstantin Porotchkin if (win_count <= 0) { 160*c0474d58SKonstantin Porotchkin INFO("no windows configurations found\n"); 161*c0474d58SKonstantin Porotchkin return 0; 162*c0474d58SKonstantin Porotchkin } else if (win_count > (MVEBU_IOB_MAX_WINS - 1)) { 163*c0474d58SKonstantin Porotchkin ERROR("IOB mem map array > than max available windows (%d)\n", 164*c0474d58SKonstantin Porotchkin MVEBU_IOB_MAX_WINS); 165*c0474d58SKonstantin Porotchkin win_count = MVEBU_IOB_MAX_WINS; 166*c0474d58SKonstantin Porotchkin } 167*c0474d58SKonstantin Porotchkin 168*c0474d58SKonstantin Porotchkin /* disable all IOB windows, start from win_id = 1 169*c0474d58SKonstantin Porotchkin * because can't disable internal register window 170*c0474d58SKonstantin Porotchkin */ 171*c0474d58SKonstantin Porotchkin for (win_id = 1; win_id < MVEBU_IOB_MAX_WINS; win_id++) { 172*c0474d58SKonstantin Porotchkin win_reg = mmio_read_32(IOB_WIN_CR_OFFSET(win_id)); 173*c0474d58SKonstantin Porotchkin win_reg &= ~WIN_ENABLE_BIT; 174*c0474d58SKonstantin Porotchkin mmio_write_32(IOB_WIN_CR_OFFSET(win_id), win_reg); 175*c0474d58SKonstantin Porotchkin 176*c0474d58SKonstantin Porotchkin win_reg = ~IOB_WIN_ENA_CTRL_WRITE_SECURE; 177*c0474d58SKonstantin Porotchkin win_reg &= ~IOB_WIN_ENA_CTRL_READ_SECURE; 178*c0474d58SKonstantin Porotchkin win_reg &= ~IOB_WIN_ENA_WRITE_SECURE; 179*c0474d58SKonstantin Porotchkin win_reg &= ~IOB_WIN_ENA_READ_SECURE; 180*c0474d58SKonstantin Porotchkin mmio_write_32(IOB_WIN_SCR_OFFSET(win_id), win_reg); 181*c0474d58SKonstantin Porotchkin } 182*c0474d58SKonstantin Porotchkin 183*c0474d58SKonstantin Porotchkin for (win_id = 1; win_id < win_count + 1; win_id++, win++) { 184*c0474d58SKonstantin Porotchkin iob_win_check(win, win_id); 185*c0474d58SKonstantin Porotchkin iob_enable_win(win, win_id); 186*c0474d58SKonstantin Porotchkin } 187*c0474d58SKonstantin Porotchkin 188*c0474d58SKonstantin Porotchkin #ifdef DEBUG_ADDR_MAP 189*c0474d58SKonstantin Porotchkin dump_iob(); 190*c0474d58SKonstantin Porotchkin #endif 191*c0474d58SKonstantin Porotchkin 192*c0474d58SKonstantin Porotchkin INFO("Done IOB Address decoding Initializing\n"); 193*c0474d58SKonstantin Porotchkin 194*c0474d58SKonstantin Porotchkin return 0; 195*c0474d58SKonstantin Porotchkin } 196