1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2016 Google, Inc 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 <dm/pinctrl.h> 17 18 DECLARE_GLOBAL_DATA_PTR; 19 20 #define GPIO_USESEL_OFFSET(x) (x) 21 #define GPIO_IOSEL_OFFSET(x) (x + 4) 22 #define GPIO_LVL_OFFSET(x) ((x) ? (x) + 8 : 0xc) 23 #define GPI_INV 0x2c 24 25 #define IOPAD_MODE_MASK 0x7 26 #define IOPAD_PULL_ASSIGN_SHIFT 7 27 #define IOPAD_PULL_ASSIGN_MASK (0x3 << IOPAD_PULL_ASSIGN_SHIFT) 28 #define IOPAD_PULL_STRENGTH_SHIFT 9 29 #define IOPAD_PULL_STRENGTH_MASK (0x3 << IOPAD_PULL_STRENGTH_SHIFT) 30 31 static int ich6_pinctrl_set_value(uint16_t base, unsigned offset, int value) 32 { 33 if (value) 34 setio_32(base, 1UL << offset); 35 else 36 clrio_32(base, 1UL << offset); 37 38 return 0; 39 } 40 41 static int ich6_pinctrl_set_function(uint16_t base, unsigned offset, int func) 42 { 43 if (func) 44 setio_32(base, 1UL << offset); 45 else 46 clrio_32(base, 1UL << offset); 47 48 return 0; 49 } 50 51 static int ich6_pinctrl_set_direction(uint16_t base, unsigned offset, int dir) 52 { 53 if (!dir) 54 setio_32(base, 1UL << offset); 55 else 56 clrio_32(base, 1UL << offset); 57 58 return 0; 59 } 60 61 static int ich6_pinctrl_cfg_pin(s32 gpiobase, s32 iobase, int pin_node) 62 { 63 bool is_gpio, invert; 64 u32 gpio_offset[2]; 65 int pad_offset; 66 int dir, val; 67 int ret; 68 69 /* 70 * GPIO node is not mandatory, so we only do the pinmuxing if the 71 * node exists. 72 */ 73 ret = fdtdec_get_int_array(gd->fdt_blob, pin_node, "gpio-offset", 74 gpio_offset, 2); 75 if (!ret) { 76 /* Do we want to force the GPIO mode? */ 77 is_gpio = fdtdec_get_bool(gd->fdt_blob, pin_node, "mode-gpio"); 78 if (is_gpio) 79 ich6_pinctrl_set_function(GPIO_USESEL_OFFSET(gpiobase) + 80 gpio_offset[0], gpio_offset[1], 81 1); 82 83 dir = fdtdec_get_int(gd->fdt_blob, pin_node, "direction", -1); 84 if (dir != -1) 85 ich6_pinctrl_set_direction(GPIO_IOSEL_OFFSET(gpiobase) + 86 gpio_offset[0], gpio_offset[1], 87 dir); 88 89 val = fdtdec_get_int(gd->fdt_blob, pin_node, "output-value", 90 -1); 91 if (val != -1) 92 ich6_pinctrl_set_value(GPIO_LVL_OFFSET(gpiobase) + 93 gpio_offset[0], gpio_offset[1], 94 val); 95 96 invert = fdtdec_get_bool(gd->fdt_blob, pin_node, "invert"); 97 if (invert) 98 setio_32(gpiobase + GPI_INV, 1 << gpio_offset[1]); 99 debug("gpio %#x bit %d, is_gpio %d, dir %d, val %d, invert %d\n", 100 gpio_offset[0], gpio_offset[1], is_gpio, dir, val, 101 invert); 102 } 103 104 /* if iobase is present, let's configure the pad */ 105 if (iobase != -1) { 106 ulong iobase_addr; 107 108 /* 109 * The offset for the same pin for the IOBASE and GPIOBASE are 110 * different, so instead of maintaining a lookup table, 111 * the device tree should provide directly the correct 112 * value for both mapping. 113 */ 114 pad_offset = fdtdec_get_int(gd->fdt_blob, pin_node, 115 "pad-offset", -1); 116 if (pad_offset == -1) 117 return 0; 118 119 /* compute the absolute pad address */ 120 iobase_addr = iobase + pad_offset; 121 122 /* 123 * Do we need to set a specific function mode? 124 * If someone put also 'mode-gpio', this option will 125 * be just ignored by the controller 126 */ 127 val = fdtdec_get_int(gd->fdt_blob, pin_node, "mode-func", -1); 128 if (val != -1) 129 clrsetbits_le32(iobase_addr, IOPAD_MODE_MASK, val); 130 131 /* Configure the pull-up/down if needed */ 132 val = fdtdec_get_int(gd->fdt_blob, pin_node, "pull-assign", -1); 133 if (val != -1) 134 clrsetbits_le32(iobase_addr, 135 IOPAD_PULL_ASSIGN_MASK, 136 val << IOPAD_PULL_ASSIGN_SHIFT); 137 138 val = fdtdec_get_int(gd->fdt_blob, pin_node, "pull-strength", 139 -1); 140 if (val != -1) 141 clrsetbits_le32(iobase_addr, 142 IOPAD_PULL_STRENGTH_MASK, 143 val << IOPAD_PULL_STRENGTH_SHIFT); 144 145 debug("%s: pad cfg [0x%x]: %08x\n", __func__, pad_offset, 146 readl(iobase_addr)); 147 } 148 149 return 0; 150 } 151 152 static int ich6_pinctrl_probe(struct udevice *dev) 153 { 154 struct udevice *pch; 155 int pin_node; 156 int ret; 157 u32 gpiobase; 158 u32 iobase = -1; 159 160 debug("%s: start\n", __func__); 161 ret = uclass_first_device(UCLASS_PCH, &pch); 162 if (ret) 163 return ret; 164 if (!pch) 165 return -ENODEV; 166 167 /* 168 * Get the memory/io base address to configure every pins. 169 * IOBASE is used to configure the mode/pads 170 * GPIOBASE is used to configure the direction and default value 171 */ 172 ret = pch_get_gpio_base(pch, &gpiobase); 173 if (ret) { 174 debug("%s: invalid GPIOBASE address (%08x)\n", __func__, 175 gpiobase); 176 return -EINVAL; 177 } 178 179 /* 180 * Get the IOBASE, this is not mandatory as this is not 181 * supported by all the CPU 182 */ 183 ret = pch_get_io_base(pch, &iobase); 184 if (ret && ret != -ENOSYS) { 185 debug("%s: invalid IOBASE address (%08x)\n", __func__, iobase); 186 return -EINVAL; 187 } 188 189 for (pin_node = fdt_first_subnode(gd->fdt_blob, dev_of_offset(dev)); 190 pin_node > 0; 191 pin_node = fdt_next_subnode(gd->fdt_blob, pin_node)) { 192 /* Configure the pin */ 193 ret = ich6_pinctrl_cfg_pin(gpiobase, iobase, pin_node); 194 if (ret != 0) { 195 debug("%s: invalid configuration for the pin %d\n", 196 __func__, pin_node); 197 return ret; 198 } 199 } 200 debug("%s: done\n", __func__); 201 202 return 0; 203 } 204 205 static const struct udevice_id ich6_pinctrl_match[] = { 206 { .compatible = "intel,x86-pinctrl", .data = X86_SYSCON_PINCONF }, 207 { /* sentinel */ } 208 }; 209 210 U_BOOT_DRIVER(ich6_pinctrl) = { 211 .name = "ich6_pinctrl", 212 .id = UCLASS_SYSCON, 213 .of_match = ich6_pinctrl_match, 214 .probe = ich6_pinctrl_probe, 215 }; 216