stm32mp_dt.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. /*
  2. * Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #include <assert.h>
  7. #include <errno.h>
  8. #include <common/debug.h>
  9. #include <common/fdt_wrappers.h>
  10. #include <drivers/st/regulator.h>
  11. #include <drivers/st/stm32_gpio.h>
  12. #include <libfdt.h>
  13. #include <platform_def.h>
  14. #include <stm32mp_dt.h>
  15. static void *fdt;
  16. /*******************************************************************************
  17. * This function checks device tree file with its header.
  18. * Returns 0 on success and a negative FDT error code on failure.
  19. ******************************************************************************/
  20. int dt_open_and_check(uintptr_t dt_addr)
  21. {
  22. int ret;
  23. ret = fdt_check_header((void *)dt_addr);
  24. if (ret == 0) {
  25. fdt = (void *)dt_addr;
  26. }
  27. return ret;
  28. }
  29. /*******************************************************************************
  30. * This function gets the address of the DT.
  31. * If DT is OK, fdt_addr is filled with DT address.
  32. * Returns 1 if success, 0 otherwise.
  33. ******************************************************************************/
  34. int fdt_get_address(void **fdt_addr)
  35. {
  36. if (fdt == NULL) {
  37. return 0;
  38. }
  39. *fdt_addr = fdt;
  40. return 1;
  41. }
  42. /*******************************************************************************
  43. * This function check the presence of a node (generic use of fdt library).
  44. * Returns true if present, else return false.
  45. ******************************************************************************/
  46. bool fdt_check_node(int node)
  47. {
  48. int len;
  49. const char *cchar;
  50. cchar = fdt_get_name(fdt, node, &len);
  51. return (cchar != NULL) && (len >= 0);
  52. }
  53. /*******************************************************************************
  54. * This function return global node status (generic use of fdt library).
  55. ******************************************************************************/
  56. uint8_t fdt_get_status(int node)
  57. {
  58. uint8_t status = DT_DISABLED;
  59. const char *cchar;
  60. cchar = fdt_getprop(fdt, node, "status", NULL);
  61. if ((cchar == NULL) ||
  62. (strncmp(cchar, "okay", strlen("okay")) == 0)) {
  63. status |= DT_NON_SECURE;
  64. }
  65. cchar = fdt_getprop(fdt, node, "secure-status", NULL);
  66. if (((cchar == NULL) && (status == DT_NON_SECURE)) ||
  67. ((cchar != NULL) && (strncmp(cchar, "okay", strlen("okay")) == 0))) {
  68. status |= DT_SECURE;
  69. }
  70. return status;
  71. }
  72. #if ENABLE_ASSERTIONS
  73. /*******************************************************************************
  74. * This function returns the address cells from the node parent.
  75. * Returns:
  76. * - #address-cells value if success.
  77. * - invalid value if error.
  78. * - a default value if undefined #address-cells property as per libfdt
  79. * implementation.
  80. ******************************************************************************/
  81. static int fdt_get_node_parent_address_cells(int node)
  82. {
  83. int parent;
  84. parent = fdt_parent_offset(fdt, node);
  85. if (parent < 0) {
  86. return -FDT_ERR_NOTFOUND;
  87. }
  88. return fdt_address_cells(fdt, parent);
  89. }
  90. #endif
  91. /*******************************************************************************
  92. * This function gets the stdout pin configuration information from the DT.
  93. * And then calls the sub-function to treat it and set GPIO registers.
  94. * Returns 0 on success and a negative FDT error code on failure.
  95. ******************************************************************************/
  96. int dt_set_stdout_pinctrl(void)
  97. {
  98. int node;
  99. node = fdt_get_stdout_node_offset(fdt);
  100. if (node < 0) {
  101. return -FDT_ERR_NOTFOUND;
  102. }
  103. return dt_set_pinctrl_config(node);
  104. }
  105. /*******************************************************************************
  106. * This function fills the generic information from a given node.
  107. ******************************************************************************/
  108. void dt_fill_device_info(struct dt_node_info *info, int node)
  109. {
  110. const fdt32_t *cuint;
  111. assert(fdt_get_node_parent_address_cells(node) == 1);
  112. cuint = fdt_getprop(fdt, node, "reg", NULL);
  113. if (cuint != NULL) {
  114. info->base = fdt32_to_cpu(*cuint);
  115. } else {
  116. info->base = 0;
  117. }
  118. cuint = fdt_getprop(fdt, node, "clocks", NULL);
  119. if (cuint != NULL) {
  120. cuint++;
  121. info->clock = (int)fdt32_to_cpu(*cuint);
  122. } else {
  123. info->clock = -1;
  124. }
  125. cuint = fdt_getprop(fdt, node, "resets", NULL);
  126. if (cuint != NULL) {
  127. cuint++;
  128. info->reset = (int)fdt32_to_cpu(*cuint);
  129. } else {
  130. info->reset = -1;
  131. }
  132. info->status = fdt_get_status(node);
  133. }
  134. /*******************************************************************************
  135. * This function retrieve the generic information from DT.
  136. * Returns node on success and a negative FDT error code on failure.
  137. ******************************************************************************/
  138. int dt_get_node(struct dt_node_info *info, int offset, const char *compat)
  139. {
  140. int node;
  141. node = fdt_node_offset_by_compatible(fdt, offset, compat);
  142. if (node < 0) {
  143. return -FDT_ERR_NOTFOUND;
  144. }
  145. dt_fill_device_info(info, node);
  146. return node;
  147. }
  148. /*******************************************************************************
  149. * This function gets the UART instance info of stdout from the DT.
  150. * Returns node on success and a negative FDT error code on failure.
  151. ******************************************************************************/
  152. int dt_get_stdout_uart_info(struct dt_node_info *info)
  153. {
  154. int node;
  155. node = fdt_get_stdout_node_offset(fdt);
  156. if (node < 0) {
  157. return -FDT_ERR_NOTFOUND;
  158. }
  159. dt_fill_device_info(info, node);
  160. return node;
  161. }
  162. /*******************************************************************************
  163. * This function returns the node offset matching compatible string in the DT,
  164. * and also matching the reg property with the given address.
  165. * Returns value on success, and error value on failure.
  166. ******************************************************************************/
  167. int dt_match_instance_by_compatible(const char *compatible, uintptr_t address)
  168. {
  169. int node;
  170. fdt_for_each_compatible_node(fdt, node, compatible) {
  171. const fdt32_t *cuint;
  172. assert(fdt_get_node_parent_address_cells(node) == 1);
  173. cuint = fdt_getprop(fdt, node, "reg", NULL);
  174. if (cuint == NULL) {
  175. continue;
  176. }
  177. if ((uintptr_t)fdt32_to_cpu(*cuint) == address) {
  178. return node;
  179. }
  180. }
  181. return -FDT_ERR_NOTFOUND;
  182. }
  183. /*******************************************************************************
  184. * This function gets DDR size information from the DT.
  185. * Returns value in bytes on success, and 0 on failure.
  186. ******************************************************************************/
  187. size_t dt_get_ddr_size(void)
  188. {
  189. static size_t size;
  190. int node;
  191. if (size != 0U) {
  192. return size;
  193. }
  194. node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
  195. if (node < 0) {
  196. INFO("%s: Cannot read DDR node in DT\n", __func__);
  197. return 0U;
  198. }
  199. #ifdef __aarch64__
  200. size = (size_t)fdt_read_uint64_default(fdt, node, "st,mem-size", 0ULL);
  201. #else /* __aarch64__ */
  202. size = (size_t)fdt_read_uint32_default(fdt, node, "st,mem-size", 0U);
  203. #endif /* __aarch64__ */
  204. flush_dcache_range((uintptr_t)&size, sizeof(size_t));
  205. return size;
  206. }
  207. /*******************************************************************************
  208. * This function gets PWR VDD regulator voltage information from the DT.
  209. * Returns value in microvolts on success, and 0 on failure.
  210. ******************************************************************************/
  211. uint32_t dt_get_pwr_vdd_voltage(void)
  212. {
  213. struct rdev *regul = dt_get_vdd_regulator();
  214. uint16_t min;
  215. if (regul == NULL) {
  216. return 0;
  217. }
  218. regulator_get_range(regul, &min, NULL);
  219. return (uint32_t)min * 1000U;
  220. }
  221. /*******************************************************************************
  222. * This function retrieves VDD supply regulator from DT.
  223. * Returns an rdev taken from supply node, NULL otherwise.
  224. ******************************************************************************/
  225. struct rdev *dt_get_vdd_regulator(void)
  226. {
  227. int node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
  228. if (node < 0) {
  229. return NULL;
  230. }
  231. return regulator_get_by_supply_name(fdt, node, "vdd");
  232. }
  233. /*******************************************************************************
  234. * This function retrieves CPU supply regulator from DT.
  235. * Returns an rdev taken from supply node, NULL otherwise.
  236. ******************************************************************************/
  237. struct rdev *dt_get_cpu_regulator(void)
  238. {
  239. int node = fdt_path_offset(fdt, "/cpus/cpu@0");
  240. if (node < 0) {
  241. return NULL;
  242. }
  243. return regulator_get_by_supply_name(fdt, node, "cpu");
  244. }
  245. /*******************************************************************************
  246. * This function retrieves board model from DT
  247. * Returns string taken from model node, NULL otherwise
  248. ******************************************************************************/
  249. const char *dt_get_board_model(void)
  250. {
  251. int node = fdt_path_offset(fdt, "/");
  252. if (node < 0) {
  253. return NULL;
  254. }
  255. return (const char *)fdt_getprop(fdt, node, "model", NULL);
  256. }
  257. /*******************************************************************************
  258. * dt_find_otp_name: get OTP ID and length in DT.
  259. * name: sub-node name to look up.
  260. * otp: pointer to read OTP number or NULL.
  261. * otp_len: pointer to read OTP length in bits or NULL.
  262. * return value: 0 if no error, an FDT error value otherwise.
  263. ******************************************************************************/
  264. int dt_find_otp_name(const char *name, uint32_t *otp, uint32_t *otp_len)
  265. {
  266. int node;
  267. int len;
  268. const fdt32_t *cuint;
  269. if ((name == NULL) || (otp == NULL)) {
  270. return -FDT_ERR_BADVALUE;
  271. }
  272. node = fdt_node_offset_by_compatible(fdt, -1, DT_BSEC_COMPAT);
  273. if (node < 0) {
  274. return node;
  275. }
  276. node = fdt_subnode_offset(fdt, node, name);
  277. if (node < 0) {
  278. ERROR("nvmem node %s not found\n", name);
  279. return node;
  280. }
  281. cuint = fdt_getprop(fdt, node, "reg", &len);
  282. if ((cuint == NULL) || (len != (2 * (int)sizeof(uint32_t)))) {
  283. ERROR("Malformed nvmem node %s: ignored\n", name);
  284. return -FDT_ERR_BADVALUE;
  285. }
  286. if ((fdt32_to_cpu(*cuint) % sizeof(uint32_t)) != 0U) {
  287. ERROR("Misaligned nvmem %s element: ignored\n", name);
  288. return -FDT_ERR_BADVALUE;
  289. }
  290. if (otp != NULL) {
  291. *otp = fdt32_to_cpu(*cuint) / sizeof(uint32_t);
  292. }
  293. if (otp_len != NULL) {
  294. cuint++;
  295. *otp_len = fdt32_to_cpu(*cuint) * CHAR_BIT;
  296. }
  297. return 0;
  298. }
  299. /*******************************************************************************
  300. * This function gets the pin count for a GPIO bank based from the FDT.
  301. * It also checks node consistency.
  302. ******************************************************************************/
  303. int fdt_get_gpio_bank_pin_count(unsigned int bank)
  304. {
  305. int pinctrl_node;
  306. int node;
  307. uint32_t bank_offset;
  308. pinctrl_node = stm32_get_gpio_bank_pinctrl_node(fdt, bank);
  309. if (pinctrl_node < 0) {
  310. return -FDT_ERR_NOTFOUND;
  311. }
  312. bank_offset = stm32_get_gpio_bank_offset(bank);
  313. fdt_for_each_subnode(node, fdt, pinctrl_node) {
  314. const fdt32_t *cuint;
  315. int pin_count = 0;
  316. int len;
  317. int i;
  318. if (fdt_getprop(fdt, node, "gpio-controller", NULL) == NULL) {
  319. continue;
  320. }
  321. cuint = fdt_getprop(fdt, node, "reg", NULL);
  322. if (cuint == NULL) {
  323. continue;
  324. }
  325. if (fdt32_to_cpu(*cuint) != bank_offset) {
  326. continue;
  327. }
  328. if (fdt_get_status(node) == DT_DISABLED) {
  329. return 0;
  330. }
  331. /* Parse gpio-ranges with its 4 parameters */
  332. cuint = fdt_getprop(fdt, node, "gpio-ranges", &len);
  333. len /= sizeof(*cuint);
  334. if ((len % 4) != 0) {
  335. return -FDT_ERR_BADVALUE;
  336. }
  337. /* Get the last defined gpio line (offset + nb of pins) */
  338. for (i = 0; i < len; i += 4) {
  339. pin_count = MAX(pin_count, (int)(fdt32_to_cpu(cuint[i + 1]) +
  340. fdt32_to_cpu(cuint[i + 3])));
  341. }
  342. return pin_count;
  343. }
  344. return 0;
  345. }