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
71struct pinmux_softc {
72	device_t	dev;
73	struct resource	*pad_mem_res;
74	struct resource	*mux_mem_res;
75};
76
77static struct ofw_compat_data compat_data[] = {
78	{"nvidia,tegra210-pinmux",	1},
79	{NULL,				0},
80};
81
82enum 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. */
103static 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 */
128struct 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
165struct 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 */
185static 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
213struct 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
250static 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
416static const struct tegra_grp *
417pinmux_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
428static const struct tegra_mux *
429pinmux_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
440static int
441pinmux_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
452static int
453pinmux_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
517static int
518pinmux_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
570static int
571pinmux_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
611static int
612pinmux_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
636static int
637pinmux_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
666static 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
683static int
684pinmux_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
697static int
698pinmux_detach(device_t dev)
699{
700
701	/* This device is always present. */
702	return (EBUSY);
703}
704
705static int
706pinmux_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
739static 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
751static DEFINE_CLASS_0(pinmux, tegra210_pinmux_driver, tegra210_pinmux_methods,
752    sizeof(struct pinmux_softc));
753EARLY_DRIVER_MODULE(tegra210_pinmux, simplebus, tegra210_pinmux_driver,
754    NULL, NULL, 71);
755