1 /*
2  * Pinctrl driver for STMicroelectronics STi SoCs
3  *
4  *  Copyright (c) 2017
5  *  Patrice Chotard <patrice.chotard@st.com>
6  *
7  * SPDX-License-Identifier:	GPL-2.0
8  */
9 
10 #include <common.h>
11 #include <bitfield.h>
12 #include <dm.h>
13 #include <errno.h>
14 #include <regmap.h>
15 #include <syscon.h>
16 #include <asm/io.h>
17 #include <dm/pinctrl.h>
18 
19 DECLARE_GLOBAL_DATA_PTR;
20 
21 #define MAX_STI_PINCONF_ENTRIES		7
22 /* Output enable */
23 #define OE			(1 << 27)
24 /* Pull Up */
25 #define PU			(1 << 26)
26 /* Open Drain */
27 #define OD			(1 << 25)
28 
29 /* User-frendly defines for Pin Direction */
30 		/* oe = 0, pu = 0, od = 0 */
31 #define IN			(0)
32 		/* oe = 0, pu = 1, od = 0 */
33 #define IN_PU			(PU)
34 		/* oe = 1, pu = 0, od = 0 */
35 #define OUT			(OE)
36 		/* oe = 1, pu = 1, od = 0 */
37 #define OUT_PU			(OE | PU)
38 		/* oe = 1, pu = 0, od = 1 */
39 #define BIDIR			(OE | OD)
40 		/* oe = 1, pu = 1, od = 1 */
41 #define BIDIR_PU		(OE | PU | OD)
42 
43 struct sti_pinctrl_platdata {
44 	struct regmap *regmap;
45 };
46 
47 struct sti_pin_desc {
48 	unsigned char bank;
49 	unsigned char pin;
50 	unsigned char alt;
51 	int dir;
52 };
53 
54 /*
55  * PIO alternative Function selector
56  */
57 void sti_alternate_select(struct udevice *dev, struct sti_pin_desc *pin_desc)
58 {
59 	struct sti_pinctrl_platdata *plat = dev_get_platdata(dev);
60 	unsigned long sysconf, *sysconfreg;
61 	int alt = pin_desc->alt;
62 	int bank = pin_desc->bank;
63 	int pin = pin_desc->pin;
64 
65 	sysconfreg = (unsigned long *)plat->regmap->base;
66 
67 	switch (bank) {
68 	case 0 ... 5:		/* in "SBC Bank" */
69 		sysconfreg += bank;
70 		break;
71 	case 10 ... 20:		/* in "FRONT Bank" */
72 		sysconfreg += bank - 10;
73 		break;
74 	case 30 ... 35:		/* in "REAR Bank" */
75 		sysconfreg += bank - 30;
76 		break;
77 	case 40 ... 42:		/* in "FLASH Bank" */
78 		sysconfreg += bank - 40;
79 		break;
80 	default:
81 		BUG();
82 		return;
83 	}
84 
85 	sysconf = readl(sysconfreg);
86 	sysconf = bitfield_replace(sysconf, pin * 4, 3, alt);
87 	writel(sysconf, sysconfreg);
88 }
89 
90 /* pin configuration */
91 void sti_pin_configure(struct udevice *dev, struct sti_pin_desc *pin_desc)
92 {
93 	struct sti_pinctrl_platdata *plat = dev_get_platdata(dev);
94 	int bit;
95 	int oe = 0, pu = 0, od = 0;
96 	unsigned long *sysconfreg;
97 	int bank = pin_desc->bank;
98 
99 	sysconfreg = (unsigned long *)plat->regmap->base + 40;
100 
101 	/*
102 	 * NOTE: The PIO configuration for the PIO pins in the
103 	 * "FLASH Bank" are different from all the other banks!
104 	 * Specifically, the output-enable pin control register
105 	 * (SYS_CFG_3040) and the pull-up pin control register
106 	 * (SYS_CFG_3050), are both classed as being "reserved".
107 	 * Hence, we do not write to these registers to configure
108 	 * the OE and PU features for PIOs in this bank. However,
109 	 * the open-drain pin control register (SYS_CFG_3060)
110 	 * follows the style of the other banks, and so we can
111 	 * treat that register normally.
112 	 *
113 	 * Being pedantic, we should configure the PU and PD features
114 	 * in the "FLASH Bank" explicitly instead using the four
115 	 * SYS_CFG registers: 3080, 3081, 3085, and 3086. However, this
116 	 * would necessitate passing in the alternate function number
117 	 * to this function, and adding some horrible complexity here.
118 	 * Alternatively, we could just perform 4 32-bit "pokes" to
119 	 * these four SYS_CFG registers early in the initialization.
120 	 * In practice, these four SYS_CFG registers are correct
121 	 * after a reset, and U-Boot does not need to change them, so
122 	 * we (cheat and) rely on these registers being correct.
123 	 * WARNING: Please be aware of this (pragmatic) behaviour!
124 	 */
125 	int flashss = 0;	/* bool: PIO in the Flash Sub-System ? */
126 
127 	switch (pin_desc->dir) {
128 	case IN:
129 		oe = 0; pu = 0; od = 0;
130 		break;
131 	case IN_PU:
132 		oe = 0; pu = 1; od = 0;
133 		break;
134 	case OUT:
135 		oe = 1; pu = 0; od = 0;
136 		break;
137 	case BIDIR:
138 		oe = 1; pu = 0; od = 1;
139 		break;
140 	case BIDIR_PU:
141 		oe = 1; pu = 1; od = 1;
142 		break;
143 
144 	default:
145 		error("%s invalid direction value: 0x%x\n",
146 		      __func__, pin_desc->dir);
147 		BUG();
148 		break;
149 	}
150 
151 	switch (bank) {
152 	case 0 ... 5:		/* in "SBC Bank" */
153 		sysconfreg += bank / 4;
154 		break;
155 	case 10 ... 20:		/* in "FRONT Bank" */
156 		bank -= 10;
157 		sysconfreg += bank / 4;
158 		break;
159 	case 30 ... 35:		/* in "REAR Bank" */
160 		bank -= 30;
161 		sysconfreg += bank / 4;
162 		break;
163 	case 40 ... 42:		/* in "FLASH Bank" */
164 		bank -= 40;
165 		sysconfreg += bank / 4;
166 		flashss = 1;	/* pin is in the Flash Sub-System */
167 		break;
168 	default:
169 		BUG();
170 		return;
171 	}
172 
173 	bit = ((bank * 8) + pin_desc->pin) % 32;
174 
175 	/*
176 	 * set the "Output Enable" pin control
177 	 * but, do nothing if in the flashSS
178 	 */
179 	if (!flashss) {
180 		if (oe)
181 			generic_set_bit(bit, sysconfreg);
182 		else
183 			generic_clear_bit(bit, sysconfreg);
184 	}
185 
186 	sysconfreg += 10;	/* skip to next set of syscfg registers */
187 
188 	/*
189 	 * set the "Pull Up" pin control
190 	 * but, do nothing if in the FlashSS
191 	 */
192 
193 	if (!flashss) {
194 		if (pu)
195 			generic_set_bit(bit, sysconfreg);
196 		else
197 			generic_clear_bit(bit, sysconfreg);
198 	}
199 
200 	sysconfreg += 10;	/* skip to next set of syscfg registers */
201 
202 	/* set the "Open Drain Enable" pin control */
203 	if (od)
204 		generic_set_bit(bit, sysconfreg);
205 	else
206 		generic_clear_bit(bit, sysconfreg);
207 }
208 
209 
210 static int sti_pinctrl_set_state(struct udevice *dev, struct udevice *config)
211 {
212 	struct fdtdec_phandle_args args;
213 	const void *blob = gd->fdt_blob;
214 	const char *prop_name;
215 	int node = dev_of_offset(config);
216 	int property_offset, prop_len;
217 	int pinconf_node, ret, count;
218 	const char *bank_name;
219 	u32 cells[MAX_STI_PINCONF_ENTRIES];
220 
221 	struct sti_pin_desc pin_desc;
222 
223 	/* go to next node "st,pins" which contains the pins configuration */
224 	pinconf_node = fdt_subnode_offset(blob, node, "st,pins");
225 
226 	/*
227 	 * parse each pins configuration which looks like :
228 	 *	pin_name = <bank_phandle pin_nb alt dir rt_type rt_delay rt_clk>
229 	 */
230 
231 	fdt_for_each_property_offset(property_offset, blob, pinconf_node) {
232 		fdt_getprop_by_offset(blob, property_offset, &prop_name,
233 				      &prop_len);
234 
235 		/* extract the bank of the pin description */
236 		ret = fdtdec_parse_phandle_with_args(blob, pinconf_node,
237 						     prop_name, "#gpio-cells",
238 						     0, 0, &args);
239 		if (ret < 0) {
240 			error("Can't get the gpio bank phandle: %d\n", ret);
241 			return ret;
242 		}
243 
244 		bank_name = fdt_getprop(blob, args.node, "st,bank-name",
245 					&count);
246 		if (count < 0) {
247 			error("Can't find bank-name property %d\n", count);
248 			return -EINVAL;
249 		}
250 
251 		pin_desc.bank = trailing_strtoln(bank_name, NULL);
252 
253 		count = fdtdec_get_int_array_count(blob, pinconf_node,
254 						   prop_name, cells,
255 						   ARRAY_SIZE(cells));
256 		if (count < 0) {
257 			error("Bad pin configuration array %d\n", count);
258 			return -EINVAL;
259 		}
260 
261 		if (count > MAX_STI_PINCONF_ENTRIES) {
262 			error("Unsupported pinconf array count %d\n", count);
263 			return -EINVAL;
264 		}
265 
266 		pin_desc.pin = cells[1];
267 		pin_desc.alt = cells[2];
268 		pin_desc.dir = cells[3];
269 
270 		sti_alternate_select(dev, &pin_desc);
271 		sti_pin_configure(dev, &pin_desc);
272 	};
273 
274 	return 0;
275 }
276 
277 static int sti_pinctrl_probe(struct udevice *dev)
278 {
279 	struct sti_pinctrl_platdata *plat = dev_get_platdata(dev);
280 	struct udevice *syscon;
281 	int err;
282 
283 	/* get corresponding syscon phandle */
284 	err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
285 					   "st,syscfg", &syscon);
286 	if (err) {
287 		error("unable to find syscon device\n");
288 		return err;
289 	}
290 
291 	plat->regmap = syscon_get_regmap(syscon);
292 	if (!plat->regmap) {
293 		error("unable to find regmap\n");
294 		return -ENODEV;
295 	}
296 
297 	return 0;
298 }
299 
300 static const struct udevice_id sti_pinctrl_ids[] = {
301 	{ .compatible = "st,stih407-sbc-pinctrl" },
302 	{ .compatible = "st,stih407-front-pinctrl" },
303 	{ .compatible = "st,stih407-rear-pinctrl" },
304 	{ .compatible = "st,stih407-flash-pinctrl" },
305 	{ }
306 };
307 
308 const struct pinctrl_ops sti_pinctrl_ops = {
309 	.set_state = sti_pinctrl_set_state,
310 };
311 
312 U_BOOT_DRIVER(pinctrl_sti) = {
313 	.name = "pinctrl_sti",
314 	.id = UCLASS_PINCTRL,
315 	.of_match = sti_pinctrl_ids,
316 	.ops = &sti_pinctrl_ops,
317 	.probe = sti_pinctrl_probe,
318 	.platdata_auto_alloc_size = sizeof(struct sti_pinctrl_platdata),
319 	.ops = &sti_pinctrl_ops,
320 };
321