1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright 2008-2011 Freescale Semiconductor, Inc. 4 * 5 * (C) Copyright 2000 6 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 7 */ 8 9#include <common.h> 10#include <display_options.h> 11#include <asm/bitops.h> 12#include <asm/global_data.h> 13#include <linux/compiler.h> 14#include <asm/fsl_law.h> 15#include <asm/io.h> 16#include <linux/log2.h> 17 18DECLARE_GLOBAL_DATA_PTR; 19 20#define FSL_HW_NUM_LAWS CONFIG_SYS_FSL_NUM_LAWS 21 22#ifdef CONFIG_FSL_CORENET 23#define LAW_BASE (CFG_SYS_FSL_CORENET_CCM_ADDR) 24#define LAWAR_ADDR(x) (&((ccsr_local_t *)LAW_BASE)->law[x].lawar) 25#define LAWBARH_ADDR(x) (&((ccsr_local_t *)LAW_BASE)->law[x].lawbarh) 26#define LAWBARL_ADDR(x) (&((ccsr_local_t *)LAW_BASE)->law[x].lawbarl) 27#define LAWBAR_SHIFT 0 28#else 29#define LAW_BASE (CONFIG_SYS_IMMR + 0xc08) 30#define LAWAR_ADDR(x) ((u32 *)LAW_BASE + 8 * x + 2) 31#define LAWBAR_ADDR(x) ((u32 *)LAW_BASE + 8 * x) 32#define LAWBAR_SHIFT 12 33#endif 34 35 36static inline phys_addr_t get_law_base_addr(int idx) 37{ 38#ifdef CONFIG_FSL_CORENET 39 return (phys_addr_t) 40 ((u64)in_be32(LAWBARH_ADDR(idx)) << 32) | 41 in_be32(LAWBARL_ADDR(idx)); 42#else 43 return (phys_addr_t)in_be32(LAWBAR_ADDR(idx)) << LAWBAR_SHIFT; 44#endif 45} 46 47static inline void set_law_base_addr(int idx, phys_addr_t addr) 48{ 49#ifdef CONFIG_FSL_CORENET 50 out_be32(LAWBARL_ADDR(idx), addr & 0xffffffff); 51 out_be32(LAWBARH_ADDR(idx), (u64)addr >> 32); 52#else 53 out_be32(LAWBAR_ADDR(idx), addr >> LAWBAR_SHIFT); 54#endif 55} 56 57void set_law(u8 idx, phys_addr_t addr, enum law_size sz, enum law_trgt_if id) 58{ 59 gd->arch.used_laws |= (1 << idx); 60 61 out_be32(LAWAR_ADDR(idx), 0); 62 set_law_base_addr(idx, addr); 63 out_be32(LAWAR_ADDR(idx), LAW_EN | ((u32)id << 20) | (u32)sz); 64 65 /* Read back so that we sync the writes */ 66 in_be32(LAWAR_ADDR(idx)); 67} 68 69void disable_law(u8 idx) 70{ 71 gd->arch.used_laws &= ~(1 << idx); 72 73 out_be32(LAWAR_ADDR(idx), 0); 74 set_law_base_addr(idx, 0); 75 76 /* Read back so that we sync the writes */ 77 in_be32(LAWAR_ADDR(idx)); 78 79 return; 80} 81 82#if !defined(CONFIG_NAND_SPL) && \ 83 (!defined(CONFIG_SPL_BUILD) || !CONFIG_IS_ENABLED(INIT_MINIMAL)) 84static int get_law_entry(u8 i, struct law_entry *e) 85{ 86 u32 lawar; 87 88 lawar = in_be32(LAWAR_ADDR(i)); 89 90 if (!(lawar & LAW_EN)) 91 return 0; 92 93 e->addr = get_law_base_addr(i); 94 e->size = lawar & 0x3f; 95 e->trgt_id = (lawar >> 20) & 0xff; 96 97 return 1; 98} 99#endif 100 101int set_next_law(phys_addr_t addr, enum law_size sz, enum law_trgt_if id) 102{ 103 u32 idx = ffz(gd->arch.used_laws); 104 105 if (idx >= FSL_HW_NUM_LAWS) 106 return -1; 107 108 set_law(idx, addr, sz, id); 109 110 return idx; 111} 112 113#if !defined(CONFIG_NAND_SPL) && \ 114 (!defined(CONFIG_SPL_BUILD) || !CONFIG_IS_ENABLED(INIT_MINIMAL)) 115int set_last_law(phys_addr_t addr, enum law_size sz, enum law_trgt_if id) 116{ 117 u32 idx; 118 119 /* we have no LAWs free */ 120 if (gd->arch.used_laws == -1) 121 return -1; 122 123 /* grab the last free law */ 124 idx = __ilog2(~(gd->arch.used_laws)); 125 126 if (idx >= FSL_HW_NUM_LAWS) 127 return -1; 128 129 set_law(idx, addr, sz, id); 130 131 return idx; 132} 133 134struct law_entry find_law(phys_addr_t addr) 135{ 136 struct law_entry entry; 137 int i; 138 139 entry.index = -1; 140 entry.addr = 0; 141 entry.size = 0; 142 entry.trgt_id = 0; 143 144 for (i = 0; i < FSL_HW_NUM_LAWS; i++) { 145 u64 upper; 146 147 if (!get_law_entry(i, &entry)) 148 continue; 149 150 upper = entry.addr + (2ull << entry.size); 151 if ((addr >= entry.addr) && (addr < upper)) { 152 entry.index = i; 153 break; 154 } 155 } 156 157 return entry; 158} 159 160void print_laws(void) 161{ 162 int i; 163 u32 lawar; 164 165 printf("\nLocal Access Window Configuration\n"); 166 for (i = 0; i < FSL_HW_NUM_LAWS; i++) { 167 lawar = in_be32(LAWAR_ADDR(i)); 168#ifdef CONFIG_FSL_CORENET 169 printf("LAWBARH%02d: 0x%08x LAWBARL%02d: 0x%08x", 170 i, in_be32(LAWBARH_ADDR(i)), 171 i, in_be32(LAWBARL_ADDR(i))); 172#else 173 printf("LAWBAR%02d: 0x%08x", i, in_be32(LAWBAR_ADDR(i))); 174#endif 175 printf(" LAWAR%02d: 0x%08x\n", i, lawar); 176 printf("\t(EN: %d TGT: 0x%02x SIZE: ", 177 (lawar & LAW_EN) ? 1 : 0, (lawar >> 20) & 0xff); 178 print_size(lawar_size(lawar), ")\n"); 179 } 180 181 return; 182} 183 184/* use up to 2 LAWs for DDR, used the last available LAWs */ 185int set_ddr_laws(u64 start, u64 sz, enum law_trgt_if id) 186{ 187 u64 start_align, law_sz; 188 int law_sz_enc; 189 190 if (start == 0) 191 start_align = 1ull << (LAW_SIZE_32G + 1); 192 else 193 start_align = 1ull << (__ffs64(start)); 194 law_sz = min(start_align, sz); 195 law_sz_enc = __ilog2_u64(law_sz) - 1; 196 197 if (set_last_law(start, law_sz_enc, id) < 0) 198 return -1; 199 200 /* recalculate size based on what was actually covered by the law */ 201 law_sz = 1ull << __ilog2_u64(law_sz); 202 203 /* do we still have anything to map */ 204 sz = sz - law_sz; 205 if (sz) { 206 start += law_sz; 207 208 start_align = 1ull << (__ffs64(start)); 209 law_sz = min(start_align, sz); 210 law_sz_enc = __ilog2_u64(law_sz) - 1; 211 212 if (set_last_law(start, law_sz_enc, id) < 0) 213 return -1; 214 } else { 215 return 0; 216 } 217 218 /* do we still have anything to map */ 219 sz = sz - law_sz; 220 if (sz) 221 return 1; 222 223 return 0; 224} 225#endif /* not SPL */ 226 227void disable_non_ddr_laws(void) 228{ 229 int i; 230 int id; 231 for (i = 0; i < FSL_HW_NUM_LAWS; i++) { 232 u32 lawar = in_be32(LAWAR_ADDR(i)); 233 234 if (lawar & LAW_EN) { 235 id = (lawar & ~LAW_EN) >> 20; 236 switch (id) { 237 case LAW_TRGT_IF_DDR_1: 238 case LAW_TRGT_IF_DDR_2: 239 case LAW_TRGT_IF_DDR_3: 240 case LAW_TRGT_IF_DDR_4: 241 case LAW_TRGT_IF_DDR_INTRLV: 242 case LAW_TRGT_IF_DDR_INTLV_34: 243 case LAW_TRGT_IF_DDR_INTLV_123: 244 case LAW_TRGT_IF_DDR_INTLV_1234: 245 continue; 246 default: 247 disable_law(i); 248 } 249 } 250 } 251} 252 253void init_laws(void) 254{ 255 int i; 256 257#if FSL_HW_NUM_LAWS < 32 258 gd->arch.used_laws = ~((1 << FSL_HW_NUM_LAWS) - 1); 259#elif FSL_HW_NUM_LAWS == 32 260 gd->arch.used_laws = 0; 261#else 262#error FSL_HW_NUM_LAWS can not be greater than 32 w/o code changes 263#endif 264 265#if defined(CONFIG_NXP_ESBC) && defined(CONFIG_E500) && \ 266 !defined(CONFIG_E500MC) 267 /* ISBC (Boot ROM) creates a LAW 0 entry for non PBL platforms, 268 * which is not disabled before transferring the control to uboot. 269 * Disable the LAW 0 entry here. 270 */ 271 disable_law(0); 272#endif 273 274#if !defined(CONFIG_NXP_ESBC) 275 /* 276 * if any non DDR LAWs has been created earlier, remove them before 277 * LAW table is parsed. 278 */ 279 disable_non_ddr_laws(); 280#endif 281 282 /* 283 * Any LAWs that were set up before we booted assume they are meant to 284 * be around and mark them used. 285 */ 286 for (i = 0; i < FSL_HW_NUM_LAWS; i++) { 287 u32 lawar = in_be32(LAWAR_ADDR(i)); 288 289 if (lawar & LAW_EN) 290 gd->arch.used_laws |= (1 << i); 291 } 292 293 for (i = 0; i < num_law_entries; i++) { 294 if (law_table[i].index == -1) 295 set_next_law(law_table[i].addr, law_table[i].size, 296 law_table[i].trgt_id); 297 else 298 set_law(law_table[i].index, law_table[i].addr, 299 law_table[i].size, law_table[i].trgt_id); 300 } 301 302#ifdef CONFIG_SRIO_PCIE_BOOT_SLAVE 303 /* check RCW to get which port is used for boot */ 304 ccsr_gur_t *gur = (void *)CFG_SYS_MPC85xx_GUTS_ADDR; 305 u32 bootloc = in_be32(&gur->rcwsr[6]); 306 /* 307 * in SRIO or PCIE boot we need to set specail LAWs for 308 * SRIO or PCIE interfaces. 309 */ 310 switch ((bootloc & FSL_CORENET_RCWSR6_BOOT_LOC) >> 23) { 311 case 0x0: /* boot from PCIE1 */ 312 set_next_law(CFG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS, 313 LAW_SIZE_1M, 314 LAW_TRGT_IF_PCIE_1); 315 set_next_law(CFG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS, 316 LAW_SIZE_1M, 317 LAW_TRGT_IF_PCIE_1); 318 break; 319 case 0x1: /* boot from PCIE2 */ 320 set_next_law(CFG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS, 321 LAW_SIZE_1M, 322 LAW_TRGT_IF_PCIE_2); 323 set_next_law(CFG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS, 324 LAW_SIZE_1M, 325 LAW_TRGT_IF_PCIE_2); 326 break; 327 case 0x2: /* boot from PCIE3 */ 328 set_next_law(CFG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS, 329 LAW_SIZE_1M, 330 LAW_TRGT_IF_PCIE_3); 331 set_next_law(CFG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS, 332 LAW_SIZE_1M, 333 LAW_TRGT_IF_PCIE_3); 334 break; 335 case 0x8: /* boot from SRIO1 */ 336 set_next_law(CFG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS, 337 LAW_SIZE_1M, 338 LAW_TRGT_IF_RIO_1); 339 set_next_law(CFG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS, 340 LAW_SIZE_1M, 341 LAW_TRGT_IF_RIO_1); 342 break; 343 case 0x9: /* boot from SRIO2 */ 344 set_next_law(CFG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS, 345 LAW_SIZE_1M, 346 LAW_TRGT_IF_RIO_2); 347 set_next_law(CFG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS, 348 LAW_SIZE_1M, 349 LAW_TRGT_IF_RIO_2); 350 break; 351 default: 352 break; 353 } 354#endif 355 356 return; 357} 358