1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Universal Flash Storage Host controller Platform bus based glue driver
4 * Copyright (C) 2011-2013 Samsung India Software Operations
5 *
6 * Authors:
7 *	Santosh Yaraganavi <santosh.sy@samsung.com>
8 *	Vinayak Holikatti <h.vinayak@samsung.com>
9 */
10
11#include <linux/clk.h>
12#include <linux/module.h>
13#include <linux/platform_device.h>
14#include <linux/pm_opp.h>
15#include <linux/pm_runtime.h>
16#include <linux/of.h>
17
18#include <ufs/ufshcd.h>
19#include "ufshcd-pltfrm.h"
20#include <ufs/unipro.h>
21
22#define UFSHCD_DEFAULT_LANES_PER_DIRECTION		2
23
24static int ufshcd_parse_clock_info(struct ufs_hba *hba)
25{
26	int ret = 0;
27	int cnt;
28	int i;
29	struct device *dev = hba->dev;
30	struct device_node *np = dev->of_node;
31	const char *name;
32	u32 *clkfreq = NULL;
33	struct ufs_clk_info *clki;
34	int len = 0;
35	size_t sz = 0;
36
37	if (!np)
38		goto out;
39
40	cnt = of_property_count_strings(np, "clock-names");
41	if (!cnt || (cnt == -EINVAL)) {
42		dev_info(dev, "%s: Unable to find clocks, assuming enabled\n",
43				__func__);
44	} else if (cnt < 0) {
45		dev_err(dev, "%s: count clock strings failed, err %d\n",
46				__func__, cnt);
47		ret = cnt;
48	}
49
50	if (cnt <= 0)
51		goto out;
52
53	if (!of_get_property(np, "freq-table-hz", &len)) {
54		dev_info(dev, "freq-table-hz property not specified\n");
55		goto out;
56	}
57
58	if (len <= 0)
59		goto out;
60
61	sz = len / sizeof(*clkfreq);
62	if (sz != 2 * cnt) {
63		dev_err(dev, "%s len mismatch\n", "freq-table-hz");
64		ret = -EINVAL;
65		goto out;
66	}
67
68	clkfreq = devm_kcalloc(dev, sz, sizeof(*clkfreq),
69			       GFP_KERNEL);
70	if (!clkfreq) {
71		ret = -ENOMEM;
72		goto out;
73	}
74
75	ret = of_property_read_u32_array(np, "freq-table-hz",
76			clkfreq, sz);
77	if (ret && (ret != -EINVAL)) {
78		dev_err(dev, "%s: error reading array %d\n",
79				"freq-table-hz", ret);
80		return ret;
81	}
82
83	for (i = 0; i < sz; i += 2) {
84		ret = of_property_read_string_index(np,	"clock-names", i/2,
85						    &name);
86		if (ret)
87			goto out;
88
89		clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL);
90		if (!clki) {
91			ret = -ENOMEM;
92			goto out;
93		}
94
95		clki->min_freq = clkfreq[i];
96		clki->max_freq = clkfreq[i+1];
97		clki->name = devm_kstrdup(dev, name, GFP_KERNEL);
98		if (!clki->name) {
99			ret = -ENOMEM;
100			goto out;
101		}
102
103		if (!strcmp(name, "ref_clk"))
104			clki->keep_link_active = true;
105		dev_dbg(dev, "%s: min %u max %u name %s\n", "freq-table-hz",
106				clki->min_freq, clki->max_freq, clki->name);
107		list_add_tail(&clki->list, &hba->clk_list_head);
108	}
109out:
110	return ret;
111}
112
113static bool phandle_exists(const struct device_node *np,
114			   const char *phandle_name, int index)
115{
116	struct device_node *parse_np = of_parse_phandle(np, phandle_name, index);
117
118	if (parse_np)
119		of_node_put(parse_np);
120
121	return parse_np != NULL;
122}
123
124#define MAX_PROP_SIZE 32
125int ufshcd_populate_vreg(struct device *dev, const char *name,
126			 struct ufs_vreg **out_vreg, bool skip_current)
127{
128	char prop_name[MAX_PROP_SIZE];
129	struct ufs_vreg *vreg = NULL;
130	struct device_node *np = dev->of_node;
131
132	if (!np) {
133		dev_err(dev, "%s: non DT initialization\n", __func__);
134		goto out;
135	}
136
137	snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", name);
138	if (!phandle_exists(np, prop_name, 0)) {
139		dev_info(dev, "%s: Unable to find %s regulator, assuming enabled\n",
140				__func__, prop_name);
141		goto out;
142	}
143
144	vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
145	if (!vreg)
146		return -ENOMEM;
147
148	vreg->name = devm_kstrdup(dev, name, GFP_KERNEL);
149	if (!vreg->name)
150		return -ENOMEM;
151
152	if (skip_current) {
153		vreg->max_uA = 0;
154		goto out;
155	}
156
157	snprintf(prop_name, MAX_PROP_SIZE, "%s-max-microamp", name);
158	if (of_property_read_u32(np, prop_name, &vreg->max_uA)) {
159		dev_info(dev, "%s: unable to find %s\n", __func__, prop_name);
160		vreg->max_uA = 0;
161	}
162out:
163	*out_vreg = vreg;
164	return 0;
165}
166EXPORT_SYMBOL_GPL(ufshcd_populate_vreg);
167
168/**
169 * ufshcd_parse_regulator_info - get regulator info from device tree
170 * @hba: per adapter instance
171 *
172 * Get regulator info from device tree for vcc, vccq, vccq2 power supplies.
173 * If any of the supplies are not defined it is assumed that they are always-on
174 * and hence return zero. If the property is defined but parsing is failed
175 * then return corresponding error.
176 *
177 * Return: 0 upon success; < 0 upon failure.
178 */
179static int ufshcd_parse_regulator_info(struct ufs_hba *hba)
180{
181	int err;
182	struct device *dev = hba->dev;
183	struct ufs_vreg_info *info = &hba->vreg_info;
184
185	err = ufshcd_populate_vreg(dev, "vdd-hba", &info->vdd_hba, true);
186	if (err)
187		goto out;
188
189	err = ufshcd_populate_vreg(dev, "vcc", &info->vcc, false);
190	if (err)
191		goto out;
192
193	err = ufshcd_populate_vreg(dev, "vccq", &info->vccq, false);
194	if (err)
195		goto out;
196
197	err = ufshcd_populate_vreg(dev, "vccq2", &info->vccq2, false);
198out:
199	return err;
200}
201
202static void ufshcd_init_lanes_per_dir(struct ufs_hba *hba)
203{
204	struct device *dev = hba->dev;
205	int ret;
206
207	ret = of_property_read_u32(dev->of_node, "lanes-per-direction",
208		&hba->lanes_per_direction);
209	if (ret) {
210		dev_dbg(hba->dev,
211			"%s: failed to read lanes-per-direction, ret=%d\n",
212			__func__, ret);
213		hba->lanes_per_direction = UFSHCD_DEFAULT_LANES_PER_DIRECTION;
214	}
215}
216
217/**
218 * ufshcd_parse_clock_min_max_freq  - Parse MIN and MAX clocks freq
219 * @hba: per adapter instance
220 *
221 * This function parses MIN and MAX frequencies of all clocks required
222 * by the host drivers.
223 *
224 * Returns 0 for success and non-zero for failure
225 */
226static int ufshcd_parse_clock_min_max_freq(struct ufs_hba *hba)
227{
228	struct list_head *head = &hba->clk_list_head;
229	struct ufs_clk_info *clki;
230	struct dev_pm_opp *opp;
231	unsigned long freq;
232	u8 idx = 0;
233
234	list_for_each_entry(clki, head, list) {
235		if (!clki->name)
236			continue;
237
238		clki->clk = devm_clk_get(hba->dev, clki->name);
239		if (IS_ERR(clki->clk))
240			continue;
241
242		/* Find Max Freq */
243		freq = ULONG_MAX;
244		opp = dev_pm_opp_find_freq_floor_indexed(hba->dev, &freq, idx);
245		if (IS_ERR(opp)) {
246			dev_err(hba->dev, "Failed to find OPP for MAX frequency\n");
247			return PTR_ERR(opp);
248		}
249		clki->max_freq = dev_pm_opp_get_freq_indexed(opp, idx);
250		dev_pm_opp_put(opp);
251
252		/* Find Min Freq */
253		freq = 0;
254		opp = dev_pm_opp_find_freq_ceil_indexed(hba->dev, &freq, idx);
255		if (IS_ERR(opp)) {
256			dev_err(hba->dev, "Failed to find OPP for MIN frequency\n");
257			return PTR_ERR(opp);
258		}
259		clki->min_freq = dev_pm_opp_get_freq_indexed(opp, idx++);
260		dev_pm_opp_put(opp);
261	}
262
263	return 0;
264}
265
266static int ufshcd_parse_operating_points(struct ufs_hba *hba)
267{
268	struct device *dev = hba->dev;
269	struct device_node *np = dev->of_node;
270	struct dev_pm_opp_config config = {};
271	struct ufs_clk_info *clki;
272	const char **clk_names;
273	int cnt, i, ret;
274
275	if (!of_find_property(np, "operating-points-v2", NULL))
276		return 0;
277
278	if (of_find_property(np, "freq-table-hz", NULL)) {
279		dev_err(dev, "%s: operating-points and freq-table-hz are incompatible\n",
280			 __func__);
281		return -EINVAL;
282	}
283
284	cnt = of_property_count_strings(np, "clock-names");
285	if (cnt <= 0) {
286		dev_err(dev, "%s: Missing clock-names\n",  __func__);
287		return -ENODEV;
288	}
289
290	/* OPP expects clk_names to be NULL terminated */
291	clk_names = devm_kcalloc(dev, cnt + 1, sizeof(*clk_names), GFP_KERNEL);
292	if (!clk_names)
293		return -ENOMEM;
294
295	/*
296	 * We still need to get reference to all clocks as the UFS core uses
297	 * them separately.
298	 */
299	for (i = 0; i < cnt; i++) {
300		ret = of_property_read_string_index(np, "clock-names", i,
301						    &clk_names[i]);
302		if (ret)
303			return ret;
304
305		clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL);
306		if (!clki)
307			return -ENOMEM;
308
309		clki->name = devm_kstrdup(dev, clk_names[i], GFP_KERNEL);
310		if (!clki->name)
311			return -ENOMEM;
312
313		if (!strcmp(clk_names[i], "ref_clk"))
314			clki->keep_link_active = true;
315
316		list_add_tail(&clki->list, &hba->clk_list_head);
317	}
318
319	config.clk_names = clk_names,
320	config.config_clks = ufshcd_opp_config_clks;
321
322	ret = devm_pm_opp_set_config(dev, &config);
323	if (ret)
324		return ret;
325
326	ret = devm_pm_opp_of_add_table(dev);
327	if (ret) {
328		dev_err(dev, "Failed to add OPP table: %d\n", ret);
329		return ret;
330	}
331
332	ret = ufshcd_parse_clock_min_max_freq(hba);
333	if (ret)
334		return ret;
335
336	hba->use_pm_opp = true;
337
338	return 0;
339}
340
341/**
342 * ufshcd_negotiate_pwr_params - find power mode settings that are supported by
343 *				 both the controller and the device
344 * @host_params: pointer to host parameters
345 * @dev_max: pointer to device attributes
346 * @agreed_pwr: returned agreed attributes
347 *
348 * Return: 0 on success, non-zero value on failure.
349 */
350int ufshcd_negotiate_pwr_params(const struct ufs_host_params *host_params,
351				const struct ufs_pa_layer_attr *dev_max,
352				struct ufs_pa_layer_attr *agreed_pwr)
353{
354	int min_host_gear;
355	int min_dev_gear;
356	bool is_dev_sup_hs = false;
357	bool is_host_max_hs = false;
358
359	if (dev_max->pwr_rx == FAST_MODE)
360		is_dev_sup_hs = true;
361
362	if (host_params->desired_working_mode == UFS_HS_MODE) {
363		is_host_max_hs = true;
364		min_host_gear = min_t(u32, host_params->hs_rx_gear,
365					host_params->hs_tx_gear);
366	} else {
367		min_host_gear = min_t(u32, host_params->pwm_rx_gear,
368					host_params->pwm_tx_gear);
369	}
370
371	/*
372	 * device doesn't support HS but host_params->desired_working_mode is HS,
373	 * thus device and host_params don't agree
374	 */
375	if (!is_dev_sup_hs && is_host_max_hs) {
376		pr_info("%s: device doesn't support HS\n",
377			__func__);
378		return -ENOTSUPP;
379	} else if (is_dev_sup_hs && is_host_max_hs) {
380		/*
381		 * since device supports HS, it supports FAST_MODE.
382		 * since host_params->desired_working_mode is also HS
383		 * then final decision (FAST/FASTAUTO) is done according
384		 * to pltfrm_params as it is the restricting factor
385		 */
386		agreed_pwr->pwr_rx = host_params->rx_pwr_hs;
387		agreed_pwr->pwr_tx = agreed_pwr->pwr_rx;
388	} else {
389		/*
390		 * here host_params->desired_working_mode is PWM.
391		 * it doesn't matter whether device supports HS or PWM,
392		 * in both cases host_params->desired_working_mode will
393		 * determine the mode
394		 */
395		agreed_pwr->pwr_rx = host_params->rx_pwr_pwm;
396		agreed_pwr->pwr_tx = agreed_pwr->pwr_rx;
397	}
398
399	/*
400	 * we would like tx to work in the minimum number of lanes
401	 * between device capability and vendor preferences.
402	 * the same decision will be made for rx
403	 */
404	agreed_pwr->lane_tx = min_t(u32, dev_max->lane_tx,
405				    host_params->tx_lanes);
406	agreed_pwr->lane_rx = min_t(u32, dev_max->lane_rx,
407				    host_params->rx_lanes);
408
409	/* device maximum gear is the minimum between device rx and tx gears */
410	min_dev_gear = min_t(u32, dev_max->gear_rx, dev_max->gear_tx);
411
412	/*
413	 * if both device capabilities and vendor pre-defined preferences are
414	 * both HS or both PWM then set the minimum gear to be the chosen
415	 * working gear.
416	 * if one is PWM and one is HS then the one that is PWM get to decide
417	 * what is the gear, as it is the one that also decided previously what
418	 * pwr the device will be configured to.
419	 */
420	if ((is_dev_sup_hs && is_host_max_hs) ||
421	    (!is_dev_sup_hs && !is_host_max_hs)) {
422		agreed_pwr->gear_rx =
423			min_t(u32, min_dev_gear, min_host_gear);
424	} else if (!is_dev_sup_hs) {
425		agreed_pwr->gear_rx = min_dev_gear;
426	} else {
427		agreed_pwr->gear_rx = min_host_gear;
428	}
429	agreed_pwr->gear_tx = agreed_pwr->gear_rx;
430
431	agreed_pwr->hs_rate = host_params->hs_rate;
432
433	return 0;
434}
435EXPORT_SYMBOL_GPL(ufshcd_negotiate_pwr_params);
436
437void ufshcd_init_host_params(struct ufs_host_params *host_params)
438{
439	*host_params = (struct ufs_host_params){
440		.tx_lanes = UFS_LANE_2,
441		.rx_lanes = UFS_LANE_2,
442		.hs_rx_gear = UFS_HS_G3,
443		.hs_tx_gear = UFS_HS_G3,
444		.pwm_rx_gear = UFS_PWM_G4,
445		.pwm_tx_gear = UFS_PWM_G4,
446		.rx_pwr_pwm = SLOW_MODE,
447		.tx_pwr_pwm = SLOW_MODE,
448		.rx_pwr_hs = FAST_MODE,
449		.tx_pwr_hs = FAST_MODE,
450		.hs_rate = PA_HS_MODE_B,
451		.desired_working_mode = UFS_HS_MODE,
452	};
453}
454EXPORT_SYMBOL_GPL(ufshcd_init_host_params);
455
456/**
457 * ufshcd_pltfrm_init - probe routine of the driver
458 * @pdev: pointer to Platform device handle
459 * @vops: pointer to variant ops
460 *
461 * Return: 0 on success, non-zero value on failure.
462 */
463int ufshcd_pltfrm_init(struct platform_device *pdev,
464		       const struct ufs_hba_variant_ops *vops)
465{
466	struct ufs_hba *hba;
467	void __iomem *mmio_base;
468	int irq, err;
469	struct device *dev = &pdev->dev;
470
471	mmio_base = devm_platform_ioremap_resource(pdev, 0);
472	if (IS_ERR(mmio_base)) {
473		err = PTR_ERR(mmio_base);
474		goto out;
475	}
476
477	irq = platform_get_irq(pdev, 0);
478	if (irq < 0) {
479		err = irq;
480		goto out;
481	}
482
483	err = ufshcd_alloc_host(dev, &hba);
484	if (err) {
485		dev_err(dev, "Allocation failed\n");
486		goto out;
487	}
488
489	hba->vops = vops;
490
491	err = ufshcd_parse_clock_info(hba);
492	if (err) {
493		dev_err(dev, "%s: clock parse failed %d\n",
494				__func__, err);
495		goto dealloc_host;
496	}
497	err = ufshcd_parse_regulator_info(hba);
498	if (err) {
499		dev_err(dev, "%s: regulator init failed %d\n",
500				__func__, err);
501		goto dealloc_host;
502	}
503
504	ufshcd_init_lanes_per_dir(hba);
505
506	err = ufshcd_parse_operating_points(hba);
507	if (err) {
508		dev_err(dev, "%s: OPP parse failed %d\n", __func__, err);
509		goto dealloc_host;
510	}
511
512	err = ufshcd_init(hba, mmio_base, irq);
513	if (err) {
514		dev_err_probe(dev, err, "Initialization failed with error %d\n",
515			      err);
516		goto dealloc_host;
517	}
518
519	pm_runtime_set_active(dev);
520	pm_runtime_enable(dev);
521
522	return 0;
523
524dealloc_host:
525	ufshcd_dealloc_host(hba);
526out:
527	return err;
528}
529EXPORT_SYMBOL_GPL(ufshcd_pltfrm_init);
530
531MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>");
532MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>");
533MODULE_DESCRIPTION("UFS host controller Platform bus based glue driver");
534MODULE_LICENSE("GPL");
535