1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (c) 2012 The Chromium OS Authors.
4 */
5
6 /*
7 * This is a GPIO driver for Intel ICH6 and later. The x86 GPIOs are accessed
8 * through the PCI bus. Each PCI device has 256 bytes of configuration space,
9 * consisting of a standard header and a device-specific set of registers. PCI
10 * bus 0, device 31, function 0 gives us access to the chipset GPIOs (among
11 * other things). Within the PCI configuration space, the GPIOBASE register
12 * tells us where in the device's I/O region we can find more registers to
13 * actually access the GPIOs.
14 *
15 * PCI bus/device/function 0:1f:0 => PCI config registers
16 * PCI config register "GPIOBASE"
17 * PCI I/O space + [GPIOBASE] => start of GPIO registers
18 * GPIO registers => gpio pin function, direction, value
19 *
20 *
21 * Danger Will Robinson! Bank 0 (GPIOs 0-31) seems to be fairly stable. Most
22 * ICH versions have more, but the decoding the matrix that describes them is
23 * absurdly complex and constantly changing. We'll provide Bank 1 and Bank 2,
24 * but they will ONLY work for certain unspecified chipsets because the offset
25 * from GPIOBASE changes randomly. Even then, many GPIOs are unimplemented or
26 * reserved or subject to arcane restrictions.
27 */
28
29 #include <common.h>
30 #include <dm.h>
31 #include <errno.h>
32 #include <fdtdec.h>
33 #include <log.h>
34 #include <pch.h>
35 #include <pci.h>
36 #include <asm/cpu.h>
37 #include <asm/global_data.h>
38 #include <asm/gpio.h>
39 #include <asm/io.h>
40 #include <asm/pci.h>
41
42 DECLARE_GLOBAL_DATA_PTR;
43
44 #define GPIO_PER_BANK 32
45
46 struct ich6_bank_priv {
47 /* These are I/O addresses */
48 uint16_t use_sel;
49 uint16_t io_sel;
50 uint16_t lvl;
51 u32 lvl_write_cache;
52 bool use_lvl_write_cache;
53 };
54
55 #define GPIO_USESEL_OFFSET(x) (x)
56 #define GPIO_IOSEL_OFFSET(x) (x + 4)
57 #define GPIO_LVL_OFFSET(x) (x + 8)
58
_ich6_gpio_set_value(struct ich6_bank_priv * bank,unsigned offset,int value)59 static int _ich6_gpio_set_value(struct ich6_bank_priv *bank, unsigned offset,
60 int value)
61 {
62 u32 val;
63
64 if (bank->use_lvl_write_cache)
65 val = bank->lvl_write_cache;
66 else
67 val = inl(bank->lvl);
68
69 if (value)
70 val |= (1UL << offset);
71 else
72 val &= ~(1UL << offset);
73 outl(val, bank->lvl);
74 if (bank->use_lvl_write_cache)
75 bank->lvl_write_cache = val;
76
77 return 0;
78 }
79
_ich6_gpio_set_direction(uint16_t base,unsigned offset,int dir)80 static int _ich6_gpio_set_direction(uint16_t base, unsigned offset, int dir)
81 {
82 u32 val;
83
84 if (!dir) {
85 val = inl(base);
86 val |= (1UL << offset);
87 outl(val, base);
88 } else {
89 val = inl(base);
90 val &= ~(1UL << offset);
91 outl(val, base);
92 }
93
94 return 0;
95 }
96
gpio_ich6_of_to_plat(struct udevice * dev)97 static int gpio_ich6_of_to_plat(struct udevice *dev)
98 {
99 struct ich6_bank_plat *plat = dev_get_plat(dev);
100 u32 gpiobase;
101 int offset;
102 int ret;
103
104 ret = pch_get_gpio_base(dev->parent, &gpiobase);
105 if (ret)
106 return ret;
107
108 offset = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "reg", -1);
109 if (offset == -1) {
110 debug("%s: Invalid register offset %d\n", __func__, offset);
111 return -EINVAL;
112 }
113 plat->offset = offset;
114 plat->base_addr = gpiobase + offset;
115 plat->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
116 "bank-name", NULL);
117
118 return 0;
119 }
120
ich6_gpio_probe(struct udevice * dev)121 static int ich6_gpio_probe(struct udevice *dev)
122 {
123 struct ich6_bank_plat *plat = dev_get_plat(dev);
124 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
125 struct ich6_bank_priv *bank = dev_get_priv(dev);
126 const void *prop;
127
128 uc_priv->gpio_count = GPIO_PER_BANK;
129 uc_priv->bank_name = plat->bank_name;
130 bank->use_sel = plat->base_addr;
131 bank->io_sel = plat->base_addr + 4;
132 bank->lvl = plat->base_addr + 8;
133
134 prop = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
135 "use-lvl-write-cache", NULL);
136 if (prop)
137 bank->use_lvl_write_cache = true;
138 else
139 bank->use_lvl_write_cache = false;
140 bank->lvl_write_cache = 0;
141
142 return 0;
143 }
144
ich6_gpio_request(struct udevice * dev,unsigned offset,const char * label)145 static int ich6_gpio_request(struct udevice *dev, unsigned offset,
146 const char *label)
147 {
148 struct ich6_bank_priv *bank = dev_get_priv(dev);
149 u32 tmplong;
150
151 /*
152 * Make sure that the GPIO pin we want isn't already in use for some
153 * built-in hardware function. We have to check this for every
154 * requested pin.
155 */
156 tmplong = inl(bank->use_sel);
157 if (!(tmplong & (1UL << offset))) {
158 debug("%s: gpio %d is reserved for internal use\n", __func__,
159 offset);
160 return -EPERM;
161 }
162
163 return 0;
164 }
165
ich6_gpio_direction_input(struct udevice * dev,unsigned offset)166 static int ich6_gpio_direction_input(struct udevice *dev, unsigned offset)
167 {
168 struct ich6_bank_priv *bank = dev_get_priv(dev);
169
170 return _ich6_gpio_set_direction(bank->io_sel, offset, 0);
171 }
172
ich6_gpio_direction_output(struct udevice * dev,unsigned offset,int value)173 static int ich6_gpio_direction_output(struct udevice *dev, unsigned offset,
174 int value)
175 {
176 int ret;
177 struct ich6_bank_priv *bank = dev_get_priv(dev);
178
179 ret = _ich6_gpio_set_direction(bank->io_sel, offset, 1);
180 if (ret)
181 return ret;
182
183 return _ich6_gpio_set_value(bank, offset, value);
184 }
185
ich6_gpio_get_value(struct udevice * dev,unsigned offset)186 static int ich6_gpio_get_value(struct udevice *dev, unsigned offset)
187 {
188 struct ich6_bank_priv *bank = dev_get_priv(dev);
189 u32 tmplong;
190 int r;
191
192 tmplong = inl(bank->lvl);
193 if (bank->use_lvl_write_cache)
194 tmplong |= bank->lvl_write_cache;
195 r = (tmplong & (1UL << offset)) ? 1 : 0;
196 return r;
197 }
198
ich6_gpio_set_value(struct udevice * dev,unsigned offset,int value)199 static int ich6_gpio_set_value(struct udevice *dev, unsigned offset,
200 int value)
201 {
202 struct ich6_bank_priv *bank = dev_get_priv(dev);
203 return _ich6_gpio_set_value(bank, offset, value);
204 }
205
ich6_gpio_get_function(struct udevice * dev,unsigned offset)206 static int ich6_gpio_get_function(struct udevice *dev, unsigned offset)
207 {
208 struct ich6_bank_priv *bank = dev_get_priv(dev);
209 u32 mask = 1UL << offset;
210
211 if (!(inl(bank->use_sel) & mask))
212 return GPIOF_FUNC;
213 if (inl(bank->io_sel) & mask)
214 return GPIOF_INPUT;
215 else
216 return GPIOF_OUTPUT;
217 }
218
219 static const struct dm_gpio_ops gpio_ich6_ops = {
220 .request = ich6_gpio_request,
221 .direction_input = ich6_gpio_direction_input,
222 .direction_output = ich6_gpio_direction_output,
223 .get_value = ich6_gpio_get_value,
224 .set_value = ich6_gpio_set_value,
225 .get_function = ich6_gpio_get_function,
226 };
227
228 static const struct udevice_id intel_ich6_gpio_ids[] = {
229 { .compatible = "intel,ich6-gpio" },
230 { }
231 };
232
233 U_BOOT_DRIVER(gpio_ich6) = {
234 .name = "gpio_ich6",
235 .id = UCLASS_GPIO,
236 .of_match = intel_ich6_gpio_ids,
237 .ops = &gpio_ich6_ops,
238 .of_to_plat = gpio_ich6_of_to_plat,
239 .probe = ich6_gpio_probe,
240 .priv_auto = sizeof(struct ich6_bank_priv),
241 .plat_auto = sizeof(struct ich6_bank_plat),
242 };
243