blob: 4a6ae554bf7860deb32829295b1c8c8f14da196c [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass8fa4d5a2015-08-30 16:55:27 -06002/*
3 * (C) Copyright 2015 Google, Inc
4 *
5 * (C) Copyright 2008-2014 Rockchip Electronics
6 * Peter, Software Engineering, <superpeter.cai@gmail.com>.
Simon Glass8fa4d5a2015-08-30 16:55:27 -06007 */
8
9#include <common.h>
10#include <dm.h>
Simon Glass9c73e742016-01-21 19:44:09 -070011#include <syscon.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +090012#include <linux/errno.h>
Simon Glass8fa4d5a2015-08-30 16:55:27 -060013#include <asm/gpio.h>
14#include <asm/io.h>
Kever Yang9fbe17c2019-03-28 11:01:23 +080015#include <asm/arch-rockchip/clock.h>
Jonas Karlmanc8078412023-03-19 18:39:51 +000016#include <asm/arch-rockchip/hardware.h>
Kever Yang9fbe17c2019-03-28 11:01:23 +080017#include <asm/arch-rockchip/gpio.h>
Simon Glass9c73e742016-01-21 19:44:09 -070018#include <dm/pinctrl.h>
Jonas Karlmanc8078412023-03-19 18:39:51 +000019#include <dm/read.h>
20#include <dt-bindings/pinctrl/rockchip.h>
21
22#define SWPORT_DR 0x0000
23#define SWPORT_DDR 0x0004
24#define EXT_PORT 0x0050
25#define SWPORT_DR_L 0x0000
26#define SWPORT_DR_H 0x0004
27#define SWPORT_DDR_L 0x0008
28#define SWPORT_DDR_H 0x000C
29#define EXT_PORT_V2 0x0070
30#define VER_ID_V2 0x0078
Simon Glass8fa4d5a2015-08-30 16:55:27 -060031
32enum {
33 ROCKCHIP_GPIOS_PER_BANK = 32,
34};
35
Simon Glass8fa4d5a2015-08-30 16:55:27 -060036struct rockchip_gpio_priv {
Jonas Karlmanc8078412023-03-19 18:39:51 +000037 void __iomem *regs;
Simon Glass9c73e742016-01-21 19:44:09 -070038 struct udevice *pinctrl;
39 int bank;
Simon Glass8fa4d5a2015-08-30 16:55:27 -060040 char name[2];
Jonas Karlmanc8078412023-03-19 18:39:51 +000041 u32 version;
Simon Glass8fa4d5a2015-08-30 16:55:27 -060042};
43
Jonas Karlmanc8078412023-03-19 18:39:51 +000044static int rockchip_gpio_get_value(struct udevice *dev, unsigned offset)
Simon Glass8fa4d5a2015-08-30 16:55:27 -060045{
46 struct rockchip_gpio_priv *priv = dev_get_priv(dev);
Jonas Karlmanc8078412023-03-19 18:39:51 +000047 u32 mask = BIT(offset), data;
Simon Glass8fa4d5a2015-08-30 16:55:27 -060048
Jonas Karlmanc8078412023-03-19 18:39:51 +000049 if (priv->version)
50 data = readl(priv->regs + EXT_PORT_V2);
51 else
52 data = readl(priv->regs + EXT_PORT);
Simon Glass8fa4d5a2015-08-30 16:55:27 -060053
Jonas Karlmanc8078412023-03-19 18:39:51 +000054 return (data & mask) ? 1 : 0;
Simon Glass8fa4d5a2015-08-30 16:55:27 -060055}
56
Jonas Karlmanc8078412023-03-19 18:39:51 +000057static int rockchip_gpio_set_value(struct udevice *dev, unsigned offset,
58 int value)
Simon Glass8fa4d5a2015-08-30 16:55:27 -060059{
60 struct rockchip_gpio_priv *priv = dev_get_priv(dev);
Jonas Karlmanc8078412023-03-19 18:39:51 +000061 u32 mask = BIT(offset), data = value ? mask : 0;
Simon Glass8fa4d5a2015-08-30 16:55:27 -060062
Jonas Karlmanc8078412023-03-19 18:39:51 +000063 if (priv->version && offset >= 16)
64 rk_clrsetreg(priv->regs + SWPORT_DR_H, mask >> 16, data >> 16);
65 else if (priv->version)
66 rk_clrsetreg(priv->regs + SWPORT_DR_L, mask, data);
67 else
68 clrsetbits_le32(priv->regs + SWPORT_DR, mask, data);
Simon Glass8fa4d5a2015-08-30 16:55:27 -060069
70 return 0;
71}
72
Jonas Karlmanc8078412023-03-19 18:39:51 +000073static int rockchip_gpio_direction_input(struct udevice *dev, unsigned offset)
Simon Glass8fa4d5a2015-08-30 16:55:27 -060074{
75 struct rockchip_gpio_priv *priv = dev_get_priv(dev);
Jonas Karlmanc8078412023-03-19 18:39:51 +000076 u32 mask = BIT(offset);
77
78 if (priv->version && offset >= 16)
79 rk_clrreg(priv->regs + SWPORT_DDR_H, mask >> 16);
80 else if (priv->version)
81 rk_clrreg(priv->regs + SWPORT_DDR_L, mask);
82 else
83 clrbits_le32(priv->regs + SWPORT_DDR, mask);
Simon Glass8fa4d5a2015-08-30 16:55:27 -060084
Jonas Karlmanc8078412023-03-19 18:39:51 +000085 return 0;
Simon Glass8fa4d5a2015-08-30 16:55:27 -060086}
87
Jonas Karlmanc8078412023-03-19 18:39:51 +000088static int rockchip_gpio_direction_output(struct udevice *dev, unsigned offset,
89 int value)
Simon Glass8fa4d5a2015-08-30 16:55:27 -060090{
91 struct rockchip_gpio_priv *priv = dev_get_priv(dev);
Jonas Karlmanc8078412023-03-19 18:39:51 +000092 u32 mask = BIT(offset);
93
94 rockchip_gpio_set_value(dev, offset, value);
Simon Glass8fa4d5a2015-08-30 16:55:27 -060095
Jonas Karlmanc8078412023-03-19 18:39:51 +000096 if (priv->version && offset >= 16)
97 rk_setreg(priv->regs + SWPORT_DDR_H, mask >> 16);
98 else if (priv->version)
99 rk_setreg(priv->regs + SWPORT_DDR_L, mask);
100 else
101 setbits_le32(priv->regs + SWPORT_DDR, mask);
Simon Glass8fa4d5a2015-08-30 16:55:27 -0600102
103 return 0;
104}
105
106static int rockchip_gpio_get_function(struct udevice *dev, unsigned offset)
107{
Simon Glass9c73e742016-01-21 19:44:09 -0700108 struct rockchip_gpio_priv *priv = dev_get_priv(dev);
Jonas Karlmanc8078412023-03-19 18:39:51 +0000109 u32 mask = BIT(offset), data;
Simon Glass9c73e742016-01-21 19:44:09 -0700110 int ret;
111
Jonas Karlmanc8078412023-03-19 18:39:51 +0000112 if (CONFIG_IS_ENABLED(PINCTRL)) {
113 ret = pinctrl_get_gpio_mux(priv->pinctrl, priv->bank, offset);
114 if (ret < 0)
115 return ret;
116 else if (ret != RK_FUNC_GPIO)
117 return GPIOF_FUNC;
118 }
119
120 if (priv->version && offset >= 16)
121 data = readl(priv->regs + SWPORT_DDR_H) << 16;
122 else if (priv->version)
123 data = readl(priv->regs + SWPORT_DDR_L);
124 else
125 data = readl(priv->regs + SWPORT_DDR);
Simon Glass9c73e742016-01-21 19:44:09 -0700126
Jonas Karlmanc8078412023-03-19 18:39:51 +0000127 return (data & mask) ? GPIOF_OUTPUT : GPIOF_INPUT;
Simon Glass8fa4d5a2015-08-30 16:55:27 -0600128}
129
Simon Glassf642c532019-01-21 14:53:34 -0700130/* Simple SPL interface to GPIOs */
131#ifdef CONFIG_SPL_BUILD
132
133enum {
134 PULL_NONE_1V8 = 0,
135 PULL_DOWN_1V8 = 1,
136 PULL_UP_1V8 = 3,
137};
138
139int spl_gpio_set_pull(void *vregs, uint gpio, int pull)
140{
141 u32 *regs = vregs;
142 uint val;
143
144 regs += gpio >> GPIO_BANK_SHIFT;
145 gpio &= GPIO_OFFSET_MASK;
146 switch (pull) {
147 case GPIO_PULL_UP:
148 val = PULL_UP_1V8;
149 break;
150 case GPIO_PULL_DOWN:
151 val = PULL_DOWN_1V8;
152 break;
153 case GPIO_PULL_NORMAL:
154 default:
155 val = PULL_NONE_1V8;
156 break;
157 }
158 clrsetbits_le32(regs, 3 << (gpio * 2), val << (gpio * 2));
159
160 return 0;
161}
162
163int spl_gpio_output(void *vregs, uint gpio, int value)
164{
165 struct rockchip_gpio_regs * const regs = vregs;
166
167 clrsetbits_le32(&regs->swport_dr, 1 << gpio, value << gpio);
168
169 /* Set direction */
170 clrsetbits_le32(&regs->swport_ddr, 1 << gpio, 1 << gpio);
171
172 return 0;
173}
174#endif /* CONFIG_SPL_BUILD */
175
Simon Glass8fa4d5a2015-08-30 16:55:27 -0600176static int rockchip_gpio_probe(struct udevice *dev)
177{
178 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
179 struct rockchip_gpio_priv *priv = dev_get_priv(dev);
Chris Morgan01c69eb2023-02-13 16:27:34 -0600180 struct ofnode_phandle_args args;
Simon Glass8fa4d5a2015-08-30 16:55:27 -0600181 char *end;
Simon Glass9c73e742016-01-21 19:44:09 -0700182 int ret;
Simon Glass8fa4d5a2015-08-30 16:55:27 -0600183
Philipp Tomsich66482052017-09-11 22:04:24 +0200184 priv->regs = dev_read_addr_ptr(dev);
Jonas Karlmanc8078412023-03-19 18:39:51 +0000185
186 if (CONFIG_IS_ENABLED(PINCTRL)) {
187 ret = uclass_first_device_err(UCLASS_PINCTRL, &priv->pinctrl);
188 if (ret)
189 return ret;
190 }
Simon Glass9c73e742016-01-21 19:44:09 -0700191
Chris Morgan01c69eb2023-02-13 16:27:34 -0600192 /*
193 * If "gpio-ranges" is present in the devicetree use it to parse
194 * the GPIO bank ID, otherwise use the legacy method.
195 */
196 ret = ofnode_parse_phandle_with_args(dev_ofnode(dev),
197 "gpio-ranges", NULL, 3,
198 0, &args);
199 if (!ret || ret != -ENOENT) {
200 uc_priv->gpio_count = args.args[2];
Johan Jonker7fd2fdb2023-03-19 16:02:18 +0100201 priv->bank = args.args[1] / ROCKCHIP_GPIOS_PER_BANK;
Chris Morgan01c69eb2023-02-13 16:27:34 -0600202 } else {
203 uc_priv->gpio_count = ROCKCHIP_GPIOS_PER_BANK;
204 end = strrchr(dev->name, '@');
205 priv->bank = trailing_strtoln(dev->name, end);
206 }
207
Simon Glass9c73e742016-01-21 19:44:09 -0700208 priv->name[0] = 'A' + priv->bank;
Simon Glass8fa4d5a2015-08-30 16:55:27 -0600209 uc_priv->bank_name = priv->name;
210
Jonas Karlmanc8078412023-03-19 18:39:51 +0000211 priv->version = readl(priv->regs + VER_ID_V2);
212
Simon Glass8fa4d5a2015-08-30 16:55:27 -0600213 return 0;
214}
215
216static const struct dm_gpio_ops gpio_rockchip_ops = {
217 .direction_input = rockchip_gpio_direction_input,
218 .direction_output = rockchip_gpio_direction_output,
219 .get_value = rockchip_gpio_get_value,
220 .set_value = rockchip_gpio_set_value,
221 .get_function = rockchip_gpio_get_function,
Simon Glass8fa4d5a2015-08-30 16:55:27 -0600222};
223
224static const struct udevice_id rockchip_gpio_ids[] = {
225 { .compatible = "rockchip,gpio-bank" },
226 { }
227};
228
Walter Lozano2901ac62020-06-25 01:10:04 -0300229U_BOOT_DRIVER(rockchip_gpio_bank) = {
230 .name = "rockchip_gpio_bank",
Simon Glass8fa4d5a2015-08-30 16:55:27 -0600231 .id = UCLASS_GPIO,
232 .of_match = rockchip_gpio_ids,
233 .ops = &gpio_rockchip_ops,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700234 .priv_auto = sizeof(struct rockchip_gpio_priv),
Simon Glass8fa4d5a2015-08-30 16:55:27 -0600235 .probe = rockchip_gpio_probe,
236};