fdt_helper.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940
  1. // SPDX-License-Identifier: BSD-2-Clause
  2. /*
  3. * fdt_helper.c - Flat Device Tree manipulation helper routines
  4. * Implement helper routines on top of libfdt for OpenSBI usage
  5. *
  6. * Copyright (C) 2020 Bin Meng <bmeng.cn@gmail.com>
  7. */
  8. #include <libfdt.h>
  9. #include <sbi/riscv_asm.h>
  10. #include <sbi/sbi_console.h>
  11. #include <sbi/sbi_hartmask.h>
  12. #include <sbi/sbi_platform.h>
  13. #include <sbi/sbi_scratch.h>
  14. #include <sbi_utils/fdt/fdt_helper.h>
  15. #include <sbi_utils/irqchip/aplic.h>
  16. #include <sbi_utils/irqchip/imsic.h>
  17. #include <sbi_utils/irqchip/plic.h>
  18. #define DEFAULT_UART_FREQ 0
  19. #define DEFAULT_UART_BAUD 115200
  20. #define DEFAULT_UART_REG_SHIFT 0
  21. #define DEFAULT_UART_REG_IO_WIDTH 1
  22. #define DEFAULT_UART_REG_OFFSET 0
  23. #define DEFAULT_RENESAS_SCIF_FREQ 100000000
  24. #define DEFAULT_RENESAS_SCIF_BAUD 115200
  25. #define DEFAULT_SIFIVE_UART_FREQ 0
  26. #define DEFAULT_SIFIVE_UART_BAUD 115200
  27. #define DEFAULT_SHAKTI_UART_FREQ 50000000
  28. #define DEFAULT_SHAKTI_UART_BAUD 115200
  29. const struct fdt_match *fdt_match_node(void *fdt, int nodeoff,
  30. const struct fdt_match *match_table)
  31. {
  32. int ret;
  33. if (!fdt || nodeoff < 0 || !match_table)
  34. return NULL;
  35. while (match_table->compatible) {
  36. ret = fdt_node_check_compatible(fdt, nodeoff,
  37. match_table->compatible);
  38. if (!ret)
  39. return match_table;
  40. match_table++;
  41. }
  42. return NULL;
  43. }
  44. int fdt_find_match(void *fdt, int startoff,
  45. const struct fdt_match *match_table,
  46. const struct fdt_match **out_match)
  47. {
  48. int nodeoff;
  49. if (!fdt || !match_table)
  50. return SBI_ENODEV;
  51. while (match_table->compatible) {
  52. nodeoff = fdt_node_offset_by_compatible(fdt, startoff,
  53. match_table->compatible);
  54. if (nodeoff >= 0) {
  55. if (out_match)
  56. *out_match = match_table;
  57. return nodeoff;
  58. }
  59. match_table++;
  60. }
  61. return SBI_ENODEV;
  62. }
  63. int fdt_parse_phandle_with_args(void *fdt, int nodeoff,
  64. const char *prop, const char *cells_prop,
  65. int index, struct fdt_phandle_args *out_args)
  66. {
  67. u32 i, pcells;
  68. int len, pnodeoff;
  69. const fdt32_t *list, *list_end, *val;
  70. if (!fdt || (nodeoff < 0) || !prop || !cells_prop || !out_args)
  71. return SBI_EINVAL;
  72. list = fdt_getprop(fdt, nodeoff, prop, &len);
  73. if (!list)
  74. return SBI_ENOENT;
  75. list_end = list + (len / sizeof(*list));
  76. while (list < list_end) {
  77. pnodeoff = fdt_node_offset_by_phandle(fdt,
  78. fdt32_to_cpu(*list));
  79. if (pnodeoff < 0)
  80. return pnodeoff;
  81. list++;
  82. val = fdt_getprop(fdt, pnodeoff, cells_prop, &len);
  83. if (!val)
  84. return SBI_ENOENT;
  85. pcells = fdt32_to_cpu(*val);
  86. if (FDT_MAX_PHANDLE_ARGS < pcells)
  87. return SBI_EINVAL;
  88. if (list + pcells > list_end)
  89. return SBI_ENOENT;
  90. if (index > 0) {
  91. list += pcells;
  92. index--;
  93. } else {
  94. out_args->node_offset = pnodeoff;
  95. out_args->args_count = pcells;
  96. for (i = 0; i < pcells; i++)
  97. out_args->args[i] = fdt32_to_cpu(list[i]);
  98. return 0;
  99. }
  100. }
  101. return SBI_ENOENT;
  102. }
  103. static int fdt_translate_address(void *fdt, uint64_t reg, int parent,
  104. uint64_t *addr)
  105. {
  106. int i, rlen;
  107. int cell_addr, cell_size;
  108. const fdt32_t *ranges;
  109. uint64_t offset, caddr = 0, paddr = 0, rsize = 0;
  110. cell_addr = fdt_address_cells(fdt, parent);
  111. if (cell_addr < 1)
  112. return SBI_ENODEV;
  113. cell_size = fdt_size_cells(fdt, parent);
  114. if (cell_size < 0)
  115. return SBI_ENODEV;
  116. ranges = fdt_getprop(fdt, parent, "ranges", &rlen);
  117. if (ranges && rlen > 0) {
  118. for (i = 0; i < cell_addr; i++)
  119. caddr = (caddr << 32) | fdt32_to_cpu(*ranges++);
  120. for (i = 0; i < cell_addr; i++)
  121. paddr = (paddr << 32) | fdt32_to_cpu(*ranges++);
  122. for (i = 0; i < cell_size; i++)
  123. rsize = (rsize << 32) | fdt32_to_cpu(*ranges++);
  124. if (reg < caddr || caddr >= (reg + rsize )) {
  125. sbi_printf("invalid address translation\n");
  126. return SBI_ENODEV;
  127. }
  128. offset = reg - caddr;
  129. *addr = paddr + offset;
  130. } else {
  131. /* No translation required */
  132. *addr = reg;
  133. }
  134. return 0;
  135. }
  136. int fdt_get_node_addr_size(void *fdt, int node, int index,
  137. uint64_t *addr, uint64_t *size)
  138. {
  139. int parent, len, i, rc;
  140. int cell_addr, cell_size;
  141. const fdt32_t *prop_addr, *prop_size;
  142. uint64_t temp = 0;
  143. if (!fdt || node < 0 || index < 0)
  144. return SBI_EINVAL;
  145. parent = fdt_parent_offset(fdt, node);
  146. if (parent < 0)
  147. return parent;
  148. cell_addr = fdt_address_cells(fdt, parent);
  149. if (cell_addr < 1)
  150. return SBI_ENODEV;
  151. cell_size = fdt_size_cells(fdt, parent);
  152. if (cell_size < 0)
  153. return SBI_ENODEV;
  154. prop_addr = fdt_getprop(fdt, node, "reg", &len);
  155. if (!prop_addr)
  156. return SBI_ENODEV;
  157. if ((len / sizeof(u32)) <= (index * (cell_addr + cell_size)))
  158. return SBI_EINVAL;
  159. prop_addr = prop_addr + (index * (cell_addr + cell_size));
  160. prop_size = prop_addr + cell_addr;
  161. if (addr) {
  162. for (i = 0; i < cell_addr; i++)
  163. temp = (temp << 32) | fdt32_to_cpu(*prop_addr++);
  164. do {
  165. if (parent < 0)
  166. break;
  167. rc = fdt_translate_address(fdt, temp, parent, addr);
  168. if (rc)
  169. break;
  170. parent = fdt_parent_offset(fdt, parent);
  171. temp = *addr;
  172. } while (1);
  173. }
  174. temp = 0;
  175. if (size) {
  176. for (i = 0; i < cell_size; i++)
  177. temp = (temp << 32) | fdt32_to_cpu(*prop_size++);
  178. *size = temp;
  179. }
  180. return 0;
  181. }
  182. bool fdt_node_is_enabled(void *fdt, int nodeoff)
  183. {
  184. int len;
  185. const void *prop;
  186. prop = fdt_getprop(fdt, nodeoff, "status", &len);
  187. if (!prop)
  188. return true;
  189. if (!strncmp(prop, "okay", strlen("okay")))
  190. return true;
  191. if (!strncmp(prop, "ok", strlen("ok")))
  192. return true;
  193. return false;
  194. }
  195. int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid)
  196. {
  197. int len;
  198. const void *prop;
  199. const fdt32_t *val;
  200. if (!fdt || cpu_offset < 0)
  201. return SBI_EINVAL;
  202. prop = fdt_getprop(fdt, cpu_offset, "device_type", &len);
  203. if (!prop || !len)
  204. return SBI_EINVAL;
  205. if (strncmp (prop, "cpu", strlen ("cpu")))
  206. return SBI_EINVAL;
  207. val = fdt_getprop(fdt, cpu_offset, "reg", &len);
  208. if (!val || len < sizeof(fdt32_t))
  209. return SBI_EINVAL;
  210. if (len > sizeof(fdt32_t))
  211. val++;
  212. if (hartid)
  213. *hartid = fdt32_to_cpu(*val);
  214. return 0;
  215. }
  216. int fdt_parse_max_enabled_hart_id(void *fdt, u32 *max_hartid)
  217. {
  218. u32 hartid;
  219. int err, cpu_offset, cpus_offset;
  220. if (!fdt)
  221. return SBI_EINVAL;
  222. if (!max_hartid)
  223. return 0;
  224. *max_hartid = 0;
  225. cpus_offset = fdt_path_offset(fdt, "/cpus");
  226. if (cpus_offset < 0)
  227. return cpus_offset;
  228. fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
  229. err = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
  230. if (err)
  231. continue;
  232. if (!fdt_node_is_enabled(fdt, cpu_offset))
  233. continue;
  234. if (hartid > *max_hartid)
  235. *max_hartid = hartid;
  236. }
  237. return 0;
  238. }
  239. int fdt_parse_timebase_frequency(void *fdt, unsigned long *freq)
  240. {
  241. const fdt32_t *val;
  242. int len, cpus_offset;
  243. if (!fdt || !freq)
  244. return SBI_EINVAL;
  245. cpus_offset = fdt_path_offset(fdt, "/cpus");
  246. if (cpus_offset < 0)
  247. return cpus_offset;
  248. val = fdt_getprop(fdt, cpus_offset, "timebase-frequency", &len);
  249. if (len > 0 && val)
  250. *freq = fdt32_to_cpu(*val);
  251. else
  252. return SBI_ENOENT;
  253. return 0;
  254. }
  255. static int fdt_parse_uart_node_common(void *fdt, int nodeoffset,
  256. struct platform_uart_data *uart,
  257. unsigned long default_freq,
  258. unsigned long default_baud)
  259. {
  260. int len, rc;
  261. const fdt32_t *val;
  262. uint64_t reg_addr, reg_size;
  263. if (nodeoffset < 0 || !uart || !fdt)
  264. return SBI_ENODEV;
  265. rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
  266. &reg_addr, &reg_size);
  267. if (rc < 0 || !reg_addr || !reg_size)
  268. return SBI_ENODEV;
  269. uart->addr = reg_addr;
  270. /**
  271. * UART address is mandatory. clock-frequency and current-speed
  272. * may not be present. Don't return error.
  273. */
  274. val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "clock-frequency", &len);
  275. if (len > 0 && val)
  276. uart->freq = fdt32_to_cpu(*val);
  277. else
  278. uart->freq = default_freq;
  279. val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "current-speed", &len);
  280. if (len > 0 && val)
  281. uart->baud = fdt32_to_cpu(*val);
  282. else
  283. uart->baud = default_baud;
  284. return 0;
  285. }
  286. int fdt_parse_gaisler_uart_node(void *fdt, int nodeoffset,
  287. struct platform_uart_data *uart)
  288. {
  289. return fdt_parse_uart_node_common(fdt, nodeoffset, uart,
  290. DEFAULT_UART_FREQ,
  291. DEFAULT_UART_BAUD);
  292. }
  293. int fdt_parse_renesas_scif_node(void *fdt, int nodeoffset,
  294. struct platform_uart_data *uart)
  295. {
  296. return fdt_parse_uart_node_common(fdt, nodeoffset, uart,
  297. DEFAULT_RENESAS_SCIF_FREQ,
  298. DEFAULT_RENESAS_SCIF_BAUD);
  299. }
  300. int fdt_parse_shakti_uart_node(void *fdt, int nodeoffset,
  301. struct platform_uart_data *uart)
  302. {
  303. return fdt_parse_uart_node_common(fdt, nodeoffset, uart,
  304. DEFAULT_SHAKTI_UART_FREQ,
  305. DEFAULT_SHAKTI_UART_BAUD);
  306. }
  307. int fdt_parse_sifive_uart_node(void *fdt, int nodeoffset,
  308. struct platform_uart_data *uart)
  309. {
  310. return fdt_parse_uart_node_common(fdt, nodeoffset, uart,
  311. DEFAULT_SIFIVE_UART_FREQ,
  312. DEFAULT_SIFIVE_UART_BAUD);
  313. }
  314. int fdt_parse_uart_node(void *fdt, int nodeoffset,
  315. struct platform_uart_data *uart)
  316. {
  317. int len, rc;
  318. const fdt32_t *val;
  319. rc = fdt_parse_uart_node_common(fdt, nodeoffset, uart,
  320. DEFAULT_UART_FREQ,
  321. DEFAULT_UART_BAUD);
  322. if (rc)
  323. return rc;
  324. val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "reg-shift", &len);
  325. if (len > 0 && val)
  326. uart->reg_shift = fdt32_to_cpu(*val);
  327. else
  328. uart->reg_shift = DEFAULT_UART_REG_SHIFT;
  329. val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "reg-io-width", &len);
  330. if (len > 0 && val)
  331. uart->reg_io_width = fdt32_to_cpu(*val);
  332. else
  333. uart->reg_io_width = DEFAULT_UART_REG_IO_WIDTH;
  334. val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "reg-offset", &len);
  335. if (len > 0 && val)
  336. uart->reg_offset = fdt32_to_cpu(*val);
  337. else
  338. uart->reg_offset = DEFAULT_UART_REG_OFFSET;
  339. return 0;
  340. }
  341. int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
  342. const char *compatible)
  343. {
  344. int nodeoffset;
  345. if (!compatible || !uart || !fdt)
  346. return SBI_ENODEV;
  347. nodeoffset = fdt_node_offset_by_compatible(fdt, -1, compatible);
  348. if (nodeoffset < 0)
  349. return nodeoffset;
  350. return fdt_parse_uart_node(fdt, nodeoffset, uart);
  351. }
  352. int fdt_parse_xlnx_uartlite_node(void *fdt, int nodeoffset,
  353. struct platform_uart_data *uart)
  354. {
  355. return fdt_parse_uart_node_common(fdt, nodeoffset, uart, 0, 0);
  356. }
  357. int fdt_parse_aplic_node(void *fdt, int nodeoff, struct aplic_data *aplic)
  358. {
  359. bool child_found;
  360. const fdt32_t *val;
  361. const fdt32_t *del;
  362. struct imsic_data imsic;
  363. int i, j, d, dcnt, len, noff, rc;
  364. uint64_t reg_addr, reg_size;
  365. struct aplic_delegate_data *deleg;
  366. if (nodeoff < 0 || !aplic || !fdt)
  367. return SBI_ENODEV;
  368. memset(aplic, 0, sizeof(*aplic));
  369. rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &reg_addr, &reg_size);
  370. if (rc < 0 || !reg_addr || !reg_size)
  371. return SBI_ENODEV;
  372. aplic->addr = reg_addr;
  373. aplic->size = reg_size;
  374. val = fdt_getprop(fdt, nodeoff, "riscv,num-sources", &len);
  375. if (len > 0)
  376. aplic->num_source = fdt32_to_cpu(*val);
  377. val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &len);
  378. if (val && len > sizeof(fdt32_t)) {
  379. len = len / sizeof(fdt32_t);
  380. for (i = 0; i < len; i += 2) {
  381. if (fdt32_to_cpu(val[i + 1]) == IRQ_M_EXT) {
  382. aplic->targets_mmode = true;
  383. break;
  384. }
  385. }
  386. aplic->num_idc = len / 2;
  387. goto aplic_msi_parent_done;
  388. }
  389. val = fdt_getprop(fdt, nodeoff, "msi-parent", &len);
  390. if (val && len >= sizeof(fdt32_t)) {
  391. noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
  392. if (noff < 0)
  393. return noff;
  394. rc = fdt_parse_imsic_node(fdt, noff, &imsic);
  395. if (rc)
  396. return rc;
  397. rc = imsic_data_check(&imsic);
  398. if (rc)
  399. return rc;
  400. aplic->targets_mmode = imsic.targets_mmode;
  401. if (imsic.targets_mmode) {
  402. aplic->has_msicfg_mmode = true;
  403. aplic->msicfg_mmode.lhxs = imsic.guest_index_bits;
  404. aplic->msicfg_mmode.lhxw = imsic.hart_index_bits;
  405. aplic->msicfg_mmode.hhxw = imsic.group_index_bits;
  406. aplic->msicfg_mmode.hhxs = imsic.group_index_shift;
  407. if (aplic->msicfg_mmode.hhxs <
  408. (2 * IMSIC_MMIO_PAGE_SHIFT))
  409. return SBI_EINVAL;
  410. aplic->msicfg_mmode.hhxs -= 24;
  411. aplic->msicfg_mmode.base_addr = imsic.regs[0].addr;
  412. } else {
  413. goto aplic_msi_parent_done;
  414. }
  415. val = fdt_getprop(fdt, nodeoff, "riscv,children", &len);
  416. if (!val || len < sizeof(fdt32_t))
  417. goto aplic_msi_parent_done;
  418. noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
  419. if (noff < 0)
  420. return noff;
  421. val = fdt_getprop(fdt, noff, "msi-parent", &len);
  422. if (!val || len < sizeof(fdt32_t))
  423. goto aplic_msi_parent_done;
  424. noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
  425. if (noff < 0)
  426. return noff;
  427. rc = fdt_parse_imsic_node(fdt, noff, &imsic);
  428. if (rc)
  429. return rc;
  430. rc = imsic_data_check(&imsic);
  431. if (rc)
  432. return rc;
  433. if (!imsic.targets_mmode) {
  434. aplic->has_msicfg_smode = true;
  435. aplic->msicfg_smode.lhxs = imsic.guest_index_bits;
  436. aplic->msicfg_smode.lhxw = imsic.hart_index_bits;
  437. aplic->msicfg_smode.hhxw = imsic.group_index_bits;
  438. aplic->msicfg_smode.hhxs = imsic.group_index_shift;
  439. if (aplic->msicfg_smode.hhxs <
  440. (2 * IMSIC_MMIO_PAGE_SHIFT))
  441. return SBI_EINVAL;
  442. aplic->msicfg_smode.hhxs -= 24;
  443. aplic->msicfg_smode.base_addr = imsic.regs[0].addr;
  444. }
  445. }
  446. aplic_msi_parent_done:
  447. for (d = 0; d < APLIC_MAX_DELEGATE; d++) {
  448. deleg = &aplic->delegate[d];
  449. deleg->first_irq = 0;
  450. deleg->last_irq = 0;
  451. deleg->child_index = 0;
  452. }
  453. del = fdt_getprop(fdt, nodeoff, "riscv,delegate", &len);
  454. if (!del || len < (3 * sizeof(fdt32_t)))
  455. goto skip_delegate_parse;
  456. d = 0;
  457. dcnt = len / sizeof(fdt32_t);
  458. for (i = 0; i < dcnt; i += 3) {
  459. if (d >= APLIC_MAX_DELEGATE)
  460. break;
  461. deleg = &aplic->delegate[d];
  462. deleg->first_irq = fdt32_to_cpu(del[i + 1]);
  463. deleg->last_irq = fdt32_to_cpu(del[i + 2]);
  464. deleg->child_index = 0;
  465. child_found = false;
  466. val = fdt_getprop(fdt, nodeoff, "riscv,children", &len);
  467. if (!val || len < sizeof(fdt32_t)) {
  468. deleg->first_irq = 0;
  469. deleg->last_irq = 0;
  470. deleg->child_index = 0;
  471. continue;
  472. }
  473. len = len / sizeof(fdt32_t);
  474. for (j = 0; j < len; j++) {
  475. if (del[i] != val[j])
  476. continue;
  477. deleg->child_index = j;
  478. child_found = true;
  479. break;
  480. }
  481. if (child_found) {
  482. d++;
  483. } else {
  484. deleg->first_irq = 0;
  485. deleg->last_irq = 0;
  486. deleg->child_index = 0;
  487. }
  488. }
  489. skip_delegate_parse:
  490. return 0;
  491. }
  492. bool fdt_check_imsic_mlevel(void *fdt)
  493. {
  494. const fdt32_t *val;
  495. int i, len, noff = 0;
  496. if (!fdt)
  497. return false;
  498. while ((noff = fdt_node_offset_by_compatible(fdt, noff,
  499. "riscv,imsics")) >= 0) {
  500. val = fdt_getprop(fdt, noff, "interrupts-extended", &len);
  501. if (val && len > sizeof(fdt32_t)) {
  502. len = len / sizeof(fdt32_t);
  503. for (i = 0; i < len; i += 2) {
  504. if (fdt32_to_cpu(val[i + 1]) == IRQ_M_EXT)
  505. return true;
  506. }
  507. }
  508. }
  509. return false;
  510. }
  511. int fdt_parse_imsic_node(void *fdt, int nodeoff, struct imsic_data *imsic)
  512. {
  513. const fdt32_t *val;
  514. struct imsic_regs *regs;
  515. uint64_t reg_addr, reg_size;
  516. int i, rc, len, nr_parent_irqs;
  517. if (nodeoff < 0 || !imsic || !fdt)
  518. return SBI_ENODEV;
  519. imsic->targets_mmode = false;
  520. val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &len);
  521. if (val && len > sizeof(fdt32_t)) {
  522. len = len / sizeof(fdt32_t);
  523. nr_parent_irqs = len / 2;
  524. for (i = 0; i < len; i += 2) {
  525. if (fdt32_to_cpu(val[i + 1]) == IRQ_M_EXT) {
  526. imsic->targets_mmode = true;
  527. break;
  528. }
  529. }
  530. } else
  531. return SBI_EINVAL;
  532. val = fdt_getprop(fdt, nodeoff, "riscv,guest-index-bits", &len);
  533. if (val && len > 0)
  534. imsic->guest_index_bits = fdt32_to_cpu(*val);
  535. else
  536. imsic->guest_index_bits = 0;
  537. val = fdt_getprop(fdt, nodeoff, "riscv,hart-index-bits", &len);
  538. if (val && len > 0) {
  539. imsic->hart_index_bits = fdt32_to_cpu(*val);
  540. } else {
  541. imsic->hart_index_bits = sbi_fls(nr_parent_irqs);
  542. if ((1UL << imsic->hart_index_bits) < nr_parent_irqs)
  543. imsic->hart_index_bits++;
  544. }
  545. val = fdt_getprop(fdt, nodeoff, "riscv,group-index-bits", &len);
  546. if (val && len > 0)
  547. imsic->group_index_bits = fdt32_to_cpu(*val);
  548. else
  549. imsic->group_index_bits = 0;
  550. val = fdt_getprop(fdt, nodeoff, "riscv,group-index-shift", &len);
  551. if (val && len > 0)
  552. imsic->group_index_shift = fdt32_to_cpu(*val);
  553. else
  554. imsic->group_index_shift = 2 * IMSIC_MMIO_PAGE_SHIFT;
  555. val = fdt_getprop(fdt, nodeoff, "riscv,num-ids", &len);
  556. if (val && len > 0)
  557. imsic->num_ids = fdt32_to_cpu(*val);
  558. else
  559. return SBI_EINVAL;
  560. for (i = 0; i < IMSIC_MAX_REGS; i++) {
  561. regs = &imsic->regs[i];
  562. regs->addr = 0;
  563. regs->size = 0;
  564. }
  565. for (i = 0; i < (IMSIC_MAX_REGS - 1); i++) {
  566. regs = &imsic->regs[i];
  567. rc = fdt_get_node_addr_size(fdt, nodeoff, i,
  568. &reg_addr, &reg_size);
  569. if (rc < 0 || !reg_addr || !reg_size)
  570. break;
  571. regs->addr = reg_addr;
  572. regs->size = reg_size;
  573. };
  574. if (!imsic->regs[0].size)
  575. return SBI_EINVAL;
  576. return 0;
  577. }
  578. int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic)
  579. {
  580. int len, rc;
  581. const fdt32_t *val;
  582. uint64_t reg_addr, reg_size;
  583. if (nodeoffset < 0 || !plic || !fdt)
  584. return SBI_ENODEV;
  585. rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
  586. &reg_addr, &reg_size);
  587. if (rc < 0 || !reg_addr || !reg_size)
  588. return SBI_ENODEV;
  589. plic->addr = reg_addr;
  590. val = fdt_getprop(fdt, nodeoffset, "riscv,ndev", &len);
  591. if (len > 0)
  592. plic->num_src = fdt32_to_cpu(*val);
  593. return 0;
  594. }
  595. int fdt_parse_plic(void *fdt, struct plic_data *plic, const char *compat)
  596. {
  597. int nodeoffset;
  598. if (!compat || !plic || !fdt)
  599. return SBI_ENODEV;
  600. nodeoffset = fdt_node_offset_by_compatible(fdt, -1, compat);
  601. if (nodeoffset < 0)
  602. return nodeoffset;
  603. return fdt_parse_plic_node(fdt, nodeoffset, plic);
  604. }
  605. int fdt_parse_aclint_node(void *fdt, int nodeoffset, bool for_timer,
  606. unsigned long *out_addr1, unsigned long *out_size1,
  607. unsigned long *out_addr2, unsigned long *out_size2,
  608. u32 *out_first_hartid, u32 *out_hart_count)
  609. {
  610. const fdt32_t *val;
  611. uint64_t reg_addr, reg_size;
  612. int i, rc, count, cpu_offset, cpu_intc_offset;
  613. u32 phandle, hwirq, hartid, first_hartid, last_hartid, hart_count;
  614. u32 match_hwirq = (for_timer) ? IRQ_M_TIMER : IRQ_M_SOFT;
  615. if (nodeoffset < 0 || !fdt ||
  616. !out_addr1 || !out_size1 ||
  617. !out_first_hartid || !out_hart_count)
  618. return SBI_EINVAL;
  619. rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
  620. &reg_addr, &reg_size);
  621. if (rc < 0 || !reg_size)
  622. return SBI_ENODEV;
  623. *out_addr1 = reg_addr;
  624. *out_size1 = reg_size;
  625. rc = fdt_get_node_addr_size(fdt, nodeoffset, 1,
  626. &reg_addr, &reg_size);
  627. if (rc < 0 || !reg_size)
  628. reg_addr = reg_size = 0;
  629. if (out_addr2)
  630. *out_addr2 = reg_addr;
  631. if (out_size2)
  632. *out_size2 = reg_size;
  633. *out_first_hartid = 0;
  634. *out_hart_count = 0;
  635. val = fdt_getprop(fdt, nodeoffset, "interrupts-extended", &count);
  636. if (!val || count < sizeof(fdt32_t))
  637. return 0;
  638. count = count / sizeof(fdt32_t);
  639. first_hartid = -1U;
  640. hart_count = last_hartid = 0;
  641. for (i = 0; i < (count / 2); i++) {
  642. phandle = fdt32_to_cpu(val[2 * i]);
  643. hwirq = fdt32_to_cpu(val[(2 * i) + 1]);
  644. cpu_intc_offset = fdt_node_offset_by_phandle(fdt, phandle);
  645. if (cpu_intc_offset < 0)
  646. continue;
  647. cpu_offset = fdt_parent_offset(fdt, cpu_intc_offset);
  648. if (cpu_offset < 0)
  649. continue;
  650. rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
  651. if (rc)
  652. continue;
  653. if (SBI_HARTMASK_MAX_BITS <= hartid)
  654. continue;
  655. if (match_hwirq == hwirq) {
  656. if (hartid < first_hartid)
  657. first_hartid = hartid;
  658. if (hartid > last_hartid)
  659. last_hartid = hartid;
  660. hart_count++;
  661. }
  662. }
  663. if ((last_hartid >= first_hartid) && first_hartid != -1U) {
  664. *out_first_hartid = first_hartid;
  665. count = last_hartid - first_hartid + 1;
  666. *out_hart_count = (hart_count < count) ? hart_count : count;
  667. }
  668. return 0;
  669. }
  670. int fdt_parse_plmt_node(void *fdt, int nodeoffset, unsigned long *plmt_base,
  671. unsigned long *plmt_size, u32 *hart_count)
  672. {
  673. const fdt32_t *val;
  674. int rc, i, count;
  675. uint64_t reg_addr, reg_size;
  676. u32 phandle, hwirq, hartid, hcount;
  677. if (nodeoffset < 0 || !fdt || !plmt_base ||
  678. !hart_count || !plmt_size)
  679. return SBI_EINVAL;
  680. rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
  681. &reg_addr, &reg_size);
  682. if (rc < 0)
  683. return SBI_ENODEV;
  684. *plmt_base = reg_addr;
  685. *plmt_size = reg_size;
  686. val = fdt_getprop(fdt, nodeoffset, "interrupts-extended", &count);
  687. if (!val || count < sizeof(fdt32_t))
  688. return 0;
  689. count = count / sizeof(fdt32_t);
  690. hcount = 0;
  691. for (i = 0; i < (count / 2); i++) {
  692. int cpu_offset, cpu_intc_offset;
  693. phandle = fdt32_to_cpu(val[2 * i]);
  694. hwirq = fdt32_to_cpu(val[2 * i + 1]);
  695. cpu_intc_offset = fdt_node_offset_by_phandle(fdt, phandle);
  696. if (cpu_intc_offset < 0)
  697. continue;
  698. cpu_offset = fdt_parent_offset(fdt, cpu_intc_offset);
  699. if (cpu_offset < 0)
  700. continue;
  701. rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
  702. if (rc)
  703. continue;
  704. if (SBI_HARTMASK_MAX_BITS <= hartid)
  705. continue;
  706. if (hwirq == IRQ_M_TIMER)
  707. hcount++;
  708. }
  709. *hart_count = hcount;
  710. return 0;
  711. }
  712. int fdt_parse_plicsw_node(void *fdt, int nodeoffset, unsigned long *plicsw_base,
  713. unsigned long *size, u32 *hart_count)
  714. {
  715. const fdt32_t *val;
  716. int rc, i, count;
  717. uint64_t reg_addr, reg_size;
  718. u32 phandle, hwirq, hartid, hcount;
  719. if (nodeoffset < 0 || !fdt || !plicsw_base ||
  720. !hart_count || !size)
  721. return SBI_EINVAL;
  722. rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
  723. &reg_addr, &reg_size);
  724. if (rc < 0)
  725. return SBI_ENODEV;
  726. *plicsw_base = reg_addr;
  727. *size = reg_size;
  728. val = fdt_getprop(fdt, nodeoffset, "interrupts-extended", &count);
  729. if (!val || count < sizeof(fdt32_t))
  730. return 0;
  731. count = count / sizeof(fdt32_t);
  732. hcount = 0;
  733. for (i = 0; i < (count / 2); i++) {
  734. int cpu_offset, cpu_intc_offset;
  735. phandle = fdt32_to_cpu(val[2 * i]);
  736. hwirq = fdt32_to_cpu(val[2 * i + 1]);
  737. cpu_intc_offset = fdt_node_offset_by_phandle(fdt, phandle);
  738. if (cpu_intc_offset < 0)
  739. continue;
  740. cpu_offset = fdt_parent_offset(fdt, cpu_intc_offset);
  741. if (cpu_offset < 0)
  742. continue;
  743. rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
  744. if (rc)
  745. continue;
  746. if (SBI_HARTMASK_MAX_BITS <= hartid)
  747. continue;
  748. if (hwirq == IRQ_M_SOFT)
  749. hcount++;
  750. }
  751. *hart_count = hcount;
  752. return 0;
  753. }
  754. int fdt_parse_compat_addr(void *fdt, uint64_t *addr,
  755. const char *compatible)
  756. {
  757. int nodeoffset, rc;
  758. nodeoffset = fdt_node_offset_by_compatible(fdt, -1, compatible);
  759. if (nodeoffset < 0)
  760. return nodeoffset;
  761. rc = fdt_get_node_addr_size(fdt, nodeoffset, 0, addr, NULL);
  762. if (rc < 0 || !addr)
  763. return SBI_ENODEV;
  764. return 0;
  765. }