1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright 2020 Michal Meloun <mmel@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 /*
32  * Pin multiplexer driver for Tegra SoCs.
33  */
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/bus.h>
37 #include <sys/kernel.h>
38 #include <sys/module.h>
39 #include <sys/malloc.h>
40 #include <sys/rman.h>
41 
42 #include <machine/bus.h>
43 
44 #include <dev/fdt/fdt_common.h>
45 #include <dev/fdt/fdt_pinctrl.h>
46 #include <dev/ofw/openfirm.h>
47 #include <dev/ofw/ofw_bus.h>
48 #include <dev/ofw/ofw_bus_subr.h>
49 
50 /* Pin multipexor register. */
51 #define	TEGRA_MUX_FUNCTION_MASK  0x03
52 #define	TEGRA_MUX_FUNCTION_SHIFT 0
53 #define	TEGRA_MUX_PUPD_MASK  0x03
54 #define	TEGRA_MUX_PUPD_SHIFT 2
55 #define	TEGRA_MUX_TRISTATE_SHIFT 4
56 #define	TEGRA_MUX_ENABLE_INPUT_SHIFT 5
57 #define	TEGRA_MUX_OPEN_DRAIN_SHIFT 6
58 #define	TEGRA_MUX_LOCK_SHIFT 7
59 #define	TEGRA_MUX_IORESET_SHIFT 8
60 #define	TEGRA_MUX_RCV_SEL_SHIFT 9
61 
62 
63 /* Pin goup register. */
64 #define	TEGRA_GRP_HSM_SHIFT 2
65 #define	TEGRA_GRP_SCHMT_SHIFT 3
66 #define	TEGRA_GRP_DRV_TYPE_SHIFT 6
67 #define	TEGRA_GRP_DRV_TYPE_MASK 0x03
68 #define	TEGRA_GRP_DRV_DRVDN_SLWR_SHIFT 28
69 #define	TEGRA_GRP_DRV_DRVDN_SLWR_MASK 0x03
70 #define	TEGRA_GRP_DRV_DRVUP_SLWF_SHIFT 30
71 #define	TEGRA_GRP_DRV_DRVUP_SLWF_MASK 0x03
72 
73 struct pinmux_softc {
74 	device_t	dev;
75 	struct resource	*pad_mem_res;
76 	struct resource	*mux_mem_res;
77 };
78 
79 static struct ofw_compat_data compat_data[] = {
80 	{"nvidia,tegra210-pinmux",	1},
81 	{NULL,				0},
82 };
83 
84 enum prop_id {
85 	PROP_ID_PULL,
86 	PROP_ID_TRISTATE,
87 	PROP_ID_ENABLE_INPUT,
88 	PROP_ID_OPEN_DRAIN,
89 	PROP_ID_LOCK,
90 	PROP_ID_IORESET,
91 	PROP_ID_RCV_SEL,
92 	PROP_ID_HIGH_SPEED_MODE,
93 	PROP_ID_SCHMITT,
94 	PROP_ID_LOW_POWER_MODE,
95 	PROP_ID_DRIVE_DOWN_STRENGTH,
96 	PROP_ID_DRIVE_UP_STRENGTH,
97 	PROP_ID_SLEW_RATE_FALLING,
98 	PROP_ID_SLEW_RATE_RISING,
99 	PROP_ID_DRIVE_TYPE,
100 
101 	PROP_ID_MAX_ID
102 };
103 
104 /* Numeric based parameters. */
105 static const struct prop_name {
106 	const char *name;
107 	enum prop_id id;
108 } prop_names[] = {
109 	{"nvidia,pull",			PROP_ID_PULL},
110 	{"nvidia,tristate",		PROP_ID_TRISTATE},
111 	{"nvidia,enable-input",		PROP_ID_ENABLE_INPUT},
112 	{"nvidia,open-drain",		PROP_ID_OPEN_DRAIN},
113 	{"nvidia,lock",			PROP_ID_LOCK},
114 	{"nvidia,io-reset",		PROP_ID_IORESET},
115 	{"nvidia,rcv-sel",		PROP_ID_RCV_SEL},
116 	{"nvidia,io-hv",		PROP_ID_RCV_SEL},
117 	{"nvidia,high-speed-mode",	PROP_ID_HIGH_SPEED_MODE},
118 	{"nvidia,schmitt",		PROP_ID_SCHMITT},
119 	{"nvidia,low-power-mode",	PROP_ID_LOW_POWER_MODE},
120 	{"nvidia,pull-down-strength",	PROP_ID_DRIVE_DOWN_STRENGTH},
121 	{"nvidia,pull-up-strength",	PROP_ID_DRIVE_UP_STRENGTH},
122 	{"nvidia,slew-rate-falling",	PROP_ID_SLEW_RATE_FALLING},
123 	{"nvidia,slew-rate-rising",	PROP_ID_SLEW_RATE_RISING},
124 	{"nvidia,drive-type",		PROP_ID_DRIVE_TYPE},
125 };
126 
127 /*
128  * configuration for one pin group.
129  */
130 struct pincfg {
131 	char	*function;
132 	int	params[PROP_ID_MAX_ID];
133 };
134 #define	GPIO_BANK_A	 0
135 #define	GPIO_BANK_B	 1
136 #define	GPIO_BANK_C	 2
137 #define	GPIO_BANK_D	 3
138 #define	GPIO_BANK_E	 4
139 #define	GPIO_BANK_F	 5
140 #define	GPIO_BANK_G	 6
141 #define	GPIO_BANK_H	 7
142 #define	GPIO_BANK_I	 8
143 #define	GPIO_BANK_J	 9
144 #define	GPIO_BANK_K	10
145 #define	GPIO_BANK_L	11
146 #define	GPIO_BANK_M	12
147 #define	GPIO_BANK_N	13
148 #define	GPIO_BANK_O	14
149 #define	GPIO_BANK_P	15
150 #define	GPIO_BANK_Q	16
151 #define	GPIO_BANK_R	17
152 #define	GPIO_BANK_S	18
153 #define	GPIO_BANK_T	19
154 #define	GPIO_BANK_U	20
155 #define	GPIO_BANK_V	21
156 #define	GPIO_BANK_W	22
157 #define	GPIO_BANK_X	23
158 #define	GPIO_BANK_Y	24
159 #define	GPIO_BANK_Z	25
160 #define	GPIO_BANK_AA	26
161 #define	GPIO_BANK_BB	27
162 #define	GPIO_BANK_CC	28
163 #define	GPIO_BANK_DD	29
164 #define	GPIO_BANK_EE	30
165 #define	GPIO_NUM(b, p) (8 * (b) + (p))
166 
167 struct tegra_grp {
168 	char *name;
169 	bus_size_t reg;
170 	int drvdn_shift;
171 	int drvdn_mask;
172 	int drvup_shift;
173 	int drvup_mask;
174 };
175 
176 #define	GRP(r, nm, dn_s, dn_w, up_s, up_w)				\
177 {									\
178 	.name = #nm,							\
179 	.reg = r - 0x8D4,						\
180 	.drvdn_shift = dn_s,						\
181 	.drvdn_mask = (1 << dn_w) - 1,					\
182 	.drvup_shift = up_s,						\
183 	.drvup_mask = (1 << up_w) - 1,					\
184 }
185 
186 /* Use register offsets from TRM */
187 static const struct tegra_grp pin_grp_tbl[] = {
188 	GRP(0x9c0,    pa6, 12,  5, 20,  5),
189 	GRP(0x9c4,   pcc7, 12,  5, 20,  5),
190 	GRP(0x9c8,    pe6, 12,  5, 20,  5),
191 	GRP(0x9cc,    pe7, 12,  5, 20,  5),
192 	GRP(0x9d0,    ph6, 12,  5, 20,  5),
193 	GRP(0x9d4,    pk0,  0,  0,  0,  0),
194 	GRP(0x9d8,    pk1,  0,  0,  0,  0),
195 	GRP(0x9dc,    pk2,  0,  0,  0,  0),
196 	GRP(0x9e0,    pk3,  0,  0,  0,  0),
197 	GRP(0x9e4,    pk4,  0,  0,  0,  0),
198 	GRP(0x9e8,    pk5,  0,  0,  0,  0),
199 	GRP(0x9ec,    pk6,  0,  0,  0,  0),
200 	GRP(0x9f0,    pk7,  0,  0,  0,  0),
201 	GRP(0x9f4,    pl0,  0,  0,  0,  0),
202 	GRP(0x9f8,    pl1,  0,  0,  0,  0),
203 	GRP(0x9fc,    pz0, 12,  7, 20,  7),
204 	GRP(0xa00,    pz1, 12,  7, 20,  7),
205 	GRP(0xa04,    pz2, 12,  7, 20,  7),
206 	GRP(0xa08,    pz3, 12,  7, 20,  7),
207 	GRP(0xa0c,    pz4, 12,  7, 20,  7),
208 	GRP(0xa10,    pz5, 12,  7, 20,  7),
209 	GRP(0xa98, sdmmc1, 12,  7, 20,  7),
210 	GRP(0xa9c, sdmmc2,  2,  6,  8,  6),
211 	GRP(0xab0, sdmmc3, 12,  7, 20,  7),
212 	GRP(0xab4, sdmmc4,  2,  6,  8,  6),
213 };
214 
215 struct tegra_mux {
216 	struct tegra_grp grp;
217 	char *name;
218 	bus_size_t reg;
219 	char *functions[4];
220 	int gpio_num;
221 
222 };
223 
224 #define	GMUX(r, gb, gi, nm, f1, f2, f3, f4, gr, dn_s, dn_w, up_s, up_w)	\
225 {									\
226 	.name = #nm,							\
227 	.reg = r,							\
228 	.gpio_num = GPIO_NUM(GPIO_BANK_##gb, gi),			\
229 	.functions = {#f1, #f2, #f3, #f4},				\
230 	.grp.name = #nm,						\
231 	.grp.reg = gr - 0x8D4,						\
232 	.grp.drvdn_shift = dn_s,					\
233 	.grp.drvdn_mask = (1 << dn_w) - 1,				\
234 	.grp.drvup_shift = up_s,					\
235 	.grp.drvup_mask = (1 << up_w) - 1,				\
236 }
237 
238 #define	FMUX(r, nm, f1, f2, f3, f4, gr, dn_s, dn_w, up_s, up_w)		\
239 {									\
240 	.name = #nm,							\
241 	.reg = r,							\
242 	.gpio_num = -1,							\
243 	.functions = {#f1, #f2, #f3, #f4},				\
244 	.grp.name = #nm,						\
245 	.grp.reg = gr - 0x8D4,						\
246 	.grp.drvdn_shift = dn_s,					\
247 	.grp.drvdn_mask = (1 << dn_w) - 1,				\
248 	.grp.drvup_shift = up_s,					\
249 	.grp.drvup_mask = (1 << up_w) - 1,				\
250 }
251 
252 static const struct tegra_mux pin_mux_tbl[] = {
253 	GMUX(0x000,  M, 0, sdmmc1_clk_pm0,       sdmmc1,  rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
254 	GMUX(0x004,  M, 1, sdmmc1_cmd_pm1,       sdmmc1,   spi3, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
255 	GMUX(0x008,  M, 2, sdmmc1_dat3_pm2,      sdmmc1,   spi3, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
256 	GMUX(0x00c,  M, 3, sdmmc1_dat2_pm3,      sdmmc1,   spi3, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
257 	GMUX(0x010,  M, 4, sdmmc1_dat1_pm4,      sdmmc1,   spi3, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
258 	GMUX(0x014,  M, 5, sdmmc1_dat0_pm5,      sdmmc1,  rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
259 	GMUX(0x01c,  P, 0, sdmmc3_clk_pp0,       sdmmc3,  rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
260 	GMUX(0x020,  P, 1, sdmmc3_cmd_pp1,       sdmmc3,  rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
261 	GMUX(0x024,  P, 5, sdmmc3_dat0_pp5,      sdmmc3,  rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
262 	GMUX(0x028,  P, 4, sdmmc3_dat1_pp4,      sdmmc3,  rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
263 	GMUX(0x02c,  P, 3, sdmmc3_dat2_pp3,      sdmmc3,  rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
264 	GMUX(0x030,  P, 2, sdmmc3_dat3_pp2,      sdmmc3,  rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
265 	GMUX(0x038,  A, 0, pex_l0_rst_n_pa0,        pe0,  rsvd1, rsvd2, rsvd3,   0xa5c, 12,  5, 20,  5),
266 	GMUX(0x03c,  A, 1, pex_l0_clkreq_n_pa1,     pe0,  rsvd1, rsvd2, rsvd3,   0xa58, 12,  5, 20,  5),
267 	GMUX(0x040,  A, 2, pex_wake_n_pa2,           pe,  rsvd1, rsvd2, rsvd3,   0xa68, 12,  5, 20,  5),
268 	GMUX(0x044,  A, 3, pex_l1_rst_n_pa3,        pe1,  rsvd1, rsvd2, rsvd3,   0xa64, 12,  5, 20,  5),
269 	GMUX(0x048,  A, 4, pex_l1_clkreq_n_pa4,     pe1,  rsvd1, rsvd2, rsvd3,   0xa60, 12,  5, 20,  5),
270 	GMUX(0x04c,  A, 5, sata_led_active_pa5,    sata,  rsvd1, rsvd2, rsvd3,   0xa94, 12,  5, 20,  5),
271 	GMUX(0x050,  C, 0, spi1_mosi_pc0,          spi1,  rsvd1, rsvd2, rsvd3,   0xae0,  0,  0,  0,  0),
272 	GMUX(0x054,  C, 1, spi1_miso_pc1,          spi1,  rsvd1, rsvd2, rsvd3,   0xadc,  0,  0,  0,  0),
273 	GMUX(0x058,  C, 2, spi1_sck_pc2,           spi1,  rsvd1, rsvd2, rsvd3,   0xae4,  0,  0,  0,  0),
274 	GMUX(0x05c,  C, 3, spi1_cs0_pc3,           spi1,  rsvd1, rsvd2, rsvd3,   0xad4,  0,  0,  0,  0),
275 	GMUX(0x060,  C, 4, spi1_cs1_pc4,           spi1,  rsvd1, rsvd2, rsvd3,   0xad8,  0,  0,  0,  0),
276 	GMUX(0x064,  B, 4, spi2_mosi_pb4,          spi2,    dtv, rsvd2, rsvd3,   0xaf4,  0,  0,  0,  0),
277 	GMUX(0x068,  B, 5, spi2_miso_pb5,          spi2,    dtv, rsvd2, rsvd3,   0xaf0,  0,  0,  0,  0),
278 	GMUX(0x06c,  B, 6, spi2_sck_pb6,           spi2,    dtv, rsvd2, rsvd3,   0xaf8,  0,  0,  0,  0),
279 	GMUX(0x070,  B, 7, spi2_cs0_pb7,           spi2,    dtv, rsvd2, rsvd3,   0xae8,  0,  0,  0,  0),
280 	GMUX(0x074, DD, 0, spi2_cs1_pdd0,          spi2,  rsvd1, rsvd2, rsvd3,   0xaec,  0,  0,  0,  0),
281 	GMUX(0x078,  C, 7, spi4_mosi_pc7,          spi4,  rsvd1, rsvd2, rsvd3,   0xb04,  0,  0,  0,  0),
282 	GMUX(0x07c,  D, 0, spi4_miso_pd0,          spi4,  rsvd1, rsvd2, rsvd3,   0xb00,  0,  0,  0,  0),
283 	GMUX(0x080,  C, 5, spi4_sck_pc5,           spi4,  rsvd1, rsvd2, rsvd3,   0xb08,  0,  0,  0,  0),
284 	GMUX(0x084,  C, 6, spi4_cs0_pc6,           spi4,  rsvd1, rsvd2, rsvd3,   0xafc,  0,  0,  0,  0),
285 	GMUX(0x088, EE, 0, qspi_sck_pee0,          qspi,  rsvd1, rsvd2, rsvd3,   0xa90,  0,  0,  0,  0),
286 	GMUX(0x08c, EE, 1, qspi_cs_n_pee1,         qspi,  rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
287 	GMUX(0x090, EE, 2, qspi_io0_pee2,          qspi,  rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
288 	GMUX(0x094, EE, 3, qspi_io1_pee3,          qspi,  rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
289 	GMUX(0x098, EE, 4, qspi_io2_pee4,          qspi,  rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
290 	GMUX(0x09c, EE, 5, qspi_io3_pee5,          qspi,  rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
291 	GMUX(0x0a4,  E, 0, dmic1_clk_pe0,         dmic1,   i2s3, rsvd2, rsvd3,   0x984, 12,  5, 20,  5),
292 	GMUX(0x0a8,  E, 1, dmic1_dat_pe1,         dmic1,   i2s3, rsvd2, rsvd3,   0x988, 12,  5, 20,  5),
293 	GMUX(0x0ac,  E, 2, dmic2_clk_pe2,         dmic2,   i2s3, rsvd2, rsvd3,   0x98c, 12,  5, 20,  5),
294 	GMUX(0x0b0,  E, 3, dmic2_dat_pe3,         dmic2,   i2s3, rsvd2, rsvd3,   0x990, 12,  5, 20,  5),
295 	GMUX(0x0b4,  E, 4, dmic3_clk_pe4,         dmic3,  i2s5a, rsvd2, rsvd3,   0x994, 12,  5, 20,  5),
296 	GMUX(0x0b8,  E, 5, dmic3_dat_pe5,         dmic3,  i2s5a, rsvd2, rsvd3,   0x998, 12,  5, 20,  5),
297 	GMUX(0x0bc,  J, 1, gen1_i2c_scl_pj1,       i2c1,  rsvd1, rsvd2, rsvd3,   0x9a8, 12,  5, 20,  5),
298 	GMUX(0x0c0,  J, 0, gen1_i2c_sda_pj0,       i2c1,  rsvd1, rsvd2, rsvd3,   0x9ac, 12,  5, 20,  5),
299 	GMUX(0x0c4,  J, 2, gen2_i2c_scl_pj2,       i2c2,  rsvd1, rsvd2, rsvd3,   0x9b0, 12,  5, 20,  5),
300 	GMUX(0x0c8,  J, 3, gen2_i2c_sda_pj3,       i2c2,  rsvd1, rsvd2, rsvd3,   0x9b4, 12,  5, 20,  5),
301 	GMUX(0x0cc,  F, 0, gen3_i2c_scl_pf0,       i2c3,  rsvd1, rsvd2, rsvd3,   0x9b8, 12,  5, 20,  5),
302 	GMUX(0x0d0,  F, 1, gen3_i2c_sda_pf1,       i2c3,  rsvd1, rsvd2, rsvd3,   0x9bc, 12,  5, 20,  5),
303 	GMUX(0x0d4,  S, 2, cam_i2c_scl_ps2,        i2c3,  i2cvi, rsvd2, rsvd3,   0x934, 12,  5, 20,  5),
304 	GMUX(0x0d8,  S, 3, cam_i2c_sda_ps3,        i2c3,  i2cvi, rsvd2, rsvd3,   0x938, 12,  5, 20,  5),
305 	GMUX(0x0dc,  Y, 3, pwr_i2c_scl_py3,      i2cpmu,  rsvd1, rsvd2, rsvd3,   0xa6c, 12,  5, 20,  5),
306 	GMUX(0x0e0,  Y, 4, pwr_i2c_sda_py4,      i2cpmu,  rsvd1, rsvd2, rsvd3,   0xa70, 12,  5, 20,  5),
307 	GMUX(0x0e4,  U, 0, uart1_tx_pu0,          uarta,  rsvd1, rsvd2, rsvd3,   0xb28, 12,  5, 20,  5),
308 	GMUX(0x0e8,  U, 1, uart1_rx_pu1,          uarta,  rsvd1, rsvd2, rsvd3,   0xb24, 12,  5, 20,  5),
309 	GMUX(0x0ec,  U, 2, uart1_rts_pu2,         uarta,  rsvd1, rsvd2, rsvd3,   0xb20, 12,  5, 20,  5),
310 	GMUX(0x0f0,  U, 3, uart1_cts_pu3,         uarta,  rsvd1, rsvd2, rsvd3,   0xb1c, 12,  5, 20,  5),
311 	GMUX(0x0f4,  G, 0, uart2_tx_pg0,          uartb,  i2s4a, spdif,  uart,   0xb38, 12,  5, 20,  5),
312 	GMUX(0x0f8,  G, 1, uart2_rx_pg1,          uartb,  i2s4a, spdif,  uart,   0xb34, 12,  5, 20,  5),
313 	GMUX(0x0fc,  G, 2, uart2_rts_pg2,         uartb,  i2s4a, rsvd2,  uart,   0xb30, 12,  5, 20,  5),
314 	GMUX(0x100,  G, 3, uart2_cts_pg3,         uartb,  i2s4a, rsvd2,  uart,   0xb2c, 12,  5, 20,  5),
315 	GMUX(0x104,  D, 1, uart3_tx_pd1,          uartc,   spi4, rsvd2, rsvd3,   0xb48, 12,  5, 20,  5),
316 	GMUX(0x108,  D, 2, uart3_rx_pd2,          uartc,   spi4, rsvd2, rsvd3,   0xb44, 12,  5, 20,  5),
317 	GMUX(0x10c,  D, 3, uart3_rts_pd3,         uartc,   spi4, rsvd2, rsvd3,   0xb40, 12,  5, 20,  5),
318 	GMUX(0x110,  D, 4, uart3_cts_pd4,         uartc,   spi4, rsvd2, rsvd3,   0xb3c, 12,  5, 20,  5),
319 	GMUX(0x114,  I, 4, uart4_tx_pi4,          uartd,   uart, rsvd2, rsvd3,   0xb58, 12,  5, 20,  5),
320 	GMUX(0x118,  I, 5, uart4_rx_pi5,          uartd,   uart, rsvd2, rsvd3,   0xb54, 12,  5, 20,  5),
321 	GMUX(0x11c,  I, 6, uart4_rts_pi6,         uartd,   uart, rsvd2, rsvd3,   0xb50, 12,  5, 20,  5),
322 	GMUX(0x120,  I, 7, uart4_cts_pi7,         uartd,   uart, rsvd2, rsvd3,   0xb4c, 12,  5, 20,  5),
323 	GMUX(0x124,  B, 0, dap1_fs_pb0,            i2s1,  rsvd1, rsvd2, rsvd3,   0x95c,  0,  0,  0,  0),
324 	GMUX(0x128,  B, 1, dap1_din_pb1,           i2s1,  rsvd1, rsvd2, rsvd3,   0x954,  0,  0,  0,  0),
325 	GMUX(0x12c,  B, 2, dap1_dout_pb2,          i2s1,  rsvd1, rsvd2, rsvd3,   0x958,  0,  0,  0,  0),
326 	GMUX(0x130,  B, 3, dap1_sclk_pb3,          i2s1,  rsvd1, rsvd2, rsvd3,   0x960,  0,  0,  0,  0),
327 	GMUX(0x134, AA, 0, dap2_fs_paa0,           i2s2,  rsvd1, rsvd2, rsvd3,   0x96c,  0,  0,  0,  0),
328 	GMUX(0x138, AA, 2, dap2_din_paa2,          i2s2,  rsvd1, rsvd2, rsvd3,   0x964,  0,  0,  0,  0),
329 	GMUX(0x13c, AA, 3, dap2_dout_paa3,         i2s2,  rsvd1, rsvd2, rsvd3,   0x968,  0,  0,  0,  0),
330 	GMUX(0x140, AA, 1, dap2_sclk_paa1,         i2s2,  rsvd1, rsvd2, rsvd3,   0x970,  0,  0,  0,  0),
331 	GMUX(0x144,  J, 4, dap4_fs_pj4,           i2s4b,  rsvd1, rsvd2, rsvd3,   0x97c, 12,  5, 20,  5),
332 	GMUX(0x148,  J, 5, dap4_din_pj5,          i2s4b,  rsvd1, rsvd2, rsvd3,   0x974, 12,  5, 20,  5),
333 	GMUX(0x14c,  J, 6, dap4_dout_pj6,         i2s4b,  rsvd1, rsvd2, rsvd3,   0x978, 12,  5, 20,  5),
334 	GMUX(0x150,  J, 7, dap4_sclk_pj7,         i2s4b,  rsvd1, rsvd2, rsvd3,   0x980, 12,  5, 20,  5),
335 	GMUX(0x154,  S, 0, cam1_mclk_ps0,    extperiph3,  rsvd1, rsvd2, rsvd3,   0x918, 12,  5, 20,  5),
336 	GMUX(0x158,  S, 1, cam2_mclk_ps1,    extperiph3,  rsvd1, rsvd2, rsvd3,   0x924, 12,  5, 20,  5),
337 	FMUX(0x15c,        jtag_rtck,              jtag,  rsvd1, rsvd2, rsvd3,   0xa2c, 12,  5, 20,  5),
338 	FMUX(0x160,        clk_32k_in,              clk,  rsvd1, rsvd2, rsvd3,   0x940, 12,  5, 20,  5),
339 	GMUX(0x164,  Y, 5, clk_32k_out_py5,         soc,  blink, rsvd2, rsvd3,   0x944, 12,  5, 20,  5),
340 	FMUX(0x168,        batt_bcl,                bcl,  rsvd1, rsvd2, rsvd3,   0x8f8, 12,  5, 20,  5),
341 	FMUX(0x16c,        clk_req,                 sys,  rsvd1, rsvd2, rsvd3,   0x948, 12,  5, 20,  5),
342 	FMUX(0x170,        cpu_pwr_req,             cpu,  rsvd1, rsvd2, rsvd3,   0x950, 12,  5, 20,  5),
343 	FMUX(0x174,        pwr_int_n,               pmi,  rsvd1, rsvd2, rsvd3,   0xa74, 12,  5, 20,  5),
344 	FMUX(0x178,        shutdown,           shutdown,  rsvd1, rsvd2, rsvd3,   0xac8, 12,  5, 20,  5),
345 	FMUX(0x17c,        core_pwr_req,           core,  rsvd1, rsvd2, rsvd3,   0x94c, 12,  5, 20,  5),
346 	GMUX(0x180, BB, 0, aud_mclk_pbb0,           aud,  rsvd1, rsvd2, rsvd3,   0x8f4, 12,  5, 20,  5),
347 	GMUX(0x184, BB, 1, dvfs_pwm_pbb1,         rsvd0, cldvfs,  spi3, rsvd3,   0x9a4, 12,  5, 20,  5),
348 	GMUX(0x188, BB, 2, dvfs_clk_pbb2,         rsvd0, cldvfs,  spi3, rsvd3,   0x9a0, 12,  5, 20,  5),
349 	GMUX(0x18c, BB, 3, gpio_x1_aud_pbb3,      rsvd0,  rsvd1,  spi3, rsvd3,   0xa14, 12,  5, 20,  5),
350 	GMUX(0x190, BB, 4, gpio_x3_aud_pbb4,      rsvd0,  rsvd1,  spi3, rsvd3,   0xa18, 12,  5, 20,  5),
351 	GMUX(0x194, CC, 7, pcc7,                  rsvd0,  rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
352 	GMUX(0x198, CC, 0, hdmi_cec_pcc0,           cec,  rsvd1, rsvd2, rsvd3,   0xa24, 12,  5, 20,  5),
353 	GMUX(0x19c, CC, 1, hdmi_int_dp_hpd_pcc1,     dp,  rsvd1, rsvd2, rsvd3,   0xa28, 12,  5, 20,  5),
354 	GMUX(0x1a0, CC, 2, spdif_out_pcc2,        spdif,  rsvd1, rsvd2, rsvd3,   0xad0, 12,  5, 20,  5),
355 	GMUX(0x1a4, CC, 3, spdif_in_pcc3,         spdif,  rsvd1, rsvd2, rsvd3,   0xacc, 12,  5, 20,  5),
356 	GMUX(0x1a8, CC, 4, usb_vbus_en0_pcc4,       usb,  rsvd1, rsvd2, rsvd3,   0xb5c, 12,  5, 20,  5),
357 	GMUX(0x1ac, CC, 5, usb_vbus_en1_pcc5,       usb,  rsvd1, rsvd2, rsvd3,   0xb60, 12,  5, 20,  5),
358 	GMUX(0x1b0, CC, 6, dp_hpd0_pcc6,             dp,  rsvd1, rsvd2, rsvd3,   0x99c, 12,  5, 20,  5),
359 	GMUX(0x1b4,  H, 0, wifi_en_ph0,           rsvd0,  rsvd1, rsvd2, rsvd3,   0xb64, 12,  5, 20,  5),
360 	GMUX(0x1b8,  H, 1, wifi_rst_ph1,          rsvd0,  rsvd1, rsvd2, rsvd3,   0xb68, 12,  5, 20,  5),
361 	GMUX(0x1bc,  H, 2, wifi_wake_ap_ph2,      rsvd0,  rsvd1, rsvd2, rsvd3,   0xb6c, 12,  5, 20,  5),
362 	GMUX(0x1c0,  H, 3, ap_wake_bt_ph3,        rsvd0,  uartb, spdif, rsvd3,   0x8ec, 12,  5, 20,  5),
363 	GMUX(0x1c4,  H, 4, bt_rst_ph4,            rsvd0,  uartb, spdif, rsvd3,   0x8fc, 12,  5, 20,  5),
364 	GMUX(0x1c8,  H, 5, bt_wake_ap_ph5,        rsvd0,  rsvd1, rsvd2, rsvd3,   0x900, 12,  5, 20,  5),
365 	GMUX(0x1cc,  H, 7, ap_wake_nfc_ph7,       rsvd0,  rsvd1, rsvd2, rsvd3,   0x8f0, 12,  5, 20,  5),
366 	GMUX(0x1d0,  I, 0, nfc_en_pi0,            rsvd0,  rsvd1, rsvd2, rsvd3,   0xa50, 12,  5, 20,  5),
367 	GMUX(0x1d4,  I, 1, nfc_int_pi1,           rsvd0,  rsvd1, rsvd2, rsvd3,   0xa54, 12,  5, 20,  5),
368 	GMUX(0x1d8,  I, 2, gps_en_pi2,            rsvd0,  rsvd1, rsvd2, rsvd3,   0xa1c, 12,  5, 20,  5),
369 	GMUX(0x1dc,  I, 3, gps_rst_pi3,           rsvd0,  rsvd1, rsvd2, rsvd3,   0xa20, 12,  5, 20,  5),
370 	GMUX(0x1e0,  S, 4, cam_rst_ps4,            vgp1,  rsvd1, rsvd2, rsvd3,   0x93c, 12,  5, 20,  5),
371 	GMUX(0x1e4,  S, 5, cam_af_en_ps5,        vimclk,   vgp2, rsvd2, rsvd3,   0x92c, 12,  5, 20,  5),
372 	GMUX(0x1e8,  S, 6, cam_flash_en_ps6,     vimclk,   vgp3, rsvd2, rsvd3,   0x930, 12,  5, 20,  5),
373 	GMUX(0x1ec,  S, 7, cam1_pwdn_ps7,          vgp4,  rsvd1, rsvd2, rsvd3,   0x91c, 12,  5, 20,  5),
374 	GMUX(0x1f0,  T, 0, cam2_pwdn_pt0,          vgp5,  rsvd1, rsvd2, rsvd3,   0x928, 12,  5, 20,  5),
375 	GMUX(0x1f4,  T, 1, cam1_strobe_pt1,        vgp6,  rsvd1, rsvd2, rsvd3,   0x920, 12,  5, 20,  5),
376 	GMUX(0x1f8,  Y, 2, lcd_te_py2,         displaya,  rsvd1, rsvd2, rsvd3,   0xa44, 12,  5, 20,  5),
377 	GMUX(0x1fc,  V, 0, lcd_bl_pwm_pv0,     displaya,   pwm0,  sor0, rsvd3,   0xa34, 12,  5, 20,  5),
378 	GMUX(0x200,  V, 1, lcd_bl_en_pv1,         rsvd0,  rsvd1, rsvd2, rsvd3,   0xa30, 12,  5, 20,  5),
379 	GMUX(0x204,  V, 2, lcd_rst_pv2,           rsvd0,  rsvd1, rsvd2, rsvd3,   0xa40, 12,  5, 20,  5),
380 	GMUX(0x208,  V, 3, lcd_gpio1_pv3,      displayb,  rsvd1, rsvd2, rsvd3,   0xa38, 12,  5, 20,  5),
381 	GMUX(0x20c,  V, 4, lcd_gpio2_pv4,      displayb,   pwm1, rsvd2,  sor1,   0xa3c, 12,  5, 20,  5),
382 	GMUX(0x210,  V, 5, ap_ready_pv5,          rsvd0,  rsvd1, rsvd2, rsvd3,   0x8e8, 12,  5, 20,  5),
383 	GMUX(0x214,  V, 6, touch_rst_pv6,         rsvd0,  rsvd1, rsvd2, rsvd3,   0xb18, 12,  5, 20,  5),
384 	GMUX(0x218,  V, 7, touch_clk_pv7,         touch,  rsvd1, rsvd2, rsvd3,   0xb10, 12,  5, 20,  5),
385 	GMUX(0x21c,  X, 0, modem_wake_ap_px0,     rsvd0,  rsvd1, rsvd2, rsvd3,   0xa48, 12,  5, 20,  5),
386 	GMUX(0x220,  X, 1, touch_int_px1,         rsvd0,  rsvd1, rsvd2, rsvd3,   0xb14, 12,  5, 20,  5),
387 	GMUX(0x224,  X, 2, motion_int_px2,        rsvd0,  rsvd1, rsvd2, rsvd3,   0xa4c, 12,  5, 20,  5),
388 	GMUX(0x228,  X, 3, als_prox_int_px3,      rsvd0,  rsvd1, rsvd2, rsvd3,   0x8e4, 12,  5, 20,  5),
389 	GMUX(0x22c,  X, 4, temp_alert_px4,        rsvd0,  rsvd1, rsvd2, rsvd3,   0xb0c, 12,  5, 20,  5),
390 	GMUX(0x230,  X, 5, button_power_on_px5,   rsvd0,  rsvd1, rsvd2, rsvd3,   0x908, 12,  5, 20,  5),
391 	GMUX(0x234,  X, 6, button_vol_up_px6,     rsvd0,  rsvd1, rsvd2, rsvd3,   0x914, 12,  5, 20,  5),
392 	GMUX(0x238,  X, 7, button_vol_down_px7,   rsvd0,  rsvd1, rsvd2, rsvd3,   0x910, 12,  5, 20,  5),
393 	GMUX(0x23c,  Y, 0, button_slide_sw_py0,   rsvd0,  rsvd1, rsvd2, rsvd3,   0x90c, 12,  5, 20,  5),
394 	GMUX(0x240,  Y, 1, button_home_py1,       rsvd0,  rsvd1, rsvd2, rsvd3,   0x904, 12,  5, 20,  5),
395 	GMUX(0x244,  A, 6, pa6,                   sata,   rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
396 	GMUX(0x248,  E, 6, pe6,                   rsvd0,  i2s5a,  pwm2, rsvd3,      -1,  0,  0,  0,  0),
397 	GMUX(0x24c,  E, 7, pe7,                   rsvd0,  i2s5a,  pwm3, rsvd3,      -1,  0,  0,  0,  0),
398 	GMUX(0x250,  H, 6, ph6,                   rsvd0,  rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
399 	GMUX(0x254,  K, 0, pk0,                   iqc0,   i2s5b, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
400 	GMUX(0x258,  K, 1, pk1,                   iqc0,   i2s5b, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
401 	GMUX(0x25c,  K, 2, pk2,                   iqc0,   i2s5b, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
402 	GMUX(0x260,  K, 3, pk3,                   iqc0,   i2s5b, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
403 	GMUX(0x264,  K, 4, pk4,                   iqc1,   rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
404 	GMUX(0x268,  K, 5, pk5,                   iqc1,   rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
405 	GMUX(0x26c,  K, 6, pk6,                   iqc1,   rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
406 	GMUX(0x270,  K, 7, pk7,                   iqc1,   rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
407 	GMUX(0x274,  L, 0, pl0,                  rsvd0,   rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
408 	GMUX(0x278,  L, 1, pl1,                    soc,   rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
409 	GMUX(0x27c,  Z, 0, pz0,                vimclk2,   rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
410 	GMUX(0x280,  Z, 1, pz1,                vimclk2,  sdmmc1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
411 	GMUX(0x284,  Z, 2, pz2,                 sdmmc3,    ccla, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
412 	GMUX(0x288,  Z, 3, pz3,                 sdmmc3,   rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
413 	GMUX(0x28c,  Z, 4, pz4,                 sdmmc1,   rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
414 	GMUX(0x290,  Z, 5, pz5,                    soc,   rsvd1, rsvd2, rsvd3,      -1,  0,  0,  0,  0),
415 };
416 
417 
418 static const struct tegra_grp *
419 pinmux_search_grp(char *grp_name)
420 {
421 	int i;
422 
423 	for (i = 0; i < nitems(pin_grp_tbl); i++) {
424 		if (strcmp(grp_name, pin_grp_tbl[i].name) == 0)
425 			return 	(&pin_grp_tbl[i]);
426 	}
427 	return (NULL);
428 }
429 
430 static const struct tegra_mux *
431 pinmux_search_mux(char *pin_name)
432 {
433 	int i;
434 
435 	for (i = 0; i < nitems(pin_mux_tbl); i++) {
436 		if (strcmp(pin_name, pin_mux_tbl[i].name) == 0)
437 			return 	(&pin_mux_tbl[i]);
438 	}
439 	return (NULL);
440 }
441 
442 static int
443 pinmux_mux_function(const struct tegra_mux *mux, char *fnc_name)
444 {
445 	int i;
446 
447 	for (i = 0; i < 4; i++) {
448 		if (strcmp(fnc_name, mux->functions[i]) == 0)
449 			return 	(i);
450 	}
451 	return (-1);
452 }
453 
454 static int
455 pinmux_config_mux(struct pinmux_softc *sc, char *pin_name,
456     const struct tegra_mux *mux, struct pincfg *cfg)
457 {
458 	int tmp;
459 	uint32_t reg;
460 
461 	reg = bus_read_4(sc->mux_mem_res, mux->reg);
462 
463 	if (cfg->function != NULL) {
464 		tmp = pinmux_mux_function(mux, cfg->function);
465 		if (tmp == -1) {
466 			device_printf(sc->dev,
467 			    "Unknown function %s for pin %s\n", cfg->function,
468 			    pin_name);
469 			return (ENXIO);
470 		}
471 		reg &= ~(TEGRA_MUX_FUNCTION_MASK << TEGRA_MUX_FUNCTION_SHIFT);
472 		reg |=  (tmp & TEGRA_MUX_FUNCTION_MASK) <<
473 		    TEGRA_MUX_FUNCTION_SHIFT;
474 	}
475 	if (cfg->params[PROP_ID_PULL] != -1) {
476 		reg &= ~(TEGRA_MUX_PUPD_MASK << TEGRA_MUX_PUPD_SHIFT);
477 		reg |=  (cfg->params[PROP_ID_PULL] & TEGRA_MUX_PUPD_MASK) <<
478 		    TEGRA_MUX_PUPD_SHIFT;
479 	}
480 	if (cfg->params[PROP_ID_TRISTATE] != -1) {
481 		reg &= ~(1 << TEGRA_MUX_TRISTATE_SHIFT);
482 		reg |=  (cfg->params[PROP_ID_TRISTATE] & 1) <<
483 		    TEGRA_MUX_TRISTATE_SHIFT;
484 	}
485 	if (cfg->params[TEGRA_MUX_ENABLE_INPUT_SHIFT] != -1) {
486 		reg &= ~(1 << TEGRA_MUX_ENABLE_INPUT_SHIFT);
487 		reg |=  (cfg->params[TEGRA_MUX_ENABLE_INPUT_SHIFT] & 1) <<
488 		    TEGRA_MUX_ENABLE_INPUT_SHIFT;
489 	}
490 	if (cfg->params[PROP_ID_ENABLE_INPUT] != -1) {
491 		reg &= ~(1 << TEGRA_MUX_ENABLE_INPUT_SHIFT);
492 		reg |=  (cfg->params[PROP_ID_ENABLE_INPUT] & 1) <<
493 		    TEGRA_MUX_ENABLE_INPUT_SHIFT;
494 	}
495 	if (cfg->params[PROP_ID_ENABLE_INPUT] != -1) {
496 		reg &= ~(1 << TEGRA_MUX_ENABLE_INPUT_SHIFT);
497 		reg |=  (cfg->params[PROP_ID_OPEN_DRAIN] & 1) <<
498 		    TEGRA_MUX_ENABLE_INPUT_SHIFT;
499 	}
500 	if (cfg->params[PROP_ID_LOCK] != -1) {
501 		reg &= ~(1 << TEGRA_MUX_LOCK_SHIFT);
502 		reg |=  (cfg->params[PROP_ID_LOCK] & 1) <<
503 		    TEGRA_MUX_LOCK_SHIFT;
504 	}
505 	if (cfg->params[PROP_ID_IORESET] != -1) {
506 		reg &= ~(1 << TEGRA_MUX_IORESET_SHIFT);
507 		reg |=  (cfg->params[PROP_ID_IORESET] & 1) <<
508 		    TEGRA_MUX_IORESET_SHIFT;
509 	}
510 	if (cfg->params[PROP_ID_RCV_SEL] != -1) {
511 		reg &= ~(1 << TEGRA_MUX_RCV_SEL_SHIFT);
512 		reg |=  (cfg->params[PROP_ID_RCV_SEL] & 1) <<
513 		    TEGRA_MUX_RCV_SEL_SHIFT;
514 	}
515 	bus_write_4(sc->mux_mem_res, mux->reg, reg);
516 	return (0);
517 }
518 
519 static int
520 pinmux_config_grp(struct pinmux_softc *sc, char *grp_name,
521     const struct tegra_grp *grp, struct pincfg *cfg)
522 {
523 	uint32_t reg;
524 
525 	reg = bus_read_4(sc->pad_mem_res, grp->reg);
526 
527 	if (cfg->params[PROP_ID_HIGH_SPEED_MODE] != -1) {
528 		reg &= ~(1 << TEGRA_GRP_HSM_SHIFT);
529 		reg |=  (cfg->params[PROP_ID_HIGH_SPEED_MODE] & 1) <<
530 		    TEGRA_GRP_HSM_SHIFT;
531 	}
532 	if (cfg->params[PROP_ID_SCHMITT] != -1) {
533 		reg &= ~(1 << TEGRA_GRP_SCHMT_SHIFT);
534 		reg |=  (cfg->params[PROP_ID_SCHMITT] & 1) <<
535 		    TEGRA_GRP_SCHMT_SHIFT;
536 	}
537 	if (cfg->params[PROP_ID_DRIVE_TYPE] != -1) {
538 		reg &= ~(TEGRA_GRP_DRV_TYPE_MASK << TEGRA_GRP_DRV_TYPE_SHIFT);
539 		reg |=  (cfg->params[PROP_ID_DRIVE_TYPE] &
540 		    TEGRA_GRP_DRV_TYPE_MASK) << TEGRA_GRP_DRV_TYPE_SHIFT;
541 	}
542 	if (cfg->params[PROP_ID_SLEW_RATE_RISING] != -1) {
543 		reg &= ~(TEGRA_GRP_DRV_DRVDN_SLWR_MASK <<
544 		    TEGRA_GRP_DRV_DRVDN_SLWR_SHIFT);
545 		reg |=  (cfg->params[PROP_ID_SLEW_RATE_RISING] &
546 		    TEGRA_GRP_DRV_DRVDN_SLWR_MASK) <<
547 		    TEGRA_GRP_DRV_DRVDN_SLWR_SHIFT;
548 	}
549 	if (cfg->params[PROP_ID_SLEW_RATE_FALLING] != -1) {
550 		reg &= ~(TEGRA_GRP_DRV_DRVUP_SLWF_MASK <<
551 		    TEGRA_GRP_DRV_DRVUP_SLWF_SHIFT);
552 		reg |=  (cfg->params[PROP_ID_SLEW_RATE_FALLING] &
553 		    TEGRA_GRP_DRV_DRVUP_SLWF_MASK) <<
554 		    TEGRA_GRP_DRV_DRVUP_SLWF_SHIFT;
555 	}
556 	if ((cfg->params[PROP_ID_DRIVE_DOWN_STRENGTH] != -1) &&
557 		 (grp->drvdn_mask != 0)) {
558 		reg &= ~(grp->drvdn_shift << grp->drvdn_mask);
559 		reg |=  (cfg->params[PROP_ID_DRIVE_DOWN_STRENGTH] &
560 		    grp->drvdn_mask) << grp->drvdn_shift;
561 	}
562 	if ((cfg->params[PROP_ID_DRIVE_UP_STRENGTH] != -1) &&
563 		 (grp->drvup_mask != 0)) {
564 		reg &= ~(grp->drvup_shift << grp->drvup_mask);
565 		reg |=  (cfg->params[PROP_ID_DRIVE_UP_STRENGTH] &
566 		    grp->drvup_mask) << grp->drvup_shift;
567 	}
568 	bus_write_4(sc->pad_mem_res, grp->reg, reg);
569 	return (0);
570 }
571 
572 static int
573 pinmux_config_node(struct pinmux_softc *sc, char *pin_name, struct pincfg *cfg)
574 {
575 	const struct tegra_mux *mux;
576 	const struct tegra_grp *grp;
577 	bool handled;
578 	int rv;
579 
580 	/* Handle pin muxes */
581 	mux = pinmux_search_mux(pin_name);
582 	handled = false;
583 	if (mux != NULL) {
584 		if (mux->gpio_num != -1) {
585 			/* XXXX TODO: Reserve gpio here */
586 		}
587 		rv = pinmux_config_mux(sc, pin_name, mux, cfg);
588 		if (rv != 0)
589 			return (rv);
590 		if (mux->grp.reg <= 0) {
591 			rv = pinmux_config_grp(sc, pin_name, &mux->grp, cfg);
592 			return (rv);
593 		}
594 		handled = true;
595 	}
596 
597 	/* And/or handle pin groups */
598 	grp = pinmux_search_grp(pin_name);
599 	if (grp != NULL) {
600 		rv = pinmux_config_grp(sc, pin_name, grp, cfg);
601 		if (rv != 0)
602 			return (rv);
603 		handled = true;
604 	}
605 
606 	if (!handled) {
607 		device_printf(sc->dev, "Unknown pin: %s\n", pin_name);
608 		return (ENXIO);
609 	}
610 	return (0);
611 }
612 
613 static int
614 pinmux_read_node(struct pinmux_softc *sc, phandle_t node, struct pincfg *cfg,
615     char **pins, int *lpins)
616 {
617 	int rv, i;
618 
619 	*lpins = OF_getprop_alloc(node, "nvidia,pins", (void **)pins);
620 	if (*lpins <= 0)
621 		return (ENOENT);
622 
623 	/* Read function (mux) settings. */
624 	rv = OF_getprop_alloc(node, "nvidia,function", (void **)&cfg->function);
625 	if (rv <= 0)
626 		cfg->function = NULL;
627 
628 	/* Read numeric properties. */
629 	for (i = 0; i < PROP_ID_MAX_ID; i++) {
630 		rv = OF_getencprop(node, prop_names[i].name, &cfg->params[i],
631 		    sizeof(cfg->params[i]));
632 		if (rv <= 0)
633 			cfg->params[i] = -1;
634 	}
635 	return (0);
636 }
637 
638 static int
639 pinmux_process_node(struct pinmux_softc *sc, phandle_t node)
640 {
641 	struct pincfg cfg;
642 	char *pins, *pname;
643 	int i, len, lpins, rv;
644 
645 	rv = pinmux_read_node(sc, node, &cfg, &pins, &lpins);
646 	if (rv != 0)
647 		return (rv);
648 
649 	len = 0;
650 	pname = pins;
651 	do {
652 		i = strlen(pname) + 1;
653 		rv = pinmux_config_node(sc, pname, &cfg);
654 		if (rv != 0)
655 			device_printf(sc->dev, "Cannot configure pin: %s: %d\n",
656 			    pname, rv);
657 		len += i;
658 		pname += i;
659 	} while (len < lpins);
660 
661 	if (pins != NULL)
662 		OF_prop_free(pins);
663 	if (cfg.function != NULL)
664 		OF_prop_free(cfg.function);
665 	return (rv);
666 }
667 
668 static int pinmux_configure(device_t dev, phandle_t cfgxref)
669 {
670 	struct pinmux_softc *sc;
671 	phandle_t node, cfgnode;
672 
673 	sc = device_get_softc(dev);
674 	cfgnode = OF_node_from_xref(cfgxref);
675 
676 
677 	for (node = OF_child(cfgnode); node != 0; node = OF_peer(node)) {
678 		if (!ofw_bus_node_status_okay(node))
679 			continue;
680 		pinmux_process_node(sc, node);
681 	}
682 	return (0);
683 }
684 
685 static int
686 pinmux_probe(device_t dev)
687 {
688 
689 	if (!ofw_bus_status_okay(dev))
690 		return (ENXIO);
691 
692 	if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
693 		return (ENXIO);
694 
695 	device_set_desc(dev, "Tegra pin configuration");
696 	return (BUS_PROBE_DEFAULT);
697 }
698 
699 static int
700 pinmux_detach(device_t dev)
701 {
702 
703 	/* This device is always present. */
704 	return (EBUSY);
705 }
706 
707 static int
708 pinmux_attach(device_t dev)
709 {
710 	struct pinmux_softc * sc;
711 	int rid;
712 
713 	sc = device_get_softc(dev);
714 	sc->dev = dev;
715 
716 	rid = 0;
717 	sc->pad_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
718 	    RF_ACTIVE);
719 	if (sc->pad_mem_res == NULL) {
720 		device_printf(dev, "Cannot allocate memory resources\n");
721 		return (ENXIO);
722 	}
723 
724 	rid = 1;
725 	sc->mux_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
726 	    RF_ACTIVE);
727 	if (sc->mux_mem_res == NULL) {
728 		device_printf(dev, "Cannot allocate memory resources\n");
729 		return (ENXIO);
730 	}
731 
732 
733 	/* Register as a pinctrl device and process default configuration */
734 	fdt_pinctrl_register(dev, NULL);
735 	fdt_pinctrl_configure_by_name(dev, "boot");
736 
737 	return (0);
738 }
739 
740 
741 static device_method_t tegra210_pinmux_methods[] = {
742 	/* Device interface */
743 	DEVMETHOD(device_probe,         pinmux_probe),
744 	DEVMETHOD(device_attach,        pinmux_attach),
745 	DEVMETHOD(device_detach,        pinmux_detach),
746 
747 	/* fdt_pinctrl interface */
748 	DEVMETHOD(fdt_pinctrl_configure,pinmux_configure),
749 
750 	DEVMETHOD_END
751 };
752 
753 static DEFINE_CLASS_0(pinmux, tegra210_pinmux_driver, tegra210_pinmux_methods,
754     sizeof(struct pinmux_softc));
755 EARLY_DRIVER_MODULE(tegra210_pinmux, simplebus, tegra210_pinmux_driver,
756     NULL, NULL, 71);
757