Skip to content

Commit f5e2cd3

Browse files
Andre-ARMlinusw
authored andcommitted
pinctrl: sunxi: allow reading mux values from DT
So far every Allwinner SoC needs a large table in the kernel code, to describe the mapping between the pinctrl function names ("uart") and the actual pincontroller mux value to be written into the registers. This adds a lot of data into a single image kernel, and also looks somewhat weird, as the DT can easily store the mux value. Add some code that allows to avoid that table: the struct that describes the existing pins will be build at *runtime*, based on very basic information provided by the respective SoC's pinctrl driver. This consists of the number of pins per bank, plus information which bank provides IRQ support, along with the mux value to use for that. The code will then iterate over all children of the pincontroller DT node (which describe each pin group), and populate that struct with the mapping between function names and mux values. The only thing that needs adding in the DT is a property with that value, per pin group. When this table is built, it will be handed over to the existing sunxi pinctrl driver, which cannot tell a difference between a hardcoded struct and this new one built at runtime. It will take care of registering the pinctrl device with the pinctrl subsystem. All a new SoC driver would need to do is to provide two arrays, and then call the sunxi_pinctrl_dt_table_init() function. Signed-off-by: Andre Przywara <[email protected]> Reviewed-by: Jernej Skrabec <[email protected]> Link: https://lore.kernel.org/[email protected] Signed-off-by: Linus Walleij <[email protected]>
1 parent 6d079d9 commit f5e2cd3

File tree

3 files changed

+384
-0
lines changed

3 files changed

+384
-0
lines changed

drivers/pinctrl/sunxi/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# SPDX-License-Identifier: GPL-2.0
22
# Core
33
obj-y += pinctrl-sunxi.o
4+
obj-y += pinctrl-sunxi-dt.o
45

