jcs's openbsd hax
openbsd
1/* $OpenBSD: pinctrl.c,v 1.5 2021/10/24 17:52:26 mpi Exp $ */
2/*
3 * Copyright (c) 2018, 2019 Mark Kettenis <kettenis@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <sys/param.h>
19#include <sys/systm.h>
20#include <sys/device.h>
21#include <sys/malloc.h>
22
23#include <machine/intr.h>
24#include <machine/bus.h>
25#include <machine/fdt.h>
26
27#include <dev/ofw/openfirm.h>
28#include <dev/ofw/ofw_misc.h>
29#include <dev/ofw/ofw_pinctrl.h>
30#include <dev/ofw/fdt.h>
31
32#define HREAD2(sc, reg) \
33 (bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, (reg)))
34#define HWRITE2(sc, reg, val) \
35 bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
36#define HREAD4(sc, reg) \
37 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
38#define HWRITE4(sc, reg, val) \
39 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
40
41struct pinctrl_softc {
42 struct device sc_dev;
43 bus_space_tag_t sc_iot;
44 bus_space_handle_t sc_ioh;
45
46 uint32_t sc_reg_width;
47 uint32_t sc_func_mask;
48 uint32_t sc_ncells;
49};
50
51int pinctrl_match(struct device *, void *, void *);
52void pinctrl_attach(struct device *, struct device *, void *);
53
54const struct cfattach pinctrl_ca = {
55 sizeof (struct pinctrl_softc), pinctrl_match, pinctrl_attach
56};
57
58struct cfdriver pinctrl_cd = {
59 NULL, "pinctrl", DV_DULL
60};
61
62int pinctrl_pinctrl(uint32_t, void *);
63
64int
65pinctrl_match(struct device *parent, void *match, void *aux)
66{
67 struct fdt_attach_args *faa = aux;
68
69 return (OF_is_compatible(faa->fa_node, "pinctrl-single") ||
70 OF_is_compatible(faa->fa_node, "pinconf-single"));
71}
72
73void
74pinctrl_attach(struct device *parent, struct device *self, void *aux)
75{
76 struct pinctrl_softc *sc = (struct pinctrl_softc *)self;
77 struct fdt_attach_args *faa = aux;
78
79 if (faa->fa_nreg < 1) {
80 printf(": no registers\n");
81 return;
82 }
83
84 sc->sc_reg_width = OF_getpropint(faa->fa_node,
85 "pinctrl-single,register-width", 0);
86 if (sc->sc_reg_width != 16 &&
87 sc->sc_reg_width != 32) {
88 printf(": unsupported register width\n");
89 return;
90 }
91
92 sc->sc_ncells = OF_getpropint(faa->fa_node, "#pinctrl-cells", 1);
93 sc->sc_func_mask = OF_getpropint(faa->fa_node,
94 "pinctrl-single,function-mask", 0);
95
96 sc->sc_iot = faa->fa_iot;
97 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
98 faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
99 printf(": can't map registers\n");
100 return;
101 }
102
103 pinctrl_register(faa->fa_node, pinctrl_pinctrl, sc);
104
105 printf("\n");
106}
107
108uint32_t
109pinctrl_set2(int node, char *setting, uint32_t val)
110{
111 uint32_t values[2];
112
113 if (OF_getpropintarray(node, setting, values, sizeof(values)) !=
114 sizeof(values))
115 return val;
116
117 val &= ~values[1];
118 val |= (values[0] & values[1]);
119 return val;
120}
121
122uint32_t
123pinctrl_set4(int node, char *setting, uint32_t val)
124{
125 uint32_t values[4];
126
127 if (OF_getpropintarray(node, setting, values, sizeof(values)) !=
128 sizeof(values))
129 return val;
130
131 val &= ~values[3];
132 val |= (values[0] & values[3]);
133 return val;
134}
135
136int
137pinctrl_pinctrl(uint32_t phandle, void *cookie)
138{
139 struct pinctrl_softc *sc = cookie;
140 uint32_t *pins;
141 int node, len, i;
142
143 node = OF_getnodebyphandle(phandle);
144 if (node == 0)
145 return -1;
146
147 len = OF_getproplen(node, "pinctrl-single,pins");
148 if (len <= 0)
149 return -1;
150
151 pins = malloc(len, M_TEMP, M_WAITOK);
152 OF_getpropintarray(node, "pinctrl-single,pins", pins, len);
153
154 for (i = 0; i < len / sizeof(uint32_t); i += (1 + sc->sc_ncells)) {
155 uint32_t reg = pins[i];
156 uint32_t func = pins[i + 1];
157 uint32_t val = 0;
158
159 if (sc->sc_ncells == 2)
160 func |= pins[i + 2];
161
162 if (sc->sc_reg_width == 16)
163 val = HREAD2(sc, reg);
164 else if (sc->sc_reg_width == 32)
165 val = HREAD4(sc, reg);
166
167 val &= ~sc->sc_func_mask;
168 val |= (func & sc->sc_func_mask);
169
170 val = pinctrl_set2(node, "pinctrl-single,drive-strength", val);
171 val = pinctrl_set4(node, "pinctrl-single,bias-pulldown", val);
172 val = pinctrl_set4(node, "pinctrl-single,bias-pullup", val);
173
174 if (sc->sc_reg_width == 16)
175 HWRITE2(sc, reg, val);
176 else if (sc->sc_reg_width == 32)
177 HWRITE4(sc, reg, val);
178 }
179
180 free(pins, M_TEMP, len);
181 return 0;
182}