GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,393 @@
|
||||
/*
|
||||
* Copyright (C) 2022, STMicroelectronics - All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef CLK_STM32_CORE_H
|
||||
#define CLK_STM32_CORE_H
|
||||
|
||||
struct mux_cfg {
|
||||
uint16_t offset;
|
||||
uint8_t shift;
|
||||
uint8_t width;
|
||||
uint8_t bitrdy;
|
||||
};
|
||||
|
||||
struct gate_cfg {
|
||||
uint16_t offset;
|
||||
uint8_t bit_idx;
|
||||
uint8_t set_clr;
|
||||
};
|
||||
|
||||
struct clk_div_table {
|
||||
unsigned int val;
|
||||
unsigned int div;
|
||||
};
|
||||
|
||||
struct div_cfg {
|
||||
uint16_t offset;
|
||||
uint8_t shift;
|
||||
uint8_t width;
|
||||
uint8_t flags;
|
||||
uint8_t bitrdy;
|
||||
const struct clk_div_table *table;
|
||||
};
|
||||
|
||||
struct parent_cfg {
|
||||
uint8_t num_parents;
|
||||
const uint16_t *id_parents;
|
||||
struct mux_cfg *mux;
|
||||
};
|
||||
|
||||
struct stm32_clk_priv;
|
||||
|
||||
struct stm32_clk_ops {
|
||||
unsigned long (*recalc_rate)(struct stm32_clk_priv *priv, int id, unsigned long rate);
|
||||
int (*get_parent)(struct stm32_clk_priv *priv, int id);
|
||||
int (*set_rate)(struct stm32_clk_priv *priv, int id, unsigned long rate,
|
||||
unsigned long prate);
|
||||
int (*enable)(struct stm32_clk_priv *priv, int id);
|
||||
void (*disable)(struct stm32_clk_priv *priv, int id);
|
||||
bool (*is_enabled)(struct stm32_clk_priv *priv, int id);
|
||||
void (*init)(struct stm32_clk_priv *priv, int id);
|
||||
};
|
||||
|
||||
struct clk_stm32 {
|
||||
uint16_t binding;
|
||||
uint16_t parent;
|
||||
uint8_t flags;
|
||||
void *clock_cfg;
|
||||
const struct stm32_clk_ops *ops;
|
||||
};
|
||||
|
||||
struct stm32_clk_priv {
|
||||
uintptr_t base;
|
||||
const uint32_t num;
|
||||
const struct clk_stm32 *clks;
|
||||
const struct parent_cfg *parents;
|
||||
const uint32_t nb_parents;
|
||||
const struct gate_cfg *gates;
|
||||
const uint32_t nb_gates;
|
||||
const struct div_cfg *div;
|
||||
const uint32_t nb_div;
|
||||
struct clk_oscillator_data *osci_data;
|
||||
const uint32_t nb_osci_data;
|
||||
uint32_t *gate_refcounts;
|
||||
void *pdata;
|
||||
};
|
||||
|
||||
struct stm32_clk_bypass {
|
||||
uint16_t offset;
|
||||
uint8_t bit_byp;
|
||||
uint8_t bit_digbyp;
|
||||
};
|
||||
|
||||
struct stm32_clk_css {
|
||||
uint16_t offset;
|
||||
uint8_t bit_css;
|
||||
};
|
||||
|
||||
struct stm32_clk_drive {
|
||||
uint16_t offset;
|
||||
uint8_t drv_shift;
|
||||
uint8_t drv_width;
|
||||
uint8_t drv_default;
|
||||
};
|
||||
|
||||
struct clk_oscillator_data {
|
||||
const char *name;
|
||||
uint16_t id_clk;
|
||||
unsigned long frequency;
|
||||
uint16_t gate_id;
|
||||
uint16_t gate_rdy_id;
|
||||
struct stm32_clk_bypass *bypass;
|
||||
struct stm32_clk_css *css;
|
||||
struct stm32_clk_drive *drive;
|
||||
};
|
||||
|
||||
struct clk_fixed_rate {
|
||||
const char *name;
|
||||
unsigned long fixed_rate;
|
||||
};
|
||||
|
||||
struct clk_gate_cfg {
|
||||
uint32_t offset;
|
||||
uint8_t bit_idx;
|
||||
};
|
||||
|
||||
/* CLOCK FLAGS */
|
||||
#define CLK_IS_CRITICAL BIT(0)
|
||||
#define CLK_IGNORE_UNUSED BIT(1)
|
||||
#define CLK_SET_RATE_PARENT BIT(2)
|
||||
|
||||
#define CLK_DIVIDER_ONE_BASED BIT(0)
|
||||
#define CLK_DIVIDER_POWER_OF_TWO BIT(1)
|
||||
#define CLK_DIVIDER_ALLOW_ZERO BIT(2)
|
||||
#define CLK_DIVIDER_HIWORD_MASK BIT(3)
|
||||
#define CLK_DIVIDER_ROUND_CLOSEST BIT(4)
|
||||
#define CLK_DIVIDER_READ_ONLY BIT(5)
|
||||
#define CLK_DIVIDER_MAX_AT_ZERO BIT(6)
|
||||
#define CLK_DIVIDER_BIG_ENDIAN BIT(7)
|
||||
|
||||
#define MUX_MAX_PARENTS U(0x8000)
|
||||
#define MUX_PARENT_MASK GENMASK(14, 0)
|
||||
#define MUX_FLAG U(0x8000)
|
||||
#define MUX(mux) ((mux) | MUX_FLAG)
|
||||
|
||||
#define NO_GATE 0
|
||||
#define _NO_ID UINT16_MAX
|
||||
#define CLK_IS_ROOT UINT16_MAX
|
||||
#define MUX_NO_BIT_RDY UINT8_MAX
|
||||
#define DIV_NO_BIT_RDY UINT8_MAX
|
||||
|
||||
#define MASK_WIDTH_SHIFT(_width, _shift) \
|
||||
GENMASK(((_width) + (_shift) - 1U), (_shift))
|
||||
|
||||
int clk_stm32_init(struct stm32_clk_priv *priv, uintptr_t base);
|
||||
void clk_stm32_enable_critical_clocks(void);
|
||||
|
||||
struct stm32_clk_priv *clk_stm32_get_priv(void);
|
||||
|
||||
int clk_get_index(struct stm32_clk_priv *priv, unsigned long binding_id);
|
||||
const struct clk_stm32 *_clk_get(struct stm32_clk_priv *priv, int id);
|
||||
|
||||
void clk_oscillator_set_bypass(struct stm32_clk_priv *priv, int id, bool digbyp, bool bypass);
|
||||
void clk_oscillator_set_drive(struct stm32_clk_priv *priv, int id, uint8_t lsedrv);
|
||||
void clk_oscillator_set_css(struct stm32_clk_priv *priv, int id, bool css);
|
||||
|
||||
int _clk_stm32_gate_wait_ready(struct stm32_clk_priv *priv, uint16_t gate_id, bool ready_on);
|
||||
|
||||
int clk_oscillator_wait_ready(struct stm32_clk_priv *priv, int id, bool ready_on);
|
||||
int clk_oscillator_wait_ready_on(struct stm32_clk_priv *priv, int id);
|
||||
int clk_oscillator_wait_ready_off(struct stm32_clk_priv *priv, int id);
|
||||
|
||||
int clk_stm32_get_counter(unsigned long binding_id);
|
||||
|
||||
void _clk_stm32_gate_disable(struct stm32_clk_priv *priv, uint16_t gate_id);
|
||||
int _clk_stm32_gate_enable(struct stm32_clk_priv *priv, uint16_t gate_id);
|
||||
|
||||
int _clk_stm32_set_parent(struct stm32_clk_priv *priv, int id, int src_id);
|
||||
int _clk_stm32_set_parent_by_index(struct stm32_clk_priv *priv, int clk, int sel);
|
||||
|
||||
int _clk_stm32_get_parent(struct stm32_clk_priv *priv, int id);
|
||||
int _clk_stm32_get_parent_by_index(struct stm32_clk_priv *priv, int clk_id, int idx);
|
||||
int _clk_stm32_get_parent_index(struct stm32_clk_priv *priv, int clk_id);
|
||||
|
||||
unsigned long _clk_stm32_get_rate(struct stm32_clk_priv *priv, int id);
|
||||
unsigned long _clk_stm32_get_parent_rate(struct stm32_clk_priv *priv, int id);
|
||||
|
||||
bool _stm32_clk_is_flags(struct stm32_clk_priv *priv, int id, uint8_t flag);
|
||||
|
||||
int _clk_stm32_enable(struct stm32_clk_priv *priv, int id);
|
||||
void _clk_stm32_disable(struct stm32_clk_priv *priv, int id);
|
||||
|
||||
int clk_stm32_enable_call_ops(struct stm32_clk_priv *priv, uint16_t id);
|
||||
void clk_stm32_disable_call_ops(struct stm32_clk_priv *priv, uint16_t id);
|
||||
|
||||
bool _clk_stm32_is_enabled(struct stm32_clk_priv *priv, int id);
|
||||
|
||||
int _clk_stm32_divider_set_rate(struct stm32_clk_priv *priv, int div_id,
|
||||
unsigned long rate, unsigned long parent_rate);
|
||||
|
||||
int clk_stm32_divider_set_rate(struct stm32_clk_priv *priv, int id, unsigned long rate,
|
||||
unsigned long prate);
|
||||
|
||||
unsigned long _clk_stm32_divider_recalc(struct stm32_clk_priv *priv,
|
||||
int div_id,
|
||||
unsigned long prate);
|
||||
|
||||
unsigned long clk_stm32_divider_recalc(struct stm32_clk_priv *priv, int idx,
|
||||
unsigned long prate);
|
||||
|
||||
int clk_stm32_gate_enable(struct stm32_clk_priv *priv, int idx);
|
||||
void clk_stm32_gate_disable(struct stm32_clk_priv *priv, int idx);
|
||||
|
||||
bool _clk_stm32_gate_is_enabled(struct stm32_clk_priv *priv, int gate_id);
|
||||
bool clk_stm32_gate_is_enabled(struct stm32_clk_priv *priv, int idx);
|
||||
|
||||
uint32_t clk_stm32_div_get_value(struct stm32_clk_priv *priv, int div_id);
|
||||
int clk_stm32_set_div(struct stm32_clk_priv *priv, uint32_t div_id, uint32_t value);
|
||||
int clk_mux_set_parent(struct stm32_clk_priv *priv, uint16_t pid, uint8_t sel);
|
||||
int clk_mux_get_parent(struct stm32_clk_priv *priv, uint32_t mux_id);
|
||||
|
||||
int stm32_clk_parse_fdt_by_name(void *fdt, int node, const char *name, uint32_t *tab, uint32_t *nb);
|
||||
|
||||
#ifdef CFG_STM32_CLK_DEBUG
|
||||
void clk_stm32_display_clock_info(void);
|
||||
#endif
|
||||
|
||||
struct clk_stm32_div_cfg {
|
||||
int id;
|
||||
};
|
||||
|
||||
#define STM32_DIV(idx, _binding, _parent, _flags, _div_id) \
|
||||
[(idx)] = (struct clk_stm32){ \
|
||||
.binding = (_binding),\
|
||||
.parent = (_parent),\
|
||||
.flags = (_flags),\
|
||||
.clock_cfg = &(struct clk_stm32_div_cfg){\
|
||||
.id = (_div_id),\
|
||||
},\
|
||||
.ops = &clk_stm32_divider_ops,\
|
||||
}
|
||||
|
||||
struct clk_stm32_gate_cfg {
|
||||
int id;
|
||||
};
|
||||
|
||||
#define STM32_GATE(idx, _binding, _parent, _flags, _gate_id) \
|
||||
[(idx)] = (struct clk_stm32){ \
|
||||
.binding = (_binding),\
|
||||
.parent = (_parent),\
|
||||
.flags = (_flags),\
|
||||
.clock_cfg = &(struct clk_stm32_gate_cfg){\
|
||||
.id = (_gate_id),\
|
||||
},\
|
||||
.ops = &clk_stm32_gate_ops,\
|
||||
}
|
||||
|
||||
struct fixed_factor_cfg {
|
||||
unsigned int mult;
|
||||
unsigned int div;
|
||||
};
|
||||
|
||||
unsigned long fixed_factor_recalc_rate(struct stm32_clk_priv *priv,
|
||||
int _idx, unsigned long prate);
|
||||
|
||||
#define FIXED_FACTOR(idx, _idx, _parent, _mult, _div) \
|
||||
[(idx)] = (struct clk_stm32){ \
|
||||
.binding = (_idx),\
|
||||
.parent = (_parent),\
|
||||
.clock_cfg = &(struct fixed_factor_cfg){\
|
||||
.mult = (_mult),\
|
||||
.div = (_div),\
|
||||
},\
|
||||
.ops = &clk_fixed_factor_ops,\
|
||||
}
|
||||
|
||||
#define GATE(idx, _binding, _parent, _flags, _offset, _bit_idx) \
|
||||
[(idx)] = (struct clk_stm32){ \
|
||||
.binding = (_binding),\
|
||||
.parent = (_parent),\
|
||||
.flags = (_flags),\
|
||||
.clock_cfg = &(struct clk_gate_cfg){\
|
||||
.offset = (_offset),\
|
||||
.bit_idx = (_bit_idx),\
|
||||
},\
|
||||
.ops = &clk_gate_ops,\
|
||||
}
|
||||
|
||||
#define STM32_MUX(idx, _binding, _mux_id, _flags) \
|
||||
[(idx)] = (struct clk_stm32){ \
|
||||
.binding = (_binding),\
|
||||
.parent = (MUX(_mux_id)),\
|
||||
.flags = (_flags),\
|
||||
.clock_cfg = NULL,\
|
||||
.ops = (&clk_mux_ops),\
|
||||
}
|
||||
|
||||
struct clk_timer_cfg {
|
||||
uint32_t apbdiv;
|
||||
uint32_t timpre;
|
||||
};
|
||||
|
||||
#define CK_TIMER(idx, _idx, _parent, _flags, _apbdiv, _timpre) \
|
||||
[(idx)] = (struct clk_stm32){ \
|
||||
.binding = (_idx),\
|
||||
.parent = (_parent),\
|
||||
.flags = (CLK_SET_RATE_PARENT | (_flags)),\
|
||||
.clock_cfg = &(struct clk_timer_cfg){\
|
||||
.apbdiv = (_apbdiv),\
|
||||
.timpre = (_timpre),\
|
||||
},\
|
||||
.ops = &clk_timer_ops,\
|
||||
}
|
||||
|
||||
struct clk_stm32_fixed_rate_cfg {
|
||||
unsigned long rate;
|
||||
};
|
||||
|
||||
#define CLK_FIXED_RATE(idx, _binding, _rate) \
|
||||
[(idx)] = (struct clk_stm32){ \
|
||||
.binding = (_binding),\
|
||||
.parent = (CLK_IS_ROOT),\
|
||||
.clock_cfg = &(struct clk_stm32_fixed_rate_cfg){\
|
||||
.rate = (_rate),\
|
||||
},\
|
||||
.ops = &clk_stm32_fixed_rate_ops,\
|
||||
}
|
||||
|
||||
#define BYPASS(_offset, _bit_byp, _bit_digbyp) &(struct stm32_clk_bypass){\
|
||||
.offset = (_offset),\
|
||||
.bit_byp = (_bit_byp),\
|
||||
.bit_digbyp = (_bit_digbyp),\
|
||||
}
|
||||
|
||||
#define CSS(_offset, _bit_css) &(struct stm32_clk_css){\
|
||||
.offset = (_offset),\
|
||||
.bit_css = (_bit_css),\
|
||||
}
|
||||
|
||||
#define DRIVE(_offset, _shift, _width, _default) &(struct stm32_clk_drive){\
|
||||
.offset = (_offset),\
|
||||
.drv_shift = (_shift),\
|
||||
.drv_width = (_width),\
|
||||
.drv_default = (_default),\
|
||||
}
|
||||
|
||||
#define OSCILLATOR(idx_osc, _id, _name, _gate_id, _gate_rdy_id, _bypass, _css, _drive) \
|
||||
[(idx_osc)] = (struct clk_oscillator_data){\
|
||||
.name = (_name),\
|
||||
.id_clk = (_id),\
|
||||
.gate_id = (_gate_id),\
|
||||
.gate_rdy_id = (_gate_rdy_id),\
|
||||
.bypass = (_bypass),\
|
||||
.css = (_css),\
|
||||
.drive = (_drive),\
|
||||
}
|
||||
|
||||
struct clk_oscillator_data *clk_oscillator_get_data(struct stm32_clk_priv *priv, int id);
|
||||
|
||||
void clk_stm32_osc_init(struct stm32_clk_priv *priv, int id);
|
||||
bool clk_stm32_osc_gate_is_enabled(struct stm32_clk_priv *priv, int id);
|
||||
int clk_stm32_osc_gate_enable(struct stm32_clk_priv *priv, int id);
|
||||
void clk_stm32_osc_gate_disable(struct stm32_clk_priv *priv, int id);
|
||||
|
||||
struct stm32_osc_cfg {
|
||||
int osc_id;
|
||||
};
|
||||
|
||||
#define CLK_OSC(idx, _idx, _parent, _osc_id) \
|
||||
[(idx)] = (struct clk_stm32){ \
|
||||
.binding = (_idx),\
|
||||
.parent = (_parent),\
|
||||
.flags = CLK_IS_CRITICAL,\
|
||||
.clock_cfg = &(struct stm32_osc_cfg){\
|
||||
.osc_id = (_osc_id),\
|
||||
},\
|
||||
.ops = &clk_stm32_osc_ops,\
|
||||
}
|
||||
|
||||
#define CLK_OSC_FIXED(idx, _idx, _parent, _osc_id) \
|
||||
[(idx)] = (struct clk_stm32){ \
|
||||
.binding = (_idx),\
|
||||
.parent = (_parent),\
|
||||
.flags = CLK_IS_CRITICAL,\
|
||||
.clock_cfg = &(struct stm32_osc_cfg){\
|
||||
.osc_id = (_osc_id),\
|
||||
},\
|
||||
.ops = &clk_stm32_osc_nogate_ops,\
|
||||
}
|
||||
|
||||
extern const struct stm32_clk_ops clk_mux_ops;
|
||||
extern const struct stm32_clk_ops clk_stm32_divider_ops;
|
||||
extern const struct stm32_clk_ops clk_stm32_gate_ops;
|
||||
extern const struct stm32_clk_ops clk_fixed_factor_ops;
|
||||
extern const struct stm32_clk_ops clk_gate_ops;
|
||||
extern const struct stm32_clk_ops clk_timer_ops;
|
||||
extern const struct stm32_clk_ops clk_stm32_fixed_rate_ops;
|
||||
extern const struct stm32_clk_ops clk_stm32_osc_ops;
|
||||
extern const struct stm32_clk_ops clk_stm32_osc_nogate_ops;
|
||||
|
||||
#endif /* CLK_STM32_CORE_H */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,377 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2022, 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 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);
|
||||
counter = stm32mp_stgen_get_counter() * rate / cntfid0;
|
||||
|
||||
mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)counter);
|
||||
mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(counter >> 32));
|
||||
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 returns the STGEN counter value.
|
||||
******************************************************************************/
|
||||
unsigned long long stm32mp_stgen_get_counter(void)
|
||||
{
|
||||
return (((unsigned long long)mmio_read_32(STGEN_BASE + CNTCVU_OFF) << 32) |
|
||||
mmio_read_32(STGEN_BASE + CNTCVL_OFF));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function restores the STGEN counter value.
|
||||
* It takes a first input value as a counter backup value to be restored and a
|
||||
* offset in ms to be added.
|
||||
******************************************************************************/
|
||||
void stm32mp_stgen_restore_counter(unsigned long long value,
|
||||
unsigned long long offset_in_ms)
|
||||
{
|
||||
unsigned long long cnt;
|
||||
|
||||
cnt = value + ((offset_in_ms *
|
||||
mmio_read_32(STGEN_BASE + CNTFID_OFF)) / 1000U);
|
||||
|
||||
mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
|
||||
mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)cnt);
|
||||
mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(cnt >> 32));
|
||||
mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
|
||||
}
|
||||
Reference in New Issue
Block a user