1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (c) 2012 The Chromium OS Authors. 4 */ 5 6 #include <common.h> 7 #include <dm.h> 8 #include <errno.h> 9 #include <fdtdec.h> 10 #include <pch.h> 11 #include <pci.h> 12 #include <syscon.h> 13 #include <asm/cpu.h> 14 #include <asm/gpio.h> 15 #include <asm/io.h> 16 #include <asm/pci.h> 17 #include <asm/arch/gpio.h> 18 #include <dt-bindings/gpio/x86-gpio.h> 19 20 DECLARE_GLOBAL_DATA_PTR; 21 22 /** 23 * struct broadwell_bank_priv - Private driver data 24 * 25 * @regs: Pointer to GPIO registers 26 * @bank: Bank number for this bank (0, 1 or 2) 27 * @offset: GPIO offset for this bank (0, 32 or 64) 28 */ 29 struct broadwell_bank_priv { 30 struct pch_lp_gpio_regs *regs; 31 int bank; 32 int offset; 33 }; 34 35 static int broadwell_gpio_request(struct udevice *dev, unsigned offset, 36 const char *label) 37 { 38 struct broadwell_bank_priv *priv = dev_get_priv(dev); 39 struct pch_lp_gpio_regs *regs = priv->regs; 40 u32 val; 41 42 /* 43 * Make sure that the GPIO pin we want isn't already in use for some 44 * built-in hardware function. We have to check this for every 45 * requested pin. 46 */ 47 debug("%s: request bank %d offset %d: ", __func__, priv->bank, offset); 48 val = inl(®s->own[priv->bank]); 49 if (!(val & (1UL << offset))) { 50 debug("gpio is reserved for internal use\n"); 51 return -EPERM; 52 } 53 debug("ok\n"); 54 55 return 0; 56 } 57 58 static int broadwell_gpio_direction_input(struct udevice *dev, unsigned offset) 59 { 60 struct broadwell_bank_priv *priv = dev_get_priv(dev); 61 struct pch_lp_gpio_regs *regs = priv->regs; 62 63 setio_32(®s->config[priv->offset + offset], CONFA_DIR_INPUT); 64 65 return 0; 66 } 67 68 static int broadwell_gpio_get_value(struct udevice *dev, unsigned offset) 69 { 70 struct broadwell_bank_priv *priv = dev_get_priv(dev); 71 struct pch_lp_gpio_regs *regs = priv->regs; 72 73 return inl(®s->config[priv->offset + offset]) & CONFA_LEVEL_HIGH ? 74 1 : 0; 75 } 76 77 static int broadwell_gpio_set_value(struct udevice *dev, unsigned offset, 78 int value) 79 { 80 struct broadwell_bank_priv *priv = dev_get_priv(dev); 81 struct pch_lp_gpio_regs *regs = priv->regs; 82 83 debug("%s: dev=%s, offset=%d, value=%d\n", __func__, dev->name, offset, 84 value); 85 clrsetio_32(®s->config[priv->offset + offset], CONFA_OUTPUT_HIGH, 86 value ? CONFA_OUTPUT_HIGH : 0); 87 88 return 0; 89 } 90 91 static int broadwell_gpio_direction_output(struct udevice *dev, unsigned offset, 92 int value) 93 { 94 struct broadwell_bank_priv *priv = dev_get_priv(dev); 95 struct pch_lp_gpio_regs *regs = priv->regs; 96 97 broadwell_gpio_set_value(dev, offset, value); 98 clrio_32(®s->config[priv->offset + offset], CONFA_DIR_INPUT); 99 100 return 0; 101 } 102 103 static int broadwell_gpio_get_function(struct udevice *dev, unsigned offset) 104 { 105 struct broadwell_bank_priv *priv = dev_get_priv(dev); 106 struct pch_lp_gpio_regs *regs = priv->regs; 107 u32 mask = 1UL << offset; 108 109 if (!(inl(®s->own[priv->bank]) & mask)) 110 return GPIOF_FUNC; 111 if (inl(®s->config[priv->offset + offset]) & CONFA_DIR_INPUT) 112 return GPIOF_INPUT; 113 else 114 return GPIOF_OUTPUT; 115 } 116 117 static int broadwell_gpio_probe(struct udevice *dev) 118 { 119 struct broadwell_bank_platdata *plat = dev_get_platdata(dev); 120 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 121 struct broadwell_bank_priv *priv = dev_get_priv(dev); 122 struct udevice *pinctrl; 123 int ret; 124 125 /* Set up pin control if available */ 126 ret = syscon_get_by_driver_data(X86_SYSCON_PINCONF, &pinctrl); 127 debug("%s, pinctrl=%p, ret=%d\n", __func__, pinctrl, ret); 128 129 uc_priv->gpio_count = GPIO_PER_BANK; 130 uc_priv->bank_name = plat->bank_name; 131 132 priv->regs = (struct pch_lp_gpio_regs *)(uintptr_t)plat->base_addr; 133 priv->bank = plat->bank; 134 priv->offset = priv->bank * 32; 135 debug("%s: probe done, regs %p, bank %d\n", __func__, priv->regs, 136 priv->bank); 137 138 return 0; 139 } 140 141 static int broadwell_gpio_ofdata_to_platdata(struct udevice *dev) 142 { 143 struct broadwell_bank_platdata *plat = dev_get_platdata(dev); 144 u32 gpiobase; 145 int bank; 146 int ret; 147 148 ret = pch_get_gpio_base(dev->parent, &gpiobase); 149 if (ret) 150 return ret; 151 152 bank = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "reg", -1); 153 if (bank == -1) { 154 debug("%s: Invalid bank number %d\n", __func__, bank); 155 return -EINVAL; 156 } 157 plat->bank = bank; 158 plat->base_addr = gpiobase; 159 plat->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), 160 "bank-name", NULL); 161 162 return 0; 163 } 164 165 static const struct dm_gpio_ops gpio_broadwell_ops = { 166 .request = broadwell_gpio_request, 167 .direction_input = broadwell_gpio_direction_input, 168 .direction_output = broadwell_gpio_direction_output, 169 .get_value = broadwell_gpio_get_value, 170 .set_value = broadwell_gpio_set_value, 171 .get_function = broadwell_gpio_get_function, 172 }; 173 174 static const struct udevice_id intel_broadwell_gpio_ids[] = { 175 { .compatible = "intel,broadwell-gpio" }, 176 { } 177 }; 178 179 U_BOOT_DRIVER(gpio_broadwell) = { 180 .name = "gpio_broadwell", 181 .id = UCLASS_GPIO, 182 .of_match = intel_broadwell_gpio_ids, 183 .ops = &gpio_broadwell_ops, 184 .ofdata_to_platdata = broadwell_gpio_ofdata_to_platdata, 185 .probe = broadwell_gpio_probe, 186 .priv_auto_alloc_size = sizeof(struct broadwell_bank_priv), 187 .platdata_auto_alloc_size = sizeof(struct broadwell_bank_platdata), 188 }; 189