1 /*
2 * ast_gpio.c - GPIO driver for the Aspeed SoC
3 *
4 * Copyright (C) ASPEED Technology Inc.
5 * Ryan Chen <ryan_chen@aspeedtech.com>
6 *
7 */
8 #include <common.h>
9 #include <asm/io.h>
10 #include <asm/gpio.h>
11
12 #include <config.h>
13 #include <common.h>
14 #include <clk.h>
15 #include <dm.h>
16 #include <asm/io.h>
17 #include <linux/sizes.h>
18
19 struct aspeed_gpio_priv {
20 void *regs;
21 };
22
23 struct aspeed_gpio_bank {
24 uint16_t val_regs; /* +0: Rd: read input value, Wr: set write latch
25 * +4: Rd/Wr: Direction (0=in, 1=out)
26 */
27 uint16_t rdata_reg; /* Rd: read write latch, Wr: <none> */
28 uint16_t irq_regs;
29 uint16_t debounce_regs;
30 uint16_t tolerance_regs;
31 uint16_t cmdsrc_regs;
32 const char names[4][3];
33 };
34
35 static 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
110 enum 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 */
bank_reg(struct aspeed_gpio_priv * gpio,const struct aspeed_gpio_bank * bank,const enum aspeed_gpio_reg reg)146 static 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
to_bank(unsigned int offset)185 static 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
193 static int
aspeed_gpio_direction_input(struct udevice * dev,unsigned offset)194 aspeed_gpio_direction_input(struct udevice *dev, unsigned 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
206 static int
aspeed_gpio_direction_output(struct udevice * dev,unsigned offset,int value)207 aspeed_gpio_direction_output(struct udevice *dev, unsigned offset,
208 int value)
209 {
210 struct aspeed_gpio_priv *priv = dev_get_priv(dev);
211 const struct aspeed_gpio_bank *bank = to_bank(offset);
212 u32 dir = readl(bank_reg(priv, bank, reg_dir));
213 u32 output = readl(bank_reg(priv, bank, reg_rdata));
214
215 dir |= GPIO_BIT(offset);
216 writel(dir, bank_reg(priv, bank, reg_dir));
217
218 if(value)
219 output |= GPIO_BIT(offset);
220 else
221 output &= ~GPIO_BIT(offset);
222
223 writel(output, bank_reg(priv, bank, reg_val));
224
225 return 0;
226 }
227
aspeed_gpio_get_value(struct udevice * dev,unsigned offset)228 static int aspeed_gpio_get_value(struct udevice *dev, unsigned offset)
229 {
230 struct aspeed_gpio_priv *priv = dev_get_priv(dev);
231 const struct aspeed_gpio_bank *bank = to_bank(offset);
232
233 return !!(readl(bank_reg(priv, bank, reg_val)) & GPIO_BIT(offset));
234 }
235
aspeed_gpio_set_value(struct udevice * dev,unsigned offset,int value)236 static int aspeed_gpio_set_value(struct udevice *dev, unsigned offset,
237 int value)
238 {
239
240 struct aspeed_gpio_priv *priv = dev_get_priv(dev);
241 const struct aspeed_gpio_bank *bank = to_bank(offset);
242 u32 data = readl(bank_reg(priv, bank, reg_rdata));
243
244 if (value)
245 data |= GPIO_BIT(offset);
246 else
247 data &= ~GPIO_BIT(offset);
248
249 writel(data, bank_reg(priv, bank, reg_val));
250
251 return 0;
252 }
253
aspeed_gpio_get_function(struct udevice * dev,unsigned offset)254 static int aspeed_gpio_get_function(struct udevice *dev, unsigned offset)
255 {
256 struct aspeed_gpio_priv *priv = dev_get_priv(dev);
257 const struct aspeed_gpio_bank *bank = to_bank(offset);
258
259 if(readl(bank_reg(priv, bank, reg_dir)) & GPIO_BIT(offset))
260 return GPIOF_OUTPUT;
261 else
262 return GPIOF_INPUT;
263 }
264
265 static const struct dm_gpio_ops gpio_aspeed_ops = {
266 .direction_input = aspeed_gpio_direction_input,
267 .direction_output = aspeed_gpio_direction_output,
268 .get_value = aspeed_gpio_get_value,
269 .set_value = aspeed_gpio_set_value,
270 .get_function = aspeed_gpio_get_function,
271 };
272
aspeed_gpio_probe(struct udevice * dev)273 static int aspeed_gpio_probe(struct udevice *dev)
274 {
275 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
276 struct aspeed_gpio_priv *priv = dev_get_priv(dev);
277
278 uc_priv->bank_name = dev->name;
279 ofnode_read_u32(dev_ofnode(dev), "ngpios", &uc_priv->gpio_count);
280 priv->regs = devfdt_get_addr_ptr(dev);
281
282 return 0;
283 }
284
285 static const struct udevice_id aspeed_gpio_ids[] = {
286 { .compatible = "aspeed,ast2400-gpio", },
287 { .compatible = "aspeed,ast2500-gpio", },
288 { .compatible = "aspeed,ast2600-gpio", },
289 { }
290 };
291
292 U_BOOT_DRIVER(gpio_aspeed) = {
293 .name = "gpio_aspeed",
294 .id = UCLASS_GPIO,
295 .of_match = aspeed_gpio_ids,
296 .ops = &gpio_aspeed_ops,
297 .probe = aspeed_gpio_probe,
298 .priv_auto_alloc_size = sizeof(struct aspeed_gpio_priv),
299 };
300