stm32mp_clkfunc.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. /*
  2. * Copyright (c) 2017-2024, STMicroelectronics - All Rights Reserved
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #include <errno.h>
  7. #include <arch_helpers.h>
  8. #include <common/fdt_wrappers.h>
  9. #include <drivers/clk.h>
  10. #include <drivers/generic_delay_timer.h>
  11. #include <drivers/st/stm32_gpio.h>
  12. #include <drivers/st/stm32mp_clkfunc.h>
  13. #include <lib/mmio.h>
  14. #include <libfdt.h>
  15. #include <platform_def.h>
  16. /*
  17. * Get the frequency of an oscillator from its name in device tree.
  18. * @param name: oscillator name
  19. * @param freq: stores the frequency of the oscillator
  20. * @return: 0 on success, and a negative FDT/ERRNO error code on failure.
  21. */
  22. int fdt_osc_read_freq(const char *name, uint32_t *freq)
  23. {
  24. int node, subnode;
  25. void *fdt;
  26. if (fdt_get_address(&fdt) == 0) {
  27. return -ENOENT;
  28. }
  29. node = fdt_path_offset(fdt, "/clocks");
  30. if (node < 0) {
  31. return -FDT_ERR_NOTFOUND;
  32. }
  33. fdt_for_each_subnode(subnode, fdt, node) {
  34. const char *cchar;
  35. int ret;
  36. cchar = fdt_get_name(fdt, subnode, &ret);
  37. if (cchar == NULL) {
  38. return ret;
  39. }
  40. if ((strncmp(cchar, name, (size_t)ret) == 0) &&
  41. (fdt_get_status(subnode) != DT_DISABLED)) {
  42. const fdt32_t *cuint;
  43. cuint = fdt_getprop(fdt, subnode, "clock-frequency",
  44. &ret);
  45. if (cuint == NULL) {
  46. return ret;
  47. }
  48. *freq = fdt32_to_cpu(*cuint);
  49. return 0;
  50. }
  51. }
  52. /* Oscillator not found, freq=0 */
  53. *freq = 0;
  54. return 0;
  55. }
  56. /*
  57. * Check the presence of an oscillator property from its id.
  58. * @param node_label: clock node name
  59. * @param prop_name: property name
  60. * @return: true/false regarding search result.
  61. */
  62. bool fdt_clk_read_bool(const char *node_label, const char *prop_name)
  63. {
  64. int node, subnode;
  65. void *fdt;
  66. if (fdt_get_address(&fdt) == 0) {
  67. return false;
  68. }
  69. node = fdt_path_offset(fdt, "/clocks");
  70. if (node < 0) {
  71. return false;
  72. }
  73. fdt_for_each_subnode(subnode, fdt, node) {
  74. const char *cchar;
  75. int ret;
  76. cchar = fdt_get_name(fdt, subnode, &ret);
  77. if (cchar == NULL) {
  78. return false;
  79. }
  80. if (strncmp(cchar, node_label, (size_t)ret) != 0) {
  81. continue;
  82. }
  83. if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) {
  84. return true;
  85. }
  86. }
  87. return false;
  88. }
  89. /*
  90. * Get the value of a oscillator property from its name.
  91. * @param node_label: oscillator name
  92. * @param prop_name: property name
  93. * @param dflt_value: default value
  94. * @return oscillator value on success, default value if property not found.
  95. */
  96. uint32_t fdt_clk_read_uint32_default(const char *node_label,
  97. const char *prop_name, uint32_t dflt_value)
  98. {
  99. int node, subnode;
  100. void *fdt;
  101. if (fdt_get_address(&fdt) == 0) {
  102. return dflt_value;
  103. }
  104. node = fdt_path_offset(fdt, "/clocks");
  105. if (node < 0) {
  106. return dflt_value;
  107. }
  108. fdt_for_each_subnode(subnode, fdt, node) {
  109. const char *cchar;
  110. int ret;
  111. cchar = fdt_get_name(fdt, subnode, &ret);
  112. if (cchar == NULL) {
  113. return dflt_value;
  114. }
  115. if (strncmp(cchar, node_label, (size_t)ret) != 0) {
  116. continue;
  117. }
  118. return fdt_read_uint32_default(fdt, subnode, prop_name,
  119. dflt_value);
  120. }
  121. return dflt_value;
  122. }
  123. /*
  124. * Get the RCC node offset from the device tree
  125. * @param fdt: Device tree reference
  126. * @return: Node offset or a negative value on error
  127. */
  128. static int fdt_get_rcc_node(void *fdt)
  129. {
  130. static int node;
  131. if (node <= 0) {
  132. node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
  133. }
  134. return node;
  135. }
  136. /*
  137. * Read a series of parameters in rcc-clk section in device tree
  138. * @param prop_name: Name of the RCC property to be read
  139. * @param array: the array to store the property parameters
  140. * @param count: number of parameters to be read
  141. * @return: 0 on succes or a negative value on error
  142. */
  143. int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count,
  144. uint32_t *array)
  145. {
  146. int node;
  147. void *fdt;
  148. if (fdt_get_address(&fdt) == 0) {
  149. return -ENOENT;
  150. }
  151. node = fdt_get_rcc_node(fdt);
  152. if (node < 0) {
  153. return -FDT_ERR_NOTFOUND;
  154. }
  155. return fdt_read_uint32_array(fdt, node, prop_name, count, array);
  156. }
  157. /*
  158. * Get the subnode offset in rcc-clk section from its name in device tree
  159. * @param name: name of the RCC property
  160. * @return: offset on success, and a negative FDT/ERRNO error code on failure.
  161. */
  162. int fdt_rcc_subnode_offset(const char *name)
  163. {
  164. int node, subnode;
  165. void *fdt;
  166. if (fdt_get_address(&fdt) == 0) {
  167. return -ENOENT;
  168. }
  169. node = fdt_get_rcc_node(fdt);
  170. if (node < 0) {
  171. return -FDT_ERR_NOTFOUND;
  172. }
  173. subnode = fdt_subnode_offset(fdt, node, name);
  174. if (subnode <= 0) {
  175. return -FDT_ERR_NOTFOUND;
  176. }
  177. return subnode;
  178. }
  179. /*
  180. * Get the pointer to a rcc-clk property from its name.
  181. * @param name: name of the RCC property
  182. * @param lenp: stores the length of the property.
  183. * @return: pointer to the property on success, and NULL value on failure.
  184. */
  185. const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
  186. {
  187. const fdt32_t *cuint;
  188. int node, len;
  189. void *fdt;
  190. if (fdt_get_address(&fdt) == 0) {
  191. return NULL;
  192. }
  193. node = fdt_get_rcc_node(fdt);
  194. if (node < 0) {
  195. return NULL;
  196. }
  197. cuint = fdt_getprop(fdt, node, prop_name, &len);
  198. if (cuint == NULL) {
  199. return NULL;
  200. }
  201. *lenp = len;
  202. return cuint;
  203. }
  204. #if defined(IMAGE_BL32)
  205. /*
  206. * Get the secure state for rcc node in device tree.
  207. * @return: true if rcc is configured for secure world access, false if not.
  208. */
  209. bool fdt_get_rcc_secure_state(void)
  210. {
  211. void *fdt;
  212. if (fdt_get_address(&fdt) == 0) {
  213. return false;
  214. }
  215. if (fdt_node_offset_by_compatible(fdt, -1, DT_RCC_SEC_CLK_COMPAT) < 0) {
  216. return false;
  217. }
  218. return true;
  219. }
  220. #endif
  221. /*
  222. * Get the clock ID of the given node in device tree.
  223. * @param node: node offset
  224. * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure.
  225. */
  226. int fdt_get_clock_id(int node)
  227. {
  228. const fdt32_t *cuint;
  229. void *fdt;
  230. if (fdt_get_address(&fdt) == 0) {
  231. return -ENOENT;
  232. }
  233. cuint = fdt_getprop(fdt, node, "clocks", NULL);
  234. if (cuint == NULL) {
  235. return -FDT_ERR_NOTFOUND;
  236. }
  237. cuint++;
  238. return (int)fdt32_to_cpu(*cuint);
  239. }
  240. /*
  241. * Get the frequency of the specified UART instance.
  242. * @param instance: UART interface registers base address.
  243. * @return: clock frequency on success, 0 value on failure.
  244. */
  245. unsigned long fdt_get_uart_clock_freq(uintptr_t instance)
  246. {
  247. void *fdt;
  248. int node;
  249. int clk_id;
  250. if (fdt_get_address(&fdt) == 0) {
  251. return 0UL;
  252. }
  253. /* Check for UART nodes */
  254. node = dt_match_instance_by_compatible(DT_UART_COMPAT, instance);
  255. if (node < 0) {
  256. return 0UL;
  257. }
  258. clk_id = fdt_get_clock_id(node);
  259. if (clk_id < 0) {
  260. return 0UL;
  261. }
  262. return clk_get_rate((unsigned long)clk_id);
  263. }
  264. /*******************************************************************************
  265. * This function sets the STGEN counter value.
  266. ******************************************************************************/
  267. static void stgen_set_counter(unsigned long long counter)
  268. {
  269. #ifdef __aarch64__
  270. mmio_write_64(STGEN_BASE + CNTCV_OFF, counter);
  271. #else
  272. mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)counter);
  273. mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(counter >> 32));
  274. #endif
  275. }
  276. /*******************************************************************************
  277. * This function returns the STGEN counter value.
  278. ******************************************************************************/
  279. static unsigned long long stm32mp_stgen_get_counter(void)
  280. {
  281. #ifdef __aarch64__
  282. return mmio_read_64(STGEN_BASE + CNTCV_OFF);
  283. #else
  284. return (((unsigned long long)mmio_read_32(STGEN_BASE + CNTCVU_OFF) << 32) |
  285. mmio_read_32(STGEN_BASE + CNTCVL_OFF));
  286. #endif
  287. }
  288. /*******************************************************************************
  289. * This function configures and restores the STGEN counter depending on the
  290. * connected clock.
  291. ******************************************************************************/
  292. void stm32mp_stgen_config(unsigned long rate)
  293. {
  294. uint32_t cntfid0;
  295. unsigned long long counter;
  296. cntfid0 = mmio_read_32(STGEN_BASE + CNTFID_OFF);
  297. if (cntfid0 == rate) {
  298. return;
  299. }
  300. mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
  301. if (cntfid0 != 0U) {
  302. counter = stm32mp_stgen_get_counter() * rate / cntfid0;
  303. stgen_set_counter(counter);
  304. }
  305. mmio_write_32(STGEN_BASE + CNTFID_OFF, rate);
  306. mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
  307. write_cntfrq_el0(rate);
  308. /* Need to update timer with new frequency */
  309. generic_delay_timer_init();
  310. }
  311. /*******************************************************************************
  312. * This function restores CPU generic timer rate from the STGEN clock rate.
  313. ******************************************************************************/
  314. void stm32mp_stgen_restore_rate(void)
  315. {
  316. unsigned long rate;
  317. rate = mmio_read_32(STGEN_BASE + CNTFID_OFF);
  318. write_cntfrq_el0((u_register_t)rate);
  319. }