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 */
   5
   6#include <common.h>
   7#include <cpu.h>
   8#include <dm.h>
   9#include <errno.h>
  10#include <dm/device-internal.h>
  11#include <dm/lists.h>
  12
  13DECLARE_GLOBAL_DATA_PTR;
  14
  15static int riscv_cpu_get_desc(struct udevice *dev, char *buf, int size)
  16{
  17        const char *isa;
  18
  19        isa = dev_read_string(dev, "riscv,isa");
  20        if (size < (strlen(isa) + 1))
  21                return -ENOSPC;
  22
  23        strcpy(buf, isa);
  24
  25        return 0;
  26}
  27
  28static int riscv_cpu_get_info(struct udevice *dev, struct cpu_info *info)
  29{
  30        const char *mmu;
  31
  32        dev_read_u32(dev, "clock-frequency", (u32 *)&info->cpu_freq);
  33
  34        mmu = dev_read_string(dev, "mmu-type");
  35        if (!mmu)
  36                info->features |= BIT(CPU_FEAT_MMU);
  37
  38        return 0;
  39}
  40
  41static int riscv_cpu_get_count(struct udevice *dev)
  42{
  43        ofnode node;
  44        int num = 0;
  45
  46        ofnode_for_each_subnode(node, dev_ofnode(dev->parent)) {
  47                const char *device_type;
  48
  49                device_type = ofnode_read_string(node, "device_type");
  50                if (!device_type)
  51                        continue;
  52                if (strcmp(device_type, "cpu") == 0)
  53                        num++;
  54        }
  55
  56        return num;
  57}
  58
  59static int riscv_cpu_bind(struct udevice *dev)
  60{
  61        struct cpu_platdata *plat = dev_get_parent_platdata(dev);
  62        struct driver *drv;
  63        int ret;
  64
  65        /* save the hart id */
  66        plat->cpu_id = dev_read_addr(dev);
  67        /* first examine the property in current cpu node */
  68        ret = dev_read_u32(dev, "timebase-frequency", &plat->timebase_freq);
  69        /* if not found, then look at the parent /cpus node */
  70        if (ret)
  71                dev_read_u32(dev->parent, "timebase-frequency",
  72                             &plat->timebase_freq);
  73
  74        /*
  75         * Bind riscv-timer driver on boot hart.
  76         *
  77         * We only instantiate one timer device which is enough for U-Boot.
  78         * Pass the "timebase-frequency" value as the driver data for the
  79         * timer device.
  80         *
  81         * Return value is not checked since it's possible that the timer
  82         * driver is not included.
  83         */
  84        if (plat->cpu_id == gd->arch.boot_hart && plat->timebase_freq) {
  85                drv = lists_driver_lookup_name("riscv_timer");
  86                if (!drv) {
  87                        debug("Cannot find the timer driver, not included?\n");
  88                        return 0;
  89                }
  90
  91                device_bind_with_driver_data(dev, drv, "riscv_timer",
  92                                             plat->timebase_freq, ofnode_null(),
  93                                             NULL);
  94        }
  95
  96        return 0;
  97}
  98
  99static const struct cpu_ops riscv_cpu_ops = {
 100        .get_desc       = riscv_cpu_get_desc,
 101        .get_info       = riscv_cpu_get_info,
 102        .get_count      = riscv_cpu_get_count,
 103};
 104
 105static const struct udevice_id riscv_cpu_ids[] = {
 106        { .compatible = "riscv" },
 107        { }
 108};
 109
 110U_BOOT_DRIVER(riscv_cpu) = {
 111        .name = "riscv_cpu",
 112        .id = UCLASS_CPU,
 113        .of_match = riscv_cpu_ids,
 114        .bind = riscv_cpu_bind,
 115        .ops = &riscv_cpu_ops,
 116        .flags = DM_FLAG_PRE_RELOC,
 117};
 118