uboot/board/emulation/qemu-ppce500/qemu-ppce500.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright 2007,2009-2014 Freescale Semiconductor, Inc.
   4 * Copyright (C) 2021, Bin Meng <bmeng.cn@gmail.com>
   5 */
   6
   7#include <common.h>
   8#include <command.h>
   9#include <cpu_func.h>
  10#include <dm.h>
  11#include <env.h>
  12#include <init.h>
  13#include <log.h>
  14#include <net.h>
  15#include <pci.h>
  16#include <time.h>
  17#include <dm/simple_bus.h>
  18#include <dm/uclass-internal.h>
  19#include <asm/global_data.h>
  20#include <asm/processor.h>
  21#include <asm/mmu.h>
  22#include <asm/fsl_pci.h>
  23#include <asm/io.h>
  24#include <linux/libfdt.h>
  25#include <fdt_support.h>
  26#include <netdev.h>
  27#include <fdtdec.h>
  28#include <errno.h>
  29#include <malloc.h>
  30#include <virtio_types.h>
  31#include <virtio.h>
  32
  33DECLARE_GLOBAL_DATA_PTR;
  34
  35/* Virtual address range for PCI region maps */
  36#define SYS_PCI_MAP_START       0x80000000
  37#define SYS_PCI_MAP_END         0xe0000000
  38
  39static void *get_fdt_virt(void)
  40{
  41        if (gd->flags & GD_FLG_RELOC)
  42                return (void *)gd->fdt_blob;
  43        else
  44                return (void *)CFG_SYS_TMPVIRT;
  45}
  46
  47static uint64_t get_fdt_phys(void)
  48{
  49        return (uint64_t)(uintptr_t)gd->fdt_blob;
  50}
  51
  52static void map_fdt_as(int esel)
  53{
  54        u32 mas0, mas1, mas2, mas3, mas7;
  55        uint64_t fdt_phys = get_fdt_phys();
  56        unsigned long fdt_phys_tlb = fdt_phys & ~0xffffful;
  57        unsigned long fdt_virt_tlb = (ulong)get_fdt_virt() & ~0xffffful;
  58
  59        mas0 = MAS0_TLBSEL(1) | MAS0_ESEL(esel);
  60        mas1 = MAS1_VALID | MAS1_TID(0) | MAS1_TS | MAS1_TSIZE(BOOKE_PAGESZ_1M);
  61        mas2 = FSL_BOOKE_MAS2(fdt_virt_tlb, 0);
  62        mas3 = FSL_BOOKE_MAS3(fdt_phys_tlb, 0, MAS3_SW|MAS3_SR);
  63        mas7 = FSL_BOOKE_MAS7(fdt_phys_tlb);
  64
  65        write_tlb(mas0, mas1, mas2, mas3, mas7);
  66}
  67
  68uint64_t get_phys_ccsrbar_addr_early(void)
  69{
  70        void *fdt = get_fdt_virt();
  71        uint64_t r;
  72        int size, node;
  73        u32 naddr;
  74        const fdt32_t *prop;
  75
  76        /*
  77         * To be able to read the FDT we need to create a temporary TLB
  78         * map for it.
  79         */
  80        map_fdt_as(10);
  81        node = fdt_path_offset(fdt, "/soc");
  82        naddr = fdt_address_cells(fdt, node);
  83        prop = fdt_getprop(fdt, node, "ranges", &size);
  84        r = fdt_translate_address(fdt, node, prop + naddr);
  85        disable_tlb(10);
  86
  87        return r;
  88}
  89
  90int checkboard(void)
  91{
  92        return 0;
  93}
  94
  95static int pci_map_region(phys_addr_t paddr, phys_size_t size, ulong *pmap_addr)
  96{
  97        ulong map_addr;
  98
  99        if (!pmap_addr)
 100                return 0;
 101
 102        map_addr = *pmap_addr;
 103
 104        /* Align map_addr */
 105        map_addr += size - 1;
 106        map_addr &= ~(size - 1);
 107
 108        if (map_addr + size >= SYS_PCI_MAP_END)
 109                return -1;
 110
 111        /* Map virtual memory for range */
 112        assert(!tlb_map_range(map_addr, paddr, size, TLB_MAP_IO));
 113        *pmap_addr = map_addr + size;
 114
 115        return 0;
 116}
 117
 118static void platform_bus_map_region(ulong map_addr, phys_addr_t paddr,
 119                                    phys_size_t size)
 120{
 121        /* Align map_addr */
 122        map_addr += size - 1;
 123        map_addr &= ~(size - 1);
 124
 125        /* Map virtual memory for range */
 126        assert(!tlb_map_range(map_addr, paddr, size, TLB_MAP_IO));
 127}
 128
 129int misc_init_r(void)
 130{
 131        struct udevice *dev;
 132        struct pci_region *io;
 133        struct pci_region *mem;
 134        struct pci_region *pre;
 135        ulong map_addr;
 136        int ret;
 137
 138        /* Ensure PCI is probed */
 139        uclass_first_device(UCLASS_PCI, &dev);
 140
 141        pci_get_regions(dev, &io, &mem, &pre);
 142
 143        /* Start MMIO and PIO range maps above RAM */
 144        map_addr = SYS_PCI_MAP_START;
 145
 146        /* Map MMIO range */
 147        ret = pci_map_region(mem->phys_start, mem->size, &map_addr);
 148        if (ret)
 149                return ret;
 150
 151        /* Map PIO range */
 152        ret = pci_map_region(io->phys_start, io->size, &map_addr);
 153        if (ret)
 154                return ret;
 155
 156        /*
 157         * Make sure virtio bus is enumerated so that peripherals
 158         * on the virtio bus can be discovered by their drivers.
 159         */
 160        virtio_init();
 161
 162        /*
 163         * U-Boot is relocated to RAM already, let's delete the temporary FDT
 164         * virtual-physical mapping that was used in the pre-relocation phase.
 165         */
 166        disable_tlb(find_tlb_idx((void *)CFG_SYS_TMPVIRT, 1));
 167
 168        /*
 169         * Detect the presence of the platform bus node, and
 170         * create a virtual memory mapping for it.
 171         */
 172        for (ret = uclass_find_first_device(UCLASS_SIMPLE_BUS, &dev);
 173             dev;
 174             ret = uclass_find_next_device(&dev)) {
 175                if (device_is_compatible(dev, "qemu,platform")) {
 176                        struct simple_bus_plat *plat = dev_get_uclass_plat(dev);
 177
 178                        platform_bus_map_region(CONFIG_PLATFORM_BUS_MAP_ADDR,
 179                                                plat->target, plat->size);
 180                        break;
 181                }
 182        }
 183
 184        return 0;
 185}
 186
 187int last_stage_init(void)
 188{
 189        void *fdt = get_fdt_virt();
 190        int len = 0;
 191        const uint64_t *prop;
 192        int chosen;
 193
 194        chosen = fdt_path_offset(fdt, "/chosen");
 195        if (chosen < 0) {
 196                printf("Couldn't find /chosen node in fdt\n");
 197                return -EIO;
 198        }
 199
 200        /* -kernel boot */
 201        prop = fdt_getprop(fdt, chosen, "qemu,boot-kernel", &len);
 202        if (prop && (len >= 8))
 203                env_set_hex("qemu_kernel_addr", *prop);
 204
 205        return 0;
 206}
 207
 208static uint64_t get_linear_ram_size(void)
 209{
 210        void *fdt = get_fdt_virt();
 211        const void *prop;
 212        int memory;
 213        int len;
 214
 215        memory = fdt_path_offset(fdt, "/memory");
 216        prop = fdt_getprop(fdt, memory, "reg", &len);
 217
 218        if (prop && len >= 16)
 219                return *(uint64_t *)(prop+8);
 220
 221        panic("Couldn't determine RAM size");
 222}
 223
 224phys_size_t fsl_ddr_sdram_size(void)
 225{
 226        return get_linear_ram_size();
 227}
 228
 229void init_tlbs(void)
 230{
 231        phys_size_t ram_size;
 232
 233        /*
 234         * Create a temporary AS=1 map for the fdt
 235         *
 236         * We use ESEL=0 here to overwrite the previous AS=0 map for ourselves
 237         * which was only 4k big. This way we don't have to clear any other maps.
 238         */
 239        map_fdt_as(0);
 240
 241        /* Fetch RAM size from the fdt */
 242        ram_size = get_linear_ram_size();
 243
 244        /* And remove our fdt map again */
 245        disable_tlb(0);
 246
 247        /* Create an internal map of manually created TLB maps */
 248        init_used_tlb_cams();
 249
 250        /* Create a dynamic AS=0 CCSRBAR mapping */
 251        assert(!tlb_map_range(CFG_SYS_CCSRBAR, CFG_SYS_CCSRBAR_PHYS,
 252                              1024 * 1024, TLB_MAP_IO));
 253
 254        /* Create a RAM map that spans all accessible RAM */
 255        setup_ddr_tlbs(ram_size >> 20);
 256
 257        /* Create a map for the TLB */
 258        assert(!tlb_map_range((ulong)get_fdt_virt(), get_fdt_phys(),
 259                              1024 * 1024, TLB_MAP_RAM));
 260}
 261
 262static uint32_t get_cpu_freq(void)
 263{
 264        void *fdt = get_fdt_virt();
 265        int cpus_node = fdt_path_offset(fdt, "/cpus");
 266        int cpu_node = fdt_first_subnode(fdt, cpus_node);
 267        const char *prop = "clock-frequency";
 268        return fdt_getprop_u32_default_node(fdt, cpu_node, 0, prop, 0);
 269}
 270
 271void get_sys_info(sys_info_t *sys_info)
 272{
 273        int freq = get_cpu_freq();
 274
 275        memset(sys_info, 0, sizeof(sys_info_t));
 276        sys_info->freq_systembus = freq;
 277        sys_info->freq_ddrbus = freq;
 278        sys_info->freq_processor[0] = freq;
 279}
 280
 281int get_clocks(void)
 282{
 283        sys_info_t sys_info;
 284
 285        get_sys_info(&sys_info);
 286
 287        gd->cpu_clk = sys_info.freq_processor[0];
 288        gd->bus_clk = sys_info.freq_systembus;
 289        gd->mem_clk = sys_info.freq_ddrbus;
 290        gd->arch.lbc_clk = sys_info.freq_ddrbus;
 291
 292        return 0;
 293}
 294
 295unsigned long get_tbclk(void)
 296{
 297        void *fdt = get_fdt_virt();
 298        int cpus_node = fdt_path_offset(fdt, "/cpus");
 299        int cpu_node = fdt_first_subnode(fdt, cpus_node);
 300        const char *prop = "timebase-frequency";
 301        return fdt_getprop_u32_default_node(fdt, cpu_node, 0, prop, 0);
 302}
 303
 304/********************************************
 305 * get_bus_freq
 306 * return system bus freq in Hz
 307 *********************************************/
 308ulong get_bus_freq(ulong dummy)
 309{
 310        sys_info_t sys_info;
 311        get_sys_info(&sys_info);
 312        return sys_info.freq_systembus;
 313}
 314
 315/*
 316 * Return the number of cores on this SOC.
 317 */
 318int cpu_numcores(void)
 319{
 320        /*
 321         * The QEMU u-boot target only needs to drive the first core,
 322         * spinning and device tree nodes get driven by QEMU itself
 323         */
 324        return 1;
 325}
 326
 327/*
 328 * Return a 32-bit mask indicating which cores are present on this SOC.
 329 */
 330u32 cpu_mask(void)
 331{
 332        return (1 << cpu_numcores()) - 1;
 333}
 334
 335/**
 336 * Return the virtual address of FDT that was passed by QEMU
 337 *
 338 * Return: virtual address of FDT received from QEMU in r3 register
 339 */
 340void *board_fdt_blob_setup(int *err)
 341{
 342        *err = 0;
 343        return get_fdt_virt();
 344}
 345
 346/* See CFG_SYS_NS16550_CLK in arch/powerpc/include/asm/config.h */
 347int get_serial_clock(void)
 348{
 349        return get_bus_freq(0);
 350}
 351