blob: c2a8fe4d9e9b696695df2678216bc9156513fdc4 [file] [log] [blame]
Rick Chen6df4ed02019-04-02 15:56:39 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2019, Rick Chen <rick@andestech.com>
4 *
5 * U-Boot syscon driver for Andes's Platform Level Interrupt Controller (PLIC).
6 * The PLIC block holds memory-mapped claim and pending registers
7 * associated with software interrupt.
8 */
9
10#include <common.h>
11#include <dm.h>
12#include <dm/device-internal.h>
13#include <dm/lists.h>
14#include <dm/uclass-internal.h>
15#include <regmap.h>
16#include <syscon.h>
17#include <asm/io.h>
18#include <asm/syscon.h>
19#include <cpu.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070020#include <linux/err.h>
Rick Chen6df4ed02019-04-02 15:56:39 +080021
22/* pending register */
Rick Cheneb613032019-11-14 13:52:24 +080023#define PENDING_REG(base, hart) ((ulong)(base) + 0x1000 + ((hart) / 4) * 4)
Rick Chen6df4ed02019-04-02 15:56:39 +080024/* enable register */
25#define ENABLE_REG(base, hart) ((ulong)(base) + 0x2000 + (hart) * 0x80)
26/* claim register */
27#define CLAIM_REG(base, hart) ((ulong)(base) + 0x200004 + (hart) * 0x1000)
28
29#define ENABLE_HART_IPI (0x80808080)
30#define SEND_IPI_TO_HART(hart) (0x80 >> (hart))
31
32DECLARE_GLOBAL_DATA_PTR;
Rick Chen6df4ed02019-04-02 15:56:39 +080033
Rick Cheneaae83b2019-08-21 11:26:50 +080034static int enable_ipi(int hart)
Rick Chen6df4ed02019-04-02 15:56:39 +080035{
Rick Cheneb613032019-11-14 13:52:24 +080036 unsigned int en;
Rick Chen6df4ed02019-04-02 15:56:39 +080037
Rick Cheneaae83b2019-08-21 11:26:50 +080038 en = ENABLE_HART_IPI >> hart;
39 writel(en, (void __iomem *)ENABLE_REG(gd->arch.plic, hart));
Rick Chen6df4ed02019-04-02 15:56:39 +080040
41 return 0;
42}
43
44static int init_plic(void)
45{
46 struct udevice *dev;
Rick Cheneaae83b2019-08-21 11:26:50 +080047 ofnode node;
Rick Chen6df4ed02019-04-02 15:56:39 +080048 int ret;
Rick Cheneaae83b2019-08-21 11:26:50 +080049 u32 reg;
Rick Chen6df4ed02019-04-02 15:56:39 +080050
51 ret = uclass_find_first_device(UCLASS_CPU, &dev);
52 if (ret)
53 return ret;
54
Heinrich Schuchardtd2014d12020-08-03 23:33:42 +020055 if (dev) {
Rick Cheneaae83b2019-08-21 11:26:50 +080056 ofnode_for_each_subnode(node, dev_ofnode(dev->parent)) {
57 const char *device_type;
58
59 device_type = ofnode_read_string(node, "device_type");
60 if (!device_type)
61 continue;
62
63 if (strcmp(device_type, "cpu"))
64 continue;
65
66 /* skip if hart is marked as not available */
67 if (!ofnode_is_available(node))
68 continue;
69
70 /* read hart ID of CPU */
71 ret = ofnode_read_u32(node, "reg", &reg);
72 if (ret == 0)
73 enable_ipi(reg);
74 }
Rick Chen6df4ed02019-04-02 15:56:39 +080075
Rick Chen6df4ed02019-04-02 15:56:39 +080076 return 0;
77 }
78
79 return -ENODEV;
80}
81
Sean Andersonb1d0cb32020-06-24 06:41:18 -040082int riscv_init_ipi(void)
Rick Chen6df4ed02019-04-02 15:56:39 +080083{
Sean Andersonb1d0cb32020-06-24 06:41:18 -040084 long *ret = syscon_get_first_range(RISCV_SYSCON_PLIC);
Rick Cheneb613032019-11-14 13:52:24 +080085
Sean Andersonb1d0cb32020-06-24 06:41:18 -040086 if (IS_ERR(ret))
87 return PTR_ERR(ret);
88 gd->arch.plic = ret;
Rick Chen6df4ed02019-04-02 15:56:39 +080089
Sean Andersonb1d0cb32020-06-24 06:41:18 -040090 return init_plic();
91}
92
93int riscv_send_ipi(int hart)
94{
95 unsigned int ipi = (SEND_IPI_TO_HART(hart) << (8 * gd->arch.boot_hart));
96
Rick Cheneb613032019-11-14 13:52:24 +080097 writel(ipi, (void __iomem *)PENDING_REG(gd->arch.plic,
98 gd->arch.boot_hart));
Rick Chen6df4ed02019-04-02 15:56:39 +080099
100 return 0;
101}
102
103int riscv_clear_ipi(int hart)
104{
105 u32 source_id;
106
Rick Chen6df4ed02019-04-02 15:56:39 +0800107 source_id = readl((void __iomem *)CLAIM_REG(gd->arch.plic, hart));
108 writel(source_id, (void __iomem *)CLAIM_REG(gd->arch.plic, hart));
109
110 return 0;
111}
112
Lukas Auerc7460b82019-12-08 23:28:50 +0100113int riscv_get_ipi(int hart, int *pending)
114{
Lukas Auerc7460b82019-12-08 23:28:50 +0100115 *pending = readl((void __iomem *)PENDING_REG(gd->arch.plic,
116 gd->arch.boot_hart));
117 *pending = !!(*pending & SEND_IPI_TO_HART(hart));
118
119 return 0;
120}
121
Rick Chen6df4ed02019-04-02 15:56:39 +0800122static const struct udevice_id andes_plic_ids[] = {
123 { .compatible = "riscv,plic1", .data = RISCV_SYSCON_PLIC },
124 { }
125};
126
127U_BOOT_DRIVER(andes_plic) = {
128 .name = "andes_plic",
129 .id = UCLASS_SYSCON,
130 .of_match = andes_plic_ids,
131 .flags = DM_FLAG_PRE_RELOC,
132};