blob: bc02825ee1fcddcf8b95d60929744496fad5ebd5 [file] [log] [blame]
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2023
4 * Svyatoslav Ryhel <clamor95@gmail.com>
5 */
6
7#include <dm.h>
8#include <dm/device_compat.h>
9#include <dm/pinctrl.h>
10#include <stdlib.h>
11
12#include <asm/arch/pinmux.h>
13
14static void tegra_pinctrl_set_drive(struct udevice *config, int drvcnt)
15{
16 struct pmux_drvgrp_config *drive_group;
Svyatoslav Ryhel49c275a2025-03-31 11:28:53 +030017 int i, ret, pad_id, count = 0;
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +020018 const char **pads;
19
20 drive_group = kmalloc_array(drvcnt, sizeof(*drive_group), GFP_KERNEL);
21 if (!drive_group) {
22 log_debug("%s: cannot allocate drive group array\n", __func__);
23 return;
24 }
25
Svyatoslav Ryhel3648edc2025-03-13 10:48:06 +020026 drive_group[0].slwf = dev_read_u32_default(config, "nvidia,slew-rate-falling", PMUX_SLWF_NONE);
27 drive_group[0].slwr = dev_read_u32_default(config, "nvidia,slew-rate-rising", PMUX_SLWR_NONE);
28 drive_group[0].drvup = dev_read_u32_default(config, "nvidia,pull-up-strength", PMUX_DRVUP_NONE);
29 drive_group[0].drvdn = dev_read_u32_default(config, "nvidia,pull-down-strength", PMUX_DRVDN_NONE);
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +020030#ifdef TEGRA_PMX_GRPS_HAVE_LPMD
Svyatoslav Ryhel3648edc2025-03-13 10:48:06 +020031 drive_group[0].lpmd = dev_read_u32_default(config, "nvidia,low-power-mode", PMUX_LPMD_NONE);
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +020032#endif
33#ifdef TEGRA_PMX_GRPS_HAVE_SCHMT
Svyatoslav Ryhel3648edc2025-03-13 10:48:06 +020034 drive_group[0].schmt = dev_read_u32_default(config, "nvidia,schmitt", PMUX_SCHMT_NONE);
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +020035#endif
36#ifdef TEGRA_PMX_GRPS_HAVE_HSM
Svyatoslav Ryhel3648edc2025-03-13 10:48:06 +020037 drive_group[0].hsm = dev_read_u32_default(config, "nvidia,high-speed-mode", PMUX_HSM_NONE);
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +020038#endif
39
40 for (i = 1; i < drvcnt; i++)
41 memcpy(&drive_group[i], &drive_group[0], sizeof(drive_group[0]));
42
43 ret = dev_read_string_list(config, "nvidia,pins", &pads);
44 if (ret < 0) {
45 log_debug("%s: could not parse property nvidia,pins\n", __func__);
46 goto exit;
47 }
48
Svyatoslav Ryhel49c275a2025-03-31 11:28:53 +030049 /*
50 * i goes through all drive instances defined, while
51 * count is increased only if a valid configuration is found
52 */
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +020053 for (i = 0; i < drvcnt; i++) {
54 for (pad_id = 0; pad_id < PMUX_DRVGRP_COUNT; pad_id++)
55 if (tegra_pinctrl_to_drvgrp[pad_id])
56 if (!strcmp(pads[i], tegra_pinctrl_to_drvgrp[pad_id])) {
Svyatoslav Ryhel49c275a2025-03-31 11:28:53 +030057 drive_group[count].drvgrp = pad_id;
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +020058 break;
59 }
60
Svyatoslav Ryhel49c275a2025-03-31 11:28:53 +030061 if (pad_id == PMUX_DRVGRP_COUNT) {
62 log_debug("%s: drive %s is not valid\n", __func__, pads[i]);
63 continue;
64 }
65
66 log_debug("%s(%d) drvmap: %d, %d, %d, %d, %d\n", pads[count], count,
67 drive_group[count].drvgrp, drive_group[count].slwf,
68 drive_group[count].slwr, drive_group[count].drvup,
69 drive_group[count].drvdn);
70
71 count++;
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +020072 }
73
Svyatoslav Ryhel49c275a2025-03-31 11:28:53 +030074 pinmux_config_drvgrp_table(drive_group, count);
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +020075
76 free(pads);
77exit:
78 kfree(drive_group);
79}
80
Svyatoslav Ryhel1fc2d612024-11-21 14:43:00 +020081#ifdef TEGRA_PMX_SOC_HAS_MIPI_PAD_CTRL_GRPS
82static void tegra_pinctrl_set_mipipad(struct udevice *config, int padcnt)
83{
84 struct pmux_mipipadctrlgrp_config *mipipad_group;
Svyatoslav Ryhel49c275a2025-03-31 11:28:53 +030085 int i, ret, pad_id, count = 0;
Svyatoslav Ryhel1fc2d612024-11-21 14:43:00 +020086 const char *function;
87 const char **pads;
88
89 mipipad_group = kmalloc_array(padcnt, sizeof(*mipipad_group), GFP_KERNEL);
90 if (!mipipad_group) {
91 log_debug("%s: cannot allocate mipi pad group array\n", __func__);
92 return;
93 }
94
95 /* decode function id and fill the first copy of pmux_mipipadctrlgrp_config */
96 function = dev_read_string(config, "nvidia,function");
97 if (function)
98 for (i = 0; i < PMUX_FUNC_COUNT; i++)
99 if (tegra_pinctrl_to_func[i])
100 if (!strcmp(function, tegra_pinctrl_to_func[i]))
101 break;
102
Svyatoslav Ryhel49c275a2025-03-31 11:28:53 +0300103 if (!function || i == PMUX_FUNC_COUNT) {
104 log_debug("%s: pin function is not defined or is not valid\n", __func__);
105 goto exit;
106 }
107
Svyatoslav Ryhel1fc2d612024-11-21 14:43:00 +0200108 mipipad_group[0].func = i;
109
110 for (i = 1; i < padcnt; i++)
111 memcpy(&mipipad_group[i], &mipipad_group[0], sizeof(mipipad_group[0]));
112
113 ret = dev_read_string_list(config, "nvidia,pins", &pads);
114 if (ret < 0) {
115 log_debug("%s: could not parse property nvidia,pins\n", __func__);
116 goto exit;
117 }
118
Svyatoslav Ryhel49c275a2025-03-31 11:28:53 +0300119 /*
120 * i goes through all pin instances defined, while
121 * count is increased only if a valid configuration is found
122 */
Svyatoslav Ryhel1fc2d612024-11-21 14:43:00 +0200123 for (i = 0; i < padcnt; i++) {
124 for (pad_id = 0; pad_id < PMUX_MIPIPADCTRLGRP_COUNT; pad_id++)
125 if (tegra_pinctrl_to_mipipadgrp[pad_id])
126 if (!strcmp(pads[i], tegra_pinctrl_to_mipipadgrp[pad_id])) {
Svyatoslav Ryhel49c275a2025-03-31 11:28:53 +0300127 mipipad_group[count].grp = pad_id;
Svyatoslav Ryhel1fc2d612024-11-21 14:43:00 +0200128 break;
129 }
Svyatoslav Ryhel49c275a2025-03-31 11:28:53 +0300130
131 if (pad_id == PMUX_MIPIPADCTRLGRP_COUNT) {
132 log_debug("%s: drive %s is not valid\n", __func__, pads[i]);
133 continue;
134 }
135
136 count++;
Svyatoslav Ryhel1fc2d612024-11-21 14:43:00 +0200137 }
138
Svyatoslav Ryhel49c275a2025-03-31 11:28:53 +0300139 pinmux_config_mipipadctrlgrp_table(mipipad_group, count);
Svyatoslav Ryhel1fc2d612024-11-21 14:43:00 +0200140
141 free(pads);
142exit:
143 kfree(mipipad_group);
144}
145#else
146static void tegra_pinctrl_set_mipipad(struct udevice *config, int padcnt) { }
147#endif
148
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +0200149static void tegra_pinctrl_set_pin(struct udevice *config, int pincnt)
150{
151 struct pmux_pingrp_config *pinmux_group;
Svyatoslav Ryhel49c275a2025-03-31 11:28:53 +0300152 int i, ret, pin_id, count = 0;
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +0200153 const char *function;
154 const char **pins;
155
156 pinmux_group = kmalloc_array(pincnt, sizeof(*pinmux_group), GFP_KERNEL);
157 if (!pinmux_group) {
158 log_debug("%s: cannot allocate pinmux group array\n", __func__);
159 return;
160 }
161
162 /* decode function id and fill the first copy of pmux_pingrp_config */
163 function = dev_read_string(config, "nvidia,function");
164 if (function)
165 for (i = 0; i < PMUX_FUNC_COUNT; i++)
166 if (tegra_pinctrl_to_func[i])
167 if (!strcmp(function, tegra_pinctrl_to_func[i]))
168 break;
169
Svyatoslav Ryhel49c275a2025-03-31 11:28:53 +0300170 if (!function || i == PMUX_FUNC_COUNT) {
171 log_debug("%s: pin function is not defined or is not valid\n", __func__);
172 goto exit;
173 }
174
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +0200175 pinmux_group[0].func = i;
176
Svyatoslav Ryhel3648edc2025-03-13 10:48:06 +0200177 pinmux_group[0].pull = dev_read_u32_default(config, "nvidia,pull", PMUX_PULL_NORMAL);
178 pinmux_group[0].tristate = dev_read_u32_default(config, "nvidia,tristate", PMUX_TRI_TRISTATE);
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +0200179#ifdef TEGRA_PMX_PINS_HAVE_E_INPUT
Svyatoslav Ryhel3648edc2025-03-13 10:48:06 +0200180 pinmux_group[0].io = dev_read_u32_default(config, "nvidia,enable-input", PMUX_PIN_NONE);
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +0200181#endif
182#ifdef TEGRA_PMX_PINS_HAVE_LOCK
Svyatoslav Ryhel3648edc2025-03-13 10:48:06 +0200183 pinmux_group[0].lock = dev_read_u32_default(config, "nvidia,lock", PMUX_PIN_LOCK_DEFAULT);
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +0200184#endif
185#ifdef TEGRA_PMX_PINS_HAVE_OD
Svyatoslav Ryhel3648edc2025-03-13 10:48:06 +0200186 pinmux_group[0].od = dev_read_u32_default(config, "nvidia,open-drain", PMUX_PIN_OD_DEFAULT);
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +0200187#endif
188#ifdef TEGRA_PMX_PINS_HAVE_IO_RESET
Svyatoslav Ryhel3648edc2025-03-13 10:48:06 +0200189 pinmux_group[0].ioreset = dev_read_u32_default(config, "nvidia,io-reset", PMUX_PIN_IO_RESET_DEFAULT);
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +0200190#endif
191#ifdef TEGRA_PMX_PINS_HAVE_RCV_SEL
Svyatoslav Ryhel3648edc2025-03-13 10:48:06 +0200192 pinmux_group[0].rcv_sel = dev_read_u32_default(config, "nvidia,rcv-sel", PMUX_PIN_RCV_SEL_DEFAULT);
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +0200193#endif
194#ifdef TEGRA_PMX_PINS_HAVE_E_IO_HV
Svyatoslav Ryhel3648edc2025-03-13 10:48:06 +0200195 pinmux_group[0].e_io_hv = dev_read_u32_default(config, "nvidia,io-hv", PMUX_PIN_E_IO_HV_DEFAULT);
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +0200196#endif
197#ifdef TEGRA_PMX_PINS_HAVE_SCHMT
Svyatoslav Ryhel3648edc2025-03-13 10:48:06 +0200198 pinmux_group[0].schmt = dev_read_u32_default(config, "nvidia,schmitt", PMUX_SCHMT_NONE);
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +0200199#endif
200#ifdef TEGRA_PMX_PINS_HAVE_HSM
Svyatoslav Ryhel3648edc2025-03-13 10:48:06 +0200201 pinmux_group[0].hsm = dev_read_u32_default(config, "nvidia,high-speed-mode", PMUX_HSM_NONE);
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +0200202#endif
203
204 for (i = 1; i < pincnt; i++)
205 memcpy(&pinmux_group[i], &pinmux_group[0], sizeof(pinmux_group[0]));
206
207 ret = dev_read_string_list(config, "nvidia,pins", &pins);
208 if (ret < 0) {
209 log_debug("%s: could not parse property nvidia,pins\n", __func__);
210 goto exit;
211 }
212
Svyatoslav Ryhel49c275a2025-03-31 11:28:53 +0300213 /*
214 * i goes through all pin instances defined, while
215 * count is increased only if a valid configuration is found
216 */
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +0200217 for (i = 0; i < pincnt; i++) {
218 for (pin_id = 0; pin_id < PMUX_PINGRP_COUNT; pin_id++)
219 if (tegra_pinctrl_to_pingrp[pin_id])
220 if (!strcmp(pins[i], tegra_pinctrl_to_pingrp[pin_id])) {
Svyatoslav Ryhel49c275a2025-03-31 11:28:53 +0300221 pinmux_group[count].pingrp = pin_id;
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +0200222 break;
223 }
224
Svyatoslav Ryhel49c275a2025-03-31 11:28:53 +0300225 if (pin_id == PMUX_PINGRP_COUNT) {
226 log_debug("%s: pin %s is not valid\n", __func__, pins[i]);
227 continue;
228 }
229
230 log_debug("%s(%d) pinmap: %d, %d, %d, %d\n", pins[count], count,
231 pinmux_group[count].pingrp, pinmux_group[count].func,
232 pinmux_group[count].pull, pinmux_group[count].tristate);
233
234 count++;
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +0200235 }
236
Svyatoslav Ryhel49c275a2025-03-31 11:28:53 +0300237 pinmux_config_pingrp_table(pinmux_group, count);
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +0200238
239 free(pins);
240exit:
241 kfree(pinmux_group);
242}
243
244static int tegra_pinctrl_set_state(struct udevice *dev, struct udevice *config)
245{
246 struct udevice *child;
247 int ret;
248 const char *name;
249
250 device_foreach_child(child, config) {
251 /* Pinmux node can contain pins and drives */
252 ret = dev_read_string_index(child, "nvidia,pins", 0,
253 &name);
254 if (ret < 0) {
255 log_debug("%s: could not parse property nvidia,pins\n", __func__);
256 return ret;
257 }
258
259 ret = dev_read_string_count(child, "nvidia,pins");
260 if (ret < 0) {
261 log_debug("%s: could not count nvidia,pins\n", __func__);
262 return ret;
263 }
264
265 if (!strncmp(name, "drive_", 6))
266 /* Drive node is detected */
267 tegra_pinctrl_set_drive(child, ret);
Svyatoslav Ryhel1fc2d612024-11-21 14:43:00 +0200268 else if (!strncmp(name, "mipi_pad_ctrl_", 14))
269 /* Handle T124 specific pinconfig */
270 tegra_pinctrl_set_mipipad(child, ret);
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +0200271 else
272 /* Pin node is detected */
273 tegra_pinctrl_set_pin(child, ret);
274 }
275
276 return 0;
277}
278
279static int tegra_pinctrl_get_pins_count(struct udevice *dev)
280{
281 return PMUX_PINGRP_COUNT;
282}
283
284static const char *tegra_pinctrl_get_pin_name(struct udevice *dev,
285 unsigned int selector)
286{
287 return tegra_pinctrl_to_pingrp[selector];
288}
289
290static int tegra_pinctrl_get_groups_count(struct udevice *dev)
291{
292 return PMUX_DRVGRP_COUNT;
293}
294
295static const char *tegra_pinctrl_get_group_name(struct udevice *dev,
296 unsigned int selector)
297{
298 return tegra_pinctrl_to_drvgrp[selector];
299}
300
301static int tegra_pinctrl_get_functions_count(struct udevice *dev)
302{
303 return PMUX_FUNC_COUNT;
304}
305
306static const char *tegra_pinctrl_get_function_name(struct udevice *dev,
307 unsigned int selector)
308{
309 return tegra_pinctrl_to_func[selector];
310}
311
312const struct pinctrl_ops tegra_pinctrl_ops = {
313 .get_pins_count = tegra_pinctrl_get_pins_count,
314 .get_pin_name = tegra_pinctrl_get_pin_name,
315 .get_groups_count = tegra_pinctrl_get_groups_count,
316 .get_group_name = tegra_pinctrl_get_group_name,
317 .get_functions_count = tegra_pinctrl_get_functions_count,
318 .get_function_name = tegra_pinctrl_get_function_name,
319 .set_state = tegra_pinctrl_set_state,
320};
321
322static int tegra_pinctrl_bind(struct udevice *dev)
323{
324 /*
325 * Make sure that the pinctrl driver gets probed after binding
326 * to provide initial configuration and assure that further
327 * probed devices are working correctly.
328 */
329 dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
330
331 return 0;
332}
333
334static const struct udevice_id tegra_pinctrl_ids[] = {
335 { .compatible = "nvidia,tegra30-pinmux" },
336 { .compatible = "nvidia,tegra114-pinmux" },
Svyatoslav Ryhel1fc2d612024-11-21 14:43:00 +0200337 { .compatible = "nvidia,tegra124-pinmux" },
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +0200338 { },
339};
340
341U_BOOT_DRIVER(tegra_pinctrl) = {
342 .name = "tegra_pinctrl",
343 .id = UCLASS_PINCTRL,
344 .of_match = tegra_pinctrl_ids,
345 .bind = tegra_pinctrl_bind,
346 .ops = &tegra_pinctrl_ops,
347};