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