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