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