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