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