0012-riscv-Add-a-SYSCON-driver-for-Andestech-s-PLIC.patch 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. From 0d389468e2144f3ba3bdbc566c05c0c05dc14fc6 Mon Sep 17 00:00:00 2001
  2. From: Rick Chen <rick@andestech.com>
  3. Date: Tue, 2 Apr 2019 15:56:39 +0800
  4. Subject: [PATCH 12/18] riscv: Add a SYSCON driver for Andestech's PLIC
  5. The Platform-Level Interrupt Controller (PLIC)
  6. block holds memory-mapped claim and pending registers
  7. associated with software interrupt. It is required
  8. for handling IPI.
  9. Signed-off-by: Rick Chen <rick@andestech.com>
  10. Cc: Greentime Hu <greentime@andestech.com>
  11. Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
  12. Reviewed-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
  13. ---
  14. arch/riscv/Kconfig | 9 +++
  15. arch/riscv/include/asm/global_data.h | 3 +
  16. arch/riscv/include/asm/syscon.h | 3 +-
  17. arch/riscv/lib/Makefile | 1 +
  18. arch/riscv/lib/andes_plic.c | 113 +++++++++++++++++++++++++++
  19. 5 files changed, 127 insertions(+), 2 deletions(-)
  20. create mode 100644 arch/riscv/lib/andes_plic.c
  21. diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
  22. index 3a4470daf3..511768befc 100644
  23. --- a/arch/riscv/Kconfig
  24. +++ b/arch/riscv/Kconfig
  25. @@ -109,6 +109,15 @@ config SIFIVE_CLINT
  26. The SiFive CLINT block holds memory-mapped control and status registers
  27. associated with software and timer interrupts.
  28. +config ANDES_PLIC
  29. + bool
  30. + depends on RISCV_MMODE
  31. + select REGMAP
  32. + select SYSCON
  33. + help
  34. + The Andes PLIC block holds memory-mapped claim and pending registers
  35. + associated with software interrupt.
  36. +
  37. config RISCV_RDTIME
  38. bool
  39. default y if RISCV_SMODE
  40. diff --git a/arch/riscv/include/asm/global_data.h b/arch/riscv/include/asm/global_data.h
  41. index 80e3165e39..b86791094b 100644
  42. --- a/arch/riscv/include/asm/global_data.h
  43. +++ b/arch/riscv/include/asm/global_data.h
  44. @@ -18,6 +18,9 @@ struct arch_global_data {
  45. #ifdef CONFIG_SIFIVE_CLINT
  46. void __iomem *clint; /* clint base address */
  47. #endif
  48. +#ifdef CONFIG_ANDES_PLIC
  49. + void __iomem *plic; /* plic base address */
  50. +#endif
  51. #ifdef CONFIG_SMP
  52. struct ipi_data ipi[CONFIG_NR_CPUS];
  53. #endif
  54. diff --git a/arch/riscv/include/asm/syscon.h b/arch/riscv/include/asm/syscon.h
  55. index d311ee6b45..a086208261 100644
  56. --- a/arch/riscv/include/asm/syscon.h
  57. +++ b/arch/riscv/include/asm/syscon.h
  58. @@ -8,12 +8,11 @@
  59. /*
  60. * System controllers in a RISC-V system
  61. - *
  62. - * So far only SiFive's Core Local Interruptor (CLINT) is defined.
  63. */
  64. enum {
  65. RISCV_NONE,
  66. RISCV_SYSCON_CLINT, /* Core Local Interruptor (CLINT) */
  67. + RISCV_SYSCON_PLIC, /* Platform Level Interrupt Controller (PLIC) */
  68. };
  69. #endif /* _ASM_SYSCON_H */
  70. diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile
  71. index 35dbf643e4..1bf554bad5 100644
  72. --- a/arch/riscv/lib/Makefile
  73. +++ b/arch/riscv/lib/Makefile
  74. @@ -11,6 +11,7 @@ obj-$(CONFIG_CMD_GO) += boot.o
  75. obj-y += cache.o
  76. obj-$(CONFIG_RISCV_RDTIME) += rdtime.o
  77. obj-$(CONFIG_SIFIVE_CLINT) += sifive_clint.o
  78. +obj-$(CONFIG_ANDES_PLIC) += andes_plic.o
  79. obj-y += interrupts.o
  80. obj-y += reset.o
  81. obj-$(CONFIG_SBI_IPI) += sbi_ipi.o
  82. diff --git a/arch/riscv/lib/andes_plic.c b/arch/riscv/lib/andes_plic.c
  83. new file mode 100644
  84. index 0000000000..2ffe49ac90
  85. --- /dev/null
  86. +++ b/arch/riscv/lib/andes_plic.c
  87. @@ -0,0 +1,113 @@
  88. +// SPDX-License-Identifier: GPL-2.0+
  89. +/*
  90. + * Copyright (C) 2019, Rick Chen <rick@andestech.com>
  91. + *
  92. + * U-Boot syscon driver for Andes's Platform Level Interrupt Controller (PLIC).
  93. + * The PLIC block holds memory-mapped claim and pending registers
  94. + * associated with software interrupt.
  95. + */
  96. +
  97. +#include <common.h>
  98. +#include <dm.h>
  99. +#include <dm/device-internal.h>
  100. +#include <dm/lists.h>
  101. +#include <dm/uclass-internal.h>
  102. +#include <regmap.h>
  103. +#include <syscon.h>
  104. +#include <asm/io.h>
  105. +#include <asm/syscon.h>
  106. +#include <cpu.h>
  107. +
  108. +/* pending register */
  109. +#define PENDING_REG(base, hart) ((ulong)(base) + 0x1000 + (hart) * 8)
  110. +/* enable register */
  111. +#define ENABLE_REG(base, hart) ((ulong)(base) + 0x2000 + (hart) * 0x80)
  112. +/* claim register */
  113. +#define CLAIM_REG(base, hart) ((ulong)(base) + 0x200004 + (hart) * 0x1000)
  114. +
  115. +#define ENABLE_HART_IPI (0x80808080)
  116. +#define SEND_IPI_TO_HART(hart) (0x80 >> (hart))
  117. +
  118. +DECLARE_GLOBAL_DATA_PTR;
  119. +static int init_plic(void);
  120. +
  121. +#define PLIC_BASE_GET(void) \
  122. + do { \
  123. + long *ret; \
  124. + \
  125. + if (!gd->arch.plic) { \
  126. + ret = syscon_get_first_range(RISCV_SYSCON_PLIC); \
  127. + if (IS_ERR(ret)) \
  128. + return PTR_ERR(ret); \
  129. + gd->arch.plic = ret; \
  130. + init_plic(); \
  131. + } \
  132. + } while (0)
  133. +
  134. +static int enable_ipi(int harts)
  135. +{
  136. + int i;
  137. + int en = ENABLE_HART_IPI;
  138. +
  139. + for (i = 0; i < harts; i++) {
  140. + en = en >> i;
  141. + writel(en, (void __iomem *)ENABLE_REG(gd->arch.plic, i));
  142. + }
  143. +
  144. + return 0;
  145. +}
  146. +
  147. +static int init_plic(void)
  148. +{
  149. + struct udevice *dev;
  150. + int ret;
  151. +
  152. + ret = uclass_find_first_device(UCLASS_CPU, &dev);
  153. + if (ret)
  154. + return ret;
  155. +
  156. + if (ret == 0 && dev) {
  157. + ret = cpu_get_count(dev);
  158. + if (ret < 0)
  159. + return ret;
  160. +
  161. + enable_ipi(ret);
  162. + return 0;
  163. + }
  164. +
  165. + return -ENODEV;
  166. +}
  167. +
  168. +int riscv_send_ipi(int hart)
  169. +{
  170. + PLIC_BASE_GET();
  171. +
  172. + writel(SEND_IPI_TO_HART(hart),
  173. + (void __iomem *)PENDING_REG(gd->arch.plic, gd->arch.boot_hart));
  174. +
  175. + return 0;
  176. +}
  177. +
  178. +int riscv_clear_ipi(int hart)
  179. +{
  180. + u32 source_id;
  181. +
  182. + PLIC_BASE_GET();
  183. +
  184. + source_id = readl((void __iomem *)CLAIM_REG(gd->arch.plic, hart));
  185. + writel(source_id, (void __iomem *)CLAIM_REG(gd->arch.plic, hart));
  186. +
  187. + return 0;
  188. +}
  189. +
  190. +static const struct udevice_id andes_plic_ids[] = {
  191. + { .compatible = "riscv,plic1", .data = RISCV_SYSCON_PLIC },
  192. + { }
  193. +};
  194. +
  195. +U_BOOT_DRIVER(andes_plic) = {
  196. + .name = "andes_plic",
  197. + .id = UCLASS_SYSCON,
  198. + .of_match = andes_plic_ids,
  199. + .flags = DM_FLAG_PRE_RELOC,
  200. +};
  201. --
  202. 2.21.0