123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390 |
- /*
- * Copyright (c) 2017-2024, STMicroelectronics - All Rights Reserved
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
- #include <errno.h>
- #include <arch_helpers.h>
- #include <common/fdt_wrappers.h>
- #include <drivers/clk.h>
- #include <drivers/generic_delay_timer.h>
- #include <drivers/st/stm32_gpio.h>
- #include <drivers/st/stm32mp_clkfunc.h>
- #include <lib/mmio.h>
- #include <libfdt.h>
- #include <platform_def.h>
- /*
- * Get the frequency of an oscillator from its name in device tree.
- * @param name: oscillator name
- * @param freq: stores the frequency of the oscillator
- * @return: 0 on success, and a negative FDT/ERRNO error code on failure.
- */
- int fdt_osc_read_freq(const char *name, uint32_t *freq)
- {
- int node, subnode;
- void *fdt;
- if (fdt_get_address(&fdt) == 0) {
- return -ENOENT;
- }
- node = fdt_path_offset(fdt, "/clocks");
- if (node < 0) {
- return -FDT_ERR_NOTFOUND;
- }
- fdt_for_each_subnode(subnode, fdt, node) {
- const char *cchar;
- int ret;
- cchar = fdt_get_name(fdt, subnode, &ret);
- if (cchar == NULL) {
- return ret;
- }
- if ((strncmp(cchar, name, (size_t)ret) == 0) &&
- (fdt_get_status(subnode) != DT_DISABLED)) {
- const fdt32_t *cuint;
- cuint = fdt_getprop(fdt, subnode, "clock-frequency",
- &ret);
- if (cuint == NULL) {
- return ret;
- }
- *freq = fdt32_to_cpu(*cuint);
- return 0;
- }
- }
- /* Oscillator not found, freq=0 */
- *freq = 0;
- return 0;
- }
- /*
- * Check the presence of an oscillator property from its id.
- * @param node_label: clock node name
- * @param prop_name: property name
- * @return: true/false regarding search result.
- */
- bool fdt_clk_read_bool(const char *node_label, const char *prop_name)
- {
- int node, subnode;
- void *fdt;
- if (fdt_get_address(&fdt) == 0) {
- return false;
- }
- node = fdt_path_offset(fdt, "/clocks");
- if (node < 0) {
- return false;
- }
- fdt_for_each_subnode(subnode, fdt, node) {
- const char *cchar;
- int ret;
- cchar = fdt_get_name(fdt, subnode, &ret);
- if (cchar == NULL) {
- return false;
- }
- if (strncmp(cchar, node_label, (size_t)ret) != 0) {
- continue;
- }
- if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) {
- return true;
- }
- }
- return false;
- }
- /*
- * Get the value of a oscillator property from its name.
- * @param node_label: oscillator name
- * @param prop_name: property name
- * @param dflt_value: default value
- * @return oscillator value on success, default value if property not found.
- */
- uint32_t fdt_clk_read_uint32_default(const char *node_label,
- const char *prop_name, uint32_t dflt_value)
- {
- int node, subnode;
- void *fdt;
- if (fdt_get_address(&fdt) == 0) {
- return dflt_value;
- }
- node = fdt_path_offset(fdt, "/clocks");
- if (node < 0) {
- return dflt_value;
- }
- fdt_for_each_subnode(subnode, fdt, node) {
- const char *cchar;
- int ret;
- cchar = fdt_get_name(fdt, subnode, &ret);
- if (cchar == NULL) {
- return dflt_value;
- }
- if (strncmp(cchar, node_label, (size_t)ret) != 0) {
- continue;
- }
- return fdt_read_uint32_default(fdt, subnode, prop_name,
- dflt_value);
- }
- return dflt_value;
- }
- /*
- * Get the RCC node offset from the device tree
- * @param fdt: Device tree reference
- * @return: Node offset or a negative value on error
- */
- static int fdt_get_rcc_node(void *fdt)
- {
- static int node;
- if (node <= 0) {
- node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
- }
- return node;
- }
- /*
- * Read a series of parameters in rcc-clk section in device tree
- * @param prop_name: Name of the RCC property to be read
- * @param array: the array to store the property parameters
- * @param count: number of parameters to be read
- * @return: 0 on succes or a negative value on error
- */
- int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t count,
- uint32_t *array)
- {
- int node;
- void *fdt;
- if (fdt_get_address(&fdt) == 0) {
- return -ENOENT;
- }
- node = fdt_get_rcc_node(fdt);
- if (node < 0) {
- return -FDT_ERR_NOTFOUND;
- }
- return fdt_read_uint32_array(fdt, node, prop_name, count, array);
- }
- /*
- * Get the subnode offset in rcc-clk section from its name in device tree
- * @param name: name of the RCC property
- * @return: offset on success, and a negative FDT/ERRNO error code on failure.
- */
- int fdt_rcc_subnode_offset(const char *name)
- {
- int node, subnode;
- void *fdt;
- if (fdt_get_address(&fdt) == 0) {
- return -ENOENT;
- }
- node = fdt_get_rcc_node(fdt);
- if (node < 0) {
- return -FDT_ERR_NOTFOUND;
- }
- subnode = fdt_subnode_offset(fdt, node, name);
- if (subnode <= 0) {
- return -FDT_ERR_NOTFOUND;
- }
- return subnode;
- }
- /*
- * Get the pointer to a rcc-clk property from its name.
- * @param name: name of the RCC property
- * @param lenp: stores the length of the property.
- * @return: pointer to the property on success, and NULL value on failure.
- */
- const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
- {
- const fdt32_t *cuint;
- int node, len;
- void *fdt;
- if (fdt_get_address(&fdt) == 0) {
- return NULL;
- }
- node = fdt_get_rcc_node(fdt);
- if (node < 0) {
- return NULL;
- }
- cuint = fdt_getprop(fdt, node, prop_name, &len);
- if (cuint == NULL) {
- return NULL;
- }
- *lenp = len;
- return cuint;
- }
- #if defined(IMAGE_BL32)
- /*
- * Get the secure state for rcc node in device tree.
- * @return: true if rcc is configured for secure world access, false if not.
- */
- bool fdt_get_rcc_secure_state(void)
- {
- void *fdt;
- if (fdt_get_address(&fdt) == 0) {
- return false;
- }
- if (fdt_node_offset_by_compatible(fdt, -1, DT_RCC_SEC_CLK_COMPAT) < 0) {
- return false;
- }
- return true;
- }
- #endif
- /*
- * Get the clock ID of the given node in device tree.
- * @param node: node offset
- * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure.
- */
- int fdt_get_clock_id(int node)
- {
- const fdt32_t *cuint;
- void *fdt;
- if (fdt_get_address(&fdt) == 0) {
- return -ENOENT;
- }
- cuint = fdt_getprop(fdt, node, "clocks", NULL);
- if (cuint == NULL) {
- return -FDT_ERR_NOTFOUND;
- }
- cuint++;
- return (int)fdt32_to_cpu(*cuint);
- }
- /*
- * Get the frequency of the specified UART instance.
- * @param instance: UART interface registers base address.
- * @return: clock frequency on success, 0 value on failure.
- */
- unsigned long fdt_get_uart_clock_freq(uintptr_t instance)
- {
- void *fdt;
- int node;
- int clk_id;
- if (fdt_get_address(&fdt) == 0) {
- return 0UL;
- }
- /* Check for UART nodes */
- node = dt_match_instance_by_compatible(DT_UART_COMPAT, instance);
- if (node < 0) {
- return 0UL;
- }
- clk_id = fdt_get_clock_id(node);
- if (clk_id < 0) {
- return 0UL;
- }
- return clk_get_rate((unsigned long)clk_id);
- }
- /*******************************************************************************
- * This function sets the STGEN counter value.
- ******************************************************************************/
- static void stgen_set_counter(unsigned long long counter)
- {
- #ifdef __aarch64__
- mmio_write_64(STGEN_BASE + CNTCV_OFF, counter);
- #else
- mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)counter);
- mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(counter >> 32));
- #endif
- }
- /*******************************************************************************
- * This function returns the STGEN counter value.
- ******************************************************************************/
- static unsigned long long stm32mp_stgen_get_counter(void)
- {
- #ifdef __aarch64__
- return mmio_read_64(STGEN_BASE + CNTCV_OFF);
- #else
- return (((unsigned long long)mmio_read_32(STGEN_BASE + CNTCVU_OFF) << 32) |
- mmio_read_32(STGEN_BASE + CNTCVL_OFF));
- #endif
- }
- /*******************************************************************************
- * This function configures and restores the STGEN counter depending on the
- * connected clock.
- ******************************************************************************/
- void stm32mp_stgen_config(unsigned long rate)
- {
- uint32_t cntfid0;
- unsigned long long counter;
- cntfid0 = mmio_read_32(STGEN_BASE + CNTFID_OFF);
- if (cntfid0 == rate) {
- return;
- }
- mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
- if (cntfid0 != 0U) {
- counter = stm32mp_stgen_get_counter() * rate / cntfid0;
- stgen_set_counter(counter);
- }
- mmio_write_32(STGEN_BASE + CNTFID_OFF, rate);
- mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
- write_cntfrq_el0(rate);
- /* Need to update timer with new frequency */
- generic_delay_timer_init();
- }
- /*******************************************************************************
- * This function restores CPU generic timer rate from the STGEN clock rate.
- ******************************************************************************/
- void stm32mp_stgen_restore_rate(void)
- {
- unsigned long rate;
- rate = mmio_read_32(STGEN_BASE + CNTFID_OFF);
- write_cntfrq_el0((u_register_t)rate);
- }
|