1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2015-2016 Socionext Inc.
4 *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
5 */
6
7#include <common.h>
8#include <dm.h>
9#include <dm/device_compat.h>
10#include <linux/bitops.h>
11#include <linux/bug.h>
12#include <linux/io.h>
13#include <linux/err.h>
14#include <linux/kernel.h>
15#include <linux/sizes.h>
16#include <dm/pinctrl.h>
17
18#include "pinctrl-uniphier.h"
19
20#define UNIPHIER_PINCTRL_PINMUX_BASE	0x1000
21#define UNIPHIER_PINCTRL_LOAD_PINMUX	0x1700
22#define UNIPHIER_PINCTRL_DRVCTRL_BASE	0x1800
23#define UNIPHIER_PINCTRL_DRV2CTRL_BASE	0x1900
24#define UNIPHIER_PINCTRL_DRV3CTRL_BASE	0x1980
25#define UNIPHIER_PINCTRL_PUPDCTRL_BASE	0x1a00
26#define UNIPHIER_PINCTRL_IECTRL		0x1d00
27
28static const char *uniphier_pinctrl_dummy_name = "_dummy";
29
30static int uniphier_pinctrl_get_pins_count(struct udevice *dev)
31{
32	struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
33	const struct uniphier_pinctrl_pin *pins = priv->socdata->pins;
34	int pins_count = priv->socdata->pins_count;
35
36	if (WARN_ON(!pins_count))
37		return 0; /* no table of pins */
38
39	/*
40	 * We do not list all pins in the pin table to save memory footprint.
41	 * Report the max pin number + 1 to fake the framework.
42	 */
43	return pins[pins_count - 1].number + 1;
44}
45
46static const char *uniphier_pinctrl_get_pin_name(struct udevice *dev,
47						 unsigned int selector)
48{
49	struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
50	const struct uniphier_pinctrl_pin *pins = priv->socdata->pins;
51	int pins_count = priv->socdata->pins_count;
52	int i;
53
54	for (i = 0; i < pins_count; i++)
55		if (pins[i].number == selector)
56			return pins[i].name;
57
58	return uniphier_pinctrl_dummy_name;
59}
60
61static int uniphier_pinctrl_get_groups_count(struct udevice *dev)
62{
63	struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
64
65	return priv->socdata->groups_count;
66}
67
68static const char *uniphier_pinctrl_get_group_name(struct udevice *dev,
69						   unsigned selector)
70{
71	struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
72
73	if (!priv->socdata->groups[selector].name)
74		return uniphier_pinctrl_dummy_name;
75
76	return priv->socdata->groups[selector].name;
77}
78
79static int uniphier_pinmux_get_functions_count(struct udevice *dev)
80{
81	struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
82
83	return priv->socdata->functions_count;
84}
85
86static const char *uniphier_pinmux_get_function_name(struct udevice *dev,
87						     unsigned selector)
88{
89	struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
90
91	if (!priv->socdata->functions[selector])
92		return uniphier_pinctrl_dummy_name;
93
94	return priv->socdata->functions[selector];
95}
96
97static int uniphier_pinconf_input_enable_perpin(struct udevice *dev,
98						unsigned int pin, int enable)
99{
100	struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
101	unsigned reg;
102	u32 mask, tmp;
103
104	reg = UNIPHIER_PINCTRL_IECTRL + pin / 32 * 4;
105	mask = BIT(pin % 32);
106
107	tmp = readl(priv->base + reg);
108	if (enable)
109		tmp |= mask;
110	else
111		tmp &= ~mask;
112	writel(tmp, priv->base + reg);
113
114	return 0;
115}
116
117static int uniphier_pinconf_input_enable_legacy(struct udevice *dev,
118						unsigned int pin, int enable)
119{
120	struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
121
122	/*
123	 * Multiple pins share one input enable, per-pin disabling is
124	 * impossible.
125	 */
126	if (!enable)
127		return -EINVAL;
128
129	/* Set all bits instead of having a bunch of pin data */
130	writel(U32_MAX, priv->base + UNIPHIER_PINCTRL_IECTRL);
131
132	return 0;
133}
134
135static int uniphier_pinconf_input_enable(struct udevice *dev,
136					 unsigned int pin, int enable)
137{
138	struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
139
140	if (priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL)
141		return uniphier_pinconf_input_enable_perpin(dev, pin, enable);
142	else
143		return uniphier_pinconf_input_enable_legacy(dev, pin, enable);
144}
145
146#if CONFIG_IS_ENABLED(PINCONF)
147
148static const struct pinconf_param uniphier_pinconf_params[] = {
149	{ "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
150	{ "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
151	{ "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
152	{ "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1 },
153	{ "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
154	{ "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
155	{ "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
156};
157
158static const struct uniphier_pinctrl_pin *
159uniphier_pinctrl_pin_get(struct uniphier_pinctrl_priv *priv, unsigned int pin)
160{
161	const struct uniphier_pinctrl_pin *pins = priv->socdata->pins;
162	int pins_count = priv->socdata->pins_count;
163	int i;
164
165	for (i = 0; i < pins_count; i++)
166		if (pins[i].number == pin)
167			return &pins[i];
168
169	return NULL;
170}
171
172static int uniphier_pinconf_bias_set(struct udevice *dev, unsigned int pin,
173				     unsigned int param, unsigned int arg)
174{
175	struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
176	unsigned int enable = 1;
177	unsigned int reg;
178	u32 mask, tmp;
179
180	if (!(priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_PUPD_SIMPLE))
181		return -ENOTSUPP;
182
183	switch (param) {
184	case PIN_CONFIG_BIAS_DISABLE:
185		enable = 0;
186		break;
187	case PIN_CONFIG_BIAS_PULL_UP:
188	case PIN_CONFIG_BIAS_PULL_DOWN:
189		if (arg == 0)	/* total bias is not supported */
190			return -EINVAL;
191		break;
192	case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
193		if (arg == 0)	/* configuration ignored */
194			return 0;
195	default:
196		BUG();
197	}
198
199	reg = UNIPHIER_PINCTRL_PUPDCTRL_BASE + pin / 32 * 4;
200	mask = BIT(pin % 32);
201
202	tmp = readl(priv->base + reg);
203	if (enable)
204		tmp |= mask;
205	else
206		tmp &= ~mask;
207	writel(tmp, priv->base + reg);
208
209	return 0;
210}
211
212static const unsigned int uniphier_pinconf_drv_strengths_1bit[] = {
213	4, 8,
214};
215
216static const unsigned int uniphier_pinconf_drv_strengths_2bit[] = {
217	8, 12, 16, 20,
218};
219
220static const unsigned int uniphier_pinconf_drv_strengths_3bit[] = {
221	4, 5, 7, 9, 11, 12, 14, 16,
222};
223
224static int uniphier_pinconf_drive_set(struct udevice *dev, unsigned int pin,
225				      unsigned int strength)
226{
227	struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
228	const struct uniphier_pinctrl_pin *desc;
229	const unsigned int *strengths;
230	unsigned int base, stride, width, drvctrl, reg, shift;
231	u32 val, mask, tmp;
232
233	desc = uniphier_pinctrl_pin_get(priv, pin);
234	if (WARN_ON(!desc))
235		return -EINVAL;
236
237	switch (uniphier_pin_get_drv_type(desc->data)) {
238	case UNIPHIER_PIN_DRV_1BIT:
239		strengths = uniphier_pinconf_drv_strengths_1bit;
240		base = UNIPHIER_PINCTRL_DRVCTRL_BASE;
241		stride = 1;
242		width = 1;
243		break;
244	case UNIPHIER_PIN_DRV_2BIT:
245		strengths = uniphier_pinconf_drv_strengths_2bit;
246		base = UNIPHIER_PINCTRL_DRV2CTRL_BASE;
247		stride = 2;
248		width = 2;
249		break;
250	case UNIPHIER_PIN_DRV_3BIT:
251		strengths = uniphier_pinconf_drv_strengths_3bit;
252		base = UNIPHIER_PINCTRL_DRV3CTRL_BASE;
253		stride = 4;
254		width = 3;
255		break;
256	default:
257		/* drive strength control is not supported for this pin */
258		return -EINVAL;
259	}
260
261	drvctrl = uniphier_pin_get_drvctrl(desc->data);
262	drvctrl *= stride;
263
264	reg = base + drvctrl / 32 * 4;
265	shift = drvctrl % 32;
266	mask = (1U << width) - 1;
267
268	for (val = 0; val <= mask; val++) {
269		if (strengths[val] > strength)
270			break;
271	}
272
273	if (val == 0) {
274		dev_err(dev, "unsupported drive strength %u mA for pin %s\n",
275			strength, desc->name);
276		return -EINVAL;
277	}
278
279	if (!mask)
280		return 0;
281
282	val--;
283
284	tmp = readl(priv->base + reg);
285	tmp &= ~(mask << shift);
286	tmp |= (mask & val) << shift;
287	writel(tmp, priv->base + reg);
288
289	return 0;
290}
291
292static int uniphier_pinconf_set(struct udevice *dev, unsigned int pin,
293				unsigned int param, unsigned int arg)
294{
295	int ret;
296
297	switch (param) {
298	case PIN_CONFIG_BIAS_DISABLE:
299	case PIN_CONFIG_BIAS_PULL_UP:
300	case PIN_CONFIG_BIAS_PULL_DOWN:
301	case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
302		ret = uniphier_pinconf_bias_set(dev, pin, param, arg);
303		break;
304	case PIN_CONFIG_DRIVE_STRENGTH:
305		ret = uniphier_pinconf_drive_set(dev, pin, arg);
306		break;
307	case PIN_CONFIG_INPUT_ENABLE:
308		ret = uniphier_pinconf_input_enable(dev, pin, arg);
309		break;
310	default:
311		dev_err(dev, "unsupported configuration parameter %u\n", param);
312		return -EINVAL;
313	}
314
315	return ret;
316}
317
318static int uniphier_pinconf_group_set(struct udevice *dev,
319				      unsigned int group_selector,
320				      unsigned int param, unsigned int arg)
321{
322	struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
323	const struct uniphier_pinctrl_group *grp =
324					&priv->socdata->groups[group_selector];
325	int i, ret;
326
327	for (i = 0; i < grp->num_pins; i++) {
328		ret = uniphier_pinconf_set(dev, grp->pins[i], param, arg);
329		if (ret)
330			return ret;
331	}
332
333	return 0;
334}
335
336#endif /* CONFIG_IS_ENABLED(PINCONF) */
337
338static void uniphier_pinmux_set_one(struct udevice *dev, unsigned pin,
339				    int muxval)
340{
341	struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
342	unsigned reg, reg_end, shift, mask;
343	unsigned mux_bits = 8;
344	unsigned reg_stride = 4;
345	bool load_pinctrl = false;
346	u32 tmp;
347
348	/* some pins need input-enabling */
349	uniphier_pinconf_input_enable(dev, pin, 1);
350
351	if (muxval < 0)
352		return;		/* dedicated pin; nothing to do for pin-mux */
353
354	if (priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_MUX_4BIT)
355		mux_bits = 4;
356
357	if (priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_DBGMUX_SEPARATE) {
358		/*
359		 *  Mode       offset        bit
360		 *  Normal     4 * n     shift+3:shift
361		 *  Debug      4 * n     shift+7:shift+4
362		 */
363		mux_bits /= 2;
364		reg_stride = 8;
365		load_pinctrl = true;
366	}
367
368	reg = UNIPHIER_PINCTRL_PINMUX_BASE + pin * mux_bits / 32 * reg_stride;
369	reg_end = reg + reg_stride;
370	shift = pin * mux_bits % 32;
371	mask = (1U << mux_bits) - 1;
372
373	/*
374	 * If reg_stride is greater than 4, the MSB of each pinsel shall be
375	 * stored in the offset+4.
376	 */
377	for (; reg < reg_end; reg += 4) {
378		tmp = readl(priv->base + reg);
379		tmp &= ~(mask << shift);
380		tmp |= (mask & muxval) << shift;
381		writel(tmp, priv->base + reg);
382
383		muxval >>= mux_bits;
384	}
385
386	if (load_pinctrl)
387		writel(1, priv->base + UNIPHIER_PINCTRL_LOAD_PINMUX);
388}
389
390static int uniphier_pinmux_group_set(struct udevice *dev,
391				     unsigned group_selector,
392				     unsigned func_selector)
393{
394	struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
395	const struct uniphier_pinctrl_group *grp =
396					&priv->socdata->groups[group_selector];
397	int i;
398
399	for (i = 0; i < grp->num_pins; i++)
400		uniphier_pinmux_set_one(dev, grp->pins[i], grp->muxvals[i]);
401
402	return 0;
403}
404
405const struct pinctrl_ops uniphier_pinctrl_ops = {
406	.get_pins_count = uniphier_pinctrl_get_pins_count,
407	.get_pin_name = uniphier_pinctrl_get_pin_name,
408	.get_groups_count = uniphier_pinctrl_get_groups_count,
409	.get_group_name = uniphier_pinctrl_get_group_name,
410	.get_functions_count = uniphier_pinmux_get_functions_count,
411	.get_function_name = uniphier_pinmux_get_function_name,
412	.pinmux_group_set = uniphier_pinmux_group_set,
413#if CONFIG_IS_ENABLED(PINCONF)
414	.pinconf_num_params = ARRAY_SIZE(uniphier_pinconf_params),
415	.pinconf_params = uniphier_pinconf_params,
416	.pinconf_set = uniphier_pinconf_set,
417	.pinconf_group_set = uniphier_pinconf_group_set,
418#endif
419	.set_state = pinctrl_generic_set_state,
420};
421
422int uniphier_pinctrl_probe(struct udevice *dev,
423			   struct uniphier_pinctrl_socdata *socdata)
424{
425	struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
426	fdt_addr_t addr;
427
428	addr = dev_read_addr(dev->parent);
429	if (addr == FDT_ADDR_T_NONE)
430		return -EINVAL;
431
432	priv->base = devm_ioremap(dev, addr, SZ_4K);
433	if (!priv->base)
434		return -ENOMEM;
435
436	priv->socdata = socdata;
437
438	return 0;
439}
440