uboot/arch/riscv/cpu/cpu.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
   4 */
   5
   6#include <common.h>
   7#include <cpu.h>
   8#include <dm.h>
   9#include <dm/lists.h>
  10#include <init.h>
  11#include <log.h>
  12#include <asm/encoding.h>
  13#include <dm/uclass-internal.h>
  14#include <linux/bitops.h>
  15
  16/*
  17 * The variables here must be stored in the data section since they are used
  18 * before the bss section is available.
  19 */
  20#ifndef CONFIG_XIP
  21u32 hart_lottery __section(".data") = 0;
  22
  23/*
  24 * The main hart running U-Boot has acquired available_harts_lock until it has
  25 * finished initialization of global data.
  26 */
  27u32 available_harts_lock = 1;
  28#endif
  29
  30static inline bool supports_extension(char ext)
  31{
  32#ifdef CONFIG_CPU
  33        struct udevice *dev;
  34        char desc[32];
  35
  36        uclass_find_first_device(UCLASS_CPU, &dev);
  37        if (!dev) {
  38                debug("unable to find the RISC-V cpu device\n");
  39                return false;
  40        }
  41        if (!cpu_get_desc(dev, desc, sizeof(desc))) {
  42                /* skip the first 4 characters (rv32|rv64) */
  43                if (strchr(desc + 4, ext))
  44                        return true;
  45        }
  46
  47        return false;
  48#else  /* !CONFIG_CPU */
  49#if CONFIG_IS_ENABLED(RISCV_MMODE)
  50        return csr_read(CSR_MISA) & (1 << (ext - 'a'));
  51#else  /* !CONFIG_IS_ENABLED(RISCV_MMODE) */
  52#warning "There is no way to determine the available extensions in S-mode."
  53#warning "Please convert your board to use the RISC-V CPU driver."
  54        return false;
  55#endif /* CONFIG_IS_ENABLED(RISCV_MMODE) */
  56#endif /* CONFIG_CPU */
  57}
  58
  59static int riscv_cpu_probe(void)
  60{
  61#ifdef CONFIG_CPU
  62        int ret;
  63
  64        /* probe cpus so that RISC-V timer can be bound */
  65        ret = cpu_probe_all();
  66        if (ret)
  67                return log_msg_ret("RISC-V cpus probe failed\n", ret);
  68#endif
  69
  70        return 0;
  71}
  72
  73/*
  74 * This is called on secondary harts just after the IPI is init'd. Currently
  75 * there's nothing to do, since we just need to clear any existing IPIs, and
  76 * that is handled by the sending of an ipi itself.
  77 */
  78#if CONFIG_IS_ENABLED(SMP)
  79static void dummy_pending_ipi_clear(ulong hart, ulong arg0, ulong arg1)
  80{
  81}
  82#endif
  83
  84int arch_cpu_init_dm(void)
  85{
  86        int ret;
  87
  88        ret = riscv_cpu_probe();
  89        if (ret)
  90                return ret;
  91
  92        /* Enable FPU */
  93        if (supports_extension('d') || supports_extension('f')) {
  94                csr_set(MODE_PREFIX(status), MSTATUS_FS);
  95                csr_write(CSR_FCSR, 0);
  96        }
  97
  98        if (CONFIG_IS_ENABLED(RISCV_MMODE)) {
  99                /*
 100                 * Enable perf counters for cycle, time,
 101                 * and instret counters only
 102                 */
 103#ifdef CONFIG_RISCV_PRIV_1_9
 104                csr_write(CSR_MSCOUNTEREN, GENMASK(2, 0));
 105                csr_write(CSR_MUCOUNTEREN, GENMASK(2, 0));
 106#else
 107                csr_write(CSR_MCOUNTEREN, GENMASK(2, 0));
 108#endif
 109
 110                /* Disable paging */
 111                if (supports_extension('s'))
 112#ifdef CONFIG_RISCV_PRIV_1_9
 113                        csr_read_clear(CSR_MSTATUS, SR_VM);
 114#else
 115                        csr_write(CSR_SATP, 0);
 116#endif
 117        }
 118
 119#if CONFIG_IS_ENABLED(SMP)
 120        ret = riscv_init_ipi();
 121        if (ret)
 122                return ret;
 123
 124        /*
 125         * Clear all pending IPIs on secondary harts. We don't do anything on
 126         * the boot hart, since we never send an IPI to ourselves, and no
 127         * interrupts are enabled
 128         */
 129        ret = smp_call_function((ulong)dummy_pending_ipi_clear, 0, 0, 0);
 130        if (ret)
 131                return ret;
 132#endif
 133
 134        return 0;
 135}
 136
 137int arch_early_init_r(void)
 138{
 139        int ret;
 140
 141        ret = riscv_cpu_probe();
 142        if (ret)
 143                return ret;
 144
 145        if (IS_ENABLED(CONFIG_SYSRESET_SBI))
 146                device_bind_driver(gd->dm_root, "sbi-sysreset",
 147                                   "sbi-sysreset", NULL);
 148
 149        return 0;
 150}
 151
 152/**
 153 * harts_early_init() - A callback function called by start.S to configure
 154 * feature settings of each hart.
 155 *
 156 * In a multi-core system, memory access shall be careful here, it shall
 157 * take care of race conditions.
 158 */
 159__weak void harts_early_init(void)
 160{
 161}
 162