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