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