blob: 1aa05bf55632b4083b69d31ab2805298ea3e2021 [file] [log] [blame]
Yann Gautier9aea69e2018-07-24 17:13:36 +02001/*
Yann Gautier1a3fc9f2019-01-17 14:35:22 +01002 * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
Yann Gautier9aea69e2018-07-24 17:13:36 +02003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
Yann Gautier9aea69e2018-07-24 17:13:36 +02007#include <errno.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00008
Yann Gautier9aea69e2018-07-24 17:13:36 +02009#include <libfdt.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000010
Yann Gautier57e282b2019-01-07 11:17:24 +010011#include <platform_def.h>
12
Yann Gautier4d429472019-02-14 11:15:20 +010013#include <drivers/st/stm32_gpio.h>
14#include <drivers/st/stm32mp_clkfunc.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000015#include <drivers/st/stm32mp1_clk.h>
16#include <drivers/st/stm32mp1_clkfunc.h>
17#include <dt-bindings/clock/stm32mp1-clksrc.h>
18
Yann Gautier9aea69e2018-07-24 17:13:36 +020019const char *stm32mp_osc_node_label[NB_OSC] = {
20 [_LSI] = "clk-lsi",
21 [_LSE] = "clk-lse",
22 [_HSI] = "clk-hsi",
23 [_HSE] = "clk-hse",
24 [_CSI] = "clk-csi",
25 [_I2S_CKIN] = "i2s_ckin",
Yann Gautier9aea69e2018-07-24 17:13:36 +020026};
27
Yann Gautier4d429472019-02-14 11:15:20 +010028/*
29 * Get the frequency of an oscillator from its name in device tree.
30 * @param name: oscillator name
31 * @param freq: stores the frequency of the oscillator
32 * @return: 0 on success, and a negative FDT/ERRNO error code on failure.
33 */
Yann Gautier9aea69e2018-07-24 17:13:36 +020034int fdt_osc_read_freq(const char *name, uint32_t *freq)
35{
36 int node, subnode;
37 void *fdt;
38
39 if (fdt_get_address(&fdt) == 0) {
40 return -ENOENT;
41 }
42
43 node = fdt_path_offset(fdt, "/clocks");
44 if (node < 0) {
45 return -FDT_ERR_NOTFOUND;
46 }
47
48 fdt_for_each_subnode(subnode, fdt, node) {
49 const char *cchar;
50 int ret;
51
52 cchar = fdt_get_name(fdt, subnode, &ret);
53 if (cchar == NULL) {
54 return ret;
55 }
56
57 if (strncmp(cchar, name, (size_t)ret) == 0) {
58 const fdt32_t *cuint;
59
60 cuint = fdt_getprop(fdt, subnode, "clock-frequency",
61 &ret);
62 if (cuint == NULL) {
63 return ret;
64 }
65
66 *freq = fdt32_to_cpu(*cuint);
67
68 return 0;
69 }
70 }
71
72 /* Oscillator not found, freq=0 */
73 *freq = 0;
74 return 0;
75}
76
Yann Gautier4d429472019-02-14 11:15:20 +010077/*
78 * Check the presence of an oscillator property from its id.
79 * @param osc_id: oscillator ID
80 * @param prop_name: property name
81 * @return: true/false regarding search result.
82 */
Yann Gautier9aea69e2018-07-24 17:13:36 +020083bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name)
84{
85 int node, subnode;
86 void *fdt;
87
88 if (fdt_get_address(&fdt) == 0) {
89 return false;
90 }
91
92 if (osc_id >= NB_OSC) {
93 return false;
94 }
95
96 node = fdt_path_offset(fdt, "/clocks");
97 if (node < 0) {
98 return false;
99 }
100
101 fdt_for_each_subnode(subnode, fdt, node) {
102 const char *cchar;
103 int ret;
104
105 cchar = fdt_get_name(fdt, subnode, &ret);
106 if (cchar == NULL) {
107 return false;
108 }
109
110 if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
111 (size_t)ret) != 0) {
112 continue;
113 }
114
115 if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) {
116 return true;
117 }
118 }
119
120 return false;
121}
122
Yann Gautier4d429472019-02-14 11:15:20 +0100123/*
124 * Get the value of a oscillator property from its ID.
125 * @param osc_id: oscillator ID
126 * @param prop_name: property name
127 * @param dflt_value: default value
128 * @return oscillator value on success, default value if property not found.
129 */
Yann Gautier9aea69e2018-07-24 17:13:36 +0200130uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,
131 const char *prop_name, uint32_t dflt_value)
132{
133 int node, subnode;
134 void *fdt;
135
136 if (fdt_get_address(&fdt) == 0) {
137 return dflt_value;
138 }
139
140 if (osc_id >= NB_OSC) {
141 return dflt_value;
142 }
143
144 node = fdt_path_offset(fdt, "/clocks");
145 if (node < 0) {
146 return dflt_value;
147 }
148
149 fdt_for_each_subnode(subnode, fdt, node) {
150 const char *cchar;
151 int ret;
152
153 cchar = fdt_get_name(fdt, subnode, &ret);
154 if (cchar == NULL) {
155 return dflt_value;
156 }
157
158 if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
159 (size_t)ret) != 0) {
160 continue;
161 }
162
163 return fdt_read_uint32_default(subnode, prop_name, dflt_value);
164 }
165
166 return dflt_value;
167}