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