xref: /rk3399_rockchip-uboot/drivers/pinctrl/mvebu/pinctrl-mvebu.c (revision a821c4af79e4f5ce9b629b20473863397bbe9b10)
1656e6cc8SKonstantin Porotchkin /*
2656e6cc8SKonstantin Porotchkin  * Copyright (C) 2016 Marvell International Ltd.
3656e6cc8SKonstantin Porotchkin  *
4656e6cc8SKonstantin Porotchkin  * SPDX-License-Identifier:	GPL-2.0
5656e6cc8SKonstantin Porotchkin  * https://spdx.org/licenses
6656e6cc8SKonstantin Porotchkin  */
7656e6cc8SKonstantin Porotchkin 
8656e6cc8SKonstantin Porotchkin #include <common.h>
9656e6cc8SKonstantin Porotchkin #include <config.h>
10656e6cc8SKonstantin Porotchkin #include <fdtdec.h>
11656e6cc8SKonstantin Porotchkin #include <errno.h>
12656e6cc8SKonstantin Porotchkin #include <dm.h>
13656e6cc8SKonstantin Porotchkin #include <dm/pinctrl.h>
14656e6cc8SKonstantin Porotchkin #include <dm/root.h>
15656e6cc8SKonstantin Porotchkin #include <asm/system.h>
16656e6cc8SKonstantin Porotchkin #include <asm/io.h>
17656e6cc8SKonstantin Porotchkin #include <asm/arch-armada8k/soc-info.h>
18656e6cc8SKonstantin Porotchkin #include "pinctrl-mvebu.h"
19656e6cc8SKonstantin Porotchkin 
20656e6cc8SKonstantin Porotchkin DECLARE_GLOBAL_DATA_PTR;
21656e6cc8SKonstantin Porotchkin 
22656e6cc8SKonstantin Porotchkin /*
23656e6cc8SKonstantin Porotchkin  * mvebu_pinctrl_set_state: configure pin functions.
24656e6cc8SKonstantin Porotchkin  * @dev: the pinctrl device to be configured.
25656e6cc8SKonstantin Porotchkin  * @config: the state to be configured.
26656e6cc8SKonstantin Porotchkin  * @return: 0 in success
27656e6cc8SKonstantin Porotchkin  */
mvebu_pinctrl_set_state(struct udevice * dev,struct udevice * config)28656e6cc8SKonstantin Porotchkin int mvebu_pinctrl_set_state(struct udevice *dev, struct udevice *config)
29656e6cc8SKonstantin Porotchkin {
30656e6cc8SKonstantin Porotchkin 	const void *blob = gd->fdt_blob;
31e160f7d4SSimon Glass 	int node = dev_of_offset(config);
32656e6cc8SKonstantin Porotchkin 	struct mvebu_pinctrl_priv *priv;
33656e6cc8SKonstantin Porotchkin 	u32 pin_arr[MVEBU_MAX_PINS_PER_BANK];
34656e6cc8SKonstantin Porotchkin 	u32 function;
35656e6cc8SKonstantin Porotchkin 	int i, pin_count;
36656e6cc8SKonstantin Porotchkin 
37656e6cc8SKonstantin Porotchkin 	priv = dev_get_priv(dev);
38656e6cc8SKonstantin Porotchkin 
39656e6cc8SKonstantin Porotchkin 	pin_count = fdtdec_get_int_array_count(blob, node,
40656e6cc8SKonstantin Porotchkin 					       "marvell,pins",
41656e6cc8SKonstantin Porotchkin 					       pin_arr,
42656e6cc8SKonstantin Porotchkin 					       MVEBU_MAX_PINS_PER_BANK);
43656e6cc8SKonstantin Porotchkin 	if (pin_count <= 0) {
44656e6cc8SKonstantin Porotchkin 		debug("Failed reading pins array for pinconfig %s (%d)\n",
45656e6cc8SKonstantin Porotchkin 		      config->name, pin_count);
46656e6cc8SKonstantin Porotchkin 		return -EINVAL;
47656e6cc8SKonstantin Porotchkin 	}
48656e6cc8SKonstantin Porotchkin 
49656e6cc8SKonstantin Porotchkin 	function = fdtdec_get_int(blob, node, "marvell,function", 0xff);
50656e6cc8SKonstantin Porotchkin 
51656e6cc8SKonstantin Porotchkin 	for (i = 0; i < pin_count; i++) {
52656e6cc8SKonstantin Porotchkin 	int reg_offset;
53656e6cc8SKonstantin Porotchkin 	int field_offset;
54656e6cc8SKonstantin Porotchkin 		int pin = pin_arr[i];
55656e6cc8SKonstantin Porotchkin 
56656e6cc8SKonstantin Porotchkin 		if (function > priv->max_func) {
57656e6cc8SKonstantin Porotchkin 			debug("Illegal function %d for pinconfig %s\n",
58656e6cc8SKonstantin Porotchkin 			      function, config->name);
59656e6cc8SKonstantin Porotchkin 			return -EINVAL;
60656e6cc8SKonstantin Porotchkin 		}
61656e6cc8SKonstantin Porotchkin 
62656e6cc8SKonstantin Porotchkin 		/* Calculate register address and bit in register */
63656e6cc8SKonstantin Porotchkin 		reg_offset   = priv->reg_direction * 4 *
64656e6cc8SKonstantin Porotchkin 					(pin >> (PIN_REG_SHIFT));
65656e6cc8SKonstantin Porotchkin 		field_offset = (BITS_PER_PIN) * (pin & PIN_FIELD_MASK);
66656e6cc8SKonstantin Porotchkin 
67656e6cc8SKonstantin Porotchkin 		clrsetbits_le32(priv->base_reg + reg_offset,
68656e6cc8SKonstantin Porotchkin 				PIN_FUNC_MASK << field_offset,
69656e6cc8SKonstantin Porotchkin 				(function & PIN_FUNC_MASK) << field_offset);
70656e6cc8SKonstantin Porotchkin 	}
71656e6cc8SKonstantin Porotchkin 
72656e6cc8SKonstantin Porotchkin 	return 0;
73656e6cc8SKonstantin Porotchkin }
74656e6cc8SKonstantin Porotchkin 
75656e6cc8SKonstantin Porotchkin /*
76656e6cc8SKonstantin Porotchkin  * mvebu_pinctrl_set_state_all: configure the entire bank pin functions.
77656e6cc8SKonstantin Porotchkin  * @dev: the pinctrl device to be configured.
78656e6cc8SKonstantin Porotchkin  * @config: the state to be configured.
79656e6cc8SKonstantin Porotchkin  * @return: 0 in success
80656e6cc8SKonstantin Porotchkin  */
mvebu_pinctrl_set_state_all(struct udevice * dev,struct udevice * config)81656e6cc8SKonstantin Porotchkin static int mvebu_pinctrl_set_state_all(struct udevice *dev,
82656e6cc8SKonstantin Porotchkin 				       struct udevice *config)
83656e6cc8SKonstantin Porotchkin {
84656e6cc8SKonstantin Porotchkin 	const void *blob = gd->fdt_blob;
85e160f7d4SSimon Glass 	int node = dev_of_offset(config);
86656e6cc8SKonstantin Porotchkin 	struct mvebu_pinctrl_priv *priv;
87656e6cc8SKonstantin Porotchkin 	u32 func_arr[MVEBU_MAX_PINS_PER_BANK];
88656e6cc8SKonstantin Porotchkin 	int pin, err;
89656e6cc8SKonstantin Porotchkin 
90656e6cc8SKonstantin Porotchkin 	priv = dev_get_priv(dev);
91656e6cc8SKonstantin Porotchkin 
92656e6cc8SKonstantin Porotchkin 	err = fdtdec_get_int_array(blob, node, "pin-func",
93656e6cc8SKonstantin Porotchkin 				   func_arr, priv->pin_cnt);
94656e6cc8SKonstantin Porotchkin 	if (err) {
95656e6cc8SKonstantin Porotchkin 		debug("Failed reading pin functions for bank %s\n",
96656e6cc8SKonstantin Porotchkin 		      priv->bank_name);
97656e6cc8SKonstantin Porotchkin 		return -EINVAL;
98656e6cc8SKonstantin Porotchkin 	}
99656e6cc8SKonstantin Porotchkin 
100656e6cc8SKonstantin Porotchkin 	for (pin = 0; pin < priv->pin_cnt; pin++) {
101656e6cc8SKonstantin Porotchkin 		int reg_offset;
102656e6cc8SKonstantin Porotchkin 		int field_offset;
103656e6cc8SKonstantin Porotchkin 		u32 func = func_arr[pin];
104656e6cc8SKonstantin Porotchkin 
105656e6cc8SKonstantin Porotchkin 		/* Bypass pins with function 0xFF */
106656e6cc8SKonstantin Porotchkin 		if (func == 0xff) {
107656e6cc8SKonstantin Porotchkin 			debug("Warning: pin %d value is not modified ", pin);
108656e6cc8SKonstantin Porotchkin 			debug("(kept as default)\n");
109656e6cc8SKonstantin Porotchkin 			continue;
110656e6cc8SKonstantin Porotchkin 		} else if (func > priv->max_func) {
111656e6cc8SKonstantin Porotchkin 			debug("Illegal function %d for pin %d\n", func, pin);
112656e6cc8SKonstantin Porotchkin 			return -EINVAL;
113656e6cc8SKonstantin Porotchkin 		}
114656e6cc8SKonstantin Porotchkin 
115656e6cc8SKonstantin Porotchkin 		/* Calculate register address and bit in register */
116656e6cc8SKonstantin Porotchkin 		reg_offset   = priv->reg_direction * 4 *
117656e6cc8SKonstantin Porotchkin 					(pin >> (PIN_REG_SHIFT));
118656e6cc8SKonstantin Porotchkin 		field_offset = (BITS_PER_PIN) * (pin & PIN_FIELD_MASK);
119656e6cc8SKonstantin Porotchkin 
120656e6cc8SKonstantin Porotchkin 		clrsetbits_le32(priv->base_reg + reg_offset,
121656e6cc8SKonstantin Porotchkin 				PIN_FUNC_MASK << field_offset,
122656e6cc8SKonstantin Porotchkin 				(func & PIN_FUNC_MASK) << field_offset);
123656e6cc8SKonstantin Porotchkin 	}
124656e6cc8SKonstantin Porotchkin 
125656e6cc8SKonstantin Porotchkin 	return 0;
126656e6cc8SKonstantin Porotchkin }
127656e6cc8SKonstantin Porotchkin 
mvebu_pinctl_probe(struct udevice * dev)128656e6cc8SKonstantin Porotchkin int mvebu_pinctl_probe(struct udevice *dev)
129656e6cc8SKonstantin Porotchkin {
130656e6cc8SKonstantin Porotchkin 	const void *blob = gd->fdt_blob;
131e160f7d4SSimon Glass 	int node = dev_of_offset(dev);
132656e6cc8SKonstantin Porotchkin 	struct mvebu_pinctrl_priv *priv;
133656e6cc8SKonstantin Porotchkin 
134656e6cc8SKonstantin Porotchkin 	priv = dev_get_priv(dev);
135656e6cc8SKonstantin Porotchkin 	if (!priv) {
136656e6cc8SKonstantin Porotchkin 		debug("%s: Failed to get private\n", __func__);
137656e6cc8SKonstantin Porotchkin 		return -EINVAL;
138656e6cc8SKonstantin Porotchkin 	}
139656e6cc8SKonstantin Porotchkin 
140*a821c4afSSimon Glass 	priv->base_reg = devfdt_get_addr_ptr(dev);
141656e6cc8SKonstantin Porotchkin 	if (priv->base_reg == (void *)FDT_ADDR_T_NONE) {
142656e6cc8SKonstantin Porotchkin 		debug("%s: Failed to get base address\n", __func__);
143656e6cc8SKonstantin Porotchkin 		return -EINVAL;
144656e6cc8SKonstantin Porotchkin 	}
145656e6cc8SKonstantin Porotchkin 
146656e6cc8SKonstantin Porotchkin 	priv->pin_cnt   = fdtdec_get_int(blob, node, "pin-count",
147656e6cc8SKonstantin Porotchkin 					MVEBU_MAX_PINS_PER_BANK);
148656e6cc8SKonstantin Porotchkin 	priv->max_func  = fdtdec_get_int(blob, node, "max-func",
149656e6cc8SKonstantin Porotchkin 					 MVEBU_MAX_FUNC);
150656e6cc8SKonstantin Porotchkin 	priv->bank_name = fdt_getprop(blob, node, "bank-name", NULL);
151656e6cc8SKonstantin Porotchkin 
152656e6cc8SKonstantin Porotchkin 	priv->reg_direction = 1;
153656e6cc8SKonstantin Porotchkin 	if (fdtdec_get_bool(blob, node, "reverse-reg"))
154656e6cc8SKonstantin Porotchkin 		priv->reg_direction = -1;
155656e6cc8SKonstantin Porotchkin 
156656e6cc8SKonstantin Porotchkin 	return mvebu_pinctrl_set_state_all(dev, dev);
157656e6cc8SKonstantin Porotchkin }
158656e6cc8SKonstantin Porotchkin 
159656e6cc8SKonstantin Porotchkin static struct pinctrl_ops mvebu_pinctrl_ops = {
160656e6cc8SKonstantin Porotchkin 	.set_state	= mvebu_pinctrl_set_state
161656e6cc8SKonstantin Porotchkin };
162656e6cc8SKonstantin Porotchkin 
163656e6cc8SKonstantin Porotchkin static const struct udevice_id mvebu_pinctrl_ids[] = {
164656e6cc8SKonstantin Porotchkin 	{ .compatible = "marvell,mvebu-pinctrl" },
165656e6cc8SKonstantin Porotchkin 	{ .compatible = "marvell,armada-ap806-pinctrl" },
166656e6cc8SKonstantin Porotchkin 	{ .compatible = "marvell,a70x0-pinctrl" },
167656e6cc8SKonstantin Porotchkin 	{ .compatible = "marvell,a80x0-cp0-pinctrl" },
168656e6cc8SKonstantin Porotchkin 	{ .compatible = "marvell,a80x0-cp1-pinctrl" },
169656e6cc8SKonstantin Porotchkin 	{ }
170656e6cc8SKonstantin Porotchkin };
171656e6cc8SKonstantin Porotchkin 
172656e6cc8SKonstantin Porotchkin U_BOOT_DRIVER(pinctrl_mvebu) = {
173656e6cc8SKonstantin Porotchkin 	.name		= "mvebu_pinctrl",
174656e6cc8SKonstantin Porotchkin 	.id		= UCLASS_PINCTRL,
175656e6cc8SKonstantin Porotchkin 	.of_match	= mvebu_pinctrl_ids,
176656e6cc8SKonstantin Porotchkin 	.priv_auto_alloc_size = sizeof(struct mvebu_pinctrl_priv),
177656e6cc8SKonstantin Porotchkin 	.ops		= &mvebu_pinctrl_ops,
178656e6cc8SKonstantin Porotchkin 	.probe		= mvebu_pinctl_probe
179656e6cc8SKonstantin Porotchkin };
180