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