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 38*8b097916SSimon Glass DECLARE_GLOBAL_DATA_PTR; 39*8b097916SSimon Glass 407414112dSSimon Glass #define GPIO_PER_BANK 32 417414112dSSimon Glass 427414112dSSimon Glass struct ich6_bank_priv { 437414112dSSimon Glass /* These are I/O addresses */ 44b71eec31SBin Meng uint16_t use_sel; 45b71eec31SBin Meng uint16_t io_sel; 46b71eec31SBin Meng uint16_t lvl; 4757be9172SBill Richardson }; 4855ae10f8SBill Richardson 495318f18dSGabriel Huau #define GPIO_USESEL_OFFSET(x) (x) 505318f18dSGabriel Huau #define GPIO_IOSEL_OFFSET(x) (x + 4) 515318f18dSGabriel Huau #define GPIO_LVL_OFFSET(x) (x + 8) 525318f18dSGabriel Huau 535318f18dSGabriel Huau #define IOPAD_MODE_MASK 0x7 545318f18dSGabriel Huau #define IOPAD_PULL_ASSIGN_SHIFT 7 555318f18dSGabriel Huau #define IOPAD_PULL_ASSIGN_MASK (0x3 << IOPAD_PULL_ASSIGN_SHIFT) 565318f18dSGabriel Huau #define IOPAD_PULL_STRENGTH_SHIFT 9 575318f18dSGabriel Huau #define IOPAD_PULL_STRENGTH_MASK (0x3 << IOPAD_PULL_STRENGTH_SHIFT) 585318f18dSGabriel Huau 591b4f25ffSSimon Glass /* TODO: Move this to device tree, or platform data */ 601b4f25ffSSimon Glass void ich_gpio_set_gpio_map(const struct pch_gpio_map *map) 611b4f25ffSSimon Glass { 621b4f25ffSSimon Glass gd->arch.gpio_map = map; 631b4f25ffSSimon Glass } 641b4f25ffSSimon Glass 655318f18dSGabriel Huau static int gpio_ich6_get_base(unsigned long base) 6657be9172SBill Richardson { 677414112dSSimon Glass pci_dev_t pci_dev; /* handle for 0:1f:0 */ 6855ae10f8SBill Richardson u8 tmpbyte; 6955ae10f8SBill Richardson u16 tmpword; 7055ae10f8SBill Richardson u32 tmplong; 7155ae10f8SBill Richardson 7255ae10f8SBill Richardson /* Where should it be? */ 737414112dSSimon Glass pci_dev = PCI_BDF(0, 0x1f, 0); 7455ae10f8SBill Richardson 7555ae10f8SBill Richardson /* Is the device present? */ 7631f57c28SSimon Glass tmpword = x86_pci_read_config16(pci_dev, PCI_VENDOR_ID); 7755ae10f8SBill Richardson if (tmpword != PCI_VENDOR_ID_INTEL) { 7855ae10f8SBill Richardson debug("%s: wrong VendorID\n", __func__); 797414112dSSimon Glass return -ENODEV; 8055ae10f8SBill Richardson } 8157be9172SBill Richardson 8231f57c28SSimon Glass tmpword = x86_pci_read_config16(pci_dev, PCI_DEVICE_ID); 8357be9172SBill Richardson debug("Found %04x:%04x\n", PCI_VENDOR_ID_INTEL, tmpword); 8455ae10f8SBill Richardson /* 8557be9172SBill Richardson * We'd like to validate the Device ID too, but pretty much any 8655ae10f8SBill Richardson * value is either a) correct with slight differences, or b) 8757be9172SBill Richardson * correct but undocumented. We'll have to check a bunch of other 8857be9172SBill Richardson * things instead... 8955ae10f8SBill Richardson */ 9055ae10f8SBill Richardson 9155ae10f8SBill Richardson /* I/O should already be enabled (it's a RO bit). */ 9231f57c28SSimon Glass tmpword = x86_pci_read_config16(pci_dev, PCI_COMMAND); 9355ae10f8SBill Richardson if (!(tmpword & PCI_COMMAND_IO)) { 9455ae10f8SBill Richardson debug("%s: device IO not enabled\n", __func__); 957414112dSSimon Glass return -ENODEV; 9655ae10f8SBill Richardson } 9755ae10f8SBill Richardson 9855ae10f8SBill Richardson /* Header Type must be normal (bits 6-0 only; see spec.) */ 9931f57c28SSimon Glass tmpbyte = x86_pci_read_config8(pci_dev, PCI_HEADER_TYPE); 10055ae10f8SBill Richardson if ((tmpbyte & 0x7f) != PCI_HEADER_TYPE_NORMAL) { 10155ae10f8SBill Richardson debug("%s: invalid Header type\n", __func__); 1027414112dSSimon Glass return -ENODEV; 10355ae10f8SBill Richardson } 10455ae10f8SBill Richardson 10555ae10f8SBill Richardson /* Base Class must be a bridge device */ 10631f57c28SSimon Glass tmpbyte = x86_pci_read_config8(pci_dev, PCI_CLASS_CODE); 10755ae10f8SBill Richardson if (tmpbyte != PCI_CLASS_CODE_BRIDGE) { 10855ae10f8SBill Richardson debug("%s: invalid class\n", __func__); 1097414112dSSimon Glass return -ENODEV; 11055ae10f8SBill Richardson } 11155ae10f8SBill Richardson /* Sub Class must be ISA */ 11231f57c28SSimon Glass tmpbyte = x86_pci_read_config8(pci_dev, PCI_CLASS_SUB_CODE); 11355ae10f8SBill Richardson if (tmpbyte != PCI_CLASS_SUB_CODE_BRIDGE_ISA) { 11455ae10f8SBill Richardson debug("%s: invalid subclass\n", __func__); 1157414112dSSimon Glass return -ENODEV; 11655ae10f8SBill Richardson } 11755ae10f8SBill Richardson 11855ae10f8SBill Richardson /* Programming Interface must be 0x00 (no others exist) */ 11931f57c28SSimon Glass tmpbyte = x86_pci_read_config8(pci_dev, PCI_CLASS_PROG); 12055ae10f8SBill Richardson if (tmpbyte != 0x00) { 12155ae10f8SBill Richardson debug("%s: invalid interface type\n", __func__); 1227414112dSSimon Glass return -ENODEV; 12355ae10f8SBill Richardson } 12455ae10f8SBill Richardson 12555ae10f8SBill Richardson /* 12655ae10f8SBill Richardson * GPIOBASE moved to its current offset with ICH6, but prior to 12755ae10f8SBill Richardson * that it was unused (or undocumented). Check that it looks 128b71eec31SBin Meng * okay: not all ones or zeros. 129b71eec31SBin Meng * 130b71eec31SBin Meng * Note we don't need check bit0 here, because the Tunnel Creek 131b71eec31SBin Meng * GPIO base address register bit0 is reserved (read returns 0), 132b71eec31SBin Meng * while on the Ivybridge the bit0 is used to indicate it is an 133b71eec31SBin Meng * I/O space. 13455ae10f8SBill Richardson */ 1355318f18dSGabriel Huau tmplong = x86_pci_read_config32(pci_dev, base); 136b71eec31SBin Meng if (tmplong == 0x00000000 || tmplong == 0xffffffff) { 1375318f18dSGabriel Huau debug("%s: unexpected BASE value\n", __func__); 1387414112dSSimon Glass return -ENODEV; 13955ae10f8SBill Richardson } 14055ae10f8SBill Richardson 14155ae10f8SBill Richardson /* 14255ae10f8SBill Richardson * Okay, I guess we're looking at the right device. The actual 14355ae10f8SBill Richardson * GPIO registers are in the PCI device's I/O space, starting 14455ae10f8SBill Richardson * at the offset that we just read. Bit 0 indicates that it's 14555ae10f8SBill Richardson * an I/O address, not a memory address, so mask that off. 14655ae10f8SBill Richardson */ 1475318f18dSGabriel Huau return tmplong & 0xfffc; 1485318f18dSGabriel Huau } 1495318f18dSGabriel Huau 1505318f18dSGabriel Huau static int _ich6_gpio_set_value(uint16_t base, unsigned offset, int value) 1515318f18dSGabriel Huau { 1525318f18dSGabriel Huau u32 val; 1535318f18dSGabriel Huau 1545318f18dSGabriel Huau val = inl(base); 1555318f18dSGabriel Huau if (value) 1565318f18dSGabriel Huau val |= (1UL << offset); 1575318f18dSGabriel Huau else 1585318f18dSGabriel Huau val &= ~(1UL << offset); 1595318f18dSGabriel Huau outl(val, base); 1605318f18dSGabriel Huau 1615318f18dSGabriel Huau return 0; 1625318f18dSGabriel Huau } 1635318f18dSGabriel Huau 1645318f18dSGabriel Huau static int _ich6_gpio_set_function(uint16_t base, unsigned offset, int func) 1655318f18dSGabriel Huau { 1665318f18dSGabriel Huau u32 val; 1675318f18dSGabriel Huau 1685318f18dSGabriel Huau if (func) { 1695318f18dSGabriel Huau val = inl(base); 1705318f18dSGabriel Huau val |= (1UL << offset); 1715318f18dSGabriel Huau outl(val, base); 1725318f18dSGabriel Huau } else { 1735318f18dSGabriel Huau val = inl(base); 1745318f18dSGabriel Huau val &= ~(1UL << offset); 1755318f18dSGabriel Huau outl(val, base); 1765318f18dSGabriel Huau } 1775318f18dSGabriel Huau 1785318f18dSGabriel Huau return 0; 1795318f18dSGabriel Huau } 1805318f18dSGabriel Huau 1815318f18dSGabriel Huau static int _ich6_gpio_set_direction(uint16_t base, unsigned offset, int dir) 1825318f18dSGabriel Huau { 1835318f18dSGabriel Huau u32 val; 1845318f18dSGabriel Huau 1855318f18dSGabriel Huau if (!dir) { 1865318f18dSGabriel Huau val = inl(base); 1875318f18dSGabriel Huau val |= (1UL << offset); 1885318f18dSGabriel Huau outl(val, base); 1895318f18dSGabriel Huau } else { 1905318f18dSGabriel Huau val = inl(base); 1915318f18dSGabriel Huau val &= ~(1UL << offset); 1925318f18dSGabriel Huau outl(val, base); 1935318f18dSGabriel Huau } 1945318f18dSGabriel Huau 1955318f18dSGabriel Huau return 0; 1965318f18dSGabriel Huau } 1975318f18dSGabriel Huau 1985318f18dSGabriel Huau static int _gpio_ich6_pinctrl_cfg_pin(s32 gpiobase, s32 iobase, int pin_node) 1995318f18dSGabriel Huau { 2005318f18dSGabriel Huau u32 gpio_offset[2]; 2015318f18dSGabriel Huau int pad_offset; 2025318f18dSGabriel Huau int val; 2035318f18dSGabriel Huau int ret; 2045318f18dSGabriel Huau const void *prop; 2055318f18dSGabriel Huau 2065318f18dSGabriel Huau /* 2075318f18dSGabriel Huau * GPIO node is not mandatory, so we only do the 2085318f18dSGabriel Huau * pinmuxing if the node exist. 2095318f18dSGabriel Huau */ 2105318f18dSGabriel Huau ret = fdtdec_get_int_array(gd->fdt_blob, pin_node, "gpio-offset", 2115318f18dSGabriel Huau gpio_offset, 2); 2125318f18dSGabriel Huau if (!ret) { 2135318f18dSGabriel Huau /* Do we want to force the GPIO mode? */ 2145318f18dSGabriel Huau prop = fdt_getprop(gd->fdt_blob, pin_node, "mode-gpio", 2155318f18dSGabriel Huau NULL); 2165318f18dSGabriel Huau if (prop) 2175318f18dSGabriel Huau _ich6_gpio_set_function(GPIO_USESEL_OFFSET 2185318f18dSGabriel Huau (gpiobase) + 2195318f18dSGabriel Huau gpio_offset[0], 2205318f18dSGabriel Huau gpio_offset[1], 1); 2215318f18dSGabriel Huau 2225318f18dSGabriel Huau val = 2235318f18dSGabriel Huau fdtdec_get_int(gd->fdt_blob, pin_node, "direction", -1); 2245318f18dSGabriel Huau if (val != -1) 2255318f18dSGabriel Huau _ich6_gpio_set_direction(GPIO_IOSEL_OFFSET 2265318f18dSGabriel Huau (gpiobase) + 2275318f18dSGabriel Huau gpio_offset[0], 2285318f18dSGabriel Huau gpio_offset[1], val); 2295318f18dSGabriel Huau 2305318f18dSGabriel Huau val = 2315318f18dSGabriel Huau fdtdec_get_int(gd->fdt_blob, pin_node, "output-value", -1); 2325318f18dSGabriel Huau if (val != -1) 2335318f18dSGabriel Huau _ich6_gpio_set_value(GPIO_LVL_OFFSET(gpiobase) 2345318f18dSGabriel Huau + gpio_offset[0], 2355318f18dSGabriel Huau gpio_offset[1], val); 2365318f18dSGabriel Huau } 2375318f18dSGabriel Huau 2385318f18dSGabriel Huau /* if iobase is present, let's configure the pad */ 2395318f18dSGabriel Huau if (iobase != -1) { 2405318f18dSGabriel Huau int iobase_addr; 2415318f18dSGabriel Huau 2425318f18dSGabriel Huau /* 2435318f18dSGabriel Huau * The offset for the same pin for the IOBASE and GPIOBASE are 2445318f18dSGabriel Huau * different, so instead of maintaining a lookup table, 2455318f18dSGabriel Huau * the device tree should provide directly the correct 2465318f18dSGabriel Huau * value for both mapping. 2475318f18dSGabriel Huau */ 2485318f18dSGabriel Huau pad_offset = 2495318f18dSGabriel Huau fdtdec_get_int(gd->fdt_blob, pin_node, "pad-offset", -1); 2505318f18dSGabriel Huau if (pad_offset == -1) { 2515318f18dSGabriel Huau debug("%s: Invalid register io offset %d\n", 2525318f18dSGabriel Huau __func__, pad_offset); 2535318f18dSGabriel Huau return -EINVAL; 2545318f18dSGabriel Huau } 2555318f18dSGabriel Huau 2565318f18dSGabriel Huau /* compute the absolute pad address */ 2575318f18dSGabriel Huau iobase_addr = iobase + pad_offset; 2585318f18dSGabriel Huau 2595318f18dSGabriel Huau /* 2605318f18dSGabriel Huau * Do we need to set a specific function mode? 2615318f18dSGabriel Huau * If someone put also 'mode-gpio', this option will 2625318f18dSGabriel Huau * be just ignored by the controller 2635318f18dSGabriel Huau */ 2645318f18dSGabriel Huau val = fdtdec_get_int(gd->fdt_blob, pin_node, "mode-func", -1); 2655318f18dSGabriel Huau if (val != -1) 2665318f18dSGabriel Huau clrsetbits_le32(iobase_addr, IOPAD_MODE_MASK, val); 2675318f18dSGabriel Huau 2685318f18dSGabriel Huau /* Configure the pull-up/down if needed */ 2695318f18dSGabriel Huau val = fdtdec_get_int(gd->fdt_blob, pin_node, "pull-assign", -1); 2705318f18dSGabriel Huau if (val != -1) 2715318f18dSGabriel Huau clrsetbits_le32(iobase_addr, 2725318f18dSGabriel Huau IOPAD_PULL_ASSIGN_MASK, 2735318f18dSGabriel Huau val << IOPAD_PULL_ASSIGN_SHIFT); 2745318f18dSGabriel Huau 2755318f18dSGabriel Huau val = 2765318f18dSGabriel Huau fdtdec_get_int(gd->fdt_blob, pin_node, "pull-strength", -1); 2775318f18dSGabriel Huau if (val != -1) 2785318f18dSGabriel Huau clrsetbits_le32(iobase_addr, 2795318f18dSGabriel Huau IOPAD_PULL_STRENGTH_MASK, 2805318f18dSGabriel Huau val << IOPAD_PULL_STRENGTH_SHIFT); 2815318f18dSGabriel Huau 2825318f18dSGabriel Huau debug("%s: pad cfg [0x%x]: %08x\n", __func__, pad_offset, 2835318f18dSGabriel Huau readl(iobase_addr)); 2845318f18dSGabriel Huau } 2855318f18dSGabriel Huau 2865318f18dSGabriel Huau return 0; 2875318f18dSGabriel Huau } 2885318f18dSGabriel Huau 2895318f18dSGabriel Huau int gpio_ich6_pinctrl_init(void) 2905318f18dSGabriel Huau { 2915318f18dSGabriel Huau int pin_node; 2925318f18dSGabriel Huau int node; 2935318f18dSGabriel Huau int ret; 2945318f18dSGabriel Huau int gpiobase; 2955318f18dSGabriel Huau int iobase_offset; 2965318f18dSGabriel Huau int iobase = -1; 2975318f18dSGabriel Huau 2985318f18dSGabriel Huau /* 2995318f18dSGabriel Huau * Get the memory/io base address to configure every pins. 3005318f18dSGabriel Huau * IOBASE is used to configure the mode/pads 3015318f18dSGabriel Huau * GPIOBASE is used to configure the direction and default value 3025318f18dSGabriel Huau */ 3035318f18dSGabriel Huau gpiobase = gpio_ich6_get_base(PCI_CFG_GPIOBASE); 3045318f18dSGabriel Huau if (gpiobase < 0) { 3055318f18dSGabriel Huau debug("%s: invalid GPIOBASE address (%08x)\n", __func__, 3065318f18dSGabriel Huau gpiobase); 3075318f18dSGabriel Huau return -EINVAL; 3085318f18dSGabriel Huau } 3095318f18dSGabriel Huau 3105318f18dSGabriel Huau /* This is not an error to not have a pinctrl node */ 3115318f18dSGabriel Huau node = 3125318f18dSGabriel Huau fdtdec_next_compatible(gd->fdt_blob, 0, COMPAT_INTEL_X86_PINCTRL); 3135318f18dSGabriel Huau if (node <= 0) { 3145318f18dSGabriel Huau debug("%s: no pinctrl node\n", __func__); 3155318f18dSGabriel Huau return 0; 3165318f18dSGabriel Huau } 3175318f18dSGabriel Huau 3185318f18dSGabriel Huau /* 3195318f18dSGabriel Huau * Get the IOBASE, this is not mandatory as this is not 3205318f18dSGabriel Huau * supported by all the CPU 3215318f18dSGabriel Huau */ 3225318f18dSGabriel Huau iobase_offset = fdtdec_get_int(gd->fdt_blob, node, "io-base", -1); 3235318f18dSGabriel Huau if (iobase_offset == -1) { 3245318f18dSGabriel Huau debug("%s: io-base offset not present\n", __func__); 3255318f18dSGabriel Huau } else { 3265318f18dSGabriel Huau iobase = gpio_ich6_get_base(iobase_offset); 3275318f18dSGabriel Huau if (iobase < 0) { 3285318f18dSGabriel Huau debug("%s: invalid IOBASE address (%08x)\n", __func__, 3295318f18dSGabriel Huau iobase); 3305318f18dSGabriel Huau return -EINVAL; 3315318f18dSGabriel Huau } 3325318f18dSGabriel Huau } 3335318f18dSGabriel Huau 3345318f18dSGabriel Huau for (pin_node = fdt_first_subnode(gd->fdt_blob, node); 3355318f18dSGabriel Huau pin_node > 0; 3365318f18dSGabriel Huau pin_node = fdt_next_subnode(gd->fdt_blob, pin_node)) { 3375318f18dSGabriel Huau /* Configure the pin */ 3385318f18dSGabriel Huau ret = _gpio_ich6_pinctrl_cfg_pin(gpiobase, iobase, pin_node); 3395318f18dSGabriel Huau if (ret != 0) { 3405318f18dSGabriel Huau debug("%s: invalid configuration for the pin %d\n", 3415318f18dSGabriel Huau __func__, pin_node); 3425318f18dSGabriel Huau return ret; 3435318f18dSGabriel Huau } 3445318f18dSGabriel Huau } 3455318f18dSGabriel Huau 3465318f18dSGabriel Huau return 0; 3475318f18dSGabriel Huau } 3485318f18dSGabriel Huau 3495318f18dSGabriel Huau static int gpio_ich6_ofdata_to_platdata(struct udevice *dev) 3505318f18dSGabriel Huau { 3515318f18dSGabriel Huau struct ich6_bank_platdata *plat = dev_get_platdata(dev); 3525318f18dSGabriel Huau u16 gpiobase; 3535318f18dSGabriel Huau int offset; 3545318f18dSGabriel Huau 3555318f18dSGabriel Huau gpiobase = gpio_ich6_get_base(PCI_CFG_GPIOBASE); 3567414112dSSimon Glass offset = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "reg", -1); 3577414112dSSimon Glass if (offset == -1) { 3587414112dSSimon Glass debug("%s: Invalid register offset %d\n", __func__, offset); 3597414112dSSimon Glass return -EINVAL; 3607414112dSSimon Glass } 3617414112dSSimon Glass plat->base_addr = gpiobase + offset; 3627414112dSSimon Glass plat->bank_name = fdt_getprop(gd->fdt_blob, dev->of_offset, 3637414112dSSimon Glass "bank-name", NULL); 36455ae10f8SBill Richardson 36555ae10f8SBill Richardson return 0; 36655ae10f8SBill Richardson } 36755ae10f8SBill Richardson 3681b4f25ffSSimon Glass static int ich6_gpio_probe(struct udevice *dev) 36955ae10f8SBill Richardson { 3707414112dSSimon Glass struct ich6_bank_platdata *plat = dev_get_platdata(dev); 371e564f054SSimon Glass struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 3727414112dSSimon Glass struct ich6_bank_priv *bank = dev_get_priv(dev); 3737414112dSSimon Glass 3741b4f25ffSSimon Glass if (gd->arch.gpio_map) { 3752795573aSBin Meng setup_pch_gpios(plat->base_addr, gd->arch.gpio_map); 3761b4f25ffSSimon Glass gd->arch.gpio_map = NULL; 3771b4f25ffSSimon Glass } 3782795573aSBin Meng 3797414112dSSimon Glass uc_priv->gpio_count = GPIO_PER_BANK; 3807414112dSSimon Glass uc_priv->bank_name = plat->bank_name; 3817414112dSSimon Glass bank->use_sel = plat->base_addr; 3827414112dSSimon Glass bank->io_sel = plat->base_addr + 4; 3837414112dSSimon Glass bank->lvl = plat->base_addr + 8; 3847414112dSSimon Glass 3857414112dSSimon Glass return 0; 3867414112dSSimon Glass } 3877414112dSSimon Glass 3881b4f25ffSSimon Glass static int ich6_gpio_request(struct udevice *dev, unsigned offset, 3891b4f25ffSSimon Glass const char *label) 3907414112dSSimon Glass { 3917414112dSSimon Glass struct ich6_bank_priv *bank = dev_get_priv(dev); 39255ae10f8SBill Richardson u32 tmplong; 39355ae10f8SBill Richardson 39455ae10f8SBill Richardson /* 39555ae10f8SBill Richardson * Make sure that the GPIO pin we want isn't already in use for some 39655ae10f8SBill Richardson * built-in hardware function. We have to check this for every 39755ae10f8SBill Richardson * requested pin. 39855ae10f8SBill Richardson */ 3997414112dSSimon Glass tmplong = inl(bank->use_sel); 4007414112dSSimon Glass if (!(tmplong & (1UL << offset))) { 40157be9172SBill Richardson debug("%s: gpio %d is reserved for internal use\n", __func__, 4027414112dSSimon Glass offset); 4037414112dSSimon Glass return -EPERM; 40455ae10f8SBill Richardson } 40555ae10f8SBill Richardson 40655ae10f8SBill Richardson return 0; 40755ae10f8SBill Richardson } 40855ae10f8SBill Richardson 4097414112dSSimon Glass static int ich6_gpio_direction_input(struct udevice *dev, unsigned offset) 41055ae10f8SBill Richardson { 4117414112dSSimon Glass struct ich6_bank_priv *bank = dev_get_priv(dev); 41257be9172SBill Richardson 4135318f18dSGabriel Huau return _ich6_gpio_set_direction(inl(bank->io_sel), offset, 0); 41455ae10f8SBill Richardson } 41555ae10f8SBill Richardson 4167414112dSSimon Glass static int ich6_gpio_direction_output(struct udevice *dev, unsigned offset, 4177414112dSSimon Glass int value) 41855ae10f8SBill Richardson { 4195318f18dSGabriel Huau int ret; 4207414112dSSimon Glass struct ich6_bank_priv *bank = dev_get_priv(dev); 42155ae10f8SBill Richardson 4225318f18dSGabriel Huau ret = _ich6_gpio_set_direction(inl(bank->io_sel), offset, 1); 4235318f18dSGabriel Huau if (ret) 4245318f18dSGabriel Huau return ret; 4250a54745fSAxel Lin 4265318f18dSGabriel Huau return _ich6_gpio_set_value(bank->lvl, offset, value); 42755ae10f8SBill Richardson } 42855ae10f8SBill Richardson 4297414112dSSimon Glass static int ich6_gpio_get_value(struct udevice *dev, unsigned offset) 43055ae10f8SBill Richardson { 4317414112dSSimon Glass struct ich6_bank_priv *bank = dev_get_priv(dev); 43255ae10f8SBill Richardson u32 tmplong; 43357be9172SBill Richardson int r; 43455ae10f8SBill Richardson 4357414112dSSimon Glass tmplong = inl(bank->lvl); 4367414112dSSimon Glass r = (tmplong & (1UL << offset)) ? 1 : 0; 43757be9172SBill Richardson return r; 43855ae10f8SBill Richardson } 43955ae10f8SBill Richardson 4407414112dSSimon Glass static int ich6_gpio_set_value(struct udevice *dev, unsigned offset, 4417414112dSSimon Glass int value) 44255ae10f8SBill Richardson { 4437414112dSSimon Glass struct ich6_bank_priv *bank = dev_get_priv(dev); 4445318f18dSGabriel Huau return _ich6_gpio_set_value(bank->lvl, offset, value); 44555ae10f8SBill Richardson } 4467414112dSSimon Glass 4477414112dSSimon Glass static int ich6_gpio_get_function(struct udevice *dev, unsigned offset) 4487414112dSSimon Glass { 4497414112dSSimon Glass struct ich6_bank_priv *bank = dev_get_priv(dev); 4507414112dSSimon Glass u32 mask = 1UL << offset; 4517414112dSSimon Glass 4527414112dSSimon Glass if (!(inl(bank->use_sel) & mask)) 4537414112dSSimon Glass return GPIOF_FUNC; 4547414112dSSimon Glass if (inl(bank->io_sel) & mask) 4557414112dSSimon Glass return GPIOF_INPUT; 4567414112dSSimon Glass else 4577414112dSSimon Glass return GPIOF_OUTPUT; 4587414112dSSimon Glass } 4597414112dSSimon Glass 4607414112dSSimon Glass static const struct dm_gpio_ops gpio_ich6_ops = { 4617414112dSSimon Glass .request = ich6_gpio_request, 4627414112dSSimon Glass .direction_input = ich6_gpio_direction_input, 4637414112dSSimon Glass .direction_output = ich6_gpio_direction_output, 4647414112dSSimon Glass .get_value = ich6_gpio_get_value, 4657414112dSSimon Glass .set_value = ich6_gpio_set_value, 4667414112dSSimon Glass .get_function = ich6_gpio_get_function, 4677414112dSSimon Glass }; 4687414112dSSimon Glass 4697414112dSSimon Glass static const struct udevice_id intel_ich6_gpio_ids[] = { 4707414112dSSimon Glass { .compatible = "intel,ich6-gpio" }, 4717414112dSSimon Glass { } 4727414112dSSimon Glass }; 4737414112dSSimon Glass 4747414112dSSimon Glass U_BOOT_DRIVER(gpio_ich6) = { 4757414112dSSimon Glass .name = "gpio_ich6", 4767414112dSSimon Glass .id = UCLASS_GPIO, 4777414112dSSimon Glass .of_match = intel_ich6_gpio_ids, 4787414112dSSimon Glass .ops = &gpio_ich6_ops, 4797414112dSSimon Glass .ofdata_to_platdata = gpio_ich6_ofdata_to_platdata, 4807414112dSSimon Glass .probe = ich6_gpio_probe, 4817414112dSSimon Glass .priv_auto_alloc_size = sizeof(struct ich6_bank_priv), 4827414112dSSimon Glass .platdata_auto_alloc_size = sizeof(struct ich6_bank_platdata), 4837414112dSSimon Glass }; 484