155ae10f8SBill Richardson /* 255ae10f8SBill Richardson * Copyright (c) 2012 The Chromium OS Authors. 31a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 455ae10f8SBill Richardson */ 555ae10f8SBill Richardson 655ae10f8SBill Richardson /* 755ae10f8SBill Richardson * This is a GPIO driver for Intel ICH6 and later. The x86 GPIOs are accessed 855ae10f8SBill Richardson * through the PCI bus. Each PCI device has 256 bytes of configuration space, 955ae10f8SBill Richardson * consisting of a standard header and a device-specific set of registers. PCI 1055ae10f8SBill Richardson * bus 0, device 31, function 0 gives us access to the chipset GPIOs (among 1155ae10f8SBill Richardson * other things). Within the PCI configuration space, the GPIOBASE register 1255ae10f8SBill Richardson * tells us where in the device's I/O region we can find more registers to 1355ae10f8SBill Richardson * actually access the GPIOs. 1455ae10f8SBill Richardson * 1555ae10f8SBill Richardson * PCI bus/device/function 0:1f:0 => PCI config registers 1655ae10f8SBill Richardson * PCI config register "GPIOBASE" 1755ae10f8SBill Richardson * PCI I/O space + [GPIOBASE] => start of GPIO registers 1855ae10f8SBill Richardson * GPIO registers => gpio pin function, direction, value 1957be9172SBill Richardson * 2057be9172SBill Richardson * 2157be9172SBill Richardson * Danger Will Robinson! Bank 0 (GPIOs 0-31) seems to be fairly stable. Most 2257be9172SBill Richardson * ICH versions have more, but the decoding the matrix that describes them is 2357be9172SBill Richardson * absurdly complex and constantly changing. We'll provide Bank 1 and Bank 2, 2457be9172SBill Richardson * but they will ONLY work for certain unspecified chipsets because the offset 2557be9172SBill Richardson * from GPIOBASE changes randomly. Even then, many GPIOs are unimplemented or 2657be9172SBill Richardson * reserved or subject to arcane restrictions. 2755ae10f8SBill Richardson */ 2855ae10f8SBill Richardson 2955ae10f8SBill Richardson #include <common.h> 307414112dSSimon Glass #include <dm.h> 317414112dSSimon Glass #include <errno.h> 327414112dSSimon Glass #include <fdtdec.h> 3355ae10f8SBill Richardson #include <pci.h> 3455ae10f8SBill Richardson #include <asm/gpio.h> 3555ae10f8SBill Richardson #include <asm/io.h> 361b4f25ffSSimon Glass #include <asm/pci.h> 3755ae10f8SBill Richardson 387414112dSSimon Glass #define GPIO_PER_BANK 32 397414112dSSimon Glass 407414112dSSimon Glass struct ich6_bank_priv { 417414112dSSimon Glass /* These are I/O addresses */ 427414112dSSimon Glass uint32_t use_sel; 437414112dSSimon Glass uint32_t io_sel; 447414112dSSimon Glass uint32_t lvl; 4557be9172SBill Richardson }; 4655ae10f8SBill Richardson 471b4f25ffSSimon Glass /* TODO: Move this to device tree, or platform data */ 481b4f25ffSSimon Glass void ich_gpio_set_gpio_map(const struct pch_gpio_map *map) 491b4f25ffSSimon Glass { 501b4f25ffSSimon Glass gd->arch.gpio_map = map; 511b4f25ffSSimon Glass } 521b4f25ffSSimon Glass 537414112dSSimon Glass static int gpio_ich6_ofdata_to_platdata(struct udevice *dev) 5457be9172SBill Richardson { 557414112dSSimon Glass struct ich6_bank_platdata *plat = dev_get_platdata(dev); 567414112dSSimon Glass pci_dev_t pci_dev; /* handle for 0:1f:0 */ 5755ae10f8SBill Richardson u8 tmpbyte; 5855ae10f8SBill Richardson u16 tmpword; 5955ae10f8SBill Richardson u32 tmplong; 607414112dSSimon Glass u32 gpiobase; 617414112dSSimon Glass int offset; 6255ae10f8SBill Richardson 6355ae10f8SBill Richardson /* Where should it be? */ 647414112dSSimon Glass pci_dev = PCI_BDF(0, 0x1f, 0); 6555ae10f8SBill Richardson 6655ae10f8SBill Richardson /* Is the device present? */ 671b4f25ffSSimon Glass tmpword = pci_read_config16(pci_dev, PCI_VENDOR_ID); 6855ae10f8SBill Richardson if (tmpword != PCI_VENDOR_ID_INTEL) { 6955ae10f8SBill Richardson debug("%s: wrong VendorID\n", __func__); 707414112dSSimon Glass return -ENODEV; 7155ae10f8SBill Richardson } 7257be9172SBill Richardson 731b4f25ffSSimon Glass tmpword = pci_read_config16(pci_dev, PCI_DEVICE_ID); 7457be9172SBill Richardson debug("Found %04x:%04x\n", PCI_VENDOR_ID_INTEL, tmpword); 7555ae10f8SBill Richardson /* 7657be9172SBill Richardson * We'd like to validate the Device ID too, but pretty much any 7755ae10f8SBill Richardson * value is either a) correct with slight differences, or b) 7857be9172SBill Richardson * correct but undocumented. We'll have to check a bunch of other 7957be9172SBill Richardson * things instead... 8055ae10f8SBill Richardson */ 8155ae10f8SBill Richardson 8255ae10f8SBill Richardson /* I/O should already be enabled (it's a RO bit). */ 831b4f25ffSSimon Glass tmpword = pci_read_config16(pci_dev, PCI_COMMAND); 8455ae10f8SBill Richardson if (!(tmpword & PCI_COMMAND_IO)) { 8555ae10f8SBill Richardson debug("%s: device IO not enabled\n", __func__); 867414112dSSimon Glass return -ENODEV; 8755ae10f8SBill Richardson } 8855ae10f8SBill Richardson 8955ae10f8SBill Richardson /* Header Type must be normal (bits 6-0 only; see spec.) */ 901b4f25ffSSimon Glass tmpbyte = pci_read_config8(pci_dev, PCI_HEADER_TYPE); 9155ae10f8SBill Richardson if ((tmpbyte & 0x7f) != PCI_HEADER_TYPE_NORMAL) { 9255ae10f8SBill Richardson debug("%s: invalid Header type\n", __func__); 937414112dSSimon Glass return -ENODEV; 9455ae10f8SBill Richardson } 9555ae10f8SBill Richardson 9655ae10f8SBill Richardson /* Base Class must be a bridge device */ 971b4f25ffSSimon Glass tmpbyte = pci_read_config8(pci_dev, PCI_CLASS_CODE); 9855ae10f8SBill Richardson if (tmpbyte != PCI_CLASS_CODE_BRIDGE) { 9955ae10f8SBill Richardson debug("%s: invalid class\n", __func__); 1007414112dSSimon Glass return -ENODEV; 10155ae10f8SBill Richardson } 10255ae10f8SBill Richardson /* Sub Class must be ISA */ 1031b4f25ffSSimon Glass tmpbyte = pci_read_config8(pci_dev, PCI_CLASS_SUB_CODE); 10455ae10f8SBill Richardson if (tmpbyte != PCI_CLASS_SUB_CODE_BRIDGE_ISA) { 10555ae10f8SBill Richardson debug("%s: invalid subclass\n", __func__); 1067414112dSSimon Glass return -ENODEV; 10755ae10f8SBill Richardson } 10855ae10f8SBill Richardson 10955ae10f8SBill Richardson /* Programming Interface must be 0x00 (no others exist) */ 1101b4f25ffSSimon Glass tmpbyte = pci_read_config8(pci_dev, PCI_CLASS_PROG); 11155ae10f8SBill Richardson if (tmpbyte != 0x00) { 11255ae10f8SBill Richardson debug("%s: invalid interface type\n", __func__); 1137414112dSSimon Glass return -ENODEV; 11455ae10f8SBill Richardson } 11555ae10f8SBill Richardson 11655ae10f8SBill Richardson /* 11755ae10f8SBill Richardson * GPIOBASE moved to its current offset with ICH6, but prior to 11855ae10f8SBill Richardson * that it was unused (or undocumented). Check that it looks 11955ae10f8SBill Richardson * okay: not all ones or zeros, and mapped to I/O space (bit 0). 12055ae10f8SBill Richardson */ 1211b4f25ffSSimon Glass tmplong = pci_read_config32(pci_dev, PCI_CFG_GPIOBASE); 12255ae10f8SBill Richardson if (tmplong == 0x00000000 || tmplong == 0xffffffff || 12355ae10f8SBill Richardson !(tmplong & 0x00000001)) { 12455ae10f8SBill Richardson debug("%s: unexpected GPIOBASE value\n", __func__); 1257414112dSSimon Glass return -ENODEV; 12655ae10f8SBill Richardson } 12755ae10f8SBill Richardson 12855ae10f8SBill Richardson /* 12955ae10f8SBill Richardson * Okay, I guess we're looking at the right device. The actual 13055ae10f8SBill Richardson * GPIO registers are in the PCI device's I/O space, starting 13155ae10f8SBill Richardson * at the offset that we just read. Bit 0 indicates that it's 13255ae10f8SBill Richardson * an I/O address, not a memory address, so mask that off. 13355ae10f8SBill Richardson */ 13455ae10f8SBill Richardson gpiobase = tmplong & 0xfffffffe; 1357414112dSSimon Glass offset = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "reg", -1); 1367414112dSSimon Glass if (offset == -1) { 1377414112dSSimon Glass debug("%s: Invalid register offset %d\n", __func__, offset); 1387414112dSSimon Glass return -EINVAL; 1397414112dSSimon Glass } 1407414112dSSimon Glass plat->base_addr = gpiobase + offset; 1417414112dSSimon Glass plat->bank_name = fdt_getprop(gd->fdt_blob, dev->of_offset, 1427414112dSSimon Glass "bank-name", NULL); 14355ae10f8SBill Richardson 14455ae10f8SBill Richardson return 0; 14555ae10f8SBill Richardson } 14655ae10f8SBill Richardson 1471b4f25ffSSimon Glass static int ich6_gpio_probe(struct udevice *dev) 14855ae10f8SBill Richardson { 1497414112dSSimon Glass struct ich6_bank_platdata *plat = dev_get_platdata(dev); 1507414112dSSimon Glass struct gpio_dev_priv *uc_priv = dev->uclass_priv; 1517414112dSSimon Glass struct ich6_bank_priv *bank = dev_get_priv(dev); 1527414112dSSimon Glass 1531b4f25ffSSimon Glass if (gd->arch.gpio_map) { 154*2795573aSBin Meng setup_pch_gpios(plat->base_addr, gd->arch.gpio_map); 1551b4f25ffSSimon Glass gd->arch.gpio_map = NULL; 1561b4f25ffSSimon Glass } 157*2795573aSBin Meng 1587414112dSSimon Glass uc_priv->gpio_count = GPIO_PER_BANK; 1597414112dSSimon Glass uc_priv->bank_name = plat->bank_name; 1607414112dSSimon Glass bank->use_sel = plat->base_addr; 1617414112dSSimon Glass bank->io_sel = plat->base_addr + 4; 1627414112dSSimon Glass bank->lvl = plat->base_addr + 8; 1637414112dSSimon Glass 1647414112dSSimon Glass return 0; 1657414112dSSimon Glass } 1667414112dSSimon Glass 1671b4f25ffSSimon Glass static int ich6_gpio_request(struct udevice *dev, unsigned offset, 1681b4f25ffSSimon Glass const char *label) 1697414112dSSimon Glass { 1707414112dSSimon Glass struct ich6_bank_priv *bank = dev_get_priv(dev); 17155ae10f8SBill Richardson u32 tmplong; 17255ae10f8SBill Richardson 17355ae10f8SBill Richardson /* 17455ae10f8SBill Richardson * Make sure that the GPIO pin we want isn't already in use for some 17555ae10f8SBill Richardson * built-in hardware function. We have to check this for every 17655ae10f8SBill Richardson * requested pin. 17755ae10f8SBill Richardson */ 1787414112dSSimon Glass tmplong = inl(bank->use_sel); 1797414112dSSimon Glass if (!(tmplong & (1UL << offset))) { 18057be9172SBill Richardson debug("%s: gpio %d is reserved for internal use\n", __func__, 1817414112dSSimon Glass offset); 1827414112dSSimon Glass return -EPERM; 18355ae10f8SBill Richardson } 18455ae10f8SBill Richardson 18555ae10f8SBill Richardson return 0; 18655ae10f8SBill Richardson } 18755ae10f8SBill Richardson 1887414112dSSimon Glass static int ich6_gpio_direction_input(struct udevice *dev, unsigned offset) 18955ae10f8SBill Richardson { 1907414112dSSimon Glass struct ich6_bank_priv *bank = dev_get_priv(dev); 19157be9172SBill Richardson u32 tmplong; 19257be9172SBill Richardson 1937414112dSSimon Glass tmplong = inl(bank->io_sel); 1947414112dSSimon Glass tmplong |= (1UL << offset); 1957414112dSSimon Glass outl(bank->io_sel, tmplong); 19655ae10f8SBill Richardson return 0; 19755ae10f8SBill Richardson } 19855ae10f8SBill Richardson 1997414112dSSimon Glass static int ich6_gpio_direction_output(struct udevice *dev, unsigned offset, 2007414112dSSimon Glass int value) 20155ae10f8SBill Richardson { 2027414112dSSimon Glass struct ich6_bank_priv *bank = dev_get_priv(dev); 20355ae10f8SBill Richardson u32 tmplong; 20455ae10f8SBill Richardson 2050a54745fSAxel Lin gpio_set_value(offset, value); 2060a54745fSAxel Lin 2077414112dSSimon Glass tmplong = inl(bank->io_sel); 2087414112dSSimon Glass tmplong &= ~(1UL << offset); 2097414112dSSimon Glass outl(bank->io_sel, tmplong); 21055ae10f8SBill Richardson return 0; 21155ae10f8SBill Richardson } 21255ae10f8SBill Richardson 2137414112dSSimon Glass static int ich6_gpio_get_value(struct udevice *dev, unsigned offset) 2147414112dSSimon Glass 21555ae10f8SBill Richardson { 2167414112dSSimon Glass struct ich6_bank_priv *bank = dev_get_priv(dev); 21755ae10f8SBill Richardson u32 tmplong; 21857be9172SBill Richardson int r; 21955ae10f8SBill Richardson 2207414112dSSimon Glass tmplong = inl(bank->lvl); 2217414112dSSimon Glass r = (tmplong & (1UL << offset)) ? 1 : 0; 22257be9172SBill Richardson return r; 22355ae10f8SBill Richardson } 22455ae10f8SBill Richardson 2257414112dSSimon Glass static int ich6_gpio_set_value(struct udevice *dev, unsigned offset, 2267414112dSSimon Glass int value) 22755ae10f8SBill Richardson { 2287414112dSSimon Glass struct ich6_bank_priv *bank = dev_get_priv(dev); 22955ae10f8SBill Richardson u32 tmplong; 23055ae10f8SBill Richardson 2317414112dSSimon Glass tmplong = inl(bank->lvl); 23255ae10f8SBill Richardson if (value) 2337414112dSSimon Glass tmplong |= (1UL << offset); 23455ae10f8SBill Richardson else 2357414112dSSimon Glass tmplong &= ~(1UL << offset); 2367414112dSSimon Glass outl(bank->lvl, tmplong); 23755ae10f8SBill Richardson return 0; 23855ae10f8SBill Richardson } 2397414112dSSimon Glass 2407414112dSSimon Glass static int ich6_gpio_get_function(struct udevice *dev, unsigned offset) 2417414112dSSimon Glass { 2427414112dSSimon Glass struct ich6_bank_priv *bank = dev_get_priv(dev); 2437414112dSSimon Glass u32 mask = 1UL << offset; 2447414112dSSimon Glass 2457414112dSSimon Glass if (!(inl(bank->use_sel) & mask)) 2467414112dSSimon Glass return GPIOF_FUNC; 2477414112dSSimon Glass if (inl(bank->io_sel) & mask) 2487414112dSSimon Glass return GPIOF_INPUT; 2497414112dSSimon Glass else 2507414112dSSimon Glass return GPIOF_OUTPUT; 2517414112dSSimon Glass } 2527414112dSSimon Glass 2537414112dSSimon Glass static const struct dm_gpio_ops gpio_ich6_ops = { 2547414112dSSimon Glass .request = ich6_gpio_request, 2557414112dSSimon Glass .direction_input = ich6_gpio_direction_input, 2567414112dSSimon Glass .direction_output = ich6_gpio_direction_output, 2577414112dSSimon Glass .get_value = ich6_gpio_get_value, 2587414112dSSimon Glass .set_value = ich6_gpio_set_value, 2597414112dSSimon Glass .get_function = ich6_gpio_get_function, 2607414112dSSimon Glass }; 2617414112dSSimon Glass 2627414112dSSimon Glass static const struct udevice_id intel_ich6_gpio_ids[] = { 2637414112dSSimon Glass { .compatible = "intel,ich6-gpio" }, 2647414112dSSimon Glass { } 2657414112dSSimon Glass }; 2667414112dSSimon Glass 2677414112dSSimon Glass U_BOOT_DRIVER(gpio_ich6) = { 2687414112dSSimon Glass .name = "gpio_ich6", 2697414112dSSimon Glass .id = UCLASS_GPIO, 2707414112dSSimon Glass .of_match = intel_ich6_gpio_ids, 2717414112dSSimon Glass .ops = &gpio_ich6_ops, 2727414112dSSimon Glass .ofdata_to_platdata = gpio_ich6_ofdata_to_platdata, 2737414112dSSimon Glass .probe = ich6_gpio_probe, 2747414112dSSimon Glass .priv_auto_alloc_size = sizeof(struct ich6_bank_priv), 2757414112dSSimon Glass .platdata_auto_alloc_size = sizeof(struct ich6_bank_platdata), 2767414112dSSimon Glass }; 277