blob: 95b1a752de2e337006dcc7cce3bf9ccd9f79291e [file] [log] [blame]
Kuan Lim Leeec2b8f22023-03-29 11:42:15 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Pinctrl / GPIO driver for StarFive JH7100 SoC
4 *
5 * Copyright (C) 2022 Shanghai StarFive Technology Co., Ltd.
6 * Author: Lee Kuan Lim <kuanlim.lee@starfivetech.com>
7 * Author: Jianlong Huang <jianlong.huang@starfivetech.com>
8 */
9
Kuan Lim Leeec2b8f22023-03-29 11:42:15 +080010#include <clk.h>
11#include <dm.h>
12#include <dm/device-internal.h>
13#include <dm/lists.h>
14#include <dm/pinctrl.h>
15#include <asm-generic/gpio.h>
16#include <linux/bitops.h>
17#include <linux/io.h>
18#include <linux/ioport.h>
19#include <dm/device_compat.h>
20#include <dt-bindings/pinctrl/pinctrl-starfive-jh7110.h>
21
22#include "pinctrl-starfive.h"
23
24/* pad control bits */
25#define STARFIVE_PADCFG_POS BIT(7)
26#define STARFIVE_PADCFG_SMT BIT(6)
27#define STARFIVE_PADCFG_SLEW BIT(5)
28#define STARFIVE_PADCFG_PD BIT(4)
29#define STARFIVE_PADCFG_PU BIT(3)
30#define STARFIVE_PADCFG_BIAS (STARFIVE_PADCFG_PD | STARFIVE_PADCFG_PU)
31#define STARFIVE_PADCFG_DS_MASK GENMASK(2, 1)
32#define STARFIVE_PADCFG_DS_2MA (0U << 1)
33#define STARFIVE_PADCFG_DS_4MA BIT(1)
34#define STARFIVE_PADCFG_DS_8MA (2U << 1)
35#define STARFIVE_PADCFG_DS_12MA (3U << 1)
36#define STARFIVE_PADCFG_IE BIT(0)
37#define GPIO_NUM_PER_WORD 32
38
39/*
40 * The packed pinmux values from the device tree look like this:
41 *
42 * | 31 - 24 | 23 - 16 | 15 - 10 | 9 - 8 | 7 - 0 |
43 * | din | dout | doen | function | pin |
44 */
45static unsigned int starfive_pinmux_din(u32 v)
46{
47 return (v & GENMASK(31, 24)) >> 24;
48}
49
50static u32 starfive_pinmux_dout(u32 v)
51{
52 return (v & GENMASK(23, 16)) >> 16;
53}
54
55static u32 starfive_pinmux_doen(u32 v)
56{
57 return (v & GENMASK(15, 10)) >> 10;
58}
59
60static u32 starfive_pinmux_function(u32 v)
61{
62 return (v & GENMASK(9, 8)) >> 8;
63}
64
65static unsigned int starfive_pinmux_pin(u32 v)
66{
67 return v & GENMASK(7, 0);
68}
69
70void starfive_set_gpiomux(struct udevice *dev, unsigned int pin,
71 unsigned int din, u32 dout, u32 doen)
72{
73 struct starfive_pinctrl_priv *priv = dev_get_priv(dev);
74 const struct starfive_pinctrl_soc_info *info = priv->info;
75
76 unsigned int offset = 4 * (pin / 4);
77 unsigned int shift = 8 * (pin % 4);
78 u32 dout_mask = info->dout_mask << shift;
79 u32 done_mask = info->doen_mask << shift;
80 u32 ival, imask;
81 void __iomem *reg_dout;
82 void __iomem *reg_doen;
83 void __iomem *reg_din;
84
85 reg_dout = priv->base + info->dout_reg_base + offset;
86 reg_doen = priv->base + info->doen_reg_base + offset;
87 dout <<= shift;
88 doen <<= shift;
89 if (din != GPI_NONE) {
90 unsigned int ioffset = 4 * (din / 4);
91 unsigned int ishift = 8 * (din % 4);
92
93 reg_din = priv->base + info->gpi_reg_base + ioffset;
94 ival = (pin + 2) << ishift;
95 imask = info->gpi_mask << ishift;
96 } else {
97 reg_din = NULL;
98 }
99
100 dout |= readl(reg_dout) & ~dout_mask;
101 writel(dout, reg_dout);
102 doen |= readl(reg_doen) & ~done_mask;
103 writel(doen, reg_doen);
104 if (reg_din) {
105 ival |= readl(reg_din) & ~imask;
106 writel(ival, reg_din);
107 }
108}
109
110static const struct pinconf_param starfive_pinconf_params[] = {
111 { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
112 { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
113 { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
114 { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
115 { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
116 { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
117 { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
118 { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
119 { "slew-rate", PIN_CONFIG_SLEW_RATE, 0 },
120};
121
122static const u8 starfive_drive_strength_mA[4] = { 2, 4, 8, 12 };
123
124static u32 starfive_padcfg_ds_from_mA(u32 v)
125{
126 int i;
127
128 for (i = 0; i < 3; i++) {
129 if (v <= starfive_drive_strength_mA[i])
130 break;
131 }
132 return i << 1;
133}
134
135static void starfive_padcfg_rmw(struct udevice *dev,
136 unsigned int pin, u32 mask, u32 value)
137{
138 struct starfive_pinctrl_priv *priv = dev_get_priv(dev);
139 struct starfive_pinctrl_soc_info *info = priv->info;
140 void __iomem *reg;
141 int padcfg_base;
142
143 if (!info->get_padcfg_base)
144 return;
145
146 padcfg_base = info->get_padcfg_base(dev, pin);
147 if (padcfg_base < 0)
148 return;
149
150 reg = priv->base + padcfg_base + 4 * pin;
151 value &= mask;
152
153 value |= readl(reg) & ~mask;
154 writel(value, reg);
155}
156
157static int starfive_pinconf_set(struct udevice *dev, unsigned int pin,
158 unsigned int param, unsigned int arg)
159{
160 u16 mask = 0;
161 u16 value = 0;
162
163 switch (param) {
164 case PIN_CONFIG_BIAS_DISABLE:
165 mask |= STARFIVE_PADCFG_BIAS;
166 value &= ~STARFIVE_PADCFG_BIAS;
167 break;
168 case PIN_CONFIG_BIAS_PULL_DOWN:
169 if (arg == 0)
170 return -EINVAL;
171 mask |= STARFIVE_PADCFG_BIAS;
172 value = (value & ~STARFIVE_PADCFG_BIAS) | STARFIVE_PADCFG_PD;
173 break;
174 case PIN_CONFIG_BIAS_PULL_UP:
175 if (arg == 0)
176 return -EINVAL;
177 mask |= STARFIVE_PADCFG_BIAS;
178 value = (value & ~STARFIVE_PADCFG_BIAS) | STARFIVE_PADCFG_PU;
179 break;
180 case PIN_CONFIG_DRIVE_STRENGTH:
181 mask |= STARFIVE_PADCFG_DS_MASK;
182 value = (value & ~STARFIVE_PADCFG_DS_MASK) |
183 starfive_padcfg_ds_from_mA(arg);
184 break;
185 case PIN_CONFIG_INPUT_ENABLE:
186 mask |= STARFIVE_PADCFG_IE;
187 if (arg)
188 value |= STARFIVE_PADCFG_IE;
189 else
190 value &= ~STARFIVE_PADCFG_IE;
191 break;
192 case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
193 mask |= STARFIVE_PADCFG_SMT;
194 if (arg)
195 value |= STARFIVE_PADCFG_SMT;
196 else
197 value &= ~STARFIVE_PADCFG_SMT;
198 break;
199 case PIN_CONFIG_SLEW_RATE:
200 mask |= STARFIVE_PADCFG_SLEW;
201 if (arg)
202 value |= STARFIVE_PADCFG_SLEW;
203 else
204 value &= ~STARFIVE_PADCFG_SLEW;
205 break;
206 default:
207 return -EINVAL;
208 }
209
210 starfive_padcfg_rmw(dev, pin, mask, value);
211
212 return 0;
213}
214
215static int starfive_property_set(struct udevice *dev, u32 pinmux_group)
216{
217 struct starfive_pinctrl_priv *priv = dev_get_priv(dev);
218 struct starfive_pinctrl_soc_info *info = priv->info;
219
220 if (info->set_one_pinmux)
221 info->set_one_pinmux(dev,
222 starfive_pinmux_pin(pinmux_group),
223 starfive_pinmux_din(pinmux_group),
224 starfive_pinmux_dout(pinmux_group),
225 starfive_pinmux_doen(pinmux_group),
226 starfive_pinmux_function(pinmux_group));
227
228 return starfive_pinmux_pin(pinmux_group);
229}
230
231const struct pinctrl_ops starfive_pinctrl_ops = {
232 .set_state = pinctrl_generic_set_state,
233 .pinconf_num_params = ARRAY_SIZE(starfive_pinconf_params),
234 .pinconf_params = starfive_pinconf_params,
235 .pinconf_set = starfive_pinconf_set,
236 .pinmux_property_set = starfive_property_set,
237};
238
239static int starfive_gpio_get_direction(struct udevice *dev, unsigned int off)
240{
241 struct udevice *pdev = dev->parent;
242 struct starfive_pinctrl_priv *priv = dev_get_priv(pdev);
243 struct starfive_pinctrl_soc_info *info = priv->info;
244
245 unsigned int offset = 4 * (off / 4);
246 unsigned int shift = 8 * (off % 4);
247 u32 doen = readl(priv->base + info->doen_reg_base + offset);
248
249 doen = (doen >> shift) & info->doen_mask;
250
251 return doen == GPOEN_ENABLE ? GPIOF_OUTPUT : GPIOF_INPUT;
252}
253
254static int starfive_gpio_direction_input(struct udevice *dev, unsigned int off)
255{
256 struct udevice *pdev = dev->parent;
257 struct starfive_pinctrl_priv *priv = dev_get_priv(pdev);
258 struct starfive_pinctrl_soc_info *info = priv->info;
259
260 /* enable input and schmitt trigger */
261 starfive_padcfg_rmw(pdev, off,
262 STARFIVE_PADCFG_IE | STARFIVE_PADCFG_SMT,
263 STARFIVE_PADCFG_IE | STARFIVE_PADCFG_SMT);
264
265 if (info->set_one_pinmux)
266 info->set_one_pinmux(pdev, off,
267 GPI_NONE, GPOUT_LOW, GPOEN_DISABLE, 0);
268
269 return 0;
270}
271
272static int starfive_gpio_direction_output(struct udevice *dev,
273 unsigned int off, int val)
274{
275 struct udevice *pdev = dev->parent;
276 struct starfive_pinctrl_priv *priv = dev_get_priv(pdev);
277 struct starfive_pinctrl_soc_info *info = priv->info;
278
279 if (info->set_one_pinmux)
280 info->set_one_pinmux(pdev, off,
281 GPI_NONE, val ? GPOUT_HIGH : GPOUT_LOW,
282 GPOEN_ENABLE, 0);
283
284 /* disable input, schmitt trigger and bias */
285 starfive_padcfg_rmw(pdev, off,
286 STARFIVE_PADCFG_IE | STARFIVE_PADCFG_SMT
287 | STARFIVE_PADCFG_BIAS,
288 0);
289
290 return 0;
291}
292
293static int starfive_gpio_get_value(struct udevice *dev, unsigned int off)
294{
295 struct udevice *pdev = dev->parent;
296 struct starfive_pinctrl_priv *priv = dev_get_priv(pdev);
297 struct starfive_pinctrl_soc_info *info = priv->info;
298
299 void __iomem *reg = priv->base + info->gpioin_reg_base
300 + 4 * (off / GPIO_NUM_PER_WORD);
301
302 return !!(readl(reg) & BIT(off % GPIO_NUM_PER_WORD));
303}
304
305static int starfive_gpio_set_value(struct udevice *dev,
306 unsigned int off, int val)
307{
308 struct udevice *pdev = dev->parent;
309 struct starfive_pinctrl_priv *priv = dev_get_priv(pdev);
310 struct starfive_pinctrl_soc_info *info = priv->info;
311
312 unsigned int offset = 4 * (off / 4);
313 unsigned int shift = 8 * (off % 4);
314 void __iomem *reg_dout = priv->base + info->dout_reg_base + offset;
315 u32 dout = (val ? GPOUT_HIGH : GPOUT_LOW) << shift;
316 u32 mask = info->dout_mask << shift;
317
318 dout |= readl(reg_dout) & ~mask;
319 writel(dout, reg_dout);
320
321 return 0;
322}
323
324static int starfive_gpio_probe(struct udevice *dev)
325{
326 struct gpio_dev_priv *uc_priv;
327 struct udevice *pdev = dev->parent;
328 struct starfive_pinctrl_priv *priv = dev_get_priv(pdev);
329 struct starfive_pinctrl_soc_info *info = priv->info;
330
331 uc_priv = dev_get_uclass_priv(dev);
332 uc_priv->bank_name = info->gpio_bank_name;
333 uc_priv->gpio_count = info->ngpios;
334
335 if (!info->gpio_init_hw)
336 return -ENXIO;
337
338 info->gpio_init_hw(pdev);
339
340 return 0;
341}
342
343static const struct dm_gpio_ops starfive_gpio_ops = {
344 .get_function = starfive_gpio_get_direction,
345 .direction_input = starfive_gpio_direction_input,
346 .direction_output = starfive_gpio_direction_output,
347 .get_value = starfive_gpio_get_value,
348 .set_value = starfive_gpio_set_value,
349};
350
351static struct driver starfive_gpio_driver = {
352 .name = "starfive_gpio",
353 .id = UCLASS_GPIO,
354 .probe = starfive_gpio_probe,
355 .ops = &starfive_gpio_ops,
356};
357
358static int starfive_gpiochip_register(struct udevice *parent)
359{
360 struct uclass_driver *drv;
361 struct udevice *dev;
362 int ret;
363 ofnode node;
364
365 drv = lists_uclass_lookup(UCLASS_GPIO);
366 if (!drv)
367 return -ENOENT;
368
369 node = dev_ofnode(parent);
370 ret = device_bind_with_driver_data(parent, &starfive_gpio_driver,
371 "starfive_gpio", 0, node, &dev);
372
373 return (ret == 0) ? 0 : ret;
374}
375
376int starfive_pinctrl_probe(struct udevice *dev,
377 const struct starfive_pinctrl_soc_info *info)
378{
379 struct starfive_pinctrl_priv *priv = dev_get_priv(dev);
380 int ret;
381
382 /* Bind pinctrl_info from .data to priv */
383 priv->info =
384 (struct starfive_pinctrl_soc_info *)dev_get_driver_data(dev);
385
386 if (!priv->info)
387 return -EINVAL;
388
389 priv->base = dev_read_addr_ptr(dev);
390 if (!priv->base)
391 return -EINVAL;
392
393 /* gpiochip register */
394 ret = starfive_gpiochip_register(dev);
395
396 return (ret == 0) ? 0 : ret;
397}