diff options
Diffstat (limited to 'drivers/pinctrl/rockchip/pinctrl_rk3399.c')
-rw-r--r-- | drivers/pinctrl/rockchip/pinctrl_rk3399.c | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3399.c b/drivers/pinctrl/rockchip/pinctrl_rk3399.c index bc92dd7c06..5c5af3a0bd 100644 --- a/drivers/pinctrl/rockchip/pinctrl_rk3399.c +++ b/drivers/pinctrl/rockchip/pinctrl_rk3399.c | |||
@@ -1,6 +1,7 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0+ | 1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | 2 | /* |
3 | * (C) Copyright 2016 Rockchip Electronics Co., Ltd | 3 | * (C) Copyright 2016 Rockchip Electronics Co., Ltd |
4 | * (C) 2018 Theobroma Systems Design und Consulting GmbH | ||
4 | */ | 5 | */ |
5 | 6 | ||
6 | #include <common.h> | 7 | #include <common.h> |
@@ -14,11 +15,241 @@ | |||
14 | #include <asm/arch/clock.h> | 15 | #include <asm/arch/clock.h> |
15 | #include <dm/pinctrl.h> | 16 | #include <dm/pinctrl.h> |
16 | 17 | ||
18 | #if CONFIG_IS_ENABLED(PINCTRL_ROCKCHIP_RK3399_FULL) | ||
19 | static const u32 RK_GRF_P_PULLUP = 1; | ||
20 | static const u32 RK_GRF_P_PULLDOWN = 2; | ||
21 | #endif /* PINCTRL_ROCKCHIP_RK3399_FULL */ | ||
22 | |||
17 | struct rk3399_pinctrl_priv { | 23 | struct rk3399_pinctrl_priv { |
18 | struct rk3399_grf_regs *grf; | 24 | struct rk3399_grf_regs *grf; |
19 | struct rk3399_pmugrf_regs *pmugrf; | 25 | struct rk3399_pmugrf_regs *pmugrf; |
26 | struct rockchip_pin_bank *banks; | ||
27 | }; | ||
28 | |||
29 | #if CONFIG_IS_ENABLED(PINCTRL_ROCKCHIP_RK3399_FULL) | ||
30 | /* Location of pinctrl/pinconf registers. */ | ||
31 | enum rk_grf_location { | ||
32 | RK_GRF, | ||
33 | RK_PMUGRF, | ||
34 | }; | ||
35 | |||
36 | /** | ||
37 | * @nr_pins: number of pins in this bank | ||
38 | * @grf_location: location of pinctrl/pinconf registers | ||
39 | * @bank_num: number of the bank, to account for holes | ||
40 | * @iomux: array describing the 4 iomux sources of the bank | ||
41 | */ | ||
42 | struct rockchip_pin_bank { | ||
43 | u8 nr_pins; | ||
44 | enum rk_grf_location grf_location; | ||
45 | size_t iomux_offset; | ||
46 | size_t pupd_offset; | ||
20 | }; | 47 | }; |
21 | 48 | ||
49 | #define PIN_BANK(pins, grf, iomux, pupd) \ | ||
50 | { \ | ||
51 | .nr_pins = pins, \ | ||
52 | .grf_location = grf, \ | ||
53 | .iomux_offset = iomux, \ | ||
54 | .pupd_offset = pupd, \ | ||
55 | } | ||
56 | |||
57 | static struct rockchip_pin_bank rk3399_pin_banks[] = { | ||
58 | PIN_BANK(16, RK_PMUGRF, | ||
59 | offsetof(struct rk3399_pmugrf_regs, gpio0a_iomux), | ||
60 | offsetof(struct rk3399_pmugrf_regs, gpio0_p)), | ||
61 | PIN_BANK(32, RK_PMUGRF, | ||
62 | offsetof(struct rk3399_pmugrf_regs, gpio1a_iomux), | ||
63 | offsetof(struct rk3399_pmugrf_regs, gpio1_p)), | ||
64 | PIN_BANK(32, RK_GRF, | ||
65 | offsetof(struct rk3399_grf_regs, gpio2a_iomux), | ||
66 | offsetof(struct rk3399_grf_regs, gpio2_p)), | ||
67 | PIN_BANK(32, RK_GRF, | ||
68 | offsetof(struct rk3399_grf_regs, gpio3a_iomux), | ||
69 | offsetof(struct rk3399_grf_regs, gpio3_p)), | ||
70 | PIN_BANK(32, RK_GRF, | ||
71 | offsetof(struct rk3399_grf_regs, gpio4a_iomux), | ||
72 | offsetof(struct rk3399_grf_regs, gpio4_p)), | ||
73 | }; | ||
74 | |||
75 | static void rk_pinctrl_get_info(uintptr_t base, u32 index, uintptr_t *addr, | ||
76 | u32 *shift, u32 *mask) | ||
77 | { | ||
78 | /* | ||
79 | * In general we four subsequent 32-bit configuration registers | ||
80 | * per bank (e.g. GPIO2A_P, GPIO2B_P, GPIO2C_P, GPIO2D_P). | ||
81 | * The configuration for each pin has two bits. | ||
82 | * | ||
83 | * @base...contains the address to the first register. | ||
84 | * @index...defines the pin within the bank (0..31). | ||
85 | * @addr...will be the address of the actual register to use | ||
86 | * @shift...will be the bit position in the configuration register | ||
87 | * @mask...will be the (unshifted) mask | ||
88 | */ | ||
89 | |||
90 | const u32 pins_per_register = 8; | ||
91 | const u32 config_bits_per_pin = 2; | ||
92 | |||
93 | /* Get the address of the configuration register. */ | ||
94 | *addr = base + (index / pins_per_register) * sizeof(u32); | ||
95 | |||
96 | /* Get the bit offset within the configuration register. */ | ||
97 | *shift = (index & (pins_per_register - 1)) * config_bits_per_pin; | ||
98 | |||
99 | /* Get the (unshifted) mask for the configuration pins. */ | ||
100 | *mask = ((1 << config_bits_per_pin) - 1); | ||
101 | |||
102 | pr_debug("%s: addr=0x%lx, mask=0x%x, shift=0x%x\n", | ||
103 | __func__, *addr, *mask, *shift); | ||
104 | } | ||
105 | |||
106 | static void rk3399_pinctrl_set_pin_iomux(uintptr_t grf_addr, | ||
107 | struct rockchip_pin_bank *bank, | ||
108 | u32 index, u32 muxval) | ||
109 | { | ||
110 | uintptr_t iomux_base, addr; | ||
111 | u32 shift, mask; | ||
112 | |||
113 | iomux_base = grf_addr + bank->iomux_offset; | ||
114 | rk_pinctrl_get_info(iomux_base, index, &addr, &shift, &mask); | ||
115 | |||
116 | /* Set pinmux register */ | ||
117 | rk_clrsetreg(addr, mask << shift, muxval << shift); | ||
118 | } | ||
119 | |||
120 | static void rk3399_pinctrl_set_pin_pupd(uintptr_t grf_addr, | ||
121 | struct rockchip_pin_bank *bank, | ||
122 | u32 index, int pinconfig) | ||
123 | { | ||
124 | uintptr_t pupd_base, addr; | ||
125 | u32 shift, mask, pupdval; | ||
126 | |||
127 | /* Fast path in case there's nothing to do. */ | ||
128 | if (!pinconfig) | ||
129 | return; | ||
130 | |||
131 | if (pinconfig & (1 << PIN_CONFIG_BIAS_PULL_UP)) | ||
132 | pupdval = RK_GRF_P_PULLUP; | ||
133 | else if (pinconfig & (1 << PIN_CONFIG_BIAS_PULL_DOWN)) { | ||
134 | pupdval = RK_GRF_P_PULLDOWN; | ||
135 | } else { | ||
136 | /* Flag not supported. */ | ||
137 | pr_warn("%s: Unsupported pinconfig flag: 0x%x\n", __func__, | ||
138 | pinconfig); | ||
139 | return; | ||
140 | } | ||
141 | |||
142 | pupd_base = grf_addr + (uintptr_t)bank->pupd_offset; | ||
143 | rk_pinctrl_get_info(pupd_base, index, &addr, &shift, &mask); | ||
144 | |||
145 | /* Set pull-up/pull-down regisrer */ | ||
146 | rk_clrsetreg(addr, mask << shift, pupdval << shift); | ||
147 | } | ||
148 | |||
149 | static int rk3399_pinctrl_set_pin(struct udevice *dev, u32 banknum, u32 index, | ||
150 | u32 muxval, int pinconfig) | ||
151 | { | ||
152 | struct rk3399_pinctrl_priv *priv = dev_get_priv(dev); | ||
153 | struct rockchip_pin_bank *bank = &priv->banks[banknum]; | ||
154 | uintptr_t grf_addr; | ||
155 | |||
156 | pr_debug("%s: 0x%x 0x%x 0x%x 0x%x\n", __func__, banknum, index, muxval, | ||
157 | pinconfig); | ||
158 | |||
159 | if (bank->grf_location == RK_GRF) | ||
160 | grf_addr = (uintptr_t)priv->grf; | ||
161 | else if (bank->grf_location == RK_PMUGRF) | ||
162 | grf_addr = (uintptr_t)priv->pmugrf; | ||
163 | else | ||
164 | return -EINVAL; | ||
165 | |||
166 | rk3399_pinctrl_set_pin_iomux(grf_addr, bank, index, muxval); | ||
167 | |||
168 | rk3399_pinctrl_set_pin_pupd(grf_addr, bank, index, pinconfig); | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static int rk3399_pinctrl_set_state(struct udevice *dev, struct udevice *config) | ||
173 | { | ||
174 | /* | ||
175 | * The order of the fields in this struct must match the order of | ||
176 | * the fields in the "rockchip,pins" property. | ||
177 | */ | ||
178 | struct rk_pin { | ||
179 | u32 banknum; | ||
180 | u32 index; | ||
181 | u32 muxval; | ||
182 | u32 phandle; | ||
183 | } __packed; | ||
184 | |||
185 | u32 *fields = NULL; | ||
186 | const int fields_per_pin = 4; | ||
187 | int num_fields, num_pins; | ||
188 | int ret; | ||
189 | int size; | ||
190 | int i; | ||
191 | struct rk_pin *pin; | ||
192 | |||
193 | pr_debug("%s: %s\n", __func__, config->name); | ||
194 | |||
195 | size = dev_read_size(config, "rockchip,pins"); | ||
196 | if (size < 0) | ||
197 | return -EINVAL; | ||
198 | |||
199 | num_fields = size / sizeof(u32); | ||
200 | num_pins = num_fields / fields_per_pin; | ||
201 | |||
202 | if (num_fields * sizeof(u32) != size || | ||
203 | num_pins * fields_per_pin != num_fields) { | ||
204 | pr_warn("Invalid number of rockchip,pins fields.\n"); | ||
205 | return -EINVAL; | ||
206 | } | ||
207 | |||
208 | fields = calloc(num_fields, sizeof(u32)); | ||
209 | if (!fields) | ||
210 | return -ENOMEM; | ||
211 | |||
212 | ret = dev_read_u32_array(config, "rockchip,pins", fields, num_fields); | ||
213 | if (ret) { | ||
214 | pr_warn("%s: Failed to read rockchip,pins fields.\n", | ||
215 | config->name); | ||
216 | goto end; | ||
217 | } | ||
218 | |||
219 | pin = (struct rk_pin *)fields; | ||
220 | for (i = 0; i < num_pins; i++, pin++) { | ||
221 | struct udevice *dev_pinconfig; | ||
222 | int pinconfig; | ||
223 | |||
224 | ret = uclass_get_device_by_phandle_id(UCLASS_PINCONFIG, | ||
225 | pin->phandle, | ||
226 | &dev_pinconfig); | ||
227 | if (ret) { | ||
228 | pr_debug("Could not get pinconfig device\n"); | ||
229 | goto end; | ||
230 | } | ||
231 | |||
232 | pinconfig = pinctrl_decode_pin_config_dm(dev_pinconfig); | ||
233 | if (pinconfig < 0) { | ||
234 | pr_warn("Could not parse pinconfig\n"); | ||
235 | goto end; | ||
236 | } | ||
237 | |||
238 | ret = rk3399_pinctrl_set_pin(dev, pin->banknum, pin->index, | ||
239 | pin->muxval, pinconfig); | ||
240 | if (ret) { | ||
241 | pr_warn("Could not set pinctrl settings\n"); | ||
242 | goto end; | ||
243 | } | ||
244 | } | ||
245 | |||
246 | end: | ||
247 | free(fields); | ||
248 | return ret; | ||
249 | } | ||
250 | |||
251 | #endif /* PINCTRL_ROCKCHIP_RK3399_FULL */ | ||
252 | |||
22 | static void pinctrl_rk3399_pwm_config(struct rk3399_grf_regs *grf, | 253 | static void pinctrl_rk3399_pwm_config(struct rk3399_grf_regs *grf, |
23 | struct rk3399_pmugrf_regs *pmugrf, int pwm_id) | 254 | struct rk3399_pmugrf_regs *pmugrf, int pwm_id) |
24 | { | 255 | { |
@@ -468,6 +699,9 @@ static int rk3399_pinctrl_set_state_simple(struct udevice *dev, | |||
468 | } | 699 | } |
469 | 700 | ||
470 | static struct pinctrl_ops rk3399_pinctrl_ops = { | 701 | static struct pinctrl_ops rk3399_pinctrl_ops = { |
702 | #if CONFIG_IS_ENABLED(PINCTRL_ROCKCHIP_RK3399_FULL) | ||
703 | .set_state = rk3399_pinctrl_set_state, | ||
704 | #endif | ||
471 | .set_state_simple = rk3399_pinctrl_set_state_simple, | 705 | .set_state_simple = rk3399_pinctrl_set_state_simple, |
472 | .request = rk3399_pinctrl_request, | 706 | .request = rk3399_pinctrl_request, |
473 | .get_periph_id = rk3399_pinctrl_get_periph_id, | 707 | .get_periph_id = rk3399_pinctrl_get_periph_id, |
@@ -481,6 +715,9 @@ static int rk3399_pinctrl_probe(struct udevice *dev) | |||
481 | priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); | 715 | priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); |
482 | priv->pmugrf = syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF); | 716 | priv->pmugrf = syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF); |
483 | debug("%s: grf=%p, pmugrf=%p\n", __func__, priv->grf, priv->pmugrf); | 717 | debug("%s: grf=%p, pmugrf=%p\n", __func__, priv->grf, priv->pmugrf); |
718 | #if CONFIG_IS_ENABLED(PINCTRL_ROCKCHIP_RK3399_FULL) | ||
719 | priv->banks = rk3399_pin_banks; | ||
720 | #endif /* PINCTRL_ROCKCHIP_RK3399_FULL */ | ||
484 | 721 | ||
485 | return ret; | 722 | return ret; |
486 | } | 723 | } |