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