Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 
0003 #include <linux/clk.h>
0004 #include <linux/clk-provider.h>
0005 #include <linux/mutex.h>
0006 #include <linux/of_device.h>
0007 #include <linux/platform_device.h>
0008 #include <linux/pm_domain.h>
0009 #include <linux/pm_opp.h>
0010 #include <linux/pm_runtime.h>
0011 #include <linux/slab.h>
0012 
0013 #include <soc/tegra/common.h>
0014 
0015 #include "clk.h"
0016 
0017 /*
0018  * This driver manages performance state of the core power domain for the
0019  * independent PLLs and system clocks.  We created a virtual clock device
0020  * for such clocks, see tegra_clk_dev_register().
0021  */
0022 
0023 struct tegra_clk_device {
0024     struct notifier_block clk_nb;
0025     struct device *dev;
0026     struct clk_hw *hw;
0027     struct mutex lock;
0028 };
0029 
0030 static int tegra_clock_set_pd_state(struct tegra_clk_device *clk_dev,
0031                     unsigned long rate)
0032 {
0033     struct device *dev = clk_dev->dev;
0034     struct dev_pm_opp *opp;
0035     unsigned int pstate;
0036 
0037     opp = dev_pm_opp_find_freq_ceil(dev, &rate);
0038     if (opp == ERR_PTR(-ERANGE)) {
0039         /*
0040          * Some clocks may be unused by a particular board and they
0041          * may have uninitiated clock rate that is overly high.  In
0042          * this case clock is expected to be disabled, but still we
0043          * need to set up performance state of the power domain and
0044          * not error out clk initialization.  A typical example is
0045          * a PCIe clock on Android tablets.
0046          */
0047         dev_dbg(dev, "failed to find ceil OPP for %luHz\n", rate);
0048         opp = dev_pm_opp_find_freq_floor(dev, &rate);
0049     }
0050 
0051     if (IS_ERR(opp)) {
0052         dev_err(dev, "failed to find OPP for %luHz: %pe\n", rate, opp);
0053         return PTR_ERR(opp);
0054     }
0055 
0056     pstate = dev_pm_opp_get_required_pstate(opp, 0);
0057     dev_pm_opp_put(opp);
0058 
0059     return dev_pm_genpd_set_performance_state(dev, pstate);
0060 }
0061 
0062 static int tegra_clock_change_notify(struct notifier_block *nb,
0063                      unsigned long msg, void *data)
0064 {
0065     struct clk_notifier_data *cnd = data;
0066     struct tegra_clk_device *clk_dev;
0067     int err = 0;
0068 
0069     clk_dev = container_of(nb, struct tegra_clk_device, clk_nb);
0070 
0071     mutex_lock(&clk_dev->lock);
0072     switch (msg) {
0073     case PRE_RATE_CHANGE:
0074         if (cnd->new_rate > cnd->old_rate)
0075             err = tegra_clock_set_pd_state(clk_dev, cnd->new_rate);
0076         break;
0077 
0078     case ABORT_RATE_CHANGE:
0079         err = tegra_clock_set_pd_state(clk_dev, cnd->old_rate);
0080         break;
0081 
0082     case POST_RATE_CHANGE:
0083         if (cnd->new_rate < cnd->old_rate)
0084             err = tegra_clock_set_pd_state(clk_dev, cnd->new_rate);
0085         break;
0086 
0087     default:
0088         break;
0089     }
0090     mutex_unlock(&clk_dev->lock);
0091 
0092     return notifier_from_errno(err);
0093 }
0094 
0095 static int tegra_clock_sync_pd_state(struct tegra_clk_device *clk_dev)
0096 {
0097     unsigned long rate;
0098     int ret;
0099 
0100     mutex_lock(&clk_dev->lock);
0101 
0102     rate = clk_hw_get_rate(clk_dev->hw);
0103     ret = tegra_clock_set_pd_state(clk_dev, rate);
0104 
0105     mutex_unlock(&clk_dev->lock);
0106 
0107     return ret;
0108 }
0109 
0110 static int tegra_clock_probe(struct platform_device *pdev)
0111 {
0112     struct tegra_core_opp_params opp_params = {};
0113     struct tegra_clk_device *clk_dev;
0114     struct device *dev = &pdev->dev;
0115     struct clk *clk;
0116     int err;
0117 
0118     if (!dev->pm_domain)
0119         return -EINVAL;
0120 
0121     clk_dev = devm_kzalloc(dev, sizeof(*clk_dev), GFP_KERNEL);
0122     if (!clk_dev)
0123         return -ENOMEM;
0124 
0125     clk = devm_clk_get(dev, NULL);
0126     if (IS_ERR(clk))
0127         return PTR_ERR(clk);
0128 
0129     clk_dev->dev = dev;
0130     clk_dev->hw = __clk_get_hw(clk);
0131     clk_dev->clk_nb.notifier_call = tegra_clock_change_notify;
0132     mutex_init(&clk_dev->lock);
0133 
0134     platform_set_drvdata(pdev, clk_dev);
0135 
0136     /*
0137      * Runtime PM was already enabled for this device by the parent clk
0138      * driver and power domain state should be synced under clk_dev lock,
0139      * hence we don't use the common OPP helper that initializes OPP
0140      * state. For some clocks common OPP helper may fail to find ceil
0141      * rate, it's handled by this driver.
0142      */
0143     err = devm_tegra_core_dev_init_opp_table(dev, &opp_params);
0144     if (err)
0145         return err;
0146 
0147     err = clk_notifier_register(clk, &clk_dev->clk_nb);
0148     if (err) {
0149         dev_err(dev, "failed to register clk notifier: %d\n", err);
0150         return err;
0151     }
0152 
0153     /*
0154      * The driver is attaching to a potentially active/resumed clock, hence
0155      * we need to sync the power domain performance state in a accordance to
0156      * the clock rate if clock is resumed.
0157      */
0158     err = tegra_clock_sync_pd_state(clk_dev);
0159     if (err)
0160         goto unreg_clk;
0161 
0162     return 0;
0163 
0164 unreg_clk:
0165     clk_notifier_unregister(clk, &clk_dev->clk_nb);
0166 
0167     return err;
0168 }
0169 
0170 /*
0171  * Tegra GENPD driver enables clocks during NOIRQ phase. It can't be done
0172  * for clocks served by this driver because runtime PM is unavailable in
0173  * NOIRQ phase. We will keep clocks resumed during suspend to mitigate this
0174  * problem. In practice this makes no difference from a power management
0175  * perspective since voltage is kept at a nominal level during suspend anyways.
0176  */
0177 static const struct dev_pm_ops tegra_clock_pm = {
0178     SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_resume_and_get, pm_runtime_put)
0179 };
0180 
0181 static const struct of_device_id tegra_clock_match[] = {
0182     { .compatible = "nvidia,tegra20-sclk" },
0183     { .compatible = "nvidia,tegra30-sclk" },
0184     { .compatible = "nvidia,tegra30-pllc" },
0185     { .compatible = "nvidia,tegra30-plle" },
0186     { .compatible = "nvidia,tegra30-pllm" },
0187     { }
0188 };
0189 
0190 static struct platform_driver tegra_clock_driver = {
0191     .driver = {
0192         .name = "tegra-clock",
0193         .of_match_table = tegra_clock_match,
0194         .pm = &tegra_clock_pm,
0195         .suppress_bind_attrs = true,
0196     },
0197     .probe = tegra_clock_probe,
0198 };
0199 builtin_platform_driver(tegra_clock_driver);