blob: fcc42087d5769b0011644a3b94e356cc1659a941 [file] [log] [blame]
Jim Liu0d500532024-07-29 16:51:03 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2024 Nuvoton Technology Corp.
4 */
5
6#include <dm.h>
Jim Liu6bd79572024-12-10 14:35:05 +08007#include <regmap.h>
8#include <syscon.h>
Jim Liu0d500532024-07-29 16:51:03 +08009#include <asm/gpio.h>
Jim Liu6bd79572024-12-10 14:35:05 +080010#include <linux/err.h>
Jim Liu0d500532024-07-29 16:51:03 +080011#include <linux/io.h>
Jim Liu6bd79572024-12-10 14:35:05 +080012#include <asm/arch/rst.h>
Jim Liu0d500532024-07-29 16:51:03 +080013
14#define MAX_NR_HW_SGPIO 64
Jim Liu6bd79572024-12-10 14:35:05 +080015#define NPCM_SIOX1 24
16#define NPCM_SIOX2 25
Jim Liu0d500532024-07-29 16:51:03 +080017
Jim Liu6bd79572024-12-10 14:35:05 +080018#define NPCM_IOXCTS 0x28
19#define NPCM_IOXCTS_IOXIF_EN BIT(7)
20#define NPCM_IOXCTS_RD_MODE GENMASK(2, 1)
Jim Liu0d500532024-07-29 16:51:03 +080021#define NPCM_IOXCTS_RD_MODE_PERIODIC BIT(2)
22
Jim Liu6bd79572024-12-10 14:35:05 +080023#define NPCM_IOXCFG1 0x2A
Jim Liu0d500532024-07-29 16:51:03 +080024#define NPCM_IOXCFG2 0x2B
25#define NPCM_IOXCFG2_PORT GENMASK(3, 0)
26
27#define GPIO_BANK(x) ((x) / 8)
28#define GPIO_BIT(x) ((x) % 8)
29
Jim Liu6bd79572024-12-10 14:35:05 +080030#define WD0RCR 0x38
31#define WD1RCR 0x3c
32#define WD2RCR 0x40
33#define SWRSTC1 0x44
34#define SWRSTC2 0x48
35#define SWRSTC3 0x4c
36#define TIPRSTC 0x50
37#define CORSTC 0x5c
38
Jim Liu0d500532024-07-29 16:51:03 +080039struct npcm_sgpio_priv {
40 void __iomem *base;
Jim Liu6bd79572024-12-10 14:35:05 +080041 struct regmap *rst_regmap;
Jim Liu0d500532024-07-29 16:51:03 +080042 u32 nin_sgpio;
43 u32 nout_sgpio;
44 u32 in_port;
45 u32 out_port;
Jim Liu6bd79572024-12-10 14:35:05 +080046 u8 persist[8];
47 u8 siox_num;
Jim Liu0d500532024-07-29 16:51:03 +080048};
49
50struct npcm_sgpio_bank {
51 u8 rdata_reg;
52 u8 wdata_reg;
53 u8 event_config;
54 u8 event_status;
55};
56
57enum npcm_sgpio_reg {
58 READ_DATA,
59 WRITE_DATA,
60 EVENT_CFG,
61 EVENT_STS,
62};
63
64static const struct npcm_sgpio_bank npcm_sgpio_banks[] = {
65 {
66 .wdata_reg = 0x00,
67 .rdata_reg = 0x08,
68 .event_config = 0x10,
69 .event_status = 0x20,
70 },
71 {
72 .wdata_reg = 0x01,
73 .rdata_reg = 0x09,
74 .event_config = 0x12,
75 .event_status = 0x21,
76 },
77 {
78 .wdata_reg = 0x02,
79 .rdata_reg = 0x0a,
80 .event_config = 0x14,
81 .event_status = 0x22,
82 },
83 {
84 .wdata_reg = 0x03,
85 .rdata_reg = 0x0b,
86 .event_config = 0x16,
87 .event_status = 0x23,
88 },
89 {
90 .wdata_reg = 0x04,
91 .rdata_reg = 0x0c,
92 .event_config = 0x18,
93 .event_status = 0x24,
94 },
95 {
96 .wdata_reg = 0x05,
97 .rdata_reg = 0x0d,
98 .event_config = 0x1a,
99 .event_status = 0x25,
100 },
101 {
102 .wdata_reg = 0x06,
103 .rdata_reg = 0x0e,
104 .event_config = 0x1c,
105 .event_status = 0x26,
106 },
107 {
108 .wdata_reg = 0x07,
109 .rdata_reg = 0x0f,
110 .event_config = 0x1e,
111 .event_status = 0x27,
112 },
113};
114
115static void __iomem *bank_reg(struct npcm_sgpio_priv *gpio,
116 const struct npcm_sgpio_bank *bank,
117 const enum npcm_sgpio_reg reg)
118{
119 switch (reg) {
120 case READ_DATA:
121 return gpio->base + bank->rdata_reg;
122 case WRITE_DATA:
123 return gpio->base + bank->wdata_reg;
124 case EVENT_CFG:
125 return gpio->base + bank->event_config;
126 case EVENT_STS:
127 return gpio->base + bank->event_status;
128 default:
129 /* actually if code runs to here, it's an error case */
130 printf("Getting here is an error condition\n");
131 return NULL;
132 }
133}
134
135static const struct npcm_sgpio_bank *offset_to_bank(unsigned int offset)
136{
137 unsigned int bank = GPIO_BANK(offset);
138
139 return &npcm_sgpio_banks[bank];
140}
141
142static int npcm_sgpio_direction_input(struct udevice *dev, unsigned int offset)
143{
144 struct npcm_sgpio_priv *priv = dev_get_priv(dev);
145
146 if (offset < priv->nout_sgpio) {
147 printf("Error: Offset %d is a output pin\n", offset);
148 return -EINVAL;
149 }
150
151 return 0;
152}
153
154static int npcm_sgpio_direction_output(struct udevice *dev, unsigned int offset,
155 int value)
156{
157 struct npcm_sgpio_priv *priv = dev_get_priv(dev);
158 const struct npcm_sgpio_bank *bank = offset_to_bank(offset);
159 void __iomem *addr;
160 u8 reg = 0;
161
162 if (offset >= priv->nout_sgpio) {
163 printf("Error: Offset %d is a input pin\n", offset);
164 return -EINVAL;
165 }
166
167 addr = bank_reg(priv, bank, WRITE_DATA);
168 reg = ioread8(addr);
169
170 if (value)
171 reg |= BIT(GPIO_BIT(offset));
172 else
173 reg &= ~BIT(GPIO_BIT(offset));
174
175 iowrite8(reg, addr);
176
177 return 0;
178}
179
180static int npcm_sgpio_get_value(struct udevice *dev, unsigned int offset)
181{
182 struct npcm_sgpio_priv *priv = dev_get_priv(dev);
183 const struct npcm_sgpio_bank *bank;
184 void __iomem *addr;
185 u8 reg;
186
187 if (offset < priv->nout_sgpio) {
188 bank = offset_to_bank(offset);
189 addr = bank_reg(priv, bank, WRITE_DATA);
190 } else {
191 offset -= priv->nout_sgpio;
192 bank = offset_to_bank(offset);
193 addr = bank_reg(priv, bank, READ_DATA);
194 }
195
196 reg = ioread8(addr);
197
198 return !!(reg & BIT(GPIO_BIT(offset)));
199}
200
201static int npcm_sgpio_set_value(struct udevice *dev, unsigned int offset,
202 int value)
203{
Jim Liu6bd79572024-12-10 14:35:05 +0800204 struct npcm_sgpio_priv *priv = dev_get_priv(dev);
205 u8 check = priv->persist[GPIO_BANK(offset)];
206
207 if (!!(check & BIT(GPIO_BIT(offset))) == 0)
208 return npcm_sgpio_direction_output(dev, offset, value);
209 else
210 return -EINVAL;
Jim Liu0d500532024-07-29 16:51:03 +0800211}
212
213static int npcm_sgpio_get_function(struct udevice *dev, unsigned int offset)
214{
215 struct npcm_sgpio_priv *priv = dev_get_priv(dev);
216
217 if (offset < priv->nout_sgpio)
218 return GPIOF_OUTPUT;
219
220 return GPIOF_INPUT;
221}
222
223static void npcm_sgpio_setup_enable(struct npcm_sgpio_priv *gpio, bool enable)
224{
225 u8 reg;
226
227 reg = ioread8(gpio->base + NPCM_IOXCTS);
228 reg = (reg & ~NPCM_IOXCTS_RD_MODE) | NPCM_IOXCTS_RD_MODE_PERIODIC;
229
230 if (enable)
231 reg |= NPCM_IOXCTS_IOXIF_EN;
232 else
233 reg &= ~NPCM_IOXCTS_IOXIF_EN;
234
235 iowrite8(reg, gpio->base + NPCM_IOXCTS);
236}
237
Jim Liu6bd79572024-12-10 14:35:05 +0800238static void npcm_sgpio_set_port(struct udevice *dev)
Jim Liu0d500532024-07-29 16:51:03 +0800239{
240 struct npcm_sgpio_priv *priv = dev_get_priv(dev);
Jim Liu6bd79572024-12-10 14:35:05 +0800241 u8 in_port, out_port;
Jim Liu0d500532024-07-29 16:51:03 +0800242
243 in_port = GPIO_BANK(priv->nin_sgpio);
244 if (GPIO_BIT(priv->nin_sgpio) > 0)
245 in_port += 1;
246
247 out_port = GPIO_BANK(priv->nout_sgpio);
248 if (GPIO_BIT(priv->nout_sgpio) > 0)
249 out_port += 1;
250
251 priv->in_port = in_port;
252 priv->out_port = out_port;
Jim Liu6bd79572024-12-10 14:35:05 +0800253}
Jim Liu0d500532024-07-29 16:51:03 +0800254
Jim Liu6bd79572024-12-10 14:35:05 +0800255static int npcm_sgpio_init_port(struct udevice *dev)
256{
257 struct npcm_sgpio_priv *priv = dev_get_priv(dev);
258 u8 set_port, reg, set_clk;
259
260 npcm_sgpio_setup_enable(priv, false);
261
262 set_port = (priv->out_port & NPCM_IOXCFG2_PORT) << 4 | (priv->in_port & NPCM_IOXCFG2_PORT);
Jim Liu0d500532024-07-29 16:51:03 +0800263 set_clk = 0x07;
264
265 iowrite8(set_port, priv->base + NPCM_IOXCFG2);
266 iowrite8(set_clk, priv->base + NPCM_IOXCFG1);
267
268 reg = ioread8(priv->base + NPCM_IOXCFG2);
269
270 return reg == set_port ? 0 : -EINVAL;
271}
272
Jim Liu6bd79572024-12-10 14:35:05 +0800273static void npcm_sgpio_reset_persist(struct udevice *dev, uint enable)
274{
275 struct npcm_sgpio_priv *priv = dev_get_priv(dev);
276 u8 num;
277
278 if (priv->siox_num == 1)
279 num = NPCM_SIOX2;
280 else
281 num = NPCM_SIOX1;
282
283 if (enable) {
284 regmap_update_bits(priv->rst_regmap, WD0RCR, BIT(num), 0);
285 regmap_update_bits(priv->rst_regmap, WD1RCR, BIT(num), 0);
286 regmap_update_bits(priv->rst_regmap, WD2RCR, BIT(num), 0);
287 regmap_update_bits(priv->rst_regmap, CORSTC, BIT(num), 0);
288 regmap_update_bits(priv->rst_regmap, SWRSTC1, BIT(num), 0);
289 regmap_update_bits(priv->rst_regmap, SWRSTC2, BIT(num), 0);
290 regmap_update_bits(priv->rst_regmap, SWRSTC3, BIT(num), 0);
291 regmap_update_bits(priv->rst_regmap, TIPRSTC, BIT(num), 0);
292 }
293}
294
295static bool is_gpio_persist(struct udevice *dev)
296{
297 struct npcm_sgpio_priv *priv = dev_get_priv(dev);
298 u32 val;
299 int status;
300
301 status = npcm_get_reset_status();
302
303 if (status & PORST)
304 return false;
305 if (status & CORST)
306 regmap_read(priv->rst_regmap, CORSTC, &val);
307 else if (status & WD0RST)
308 regmap_read(priv->rst_regmap, WD0RCR, &val);
309 else if (status & WD1RST)
310 regmap_read(priv->rst_regmap, WD1RCR, &val);
311 else if (status & WD2RST)
312 regmap_read(priv->rst_regmap, WD2RCR, &val);
313 else if (status & SW1RST)
314 regmap_read(priv->rst_regmap, SWRSTC1, &val);
315 else if (status & SW2RST)
316 regmap_read(priv->rst_regmap, SWRSTC2, &val);
317 else if (status & SW3RST)
318 regmap_read(priv->rst_regmap, SWRSTC3, &val);
319 else if (status & TIPRST)
320 regmap_read(priv->rst_regmap, TIPRSTC, &val);
321
322 if (priv->siox_num == 1)
323 return (val && BIT(NPCM_SIOX2));
324 else
325 return (val && BIT(NPCM_SIOX1));
326}
327
Jim Liu0d500532024-07-29 16:51:03 +0800328static const struct dm_gpio_ops npcm_sgpio_ops = {
329 .direction_input = npcm_sgpio_direction_input,
330 .direction_output = npcm_sgpio_direction_output,
331 .get_value = npcm_sgpio_get_value,
332 .set_value = npcm_sgpio_set_value,
333 .get_function = npcm_sgpio_get_function,
334};
335
336static int npcm_sgpio_probe(struct udevice *dev)
337{
338 struct npcm_sgpio_priv *priv = dev_get_priv(dev);
339 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Jim Liu6bd79572024-12-10 14:35:05 +0800340 int rc, i;
341 ofnode node;
342 u32 val[2];
Jim Liu0d500532024-07-29 16:51:03 +0800343
344 priv->base = dev_read_addr_ptr(dev);
Jim Liu6bd79572024-12-10 14:35:05 +0800345 priv->rst_regmap = syscon_regmap_lookup_by_phandle(dev, "syscon-rst");
346 if (IS_ERR(priv->rst_regmap))
347 return -EINVAL;
348
Jim Liu0d500532024-07-29 16:51:03 +0800349 ofnode_read_u32(dev_ofnode(dev), "nuvoton,input-ngpios", &priv->nin_sgpio);
350 ofnode_read_u32(dev_ofnode(dev), "nuvoton,output-ngpios", &priv->nout_sgpio);
351
352 if (priv->nin_sgpio > MAX_NR_HW_SGPIO || priv->nout_sgpio > MAX_NR_HW_SGPIO)
353 return -EINVAL;
354
Jim Liu6bd79572024-12-10 14:35:05 +0800355 if (!strcmp(ofnode_get_name(dev_ofnode(dev)), "sgpio2@102000"))
356 priv->siox_num = 1;
357 else if (!strcmp(ofnode_get_name(dev_ofnode(dev)), "sgpio1@101000"))
358 priv->siox_num = 0;
359 else
360 return -EINVAL;
Jim Liu0d500532024-07-29 16:51:03 +0800361
Jim Liu6bd79572024-12-10 14:35:05 +0800362 npcm_sgpio_set_port(dev);
Jim Liu0d500532024-07-29 16:51:03 +0800363 uc_priv->gpio_count = priv->nin_sgpio + priv->nout_sgpio;
364 uc_priv->bank_name = dev->name;
365
Jim Liu6bd79572024-12-10 14:35:05 +0800366 if (is_gpio_persist(dev)) {
367 ofnode_for_each_subnode(node, dev_ofnode(dev)) {
368 if (ofnode_read_bool(node, "persist-enable")) {
369 rc = ofnode_read_u32_array(node, "gpios", val, 2);
370 if (rc == 0)
371 priv->persist[GPIO_BANK(val[0])] = priv->persist[GPIO_BANK(val[0])] | BIT(GPIO_BIT(val[0]));
372 }
373 }
374 for (i = 0; i < priv->nout_sgpio; i++)
375 npcm_sgpio_set_value(dev, i, 0);
376 } else {
377 rc = npcm_sgpio_init_port(dev);
378 if (rc < 0)
379 return rc;
380
381 ofnode_for_each_subnode(node, dev_ofnode(dev)) {
382 if (ofnode_read_bool(node, "persist-enable"))
383 npcm_sgpio_reset_persist(dev, 1);
384 }
385
386 for (i = 0; i < priv->nout_sgpio; i++)
387 npcm_sgpio_set_value(dev, i, 0);
388
389 npcm_sgpio_setup_enable(priv, true);
390 }
Jim Liu0d500532024-07-29 16:51:03 +0800391
392 return 0;
393}
394
395static const struct udevice_id npcm_sgpio_match[] = {
396 { .compatible = "nuvoton,npcm845-sgpio" },
397 { .compatible = "nuvoton,npcm750-sgpio" },
398 { }
399};
400
401U_BOOT_DRIVER(npcm_sgpio) = {
402 .name = "npcm_sgpio",
403 .id = UCLASS_GPIO,
404 .of_match = npcm_sgpio_match,
405 .probe = npcm_sgpio_probe,
406 .priv_auto = sizeof(struct npcm_sgpio_priv),
407 .ops = &npcm_sgpio_ops,
408};