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