mmio_khv.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. #include <linux/io.h>
  3. #include <linux/module.h>
  4. #include <linux/of_irq.h>
  5. #include <linux/platform_device.h>
  6. #include <linux/mmio_khv.h>
  7. #include <uapi/linux/virtio_mmio.h>
  8. #include <asm/sbi.h>
  9. static struct mmio_khv_device *mk_dev;
  10. static struct mmio_khv_device __mk_dev;
  11. static bool init_flag = false;
  12. void khv_shutdown(void)
  13. {
  14. u64 stat = START | (0x5a << 16);
  15. if (!init_flag)
  16. return;
  17. writel(stat, mk_dev->base + KHV_STAT_OFF);
  18. /* notify host */
  19. writel(mk_dev->notify_host_reg_val, mk_dev->notify_host_reg);
  20. sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_STOP, 0, 0, 0, 0, 0, 0);
  21. }
  22. static void init_mk_dev(void)
  23. {
  24. if (init_flag == true)
  25. return;
  26. init_flag = true;
  27. mk_dev = &__mk_dev;
  28. mk_dev->base = ioremap(0x1fd000, 0x100);
  29. memset(mk_dev->base, 0, 0x100);
  30. #ifdef CONFIG_SOC_INT_SRC7
  31. mk_dev->notify_host_reg = ioremap(0xFFFF019094, 4);
  32. #else
  33. mk_dev->notify_host_reg = ioremap(0xffffc3b010, 4);
  34. #endif
  35. mk_dev->notify_host_reg_val = 1;
  36. }
  37. u64 readx(u32 offset, u32 bw)
  38. {
  39. u64 val;
  40. u16 stat = START | (bw << 8);
  41. init_mk_dev();
  42. /* wait host ready */
  43. while (readb(mk_dev->base + KHV_STAT_OFF) != INVAL)
  44. cpu_relax();
  45. writew(stat, mk_dev->base + KHV_STAT_OFF);
  46. writel(offset, mk_dev->base + KHV_ADDR_OFF);
  47. /* notify host */
  48. writel(mk_dev->notify_host_reg_val, mk_dev->notify_host_reg);
  49. /* wait host ready */
  50. while (readb(mk_dev->base + KHV_STAT_OFF) != READY)
  51. cpu_relax();
  52. switch (bw) {
  53. case WIDTH_8:
  54. val = readb(mk_dev->base + KHV_VAL_OFF);
  55. break;
  56. case WIDTH_16:
  57. val = readw(mk_dev->base + KHV_VAL_OFF);
  58. break;
  59. case WIDTH_32:
  60. val = readl(mk_dev->base + KHV_VAL_OFF);
  61. break;
  62. case WIDTH_64:
  63. val = readq(mk_dev->base + KHV_VAL_OFF);
  64. break;
  65. default:
  66. BUG();
  67. }
  68. writeb(ACK, mk_dev->base + KHV_STAT_OFF);
  69. return val;
  70. }
  71. void writex(u64 val, u32 offset, u32 bw)
  72. {
  73. u16 stat = START | IS_WRITE | (bw << 8);
  74. init_mk_dev();
  75. /* wait host ready */
  76. while (readb(mk_dev->base + KHV_STAT_OFF) != INVAL)
  77. cpu_relax();
  78. writew(stat, mk_dev->base + KHV_STAT_OFF);
  79. writel(offset, mk_dev->base + KHV_ADDR_OFF);
  80. switch (bw) {
  81. case WIDTH_8:
  82. writeb(val, mk_dev->base + KHV_VAL_OFF);
  83. break;
  84. case WIDTH_16:
  85. writew(val, mk_dev->base + KHV_VAL_OFF);
  86. break;
  87. case WIDTH_32:
  88. writel(val, mk_dev->base + KHV_VAL_OFF);
  89. break;
  90. case WIDTH_64:
  91. writeq(val, mk_dev->base + KHV_VAL_OFF);
  92. break;
  93. default:
  94. BUG();
  95. }
  96. /* notify host */
  97. writel(mk_dev->notify_host_reg_val, mk_dev->notify_host_reg);
  98. if ((offset & 0xff) != VIRTIO_MMIO_QUEUE_NOTIFY) {
  99. /* wait host ready */
  100. while (readb(mk_dev->base + KHV_STAT_OFF) != READY)
  101. cpu_relax();
  102. writeb(ACK, mk_dev->base + KHV_STAT_OFF);
  103. }
  104. return;
  105. }