1 /* $NetBSD: pq3gpio.c,v 1.2 2011/01/18 01:02:53 matt Exp $ */ 2 /*- 3 * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Raytheon BBN Technologies Corp and Defense Advanced Research Projects 8 * Agency and which was developed by Matt Thomas of 3am Software Foundry. 9 * 10 * This material is based upon work supported by the Defense Advanced Research 11 * Projects Agency and Space and Naval Warfare Systems Center, Pacific, under 12 * Contract No. N66001-09-C-2073. 13 * Approved for Public Release, Distribution Unlimited 14 * 15 * Redistribution and use in source and binary forms, with or without 16 * modification, are permitted provided that the following conditions 17 * are met: 18 * 1. Redistributions of source code must retain the above copyright 19 * notice, this list of conditions and the following disclaimer. 20 * 2. Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in the 22 * documentation and/or other materials provided with the distribution. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 28 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 * POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37 #define GLOBAL_PRIVATE 38 39 #include "opt_mpc85xx.h" 40 41 #include <sys/cdefs.h> 42 43 __KERNEL_RCSID(0, "$NetBSD"); 44 45 #include <sys/param.h> 46 #include <sys/cpu.h> 47 #include <sys/device.h> 48 #include <sys/tty.h> 49 #include <sys/kmem.h> 50 #include <sys/gpio.h> 51 #include <sys/bitops.h> 52 53 #include "ioconf.h" 54 55 #include <sys/intr.h> 56 #include <sys/bus.h> 57 58 #include <dev/gpio/gpiovar.h> 59 60 #include <powerpc/booke/cpuvar.h> 61 #include <powerpc/booke/spr.h> 62 #include <powerpc/booke/e500var.h> 63 #include <powerpc/booke/e500reg.h> 64 65 struct pq3gpio_group { 66 #if 0 67 SIMPLEQ_ENTRY(pq3gpio_group) gc_link; 68 struct pq3gpio_softc *gc_softc; 69 #endif 70 struct gpio_chipset_tag gc_tag; 71 gpio_pin_t gc_pins[32]; 72 bus_space_tag_t gc_bst; 73 bus_space_handle_t gc_bsh; 74 bus_size_t gc_reg; 75 }; 76 77 struct pq3gpio_softc { 78 device_t sc_dev; 79 bus_space_tag_t sc_bst; 80 bus_space_handle_t sc_bsh; 81 SIMPLEQ_HEAD(,pq3gpio_group) sc_gpios; 82 }; 83 84 static int 85 pq3gpio_pin_read(void *v, int num) 86 { 87 struct pq3gpio_group * const gc = v; 88 89 uint32_t data = bus_space_read_4(gc->gc_bst, gc->gc_bsh, gc->gc_reg); 90 91 return (data >> (gc->gc_pins[num].pin_num ^ 31)) & 1; 92 } 93 94 static void 95 pq3gpio_pin_write(void *v, int num, int val) 96 { 97 struct pq3gpio_group * const gc = v; 98 const u_int mask = 1 << (gc->gc_pins[num].pin_num ^ 31); 99 100 val = val ? mask : 0; 101 u_int data = bus_space_read_4(gc->gc_bst, gc->gc_bsh, gc->gc_reg); 102 if ((data & mask) != val) { 103 data = (data & ~mask) | val; 104 bus_space_write_4(gc->gc_bst, gc->gc_bsh, gc->gc_reg, data); 105 } 106 } 107 108 static void 109 pq3gpio_pin_ctl(void *v, int num, int ctl) 110 { 111 } 112 113 static void 114 pq3gpio_group_create(device_t self, bus_space_tag_t bst, bus_space_handle_t bsh, 115 bus_size_t reg, uint32_t pinmask, int pincaps) 116 { 117 struct pq3gpio_group * const gc = kmem_zalloc(sizeof(*gc), KM_SLEEP); 118 119 gc->gc_bst = bst; 120 gc->gc_bsh = bsh; 121 gc->gc_reg = reg; 122 gc->gc_tag.gp_cookie = gc; 123 #if 0 124 gc->gc_tag.gp_gc_open = pq3gpio_gc_open; 125 gc->gc_tag.gp_gc_close = pq3gpio_gc_close; 126 #endif 127 gc->gc_tag.gp_pin_read = pq3gpio_pin_read; 128 gc->gc_tag.gp_pin_write = pq3gpio_pin_write; 129 gc->gc_tag.gp_pin_ctl = pq3gpio_pin_ctl; 130 131 u_int data = bus_space_read_4(gc->gc_bst, gc->gc_bsh, reg); 132 u_int mask = __BIT(31); 133 gpio_pin_t *pin = gc->gc_pins; 134 for (u_int i = 0; mask != 0; i++, mask >>= 1) { 135 if (mask & pinmask) { 136 pin->pin_num = i; 137 pin->pin_caps = pincaps; 138 pin->pin_flags = pincaps; 139 pin->pin_state = (data & mask) != 0; 140 pin++; 141 } 142 } 143 144 struct gpiobus_attach_args gba = { 145 .gba_gc = &gc->gc_tag, 146 .gba_pins = gc->gc_pins, 147 .gba_npins = pin - gc->gc_pins, 148 }; 149 150 config_found_ia(self, "gpiobus", &gba, gpiobus_print); 151 } 152 153 #ifdef MPC8536 154 static void 155 pq3gpio_mpc8536_attach(device_t self, bus_space_tag_t bst, 156 bus_space_handle_t bsh, u_int svr) 157 { 158 static const uint8_t gpio2pmuxcr_map[] = { 159 [0] = ilog2(PMUXCR_PCI_REQGNT3), 160 [1] = ilog2(PMUXCR_PCI_REQGNT4), 161 [2] = ilog2(PMUXCR_PCI_REQGNT3), 162 [3] = ilog2(PMUXCR_PCI_REQGNT4), 163 [4] = ilog2(PMUXCR_SDHC_CD), 164 [5] = ilog2(PMUXCR_SDHC_WP), 165 [6] = ilog2(PMUXCR_USB1), 166 [7] = ilog2(PMUXCR_USB1), 167 [8] = ilog2(PMUXCR_USB2), 168 [9] = ilog2(PMUXCR_USB2), 169 [10] = ilog2(PMUXCR_DMA0), 170 [11] = ilog2(PMUXCR_DMA1), 171 [12] = ilog2(PMUXCR_DMA0), 172 [13] = ilog2(PMUXCR_DMA1), 173 [14] = ilog2(PMUXCR_DMA0), 174 [15] = ilog2(PMUXCR_DMA1), 175 }; 176 177 uint32_t pinmask = ~0; /* assume all bits are valid */ 178 uint32_t gpiomask = __BIT(31); 179 size_t pincnt = 32; 180 const uint32_t pmuxcr = bus_space_read_4(bst, bsh, PMUXCR); 181 for (size_t i = 0; i < __arraycount(gpio2pmuxcr_map); 182 i++, gpiomask >>= 1) { 183 if (pmuxcr & __BIT(gpio2pmuxcr_map[i])) { 184 pinmask &= ~gpiomask; 185 pincnt--; 186 } 187 } 188 189 /* 190 * Create GPIO pin groups 191 */ 192 aprint_normal_dev(self, "%zu input pins, %zu output pins\n", 193 pincnt, pincnt); 194 pq3gpio_group_create(self, bst, bsh, GPINDR, pinmask, GPIO_PIN_INPUT); 195 pq3gpio_group_create(self, bst, bsh, GPOUTDR, pinmask, GPIO_PIN_OUTPUT); 196 } 197 #endif /* MPC8536 */ 198 199 #ifdef MPC8544 200 static void 201 pq3gpio_mpc8544_attach(device_t self, bus_space_tag_t bst, 202 bus_space_handle_t bsh, u_int svr) 203 { 204 /* 205 * Enable GPOUT 206 */ 207 uint32_t gpiocr = bus_space_read_4(bst, bsh, GPIOCR); 208 gpiocr |= GPIOCR_GPOUT; 209 bus_space_write_4(bst, bsh, GPIOCR, gpiocr); 210 211 aprint_normal_dev(self, "8 input pins, 8 output pins\n"); 212 213 /* 214 * Create GPIO pin groups 215 */ 216 pq3gpio_group_create(self, bst, bsh, GPINDR, 0xff000000, GPIO_PIN_INPUT); 217 pq3gpio_group_create(self, bst, bsh, GPOUTDR, 0xff000000, GPIO_PIN_OUTPUT); 218 } 219 #endif /* MPC8544 */ 220 221 #if defined(MPC8548) || defined(MPC8555) 222 static void 223 pq3gpio_mpc8548_attach(device_t self, bus_space_tag_t bst, 224 bus_space_handle_t bsh, u_int svr) 225 { 226 const uint32_t pordevsr = bus_space_read_4(bst, bsh, PORDEVSR); 227 const uint32_t devdisr = bus_space_read_4(bst, bsh, DEVDISR); 228 uint32_t gpiocr = bus_space_read_4(bst, bsh, GPIOCR); 229 230 uint32_t inmask = 0; 231 uint32_t outmask = 0; 232 233 size_t ipins = 0; 234 size_t opins = 0; 235 236 aprint_normal_dev(self, "GPIOCR %#x, DEVDISR %#x, PORDEVSR %#x\n", 237 gpiocr, devdisr, pordevsr); 238 aprint_normal_dev(self, "GPINDR %#x, GPOUTDR %#x, GPPORCR %#x\n", 239 bus_space_read_4(bst, bsh, GPINDR), 240 bus_space_read_4(bst, bsh, GPOUTDR), 241 bus_space_read_4(bst, bsh, GPPORCR)); 242 243 /* 244 * Use PCI2 AD[15:0] as GPIO if PCI2 is disabled and 245 * PCI1 is either disabled or not 64bits wide. 246 */ 247 if ((devdisr & DEVDISR_PCI2) && 248 ((devdisr & DEVDISR_PCI1) || (pordevsr & PORDEVSR_PCI32))) { 249 gpiocr |= GPIOCR_PCIOUT; 250 gpiocr |= GPIOCR_PCIIN; 251 outmask |= 0x00ff0000; 252 inmask |= 0x00ff0000; 253 opins += 8; 254 ipins += 8; 255 } 256 if (devdisr & DEVDISR_TSEC2) { 257 gpiocr |= GPIOCR_TX2; 258 gpiocr |= GPIOCR_RX2; 259 outmask |= 0xff000000; 260 inmask |= 0xff000000; 261 opins += 8; 262 ipins += 8; 263 } 264 if (svr != (SVR_MPC8555v1 >> 16)) { 265 gpiocr |= GPIOCR_GPOUT; 266 outmask |= 0x000000ff; 267 opins += 8; 268 } 269 #if 1 270 aprint_normal_dev(self, "GPIOCR: %#x\n", gpiocr); 271 #else 272 bus_space_write_4(bst, bsh, GPIOCR, gpiocr); 273 #endif 274 275 /* 276 * Create GPIO pin groups 277 */ 278 aprint_normal_dev(self, "%zu input pins, %zu output pins\n", 279 ipins, opins); 280 281 if (inmask) 282 pq3gpio_group_create(self, bst, bsh, GPINDR, inmask, GPIO_PIN_INPUT); 283 if (outmask) 284 pq3gpio_group_create(self, bst, bsh, GPOUTDR, outmask, GPIO_PIN_OUTPUT); 285 } 286 #endif /* MPC8548 */ 287 288 static const struct { 289 uint16_t svr; 290 void (*attach)(device_t, bus_space_tag_t, bus_space_handle_t, u_int); 291 } pq3gpio_svrs[] = { 292 #ifdef MPC8548 293 { SVR_MPC8548v2 >> 16, pq3gpio_mpc8548_attach }, 294 #endif 295 #ifdef MPC8555 296 { SVR_MPC8555v1 >> 16, pq3gpio_mpc8548_attach }, 297 #endif 298 #ifdef MPC8544 299 { SVR_MPC8544v1 >> 16, pq3gpio_mpc8544_attach }, 300 #endif 301 #ifdef MPC8536 302 { SVR_MPC8536v1 >> 16, pq3gpio_mpc8536_attach }, 303 #endif 304 }; 305 306 void 307 pq3gpio_attach(device_t parent, device_t self, void *aux) 308 { 309 struct mainbus_attach_args * const ma = aux; 310 bus_space_tag_t bst = ma->ma_memt; 311 bus_space_handle_t bsh; 312 int error; 313 314 error = bus_space_map(bst, GLOBAL_BASE, GLOBAL_SIZE, 0, &bsh); 315 if (error) { 316 aprint_error_dev(self, 317 "can't map global registers for gpio: %d\n", 318 error); 319 return; 320 } 321 322 const uint16_t svr = e500_get_svr(); 323 for (u_int i = 0; i < __arraycount(pq3gpio_svrs); i++) { 324 if (pq3gpio_svrs[i].svr == svr) { 325 (*pq3gpio_svrs[i].attach)(self, bst, bsh, svr); 326 return; 327 } 328 } 329 aprint_normal_dev(self, 330 "0 input groups, 0 output groups (unknown svr %#x)\n", 331 svr); 332 } 333