brintos

brintos / linux-shallow public Read only

0
0
Text · 14.3 KiB · c20d3ec Raw
533 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2013 Freescale Semiconductor, Inc.4 */5 6#include <linux/clk.h>7#include <linux/cpu.h>8#include <linux/cpufreq.h>9#include <linux/err.h>10#include <linux/module.h>11#include <linux/nvmem-consumer.h>12#include <linux/of.h>13#include <linux/of_address.h>14#include <linux/pm_opp.h>15#include <linux/platform_device.h>16#include <linux/regulator/consumer.h>17#include <linux/mfd/syscon.h>18#include <linux/regmap.h>19 20#define PU_SOC_VOLTAGE_NORMAL	125000021#define PU_SOC_VOLTAGE_HIGH	127500022#define FREQ_1P2_GHZ		120000000023 24static struct regulator *arm_reg;25static struct regulator *pu_reg;26static struct regulator *soc_reg;27 28enum IMX6_CPUFREQ_CLKS {29	ARM,30	PLL1_SYS,31	STEP,32	PLL1_SW,33	PLL2_PFD2_396M,34	/* MX6UL requires two more clks */35	PLL2_BUS,36	SECONDARY_SEL,37};38#define IMX6Q_CPUFREQ_CLK_NUM		539#define IMX6UL_CPUFREQ_CLK_NUM		740 41static int num_clks;42static struct clk_bulk_data clks[] = {43	{ .id = "arm" },44	{ .id = "pll1_sys" },45	{ .id = "step" },46	{ .id = "pll1_sw" },47	{ .id = "pll2_pfd2_396m" },48	{ .id = "pll2_bus" },49	{ .id = "secondary_sel" },50};51 52static struct device *cpu_dev;53static struct cpufreq_frequency_table *freq_table;54static unsigned int max_freq;55static unsigned int transition_latency;56 57static u32 *imx6_soc_volt;58static u32 soc_opp_count;59 60static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)61{62	struct dev_pm_opp *opp;63	unsigned long freq_hz, volt, volt_old;64	unsigned int old_freq, new_freq;65	bool pll1_sys_temp_enabled = false;66	int ret;67 68	new_freq = freq_table[index].frequency;69	freq_hz = new_freq * 1000;70	old_freq = clk_get_rate(clks[ARM].clk) / 1000;71 72	opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);73	if (IS_ERR(opp)) {74		dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz);75		return PTR_ERR(opp);76	}77 78	volt = dev_pm_opp_get_voltage(opp);79	dev_pm_opp_put(opp);80 81	volt_old = regulator_get_voltage(arm_reg);82 83	dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",84		old_freq / 1000, volt_old / 1000,85		new_freq / 1000, volt / 1000);86 87	/* scaling up?  scale voltage before frequency */88	if (new_freq > old_freq) {89		if (!IS_ERR(pu_reg)) {90			ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0);91			if (ret) {92				dev_err(cpu_dev, "failed to scale vddpu up: %d\n", ret);93				return ret;94			}95		}96		ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0);97		if (ret) {98			dev_err(cpu_dev, "failed to scale vddsoc up: %d\n", ret);99			return ret;100		}101		ret = regulator_set_voltage_tol(arm_reg, volt, 0);102		if (ret) {103			dev_err(cpu_dev,104				"failed to scale vddarm up: %d\n", ret);105			return ret;106		}107	}108 109	/*110	 * The setpoints are selected per PLL/PDF frequencies, so we need to111	 * reprogram PLL for frequency scaling.  The procedure of reprogramming112	 * PLL1 is as below.113	 * For i.MX6UL, it has a secondary clk mux, the cpu frequency change114	 * flow is slightly different from other i.MX6 OSC.115	 * The cpu frequeny change flow for i.MX6(except i.MX6UL) is as below:116	 *  - Enable pll2_pfd2_396m_clk and reparent pll1_sw_clk to it117	 *  - Reprogram pll1_sys_clk and reparent pll1_sw_clk back to it118	 *  - Disable pll2_pfd2_396m_clk119	 */120	if (of_machine_is_compatible("fsl,imx6ul") ||121	    of_machine_is_compatible("fsl,imx6ull")) {122		/*123		 * When changing pll1_sw_clk's parent to pll1_sys_clk,124		 * CPU may run at higher than 528MHz, this will lead to125		 * the system unstable if the voltage is lower than the126		 * voltage of 528MHz, so lower the CPU frequency to one127		 * half before changing CPU frequency.128		 */129		clk_set_rate(clks[ARM].clk, (old_freq >> 1) * 1000);130		clk_set_parent(clks[PLL1_SW].clk, clks[PLL1_SYS].clk);131		if (freq_hz > clk_get_rate(clks[PLL2_PFD2_396M].clk))132			clk_set_parent(clks[SECONDARY_SEL].clk,133				       clks[PLL2_BUS].clk);134		else135			clk_set_parent(clks[SECONDARY_SEL].clk,136				       clks[PLL2_PFD2_396M].clk);137		clk_set_parent(clks[STEP].clk, clks[SECONDARY_SEL].clk);138		clk_set_parent(clks[PLL1_SW].clk, clks[STEP].clk);139		if (freq_hz > clk_get_rate(clks[PLL2_BUS].clk)) {140			clk_set_rate(clks[PLL1_SYS].clk, new_freq * 1000);141			clk_set_parent(clks[PLL1_SW].clk, clks[PLL1_SYS].clk);142		}143	} else {144		clk_set_parent(clks[STEP].clk, clks[PLL2_PFD2_396M].clk);145		clk_set_parent(clks[PLL1_SW].clk, clks[STEP].clk);146		if (freq_hz > clk_get_rate(clks[PLL2_PFD2_396M].clk)) {147			clk_set_rate(clks[PLL1_SYS].clk, new_freq * 1000);148			clk_set_parent(clks[PLL1_SW].clk, clks[PLL1_SYS].clk);149		} else {150			/* pll1_sys needs to be enabled for divider rate change to work. */151			pll1_sys_temp_enabled = true;152			clk_prepare_enable(clks[PLL1_SYS].clk);153		}154	}155 156	/* Ensure the arm clock divider is what we expect */157	ret = clk_set_rate(clks[ARM].clk, new_freq * 1000);158	if (ret) {159		int ret1;160 161		dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);162		ret1 = regulator_set_voltage_tol(arm_reg, volt_old, 0);163		if (ret1)164			dev_warn(cpu_dev,165				 "failed to restore vddarm voltage: %d\n", ret1);166		return ret;167	}168 169	/* PLL1 is only needed until after ARM-PODF is set. */170	if (pll1_sys_temp_enabled)171		clk_disable_unprepare(clks[PLL1_SYS].clk);172 173	/* scaling down?  scale voltage after frequency */174	if (new_freq < old_freq) {175		ret = regulator_set_voltage_tol(arm_reg, volt, 0);176		if (ret)177			dev_warn(cpu_dev,178				 "failed to scale vddarm down: %d\n", ret);179		ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0);180		if (ret)181			dev_warn(cpu_dev, "failed to scale vddsoc down: %d\n", ret);182		if (!IS_ERR(pu_reg)) {183			ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0);184			if (ret)185				dev_warn(cpu_dev, "failed to scale vddpu down: %d\n", ret);186		}187	}188 189	return 0;190}191 192static int imx6q_cpufreq_init(struct cpufreq_policy *policy)193{194	policy->clk = clks[ARM].clk;195	cpufreq_generic_init(policy, freq_table, transition_latency);196	policy->suspend_freq = max_freq;197 198	return 0;199}200 201static struct cpufreq_driver imx6q_cpufreq_driver = {202	.flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK |203		 CPUFREQ_IS_COOLING_DEV,204	.verify = cpufreq_generic_frequency_table_verify,205	.target_index = imx6q_set_target,206	.get = cpufreq_generic_get,207	.init = imx6q_cpufreq_init,208	.register_em = cpufreq_register_em_with_opp,209	.name = "imx6q-cpufreq",210	.attr = cpufreq_generic_attr,211	.suspend = cpufreq_generic_suspend,212};213 214static void imx6x_disable_freq_in_opp(struct device *dev, unsigned long freq)215{216	int ret = dev_pm_opp_disable(dev, freq);217 218	if (ret < 0 && ret != -ENODEV)219		dev_warn(dev, "failed to disable %ldMHz OPP\n", freq / 1000000);220}221 222#define OCOTP_CFG3			0x440223#define OCOTP_CFG3_SPEED_SHIFT		16224#define OCOTP_CFG3_SPEED_1P2GHZ		0x3225#define OCOTP_CFG3_SPEED_996MHZ		0x2226#define OCOTP_CFG3_SPEED_852MHZ		0x1227 228static int imx6q_opp_check_speed_grading(struct device *dev)229{230	u32 val;231	int ret;232 233	if (of_property_present(dev->of_node, "nvmem-cells")) {234		ret = nvmem_cell_read_u32(dev, "speed_grade", &val);235		if (ret)236			return ret;237	} else {238		struct regmap *ocotp;239 240		ocotp = syscon_regmap_lookup_by_compatible("fsl,imx6q-ocotp");241		if (IS_ERR(ocotp))242			return -ENOENT;243 244		/*245		 * SPEED_GRADING[1:0] defines the max speed of ARM:246		 * 2b'11: 1200000000Hz;247		 * 2b'10: 996000000Hz;248		 * 2b'01: 852000000Hz; -- i.MX6Q Only, exclusive with 996MHz.249		 * 2b'00: 792000000Hz;250		 * We need to set the max speed of ARM according to fuse map.251		 */252		regmap_read(ocotp, OCOTP_CFG3, &val);253	}254 255	val >>= OCOTP_CFG3_SPEED_SHIFT;256	val &= 0x3;257 258	if (val < OCOTP_CFG3_SPEED_996MHZ)259		imx6x_disable_freq_in_opp(dev, 996000000);260 261	if (of_machine_is_compatible("fsl,imx6q") ||262	    of_machine_is_compatible("fsl,imx6qp")) {263		if (val != OCOTP_CFG3_SPEED_852MHZ)264			imx6x_disable_freq_in_opp(dev, 852000000);265 266		if (val != OCOTP_CFG3_SPEED_1P2GHZ)267			imx6x_disable_freq_in_opp(dev, 1200000000);268	}269 270	return 0;271}272 273#define OCOTP_CFG3_6UL_SPEED_696MHZ	0x2274#define OCOTP_CFG3_6ULL_SPEED_792MHZ	0x2275#define OCOTP_CFG3_6ULL_SPEED_900MHZ	0x3276 277static int imx6ul_opp_check_speed_grading(struct device *dev)278{279	u32 val;280	int ret = 0;281 282	if (of_property_present(dev->of_node, "nvmem-cells")) {283		ret = nvmem_cell_read_u32(dev, "speed_grade", &val);284		if (ret)285			return ret;286	} else {287		struct regmap *ocotp;288 289		ocotp = syscon_regmap_lookup_by_compatible("fsl,imx6ul-ocotp");290		if (IS_ERR(ocotp))291			ocotp = syscon_regmap_lookup_by_compatible("fsl,imx6ull-ocotp");292 293		if (IS_ERR(ocotp))294			return -ENOENT;295 296		regmap_read(ocotp, OCOTP_CFG3, &val);297	}298 299	/*300	 * Speed GRADING[1:0] defines the max speed of ARM:301	 * 2b'00: Reserved;302	 * 2b'01: 528000000Hz;303	 * 2b'10: 696000000Hz on i.MX6UL, 792000000Hz on i.MX6ULL;304	 * 2b'11: 900000000Hz on i.MX6ULL only;305	 * We need to set the max speed of ARM according to fuse map.306	 */307	val >>= OCOTP_CFG3_SPEED_SHIFT;308	val &= 0x3;309 310	if (of_machine_is_compatible("fsl,imx6ul"))311		if (val != OCOTP_CFG3_6UL_SPEED_696MHZ)312			imx6x_disable_freq_in_opp(dev, 696000000);313 314	if (of_machine_is_compatible("fsl,imx6ull")) {315		if (val < OCOTP_CFG3_6ULL_SPEED_792MHZ)316			imx6x_disable_freq_in_opp(dev, 792000000);317 318		if (val != OCOTP_CFG3_6ULL_SPEED_900MHZ)319			imx6x_disable_freq_in_opp(dev, 900000000);320	}321 322	return ret;323}324 325static int imx6q_cpufreq_probe(struct platform_device *pdev)326{327	struct device_node *np;328	struct dev_pm_opp *opp;329	unsigned long min_volt, max_volt;330	int num, ret;331	const struct property *prop;332	const __be32 *val;333	u32 nr, i, j;334 335	cpu_dev = get_cpu_device(0);336	if (!cpu_dev) {337		pr_err("failed to get cpu0 device\n");338		return -ENODEV;339	}340 341	np = of_node_get(cpu_dev->of_node);342	if (!np) {343		dev_err(cpu_dev, "failed to find cpu0 node\n");344		return -ENOENT;345	}346 347	if (of_machine_is_compatible("fsl,imx6ul") ||348	    of_machine_is_compatible("fsl,imx6ull"))349		num_clks = IMX6UL_CPUFREQ_CLK_NUM;350	else351		num_clks = IMX6Q_CPUFREQ_CLK_NUM;352 353	ret = clk_bulk_get(cpu_dev, num_clks, clks);354	if (ret)355		goto put_node;356 357	arm_reg = regulator_get(cpu_dev, "arm");358	pu_reg = regulator_get_optional(cpu_dev, "pu");359	soc_reg = regulator_get(cpu_dev, "soc");360	if (PTR_ERR(arm_reg) == -EPROBE_DEFER ||361			PTR_ERR(soc_reg) == -EPROBE_DEFER ||362			PTR_ERR(pu_reg) == -EPROBE_DEFER) {363		ret = -EPROBE_DEFER;364		dev_dbg(cpu_dev, "regulators not ready, defer\n");365		goto put_reg;366	}367	if (IS_ERR(arm_reg) || IS_ERR(soc_reg)) {368		dev_err(cpu_dev, "failed to get regulators\n");369		ret = -ENOENT;370		goto put_reg;371	}372 373	ret = dev_pm_opp_of_add_table(cpu_dev);374	if (ret < 0) {375		dev_err(cpu_dev, "failed to init OPP table: %d\n", ret);376		goto put_reg;377	}378 379	if (of_machine_is_compatible("fsl,imx6ul") ||380	    of_machine_is_compatible("fsl,imx6ull")) {381		ret = imx6ul_opp_check_speed_grading(cpu_dev);382	} else {383		ret = imx6q_opp_check_speed_grading(cpu_dev);384	}385	if (ret) {386		dev_err_probe(cpu_dev, ret, "failed to read ocotp\n");387		goto out_free_opp;388	}389 390	num = dev_pm_opp_get_opp_count(cpu_dev);391	if (num < 0) {392		ret = num;393		dev_err(cpu_dev, "no OPP table is found: %d\n", ret);394		goto out_free_opp;395	}396 397	ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);398	if (ret) {399		dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);400		goto out_free_opp;401	}402 403	/* Make imx6_soc_volt array's size same as arm opp number */404	imx6_soc_volt = devm_kcalloc(cpu_dev, num, sizeof(*imx6_soc_volt),405				     GFP_KERNEL);406	if (imx6_soc_volt == NULL) {407		ret = -ENOMEM;408		goto free_freq_table;409	}410 411	prop = of_find_property(np, "fsl,soc-operating-points", NULL);412	if (!prop || !prop->value)413		goto soc_opp_out;414 415	/*416	 * Each OPP is a set of tuples consisting of frequency and417	 * voltage like <freq-kHz vol-uV>.418	 */419	nr = prop->length / sizeof(u32);420	if (nr % 2 || (nr / 2) < num)421		goto soc_opp_out;422 423	for (j = 0; j < num; j++) {424		val = prop->value;425		for (i = 0; i < nr / 2; i++) {426			unsigned long freq = be32_to_cpup(val++);427			unsigned long volt = be32_to_cpup(val++);428			if (freq_table[j].frequency == freq) {429				imx6_soc_volt[soc_opp_count++] = volt;430				break;431			}432		}433	}434 435soc_opp_out:436	/* use fixed soc opp volt if no valid soc opp info found in dtb */437	if (soc_opp_count != num) {438		dev_warn(cpu_dev, "can NOT find valid fsl,soc-operating-points property in dtb, use default value!\n");439		for (j = 0; j < num; j++)440			imx6_soc_volt[j] = PU_SOC_VOLTAGE_NORMAL;441		if (freq_table[num - 1].frequency * 1000 == FREQ_1P2_GHZ)442			imx6_soc_volt[num - 1] = PU_SOC_VOLTAGE_HIGH;443	}444 445	if (of_property_read_u32(np, "clock-latency", &transition_latency))446		transition_latency = CPUFREQ_ETERNAL;447 448	/*449	 * Calculate the ramp time for max voltage change in the450	 * VDDSOC and VDDPU regulators.451	 */452	ret = regulator_set_voltage_time(soc_reg, imx6_soc_volt[0], imx6_soc_volt[num - 1]);453	if (ret > 0)454		transition_latency += ret * 1000;455	if (!IS_ERR(pu_reg)) {456		ret = regulator_set_voltage_time(pu_reg, imx6_soc_volt[0], imx6_soc_volt[num - 1]);457		if (ret > 0)458			transition_latency += ret * 1000;459	}460 461	/*462	 * OPP is maintained in order of increasing frequency, and463	 * freq_table initialised from OPP is therefore sorted in the464	 * same order.465	 */466	max_freq = freq_table[--num].frequency;467	opp = dev_pm_opp_find_freq_exact(cpu_dev,468				  freq_table[0].frequency * 1000, true);469	min_volt = dev_pm_opp_get_voltage(opp);470	dev_pm_opp_put(opp);471	opp = dev_pm_opp_find_freq_exact(cpu_dev, max_freq * 1000, true);472	max_volt = dev_pm_opp_get_voltage(opp);473	dev_pm_opp_put(opp);474 475	ret = regulator_set_voltage_time(arm_reg, min_volt, max_volt);476	if (ret > 0)477		transition_latency += ret * 1000;478 479	ret = cpufreq_register_driver(&imx6q_cpufreq_driver);480	if (ret) {481		dev_err(cpu_dev, "failed register driver: %d\n", ret);482		goto free_freq_table;483	}484 485	of_node_put(np);486	return 0;487 488free_freq_table:489	dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);490out_free_opp:491	dev_pm_opp_of_remove_table(cpu_dev);492put_reg:493	if (!IS_ERR(arm_reg))494		regulator_put(arm_reg);495	if (!IS_ERR(pu_reg))496		regulator_put(pu_reg);497	if (!IS_ERR(soc_reg))498		regulator_put(soc_reg);499 500	clk_bulk_put(num_clks, clks);501put_node:502	of_node_put(np);503 504	return ret;505}506 507static void imx6q_cpufreq_remove(struct platform_device *pdev)508{509	cpufreq_unregister_driver(&imx6q_cpufreq_driver);510	dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);511	dev_pm_opp_of_remove_table(cpu_dev);512	regulator_put(arm_reg);513	if (!IS_ERR(pu_reg))514		regulator_put(pu_reg);515	regulator_put(soc_reg);516 517	clk_bulk_put(num_clks, clks);518}519 520static struct platform_driver imx6q_cpufreq_platdrv = {521	.driver = {522		.name	= "imx6q-cpufreq",523	},524	.probe		= imx6q_cpufreq_probe,525	.remove_new	= imx6q_cpufreq_remove,526};527module_platform_driver(imx6q_cpufreq_platdrv);528 529MODULE_ALIAS("platform:imx6q-cpufreq");530MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");531MODULE_DESCRIPTION("Freescale i.MX6Q cpufreq driver");532MODULE_LICENSE("GPL");533