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 /* GWIN unit device driver for Marvell AP810 SoC */ 9*91f16700Schasinglulu 10*91f16700Schasinglulu #include <inttypes.h> 11*91f16700Schasinglulu #include <stdint.h> 12*91f16700Schasinglulu 13*91f16700Schasinglulu #include <common/debug.h> 14*91f16700Schasinglulu #include <drivers/marvell/gwin.h> 15*91f16700Schasinglulu #include <lib/mmio.h> 16*91f16700Schasinglulu 17*91f16700Schasinglulu #include <armada_common.h> 18*91f16700Schasinglulu #include <mvebu.h> 19*91f16700Schasinglulu #include <mvebu_def.h> 20*91f16700Schasinglulu 21*91f16700Schasinglulu #if LOG_LEVEL >= LOG_LEVEL_INFO 22*91f16700Schasinglulu #define DEBUG_ADDR_MAP 23*91f16700Schasinglulu #endif 24*91f16700Schasinglulu 25*91f16700Schasinglulu /* common defines */ 26*91f16700Schasinglulu #define WIN_ENABLE_BIT (0x1) 27*91f16700Schasinglulu #define WIN_TARGET_MASK (0xF) 28*91f16700Schasinglulu #define WIN_TARGET_SHIFT (0x8) 29*91f16700Schasinglulu #define WIN_TARGET(tgt) (((tgt) & WIN_TARGET_MASK) \ 30*91f16700Schasinglulu << WIN_TARGET_SHIFT) 31*91f16700Schasinglulu 32*91f16700Schasinglulu /* Bits[43:26] of the physical address are the window base, 33*91f16700Schasinglulu * which is aligned to 64MB 34*91f16700Schasinglulu */ 35*91f16700Schasinglulu #define ADDRESS_RSHIFT (26) 36*91f16700Schasinglulu #define ADDRESS_LSHIFT (10) 37*91f16700Schasinglulu #define GWIN_ALIGNMENT_64M (0x4000000) 38*91f16700Schasinglulu 39*91f16700Schasinglulu /* AP registers */ 40*91f16700Schasinglulu #define GWIN_CR_OFFSET(ap, win) (MVEBU_GWIN_BASE(ap) + 0x0 + \ 41*91f16700Schasinglulu (0x10 * (win))) 42*91f16700Schasinglulu #define GWIN_ALR_OFFSET(ap, win) (MVEBU_GWIN_BASE(ap) + 0x8 + \ 43*91f16700Schasinglulu (0x10 * (win))) 44*91f16700Schasinglulu #define GWIN_AHR_OFFSET(ap, win) (MVEBU_GWIN_BASE(ap) + 0xc + \ 45*91f16700Schasinglulu (0x10 * (win))) 46*91f16700Schasinglulu 47*91f16700Schasinglulu #define CCU_GRU_CR_OFFSET(ap) (MVEBU_CCU_GRU_BASE(ap)) 48*91f16700Schasinglulu #define CCR_GRU_CR_GWIN_MBYPASS (1 << 1) 49*91f16700Schasinglulu 50*91f16700Schasinglulu static void gwin_check(struct addr_map_win *win) 51*91f16700Schasinglulu { 52*91f16700Schasinglulu /* The base is always 64M aligned */ 53*91f16700Schasinglulu if (IS_NOT_ALIGN(win->base_addr, GWIN_ALIGNMENT_64M)) { 54*91f16700Schasinglulu win->base_addr &= ~(GWIN_ALIGNMENT_64M - 1); 55*91f16700Schasinglulu NOTICE("%s: Align the base address to 0x%" PRIx64 "\n", 56*91f16700Schasinglulu __func__, win->base_addr); 57*91f16700Schasinglulu } 58*91f16700Schasinglulu 59*91f16700Schasinglulu /* size parameter validity check */ 60*91f16700Schasinglulu if (IS_NOT_ALIGN(win->win_size, GWIN_ALIGNMENT_64M)) { 61*91f16700Schasinglulu win->win_size = ALIGN_UP(win->win_size, GWIN_ALIGNMENT_64M); 62*91f16700Schasinglulu NOTICE("%s: Aligning window size to 0x%" PRIx64 "\n", 63*91f16700Schasinglulu __func__, win->win_size); 64*91f16700Schasinglulu } 65*91f16700Schasinglulu } 66*91f16700Schasinglulu 67*91f16700Schasinglulu static void gwin_enable_window(int ap_index, struct addr_map_win *win, 68*91f16700Schasinglulu uint32_t win_num) 69*91f16700Schasinglulu { 70*91f16700Schasinglulu uint32_t alr, ahr; 71*91f16700Schasinglulu uint64_t end_addr; 72*91f16700Schasinglulu 73*91f16700Schasinglulu if ((win->target_id & WIN_TARGET_MASK) != win->target_id) { 74*91f16700Schasinglulu ERROR("target ID = %d, is invalid\n", win->target_id); 75*91f16700Schasinglulu return; 76*91f16700Schasinglulu } 77*91f16700Schasinglulu 78*91f16700Schasinglulu /* calculate 64bit end-address */ 79*91f16700Schasinglulu end_addr = (win->base_addr + win->win_size - 1); 80*91f16700Schasinglulu 81*91f16700Schasinglulu alr = (uint32_t)((win->base_addr >> ADDRESS_RSHIFT) << ADDRESS_LSHIFT); 82*91f16700Schasinglulu ahr = (uint32_t)((end_addr >> ADDRESS_RSHIFT) << ADDRESS_LSHIFT); 83*91f16700Schasinglulu 84*91f16700Schasinglulu /* write start address and end address for GWIN */ 85*91f16700Schasinglulu mmio_write_32(GWIN_ALR_OFFSET(ap_index, win_num), alr); 86*91f16700Schasinglulu mmio_write_32(GWIN_AHR_OFFSET(ap_index, win_num), ahr); 87*91f16700Schasinglulu 88*91f16700Schasinglulu /* write the target ID and enable the window */ 89*91f16700Schasinglulu mmio_write_32(GWIN_CR_OFFSET(ap_index, win_num), 90*91f16700Schasinglulu WIN_TARGET(win->target_id) | WIN_ENABLE_BIT); 91*91f16700Schasinglulu } 92*91f16700Schasinglulu 93*91f16700Schasinglulu static void gwin_disable_window(int ap_index, uint32_t win_num) 94*91f16700Schasinglulu { 95*91f16700Schasinglulu uint32_t win_reg; 96*91f16700Schasinglulu 97*91f16700Schasinglulu win_reg = mmio_read_32(GWIN_CR_OFFSET(ap_index, win_num)); 98*91f16700Schasinglulu win_reg &= ~WIN_ENABLE_BIT; 99*91f16700Schasinglulu mmio_write_32(GWIN_CR_OFFSET(ap_index, win_num), win_reg); 100*91f16700Schasinglulu } 101*91f16700Schasinglulu 102*91f16700Schasinglulu /* Insert/Remove temporary window for using the out-of reset default 103*91f16700Schasinglulu * CPx base address to access the CP configuration space prior to 104*91f16700Schasinglulu * the further base address update in accordance with address mapping 105*91f16700Schasinglulu * design. 106*91f16700Schasinglulu * 107*91f16700Schasinglulu * NOTE: Use the same window array for insertion and removal of 108*91f16700Schasinglulu * temporary windows. 109*91f16700Schasinglulu */ 110*91f16700Schasinglulu void gwin_temp_win_insert(int ap_index, struct addr_map_win *win, int size) 111*91f16700Schasinglulu { 112*91f16700Schasinglulu uint32_t win_id; 113*91f16700Schasinglulu 114*91f16700Schasinglulu for (int i = 0; i < size; i++) { 115*91f16700Schasinglulu win_id = MVEBU_GWIN_MAX_WINS - i - 1; 116*91f16700Schasinglulu gwin_check(win); 117*91f16700Schasinglulu gwin_enable_window(ap_index, win, win_id); 118*91f16700Schasinglulu win++; 119*91f16700Schasinglulu } 120*91f16700Schasinglulu } 121*91f16700Schasinglulu 122*91f16700Schasinglulu /* 123*91f16700Schasinglulu * NOTE: Use the same window array for insertion and removal of 124*91f16700Schasinglulu * temporary windows. 125*91f16700Schasinglulu */ 126*91f16700Schasinglulu void gwin_temp_win_remove(int ap_index, struct addr_map_win *win, int size) 127*91f16700Schasinglulu { 128*91f16700Schasinglulu uint32_t win_id; 129*91f16700Schasinglulu 130*91f16700Schasinglulu for (int i = 0; i < size; i++) { 131*91f16700Schasinglulu uint64_t base; 132*91f16700Schasinglulu uint32_t target; 133*91f16700Schasinglulu 134*91f16700Schasinglulu win_id = MVEBU_GWIN_MAX_WINS - i - 1; 135*91f16700Schasinglulu 136*91f16700Schasinglulu target = mmio_read_32(GWIN_CR_OFFSET(ap_index, win_id)); 137*91f16700Schasinglulu target >>= WIN_TARGET_SHIFT; 138*91f16700Schasinglulu target &= WIN_TARGET_MASK; 139*91f16700Schasinglulu 140*91f16700Schasinglulu base = mmio_read_32(GWIN_ALR_OFFSET(ap_index, win_id)); 141*91f16700Schasinglulu base >>= ADDRESS_LSHIFT; 142*91f16700Schasinglulu base <<= ADDRESS_RSHIFT; 143*91f16700Schasinglulu 144*91f16700Schasinglulu if (win->target_id != target) { 145*91f16700Schasinglulu ERROR("%s: Trying to remove bad window-%d!\n", 146*91f16700Schasinglulu __func__, win_id); 147*91f16700Schasinglulu continue; 148*91f16700Schasinglulu } 149*91f16700Schasinglulu gwin_disable_window(ap_index, win_id); 150*91f16700Schasinglulu win++; 151*91f16700Schasinglulu } 152*91f16700Schasinglulu } 153*91f16700Schasinglulu 154*91f16700Schasinglulu #ifdef DEBUG_ADDR_MAP 155*91f16700Schasinglulu static void dump_gwin(int ap_index) 156*91f16700Schasinglulu { 157*91f16700Schasinglulu uint32_t win_num; 158*91f16700Schasinglulu 159*91f16700Schasinglulu /* Dump all GWIN windows */ 160*91f16700Schasinglulu printf("\tbank target start end\n"); 161*91f16700Schasinglulu printf("\t----------------------------------------------------\n"); 162*91f16700Schasinglulu for (win_num = 0; win_num < MVEBU_GWIN_MAX_WINS; win_num++) { 163*91f16700Schasinglulu uint32_t cr; 164*91f16700Schasinglulu uint64_t alr, ahr; 165*91f16700Schasinglulu 166*91f16700Schasinglulu cr = mmio_read_32(GWIN_CR_OFFSET(ap_index, win_num)); 167*91f16700Schasinglulu /* Window enabled */ 168*91f16700Schasinglulu if (cr & WIN_ENABLE_BIT) { 169*91f16700Schasinglulu alr = mmio_read_32(GWIN_ALR_OFFSET(ap_index, win_num)); 170*91f16700Schasinglulu alr = (alr >> ADDRESS_LSHIFT) << ADDRESS_RSHIFT; 171*91f16700Schasinglulu ahr = mmio_read_32(GWIN_AHR_OFFSET(ap_index, win_num)); 172*91f16700Schasinglulu ahr = (ahr >> ADDRESS_LSHIFT) << ADDRESS_RSHIFT; 173*91f16700Schasinglulu printf("\tgwin %d 0x%016" PRIx64 " 0x%016" PRIx64 "\n", 174*91f16700Schasinglulu (cr >> 8) & 0xF, alr, ahr); 175*91f16700Schasinglulu } 176*91f16700Schasinglulu } 177*91f16700Schasinglulu } 178*91f16700Schasinglulu #endif 179*91f16700Schasinglulu 180*91f16700Schasinglulu int init_gwin(int ap_index) 181*91f16700Schasinglulu { 182*91f16700Schasinglulu struct addr_map_win *win; 183*91f16700Schasinglulu uint32_t win_id; 184*91f16700Schasinglulu uint32_t win_count; 185*91f16700Schasinglulu uint32_t win_reg; 186*91f16700Schasinglulu 187*91f16700Schasinglulu INFO("Initializing GWIN Address decoding\n"); 188*91f16700Schasinglulu 189*91f16700Schasinglulu /* Get the array of the windows and its size */ 190*91f16700Schasinglulu marvell_get_gwin_memory_map(ap_index, &win, &win_count); 191*91f16700Schasinglulu if (win_count <= 0) { 192*91f16700Schasinglulu INFO("no windows configurations found\n"); 193*91f16700Schasinglulu return 0; 194*91f16700Schasinglulu } 195*91f16700Schasinglulu 196*91f16700Schasinglulu if (win_count > MVEBU_GWIN_MAX_WINS) { 197*91f16700Schasinglulu ERROR("number of windows is bigger than %d\n", 198*91f16700Schasinglulu MVEBU_GWIN_MAX_WINS); 199*91f16700Schasinglulu return 0; 200*91f16700Schasinglulu } 201*91f16700Schasinglulu 202*91f16700Schasinglulu /* disable all windows */ 203*91f16700Schasinglulu for (win_id = 0; win_id < MVEBU_GWIN_MAX_WINS; win_id++) 204*91f16700Schasinglulu gwin_disable_window(ap_index, win_id); 205*91f16700Schasinglulu 206*91f16700Schasinglulu /* enable relevant windows */ 207*91f16700Schasinglulu for (win_id = 0; win_id < win_count; win_id++, win++) { 208*91f16700Schasinglulu gwin_check(win); 209*91f16700Schasinglulu gwin_enable_window(ap_index, win, win_id); 210*91f16700Schasinglulu } 211*91f16700Schasinglulu 212*91f16700Schasinglulu /* GWIN Miss feature has not verified, therefore any access towards 213*91f16700Schasinglulu * remote AP should be accompanied with proper configuration to 214*91f16700Schasinglulu * GWIN registers group and therefore the GWIN Miss feature 215*91f16700Schasinglulu * should be set into Bypass mode, need to make sure all GWIN regions 216*91f16700Schasinglulu * are defined correctly that will assure no GWIN miss occurrence 217*91f16700Schasinglulu * JIRA-AURORA2-1630 218*91f16700Schasinglulu */ 219*91f16700Schasinglulu INFO("Update GWIN miss bypass\n"); 220*91f16700Schasinglulu win_reg = mmio_read_32(CCU_GRU_CR_OFFSET(ap_index)); 221*91f16700Schasinglulu win_reg |= CCR_GRU_CR_GWIN_MBYPASS; 222*91f16700Schasinglulu mmio_write_32(CCU_GRU_CR_OFFSET(ap_index), win_reg); 223*91f16700Schasinglulu 224*91f16700Schasinglulu #ifdef DEBUG_ADDR_MAP 225*91f16700Schasinglulu dump_gwin(ap_index); 226*91f16700Schasinglulu #endif 227*91f16700Schasinglulu 228*91f16700Schasinglulu INFO("Done GWIN Address decoding Initializing\n"); 229*91f16700Schasinglulu 230*91f16700Schasinglulu return 0; 231*91f16700Schasinglulu } 232