platform.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. /*
  2. * SPDX-License-Identifier: BSD-2-Clause
  3. *
  4. * Copyright (c) 2019 Western Digital Corporation or its affiliates.
  5. *
  6. * Authors:
  7. * Atish Patra <atish.patra@wdc.com>
  8. */
  9. #include <libfdt.h>
  10. #include <fdt.h>
  11. #include <sbi/riscv_encoding.h>
  12. #include <sbi/sbi_const.h>
  13. #include <sbi/sbi_hart.h>
  14. #include <sbi/sbi_console.h>
  15. #include <sbi/sbi_platform.h>
  16. #include <sbi/riscv_io.h>
  17. #include <plat/irqchip/plic.h>
  18. #include <plat/serial/sifive-uart.h>
  19. #include <plat/sys/clint.h>
  20. /* clang-format off */
  21. #define FU540_HART_COUNT 5
  22. #define FU540_HART_STACK_SIZE 8192
  23. #define FU540_SYS_CLK 1000000000
  24. #define FU540_CLINT_ADDR 0x2000000
  25. #define FU540_PLIC_ADDR 0xc000000
  26. #define FU540_PLIC_NUM_SOURCES 0x35
  27. #define FU540_PLIC_NUM_PRIORITIES 7
  28. #define FU540_UART0_ADDR 0x10010000
  29. #define FU540_UART1_ADDR 0x10011000
  30. #define FU540_UART_BAUDRATE 115200
  31. /**
  32. * The FU540 SoC has 5 HARTs but HART ID 0 doesn't have S mode. enable only
  33. * HARTs 1 to 4.
  34. */
  35. #ifndef FU540_ENABLED_HART_MASK
  36. #define FU540_ENABLED_HART_MASK (1 << 1 | 1 << 2 | 1 << 3 | 1 << 4)
  37. #endif
  38. #define FU540_HARITD_DISABLED ~(FU540_ENABLED_HART_MASK)
  39. /* PRCI clock related macros */
  40. //TODO: Do we need a separate driver for this ?
  41. #define FU540_PRCI_BASE_ADDR 0x10000000
  42. #define FU540_PRCI_CLKMUXSTATUSREG 0x002C
  43. #define FU540_PRCI_CLKMUX_STATUS_TLCLKSEL (0x1 << 1)
  44. /* clang-format on */
  45. static void fu540_modify_dt(void *fdt)
  46. {
  47. u32 i, size;
  48. int chosen_offset, err;
  49. int cpu_offset;
  50. char cpu_node[32] = "";
  51. const char *mmu_type;
  52. for (i = 0; i < FU540_HART_COUNT; i++) {
  53. sbi_sprintf(cpu_node, "/cpus/cpu@%d", i);
  54. cpu_offset = fdt_path_offset(fdt, cpu_node);
  55. mmu_type = fdt_getprop(fdt, cpu_offset, "mmu-type", NULL);
  56. if (mmu_type && (!strcmp(mmu_type, "riscv,sv39") ||
  57. !strcmp(mmu_type, "riscv,sv48")))
  58. continue;
  59. else
  60. fdt_setprop_string(fdt, cpu_offset, "status", "masked");
  61. memset(cpu_node, 0, sizeof(cpu_node));
  62. }
  63. size = fdt_totalsize(fdt);
  64. err = fdt_open_into(fdt, fdt, size + 256);
  65. if (err < 0)
  66. sbi_printf(
  67. "Device Tree can't be expanded to accmodate new node");
  68. chosen_offset = fdt_path_offset(fdt, "/chosen");
  69. fdt_setprop_string(fdt, chosen_offset, "stdout-path",
  70. "/soc/serial@10010000:115200");
  71. plic_fdt_fixup(fdt, "riscv,plic0");
  72. }
  73. static int fu540_final_init(bool cold_boot)
  74. {
  75. void *fdt;
  76. if (!cold_boot)
  77. return 0;
  78. fdt = sbi_scratch_thishart_arg1_ptr();
  79. fu540_modify_dt(fdt);
  80. return 0;
  81. }
  82. static u32 fu540_pmp_region_count(u32 hartid)
  83. {
  84. return 1;
  85. }
  86. static int fu540_pmp_region_info(u32 hartid, u32 index, ulong *prot,
  87. ulong *addr, ulong *log2size)
  88. {
  89. int ret = 0;
  90. switch (index) {
  91. case 0:
  92. *prot = PMP_R | PMP_W | PMP_X;
  93. *addr = 0;
  94. *log2size = __riscv_xlen;
  95. break;
  96. default:
  97. ret = -1;
  98. break;
  99. };
  100. return ret;
  101. }
  102. static int fu540_console_init(void)
  103. {
  104. unsigned long peri_in_freq;
  105. if (readl((volatile void *)FU540_PRCI_BASE_ADDR +
  106. FU540_PRCI_CLKMUXSTATUSREG) &
  107. FU540_PRCI_CLKMUX_STATUS_TLCLKSEL) {
  108. peri_in_freq = FU540_SYS_CLK;
  109. } else {
  110. peri_in_freq = FU540_SYS_CLK / 2;
  111. }
  112. return sifive_uart_init(FU540_UART0_ADDR, peri_in_freq,
  113. FU540_UART_BAUDRATE);
  114. }
  115. static int fu540_irqchip_init(bool cold_boot)
  116. {
  117. int rc;
  118. u32 hartid = sbi_current_hartid();
  119. if (cold_boot) {
  120. rc = plic_cold_irqchip_init(FU540_PLIC_ADDR,
  121. FU540_PLIC_NUM_SOURCES,
  122. FU540_HART_COUNT);
  123. if (rc)
  124. return rc;
  125. }
  126. return plic_warm_irqchip_init(hartid, (hartid) ? (2 * hartid - 1) : 0,
  127. (hartid) ? (2 * hartid) : -1);
  128. }
  129. static int fu540_ipi_init(bool cold_boot)
  130. {
  131. int rc;
  132. if (cold_boot) {
  133. rc = clint_cold_ipi_init(FU540_CLINT_ADDR, FU540_HART_COUNT);
  134. if (rc)
  135. return rc;
  136. }
  137. return clint_warm_ipi_init();
  138. }
  139. static int fu540_timer_init(bool cold_boot)
  140. {
  141. int rc;
  142. if (cold_boot) {
  143. rc = clint_cold_timer_init(FU540_CLINT_ADDR, FU540_HART_COUNT);
  144. if (rc)
  145. return rc;
  146. }
  147. return clint_warm_timer_init();
  148. }
  149. static int fu540_system_down(u32 type)
  150. {
  151. /* For now nothing to do. */
  152. return 0;
  153. }
  154. const struct sbi_platform platform = {
  155. .name = "SiFive Freedom U540",
  156. .features = SBI_PLATFORM_DEFAULT_FEATURES,
  157. .hart_count = FU540_HART_COUNT,
  158. .hart_stack_size = FU540_HART_STACK_SIZE,
  159. .disabled_hart_mask = FU540_HARITD_DISABLED,
  160. .pmp_region_count = fu540_pmp_region_count,
  161. .pmp_region_info = fu540_pmp_region_info,
  162. .final_init = fu540_final_init,
  163. .console_putc = sifive_uart_putc,
  164. .console_getc = sifive_uart_getc,
  165. .console_init = fu540_console_init,
  166. .irqchip_init = fu540_irqchip_init,
  167. .ipi_send = clint_ipi_send,
  168. .ipi_sync = clint_ipi_sync,
  169. .ipi_clear = clint_ipi_clear,
  170. .ipi_init = fu540_ipi_init,
  171. .timer_value = clint_timer_value,
  172. .timer_event_stop = clint_timer_event_stop,
  173. .timer_event_start = clint_timer_event_start,
  174. .timer_init = fu540_timer_init,
  175. .system_reboot = fu540_system_down,
  176. .system_shutdown = fu540_system_down
  177. };