56
# SoC Drivers
67
obj-$(CONFIG_PINCTRL_SUNIV_F1C100S) += pinctrl-suniv-f1c100s.o
Lines changed: 374 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,374 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright (C) 2017-2025 Arm Ltd.
4+
*
5+
* Generic DT driven Allwinner pinctrl driver routines.
6+
* Builds the pin tables from minimal driver information and pin groups
7+
* described in the DT. Then hands those tables of to the traditional
8+
* sunxi pinctrl driver.
9+
* sunxi_pinctrl_init() expects a table like shown below, previously spelled
10+
* out in a per-SoC .c file. This code generates this table, like so:
11+
*
12+
* SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1), // code iterates over every implemented
13+
* // pin, based on pins_per_bank[] array passed in
14+
*
15+
* SUNXI_FUNCTION(0x0, "gpio_in"), // always added, for every pin
16+
* SUNXI_FUNCTION(0x1, "gpio_out"), // always added, for every pin
17+
*
18+
* SUNXI_FUNCTION(0x2, "mmc0"), // based on pingroup found in DT:
19+
* // mmc0-pins {
20+
* // pins = "PF0", "PF1", ...
21+
* // function = "mmc0";
22+
* // allwinner,pinmux = <2>;
23+
*
24+
* SUNXI_FUNCTION_IRQ_BANK(0x6, 4, 1)), // derived by irq_bank_muxes[]
25+
* // array passed in
26+
*/
27+
28+
#include <linux/export.h>
29+
#include <linux/of.h>
30+
#include <linux/of_address.h>
31+
#include <linux/of_device.h>
32+
#include <linux/pinctrl/pinctrl.h>
33+
#include <linux/platform_device.h>
34+
#include <linux/slab.h>
35+
36+
#include "pinctrl-sunxi.h"
37+
38+
#define INVALID_MUX 0xff
39+
40+
/*
41+
* Return the "index"th element from the "allwinner,pinmux" property. If the
42+
* property does not hold enough entries, return the last one instead.
43+
* For almost every group the pinmux value is actually the same, so this
44+
* allows to just list one value in the property.
45+
*/
46+
static u8 sunxi_pinctrl_dt_read_pinmux(const struct device_node *node,
47+
int index)
48+
{
49+
int ret, num_elems;
50+
u32 value;
51+
52+
num_elems = of_property_count_u32_elems(node, "allwinner,pinmux");
53+
if (num_elems <= 0)
54+
return INVALID_MUX;
55+
56+
if (index >= num_elems)
57+
index = num_elems - 1;
58+
59+
ret = of_property_read_u32_index(node, "allwinner,pinmux", index,
60+
&value);
61+
if (ret)
62+
return INVALID_MUX;
63+
64+
return value;
65+
}
66+
67+
/*
68+
* Allocate a table with a sunxi_desc_pin structure for every pin needed.
69+
* Fills in the respective pin names ("PA0") and their pin numbers.
70+
* Returns the pins array. We cannot use the member in *desc yet, as this
71+
* is marked as const, and we will need to change the array still.
72+
*/
73+
static struct sunxi_desc_pin *init_pins_table(struct device *dev,
74+
const u8 *pins_per_bank,
75+
struct sunxi_pinctrl_desc *desc)
76+
{
77+
struct sunxi_desc_pin *pins, *cur_pin;
78+
int name_size = 0;
79+
int port_base = desc->pin_base / PINS_PER_BANK;
80+
char *pin_names, *cur_name;
81+
int i, j;
82+
83+
/*
84+
* Find the total number of pins.
85+
* Also work out how much memory we need to store all the pin names.
86+
*/
87+
for (i = 0; i < SUNXI_PINCTRL_MAX_BANKS; i++) {
88+
desc->npins += pins_per_bank[i];
89+
if (pins_per_bank[i] < 10) {
90+
/* 4 bytes for "PXy\0" */
91+
name_size += pins_per_bank[i] * 4;
92+
} else {
93+
/* 4 bytes for each "PXy\0" */
94+
name_size += 10 * 4;
95+
96+
/* 5 bytes for each "PXyy\0" */
97+
name_size += (pins_per_bank[i] - 10) * 5;
98+
}
99+
}
100+
101+
if (desc->npins == 0) {
102+
dev_err(dev, "no ports defined\n");
103+
return ERR_PTR(-EINVAL);
104+
}
105+
106+
pins = devm_kzalloc(dev, desc->npins * sizeof(*pins), GFP_KERNEL);
107+
if (!pins)
108+
return ERR_PTR(-ENOMEM);
109+
110+
/* Allocate memory to store the name for every pin. */
111+
pin_names = devm_kmalloc(dev, name_size, GFP_KERNEL);
112+
if (!pin_names)
113+
return ERR_PTR(-ENOMEM);
114+
115+
/* Fill the pins array with the name and the number for each pin. */
116+
cur_name = pin_names;
117+
cur_pin = pins;
118+
for (i = 0; i < SUNXI_PINCTRL_MAX_BANKS; i++) {
119+
for (j = 0; j < pins_per_bank[i]; j++, cur_pin++) {
120+
int nchars = sprintf(cur_name, "P%c%d",
121+
port_base + 'A' + i, j);
122+
123+
cur_pin->pin.number = (port_base + i) * PINS_PER_BANK + j;
124+
cur_pin->pin.name = cur_name;
125+
cur_name += nchars + 1;
126+
}
127+
}
128+
129+
return pins;
130+
}
131+
132+
/*
133+
* Work out the number of functions for each pin. This will visit every
134+
* child node of the pinctrl DT node to find all advertised functions.
135+
* Provide memory to hold the per-function information and assign it to
136+
* the pin table.
137+
* Fill in the GPIO in/out functions already (that every pin has), also add
138+
* an "irq" function at the end, for those pins in IRQ-capable ports.
139+
* We do not fill in the extra functions (those describe in DT nodes) yet.
140+
* We (ab)use the "variant" member in each pin to keep track of the number of
141+
* extra functions needed. At the end this will get reset to 2, so that we
142+
* can add extra function later, after the two GPIO functions.
143+
*/
144+
static int prepare_function_table(struct device *dev, struct device_node *pnode,
145+
struct sunxi_desc_pin *pins, int npins,
146+
const u8 *irq_bank_muxes)
147+
{
148+
struct device_node *node;
149+
struct property *prop;
150+
struct sunxi_desc_function *func;
151+
int num_funcs, irq_bank, last_bank, i;
152+
153+
/*
154+
* We need at least three functions per pin:
155+
* - one for GPIO in
156+
* - one for GPIO out
157+
* - one for the sentinel signalling the end of the list
158+
*/
159+
num_funcs = 3 * npins;
160+
161+
/*
162+
* Add a function for each pin in a bank supporting interrupts.
163+
* We temporarily (ab)use the variant field to store the number of
164+
* functions per pin. This will be cleaned back to 0 before we hand
165+
* over the whole structure to the generic sunxi pinctrl setup code.
166+
*/
167+
for (i = 0; i < npins; i++) {
168+
struct sunxi_desc_pin *pin = &pins[i];
169+
int bank = pin->pin.number / PINS_PER_BANK;
170+
171+
if (irq_bank_muxes[bank]) {
172+
pin->variant++;
173+
num_funcs++;
174+
}
175+
}
176+
177+
/*
178+
* Go over each pin group (every child of the pinctrl DT node) and
179+
* add the number of special functions each pins has. Also update the
180+
* total number of functions required.
181+
* We might slightly overshoot here in case of double definitions.
182+
*/
183+
for_each_child_of_node(pnode, node) {
184+
const char *name;
185+
186+
of_property_for_each_string(node, "pins", prop, name) {
187+
for (i = 0; i < npins; i++) {
188+
if (strcmp(pins[i].pin.name, name))
189+
continue;
190+
191+
pins[i].variant++;
192+
num_funcs++;
193+
break;
194+
}
195+
}
196+
}
197+
198+
/*
199+
* Allocate the memory needed for the functions in one table.
200+
* We later use pointers into this table to mark each pin.
201+
*/
202+
func = devm_kzalloc(dev, num_funcs * sizeof(*func), GFP_KERNEL);
203+
if (!func)
204+
return -ENOMEM;
205+
206+
/*
207+
* Assign the function's memory and fill in GPIOs, IRQ and a sentinel.
208+
* The extra functions will be filled in later.
209+
*/
210+
irq_bank = 0;
211+
last_bank = 0;
212+
for (i = 0; i < npins; i++) {
213+
struct sunxi_desc_pin *pin = &pins[i];
214+
int bank = pin->pin.number / PINS_PER_BANK;
215+
int lastfunc = pin->variant + 1;
216+
int irq_mux = irq_bank_muxes[bank];
217+
218+
func[0].name = "gpio_in";
219+
func[0].muxval = 0;
220+
func[1].name = "gpio_out";
221+
func[1].muxval = 1;
222+
223+
if (irq_mux) {
224+
if (bank > last_bank)
225+
irq_bank++;
226+
func[lastfunc].muxval = irq_mux;
227+
func[lastfunc].irqbank = irq_bank;
228+
func[lastfunc].irqnum = pin->pin.number % PINS_PER_BANK;
229+
func[lastfunc].name = "irq";
230+
}
231+
232+
if (bank > last_bank)
233+
last_bank = bank;
234+
235+
pin->functions = func;
236+
237+
/* Skip over the other needed functions and the sentinel. */
238+
func += pin->variant + 3;
239+
240+
/*
241+
* Reset the value for filling in the remaining functions
242+
* behind the GPIOs later.
243+
*/
244+
pin->variant = 2;
245+
}
246+
247+
return 0;
248+
}
249+
250+
/*
251+
* Iterate over all pins in a single group and add the function name and its
252+
* mux value to the respective pin.
253+
* The "variant" member is again used to temporarily track the number of
254+
* already added functions.
255+
*/
256+
static void fill_pin_function(struct device *dev, struct device_node *node,
257+
struct sunxi_desc_pin *pins, int npins)
258+
{
259+
const char *name, *funcname;
260+
struct sunxi_desc_function *func;
261+
struct property *prop;
262+
int pin, i, index;
263+
u8 muxval;
264+
265+
if (of_property_read_string(node, "function", &funcname)) {
266+
dev_warn(dev, "missing \"function\" property\n");
267+
return;
268+
}
269+
270+
index = 0;
271+
of_property_for_each_string(node, "pins", prop, name) {
272+
/* Find the index of this pin in our table. */
273+
for (pin = 0; pin < npins; pin++)
274+
if (!strcmp(pins[pin].pin.name, name))
275+
break;
276+
if (pin == npins) {
277+
dev_warn(dev, "%s: cannot find pin %s\n",
278+
of_node_full_name(node), name);
279+
index++;
280+
continue;
281+
}
282+
283+
/* Read the associated mux value. */
284+
muxval = sunxi_pinctrl_dt_read_pinmux(node, index);
285+
if (muxval == INVALID_MUX) {
286+
dev_warn(dev, "%s: invalid mux value for pin %s\n",
287+
of_node_full_name(node), name);
288+
index++;
289+
continue;
290+
}
291+
292+
/*
293+
* Check for double definitions by comparing the to-be-added
294+
* function with already assigned ones.
295+
* Ignore identical pairs (function name and mux value the
296+
* same), but warn about conflicting assignments.
297+
*/
298+
for (i = 2; i < pins[pin].variant; i++) {
299+
func = &pins[pin].functions[i];
300+
301+
/* Skip over totally unrelated functions. */
302+
if (strcmp(func->name, funcname) &&
303+
func->muxval != muxval)
304+
continue;
305+
306+
/* Ignore (but skip below) any identical functions. */
307+
if (!strcmp(func->name, funcname) &&
308+
muxval == func->muxval)
309+
break;
310+
311+
dev_warn(dev,
312+
"pin %s: function %s redefined to mux %d\n",
313+
name, funcname, muxval);
314+
break;
315+
}
316+
317+
/* Skip any pins with that function already assigned. */
318+
if (i < pins[pin].variant) {
319+
index++;
320+
continue;
321+
}
322+
323+
/* Assign function and muxval to the next free slot. */
324+
func = &pins[pin].functions[pins[pin].variant];
325+
func->muxval = muxval;
326+
func->name = funcname;
327+
328+
pins[pin].variant++;
329+
index++;
330+
}
331+
}
332+
333+
/*
334+
* Initialise the pinctrl table, by building it from driver provided
335+
* information: the number of pins per bank, the IRQ capable banks and their
336+
* IRQ mux value.
337+
* Then iterate over all pinctrl DT node children to enter the function name
338+
* and mux values for each mentioned pin.
339+
* At the end hand over this structure to the actual sunxi pinctrl driver.
340+
*/
341+
int sunxi_pinctrl_dt_table_init(struct platform_device *pdev,
342+
const u8 *pins_per_bank,
343+
const u8 *irq_bank_muxes,
344+
struct sunxi_pinctrl_desc *desc,
345+
unsigned long flags)
346+
{
347+
struct device_node *pnode = pdev->dev.of_node, *node;
348+
struct sunxi_desc_pin *pins;
349+
int ret, i;
350+
351+
pins = init_pins_table(&pdev->dev, pins_per_bank, desc);
352+
if (IS_ERR(pins))
353+
return PTR_ERR(pins);
354+
355+
ret = prepare_function_table(&pdev->dev, pnode, pins, desc->npins,
356+
irq_bank_muxes);
357+
if (ret)
358+
return ret;
359+
360+
/*
361+
* Now iterate over all groups and add the respective function name
362+
* and mux values to each pin listed within.
363+
*/
364+
for_each_child_of_node(pnode, node)
365+
fill_pin_function(&pdev->dev, node, pins, desc->npins);
366+
367+
/* Clear the temporary storage. */
368+
for (i = 0; i < desc->npins; i++)
369+
pins[i].variant = 0;
370+
371+
desc->pins = pins;
372+
373+
return sunxi_pinctrl_init_with_flags(pdev, desc, flags);
374+
}

0 commit comments

Comments
 (0)