uboot/drivers/cpu/riscv_cpu.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
   4 * Copyright (C) 2020, Sean Anderson <seanga2@gmail.com>
   5 */
   6
   7#include <clk.h>
   8#include <common.h>
   9#include <cpu.h>
  10#include <dm.h>
  11#include <errno.h>
  12#include <log.h>
  13#include <asm/global_data.h>
  14#include <dm/device-internal.h>
  15#include <dm/lists.h>
  16#include <linux/bitops.h>
  17#include <linux/err.h>
  18
  19DECLARE_GLOBAL_DATA_PTR;
  20
  21static int riscv_cpu_get_desc(const struct udevice *dev, char *buf, int size)
  22{
  23        const char *isa;
  24
  25        isa = dev_read_string(dev, "riscv,isa");
  26        if (size < (strlen(isa) + 1))
  27                return -ENOSPC;
  28
  29        strcpy(buf, isa);
  30
  31        return 0;
  32}
  33
  34static int riscv_cpu_get_info(const struct udevice *dev, struct cpu_info *info)
  35{
  36        int ret;
  37        struct clk clk;
  38        const char *mmu;
  39        u32 i_cache_size;
  40        u32 d_cache_size;
  41
  42        /* First try getting the frequency from the assigned clock */
  43        ret = clk_get_by_index((struct udevice *)dev, 0, &clk);
  44        if (!ret) {
  45                ret = clk_get_rate(&clk);
  46                if (!IS_ERR_VALUE(ret))
  47                        info->cpu_freq = ret;
  48                clk_free(&clk);
  49        }
  50
  51        if (!info->cpu_freq)
  52                dev_read_u32(dev, "clock-frequency", (u32 *)&info->cpu_freq);
  53
  54        mmu = dev_read_string(dev, "mmu-type");
  55        if (mmu)
  56                info->features |= BIT(CPU_FEAT_MMU);
  57
  58        /* check if I cache is present */
  59        ret = dev_read_u32(dev, "i-cache-size", &i_cache_size);
  60        if (ret)
  61                /* if not found check if d-cache is present */
  62                ret = dev_read_u32(dev, "d-cache-size", &d_cache_size);
  63
  64        /* if either I or D cache is present set L1 cache feature */
  65        if (!ret)
  66                info->features |= BIT(CPU_FEAT_L1_CACHE);
  67
  68        return 0;
  69}
  70
  71static int riscv_cpu_get_count(const struct udevice *dev)
  72{
  73        ofnode node;
  74        int num = 0;
  75
  76        ofnode_for_each_subnode(node, dev_ofnode(dev->parent)) {
  77                const char *device_type;
  78
  79                /* skip if hart is marked as not available in the device tree */
  80                if (!ofnode_is_available(node))
  81                        continue;
  82
  83                device_type = ofnode_read_string(node, "device_type");
  84                if (!device_type)
  85                        continue;
  86                if (strcmp(device_type, "cpu") == 0)
  87                        num++;
  88        }
  89
  90        return num;
  91}
  92
  93static int riscv_cpu_bind(struct udevice *dev)
  94{
  95        struct cpu_plat *plat = dev_get_parent_plat(dev);
  96        struct driver *drv;
  97        int ret;
  98
  99        /* save the hart id */
 100        plat->cpu_id = dev_read_addr(dev);
 101        /* first examine the property in current cpu node */
 102        ret = dev_read_u32(dev, "timebase-frequency", &plat->timebase_freq);
 103        /* if not found, then look at the parent /cpus node */
 104        if (ret)
 105                dev_read_u32(dev->parent, "timebase-frequency",
 106                             &plat->timebase_freq);
 107
 108        /*
 109         * Bind riscv-timer driver on boot hart.
 110         *
 111         * We only instantiate one timer device which is enough for U-Boot.
 112         * Pass the "timebase-frequency" value as the driver data for the
 113         * timer device.
 114         *
 115         * Return value is not checked since it's possible that the timer
 116         * driver is not included.
 117         */
 118        if (plat->cpu_id == gd->arch.boot_hart && plat->timebase_freq) {
 119                drv = lists_driver_lookup_name("riscv_timer");
 120                if (!drv) {
 121                        debug("Cannot find the timer driver, not included?\n");
 122                        return 0;
 123                }
 124
 125                device_bind_with_driver_data(dev, drv, "riscv_timer",
 126                                             plat->timebase_freq, ofnode_null(),
 127                                             NULL);
 128        }
 129
 130        return 0;
 131}
 132
 133static int riscv_cpu_probe(struct udevice *dev)
 134{
 135        int ret = 0;
 136        struct clk clk;
 137
 138        /* Get a clock if it exists */
 139        ret = clk_get_by_index(dev, 0, &clk);
 140        if (ret)
 141                return 0;
 142
 143        ret = clk_enable(&clk);
 144        clk_free(&clk);
 145        if (ret == -ENOSYS || ret == -ENOTSUPP)
 146                return 0;
 147        else
 148                return ret;
 149}
 150
 151static const struct cpu_ops riscv_cpu_ops = {
 152        .get_desc       = riscv_cpu_get_desc,
 153        .get_info       = riscv_cpu_get_info,
 154        .get_count      = riscv_cpu_get_count,
 155};
 156
 157static const struct udevice_id riscv_cpu_ids[] = {
 158        { .compatible = "riscv" },
 159        { }
 160};
 161
 162U_BOOT_DRIVER(riscv_cpu) = {
 163        .name = "riscv_cpu",
 164        .id = UCLASS_CPU,
 165        .of_match = riscv_cpu_ids,
 166        .bind = riscv_cpu_bind,
 167        .probe = riscv_cpu_probe,
 168        .ops = &riscv_cpu_ops,
 169        .flags = DM_FLAG_PRE_RELOC,
 170};
 171