uboot/arch/arm/mach-mvebu/armada3700/cpu.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2016 Stefan Roese <sr@denx.de>
   4 * Copyright (C) 2020 Marek Behun <marek.behun@nic.cz>
   5 */
   6
   7#include <common.h>
   8#include <cpu_func.h>
   9#include <dm.h>
  10#include <fdtdec.h>
  11#include <fdt_support.h>
  12#include <init.h>
  13#include <asm/global_data.h>
  14#include <linux/bitops.h>
  15#include <linux/libfdt.h>
  16#include <linux/sizes.h>
  17#include <asm/io.h>
  18#include <asm/system.h>
  19#include <asm/arch/cpu.h>
  20#include <asm/arch/soc.h>
  21#include <asm/armv8/mmu.h>
  22#include <sort.h>
  23
  24/* Armada 3700 */
  25#define MVEBU_GPIO_NB_REG_BASE          (MVEBU_REGISTER(0x13800))
  26
  27#define MVEBU_TEST_PIN_LATCH_N          (MVEBU_GPIO_NB_REG_BASE + 0x8)
  28#define MVEBU_XTAL_MODE_MASK            BIT(9)
  29#define MVEBU_XTAL_MODE_OFFS            9
  30#define MVEBU_XTAL_CLOCK_25MHZ          0x0
  31#define MVEBU_XTAL_CLOCK_40MHZ          0x1
  32
  33#define MVEBU_NB_WARM_RST_REG           (MVEBU_GPIO_NB_REG_BASE + 0x40)
  34#define MVEBU_NB_WARM_RST_MAGIC_NUM     0x1d1e
  35
  36/* Armada 3700 CPU Address Decoder registers */
  37#define MVEBU_CPU_DEC_WIN_REG_BASE      (size_t)(MVEBU_REGISTER(0xcf00))
  38#define MVEBU_CPU_DEC_WIN_CTRL(w) \
  39        (MVEBU_CPU_DEC_WIN_REG_BASE + ((w) << 4))
  40#define MVEBU_CPU_DEC_WIN_CTRL_EN       BIT(0)
  41#define MVEBU_CPU_DEC_WIN_CTRL_TGT_MASK 0xf
  42#define MVEBU_CPU_DEC_WIN_CTRL_TGT_OFFS 4
  43#define MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM 0
  44#define MVEBU_CPU_DEC_WIN_CTRL_TGT_PCIE 2
  45#define MVEBU_CPU_DEC_WIN_SIZE(w)       (MVEBU_CPU_DEC_WIN_CTRL(w) + 0x4)
  46#define MVEBU_CPU_DEC_WIN_BASE(w)       (MVEBU_CPU_DEC_WIN_CTRL(w) + 0x8)
  47#define MVEBU_CPU_DEC_WIN_REMAP(w)      (MVEBU_CPU_DEC_WIN_CTRL(w) + 0xc)
  48#define MVEBU_CPU_DEC_WIN_GRANULARITY   16
  49#define MVEBU_CPU_DEC_WINS              5
  50#define MVEBU_CPU_DEC_CCI_BASE          (MVEBU_CPU_DEC_WIN_REG_BASE + 0xe0)
  51#define MVEBU_CPU_DEC_ROM_BASE          (MVEBU_CPU_DEC_WIN_REG_BASE + 0xf4)
  52
  53#define MAX_MEM_MAP_REGIONS             (MVEBU_CPU_DEC_WINS + 4)
  54
  55#define A3700_PTE_BLOCK_NORMAL \
  56        (PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_INNER_SHARE)
  57#define A3700_PTE_BLOCK_DEVICE \
  58        (PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | PTE_BLOCK_NON_SHARE)
  59
  60DECLARE_GLOBAL_DATA_PTR;
  61
  62static struct mm_region mvebu_mem_map[MAX_MEM_MAP_REGIONS] = {
  63        {
  64                /*
  65                 * SRAM, MMIO regions
  66                 * Don't remove this, build_mem_map needs it.
  67                 */
  68                .phys = SOC_REGS_PHY_BASE,
  69                .virt = SOC_REGS_PHY_BASE,
  70                .size = 0x02000000UL,   /* 32MiB internal registers */
  71                .attrs = A3700_PTE_BLOCK_DEVICE
  72        },
  73};
  74
  75struct mm_region *mem_map = mvebu_mem_map;
  76
  77static int get_cpu_dec_win(int win, u32 *tgt, u32 *base, u32 *size)
  78{
  79        u32 reg;
  80
  81        reg = readl(MVEBU_CPU_DEC_WIN_CTRL(win));
  82        if (!(reg & MVEBU_CPU_DEC_WIN_CTRL_EN))
  83                return -1;
  84
  85        if (tgt) {
  86                reg >>= MVEBU_CPU_DEC_WIN_CTRL_TGT_OFFS;
  87                reg &= MVEBU_CPU_DEC_WIN_CTRL_TGT_MASK;
  88                *tgt = reg;
  89        }
  90
  91        if (base) {
  92                reg = readl(MVEBU_CPU_DEC_WIN_BASE(win));
  93                *base = reg << MVEBU_CPU_DEC_WIN_GRANULARITY;
  94        }
  95
  96        if (size) {
  97                /*
  98                 * Window size is encoded as the number of 1s from LSB to MSB,
  99                 * followed by 0s. The number of 1s specifies the size in 64 KiB
 100                 * granularity.
 101                 */
 102                reg = readl(MVEBU_CPU_DEC_WIN_SIZE(win));
 103                *size = ((reg + 1) << MVEBU_CPU_DEC_WIN_GRANULARITY);
 104        }
 105
 106        return 0;
 107}
 108
 109/*
 110 * Builds mem_map according to CPU Address Decoder settings, which were set by
 111 * the TIMH image on the Cortex-M3 secure processor, or by ARM Trusted Firmware
 112 */
 113static void build_mem_map(void)
 114{
 115        int win, region;
 116        u32 reg;
 117
 118        region = 1;
 119
 120        /* CCI-400 */
 121        reg = readl(MVEBU_CPU_DEC_CCI_BASE);
 122        mvebu_mem_map[region].phys = reg << 20;
 123        mvebu_mem_map[region].virt = reg << 20;
 124        mvebu_mem_map[region].size = SZ_64K;
 125        mvebu_mem_map[region].attrs = A3700_PTE_BLOCK_DEVICE;
 126        ++region;
 127
 128        /* AP BootROM */
 129        reg = readl(MVEBU_CPU_DEC_ROM_BASE);
 130        mvebu_mem_map[region].phys = reg << 20;
 131        mvebu_mem_map[region].virt = reg << 20;
 132        mvebu_mem_map[region].size = SZ_1M;
 133        mvebu_mem_map[region].attrs = A3700_PTE_BLOCK_NORMAL;
 134        ++region;
 135
 136        for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
 137                u32 base, tgt, size;
 138                u64 attrs;
 139
 140                /* skip disabled windows */
 141                if (get_cpu_dec_win(win, &tgt, &base, &size))
 142                        continue;
 143
 144                if (tgt == MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
 145                        attrs = A3700_PTE_BLOCK_NORMAL;
 146                else if (tgt == MVEBU_CPU_DEC_WIN_CTRL_TGT_PCIE)
 147                        attrs = A3700_PTE_BLOCK_DEVICE;
 148                else
 149                        /* skip windows with other targets */
 150                        continue;
 151
 152                mvebu_mem_map[region].phys = base;
 153                mvebu_mem_map[region].virt = base;
 154                mvebu_mem_map[region].size = size;
 155                mvebu_mem_map[region].attrs = attrs;
 156                ++region;
 157        }
 158
 159        /* add list terminator */
 160        mvebu_mem_map[region].size = 0;
 161        mvebu_mem_map[region].attrs = 0;
 162}
 163
 164void enable_caches(void)
 165{
 166        icache_enable();
 167        dcache_enable();
 168}
 169
 170int a3700_dram_init(void)
 171{
 172        int win;
 173
 174        build_mem_map();
 175
 176        gd->ram_size = 0;
 177        for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
 178                u32 base, tgt, size;
 179
 180                /* skip disabled windows */
 181                if (get_cpu_dec_win(win, &tgt, &base, &size))
 182                        continue;
 183
 184                /* skip non-DRAM windows */
 185                if (tgt != MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
 186                        continue;
 187
 188                /*
 189                 * It is possible that one image was built for boards with
 190                 * different RAM sizes, for example 512 MiB and 1 GiB.
 191                 * We therefore try to determine the actual RAM size in the
 192                 * window with get_ram_size.
 193                 */
 194                gd->ram_size += get_ram_size((void *)(size_t)base, size);
 195        }
 196
 197        return 0;
 198}
 199
 200struct a3700_dram_window {
 201        size_t base, size;
 202};
 203
 204static int dram_win_cmp(const void *a, const void *b)
 205{
 206        size_t ab, bb;
 207
 208        ab = ((const struct a3700_dram_window *)a)->base;
 209        bb = ((const struct a3700_dram_window *)b)->base;
 210
 211        if (ab < bb)
 212                return -1;
 213        else if (ab > bb)
 214                return 1;
 215        else
 216                return 0;
 217}
 218
 219int a3700_dram_init_banksize(void)
 220{
 221        struct a3700_dram_window dram_wins[MVEBU_CPU_DEC_WINS];
 222        int bank, win, ndram_wins;
 223        u32 last_end;
 224        size_t size;
 225
 226        ndram_wins = 0;
 227        for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
 228                u32 base, tgt, size;
 229
 230                /* skip disabled windows */
 231                if (get_cpu_dec_win(win, &tgt, &base, &size))
 232                        continue;
 233
 234                /* skip non-DRAM windows */
 235                if (tgt != MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
 236                        continue;
 237
 238                dram_wins[win].base = base;
 239                dram_wins[win].size = size;
 240                ++ndram_wins;
 241        }
 242
 243        qsort(dram_wins, ndram_wins, sizeof(dram_wins[0]), dram_win_cmp);
 244
 245        bank = 0;
 246        last_end = -1;
 247
 248        for (win = 0; win < ndram_wins; ++win) {
 249                /* again determining actual RAM size as in a3700_dram_init */
 250                size = get_ram_size((void *)dram_wins[win].base,
 251                                    dram_wins[win].size);
 252
 253                /*
 254                 * Check if previous window ends as the current starts. If yes,
 255                 * merge these windows into one "bank". This is possible by this
 256                 * simple check thanks to mem_map regions being qsorted in
 257                 * build_mem_map.
 258                 */
 259                if (last_end == dram_wins[win].base) {
 260                        gd->bd->bi_dram[bank - 1].size += size;
 261                        last_end += size;
 262                } else {
 263                        if (bank == CONFIG_NR_DRAM_BANKS) {
 264                                printf("Need more CONFIG_NR_DRAM_BANKS\n");
 265                                return -ENOBUFS;
 266                        }
 267
 268                        gd->bd->bi_dram[bank].start = dram_wins[win].base;
 269                        gd->bd->bi_dram[bank].size = size;
 270                        last_end = dram_wins[win].base + size;
 271                        ++bank;
 272                }
 273        }
 274
 275        /*
 276         * If there is more place for DRAM BANKS definitions than needed, fill
 277         * the rest with zeros.
 278         */
 279        for (; bank < CONFIG_NR_DRAM_BANKS; ++bank) {
 280                gd->bd->bi_dram[bank].start = 0;
 281                gd->bd->bi_dram[bank].size = 0;
 282        }
 283
 284        return 0;
 285}
 286
 287static u32 find_pcie_window_base(void)
 288{
 289        int win;
 290
 291        for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
 292                u32 base, tgt;
 293
 294                /* skip disabled windows */
 295                if (get_cpu_dec_win(win, &tgt, &base, NULL))
 296                        continue;
 297
 298                if (tgt == MVEBU_CPU_DEC_WIN_CTRL_TGT_PCIE)
 299                        return base;
 300        }
 301
 302        return -1;
 303}
 304
 305static int fdt_setprop_inplace_u32_partial(void *blob, int node,
 306                                           const char *name,
 307                                           u32 idx, u32 val)
 308{
 309        val = cpu_to_fdt32(val);
 310
 311        return fdt_setprop_inplace_namelen_partial(blob, node, name,
 312                                                   strlen(name),
 313                                                   idx * sizeof(u32),
 314                                                   &val, sizeof(u32));
 315}
 316
 317int a3700_fdt_fix_pcie_regions(void *blob)
 318{
 319        u32 base, lowest_cpu_addr, fix_offset;
 320        int pci_cells, cpu_cells, size_cells;
 321        const u32 *ranges;
 322        int node, pnode;
 323        int ret, i, len;
 324
 325        base = find_pcie_window_base();
 326        if (base == -1)
 327                return -ENOENT;
 328
 329        node = fdt_node_offset_by_compatible(blob, -1, "marvell,armada-3700-pcie");
 330        if (node < 0)
 331                return node;
 332
 333        ranges = fdt_getprop(blob, node, "ranges", &len);
 334        if (!ranges || !len || len % sizeof(u32))
 335                return -EINVAL;
 336
 337        /*
 338         * The "ranges" property is an array of
 339         *   { <PCI address> <CPU address> <size in PCI address space> }
 340         * where number of PCI address cells and size cells is stored in the
 341         * "#address-cells" and "#size-cells" properties of the same node
 342         * containing the "ranges" property and number of CPU address cells
 343         * is stored in the parent's "#address-cells" property.
 344         *
 345         * All 3 elements can span a diffent number of cells. Fetch them.
 346         */
 347        pnode = fdt_parent_offset(blob, node);
 348        pci_cells = fdt_address_cells(blob, node);
 349        cpu_cells = fdt_address_cells(blob, pnode);
 350        size_cells = fdt_size_cells(blob, node);
 351
 352        /* PCI addresses always use 3 cells */
 353        if (pci_cells != 3)
 354                return -EINVAL;
 355
 356        /* CPU addresses on Armada 37xx always use 2 cells */
 357        if (cpu_cells != 2)
 358                return -EINVAL;
 359
 360        for (i = 0; i < len / sizeof(u32);
 361             i += pci_cells + cpu_cells + size_cells) {
 362                /*
 363                 * Parent CPU addresses on Armada 37xx are always 32-bit, so
 364                 * check that the high word is zero.
 365                 */
 366                if (fdt32_to_cpu(ranges[i + pci_cells]))
 367                        return -EINVAL;
 368
 369                if (i == 0 ||
 370                    fdt32_to_cpu(ranges[i + pci_cells + 1]) < lowest_cpu_addr)
 371                        lowest_cpu_addr = fdt32_to_cpu(ranges[i + pci_cells + 1]);
 372        }
 373
 374        /* Calculate fixup offset from the lowest (first) CPU address */
 375        fix_offset = base - lowest_cpu_addr;
 376
 377        /* If fixup offset is zero there is nothing to fix */
 378        if (!fix_offset)
 379                return 0;
 380
 381        /*
 382         * Fix each CPU address and corresponding PCI address if PCI address
 383         * is not already remapped (has the same value)
 384         */
 385        for (i = 0; i < len / sizeof(u32);
 386             i += pci_cells + cpu_cells + size_cells) {
 387                u32 cpu_addr;
 388                u64 pci_addr;
 389                int idx;
 390
 391                /* Fix CPU address */
 392                idx = i + pci_cells + cpu_cells - 1;
 393                cpu_addr = fdt32_to_cpu(ranges[idx]);
 394                ret = fdt_setprop_inplace_u32_partial(blob, node, "ranges", idx,
 395                                                      cpu_addr + fix_offset);
 396                if (ret)
 397                        return ret;
 398
 399                /* Fix PCI address only if it isn't remapped (is same as CPU) */
 400                idx = i + pci_cells - 1;
 401                pci_addr = ((u64)fdt32_to_cpu(ranges[idx - 1]) << 32) |
 402                           fdt32_to_cpu(ranges[idx]);
 403                if (cpu_addr != pci_addr)
 404                        continue;
 405
 406                ret = fdt_setprop_inplace_u32_partial(blob, node, "ranges", idx,
 407                                                      cpu_addr + fix_offset);
 408                if (ret)
 409                        return ret;
 410        }
 411
 412        return 0;
 413}
 414
 415void reset_cpu(void)
 416{
 417        /*
 418         * Write magic number of 0x1d1e to North Bridge Warm Reset register
 419         * to trigger warm reset
 420         */
 421        writel(MVEBU_NB_WARM_RST_MAGIC_NUM, MVEBU_NB_WARM_RST_REG);
 422}
 423
 424/*
 425 * get_ref_clk
 426 *
 427 * return: reference clock in MHz (25 or 40)
 428 */
 429u32 get_ref_clk(void)
 430{
 431        u32 regval;
 432
 433        regval = (readl(MVEBU_TEST_PIN_LATCH_N) & MVEBU_XTAL_MODE_MASK) >>
 434                MVEBU_XTAL_MODE_OFFS;
 435
 436        if (regval == MVEBU_XTAL_CLOCK_25MHZ)
 437                return 25;
 438        else
 439                return 40;
 440}
 441