// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2020 SiFive, Inc. * Copyright (C) 2020 Zong Li */ #include <linux/delay.h> #include <linux/io.h> #include <linux/module.h> #include <linux/of.h> #include "sifive-prci.h" #include "fu540-prci.h" #include "fu740-prci.h" /* * Private functions */ /** * __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) { … } static void __prci_writel(u32 v, u32 offs, struct __prci_data *pd) { … } /* WRPLL-related private functions */ /** * __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. */ static void __prci_wrpll_unpack(struct wrpll_cfg *c, u32 r) { … } /** * __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(const struct wrpll_cfg *c) { … } /** * __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. */ static void __prci_wrpll_read_cfg0(struct __prci_data *pd, struct __prci_wrpll_data *pwd) { … } /** * __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. */ static void __prci_wrpll_write_cfg0(struct __prci_data *pd, struct __prci_wrpll_data *pwd, struct wrpll_cfg *c) { … } /** * __prci_wrpll_write_cfg1() - write Clock enable/disable configuration * into the PRCI * @pd: PRCI context * @pwd: PRCI WRPLL metadata * @enable: Clock enable or disable value */ static void __prci_wrpll_write_cfg1(struct __prci_data *pd, struct __prci_wrpll_data *pwd, u32 enable) { … } /* * Linux clock framework integration * * See the Linux clock framework documentation for more information on * these functions. */ unsigned long sifive_prci_wrpll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { … } long sifive_prci_wrpll_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { … } int sifive_prci_wrpll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { … } int sifive_clk_is_enabled(struct clk_hw *hw) { … } int sifive_prci_clock_enable(struct clk_hw *hw) { … } void sifive_prci_clock_disable(struct clk_hw *hw) { … } /* TLCLKSEL clock integration */ unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { … } /* HFPCLK clock integration */ unsigned long sifive_prci_hfpclkplldiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { … } /* * Core clock mux control */ /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /* PCIE AUX clock APIs for enable, disable. */ int sifive_prci_pcie_aux_clock_is_enabled(struct clk_hw *hw) { … } int sifive_prci_pcie_aux_clock_enable(struct clk_hw *hw) { … } void sifive_prci_pcie_aux_clock_disable(struct clk_hw *hw) { … } /** * __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. */ static int __prci_register_clocks(struct device *dev, struct __prci_data *pd, const struct prci_clk_desc *desc) { … } /** * sifive_prci_probe() - initialize prci data and check parent count * @pdev: platform device pointer for the prci * * Return: 0 upon success or a negative error code upon failure. */ static int sifive_prci_probe(struct platform_device *pdev) { … } static const struct of_device_id sifive_prci_of_match[] = …; MODULE_DEVICE_TABLE(of, sifive_prci_of_match); static struct platform_driver sifive_prci_driver = …; module_platform_driver(…) …; MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;