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