^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * CPU frequency scaling for DaVinci
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2009 Texas Instruments Incorporated - https://www.ti.com/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Based on linux/arch/arm/plat-omap/cpu-omap.c. Original Copyright follows:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Copyright (C) 2005 Nokia Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Written by Tony Lindgren <tony@atomide.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * Copyright (C) 2007-2008 Texas Instruments, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * Updated to support OMAP3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * Rajendra Nayak <rnayak@ti.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/cpufreq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/platform_data/davinci-cpufreq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct davinci_cpufreq {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct clk *armclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct clk *asyncclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) unsigned long asyncrate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) static struct davinci_cpufreq cpufreq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) static int davinci_target(struct cpufreq_policy *policy, unsigned int idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct davinci_cpufreq_config *pdata = cpufreq.dev->platform_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct clk *armclk = cpufreq.armclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) unsigned int old_freq, new_freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) old_freq = policy->cur;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) new_freq = pdata->freq_table[idx].frequency;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /* if moving to higher frequency, up the voltage beforehand */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) if (pdata->set_voltage && new_freq > old_freq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) ret = pdata->set_voltage(idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) ret = clk_set_rate(armclk, new_freq * 1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) if (cpufreq.asyncclk) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) ret = clk_set_rate(cpufreq.asyncclk, cpufreq.asyncrate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /* if moving to lower freq, lower the voltage after lowering freq */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) if (pdata->set_voltage && new_freq < old_freq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) pdata->set_voltage(idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) static int davinci_cpu_init(struct cpufreq_policy *policy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) int result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct davinci_cpufreq_config *pdata = cpufreq.dev->platform_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct cpufreq_frequency_table *freq_table = pdata->freq_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) if (policy->cpu != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) /* Finish platform specific initialization */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (pdata->init) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) result = pdata->init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) policy->clk = cpufreq.armclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * Time measurement across the target() function yields ~1500-1800us
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) * time taken with no drivers on notification list.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) * Setting the latency to 2000 us to accommodate addition of drivers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * to pre/post change notification list.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) cpufreq_generic_init(policy, freq_table, 2000 * 1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) static struct cpufreq_driver davinci_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) .verify = cpufreq_generic_frequency_table_verify,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) .target_index = davinci_target,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) .get = cpufreq_generic_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) .init = davinci_cpu_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) .name = "davinci",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) .attr = cpufreq_generic_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) static int __init davinci_cpufreq_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) struct davinci_cpufreq_config *pdata = pdev->dev.platform_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct clk *asyncclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) if (!pdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) if (!pdata->freq_table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) cpufreq.dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) cpufreq.armclk = clk_get(NULL, "arm");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (IS_ERR(cpufreq.armclk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) dev_err(cpufreq.dev, "Unable to get ARM clock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) return PTR_ERR(cpufreq.armclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) asyncclk = clk_get(cpufreq.dev, "async");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (!IS_ERR(asyncclk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) cpufreq.asyncclk = asyncclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) cpufreq.asyncrate = clk_get_rate(asyncclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) return cpufreq_register_driver(&davinci_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) static int __exit davinci_cpufreq_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) clk_put(cpufreq.armclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (cpufreq.asyncclk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) clk_put(cpufreq.asyncclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) return cpufreq_unregister_driver(&davinci_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) static struct platform_driver davinci_cpufreq_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) .name = "cpufreq-davinci",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) .remove = __exit_p(davinci_cpufreq_remove),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) int __init davinci_cpufreq_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) return platform_driver_probe(&davinci_cpufreq_driver,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) davinci_cpufreq_probe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)