xref: /rk3399_rockchip-uboot/drivers/gpio/intel_ich6_gpio.c (revision 15cf75ec15db3dd7f72fff340a5986dca5f9ad45)
1 /*
2  * Copyright (c) 2012 The Chromium OS Authors.
3  * SPDX-License-Identifier:	GPL-2.0+
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 <pch.h>
34 #include <pci.h>
35 #include <syscon.h>
36 #include <asm/cpu.h>
37 #include <asm/gpio.h>
38 #include <asm/io.h>
39 #include <asm/pci.h>
40 
41 DECLARE_GLOBAL_DATA_PTR;
42 
43 #define GPIO_PER_BANK	32
44 
45 struct ich6_bank_priv {
46 	/* These are I/O addresses */
47 	uint16_t use_sel;
48 	uint16_t io_sel;
49 	uint16_t lvl;
50 };
51 
52 #define GPIO_USESEL_OFFSET(x)	(x)
53 #define GPIO_IOSEL_OFFSET(x)	(x + 4)
54 #define GPIO_LVL_OFFSET(x)	(x + 8)
55 
56 /* TODO: Move this to device tree, or platform data */
57 void ich_gpio_set_gpio_map(const struct pch_gpio_map *map)
58 {
59 	gd->arch.gpio_map = map;
60 }
61 
62 static int _ich6_gpio_set_value(uint16_t base, unsigned offset, int value)
63 {
64 	u32 val;
65 
66 	val = inl(base);
67 	if (value)
68 		val |= (1UL << offset);
69 	else
70 		val &= ~(1UL << offset);
71 	outl(val, base);
72 
73 	return 0;
74 }
75 
76 static int _ich6_gpio_set_direction(uint16_t base, unsigned offset, int dir)
77 {
78 	u32 val;
79 
80 	if (!dir) {
81 		val = inl(base);
82 		val |= (1UL << offset);
83 		outl(val, base);
84 	} else {
85 		val = inl(base);
86 		val &= ~(1UL << offset);
87 		outl(val, base);
88 	}
89 
90 	return 0;
91 }
92 
93 int gpio_ich6_pinctrl_init(void)
94 {
95 	return 0;
96 }
97 
98 static int gpio_ich6_ofdata_to_platdata(struct udevice *dev)
99 {
100 	struct ich6_bank_platdata *plat = dev_get_platdata(dev);
101 	u32 gpiobase;
102 	int offset;
103 	int ret;
104 
105 	ret = pch_get_gpio_base(dev->parent, &gpiobase);
106 	if (ret)
107 		return ret;
108 
109 	offset = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "reg", -1);
110 	if (offset == -1) {
111 		debug("%s: Invalid register offset %d\n", __func__, offset);
112 		return -EINVAL;
113 	}
114 	plat->offset = offset;
115 	plat->base_addr = gpiobase + offset;
116 	plat->bank_name = fdt_getprop(gd->fdt_blob, dev->of_offset,
117 				      "bank-name", NULL);
118 
119 	return 0;
120 }
121 
122 static int ich6_gpio_probe(struct udevice *dev)
123 {
124 	struct ich6_bank_platdata *plat = dev_get_platdata(dev);
125 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
126 	struct ich6_bank_priv *bank = dev_get_priv(dev);
127 	struct udevice *pinctrl;
128 
129 	/* Set up pin control if available */
130 	syscon_get_by_driver_data(X86_SYSCON_PINCONF, &pinctrl);
131 
132 	uc_priv->gpio_count = GPIO_PER_BANK;
133 	uc_priv->bank_name = plat->bank_name;
134 	bank->use_sel = plat->base_addr;
135 	bank->io_sel = plat->base_addr + 4;
136 	bank->lvl = plat->base_addr + 8;
137 
138 	return 0;
139 }
140 
141 static int ich6_gpio_request(struct udevice *dev, unsigned offset,
142 			     const char *label)
143 {
144 	struct ich6_bank_priv *bank = dev_get_priv(dev);
145 	u32 tmplong;
146 
147 	/*
148 	 * Make sure that the GPIO pin we want isn't already in use for some
149 	 * built-in hardware function. We have to check this for every
150 	 * requested pin.
151 	 */
152 	tmplong = inl(bank->use_sel);
153 	if (!(tmplong & (1UL << offset))) {
154 		debug("%s: gpio %d is reserved for internal use\n", __func__,
155 		      offset);
156 		return -EPERM;
157 	}
158 
159 	return 0;
160 }
161 
162 static int ich6_gpio_direction_input(struct udevice *dev, unsigned offset)
163 {
164 	struct ich6_bank_priv *bank = dev_get_priv(dev);
165 
166 	return _ich6_gpio_set_direction(bank->io_sel, offset, 0);
167 }
168 
169 static int ich6_gpio_direction_output(struct udevice *dev, unsigned offset,
170 				       int value)
171 {
172 	int ret;
173 	struct ich6_bank_priv *bank = dev_get_priv(dev);
174 
175 	ret = _ich6_gpio_set_direction(bank->io_sel, offset, 1);
176 	if (ret)
177 		return ret;
178 
179 	return _ich6_gpio_set_value(bank->lvl, offset, value);
180 }
181 
182 static int ich6_gpio_get_value(struct udevice *dev, unsigned offset)
183 {
184 	struct ich6_bank_priv *bank = dev_get_priv(dev);
185 	u32 tmplong;
186 	int r;
187 
188 	tmplong = inl(bank->lvl);
189 	r = (tmplong & (1UL << offset)) ? 1 : 0;
190 	return r;
191 }
192 
193 static int ich6_gpio_set_value(struct udevice *dev, unsigned offset,
194 			       int value)
195 {
196 	struct ich6_bank_priv *bank = dev_get_priv(dev);
197 	return _ich6_gpio_set_value(bank->lvl, offset, value);
198 }
199 
200 static int ich6_gpio_get_function(struct udevice *dev, unsigned offset)
201 {
202 	struct ich6_bank_priv *bank = dev_get_priv(dev);
203 	u32 mask = 1UL << offset;
204 
205 	if (!(inl(bank->use_sel) & mask))
206 		return GPIOF_FUNC;
207 	if (inl(bank->io_sel) & mask)
208 		return GPIOF_INPUT;
209 	else
210 		return GPIOF_OUTPUT;
211 }
212 
213 static const struct dm_gpio_ops gpio_ich6_ops = {
214 	.request		= ich6_gpio_request,
215 	.direction_input	= ich6_gpio_direction_input,
216 	.direction_output	= ich6_gpio_direction_output,
217 	.get_value		= ich6_gpio_get_value,
218 	.set_value		= ich6_gpio_set_value,
219 	.get_function		= ich6_gpio_get_function,
220 };
221 
222 static const struct udevice_id intel_ich6_gpio_ids[] = {
223 	{ .compatible = "intel,ich6-gpio" },
224 	{ }
225 };
226 
227 U_BOOT_DRIVER(gpio_ich6) = {
228 	.name	= "gpio_ich6",
229 	.id	= UCLASS_GPIO,
230 	.of_match = intel_ich6_gpio_ids,
231 	.ops	= &gpio_ich6_ops,
232 	.ofdata_to_platdata	= gpio_ich6_ofdata_to_platdata,
233 	.probe	= ich6_gpio_probe,
234 	.priv_auto_alloc_size = sizeof(struct ich6_bank_priv),
235 	.platdata_auto_alloc_size = sizeof(struct ich6_bank_platdata),
236 };
237