uboot/arch/powerpc/cpu/mpc8xxx/law.c
<<
>>
Prefs
   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