forked from enclustra-bsp/xilinx-uboot
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This adds a driver for RISC-V CPU. Note the driver will bind a RISC-V timer driver if "timebase-frequency" property is present in the device tree. Signed-off-by: Bin Meng <[email protected]> Reviewed-by: Lukas Auer <[email protected]> Reviewed-by: Anup Patel <[email protected]>
- Loading branch information
Showing
3 changed files
with
123 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
// SPDX-License-Identifier: GPL-2.0+ | ||
/* | ||
* Copyright (C) 2018, Bin Meng <[email protected]> | ||
*/ | ||
|
||
#include <common.h> | ||
#include <cpu.h> | ||
#include <dm.h> | ||
#include <errno.h> | ||
#include <dm/device-internal.h> | ||
#include <dm/lists.h> | ||
|
||
static int riscv_cpu_get_desc(struct udevice *dev, char *buf, int size) | ||
{ | ||
const char *isa; | ||
|
||
isa = dev_read_string(dev, "riscv,isa"); | ||
if (size < (strlen(isa) + 1)) | ||
return -ENOSPC; | ||
|
||
strcpy(buf, isa); | ||
|
||
return 0; | ||
} | ||
|
||
static int riscv_cpu_get_info(struct udevice *dev, struct cpu_info *info) | ||
{ | ||
const char *mmu; | ||
|
||
dev_read_u32(dev, "clock-frequency", (u32 *)&info->cpu_freq); | ||
|
||
mmu = dev_read_string(dev, "mmu-type"); | ||
if (!mmu) | ||
info->features |= BIT(CPU_FEAT_MMU); | ||
|
||
return 0; | ||
} | ||
|
||
static int riscv_cpu_get_count(struct udevice *dev) | ||
{ | ||
ofnode node; | ||
int num = 0; | ||
|
||
ofnode_for_each_subnode(node, dev_ofnode(dev->parent)) { | ||
const char *device_type; | ||
|
||
device_type = ofnode_read_string(node, "device_type"); | ||
if (!device_type) | ||
continue; | ||
if (strcmp(device_type, "cpu") == 0) | ||
num++; | ||
} | ||
|
||
return num; | ||
} | ||
|
||
static int riscv_cpu_bind(struct udevice *dev) | ||
{ | ||
struct cpu_platdata *plat = dev_get_parent_platdata(dev); | ||
struct driver *drv; | ||
int ret; | ||
|
||
/* save the hart id */ | ||
plat->cpu_id = dev_read_addr(dev); | ||
|
||
/* first examine the property in current cpu node */ | ||
ret = dev_read_u32(dev, "timebase-frequency", &plat->timebase_freq); | ||
/* if not found, then look at the parent /cpus node */ | ||
if (ret) | ||
dev_read_u32(dev->parent, "timebase-frequency", | ||
&plat->timebase_freq); | ||
|
||
/* | ||
* Bind riscv-timer driver on hart 0 | ||
* | ||
* We only instantiate one timer device which is enough for U-Boot. | ||
* Pass the "timebase-frequency" value as the driver data for the | ||
* timer device. | ||
* | ||
* Return value is not checked since it's possible that the timer | ||
* driver is not included. | ||
*/ | ||
if (!plat->cpu_id && plat->timebase_freq) { | ||
drv = lists_driver_lookup_name("riscv_timer"); | ||
if (!drv) { | ||
debug("Cannot find the timer driver, not included?\n"); | ||
return 0; | ||
} | ||
|
||
device_bind_with_driver_data(dev, drv, "riscv_timer", | ||
plat->timebase_freq, ofnode_null(), | ||
NULL); | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static const struct cpu_ops riscv_cpu_ops = { | ||
.get_desc = riscv_cpu_get_desc, | ||
.get_info = riscv_cpu_get_info, | ||
.get_count = riscv_cpu_get_count, | ||
}; | ||
|
||
static const struct udevice_id riscv_cpu_ids[] = { | ||
{ .compatible = "riscv" }, | ||
{ } | ||
}; | ||
|
||
U_BOOT_DRIVER(riscv_cpu) = { | ||
.name = "riscv_cpu", | ||
.id = UCLASS_CPU, | ||
.of_match = riscv_cpu_ids, | ||
.bind = riscv_cpu_bind, | ||
.ops = &riscv_cpu_ops, | ||
.flags = DM_FLAG_PRE_RELOC, | ||
}; |