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 /* AXI to M-Bridge decoding unit driver for Marvell Armada 8K and 8K+ SoCs */ 9*c0474d58SKonstantin Porotchkin 10*c0474d58SKonstantin Porotchkin #include <a8k_common.h> 11*c0474d58SKonstantin Porotchkin #include <debug.h> 12*c0474d58SKonstantin Porotchkin #include <mmio.h> 13*c0474d58SKonstantin Porotchkin #include <mvebu.h> 14*c0474d58SKonstantin Porotchkin #include <mvebu_def.h> 15*c0474d58SKonstantin Porotchkin 16*c0474d58SKonstantin Porotchkin #if LOG_LEVEL >= LOG_LEVEL_INFO 17*c0474d58SKonstantin Porotchkin #define DEBUG_ADDR_MAP 18*c0474d58SKonstantin Porotchkin #endif 19*c0474d58SKonstantin Porotchkin 20*c0474d58SKonstantin Porotchkin /* common defines */ 21*c0474d58SKonstantin Porotchkin #define WIN_ENABLE_BIT (0x1) 22*c0474d58SKonstantin Porotchkin 23*c0474d58SKonstantin Porotchkin #define MVEBU_AMB_ADEC_OFFSET (0x70ff00) 24*c0474d58SKonstantin Porotchkin 25*c0474d58SKonstantin Porotchkin #define AMB_WIN_CR_OFFSET(win) (amb_base + 0x0 + (0x8 * win)) 26*c0474d58SKonstantin Porotchkin #define AMB_ATTR_OFFSET 8 27*c0474d58SKonstantin Porotchkin #define AMB_ATTR_MASK 0xFF 28*c0474d58SKonstantin Porotchkin #define AMB_SIZE_OFFSET 16 29*c0474d58SKonstantin Porotchkin #define AMB_SIZE_MASK 0xFF 30*c0474d58SKonstantin Porotchkin 31*c0474d58SKonstantin Porotchkin #define AMB_WIN_BASE_OFFSET(win) (amb_base + 0x4 + (0x8 * win)) 32*c0474d58SKonstantin Porotchkin #define AMB_BASE_OFFSET 16 33*c0474d58SKonstantin Porotchkin #define AMB_BASE_ADDR_MASK ((1 << (32 - AMB_BASE_OFFSET)) - 1) 34*c0474d58SKonstantin Porotchkin 35*c0474d58SKonstantin Porotchkin #define AMB_WIN_ALIGNMENT_64K (0x10000) 36*c0474d58SKonstantin Porotchkin #define AMB_WIN_ALIGNMENT_1M (0x100000) 37*c0474d58SKonstantin Porotchkin 38*c0474d58SKonstantin Porotchkin uintptr_t amb_base; 39*c0474d58SKonstantin Porotchkin 40*c0474d58SKonstantin Porotchkin static void amb_check_win(struct addr_map_win *win, uint32_t win_num) 41*c0474d58SKonstantin Porotchkin { 42*c0474d58SKonstantin Porotchkin uint32_t base_addr; 43*c0474d58SKonstantin Porotchkin 44*c0474d58SKonstantin Porotchkin /* make sure the base address is in 16-bit range */ 45*c0474d58SKonstantin Porotchkin if (win->base_addr > AMB_BASE_ADDR_MASK) { 46*c0474d58SKonstantin Porotchkin WARN("Window %d: base address is too big 0x%llx\n", 47*c0474d58SKonstantin Porotchkin win_num, win->base_addr); 48*c0474d58SKonstantin Porotchkin win->base_addr = AMB_BASE_ADDR_MASK; 49*c0474d58SKonstantin Porotchkin WARN("Set the base address to 0x%llx\n", win->base_addr); 50*c0474d58SKonstantin Porotchkin } 51*c0474d58SKonstantin Porotchkin 52*c0474d58SKonstantin Porotchkin base_addr = win->base_addr << AMB_BASE_OFFSET; 53*c0474d58SKonstantin Porotchkin /* for AMB The base is always 1M aligned */ 54*c0474d58SKonstantin Porotchkin /* check if address is aligned to 1M */ 55*c0474d58SKonstantin Porotchkin if (IS_NOT_ALIGN(base_addr, AMB_WIN_ALIGNMENT_1M)) { 56*c0474d58SKonstantin Porotchkin win->base_addr = ALIGN_UP(base_addr, AMB_WIN_ALIGNMENT_1M); 57*c0474d58SKonstantin Porotchkin WARN("Window %d: base address unaligned to 0x%x\n", 58*c0474d58SKonstantin Porotchkin win_num, AMB_WIN_ALIGNMENT_1M); 59*c0474d58SKonstantin Porotchkin WARN("Align up the base address to 0x%llx\n", win->base_addr); 60*c0474d58SKonstantin Porotchkin } 61*c0474d58SKonstantin Porotchkin 62*c0474d58SKonstantin Porotchkin /* size parameter validity check */ 63*c0474d58SKonstantin Porotchkin if (!IS_POWER_OF_2(win->win_size)) { 64*c0474d58SKonstantin Porotchkin WARN("Window %d: window size is not power of 2 (0x%llx)\n", 65*c0474d58SKonstantin Porotchkin win_num, win->win_size); 66*c0474d58SKonstantin Porotchkin win->win_size = ROUND_UP_TO_POW_OF_2(win->win_size); 67*c0474d58SKonstantin Porotchkin WARN("Rounding size to 0x%llx\n", win->win_size); 68*c0474d58SKonstantin Porotchkin } 69*c0474d58SKonstantin Porotchkin } 70*c0474d58SKonstantin Porotchkin 71*c0474d58SKonstantin Porotchkin static void amb_enable_win(struct addr_map_win *win, uint32_t win_num) 72*c0474d58SKonstantin Porotchkin { 73*c0474d58SKonstantin Porotchkin uint32_t ctrl, base, size; 74*c0474d58SKonstantin Porotchkin 75*c0474d58SKonstantin Porotchkin /* 76*c0474d58SKonstantin Porotchkin * size is 64KB granularity. 77*c0474d58SKonstantin Porotchkin * The number of ones specifies the size of the 78*c0474d58SKonstantin Porotchkin * window in 64 KB granularity. 0 is 64KB 79*c0474d58SKonstantin Porotchkin */ 80*c0474d58SKonstantin Porotchkin size = (win->win_size / AMB_WIN_ALIGNMENT_64K) - 1; 81*c0474d58SKonstantin Porotchkin ctrl = (size << AMB_SIZE_OFFSET) | (win->target_id << AMB_ATTR_OFFSET); 82*c0474d58SKonstantin Porotchkin base = win->base_addr << AMB_BASE_OFFSET; 83*c0474d58SKonstantin Porotchkin 84*c0474d58SKonstantin Porotchkin mmio_write_32(AMB_WIN_BASE_OFFSET(win_num), base); 85*c0474d58SKonstantin Porotchkin mmio_write_32(AMB_WIN_CR_OFFSET(win_num), ctrl); 86*c0474d58SKonstantin Porotchkin 87*c0474d58SKonstantin Porotchkin /* enable window after configuring window size (and attributes) */ 88*c0474d58SKonstantin Porotchkin ctrl |= WIN_ENABLE_BIT; 89*c0474d58SKonstantin Porotchkin mmio_write_32(AMB_WIN_CR_OFFSET(win_num), ctrl); 90*c0474d58SKonstantin Porotchkin } 91*c0474d58SKonstantin Porotchkin 92*c0474d58SKonstantin Porotchkin #ifdef DEBUG_ADDR_MAP 93*c0474d58SKonstantin Porotchkin static void dump_amb_adec(void) 94*c0474d58SKonstantin Porotchkin { 95*c0474d58SKonstantin Porotchkin uint32_t ctrl, base, win_id, attr; 96*c0474d58SKonstantin Porotchkin uint32_t size, size_count; 97*c0474d58SKonstantin Porotchkin 98*c0474d58SKonstantin Porotchkin /* Dump all AMB windows */ 99*c0474d58SKonstantin Porotchkin tf_printf("bank attribute base size\n"); 100*c0474d58SKonstantin Porotchkin tf_printf("--------------------------------------------\n"); 101*c0474d58SKonstantin Porotchkin for (win_id = 0; win_id < AMB_MAX_WIN_ID; win_id++) { 102*c0474d58SKonstantin Porotchkin ctrl = mmio_read_32(AMB_WIN_CR_OFFSET(win_id)); 103*c0474d58SKonstantin Porotchkin if (ctrl & WIN_ENABLE_BIT) { 104*c0474d58SKonstantin Porotchkin base = mmio_read_32(AMB_WIN_BASE_OFFSET(win_id)); 105*c0474d58SKonstantin Porotchkin attr = (ctrl >> AMB_ATTR_OFFSET) & AMB_ATTR_MASK; 106*c0474d58SKonstantin Porotchkin size_count = (ctrl >> AMB_SIZE_OFFSET) & AMB_SIZE_MASK; 107*c0474d58SKonstantin Porotchkin size = (size_count + 1) * AMB_WIN_ALIGNMENT_64K; 108*c0474d58SKonstantin Porotchkin tf_printf("amb 0x%04x 0x%08x 0x%08x\n", 109*c0474d58SKonstantin Porotchkin attr, base, size); 110*c0474d58SKonstantin Porotchkin } 111*c0474d58SKonstantin Porotchkin } 112*c0474d58SKonstantin Porotchkin } 113*c0474d58SKonstantin Porotchkin #endif 114*c0474d58SKonstantin Porotchkin 115*c0474d58SKonstantin Porotchkin int init_amb_adec(uintptr_t base) 116*c0474d58SKonstantin Porotchkin { 117*c0474d58SKonstantin Porotchkin struct addr_map_win *win; 118*c0474d58SKonstantin Porotchkin uint32_t win_id, win_reg; 119*c0474d58SKonstantin Porotchkin uint32_t win_count; 120*c0474d58SKonstantin Porotchkin 121*c0474d58SKonstantin Porotchkin INFO("Initializing AXI to MBus Bridge Address decoding\n"); 122*c0474d58SKonstantin Porotchkin 123*c0474d58SKonstantin Porotchkin /* Get the base address of the AMB address decoding */ 124*c0474d58SKonstantin Porotchkin amb_base = base + MVEBU_AMB_ADEC_OFFSET; 125*c0474d58SKonstantin Porotchkin 126*c0474d58SKonstantin Porotchkin /* Get the array of the windows and its size */ 127*c0474d58SKonstantin Porotchkin marvell_get_amb_memory_map(&win, &win_count, base); 128*c0474d58SKonstantin Porotchkin if (win_count <= 0) 129*c0474d58SKonstantin Porotchkin INFO("no windows configurations found\n"); 130*c0474d58SKonstantin Porotchkin 131*c0474d58SKonstantin Porotchkin if (win_count > AMB_MAX_WIN_ID) { 132*c0474d58SKonstantin Porotchkin INFO("number of windows is bigger than %d\n", AMB_MAX_WIN_ID); 133*c0474d58SKonstantin Porotchkin return 0; 134*c0474d58SKonstantin Porotchkin } 135*c0474d58SKonstantin Porotchkin 136*c0474d58SKonstantin Porotchkin /* disable all AMB windows */ 137*c0474d58SKonstantin Porotchkin for (win_id = 0; win_id < AMB_MAX_WIN_ID; win_id++) { 138*c0474d58SKonstantin Porotchkin win_reg = mmio_read_32(AMB_WIN_CR_OFFSET(win_id)); 139*c0474d58SKonstantin Porotchkin win_reg &= ~WIN_ENABLE_BIT; 140*c0474d58SKonstantin Porotchkin mmio_write_32(AMB_WIN_CR_OFFSET(win_id), win_reg); 141*c0474d58SKonstantin Porotchkin } 142*c0474d58SKonstantin Porotchkin 143*c0474d58SKonstantin Porotchkin /* enable relevant windows */ 144*c0474d58SKonstantin Porotchkin for (win_id = 0; win_id < win_count; win_id++, win++) { 145*c0474d58SKonstantin Porotchkin amb_check_win(win, win_id); 146*c0474d58SKonstantin Porotchkin amb_enable_win(win, win_id); 147*c0474d58SKonstantin Porotchkin } 148*c0474d58SKonstantin Porotchkin 149*c0474d58SKonstantin Porotchkin #ifdef DEBUG_ADDR_MAP 150*c0474d58SKonstantin Porotchkin dump_amb_adec(); 151*c0474d58SKonstantin Porotchkin #endif 152*c0474d58SKonstantin Porotchkin 153*c0474d58SKonstantin Porotchkin INFO("Done AXI to MBus Bridge Address decoding Initializing\n"); 154*c0474d58SKonstantin Porotchkin 155*c0474d58SKonstantin Porotchkin return 0; 156*c0474d58SKonstantin Porotchkin } 157