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