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