blob: c5608f4a9dfcc04183f829b0703d0f30ac839772 [file] [log] [blame]
Andrew Jeffery80fb3372022-02-16 10:26:56 +10301// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright 2015 IBM Corp.
4 * Joel Stanley <joel@jms.id.au>
5 * Ryan Chen <ryan_chen@aspeedtech.com>
6 *
7 * Implementation extracted from the Linux kernel and adapted for u-boot.
8 */
Andrew Jeffery80fb3372022-02-16 10:26:56 +10309#include <asm/io.h>
10#include <asm/gpio.h>
11
12#include <config.h>
Andrew Jeffery80fb3372022-02-16 10:26:56 +103013#include <clk.h>
14#include <dm.h>
15#include <asm/io.h>
16#include <linux/bug.h>
17#include <linux/sizes.h>
18
19struct aspeed_gpio_priv {
20 void *regs;
21};
22
23struct aspeed_gpio_bank {
24 u16 val_regs; /* +0: Rd: read input value, Wr: set write latch
25 * +4: Rd/Wr: Direction (0=in, 1=out)
26 */
27 u16 rdata_reg; /* Rd: read write latch, Wr: <none> */
28 u16 irq_regs;
29 u16 debounce_regs;
30 u16 tolerance_regs;
31 u16 cmdsrc_regs;
32 const char names[4][3];
33};
34
35static const struct aspeed_gpio_bank aspeed_gpio_banks[] = {
36 {
37 .val_regs = 0x0000,
38 .rdata_reg = 0x00c0,
39 .irq_regs = 0x0008,
40 .debounce_regs = 0x0040,
41 .tolerance_regs = 0x001c,
42 .cmdsrc_regs = 0x0060,
43 .names = { "A", "B", "C", "D" },
44 },
45 {
46 .val_regs = 0x0020,
47 .rdata_reg = 0x00c4,
48 .irq_regs = 0x0028,
49 .debounce_regs = 0x0048,
50 .tolerance_regs = 0x003c,
51 .cmdsrc_regs = 0x0068,
52 .names = { "E", "F", "G", "H" },
53 },
54 {
55 .val_regs = 0x0070,
56 .rdata_reg = 0x00c8,
57 .irq_regs = 0x0098,
58 .debounce_regs = 0x00b0,
59 .tolerance_regs = 0x00ac,
60 .cmdsrc_regs = 0x0090,
61 .names = { "I", "J", "K", "L" },
62 },
63 {
64 .val_regs = 0x0078,
65 .rdata_reg = 0x00cc,
66 .irq_regs = 0x00e8,
67 .debounce_regs = 0x0100,
68 .tolerance_regs = 0x00fc,
69 .cmdsrc_regs = 0x00e0,
70 .names = { "M", "N", "O", "P" },
71 },
72 {
73 .val_regs = 0x0080,
74 .rdata_reg = 0x00d0,
75 .irq_regs = 0x0118,
76 .debounce_regs = 0x0130,
77 .tolerance_regs = 0x012c,
78 .cmdsrc_regs = 0x0110,
79 .names = { "Q", "R", "S", "T" },
80 },
81 {
82 .val_regs = 0x0088,
83 .rdata_reg = 0x00d4,
84 .irq_regs = 0x0148,
85 .debounce_regs = 0x0160,
86 .tolerance_regs = 0x015c,
87 .cmdsrc_regs = 0x0140,
88 .names = { "U", "V", "W", "X" },
89 },
90 {
91 .val_regs = 0x01E0,
92 .rdata_reg = 0x00d8,
93 .irq_regs = 0x0178,
94 .debounce_regs = 0x0190,
95 .tolerance_regs = 0x018c,
96 .cmdsrc_regs = 0x0170,
97 .names = { "Y", "Z", "AA", "AB" },
98 },
99 {
100 .val_regs = 0x01e8,
101 .rdata_reg = 0x00dc,
102 .irq_regs = 0x01a8,
103 .debounce_regs = 0x01c0,
104 .tolerance_regs = 0x01bc,
105 .cmdsrc_regs = 0x01a0,
106 .names = { "AC", "", "", "" },
107 },
108};
109
110enum aspeed_gpio_reg {
111 reg_val,
112 reg_rdata,
113 reg_dir,
114 reg_irq_enable,
115 reg_irq_type0,
116 reg_irq_type1,
117 reg_irq_type2,
118 reg_irq_status,
119 reg_debounce_sel1,
120 reg_debounce_sel2,
121 reg_tolerance,
122 reg_cmdsrc0,
123 reg_cmdsrc1,
124};
125
126#define GPIO_VAL_VALUE 0x00
127#define GPIO_VAL_DIR 0x04
128
129#define GPIO_IRQ_ENABLE 0x00
130#define GPIO_IRQ_TYPE0 0x04
131#define GPIO_IRQ_TYPE1 0x08
132#define GPIO_IRQ_TYPE2 0x0c
133#define GPIO_IRQ_STATUS 0x10
134
135#define GPIO_DEBOUNCE_SEL1 0x00
136#define GPIO_DEBOUNCE_SEL2 0x04
137
138#define GPIO_CMDSRC_0 0x00
139#define GPIO_CMDSRC_1 0x04
140#define GPIO_CMDSRC_ARM 0
141#define GPIO_CMDSRC_LPC 1
142#define GPIO_CMDSRC_COLDFIRE 2
143#define GPIO_CMDSRC_RESERVED 3
144
145/* This will be resolved at compile time */
146static inline void __iomem *bank_reg(struct aspeed_gpio_priv *gpio,
147 const struct aspeed_gpio_bank *bank,
148 const enum aspeed_gpio_reg reg)
149{
150 switch (reg) {
151 case reg_val:
152 return gpio->regs + bank->val_regs + GPIO_VAL_VALUE;
153 case reg_rdata:
154 return gpio->regs + bank->rdata_reg;
155 case reg_dir:
156 return gpio->regs + bank->val_regs + GPIO_VAL_DIR;
157 case reg_irq_enable:
158 return gpio->regs + bank->irq_regs + GPIO_IRQ_ENABLE;
159 case reg_irq_type0:
160 return gpio->regs + bank->irq_regs + GPIO_IRQ_TYPE0;
161 case reg_irq_type1:
162 return gpio->regs + bank->irq_regs + GPIO_IRQ_TYPE1;
163 case reg_irq_type2:
164 return gpio->regs + bank->irq_regs + GPIO_IRQ_TYPE2;
165 case reg_irq_status:
166 return gpio->regs + bank->irq_regs + GPIO_IRQ_STATUS;
167 case reg_debounce_sel1:
168 return gpio->regs + bank->debounce_regs + GPIO_DEBOUNCE_SEL1;
169 case reg_debounce_sel2:
170 return gpio->regs + bank->debounce_regs + GPIO_DEBOUNCE_SEL2;
171 case reg_tolerance:
172 return gpio->regs + bank->tolerance_regs;
173 case reg_cmdsrc0:
174 return gpio->regs + bank->cmdsrc_regs + GPIO_CMDSRC_0;
175 case reg_cmdsrc1:
176 return gpio->regs + bank->cmdsrc_regs + GPIO_CMDSRC_1;
177 }
178 BUG();
179}
180
181#define GPIO_BANK(x) ((x) >> 5)
182#define GPIO_OFFSET(x) ((x) & 0x1f)
183#define GPIO_BIT(x) BIT(GPIO_OFFSET(x))
184
185static const struct aspeed_gpio_bank *to_bank(unsigned int offset)
186{
187 unsigned int bank = GPIO_BANK(offset);
188
189 WARN_ON(bank >= ARRAY_SIZE(aspeed_gpio_banks));
190 return &aspeed_gpio_banks[bank];
191}
192
193static int
194aspeed_gpio_direction_input(struct udevice *dev, unsigned int offset)
195{
196 struct aspeed_gpio_priv *priv = dev_get_priv(dev);
197 const struct aspeed_gpio_bank *bank = to_bank(offset);
198 u32 dir = readl(bank_reg(priv, bank, reg_dir));
199
200 dir &= ~GPIO_BIT(offset);
201 writel(dir, bank_reg(priv, bank, reg_dir));
202
203 return 0;
204}
205
206static int aspeed_gpio_direction_output(struct udevice *dev, unsigned int offset,
207 int value)
208{
209 struct aspeed_gpio_priv *priv = dev_get_priv(dev);
210 const struct aspeed_gpio_bank *bank = to_bank(offset);
211 u32 dir = readl(bank_reg(priv, bank, reg_dir));
Billy Tsai053bc402022-04-13 13:34:51 +0800212 u32 output = readl(bank_reg(priv, bank, reg_rdata));
Andrew Jeffery80fb3372022-02-16 10:26:56 +1030213
214 dir |= GPIO_BIT(offset);
215 writel(dir, bank_reg(priv, bank, reg_dir));
216
217 if (value)
218 output |= GPIO_BIT(offset);
219 else
220 output &= ~GPIO_BIT(offset);
221
222 writel(output, bank_reg(priv, bank, reg_val));
223
224 return 0;
225}
226
227static int aspeed_gpio_get_value(struct udevice *dev, unsigned int offset)
228{
229 struct aspeed_gpio_priv *priv = dev_get_priv(dev);
230 const struct aspeed_gpio_bank *bank = to_bank(offset);
231
232 return !!(readl(bank_reg(priv, bank, reg_val)) & GPIO_BIT(offset));
233}
234
235static int
236aspeed_gpio_set_value(struct udevice *dev, unsigned int offset, int value)
237{
238 struct aspeed_gpio_priv *priv = dev_get_priv(dev);
239 const struct aspeed_gpio_bank *bank = to_bank(offset);
Billy Tsai053bc402022-04-13 13:34:51 +0800240 u32 data = readl(bank_reg(priv, bank, reg_rdata));
Andrew Jeffery80fb3372022-02-16 10:26:56 +1030241
242 if (value)
243 data |= GPIO_BIT(offset);
244 else
245 data &= ~GPIO_BIT(offset);
246
247 writel(data, bank_reg(priv, bank, reg_val));
248
249 return 0;
250}
251
252static int aspeed_gpio_get_function(struct udevice *dev, unsigned int offset)
253{
254 struct aspeed_gpio_priv *priv = dev_get_priv(dev);
255 const struct aspeed_gpio_bank *bank = to_bank(offset);
256
257 if (readl(bank_reg(priv, bank, reg_dir)) & GPIO_BIT(offset))
258 return GPIOF_OUTPUT;
259
260 return GPIOF_INPUT;
261}
262
263static const struct dm_gpio_ops aspeed_gpio_ops = {
264 .direction_input = aspeed_gpio_direction_input,
265 .direction_output = aspeed_gpio_direction_output,
266 .get_value = aspeed_gpio_get_value,
267 .set_value = aspeed_gpio_set_value,
268 .get_function = aspeed_gpio_get_function,
269};
270
271static int aspeed_gpio_probe(struct udevice *dev)
272{
273 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
274 struct aspeed_gpio_priv *priv = dev_get_priv(dev);
275
276 uc_priv->bank_name = dev->name;
277 ofnode_read_u32(dev_ofnode(dev), "ngpios", &uc_priv->gpio_count);
278 priv->regs = devfdt_get_addr_ptr(dev);
279
280 return 0;
281}
282
283static const struct udevice_id aspeed_gpio_ids[] = {
284 { .compatible = "aspeed,ast2400-gpio", },
285 { .compatible = "aspeed,ast2500-gpio", },
286 { .compatible = "aspeed,ast2600-gpio", },
287 { }
288};
289
290U_BOOT_DRIVER(gpio_aspeed) = {
291 .name = "gpio-aspeed",
292 .id = UCLASS_GPIO,
293 .of_match = aspeed_gpio_ids,
294 .ops = &aspeed_gpio_ops,
295 .probe = aspeed_gpio_probe,
296 .priv_auto = sizeof(struct aspeed_gpio_priv),
297};