1e7ae4cf2SDavid Wu // SPDX-License-Identifier: GPL-2.0+
2e7ae4cf2SDavid Wu /*
3e7ae4cf2SDavid Wu * (C) Copyright 2019 Rockchip Electronics Co., Ltd
4e7ae4cf2SDavid Wu */
5e7ae4cf2SDavid Wu
6e7ae4cf2SDavid Wu #include <common.h>
7e7ae4cf2SDavid Wu #include <dm.h>
8e7ae4cf2SDavid Wu #include <dm/pinctrl.h>
9e7ae4cf2SDavid Wu #include <regmap.h>
10e7ae4cf2SDavid Wu #include <syscon.h>
11e7ae4cf2SDavid Wu #include <fdtdec.h>
12e7ae4cf2SDavid Wu
13e7ae4cf2SDavid Wu #include "pinctrl-rockchip.h"
14e7ae4cf2SDavid Wu
15e7ae4cf2SDavid Wu #define MAX_ROCKCHIP_PINS_ENTRIES 30
16e7ae4cf2SDavid Wu #define MAX_ROCKCHIP_GPIO_PER_BANK 32
17e7ae4cf2SDavid Wu #define RK_FUNC_GPIO 0
18e7ae4cf2SDavid Wu
rockchip_verify_config(struct udevice * dev,u32 bank,u32 pin)19e7ae4cf2SDavid Wu static int rockchip_verify_config(struct udevice *dev, u32 bank, u32 pin)
20e7ae4cf2SDavid Wu {
21e7ae4cf2SDavid Wu struct rockchip_pinctrl_priv *priv = dev_get_priv(dev);
22e7ae4cf2SDavid Wu struct rockchip_pin_ctrl *ctrl = priv->ctrl;
23e7ae4cf2SDavid Wu
24e7ae4cf2SDavid Wu if (bank >= ctrl->nr_banks) {
25e7ae4cf2SDavid Wu debug("pin conf bank %d >= nbanks %d\n", bank, ctrl->nr_banks);
26e7ae4cf2SDavid Wu return -EINVAL;
27e7ae4cf2SDavid Wu }
28e7ae4cf2SDavid Wu
29e7ae4cf2SDavid Wu if (pin >= MAX_ROCKCHIP_GPIO_PER_BANK) {
30e7ae4cf2SDavid Wu debug("pin conf pin %d >= %d\n", pin,
31e7ae4cf2SDavid Wu MAX_ROCKCHIP_GPIO_PER_BANK);
32e7ae4cf2SDavid Wu return -EINVAL;
33e7ae4cf2SDavid Wu }
34e7ae4cf2SDavid Wu
35e7ae4cf2SDavid Wu return 0;
36e7ae4cf2SDavid Wu }
37e7ae4cf2SDavid Wu
rockchip_get_recalced_mux(struct rockchip_pin_bank * bank,int pin,int * reg,u8 * bit,int * mask)38e7ae4cf2SDavid Wu static void rockchip_get_recalced_mux(struct rockchip_pin_bank *bank, int pin,
39e7ae4cf2SDavid Wu int *reg, u8 *bit, int *mask)
40e7ae4cf2SDavid Wu {
41e7ae4cf2SDavid Wu struct rockchip_pinctrl_priv *priv = bank->priv;
42e7ae4cf2SDavid Wu struct rockchip_pin_ctrl *ctrl = priv->ctrl;
43e7ae4cf2SDavid Wu struct rockchip_mux_recalced_data *data;
44e7ae4cf2SDavid Wu int i;
45e7ae4cf2SDavid Wu
46e7ae4cf2SDavid Wu for (i = 0; i < ctrl->niomux_recalced; i++) {
47e7ae4cf2SDavid Wu data = &ctrl->iomux_recalced[i];
48e7ae4cf2SDavid Wu if (data->num == bank->bank_num &&
49e7ae4cf2SDavid Wu data->pin == pin)
50e7ae4cf2SDavid Wu break;
51e7ae4cf2SDavid Wu }
52e7ae4cf2SDavid Wu
53e7ae4cf2SDavid Wu if (i >= ctrl->niomux_recalced)
54e7ae4cf2SDavid Wu return;
55e7ae4cf2SDavid Wu
56e7ae4cf2SDavid Wu *reg = data->reg;
57e7ae4cf2SDavid Wu *mask = data->mask;
58e7ae4cf2SDavid Wu *bit = data->bit;
59e7ae4cf2SDavid Wu }
60e7ae4cf2SDavid Wu
rockchip_get_mux_route(struct rockchip_pin_bank * bank,int pin,int mux,u32 * reg,u32 * value)61e7ae4cf2SDavid Wu static bool rockchip_get_mux_route(struct rockchip_pin_bank *bank, int pin,
62e7ae4cf2SDavid Wu int mux, u32 *reg, u32 *value)
63e7ae4cf2SDavid Wu {
64e7ae4cf2SDavid Wu struct rockchip_pinctrl_priv *priv = bank->priv;
65e7ae4cf2SDavid Wu struct rockchip_pin_ctrl *ctrl = priv->ctrl;
66e7ae4cf2SDavid Wu struct rockchip_mux_route_data *data;
67e7ae4cf2SDavid Wu int i;
68e7ae4cf2SDavid Wu
69e7ae4cf2SDavid Wu for (i = 0; i < ctrl->niomux_routes; i++) {
70e7ae4cf2SDavid Wu data = &ctrl->iomux_routes[i];
71e7ae4cf2SDavid Wu if (data->bank_num == bank->bank_num &&
72e7ae4cf2SDavid Wu data->pin == pin && data->func == mux)
73e7ae4cf2SDavid Wu break;
74e7ae4cf2SDavid Wu }
75e7ae4cf2SDavid Wu
76e7ae4cf2SDavid Wu if (i >= ctrl->niomux_routes)
77e7ae4cf2SDavid Wu return false;
78e7ae4cf2SDavid Wu
79e7ae4cf2SDavid Wu *reg = data->route_offset;
80e7ae4cf2SDavid Wu *value = data->route_val;
81e7ae4cf2SDavid Wu
82e7ae4cf2SDavid Wu return true;
83e7ae4cf2SDavid Wu }
84e7ae4cf2SDavid Wu
rockchip_get_mux_data(int mux_type,int pin,u8 * bit,int * mask)85e7ae4cf2SDavid Wu static int rockchip_get_mux_data(int mux_type, int pin, u8 *bit, int *mask)
86e7ae4cf2SDavid Wu {
87e7ae4cf2SDavid Wu int offset = 0;
88e7ae4cf2SDavid Wu
89e7ae4cf2SDavid Wu if (mux_type & IOMUX_WIDTH_4BIT) {
90e7ae4cf2SDavid Wu if ((pin % 8) >= 4)
91e7ae4cf2SDavid Wu offset = 0x4;
92e7ae4cf2SDavid Wu *bit = (pin % 4) * 4;
93e7ae4cf2SDavid Wu *mask = 0xf;
94e7ae4cf2SDavid Wu } else if (mux_type & IOMUX_WIDTH_3BIT) {
95e7ae4cf2SDavid Wu /*
96e7ae4cf2SDavid Wu * pin0 ~ pin4 are at first register, and
97e7ae4cf2SDavid Wu * pin5 ~ pin7 are at second register.
98e7ae4cf2SDavid Wu */
99e7ae4cf2SDavid Wu if ((pin % 8) >= 5)
100e7ae4cf2SDavid Wu offset = 0x4;
101e7ae4cf2SDavid Wu *bit = (pin % 8 % 5) * 3;
102e7ae4cf2SDavid Wu *mask = 0x7;
103e7ae4cf2SDavid Wu } else {
104e7ae4cf2SDavid Wu *bit = (pin % 8) * 2;
105e7ae4cf2SDavid Wu *mask = 0x3;
106e7ae4cf2SDavid Wu }
107e7ae4cf2SDavid Wu
108e7ae4cf2SDavid Wu return offset;
109e7ae4cf2SDavid Wu }
110e7ae4cf2SDavid Wu
rockchip_get_mux(struct rockchip_pin_bank * bank,int pin)111e7ae4cf2SDavid Wu static int rockchip_get_mux(struct rockchip_pin_bank *bank, int pin)
112e7ae4cf2SDavid Wu {
113e7ae4cf2SDavid Wu struct rockchip_pinctrl_priv *priv = bank->priv;
114e7ae4cf2SDavid Wu int iomux_num = (pin / 8);
115e7ae4cf2SDavid Wu struct regmap *regmap;
116e7ae4cf2SDavid Wu unsigned int val;
117e7ae4cf2SDavid Wu int reg, ret, mask, mux_type;
118e7ae4cf2SDavid Wu u8 bit;
119e7ae4cf2SDavid Wu
120e7ae4cf2SDavid Wu if (iomux_num > 3)
121e7ae4cf2SDavid Wu return -EINVAL;
122e7ae4cf2SDavid Wu
123e7ae4cf2SDavid Wu if (bank->iomux[iomux_num].type & IOMUX_UNROUTED) {
124e7ae4cf2SDavid Wu debug("pin %d is unrouted\n", pin);
125e7ae4cf2SDavid Wu return -EINVAL;
126e7ae4cf2SDavid Wu }
127e7ae4cf2SDavid Wu
128e7ae4cf2SDavid Wu if (bank->iomux[iomux_num].type & IOMUX_GPIO_ONLY)
129e7ae4cf2SDavid Wu return RK_FUNC_GPIO;
130e7ae4cf2SDavid Wu
131e7ae4cf2SDavid Wu regmap = (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
132e7ae4cf2SDavid Wu ? priv->regmap_pmu : priv->regmap_base;
133e7ae4cf2SDavid Wu
134e7ae4cf2SDavid Wu /* get basic quadrupel of mux registers and the correct reg inside */
135e7ae4cf2SDavid Wu mux_type = bank->iomux[iomux_num].type;
136e7ae4cf2SDavid Wu reg = bank->iomux[iomux_num].offset;
137e7ae4cf2SDavid Wu reg += rockchip_get_mux_data(mux_type, pin, &bit, &mask);
138e7ae4cf2SDavid Wu
139e7ae4cf2SDavid Wu if (bank->recalced_mask & BIT(pin))
140e7ae4cf2SDavid Wu rockchip_get_recalced_mux(bank, pin, ®, &bit, &mask);
141e7ae4cf2SDavid Wu
142e7ae4cf2SDavid Wu ret = regmap_read(regmap, reg, &val);
143e7ae4cf2SDavid Wu if (ret)
144e7ae4cf2SDavid Wu return ret;
145e7ae4cf2SDavid Wu
146e7ae4cf2SDavid Wu return ((val >> bit) & mask);
147e7ae4cf2SDavid Wu }
148e7ae4cf2SDavid Wu
rockchip_pinctrl_get_gpio_mux(struct udevice * dev,int banknum,int index)149e7ae4cf2SDavid Wu static int rockchip_pinctrl_get_gpio_mux(struct udevice *dev, int banknum,
150e7ae4cf2SDavid Wu int index)
151e7ae4cf2SDavid Wu { struct rockchip_pinctrl_priv *priv = dev_get_priv(dev);
152e7ae4cf2SDavid Wu struct rockchip_pin_ctrl *ctrl = priv->ctrl;
153e7ae4cf2SDavid Wu
154e7ae4cf2SDavid Wu return rockchip_get_mux(&ctrl->pin_banks[banknum], index);
155e7ae4cf2SDavid Wu }
156e7ae4cf2SDavid Wu
rockchip_verify_mux(struct rockchip_pin_bank * bank,int pin,int mux)157e7ae4cf2SDavid Wu static int rockchip_verify_mux(struct rockchip_pin_bank *bank,
158e7ae4cf2SDavid Wu int pin, int mux)
159e7ae4cf2SDavid Wu {
160e7ae4cf2SDavid Wu int iomux_num = (pin / 8);
161e7ae4cf2SDavid Wu
162e7ae4cf2SDavid Wu if (iomux_num > 3)
163e7ae4cf2SDavid Wu return -EINVAL;
164e7ae4cf2SDavid Wu
165e7ae4cf2SDavid Wu if (bank->iomux[iomux_num].type & IOMUX_UNROUTED) {
166e7ae4cf2SDavid Wu debug("pin %d is unrouted\n", pin);
167e7ae4cf2SDavid Wu return -EINVAL;
168e7ae4cf2SDavid Wu }
169e7ae4cf2SDavid Wu
170e7ae4cf2SDavid Wu if (bank->iomux[iomux_num].type & IOMUX_GPIO_ONLY) {
171e7ae4cf2SDavid Wu if (mux != IOMUX_GPIO_ONLY) {
172e7ae4cf2SDavid Wu debug("pin %d only supports a gpio mux\n", pin);
173e7ae4cf2SDavid Wu return -ENOTSUPP;
174e7ae4cf2SDavid Wu }
175e7ae4cf2SDavid Wu }
176e7ae4cf2SDavid Wu
177e7ae4cf2SDavid Wu return 0;
178e7ae4cf2SDavid Wu }
179e7ae4cf2SDavid Wu
180e7ae4cf2SDavid Wu /*
181e7ae4cf2SDavid Wu * Set a new mux function for a pin.
182e7ae4cf2SDavid Wu *
183e7ae4cf2SDavid Wu * The register is divided into the upper and lower 16 bit. When changing
184e7ae4cf2SDavid Wu * a value, the previous register value is not read and changed. Instead
185e7ae4cf2SDavid Wu * it seems the changed bits are marked in the upper 16 bit, while the
186e7ae4cf2SDavid Wu * changed value gets set in the same offset in the lower 16 bit.
187e7ae4cf2SDavid Wu * All pin settings seem to be 2 bit wide in both the upper and lower
188e7ae4cf2SDavid Wu * parts.
189e7ae4cf2SDavid Wu * @bank: pin bank to change
190e7ae4cf2SDavid Wu * @pin: pin to change
191e7ae4cf2SDavid Wu * @mux: new mux function to set
192e7ae4cf2SDavid Wu */
rockchip_set_mux(struct rockchip_pin_bank * bank,int pin,int mux)193e7ae4cf2SDavid Wu static int rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
194e7ae4cf2SDavid Wu {
195e7ae4cf2SDavid Wu struct rockchip_pinctrl_priv *priv = bank->priv;
196e7ae4cf2SDavid Wu int iomux_num = (pin / 8);
197e7ae4cf2SDavid Wu struct regmap *regmap;
198e7ae4cf2SDavid Wu int reg, ret, mask, mux_type;
199e7ae4cf2SDavid Wu u8 bit;
200e7ae4cf2SDavid Wu u32 data, route_reg, route_val;
201e7ae4cf2SDavid Wu
202e7ae4cf2SDavid Wu ret = rockchip_verify_mux(bank, pin, mux);
203e7ae4cf2SDavid Wu if (ret < 0)
204e7ae4cf2SDavid Wu return ret;
205e7ae4cf2SDavid Wu
206e7ae4cf2SDavid Wu if (bank->iomux[iomux_num].type & IOMUX_GPIO_ONLY)
207e7ae4cf2SDavid Wu return 0;
208e7ae4cf2SDavid Wu
209e7ae4cf2SDavid Wu debug("setting mux of GPIO%d-%d to %d\n", bank->bank_num, pin, mux);
210e7ae4cf2SDavid Wu
211e7ae4cf2SDavid Wu regmap = (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
212e7ae4cf2SDavid Wu ? priv->regmap_pmu : priv->regmap_base;
213e7ae4cf2SDavid Wu
214e7ae4cf2SDavid Wu /* get basic quadrupel of mux registers and the correct reg inside */
215e7ae4cf2SDavid Wu mux_type = bank->iomux[iomux_num].type;
216e7ae4cf2SDavid Wu reg = bank->iomux[iomux_num].offset;
217e7ae4cf2SDavid Wu reg += rockchip_get_mux_data(mux_type, pin, &bit, &mask);
218e7ae4cf2SDavid Wu
219e7ae4cf2SDavid Wu if (bank->recalced_mask & BIT(pin))
220e7ae4cf2SDavid Wu rockchip_get_recalced_mux(bank, pin, ®, &bit, &mask);
221e7ae4cf2SDavid Wu
222e7ae4cf2SDavid Wu if (bank->route_mask & BIT(pin)) {
223e7ae4cf2SDavid Wu if (rockchip_get_mux_route(bank, pin, mux, &route_reg,
224e7ae4cf2SDavid Wu &route_val)) {
225e7ae4cf2SDavid Wu ret = regmap_write(regmap, route_reg, route_val);
226e7ae4cf2SDavid Wu if (ret)
227e7ae4cf2SDavid Wu return ret;
228e7ae4cf2SDavid Wu }
229e7ae4cf2SDavid Wu }
230e7ae4cf2SDavid Wu
231*50298091SDavid Wu if (mux_type & IOMUX_WRITABLE_32BIT) {
232*50298091SDavid Wu regmap_read(regmap, reg, &data);
233*50298091SDavid Wu data &= ~(mask << bit);
234*50298091SDavid Wu } else {
235e7ae4cf2SDavid Wu data = (mask << (bit + 16));
236*50298091SDavid Wu }
237*50298091SDavid Wu
238e7ae4cf2SDavid Wu data |= (mux & mask) << bit;
239e7ae4cf2SDavid Wu ret = regmap_write(regmap, reg, data);
240e7ae4cf2SDavid Wu
241e7ae4cf2SDavid Wu return ret;
242e7ae4cf2SDavid Wu }
243e7ae4cf2SDavid Wu
244e7ae4cf2SDavid Wu static int rockchip_perpin_drv_list[DRV_TYPE_MAX][8] = {
245e7ae4cf2SDavid Wu { 2, 4, 8, 12, -1, -1, -1, -1 },
246e7ae4cf2SDavid Wu { 3, 6, 9, 12, -1, -1, -1, -1 },
247e7ae4cf2SDavid Wu { 5, 10, 15, 20, -1, -1, -1, -1 },
248e7ae4cf2SDavid Wu { 4, 6, 8, 10, 12, 14, 16, 18 },
249e7ae4cf2SDavid Wu { 4, 7, 10, 13, 16, 19, 22, 26 }
250e7ae4cf2SDavid Wu };
251e7ae4cf2SDavid Wu
rockchip_set_drive_perpin(struct rockchip_pin_bank * bank,int pin_num,int strength)252e7ae4cf2SDavid Wu static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank,
253e7ae4cf2SDavid Wu int pin_num, int strength)
254e7ae4cf2SDavid Wu {
255e7ae4cf2SDavid Wu struct rockchip_pinctrl_priv *priv = bank->priv;
256e7ae4cf2SDavid Wu struct rockchip_pin_ctrl *ctrl = priv->ctrl;
257e7ae4cf2SDavid Wu struct regmap *regmap;
258e7ae4cf2SDavid Wu int reg, ret, i;
259e7ae4cf2SDavid Wu u32 data, rmask_bits, temp;
260e7ae4cf2SDavid Wu u8 bit;
261*50298091SDavid Wu /* Where need to clean the special mask for rockchip_perpin_drv_list */
262*50298091SDavid Wu int drv_type = bank->drv[pin_num / 8].drv_type & (~DRV_TYPE_IO_MASK);
263e7ae4cf2SDavid Wu
264e7ae4cf2SDavid Wu debug("setting drive of GPIO%d-%d to %d\n", bank->bank_num,
265e7ae4cf2SDavid Wu pin_num, strength);
266e7ae4cf2SDavid Wu
267e7ae4cf2SDavid Wu ctrl->drv_calc_reg(bank, pin_num, ®map, ®, &bit);
268e7ae4cf2SDavid Wu
269e7ae4cf2SDavid Wu ret = -EINVAL;
270e7ae4cf2SDavid Wu for (i = 0; i < ARRAY_SIZE(rockchip_perpin_drv_list[drv_type]); i++) {
271e7ae4cf2SDavid Wu if (rockchip_perpin_drv_list[drv_type][i] == strength) {
272e7ae4cf2SDavid Wu ret = i;
273e7ae4cf2SDavid Wu break;
274e7ae4cf2SDavid Wu } else if (rockchip_perpin_drv_list[drv_type][i] < 0) {
275e7ae4cf2SDavid Wu ret = rockchip_perpin_drv_list[drv_type][i];
276e7ae4cf2SDavid Wu break;
277e7ae4cf2SDavid Wu }
278e7ae4cf2SDavid Wu }
279e7ae4cf2SDavid Wu
280e7ae4cf2SDavid Wu if (ret < 0) {
281e7ae4cf2SDavid Wu debug("unsupported driver strength %d\n", strength);
282e7ae4cf2SDavid Wu return ret;
283e7ae4cf2SDavid Wu }
284e7ae4cf2SDavid Wu
285e7ae4cf2SDavid Wu switch (drv_type) {
286e7ae4cf2SDavid Wu case DRV_TYPE_IO_1V8_3V0_AUTO:
287e7ae4cf2SDavid Wu case DRV_TYPE_IO_3V3_ONLY:
288e7ae4cf2SDavid Wu rmask_bits = ROCKCHIP_DRV_3BITS_PER_PIN;
289e7ae4cf2SDavid Wu switch (bit) {
290e7ae4cf2SDavid Wu case 0 ... 12:
291e7ae4cf2SDavid Wu /* regular case, nothing to do */
292e7ae4cf2SDavid Wu break;
293e7ae4cf2SDavid Wu case 15:
294e7ae4cf2SDavid Wu /*
295e7ae4cf2SDavid Wu * drive-strength offset is special, as it is spread
296e7ae4cf2SDavid Wu * over 2 registers, the bit data[15] contains bit 0
297e7ae4cf2SDavid Wu * of the value while temp[1:0] contains bits 2 and 1
298e7ae4cf2SDavid Wu */
299e7ae4cf2SDavid Wu data = (ret & 0x1) << 15;
300e7ae4cf2SDavid Wu temp = (ret >> 0x1) & 0x3;
301e7ae4cf2SDavid Wu
302e7ae4cf2SDavid Wu data |= BIT(31);
303e7ae4cf2SDavid Wu ret = regmap_write(regmap, reg, data);
304e7ae4cf2SDavid Wu if (ret)
305e7ae4cf2SDavid Wu return ret;
306e7ae4cf2SDavid Wu
307e7ae4cf2SDavid Wu temp |= (0x3 << 16);
308e7ae4cf2SDavid Wu reg += 0x4;
309e7ae4cf2SDavid Wu ret = regmap_write(regmap, reg, temp);
310e7ae4cf2SDavid Wu
311e7ae4cf2SDavid Wu return ret;
312e7ae4cf2SDavid Wu case 18 ... 21:
313e7ae4cf2SDavid Wu /* setting fully enclosed in the second register */
314e7ae4cf2SDavid Wu reg += 4;
315e7ae4cf2SDavid Wu bit -= 16;
316e7ae4cf2SDavid Wu break;
317e7ae4cf2SDavid Wu default:
318e7ae4cf2SDavid Wu debug("unsupported bit: %d for pinctrl drive type: %d\n",
319e7ae4cf2SDavid Wu bit, drv_type);
320e7ae4cf2SDavid Wu return -EINVAL;
321e7ae4cf2SDavid Wu }
322e7ae4cf2SDavid Wu break;
323e7ae4cf2SDavid Wu case DRV_TYPE_IO_DEFAULT:
324e7ae4cf2SDavid Wu case DRV_TYPE_IO_1V8_OR_3V0:
325e7ae4cf2SDavid Wu case DRV_TYPE_IO_1V8_ONLY:
326e7ae4cf2SDavid Wu rmask_bits = ROCKCHIP_DRV_BITS_PER_PIN;
327e7ae4cf2SDavid Wu break;
328e7ae4cf2SDavid Wu default:
329e7ae4cf2SDavid Wu debug("unsupported pinctrl drive type: %d\n",
330e7ae4cf2SDavid Wu drv_type);
331e7ae4cf2SDavid Wu return -EINVAL;
332e7ae4cf2SDavid Wu }
333e7ae4cf2SDavid Wu
334*50298091SDavid Wu if (bank->drv[pin_num / 8].drv_type & DRV_TYPE_WRITABLE_32BIT) {
335*50298091SDavid Wu regmap_read(regmap, reg, &data);
336*50298091SDavid Wu data &= ~(((1 << rmask_bits) - 1) << bit);
337*50298091SDavid Wu } else {
338e7ae4cf2SDavid Wu /* enable the write to the equivalent lower bits */
339e7ae4cf2SDavid Wu data = ((1 << rmask_bits) - 1) << (bit + 16);
340*50298091SDavid Wu }
341e7ae4cf2SDavid Wu
342*50298091SDavid Wu data |= (ret << bit);
343e7ae4cf2SDavid Wu ret = regmap_write(regmap, reg, data);
344e7ae4cf2SDavid Wu return ret;
345e7ae4cf2SDavid Wu }
346e7ae4cf2SDavid Wu
347e7ae4cf2SDavid Wu static int rockchip_pull_list[PULL_TYPE_MAX][4] = {
348e7ae4cf2SDavid Wu {
349e7ae4cf2SDavid Wu PIN_CONFIG_BIAS_DISABLE,
350e7ae4cf2SDavid Wu PIN_CONFIG_BIAS_PULL_UP,
351e7ae4cf2SDavid Wu PIN_CONFIG_BIAS_PULL_DOWN,
352e7ae4cf2SDavid Wu PIN_CONFIG_BIAS_BUS_HOLD
353e7ae4cf2SDavid Wu },
354e7ae4cf2SDavid Wu {
355e7ae4cf2SDavid Wu PIN_CONFIG_BIAS_DISABLE,
356e7ae4cf2SDavid Wu PIN_CONFIG_BIAS_PULL_DOWN,
357e7ae4cf2SDavid Wu PIN_CONFIG_BIAS_DISABLE,
358e7ae4cf2SDavid Wu PIN_CONFIG_BIAS_PULL_UP
359e7ae4cf2SDavid Wu },
360e7ae4cf2SDavid Wu };
361e7ae4cf2SDavid Wu
rockchip_set_pull(struct rockchip_pin_bank * bank,int pin_num,int pull)362e7ae4cf2SDavid Wu static int rockchip_set_pull(struct rockchip_pin_bank *bank,
363e7ae4cf2SDavid Wu int pin_num, int pull)
364e7ae4cf2SDavid Wu {
365e7ae4cf2SDavid Wu struct rockchip_pinctrl_priv *priv = bank->priv;
366e7ae4cf2SDavid Wu struct rockchip_pin_ctrl *ctrl = priv->ctrl;
367e7ae4cf2SDavid Wu struct regmap *regmap;
368e7ae4cf2SDavid Wu int reg, ret, i, pull_type;
369e7ae4cf2SDavid Wu u8 bit;
370e7ae4cf2SDavid Wu u32 data;
371e7ae4cf2SDavid Wu
372e7ae4cf2SDavid Wu debug("setting pull of GPIO%d-%d to %d\n", bank->bank_num,
373e7ae4cf2SDavid Wu pin_num, pull);
374e7ae4cf2SDavid Wu
375e7ae4cf2SDavid Wu ctrl->pull_calc_reg(bank, pin_num, ®map, ®, &bit);
376e7ae4cf2SDavid Wu
377e7ae4cf2SDavid Wu switch (ctrl->type) {
378e7ae4cf2SDavid Wu case RK3036:
379e7ae4cf2SDavid Wu case RK3128:
380e7ae4cf2SDavid Wu data = BIT(bit + 16);
381e7ae4cf2SDavid Wu if (pull == PIN_CONFIG_BIAS_DISABLE)
382e7ae4cf2SDavid Wu data |= BIT(bit);
383e7ae4cf2SDavid Wu ret = regmap_write(regmap, reg, data);
384e7ae4cf2SDavid Wu break;
385e7ae4cf2SDavid Wu case RV1108:
386e7ae4cf2SDavid Wu case RK3188:
387e7ae4cf2SDavid Wu case RK3288:
388e7ae4cf2SDavid Wu case RK3368:
389e7ae4cf2SDavid Wu case RK3399:
390*50298091SDavid Wu /*
391*50298091SDavid Wu * Where need to clean the special mask for
392*50298091SDavid Wu * rockchip_pull_list.
393*50298091SDavid Wu */
394*50298091SDavid Wu pull_type = bank->pull_type[pin_num / 8] & (~PULL_TYPE_IO_MASK);
395e7ae4cf2SDavid Wu ret = -EINVAL;
396e7ae4cf2SDavid Wu for (i = 0; i < ARRAY_SIZE(rockchip_pull_list[pull_type]);
397e7ae4cf2SDavid Wu i++) {
398e7ae4cf2SDavid Wu if (rockchip_pull_list[pull_type][i] == pull) {
399e7ae4cf2SDavid Wu ret = i;
400e7ae4cf2SDavid Wu break;
401e7ae4cf2SDavid Wu }
402e7ae4cf2SDavid Wu }
403e7ae4cf2SDavid Wu
404e7ae4cf2SDavid Wu if (ret < 0) {
405e7ae4cf2SDavid Wu debug("unsupported pull setting %d\n", pull);
406e7ae4cf2SDavid Wu return ret;
407e7ae4cf2SDavid Wu }
408e7ae4cf2SDavid Wu
409*50298091SDavid Wu if (bank->pull_type[pin_num / 8] & PULL_TYPE_WRITABLE_32BIT) {
410*50298091SDavid Wu regmap_read(regmap, reg, &data);
411*50298091SDavid Wu data &= ~(((1 << ROCKCHIP_PULL_BITS_PER_PIN) - 1) << bit);
412*50298091SDavid Wu } else {
413e7ae4cf2SDavid Wu /* enable the write to the equivalent lower bits */
414e7ae4cf2SDavid Wu data = ((1 << ROCKCHIP_PULL_BITS_PER_PIN) - 1) << (bit + 16);
415*50298091SDavid Wu }
416e7ae4cf2SDavid Wu
417*50298091SDavid Wu data |= (ret << bit);
418e7ae4cf2SDavid Wu ret = regmap_write(regmap, reg, data);
419e7ae4cf2SDavid Wu break;
420e7ae4cf2SDavid Wu default:
421e7ae4cf2SDavid Wu debug("unsupported pinctrl type\n");
422e7ae4cf2SDavid Wu return -EINVAL;
423e7ae4cf2SDavid Wu }
424e7ae4cf2SDavid Wu
425e7ae4cf2SDavid Wu return ret;
426e7ae4cf2SDavid Wu }
427e7ae4cf2SDavid Wu
rockchip_set_schmitt(struct rockchip_pin_bank * bank,int pin_num,int enable)428e7ae4cf2SDavid Wu static int rockchip_set_schmitt(struct rockchip_pin_bank *bank,
429e7ae4cf2SDavid Wu int pin_num, int enable)
430e7ae4cf2SDavid Wu {
431e7ae4cf2SDavid Wu struct rockchip_pinctrl_priv *priv = bank->priv;
432e7ae4cf2SDavid Wu struct rockchip_pin_ctrl *ctrl = priv->ctrl;
433e7ae4cf2SDavid Wu struct regmap *regmap;
434e7ae4cf2SDavid Wu int reg, ret;
435e7ae4cf2SDavid Wu u8 bit;
436e7ae4cf2SDavid Wu u32 data;
437e7ae4cf2SDavid Wu
438e7ae4cf2SDavid Wu debug("setting input schmitt of GPIO%d-%d to %d\n", bank->bank_num,
439e7ae4cf2SDavid Wu pin_num, enable);
440e7ae4cf2SDavid Wu
441e7ae4cf2SDavid Wu ret = ctrl->schmitt_calc_reg(bank, pin_num, ®map, ®, &bit);
442e7ae4cf2SDavid Wu if (ret)
443e7ae4cf2SDavid Wu return ret;
444e7ae4cf2SDavid Wu
445e7ae4cf2SDavid Wu /* enable the write to the equivalent lower bits */
446e7ae4cf2SDavid Wu data = BIT(bit + 16) | (enable << bit);
447e7ae4cf2SDavid Wu
448e7ae4cf2SDavid Wu return regmap_write(regmap, reg, data);
449e7ae4cf2SDavid Wu }
450e7ae4cf2SDavid Wu
451e7ae4cf2SDavid Wu /*
452e7ae4cf2SDavid Wu * Pinconf_ops handling
453e7ae4cf2SDavid Wu */
rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl * ctrl,unsigned int pull)454e7ae4cf2SDavid Wu static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl,
455e7ae4cf2SDavid Wu unsigned int pull)
456e7ae4cf2SDavid Wu {
457e7ae4cf2SDavid Wu switch (ctrl->type) {
458e7ae4cf2SDavid Wu case RK3036:
459e7ae4cf2SDavid Wu case RK3128:
460e7ae4cf2SDavid Wu return (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT ||
461e7ae4cf2SDavid Wu pull == PIN_CONFIG_BIAS_DISABLE);
462e7ae4cf2SDavid Wu case RV1108:
463e7ae4cf2SDavid Wu case RK3188:
464e7ae4cf2SDavid Wu case RK3288:
465e7ae4cf2SDavid Wu case RK3368:
466e7ae4cf2SDavid Wu case RK3399:
467e7ae4cf2SDavid Wu return (pull != PIN_CONFIG_BIAS_PULL_PIN_DEFAULT);
468e7ae4cf2SDavid Wu }
469e7ae4cf2SDavid Wu
470e7ae4cf2SDavid Wu return false;
471e7ae4cf2SDavid Wu }
472e7ae4cf2SDavid Wu
473e7ae4cf2SDavid Wu /* set the pin config settings for a specified pin */
rockchip_pinconf_set(struct rockchip_pin_bank * bank,u32 pin,u32 param,u32 arg)474e7ae4cf2SDavid Wu static int rockchip_pinconf_set(struct rockchip_pin_bank *bank,
475e7ae4cf2SDavid Wu u32 pin, u32 param, u32 arg)
476e7ae4cf2SDavid Wu {
477e7ae4cf2SDavid Wu struct rockchip_pinctrl_priv *priv = bank->priv;
478e7ae4cf2SDavid Wu struct rockchip_pin_ctrl *ctrl = priv->ctrl;
479e7ae4cf2SDavid Wu int rc;
480e7ae4cf2SDavid Wu
481e7ae4cf2SDavid Wu switch (param) {
482e7ae4cf2SDavid Wu case PIN_CONFIG_BIAS_DISABLE:
483e7ae4cf2SDavid Wu rc = rockchip_set_pull(bank, pin, param);
484e7ae4cf2SDavid Wu if (rc)
485e7ae4cf2SDavid Wu return rc;
486e7ae4cf2SDavid Wu break;
487e7ae4cf2SDavid Wu
488e7ae4cf2SDavid Wu case PIN_CONFIG_BIAS_PULL_UP:
489e7ae4cf2SDavid Wu case PIN_CONFIG_BIAS_PULL_DOWN:
490e7ae4cf2SDavid Wu case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
491e7ae4cf2SDavid Wu case PIN_CONFIG_BIAS_BUS_HOLD:
492e7ae4cf2SDavid Wu if (!rockchip_pinconf_pull_valid(ctrl, param))
493e7ae4cf2SDavid Wu return -ENOTSUPP;
494e7ae4cf2SDavid Wu
495e7ae4cf2SDavid Wu if (!arg)
496e7ae4cf2SDavid Wu return -EINVAL;
497e7ae4cf2SDavid Wu
498e7ae4cf2SDavid Wu rc = rockchip_set_pull(bank, pin, param);
499e7ae4cf2SDavid Wu if (rc)
500e7ae4cf2SDavid Wu return rc;
501e7ae4cf2SDavid Wu break;
502e7ae4cf2SDavid Wu
503e7ae4cf2SDavid Wu case PIN_CONFIG_DRIVE_STRENGTH:
504e7ae4cf2SDavid Wu if (!ctrl->drv_calc_reg)
505e7ae4cf2SDavid Wu return -ENOTSUPP;
506e7ae4cf2SDavid Wu
507e7ae4cf2SDavid Wu rc = rockchip_set_drive_perpin(bank, pin, arg);
508e7ae4cf2SDavid Wu if (rc < 0)
509e7ae4cf2SDavid Wu return rc;
510e7ae4cf2SDavid Wu break;
511e7ae4cf2SDavid Wu
512e7ae4cf2SDavid Wu case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
513e7ae4cf2SDavid Wu if (!ctrl->schmitt_calc_reg)
514e7ae4cf2SDavid Wu return -ENOTSUPP;
515e7ae4cf2SDavid Wu
516e7ae4cf2SDavid Wu rc = rockchip_set_schmitt(bank, pin, arg);
517e7ae4cf2SDavid Wu if (rc < 0)
518e7ae4cf2SDavid Wu return rc;
519e7ae4cf2SDavid Wu break;
520e7ae4cf2SDavid Wu
521e7ae4cf2SDavid Wu default:
522e7ae4cf2SDavid Wu break;
523e7ae4cf2SDavid Wu }
524e7ae4cf2SDavid Wu
525e7ae4cf2SDavid Wu return 0;
526e7ae4cf2SDavid Wu }
527e7ae4cf2SDavid Wu
528e7ae4cf2SDavid Wu static const struct pinconf_param rockchip_conf_params[] = {
529e7ae4cf2SDavid Wu { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
530e7ae4cf2SDavid Wu { "bias-bus-hold", PIN_CONFIG_BIAS_BUS_HOLD, 0 },
531e7ae4cf2SDavid Wu { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
532e7ae4cf2SDavid Wu { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
533e7ae4cf2SDavid Wu { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
534e7ae4cf2SDavid Wu { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
535e7ae4cf2SDavid Wu { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
536e7ae4cf2SDavid Wu { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
537e7ae4cf2SDavid Wu { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
538e7ae4cf2SDavid Wu };
539e7ae4cf2SDavid Wu
rockchip_pinconf_prop_name_to_param(const char * property,u32 * default_value)540e7ae4cf2SDavid Wu static int rockchip_pinconf_prop_name_to_param(const char *property,
541e7ae4cf2SDavid Wu u32 *default_value)
542e7ae4cf2SDavid Wu {
543e7ae4cf2SDavid Wu const struct pinconf_param *p, *end;
544e7ae4cf2SDavid Wu
545e7ae4cf2SDavid Wu p = rockchip_conf_params;
546e7ae4cf2SDavid Wu end = p + sizeof(rockchip_conf_params) / sizeof(struct pinconf_param);
547e7ae4cf2SDavid Wu
548e7ae4cf2SDavid Wu /* See if this pctldev supports this parameter */
549e7ae4cf2SDavid Wu for (; p < end; p++) {
550e7ae4cf2SDavid Wu if (!strcmp(property, p->property)) {
551e7ae4cf2SDavid Wu *default_value = p->default_value;
552e7ae4cf2SDavid Wu return p->param;
553e7ae4cf2SDavid Wu }
554e7ae4cf2SDavid Wu }
555e7ae4cf2SDavid Wu
556e7ae4cf2SDavid Wu *default_value = 0;
557e7ae4cf2SDavid Wu return -EPERM;
558e7ae4cf2SDavid Wu }
559e7ae4cf2SDavid Wu
rockchip_pinctrl_set_state(struct udevice * dev,struct udevice * config)560e7ae4cf2SDavid Wu static int rockchip_pinctrl_set_state(struct udevice *dev,
561e7ae4cf2SDavid Wu struct udevice *config)
562e7ae4cf2SDavid Wu {
563e7ae4cf2SDavid Wu struct rockchip_pinctrl_priv *priv = dev_get_priv(dev);
564e7ae4cf2SDavid Wu struct rockchip_pin_ctrl *ctrl = priv->ctrl;
565e7ae4cf2SDavid Wu u32 cells[MAX_ROCKCHIP_PINS_ENTRIES * 4];
566e7ae4cf2SDavid Wu u32 bank, pin, mux, conf, arg, default_val;
567e7ae4cf2SDavid Wu int ret, count, i;
568e7ae4cf2SDavid Wu const char *prop_name;
569e7ae4cf2SDavid Wu const void *value;
570e7ae4cf2SDavid Wu int prop_len, param;
571e7ae4cf2SDavid Wu const u32 *data;
572e7ae4cf2SDavid Wu ofnode node;
573e7ae4cf2SDavid Wu #ifdef CONFIG_OF_LIVE
574e7ae4cf2SDavid Wu const struct device_node *np;
575e7ae4cf2SDavid Wu struct property *pp;
576e7ae4cf2SDavid Wu #else
577e7ae4cf2SDavid Wu int property_offset, pcfg_node;
578e7ae4cf2SDavid Wu const void *blob = gd->fdt_blob;
579e7ae4cf2SDavid Wu #endif
580e7ae4cf2SDavid Wu data = dev_read_prop(config, "rockchip,pins", &count);
581e7ae4cf2SDavid Wu if (count < 0) {
582e7ae4cf2SDavid Wu debug("%s: bad array size %d\n", __func__, count);
583e7ae4cf2SDavid Wu return -EINVAL;
584e7ae4cf2SDavid Wu }
585e7ae4cf2SDavid Wu
586e7ae4cf2SDavid Wu count /= sizeof(u32);
587e7ae4cf2SDavid Wu if (count > MAX_ROCKCHIP_PINS_ENTRIES * 4) {
588e7ae4cf2SDavid Wu debug("%s: unsupported pins array count %d\n",
589e7ae4cf2SDavid Wu __func__, count);
590e7ae4cf2SDavid Wu return -EINVAL;
591e7ae4cf2SDavid Wu }
592e7ae4cf2SDavid Wu
593e7ae4cf2SDavid Wu for (i = 0; i < count; i++)
594e7ae4cf2SDavid Wu cells[i] = fdt32_to_cpu(data[i]);
595e7ae4cf2SDavid Wu
596e7ae4cf2SDavid Wu for (i = 0; i < (count >> 2); i++) {
597e7ae4cf2SDavid Wu bank = cells[4 * i + 0];
598e7ae4cf2SDavid Wu pin = cells[4 * i + 1];
599e7ae4cf2SDavid Wu mux = cells[4 * i + 2];
600e7ae4cf2SDavid Wu conf = cells[4 * i + 3];
601e7ae4cf2SDavid Wu
602e7ae4cf2SDavid Wu ret = rockchip_verify_config(dev, bank, pin);
603e7ae4cf2SDavid Wu if (ret)
604e7ae4cf2SDavid Wu return ret;
605e7ae4cf2SDavid Wu
606e7ae4cf2SDavid Wu ret = rockchip_set_mux(&ctrl->pin_banks[bank], pin, mux);
607e7ae4cf2SDavid Wu if (ret)
608e7ae4cf2SDavid Wu return ret;
609e7ae4cf2SDavid Wu
610e7ae4cf2SDavid Wu node = ofnode_get_by_phandle(conf);
611e7ae4cf2SDavid Wu if (!ofnode_valid(node))
612e7ae4cf2SDavid Wu return -ENODEV;
613e7ae4cf2SDavid Wu #ifdef CONFIG_OF_LIVE
614e7ae4cf2SDavid Wu np = ofnode_to_np(node);
615e7ae4cf2SDavid Wu for (pp = np->properties; pp; pp = pp->next) {
616e7ae4cf2SDavid Wu prop_name = pp->name;
617e7ae4cf2SDavid Wu prop_len = pp->length;
618e7ae4cf2SDavid Wu value = pp->value;
619e7ae4cf2SDavid Wu #else
620e7ae4cf2SDavid Wu pcfg_node = ofnode_to_offset(node);
621e7ae4cf2SDavid Wu fdt_for_each_property_offset(property_offset, blob, pcfg_node) {
622e7ae4cf2SDavid Wu value = fdt_getprop_by_offset(blob, property_offset,
623e7ae4cf2SDavid Wu &prop_name, &prop_len);
624e7ae4cf2SDavid Wu if (!value)
625e7ae4cf2SDavid Wu return -ENOENT;
626e7ae4cf2SDavid Wu #endif
627e7ae4cf2SDavid Wu param = rockchip_pinconf_prop_name_to_param(prop_name,
628e7ae4cf2SDavid Wu &default_val);
629e7ae4cf2SDavid Wu if (param < 0)
630e7ae4cf2SDavid Wu break;
631e7ae4cf2SDavid Wu
632e7ae4cf2SDavid Wu if (prop_len >= sizeof(fdt32_t))
633e7ae4cf2SDavid Wu arg = fdt32_to_cpu(*(fdt32_t *)value);
634e7ae4cf2SDavid Wu else
635e7ae4cf2SDavid Wu arg = default_val;
636e7ae4cf2SDavid Wu
637e7ae4cf2SDavid Wu ret = rockchip_pinconf_set(&ctrl->pin_banks[bank], pin,
638e7ae4cf2SDavid Wu param, arg);
639e7ae4cf2SDavid Wu if (ret) {
640e7ae4cf2SDavid Wu debug("%s: rockchip_pinconf_set fail: %d\n",
641e7ae4cf2SDavid Wu __func__, ret);
642e7ae4cf2SDavid Wu return ret;
643e7ae4cf2SDavid Wu }
644e7ae4cf2SDavid Wu }
645e7ae4cf2SDavid Wu }
646e7ae4cf2SDavid Wu
647e7ae4cf2SDavid Wu return 0;
648e7ae4cf2SDavid Wu }
649e7ae4cf2SDavid Wu
650e7ae4cf2SDavid Wu const struct pinctrl_ops rockchip_pinctrl_ops = {
651e7ae4cf2SDavid Wu .set_state = rockchip_pinctrl_set_state,
652e7ae4cf2SDavid Wu .get_gpio_mux = rockchip_pinctrl_get_gpio_mux,
653e7ae4cf2SDavid Wu };
654e7ae4cf2SDavid Wu
655e7ae4cf2SDavid Wu /* retrieve the soc specific data */
656e7ae4cf2SDavid Wu static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data(struct udevice *dev)
657e7ae4cf2SDavid Wu {
658e7ae4cf2SDavid Wu struct rockchip_pinctrl_priv *priv = dev_get_priv(dev);
659e7ae4cf2SDavid Wu struct rockchip_pin_ctrl *ctrl =
660e7ae4cf2SDavid Wu (struct rockchip_pin_ctrl *)dev_get_driver_data(dev);
661e7ae4cf2SDavid Wu struct rockchip_pin_bank *bank;
662e7ae4cf2SDavid Wu int grf_offs, pmu_offs, drv_grf_offs, drv_pmu_offs, i, j;
663e7ae4cf2SDavid Wu
664e7ae4cf2SDavid Wu grf_offs = ctrl->grf_mux_offset;
665e7ae4cf2SDavid Wu pmu_offs = ctrl->pmu_mux_offset;
666e7ae4cf2SDavid Wu drv_pmu_offs = ctrl->pmu_drv_offset;
667e7ae4cf2SDavid Wu drv_grf_offs = ctrl->grf_drv_offset;
668e7ae4cf2SDavid Wu bank = ctrl->pin_banks;
669e7ae4cf2SDavid Wu
670e7ae4cf2SDavid Wu for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
671e7ae4cf2SDavid Wu int bank_pins = 0;
672e7ae4cf2SDavid Wu
673e7ae4cf2SDavid Wu bank->priv = priv;
674e7ae4cf2SDavid Wu bank->pin_base = ctrl->nr_pins;
675e7ae4cf2SDavid Wu ctrl->nr_pins += bank->nr_pins;
676e7ae4cf2SDavid Wu
677e7ae4cf2SDavid Wu /* calculate iomux and drv offsets */
678e7ae4cf2SDavid Wu for (j = 0; j < 4; j++) {
679e7ae4cf2SDavid Wu struct rockchip_iomux *iom = &bank->iomux[j];
680e7ae4cf2SDavid Wu struct rockchip_drv *drv = &bank->drv[j];
681e7ae4cf2SDavid Wu int inc;
682e7ae4cf2SDavid Wu
683e7ae4cf2SDavid Wu if (bank_pins >= bank->nr_pins)
684e7ae4cf2SDavid Wu break;
685e7ae4cf2SDavid Wu
686e7ae4cf2SDavid Wu /* preset iomux offset value, set new start value */
687e7ae4cf2SDavid Wu if (iom->offset >= 0) {
688e7ae4cf2SDavid Wu if (iom->type & IOMUX_SOURCE_PMU)
689e7ae4cf2SDavid Wu pmu_offs = iom->offset;
690e7ae4cf2SDavid Wu else
691e7ae4cf2SDavid Wu grf_offs = iom->offset;
692e7ae4cf2SDavid Wu } else { /* set current iomux offset */
693e7ae4cf2SDavid Wu iom->offset = (iom->type & IOMUX_SOURCE_PMU) ?
694e7ae4cf2SDavid Wu pmu_offs : grf_offs;
695e7ae4cf2SDavid Wu }
696e7ae4cf2SDavid Wu
697e7ae4cf2SDavid Wu /* preset drv offset value, set new start value */
698e7ae4cf2SDavid Wu if (drv->offset >= 0) {
699e7ae4cf2SDavid Wu if (iom->type & IOMUX_SOURCE_PMU)
700e7ae4cf2SDavid Wu drv_pmu_offs = drv->offset;
701e7ae4cf2SDavid Wu else
702e7ae4cf2SDavid Wu drv_grf_offs = drv->offset;
703e7ae4cf2SDavid Wu } else { /* set current drv offset */
704e7ae4cf2SDavid Wu drv->offset = (iom->type & IOMUX_SOURCE_PMU) ?
705e7ae4cf2SDavid Wu drv_pmu_offs : drv_grf_offs;
706e7ae4cf2SDavid Wu }
707e7ae4cf2SDavid Wu
708e7ae4cf2SDavid Wu debug("bank %d, iomux %d has iom_offset 0x%x drv_offset 0x%x\n",
709e7ae4cf2SDavid Wu i, j, iom->offset, drv->offset);
710e7ae4cf2SDavid Wu
711e7ae4cf2SDavid Wu /*
712e7ae4cf2SDavid Wu * Increase offset according to iomux width.
713e7ae4cf2SDavid Wu * 4bit iomux'es are spread over two registers.
714e7ae4cf2SDavid Wu */
715e7ae4cf2SDavid Wu inc = (iom->type & (IOMUX_WIDTH_4BIT |
716e7ae4cf2SDavid Wu IOMUX_WIDTH_3BIT)) ? 8 : 4;
717e7ae4cf2SDavid Wu if (iom->type & IOMUX_SOURCE_PMU)
718e7ae4cf2SDavid Wu pmu_offs += inc;
719e7ae4cf2SDavid Wu else
720e7ae4cf2SDavid Wu grf_offs += inc;
721e7ae4cf2SDavid Wu
722e7ae4cf2SDavid Wu /*
723e7ae4cf2SDavid Wu * Increase offset according to drv width.
724e7ae4cf2SDavid Wu * 3bit drive-strenth'es are spread over two registers.
725e7ae4cf2SDavid Wu */
726e7ae4cf2SDavid Wu if ((drv->drv_type == DRV_TYPE_IO_1V8_3V0_AUTO) ||
727e7ae4cf2SDavid Wu (drv->drv_type == DRV_TYPE_IO_3V3_ONLY))
728e7ae4cf2SDavid Wu inc = 8;
729e7ae4cf2SDavid Wu else
730e7ae4cf2SDavid Wu inc = 4;
731e7ae4cf2SDavid Wu
732e7ae4cf2SDavid Wu if (iom->type & IOMUX_SOURCE_PMU)
733e7ae4cf2SDavid Wu drv_pmu_offs += inc;
734e7ae4cf2SDavid Wu else
735e7ae4cf2SDavid Wu drv_grf_offs += inc;
736e7ae4cf2SDavid Wu
737e7ae4cf2SDavid Wu bank_pins += 8;
738e7ae4cf2SDavid Wu }
739e7ae4cf2SDavid Wu
740e7ae4cf2SDavid Wu /* calculate the per-bank recalced_mask */
741e7ae4cf2SDavid Wu for (j = 0; j < ctrl->niomux_recalced; j++) {
742e7ae4cf2SDavid Wu int pin = 0;
743e7ae4cf2SDavid Wu
744e7ae4cf2SDavid Wu if (ctrl->iomux_recalced[j].num == bank->bank_num) {
745e7ae4cf2SDavid Wu pin = ctrl->iomux_recalced[j].pin;
746e7ae4cf2SDavid Wu bank->recalced_mask |= BIT(pin);
747e7ae4cf2SDavid Wu }
748e7ae4cf2SDavid Wu }
749e7ae4cf2SDavid Wu
750e7ae4cf2SDavid Wu /* calculate the per-bank route_mask */
751e7ae4cf2SDavid Wu for (j = 0; j < ctrl->niomux_routes; j++) {
752e7ae4cf2SDavid Wu int pin = 0;
753e7ae4cf2SDavid Wu
754e7ae4cf2SDavid Wu if (ctrl->iomux_routes[j].bank_num == bank->bank_num) {
755e7ae4cf2SDavid Wu pin = ctrl->iomux_routes[j].pin;
756e7ae4cf2SDavid Wu bank->route_mask |= BIT(pin);
757e7ae4cf2SDavid Wu }
758e7ae4cf2SDavid Wu }
759e7ae4cf2SDavid Wu }
760e7ae4cf2SDavid Wu
761e7ae4cf2SDavid Wu return ctrl;
762e7ae4cf2SDavid Wu }
763e7ae4cf2SDavid Wu
764e7ae4cf2SDavid Wu int rockchip_pinctrl_probe(struct udevice *dev)
765e7ae4cf2SDavid Wu {
766e7ae4cf2SDavid Wu struct rockchip_pinctrl_priv *priv = dev_get_priv(dev);
767e7ae4cf2SDavid Wu struct rockchip_pin_ctrl *ctrl;
768e7ae4cf2SDavid Wu struct udevice *syscon;
769e7ae4cf2SDavid Wu struct regmap *regmap;
770e7ae4cf2SDavid Wu int ret = 0;
771e7ae4cf2SDavid Wu
772e7ae4cf2SDavid Wu /* get rockchip grf syscon phandle */
773e7ae4cf2SDavid Wu ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "rockchip,grf",
774e7ae4cf2SDavid Wu &syscon);
775e7ae4cf2SDavid Wu if (ret) {
776e7ae4cf2SDavid Wu debug("unable to find rockchip,grf syscon device (%d)\n", ret);
777e7ae4cf2SDavid Wu return ret;
778e7ae4cf2SDavid Wu }
779e7ae4cf2SDavid Wu
780e7ae4cf2SDavid Wu /* get grf-reg base address */
781e7ae4cf2SDavid Wu regmap = syscon_get_regmap(syscon);
782e7ae4cf2SDavid Wu if (!regmap) {
783e7ae4cf2SDavid Wu debug("unable to find rockchip grf regmap\n");
784e7ae4cf2SDavid Wu return -ENODEV;
785e7ae4cf2SDavid Wu }
786e7ae4cf2SDavid Wu priv->regmap_base = regmap;
787e7ae4cf2SDavid Wu
788e7ae4cf2SDavid Wu /* option: get pmu-reg base address */
789e7ae4cf2SDavid Wu ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "rockchip,pmu",
790e7ae4cf2SDavid Wu &syscon);
791e7ae4cf2SDavid Wu if (!ret) {
792e7ae4cf2SDavid Wu /* get pmugrf-reg base address */
793e7ae4cf2SDavid Wu regmap = syscon_get_regmap(syscon);
794e7ae4cf2SDavid Wu if (!regmap) {
795e7ae4cf2SDavid Wu debug("unable to find rockchip pmu regmap\n");
796e7ae4cf2SDavid Wu return -ENODEV;
797e7ae4cf2SDavid Wu }
798e7ae4cf2SDavid Wu priv->regmap_pmu = regmap;
799e7ae4cf2SDavid Wu }
800e7ae4cf2SDavid Wu
801e7ae4cf2SDavid Wu ctrl = rockchip_pinctrl_get_soc_data(dev);
802e7ae4cf2SDavid Wu if (!ctrl) {
803e7ae4cf2SDavid Wu debug("driver data not available\n");
804e7ae4cf2SDavid Wu return -EINVAL;
805e7ae4cf2SDavid Wu }
806e7ae4cf2SDavid Wu
807e7ae4cf2SDavid Wu priv->ctrl = ctrl;
808e7ae4cf2SDavid Wu return 0;
809e7ae4cf2SDavid Wu }
810