]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
e2969957 SW |
2 | /* |
3 | * Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved. | |
4 | * Copyright (c) 2011 The Chromium OS Authors. | |
e2969957 SW |
5 | */ |
6 | ||
d678a59d | 7 | #include <common.h> |
f7ae49fc | 8 | #include <log.h> |
e2969957 SW |
9 | #include <asm/io.h> |
10 | #include <asm/arch/pinmux.h> | |
11 | ||
12 | /* return 1 if a pingrp is in range */ | |
dfb42fc9 | 13 | #define pmux_pingrp_isvalid(pin) (((pin) >= 0) && ((pin) < PMUX_PINGRP_COUNT)) |
e2969957 SW |
14 | |
15 | /* return 1 if a pmux_func is in range */ | |
16 | #define pmux_func_isvalid(func) \ | |
d381294a | 17 | (((func) >= 0) && ((func) < PMUX_FUNC_COUNT)) |
e2969957 SW |
18 | |
19 | /* return 1 if a pin_pupd_is in range */ | |
20 | #define pmux_pin_pupd_isvalid(pupd) \ | |
21 | (((pupd) >= PMUX_PULL_NORMAL) && ((pupd) <= PMUX_PULL_UP)) | |
22 | ||
23 | /* return 1 if a pin_tristate_is in range */ | |
24 | #define pmux_pin_tristate_isvalid(tristate) \ | |
25 | (((tristate) >= PMUX_TRI_NORMAL) && ((tristate) <= PMUX_TRI_TRISTATE)) | |
26 | ||
7a28441f | 27 | #ifdef TEGRA_PMX_PINS_HAVE_E_INPUT |
e2969957 SW |
28 | /* return 1 if a pin_io_is in range */ |
29 | #define pmux_pin_io_isvalid(io) \ | |
30 | (((io) >= PMUX_PIN_OUTPUT) && ((io) <= PMUX_PIN_INPUT)) | |
7a28441f | 31 | #endif |
e2969957 | 32 | |
7a28441f | 33 | #ifdef TEGRA_PMX_PINS_HAVE_LOCK |
e2969957 SW |
34 | /* return 1 if a pin_lock is in range */ |
35 | #define pmux_pin_lock_isvalid(lock) \ | |
36 | (((lock) >= PMUX_PIN_LOCK_DISABLE) && ((lock) <= PMUX_PIN_LOCK_ENABLE)) | |
7a28441f | 37 | #endif |
e2969957 | 38 | |
7a28441f | 39 | #ifdef TEGRA_PMX_PINS_HAVE_OD |
e2969957 SW |
40 | /* return 1 if a pin_od is in range */ |
41 | #define pmux_pin_od_isvalid(od) \ | |
42 | (((od) >= PMUX_PIN_OD_DISABLE) && ((od) <= PMUX_PIN_OD_ENABLE)) | |
7a28441f | 43 | #endif |
e2969957 | 44 | |
7a28441f | 45 | #ifdef TEGRA_PMX_PINS_HAVE_IO_RESET |
e2969957 SW |
46 | /* return 1 if a pin_ioreset_is in range */ |
47 | #define pmux_pin_ioreset_isvalid(ioreset) \ | |
48 | (((ioreset) >= PMUX_PIN_IO_RESET_DISABLE) && \ | |
49 | ((ioreset) <= PMUX_PIN_IO_RESET_ENABLE)) | |
7a28441f | 50 | #endif |
e2969957 | 51 | |
7a28441f | 52 | #ifdef TEGRA_PMX_PINS_HAVE_RCV_SEL |
e2969957 SW |
53 | /* return 1 if a pin_rcv_sel_is in range */ |
54 | #define pmux_pin_rcv_sel_isvalid(rcv_sel) \ | |
55 | (((rcv_sel) >= PMUX_PIN_RCV_SEL_NORMAL) && \ | |
56 | ((rcv_sel) <= PMUX_PIN_RCV_SEL_HIGH)) | |
7a28441f | 57 | #endif |
e2969957 | 58 | |
f4d7c9dd SW |
59 | #ifdef TEGRA_PMX_PINS_HAVE_E_IO_HV |
60 | /* return 1 if a pin_e_io_hv is in range */ | |
61 | #define pmux_pin_e_io_hv_isvalid(e_io_hv) \ | |
62 | (((e_io_hv) >= PMUX_PIN_E_IO_HV_NORMAL) && \ | |
63 | ((e_io_hv) <= PMUX_PIN_E_IO_HV_HIGH)) | |
64 | #endif | |
65 | ||
bc134728 SW |
66 | #ifdef TEGRA_PMX_GRPS_HAVE_LPMD |
67 | #define pmux_lpmd_isvalid(lpm) \ | |
68 | (((lpm) >= PMUX_LPMD_X8) && ((lpm) <= PMUX_LPMD_X)) | |
69 | #endif | |
70 | ||
f2c60eed | 71 | #if defined(TEGRA_PMX_PINS_HAVE_SCHMT) || defined(TEGRA_PMX_GRPS_HAVE_SCHMT) |
bc134728 SW |
72 | #define pmux_schmt_isvalid(schmt) \ |
73 | (((schmt) >= PMUX_SCHMT_DISABLE) && ((schmt) <= PMUX_SCHMT_ENABLE)) | |
74 | #endif | |
75 | ||
f2c60eed | 76 | #if defined(TEGRA_PMX_PINS_HAVE_HSM) || defined(TEGRA_PMX_GRPS_HAVE_HSM) |
bc134728 SW |
77 | #define pmux_hsm_isvalid(hsm) \ |
78 | (((hsm) >= PMUX_HSM_DISABLE) && ((hsm) <= PMUX_HSM_ENABLE)) | |
79 | #endif | |
80 | ||
f49357ba | 81 | #define _R(offset) (u32 *)((unsigned long)NV_PA_APB_MISC_BASE + (offset)) |
e2969957 SW |
82 | |
83 | #if defined(CONFIG_TEGRA20) | |
84 | ||
85 | #define MUX_REG(grp) _R(0x80 + ((tegra_soc_pingroups[grp].ctl_id / 16) * 4)) | |
86 | #define MUX_SHIFT(grp) ((tegra_soc_pingroups[grp].ctl_id % 16) * 2) | |
87 | ||
88 | #define PULL_REG(grp) _R(0xa0 + ((tegra_soc_pingroups[grp].pull_id / 16) * 4)) | |
89 | #define PULL_SHIFT(grp) ((tegra_soc_pingroups[grp].pull_id % 16) * 2) | |
90 | ||
91 | #define TRI_REG(grp) _R(0x14 + (((grp) / 32) * 4)) | |
92 | #define TRI_SHIFT(grp) ((grp) % 32) | |
93 | ||
94 | #else | |
95 | ||
96 | #define REG(pin) _R(0x3000 + ((pin) * 4)) | |
97 | ||
98 | #define MUX_REG(pin) REG(pin) | |
99 | #define MUX_SHIFT(pin) 0 | |
100 | ||
101 | #define PULL_REG(pin) REG(pin) | |
102 | #define PULL_SHIFT(pin) 2 | |
103 | ||
104 | #define TRI_REG(pin) REG(pin) | |
105 | #define TRI_SHIFT(pin) 4 | |
106 | ||
107 | #endif /* CONFIG_TEGRA20 */ | |
108 | ||
790f7719 | 109 | #define DRV_REG(group) _R(TEGRA_PMX_SOC_DRV_GROUP_BASE_REG + ((group) * 4)) |
e2969957 | 110 | |
5ee7ec7b SW |
111 | #define MIPIPADCTRL_REG(group) _R(TEGRA_PMX_SOC_MIPIPADCTRL_BASE_REG + ((group) * 4)) |
112 | ||
b2cd3d81 SW |
113 | /* |
114 | * We could force arch-tegraNN/pinmux.h to define all of these. However, | |
115 | * that's a lot of defines, and for now it's manageable to just put a | |
116 | * special case here. It's possible this decision will change with future | |
117 | * SoCs. | |
118 | */ | |
119 | #ifdef CONFIG_TEGRA210 | |
120 | #define IO_SHIFT 6 | |
121 | #define LOCK_SHIFT 7 | |
f2c60eed SW |
122 | #ifdef TEGRA_PMX_PINS_HAVE_HSM |
123 | #define HSM_SHIFT 9 | |
124 | #endif | |
f4d7c9dd | 125 | #define E_IO_HV_SHIFT 10 |
b2cd3d81 | 126 | #define OD_SHIFT 11 |
f2c60eed SW |
127 | #ifdef TEGRA_PMX_PINS_HAVE_SCHMT |
128 | #define SCHMT_SHIFT 12 | |
129 | #endif | |
b2cd3d81 | 130 | #else |
e2969957 SW |
131 | #define IO_SHIFT 5 |
132 | #define OD_SHIFT 6 | |
133 | #define LOCK_SHIFT 7 | |
134 | #define IO_RESET_SHIFT 8 | |
135 | #define RCV_SEL_SHIFT 9 | |
b2cd3d81 | 136 | #endif |
e2969957 | 137 | |
7a28441f | 138 | #ifdef TEGRA_PMX_SOC_HAS_IO_CLAMPING |
bb14469a SW |
139 | /* This register/field only exists on Tegra114 and later */ |
140 | #define APB_MISC_PP_PINMUX_GLOBAL_0 0x40 | |
141 | #define CLAMP_INPUTS_WHEN_TRISTATED 1 | |
142 | ||
143 | void pinmux_set_tristate_input_clamping(void) | |
144 | { | |
145 | u32 *reg = _R(APB_MISC_PP_PINMUX_GLOBAL_0); | |
bb14469a | 146 | |
f799b03f SW |
147 | setbits_le32(reg, CLAMP_INPUTS_WHEN_TRISTATED); |
148 | } | |
149 | ||
150 | void pinmux_clear_tristate_input_clamping(void) | |
151 | { | |
152 | u32 *reg = _R(APB_MISC_PP_PINMUX_GLOBAL_0); | |
153 | ||
154 | clrbits_le32(reg, CLAMP_INPUTS_WHEN_TRISTATED); | |
bb14469a SW |
155 | } |
156 | #endif | |
157 | ||
e2969957 SW |
158 | void pinmux_set_func(enum pmux_pingrp pin, enum pmux_func func) |
159 | { | |
160 | u32 *reg = MUX_REG(pin); | |
161 | int i, mux = -1; | |
162 | u32 val; | |
163 | ||
4a68d343 SW |
164 | if (func == PMUX_FUNC_DEFAULT) |
165 | return; | |
166 | ||
e2969957 SW |
167 | /* Error check on pin and func */ |
168 | assert(pmux_pingrp_isvalid(pin)); | |
169 | assert(pmux_func_isvalid(func)); | |
170 | ||
d381294a SW |
171 | if (func >= PMUX_FUNC_RSVD1) { |
172 | mux = (func - PMUX_FUNC_RSVD1) & 3; | |
e2969957 SW |
173 | } else { |
174 | /* Search for the appropriate function */ | |
175 | for (i = 0; i < 4; i++) { | |
176 | if (tegra_soc_pingroups[pin].funcs[i] == func) { | |
177 | mux = i; | |
178 | break; | |
179 | } | |
180 | } | |
181 | } | |
182 | assert(mux != -1); | |
183 | ||
184 | val = readl(reg); | |
185 | val &= ~(3 << MUX_SHIFT(pin)); | |
186 | val |= (mux << MUX_SHIFT(pin)); | |
187 | writel(val, reg); | |
188 | } | |
189 | ||
190 | void pinmux_set_pullupdown(enum pmux_pingrp pin, enum pmux_pull pupd) | |
191 | { | |
192 | u32 *reg = PULL_REG(pin); | |
193 | u32 val; | |
194 | ||
195 | /* Error check on pin and pupd */ | |
196 | assert(pmux_pingrp_isvalid(pin)); | |
197 | assert(pmux_pin_pupd_isvalid(pupd)); | |
198 | ||
199 | val = readl(reg); | |
200 | val &= ~(3 << PULL_SHIFT(pin)); | |
201 | val |= (pupd << PULL_SHIFT(pin)); | |
202 | writel(val, reg); | |
203 | } | |
204 | ||
a45fa436 | 205 | static void pinmux_set_tristate(enum pmux_pingrp pin, int tri) |
e2969957 SW |
206 | { |
207 | u32 *reg = TRI_REG(pin); | |
208 | u32 val; | |
209 | ||
210 | /* Error check on pin */ | |
211 | assert(pmux_pingrp_isvalid(pin)); | |
212 | assert(pmux_pin_tristate_isvalid(tri)); | |
213 | ||
214 | val = readl(reg); | |
215 | if (tri == PMUX_TRI_TRISTATE) | |
216 | val |= (1 << TRI_SHIFT(pin)); | |
217 | else | |
218 | val &= ~(1 << TRI_SHIFT(pin)); | |
219 | writel(val, reg); | |
220 | } | |
221 | ||
222 | void pinmux_tristate_enable(enum pmux_pingrp pin) | |
223 | { | |
224 | pinmux_set_tristate(pin, PMUX_TRI_TRISTATE); | |
225 | } | |
226 | ||
227 | void pinmux_tristate_disable(enum pmux_pingrp pin) | |
228 | { | |
229 | pinmux_set_tristate(pin, PMUX_TRI_NORMAL); | |
230 | } | |
231 | ||
7a28441f | 232 | #ifdef TEGRA_PMX_PINS_HAVE_E_INPUT |
e2969957 SW |
233 | void pinmux_set_io(enum pmux_pingrp pin, enum pmux_pin_io io) |
234 | { | |
235 | u32 *reg = REG(pin); | |
236 | u32 val; | |
237 | ||
238 | if (io == PMUX_PIN_NONE) | |
239 | return; | |
240 | ||
241 | /* Error check on pin and io */ | |
242 | assert(pmux_pingrp_isvalid(pin)); | |
243 | assert(pmux_pin_io_isvalid(io)); | |
244 | ||
245 | val = readl(reg); | |
246 | if (io == PMUX_PIN_INPUT) | |
247 | val |= (io & 1) << IO_SHIFT; | |
248 | else | |
249 | val &= ~(1 << IO_SHIFT); | |
250 | writel(val, reg); | |
251 | } | |
7a28441f | 252 | #endif |
e2969957 | 253 | |
7a28441f | 254 | #ifdef TEGRA_PMX_PINS_HAVE_LOCK |
e2969957 SW |
255 | static void pinmux_set_lock(enum pmux_pingrp pin, enum pmux_pin_lock lock) |
256 | { | |
257 | u32 *reg = REG(pin); | |
258 | u32 val; | |
259 | ||
260 | if (lock == PMUX_PIN_LOCK_DEFAULT) | |
261 | return; | |
262 | ||
263 | /* Error check on pin and lock */ | |
264 | assert(pmux_pingrp_isvalid(pin)); | |
265 | assert(pmux_pin_lock_isvalid(lock)); | |
266 | ||
267 | val = readl(reg); | |
268 | if (lock == PMUX_PIN_LOCK_ENABLE) { | |
269 | val |= (1 << LOCK_SHIFT); | |
270 | } else { | |
271 | if (val & (1 << LOCK_SHIFT)) | |
272 | printf("%s: Cannot clear LOCK bit!\n", __func__); | |
273 | val &= ~(1 << LOCK_SHIFT); | |
274 | } | |
275 | writel(val, reg); | |
276 | ||
277 | return; | |
278 | } | |
7a28441f | 279 | #endif |
e2969957 | 280 | |
7a28441f | 281 | #ifdef TEGRA_PMX_PINS_HAVE_OD |
e2969957 SW |
282 | static void pinmux_set_od(enum pmux_pingrp pin, enum pmux_pin_od od) |
283 | { | |
284 | u32 *reg = REG(pin); | |
285 | u32 val; | |
286 | ||
287 | if (od == PMUX_PIN_OD_DEFAULT) | |
288 | return; | |
289 | ||
290 | /* Error check on pin and od */ | |
291 | assert(pmux_pingrp_isvalid(pin)); | |
292 | assert(pmux_pin_od_isvalid(od)); | |
293 | ||
294 | val = readl(reg); | |
295 | if (od == PMUX_PIN_OD_ENABLE) | |
296 | val |= (1 << OD_SHIFT); | |
297 | else | |
298 | val &= ~(1 << OD_SHIFT); | |
299 | writel(val, reg); | |
300 | ||
301 | return; | |
302 | } | |
7a28441f | 303 | #endif |
e2969957 | 304 | |
7a28441f | 305 | #ifdef TEGRA_PMX_PINS_HAVE_IO_RESET |
e2969957 SW |
306 | static void pinmux_set_ioreset(enum pmux_pingrp pin, |
307 | enum pmux_pin_ioreset ioreset) | |
308 | { | |
309 | u32 *reg = REG(pin); | |
310 | u32 val; | |
311 | ||
312 | if (ioreset == PMUX_PIN_IO_RESET_DEFAULT) | |
313 | return; | |
314 | ||
315 | /* Error check on pin and ioreset */ | |
316 | assert(pmux_pingrp_isvalid(pin)); | |
317 | assert(pmux_pin_ioreset_isvalid(ioreset)); | |
318 | ||
319 | val = readl(reg); | |
320 | if (ioreset == PMUX_PIN_IO_RESET_ENABLE) | |
321 | val |= (1 << IO_RESET_SHIFT); | |
322 | else | |
323 | val &= ~(1 << IO_RESET_SHIFT); | |
324 | writel(val, reg); | |
325 | ||
326 | return; | |
327 | } | |
7a28441f | 328 | #endif |
e2969957 | 329 | |
7a28441f | 330 | #ifdef TEGRA_PMX_PINS_HAVE_RCV_SEL |
e2969957 SW |
331 | static void pinmux_set_rcv_sel(enum pmux_pingrp pin, |
332 | enum pmux_pin_rcv_sel rcv_sel) | |
333 | { | |
334 | u32 *reg = REG(pin); | |
335 | u32 val; | |
336 | ||
337 | if (rcv_sel == PMUX_PIN_RCV_SEL_DEFAULT) | |
338 | return; | |
339 | ||
340 | /* Error check on pin and rcv_sel */ | |
341 | assert(pmux_pingrp_isvalid(pin)); | |
342 | assert(pmux_pin_rcv_sel_isvalid(rcv_sel)); | |
343 | ||
344 | val = readl(reg); | |
345 | if (rcv_sel == PMUX_PIN_RCV_SEL_HIGH) | |
346 | val |= (1 << RCV_SEL_SHIFT); | |
347 | else | |
348 | val &= ~(1 << RCV_SEL_SHIFT); | |
349 | writel(val, reg); | |
350 | ||
351 | return; | |
352 | } | |
7a28441f | 353 | #endif |
e2969957 | 354 | |
f4d7c9dd SW |
355 | #ifdef TEGRA_PMX_PINS_HAVE_E_IO_HV |
356 | static void pinmux_set_e_io_hv(enum pmux_pingrp pin, | |
357 | enum pmux_pin_e_io_hv e_io_hv) | |
358 | { | |
359 | u32 *reg = REG(pin); | |
360 | u32 val; | |
361 | ||
362 | if (e_io_hv == PMUX_PIN_E_IO_HV_DEFAULT) | |
363 | return; | |
364 | ||
365 | /* Error check on pin and e_io_hv */ | |
366 | assert(pmux_pingrp_isvalid(pin)); | |
367 | assert(pmux_pin_e_io_hv_isvalid(e_io_hv)); | |
368 | ||
369 | val = readl(reg); | |
370 | if (e_io_hv == PMUX_PIN_E_IO_HV_HIGH) | |
371 | val |= (1 << E_IO_HV_SHIFT); | |
372 | else | |
373 | val &= ~(1 << E_IO_HV_SHIFT); | |
374 | writel(val, reg); | |
375 | ||
376 | return; | |
377 | } | |
378 | #endif | |
379 | ||
f2c60eed SW |
380 | #ifdef TEGRA_PMX_PINS_HAVE_SCHMT |
381 | static void pinmux_set_schmt(enum pmux_pingrp pin, enum pmux_schmt schmt) | |
382 | { | |
383 | u32 *reg = REG(grp); | |
384 | u32 val; | |
385 | ||
386 | /* NONE means unspecified/do not change/use POR value */ | |
387 | if (schmt == PMUX_SCHMT_NONE) | |
388 | return; | |
389 | ||
390 | /* Error check pad */ | |
391 | assert(pmux_pingrp_isvalid(pin)); | |
392 | assert(pmux_schmt_isvalid(schmt)); | |
393 | ||
394 | val = readl(reg); | |
395 | if (schmt == PMUX_SCHMT_ENABLE) | |
396 | val |= (1 << SCHMT_SHIFT); | |
397 | else | |
398 | val &= ~(1 << SCHMT_SHIFT); | |
399 | writel(val, reg); | |
400 | ||
401 | return; | |
402 | } | |
403 | #endif | |
404 | ||
405 | #ifdef TEGRA_PMX_PINS_HAVE_HSM | |
406 | static void pinmux_set_hsm(enum pmux_pingrp pin, enum pmux_hsm hsm) | |
407 | { | |
408 | u32 *reg = REG(grp); | |
409 | u32 val; | |
410 | ||
411 | /* NONE means unspecified/do not change/use POR value */ | |
412 | if (hsm == PMUX_HSM_NONE) | |
413 | return; | |
414 | ||
415 | /* Error check pad */ | |
416 | assert(pmux_pingrp_isvalid(pin)); | |
417 | assert(pmux_hsm_isvalid(hsm)); | |
418 | ||
419 | val = readl(reg); | |
420 | if (hsm == PMUX_HSM_ENABLE) | |
421 | val |= (1 << HSM_SHIFT); | |
422 | else | |
423 | val &= ~(1 << HSM_SHIFT); | |
424 | writel(val, reg); | |
425 | ||
426 | return; | |
427 | } | |
428 | #endif | |
429 | ||
dfb42fc9 | 430 | static void pinmux_config_pingrp(const struct pmux_pingrp_config *config) |
e2969957 | 431 | { |
dfb42fc9 | 432 | enum pmux_pingrp pin = config->pingrp; |
e2969957 SW |
433 | |
434 | pinmux_set_func(pin, config->func); | |
435 | pinmux_set_pullupdown(pin, config->pull); | |
436 | pinmux_set_tristate(pin, config->tristate); | |
7a28441f | 437 | #ifdef TEGRA_PMX_PINS_HAVE_E_INPUT |
e2969957 | 438 | pinmux_set_io(pin, config->io); |
7a28441f SW |
439 | #endif |
440 | #ifdef TEGRA_PMX_PINS_HAVE_LOCK | |
e2969957 | 441 | pinmux_set_lock(pin, config->lock); |
7a28441f SW |
442 | #endif |
443 | #ifdef TEGRA_PMX_PINS_HAVE_OD | |
e2969957 | 444 | pinmux_set_od(pin, config->od); |
7a28441f SW |
445 | #endif |
446 | #ifdef TEGRA_PMX_PINS_HAVE_IO_RESET | |
e2969957 | 447 | pinmux_set_ioreset(pin, config->ioreset); |
e2969957 | 448 | #endif |
7a28441f SW |
449 | #ifdef TEGRA_PMX_PINS_HAVE_RCV_SEL |
450 | pinmux_set_rcv_sel(pin, config->rcv_sel); | |
e2969957 | 451 | #endif |
f4d7c9dd SW |
452 | #ifdef TEGRA_PMX_PINS_HAVE_E_IO_HV |
453 | pinmux_set_e_io_hv(pin, config->e_io_hv); | |
454 | #endif | |
f2c60eed SW |
455 | #ifdef TEGRA_PMX_PINS_HAVE_SCHMT |
456 | pinmux_set_schmt(pin, config->schmt); | |
457 | #endif | |
458 | #ifdef TEGRA_PMX_PINS_HAVE_HSM | |
459 | pinmux_set_hsm(pin, config->hsm); | |
460 | #endif | |
e2969957 SW |
461 | } |
462 | ||
dfb42fc9 SW |
463 | void pinmux_config_pingrp_table(const struct pmux_pingrp_config *config, |
464 | int len) | |
e2969957 SW |
465 | { |
466 | int i; | |
467 | ||
468 | for (i = 0; i < len; i++) | |
dfb42fc9 | 469 | pinmux_config_pingrp(&config[i]); |
e2969957 SW |
470 | } |
471 | ||
7a28441f | 472 | #ifdef TEGRA_PMX_SOC_HAS_DRVGRPS |
e2969957 | 473 | |
dfb42fc9 | 474 | #define pmux_drvgrp_isvalid(pd) (((pd) >= 0) && ((pd) < PMUX_DRVGRP_COUNT)) |
e2969957 | 475 | |
dfb42fc9 SW |
476 | #define pmux_slw_isvalid(slw) \ |
477 | (((slw) >= PMUX_SLWF_MIN) && ((slw) <= PMUX_SLWF_MAX)) | |
e2969957 | 478 | |
dfb42fc9 SW |
479 | #define pmux_drv_isvalid(drv) \ |
480 | (((drv) >= PMUX_DRVUP_MIN) && ((drv) <= PMUX_DRVUP_MAX)) | |
e2969957 | 481 | |
439f5768 | 482 | #ifdef TEGRA_PMX_GRPS_HAVE_HSM |
e2969957 | 483 | #define HSM_SHIFT 2 |
439f5768 SW |
484 | #endif |
485 | #ifdef TEGRA_PMX_GRPS_HAVE_SCHMT | |
e2969957 | 486 | #define SCHMT_SHIFT 3 |
439f5768 SW |
487 | #endif |
488 | #ifdef TEGRA_PMX_GRPS_HAVE_LPMD | |
e2969957 SW |
489 | #define LPMD_SHIFT 4 |
490 | #define LPMD_MASK (3 << LPMD_SHIFT) | |
439f5768 | 491 | #endif |
9f21c1a3 SW |
492 | /* |
493 | * Note that the following DRV* and SLW* defines are accurate for many drive | |
494 | * groups on many SoCs. We really need a per-group data structure to solve | |
495 | * this, since the fields are in different positions/sizes in different | |
496 | * registers (for different groups). | |
497 | * | |
498 | * On Tegra30/114/124, the DRV*_SHIFT values vary. | |
499 | * On Tegra30, the SLW*_SHIFT values vary. | |
500 | * On Tegra30/114/124/210, the DRV*_MASK values vary, although the values | |
501 | * below are wide enough to cover the widest fields, and hopefully don't | |
502 | * interfere with any other fields. | |
503 | * On Tegra30, the SLW*_MASK values vary, but we can't use a value that's | |
504 | * wide enough to cover all cases, since that would cause the field to | |
505 | * overlap with other fields in the narrower cases. | |
506 | */ | |
e2969957 SW |
507 | #define DRVDN_SHIFT 12 |
508 | #define DRVDN_MASK (0x7F << DRVDN_SHIFT) | |
509 | #define DRVUP_SHIFT 20 | |
510 | #define DRVUP_MASK (0x7F << DRVUP_SHIFT) | |
511 | #define SLWR_SHIFT 28 | |
512 | #define SLWR_MASK (3 << SLWR_SHIFT) | |
513 | #define SLWF_SHIFT 30 | |
514 | #define SLWF_MASK (3 << SLWF_SHIFT) | |
515 | ||
dfb42fc9 | 516 | static void pinmux_set_drvup_slwf(enum pmux_drvgrp grp, int slwf) |
e2969957 SW |
517 | { |
518 | u32 *reg = DRV_REG(grp); | |
519 | u32 val; | |
520 | ||
521 | /* NONE means unspecified/do not change/use POR value */ | |
dfb42fc9 | 522 | if (slwf == PMUX_SLWF_NONE) |
e2969957 SW |
523 | return; |
524 | ||
525 | /* Error check on pad and slwf */ | |
dfb42fc9 SW |
526 | assert(pmux_drvgrp_isvalid(grp)); |
527 | assert(pmux_slw_isvalid(slwf)); | |
e2969957 SW |
528 | |
529 | val = readl(reg); | |
530 | val &= ~SLWF_MASK; | |
531 | val |= (slwf << SLWF_SHIFT); | |
532 | writel(val, reg); | |
533 | ||
534 | return; | |
535 | } | |
536 | ||
dfb42fc9 | 537 | static void pinmux_set_drvdn_slwr(enum pmux_drvgrp grp, int slwr) |
e2969957 SW |
538 | { |
539 | u32 *reg = DRV_REG(grp); | |
540 | u32 val; | |
541 | ||
542 | /* NONE means unspecified/do not change/use POR value */ | |
dfb42fc9 | 543 | if (slwr == PMUX_SLWR_NONE) |
e2969957 SW |
544 | return; |
545 | ||
546 | /* Error check on pad and slwr */ | |
dfb42fc9 SW |
547 | assert(pmux_drvgrp_isvalid(grp)); |
548 | assert(pmux_slw_isvalid(slwr)); | |
e2969957 SW |
549 | |
550 | val = readl(reg); | |
551 | val &= ~SLWR_MASK; | |
552 | val |= (slwr << SLWR_SHIFT); | |
553 | writel(val, reg); | |
554 | ||
555 | return; | |
556 | } | |
557 | ||
dfb42fc9 | 558 | static void pinmux_set_drvup(enum pmux_drvgrp grp, int drvup) |
e2969957 SW |
559 | { |
560 | u32 *reg = DRV_REG(grp); | |
561 | u32 val; | |
562 | ||
563 | /* NONE means unspecified/do not change/use POR value */ | |
dfb42fc9 | 564 | if (drvup == PMUX_DRVUP_NONE) |
e2969957 SW |
565 | return; |
566 | ||
567 | /* Error check on pad and drvup */ | |
dfb42fc9 SW |
568 | assert(pmux_drvgrp_isvalid(grp)); |
569 | assert(pmux_drv_isvalid(drvup)); | |
e2969957 SW |
570 | |
571 | val = readl(reg); | |
572 | val &= ~DRVUP_MASK; | |
573 | val |= (drvup << DRVUP_SHIFT); | |
574 | writel(val, reg); | |
575 | ||
576 | return; | |
577 | } | |
578 | ||
dfb42fc9 | 579 | static void pinmux_set_drvdn(enum pmux_drvgrp grp, int drvdn) |
e2969957 SW |
580 | { |
581 | u32 *reg = DRV_REG(grp); | |
582 | u32 val; | |
583 | ||
584 | /* NONE means unspecified/do not change/use POR value */ | |
dfb42fc9 | 585 | if (drvdn == PMUX_DRVDN_NONE) |
e2969957 SW |
586 | return; |
587 | ||
588 | /* Error check on pad and drvdn */ | |
dfb42fc9 SW |
589 | assert(pmux_drvgrp_isvalid(grp)); |
590 | assert(pmux_drv_isvalid(drvdn)); | |
e2969957 SW |
591 | |
592 | val = readl(reg); | |
593 | val &= ~DRVDN_MASK; | |
594 | val |= (drvdn << DRVDN_SHIFT); | |
595 | writel(val, reg); | |
596 | ||
597 | return; | |
598 | } | |
599 | ||
439f5768 | 600 | #ifdef TEGRA_PMX_GRPS_HAVE_LPMD |
dfb42fc9 | 601 | static void pinmux_set_lpmd(enum pmux_drvgrp grp, enum pmux_lpmd lpmd) |
e2969957 SW |
602 | { |
603 | u32 *reg = DRV_REG(grp); | |
604 | u32 val; | |
605 | ||
606 | /* NONE means unspecified/do not change/use POR value */ | |
dfb42fc9 | 607 | if (lpmd == PMUX_LPMD_NONE) |
e2969957 SW |
608 | return; |
609 | ||
610 | /* Error check pad and lpmd value */ | |
dfb42fc9 SW |
611 | assert(pmux_drvgrp_isvalid(grp)); |
612 | assert(pmux_lpmd_isvalid(lpmd)); | |
e2969957 SW |
613 | |
614 | val = readl(reg); | |
615 | val &= ~LPMD_MASK; | |
616 | val |= (lpmd << LPMD_SHIFT); | |
617 | writel(val, reg); | |
618 | ||
619 | return; | |
620 | } | |
439f5768 | 621 | #endif |
e2969957 | 622 | |
439f5768 | 623 | #ifdef TEGRA_PMX_GRPS_HAVE_SCHMT |
dfb42fc9 | 624 | static void pinmux_set_schmt(enum pmux_drvgrp grp, enum pmux_schmt schmt) |
e2969957 SW |
625 | { |
626 | u32 *reg = DRV_REG(grp); | |
627 | u32 val; | |
628 | ||
629 | /* NONE means unspecified/do not change/use POR value */ | |
dfb42fc9 | 630 | if (schmt == PMUX_SCHMT_NONE) |
e2969957 SW |
631 | return; |
632 | ||
633 | /* Error check pad */ | |
dfb42fc9 SW |
634 | assert(pmux_drvgrp_isvalid(grp)); |
635 | assert(pmux_schmt_isvalid(schmt)); | |
e2969957 SW |
636 | |
637 | val = readl(reg); | |
dfb42fc9 | 638 | if (schmt == PMUX_SCHMT_ENABLE) |
e2969957 SW |
639 | val |= (1 << SCHMT_SHIFT); |
640 | else | |
641 | val &= ~(1 << SCHMT_SHIFT); | |
642 | writel(val, reg); | |
643 | ||
644 | return; | |
645 | } | |
439f5768 | 646 | #endif |
e2969957 | 647 | |
439f5768 | 648 | #ifdef TEGRA_PMX_GRPS_HAVE_HSM |
dfb42fc9 | 649 | static void pinmux_set_hsm(enum pmux_drvgrp grp, enum pmux_hsm hsm) |
e2969957 SW |
650 | { |
651 | u32 *reg = DRV_REG(grp); | |
652 | u32 val; | |
653 | ||
654 | /* NONE means unspecified/do not change/use POR value */ | |
dfb42fc9 | 655 | if (hsm == PMUX_HSM_NONE) |
e2969957 SW |
656 | return; |
657 | ||
658 | /* Error check pad */ | |
dfb42fc9 SW |
659 | assert(pmux_drvgrp_isvalid(grp)); |
660 | assert(pmux_hsm_isvalid(hsm)); | |
e2969957 SW |
661 | |
662 | val = readl(reg); | |
dfb42fc9 | 663 | if (hsm == PMUX_HSM_ENABLE) |
e2969957 SW |
664 | val |= (1 << HSM_SHIFT); |
665 | else | |
666 | val &= ~(1 << HSM_SHIFT); | |
667 | writel(val, reg); | |
668 | ||
669 | return; | |
670 | } | |
439f5768 | 671 | #endif |
e2969957 | 672 | |
dfb42fc9 | 673 | static void pinmux_config_drvgrp(const struct pmux_drvgrp_config *config) |
e2969957 | 674 | { |
dfb42fc9 SW |
675 | enum pmux_drvgrp grp = config->drvgrp; |
676 | ||
677 | pinmux_set_drvup_slwf(grp, config->slwf); | |
678 | pinmux_set_drvdn_slwr(grp, config->slwr); | |
679 | pinmux_set_drvup(grp, config->drvup); | |
680 | pinmux_set_drvdn(grp, config->drvdn); | |
439f5768 | 681 | #ifdef TEGRA_PMX_GRPS_HAVE_LPMD |
dfb42fc9 | 682 | pinmux_set_lpmd(grp, config->lpmd); |
439f5768 SW |
683 | #endif |
684 | #ifdef TEGRA_PMX_GRPS_HAVE_SCHMT | |
dfb42fc9 | 685 | pinmux_set_schmt(grp, config->schmt); |
439f5768 SW |
686 | #endif |
687 | #ifdef TEGRA_PMX_GRPS_HAVE_HSM | |
dfb42fc9 | 688 | pinmux_set_hsm(grp, config->hsm); |
439f5768 | 689 | #endif |
e2969957 SW |
690 | } |
691 | ||
dfb42fc9 SW |
692 | void pinmux_config_drvgrp_table(const struct pmux_drvgrp_config *config, |
693 | int len) | |
e2969957 SW |
694 | { |
695 | int i; | |
696 | ||
697 | for (i = 0; i < len; i++) | |
dfb42fc9 | 698 | pinmux_config_drvgrp(&config[i]); |
e2969957 | 699 | } |
c21478bc | 700 | #endif /* TEGRA_PMX_SOC_HAS_DRVGRPS */ |
5ee7ec7b SW |
701 | |
702 | #ifdef TEGRA_PMX_SOC_HAS_MIPI_PAD_CTRL_GRPS | |
703 | ||
704 | #define pmux_mipipadctrlgrp_isvalid(pd) (((pd) >= 0) && ((pd) < PMUX_MIPIPADCTRLGRP_COUNT)) | |
705 | ||
706 | static void pinmux_mipipadctrl_set_func(enum pmux_mipipadctrlgrp grp, | |
707 | enum pmux_func func) | |
708 | { | |
709 | u32 *reg = MIPIPADCTRL_REG(grp); | |
710 | int i, mux = -1; | |
711 | u32 val; | |
712 | ||
713 | if (func == PMUX_FUNC_DEFAULT) | |
714 | return; | |
715 | ||
716 | /* Error check grp and func */ | |
717 | assert(pmux_mipipadctrlgrp_isvalid(grp)); | |
718 | assert(pmux_func_isvalid(func)); | |
719 | ||
720 | if (func >= PMUX_FUNC_RSVD1) { | |
721 | mux = (func - PMUX_FUNC_RSVD1) & 1; | |
722 | } else { | |
723 | /* Search for the appropriate function */ | |
724 | for (i = 0; i < 2; i++) { | |
725 | if (tegra_soc_mipipadctrl_groups[grp].funcs[i] | |
726 | == func) { | |
727 | mux = i; | |
728 | break; | |
729 | } | |
730 | } | |
731 | } | |
732 | assert(mux != -1); | |
733 | ||
734 | val = readl(reg); | |
735 | val &= ~(1 << 1); | |
736 | val |= (mux << 1); | |
737 | writel(val, reg); | |
738 | } | |
739 | ||
740 | static void pinmux_config_mipipadctrlgrp(const struct pmux_mipipadctrlgrp_config *config) | |
741 | { | |
742 | enum pmux_mipipadctrlgrp grp = config->grp; | |
743 | ||
744 | pinmux_mipipadctrl_set_func(grp, config->func); | |
745 | } | |
746 | ||
747 | void pinmux_config_mipipadctrlgrp_table( | |
748 | const struct pmux_mipipadctrlgrp_config *config, int len) | |
749 | { | |
750 | int i; | |
751 | ||
752 | for (i = 0; i < len; i++) | |
753 | pinmux_config_mipipadctrlgrp(&config[i]); | |
754 | } | |
755 | #endif /* TEGRA_PMX_SOC_HAS_MIPI_PAD_CTRL_GRPS */ |