sifive_clint.c 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
  4. *
  5. * U-Boot syscon driver for SiFive's Core Local Interruptor (CLINT).
  6. * The CLINT block holds memory-mapped control and status registers
  7. * associated with software and timer interrupts.
  8. */
  9. #include <common.h>
  10. #include <dm.h>
  11. #include <regmap.h>
  12. #include <syscon.h>
  13. #include <asm/io.h>
  14. #include <asm/syscon.h>
  15. #include <linux/err.h>
  16. /* MSIP registers */
  17. #define MSIP_REG(base, hart) ((ulong)(base) + (hart) * 4)
  18. /* mtime compare register */
  19. #define MTIMECMP_REG(base, hart) ((ulong)(base) + 0x4000 + (hart) * 8)
  20. /* mtime register */
  21. #define MTIME_REG(base) ((ulong)(base) + 0xbff8)
  22. DECLARE_GLOBAL_DATA_PTR;
  23. int riscv_get_time(u64 *time)
  24. {
  25. /* ensure timer register base has a sane value */
  26. riscv_init_ipi();
  27. *time = readq((void __iomem *)MTIME_REG(gd->arch.clint));
  28. return 0;
  29. }
  30. int riscv_set_timecmp(int hart, u64 cmp)
  31. {
  32. /* ensure timer register base has a sane value */
  33. riscv_init_ipi();
  34. writeq(cmp, (void __iomem *)MTIMECMP_REG(gd->arch.clint, hart));
  35. return 0;
  36. }
  37. int riscv_init_ipi(void)
  38. {
  39. if (!gd->arch.clint) {
  40. long *ret = syscon_get_first_range(RISCV_SYSCON_CLINT);
  41. if (IS_ERR(ret))
  42. return PTR_ERR(ret);
  43. gd->arch.clint = ret;
  44. }
  45. return 0;
  46. }
  47. int riscv_send_ipi(int hart)
  48. {
  49. writel(1, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
  50. return 0;
  51. }
  52. int riscv_clear_ipi(int hart)
  53. {
  54. writel(0, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
  55. return 0;
  56. }
  57. int riscv_get_ipi(int hart, int *pending)
  58. {
  59. *pending = readl((void __iomem *)MSIP_REG(gd->arch.clint, hart));
  60. return 0;
  61. }
  62. static const struct udevice_id sifive_clint_ids[] = {
  63. { .compatible = "riscv,clint0", .data = RISCV_SYSCON_CLINT },
  64. { }
  65. };
  66. U_BOOT_DRIVER(sifive_clint) = {
  67. .name = "sifive_clint",
  68. .id = UCLASS_SYSCON,
  69. .of_match = sifive_clint_ids,
  70. .flags = DM_FLAG_PRE_RELOC,
  71. };