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