1*b1bc04a2SDmitry Osipenko // SPDX-License-Identifier: GPL-2.0-only 2*b1bc04a2SDmitry Osipenko 3*b1bc04a2SDmitry Osipenko #include <linux/clk.h> 4*b1bc04a2SDmitry Osipenko #include <linux/clk-provider.h> 5*b1bc04a2SDmitry Osipenko #include <linux/mutex.h> 6*b1bc04a2SDmitry Osipenko #include <linux/of_device.h> 7*b1bc04a2SDmitry Osipenko #include <linux/platform_device.h> 8*b1bc04a2SDmitry Osipenko #include <linux/pm_domain.h> 9*b1bc04a2SDmitry Osipenko #include <linux/pm_opp.h> 10*b1bc04a2SDmitry Osipenko #include <linux/pm_runtime.h> 11*b1bc04a2SDmitry Osipenko #include <linux/slab.h> 12*b1bc04a2SDmitry Osipenko 13*b1bc04a2SDmitry Osipenko #include <soc/tegra/common.h> 14*b1bc04a2SDmitry Osipenko 15*b1bc04a2SDmitry Osipenko #include "clk.h" 16*b1bc04a2SDmitry Osipenko 17*b1bc04a2SDmitry Osipenko /* 18*b1bc04a2SDmitry Osipenko * This driver manages performance state of the core power domain for the 19*b1bc04a2SDmitry Osipenko * independent PLLs and system clocks. We created a virtual clock device 20*b1bc04a2SDmitry Osipenko * for such clocks, see tegra_clk_dev_register(). 21*b1bc04a2SDmitry Osipenko */ 22*b1bc04a2SDmitry Osipenko 23*b1bc04a2SDmitry Osipenko struct tegra_clk_device { 24*b1bc04a2SDmitry Osipenko struct notifier_block clk_nb; 25*b1bc04a2SDmitry Osipenko struct device *dev; 26*b1bc04a2SDmitry Osipenko struct clk_hw *hw; 27*b1bc04a2SDmitry Osipenko struct mutex lock; 28*b1bc04a2SDmitry Osipenko }; 29*b1bc04a2SDmitry Osipenko 30*b1bc04a2SDmitry Osipenko static int tegra_clock_set_pd_state(struct tegra_clk_device *clk_dev, 31*b1bc04a2SDmitry Osipenko unsigned long rate) 32*b1bc04a2SDmitry Osipenko { 33*b1bc04a2SDmitry Osipenko struct device *dev = clk_dev->dev; 34*b1bc04a2SDmitry Osipenko struct dev_pm_opp *opp; 35*b1bc04a2SDmitry Osipenko unsigned int pstate; 36*b1bc04a2SDmitry Osipenko 37*b1bc04a2SDmitry Osipenko opp = dev_pm_opp_find_freq_ceil(dev, &rate); 38*b1bc04a2SDmitry Osipenko if (opp == ERR_PTR(-ERANGE)) { 39*b1bc04a2SDmitry Osipenko /* 40*b1bc04a2SDmitry Osipenko * Some clocks may be unused by a particular board and they 41*b1bc04a2SDmitry Osipenko * may have uninitiated clock rate that is overly high. In 42*b1bc04a2SDmitry Osipenko * this case clock is expected to be disabled, but still we 43*b1bc04a2SDmitry Osipenko * need to set up performance state of the power domain and 44*b1bc04a2SDmitry Osipenko * not error out clk initialization. A typical example is 45*b1bc04a2SDmitry Osipenko * a PCIe clock on Android tablets. 46*b1bc04a2SDmitry Osipenko */ 47*b1bc04a2SDmitry Osipenko dev_dbg(dev, "failed to find ceil OPP for %luHz\n", rate); 48*b1bc04a2SDmitry Osipenko opp = dev_pm_opp_find_freq_floor(dev, &rate); 49*b1bc04a2SDmitry Osipenko } 50*b1bc04a2SDmitry Osipenko 51*b1bc04a2SDmitry Osipenko if (IS_ERR(opp)) { 52*b1bc04a2SDmitry Osipenko dev_err(dev, "failed to find OPP for %luHz: %pe\n", rate, opp); 53*b1bc04a2SDmitry Osipenko return PTR_ERR(opp); 54*b1bc04a2SDmitry Osipenko } 55*b1bc04a2SDmitry Osipenko 56*b1bc04a2SDmitry Osipenko pstate = dev_pm_opp_get_required_pstate(opp, 0); 57*b1bc04a2SDmitry Osipenko dev_pm_opp_put(opp); 58*b1bc04a2SDmitry Osipenko 59*b1bc04a2SDmitry Osipenko return dev_pm_genpd_set_performance_state(dev, pstate); 60*b1bc04a2SDmitry Osipenko } 61*b1bc04a2SDmitry Osipenko 62*b1bc04a2SDmitry Osipenko static int tegra_clock_change_notify(struct notifier_block *nb, 63*b1bc04a2SDmitry Osipenko unsigned long msg, void *data) 64*b1bc04a2SDmitry Osipenko { 65*b1bc04a2SDmitry Osipenko struct clk_notifier_data *cnd = data; 66*b1bc04a2SDmitry Osipenko struct tegra_clk_device *clk_dev; 67*b1bc04a2SDmitry Osipenko int err = 0; 68*b1bc04a2SDmitry Osipenko 69*b1bc04a2SDmitry Osipenko clk_dev = container_of(nb, struct tegra_clk_device, clk_nb); 70*b1bc04a2SDmitry Osipenko 71*b1bc04a2SDmitry Osipenko mutex_lock(&clk_dev->lock); 72*b1bc04a2SDmitry Osipenko switch (msg) { 73*b1bc04a2SDmitry Osipenko case PRE_RATE_CHANGE: 74*b1bc04a2SDmitry Osipenko if (cnd->new_rate > cnd->old_rate) 75*b1bc04a2SDmitry Osipenko err = tegra_clock_set_pd_state(clk_dev, cnd->new_rate); 76*b1bc04a2SDmitry Osipenko break; 77*b1bc04a2SDmitry Osipenko 78*b1bc04a2SDmitry Osipenko case ABORT_RATE_CHANGE: 79*b1bc04a2SDmitry Osipenko err = tegra_clock_set_pd_state(clk_dev, cnd->old_rate); 80*b1bc04a2SDmitry Osipenko break; 81*b1bc04a2SDmitry Osipenko 82*b1bc04a2SDmitry Osipenko case POST_RATE_CHANGE: 83*b1bc04a2SDmitry Osipenko if (cnd->new_rate < cnd->old_rate) 84*b1bc04a2SDmitry Osipenko err = tegra_clock_set_pd_state(clk_dev, cnd->new_rate); 85*b1bc04a2SDmitry Osipenko break; 86*b1bc04a2SDmitry Osipenko 87*b1bc04a2SDmitry Osipenko default: 88*b1bc04a2SDmitry Osipenko break; 89*b1bc04a2SDmitry Osipenko } 90*b1bc04a2SDmitry Osipenko mutex_unlock(&clk_dev->lock); 91*b1bc04a2SDmitry Osipenko 92*b1bc04a2SDmitry Osipenko return notifier_from_errno(err); 93*b1bc04a2SDmitry Osipenko } 94*b1bc04a2SDmitry Osipenko 95*b1bc04a2SDmitry Osipenko static int tegra_clock_sync_pd_state(struct tegra_clk_device *clk_dev) 96*b1bc04a2SDmitry Osipenko { 97*b1bc04a2SDmitry Osipenko unsigned long rate; 98*b1bc04a2SDmitry Osipenko int ret; 99*b1bc04a2SDmitry Osipenko 100*b1bc04a2SDmitry Osipenko mutex_lock(&clk_dev->lock); 101*b1bc04a2SDmitry Osipenko 102*b1bc04a2SDmitry Osipenko rate = clk_hw_get_rate(clk_dev->hw); 103*b1bc04a2SDmitry Osipenko ret = tegra_clock_set_pd_state(clk_dev, rate); 104*b1bc04a2SDmitry Osipenko 105*b1bc04a2SDmitry Osipenko mutex_unlock(&clk_dev->lock); 106*b1bc04a2SDmitry Osipenko 107*b1bc04a2SDmitry Osipenko return ret; 108*b1bc04a2SDmitry Osipenko } 109*b1bc04a2SDmitry Osipenko 110*b1bc04a2SDmitry Osipenko static int tegra_clock_probe(struct platform_device *pdev) 111*b1bc04a2SDmitry Osipenko { 112*b1bc04a2SDmitry Osipenko struct tegra_core_opp_params opp_params = {}; 113*b1bc04a2SDmitry Osipenko struct tegra_clk_device *clk_dev; 114*b1bc04a2SDmitry Osipenko struct device *dev = &pdev->dev; 115*b1bc04a2SDmitry Osipenko struct clk *clk; 116*b1bc04a2SDmitry Osipenko int err; 117*b1bc04a2SDmitry Osipenko 118*b1bc04a2SDmitry Osipenko if (!dev->pm_domain) 119*b1bc04a2SDmitry Osipenko return -EINVAL; 120*b1bc04a2SDmitry Osipenko 121*b1bc04a2SDmitry Osipenko clk_dev = devm_kzalloc(dev, sizeof(*clk_dev), GFP_KERNEL); 122*b1bc04a2SDmitry Osipenko if (!clk_dev) 123*b1bc04a2SDmitry Osipenko return -ENOMEM; 124*b1bc04a2SDmitry Osipenko 125*b1bc04a2SDmitry Osipenko clk = devm_clk_get(dev, NULL); 126*b1bc04a2SDmitry Osipenko if (IS_ERR(clk)) 127*b1bc04a2SDmitry Osipenko return PTR_ERR(clk); 128*b1bc04a2SDmitry Osipenko 129*b1bc04a2SDmitry Osipenko clk_dev->dev = dev; 130*b1bc04a2SDmitry Osipenko clk_dev->hw = __clk_get_hw(clk); 131*b1bc04a2SDmitry Osipenko clk_dev->clk_nb.notifier_call = tegra_clock_change_notify; 132*b1bc04a2SDmitry Osipenko mutex_init(&clk_dev->lock); 133*b1bc04a2SDmitry Osipenko 134*b1bc04a2SDmitry Osipenko platform_set_drvdata(pdev, clk_dev); 135*b1bc04a2SDmitry Osipenko 136*b1bc04a2SDmitry Osipenko /* 137*b1bc04a2SDmitry Osipenko * Runtime PM was already enabled for this device by the parent clk 138*b1bc04a2SDmitry Osipenko * driver and power domain state should be synced under clk_dev lock, 139*b1bc04a2SDmitry Osipenko * hence we don't use the common OPP helper that initializes OPP 140*b1bc04a2SDmitry Osipenko * state. For some clocks common OPP helper may fail to find ceil 141*b1bc04a2SDmitry Osipenko * rate, it's handled by this driver. 142*b1bc04a2SDmitry Osipenko */ 143*b1bc04a2SDmitry Osipenko err = devm_tegra_core_dev_init_opp_table(dev, &opp_params); 144*b1bc04a2SDmitry Osipenko if (err) 145*b1bc04a2SDmitry Osipenko return err; 146*b1bc04a2SDmitry Osipenko 147*b1bc04a2SDmitry Osipenko err = clk_notifier_register(clk, &clk_dev->clk_nb); 148*b1bc04a2SDmitry Osipenko if (err) { 149*b1bc04a2SDmitry Osipenko dev_err(dev, "failed to register clk notifier: %d\n", err); 150*b1bc04a2SDmitry Osipenko return err; 151*b1bc04a2SDmitry Osipenko } 152*b1bc04a2SDmitry Osipenko 153*b1bc04a2SDmitry Osipenko /* 154*b1bc04a2SDmitry Osipenko * The driver is attaching to a potentially active/resumed clock, hence 155*b1bc04a2SDmitry Osipenko * we need to sync the power domain performance state in a accordance to 156*b1bc04a2SDmitry Osipenko * the clock rate if clock is resumed. 157*b1bc04a2SDmitry Osipenko */ 158*b1bc04a2SDmitry Osipenko err = tegra_clock_sync_pd_state(clk_dev); 159*b1bc04a2SDmitry Osipenko if (err) 160*b1bc04a2SDmitry Osipenko goto unreg_clk; 161*b1bc04a2SDmitry Osipenko 162*b1bc04a2SDmitry Osipenko return 0; 163*b1bc04a2SDmitry Osipenko 164*b1bc04a2SDmitry Osipenko unreg_clk: 165*b1bc04a2SDmitry Osipenko clk_notifier_unregister(clk, &clk_dev->clk_nb); 166*b1bc04a2SDmitry Osipenko 167*b1bc04a2SDmitry Osipenko return err; 168*b1bc04a2SDmitry Osipenko } 169*b1bc04a2SDmitry Osipenko 170*b1bc04a2SDmitry Osipenko /* 171*b1bc04a2SDmitry Osipenko * Tegra GENPD driver enables clocks during NOIRQ phase. It can't be done 172*b1bc04a2SDmitry Osipenko * for clocks served by this driver because runtime PM is unavailable in 173*b1bc04a2SDmitry Osipenko * NOIRQ phase. We will keep clocks resumed during suspend to mitigate this 174*b1bc04a2SDmitry Osipenko * problem. In practice this makes no difference from a power management 175*b1bc04a2SDmitry Osipenko * perspective since voltage is kept at a nominal level during suspend anyways. 176*b1bc04a2SDmitry Osipenko */ 177*b1bc04a2SDmitry Osipenko static const struct dev_pm_ops tegra_clock_pm = { 178*b1bc04a2SDmitry Osipenko SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_resume_and_get, pm_runtime_put) 179*b1bc04a2SDmitry Osipenko }; 180*b1bc04a2SDmitry Osipenko 181*b1bc04a2SDmitry Osipenko static const struct of_device_id tegra_clock_match[] = { 182*b1bc04a2SDmitry Osipenko { .compatible = "nvidia,tegra20-sclk" }, 183*b1bc04a2SDmitry Osipenko { .compatible = "nvidia,tegra30-sclk" }, 184*b1bc04a2SDmitry Osipenko { .compatible = "nvidia,tegra30-pllc" }, 185*b1bc04a2SDmitry Osipenko { .compatible = "nvidia,tegra30-plle" }, 186*b1bc04a2SDmitry Osipenko { .compatible = "nvidia,tegra30-pllm" }, 187*b1bc04a2SDmitry Osipenko { } 188*b1bc04a2SDmitry Osipenko }; 189*b1bc04a2SDmitry Osipenko 190*b1bc04a2SDmitry Osipenko static struct platform_driver tegra_clock_driver = { 191*b1bc04a2SDmitry Osipenko .driver = { 192*b1bc04a2SDmitry Osipenko .name = "tegra-clock", 193*b1bc04a2SDmitry Osipenko .of_match_table = tegra_clock_match, 194*b1bc04a2SDmitry Osipenko .pm = &tegra_clock_pm, 195*b1bc04a2SDmitry Osipenko .suppress_bind_attrs = true, 196*b1bc04a2SDmitry Osipenko }, 197*b1bc04a2SDmitry Osipenko .probe = tegra_clock_probe, 198*b1bc04a2SDmitry Osipenko }; 199*b1bc04a2SDmitry Osipenko builtin_platform_driver(tegra_clock_driver); 200