/** * __prci_readl() - read from a PRCI register * @pd: PRCI context * @offs: register offset to read from (in bytes, from PRCI base address) * * Read the register located at offset @offs from the base virtual * address of the PRCI register target described by @pd, and return * the value to the caller. * * Context: Any context. * * Return: the contents of the register described by @pd and @offs.
*/ static u32 __prci_readl(struct __prci_data *pd, u32 offs)
{ return readl_relaxed(pd->va + offs);
}
/** * __prci_wrpll_unpack() - unpack WRPLL configuration registers into parameters * @c: ptr to a struct wrpll_cfg record to write config into * @r: value read from the PRCI PLL configuration register * * Given a value @r read from an FU740 PRCI PLL configuration register, * split it into fields and populate it into the WRPLL configuration record * pointed to by @c. * * The COREPLLCFG0 macros are used below, but the other *PLLCFG0 macros * have the same register layout. * * Context: Any context.
*/ staticvoid __prci_wrpll_unpack(struct wrpll_cfg *c, u32 r)
{
u32 v;
v = r & PRCI_COREPLLCFG0_DIVR_MASK;
v >>= PRCI_COREPLLCFG0_DIVR_SHIFT;
c->divr = v;
v = r & PRCI_COREPLLCFG0_DIVF_MASK;
v >>= PRCI_COREPLLCFG0_DIVF_SHIFT;
c->divf = v;
v = r & PRCI_COREPLLCFG0_DIVQ_MASK;
v >>= PRCI_COREPLLCFG0_DIVQ_SHIFT;
c->divq = v;
v = r & PRCI_COREPLLCFG0_RANGE_MASK;
v >>= PRCI_COREPLLCFG0_RANGE_SHIFT;
c->range = v;
/** * __prci_wrpll_pack() - pack PLL configuration parameters into a register value * @c: pointer to a struct wrpll_cfg record containing the PLL's cfg * * Using a set of WRPLL configuration values pointed to by @c, * assemble a PRCI PLL configuration register value, and return it to * the caller. * * Context: Any context. Caller must ensure that the contents of the * record pointed to by @c do not change during the execution * of this function. * * Returns: a value suitable for writing into a PRCI PLL configuration * register
*/ static u32 __prci_wrpll_pack(conststruct wrpll_cfg *c)
{
u32 r = 0;
r |= c->divr << PRCI_COREPLLCFG0_DIVR_SHIFT;
r |= c->divf << PRCI_COREPLLCFG0_DIVF_SHIFT;
r |= c->divq << PRCI_COREPLLCFG0_DIVQ_SHIFT;
r |= c->range << PRCI_COREPLLCFG0_RANGE_SHIFT;
/* external feedback mode not supported */
r |= PRCI_COREPLLCFG0_FSE_MASK;
return r;
}
/** * __prci_wrpll_read_cfg0() - read the WRPLL configuration from the PRCI * @pd: PRCI context * @pwd: PRCI WRPLL metadata * * Read the current configuration of the PLL identified by @pwd from * the PRCI identified by @pd, and store it into the local configuration * cache in @pwd. * * Context: Any context. Caller must prevent the records pointed to by * @pd and @pwd from changing during execution.
*/ staticvoid __prci_wrpll_read_cfg0(struct __prci_data *pd, struct __prci_wrpll_data *pwd)
{
__prci_wrpll_unpack(&pwd->c, __prci_readl(pd, pwd->cfg0_offs));
}
/** * __prci_wrpll_write_cfg0() - write WRPLL configuration into the PRCI * @pd: PRCI context * @pwd: PRCI WRPLL metadata * @c: WRPLL configuration record to write * * Write the WRPLL configuration described by @c into the WRPLL * configuration register identified by @pwd in the PRCI instance * described by @c. Make a cached copy of the WRPLL's current * configuration so it can be used by other code. * * Context: Any context. Caller must prevent the records pointed to by * @pd and @pwd from changing during execution.
*/ staticvoid __prci_wrpll_write_cfg0(struct __prci_data *pd, struct __prci_wrpll_data *pwd, struct wrpll_cfg *c)
{
__prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd);
/** * sifive_prci_coreclksel_use_hfclk() - switch the CORECLK mux to output HFCLK * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg * * Switch the CORECLK mux to the HFCLK input source; return once complete. * * Context: Any context. Caller must prevent concurrent changes to the * PRCI_CORECLKSEL_OFFSET register.
*/ void sifive_prci_coreclksel_use_hfclk(struct __prci_data *pd)
{
u32 r;
r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
r |= PRCI_CORECLKSEL_CORECLKSEL_MASK;
__prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
}
/** * sifive_prci_coreclksel_use_corepll() - switch the CORECLK mux to output * COREPLL * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg * * Switch the CORECLK mux to the COREPLL output clock; return once complete. * * Context: Any context. Caller must prevent concurrent changes to the * PRCI_CORECLKSEL_OFFSET register.
*/ void sifive_prci_coreclksel_use_corepll(struct __prci_data *pd)
{
u32 r;
r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK;
__prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
}
/** * sifive_prci_coreclksel_use_final_corepll() - switch the CORECLK mux to output * FINAL_COREPLL * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg * * Switch the CORECLK mux to the final COREPLL output clock; return once * complete. * * Context: Any context. Caller must prevent concurrent changes to the * PRCI_CORECLKSEL_OFFSET register.
*/ void sifive_prci_coreclksel_use_final_corepll(struct __prci_data *pd)
{
u32 r;
r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK;
__prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
}
/** * sifive_prci_corepllsel_use_dvfscorepll() - switch the COREPLL mux to * output DVFS_COREPLL * @pd: struct __prci_data * for the PRCI containing the COREPLL mux reg * * Switch the COREPLL mux to the DVFSCOREPLL output clock; return once complete. * * Context: Any context. Caller must prevent concurrent changes to the * PRCI_COREPLLSEL_OFFSET register.
*/ void sifive_prci_corepllsel_use_dvfscorepll(struct __prci_data *pd)
{
u32 r;
r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET);
r |= PRCI_COREPLLSEL_COREPLLSEL_MASK;
__prci_writel(r, PRCI_COREPLLSEL_OFFSET, pd);
r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET); /* barrier */
}
/** * sifive_prci_corepllsel_use_corepll() - switch the COREPLL mux to * output COREPLL * @pd: struct __prci_data * for the PRCI containing the COREPLL mux reg * * Switch the COREPLL mux to the COREPLL output clock; return once complete. * * Context: Any context. Caller must prevent concurrent changes to the * PRCI_COREPLLSEL_OFFSET register.
*/ void sifive_prci_corepllsel_use_corepll(struct __prci_data *pd)
{
u32 r;
r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET);
r &= ~PRCI_COREPLLSEL_COREPLLSEL_MASK;
__prci_writel(r, PRCI_COREPLLSEL_OFFSET, pd);
r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET); /* barrier */
}
/** * sifive_prci_hfpclkpllsel_use_hfclk() - switch the HFPCLKPLL mux to * output HFCLK * @pd: struct __prci_data * for the PRCI containing the HFPCLKPLL mux reg * * Switch the HFPCLKPLL mux to the HFCLK input source; return once complete. * * Context: Any context. Caller must prevent concurrent changes to the * PRCI_HFPCLKPLLSEL_OFFSET register.
*/ void sifive_prci_hfpclkpllsel_use_hfclk(struct __prci_data *pd)
{
u32 r;
r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET);
r |= PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK;
__prci_writel(r, PRCI_HFPCLKPLLSEL_OFFSET, pd);
r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET); /* barrier */
}
/** * sifive_prci_hfpclkpllsel_use_hfpclkpll() - switch the HFPCLKPLL mux to * output HFPCLKPLL * @pd: struct __prci_data * for the PRCI containing the HFPCLKPLL mux reg * * Switch the HFPCLKPLL mux to the HFPCLKPLL output clock; return once complete. * * Context: Any context. Caller must prevent concurrent changes to the * PRCI_HFPCLKPLLSEL_OFFSET register.
*/ void sifive_prci_hfpclkpllsel_use_hfpclkpll(struct __prci_data *pd)
{
u32 r;
r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET);
r &= ~PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK;
__prci_writel(r, PRCI_HFPCLKPLLSEL_OFFSET, pd);
r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET); /* barrier */
}
/* PCIE AUX clock APIs for enable, disable. */ int sifive_prci_pcie_aux_clock_is_enabled(struct clk_hw *hw)
{ struct __prci_clock *pc = clk_hw_to_prci_clock(hw); struct __prci_data *pd = pc->pd;
u32 r;
r = __prci_readl(pd, PRCI_PCIE_AUX_OFFSET);
if (r & PRCI_PCIE_AUX_EN_MASK) return 1; else return 0;
}
int sifive_prci_pcie_aux_clock_enable(struct clk_hw *hw)
{ struct __prci_clock *pc = clk_hw_to_prci_clock(hw); struct __prci_data *pd = pc->pd;
u32 r __maybe_unused;
if (sifive_prci_pcie_aux_clock_is_enabled(hw)) return 0;
__prci_writel(1, PRCI_PCIE_AUX_OFFSET, pd);
r = __prci_readl(pd, PRCI_PCIE_AUX_OFFSET); /* barrier */
__prci_writel(0, PRCI_PCIE_AUX_OFFSET, pd);
r = __prci_readl(pd, PRCI_PCIE_AUX_OFFSET); /* barrier */
}
/** * __prci_register_clocks() - register clock controls in the PRCI * @dev: Linux struct device * @pd: The pointer for PRCI per-device instance data * @desc: The pointer for the information of clocks of each SoCs * * Register the list of clock controls described in __prci_init_clocks[] with * the Linux clock framework. * * Return: 0 upon success or a negative error code upon failure.
*/ staticint __prci_register_clocks(struct device *dev, struct __prci_data *pd, conststruct prci_clk_desc *desc)
{ struct clk_init_data init = { }; struct __prci_clock *pic; int parent_count, i, r;
parent_count = of_clk_get_parent_count(dev->of_node); if (parent_count != EXPECTED_CLK_PARENT_COUNT) {
dev_err(dev, "expected only two parent clocks, found %d\n",
parent_count); return -EINVAL;
}
/* Register PLLs */ for (i = 0; i < desc->num_clks; ++i) {
pic = &(desc->clks[i]);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.