1/* $NetBSD$ */ 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#define GPIO_PRIVATE 39 40#include "opt_mpc85xx.h" 41 42#include <sys/cdefs.h> 43 44__KERNEL_RCSID(0, "$NetBSD$"); 45 46#include <sys/param.h> 47#include <sys/cpu.h> 48#include <sys/device.h> 49#include <sys/tty.h> 50#include <sys/kmem.h> 51#include <sys/gpio.h> 52#include <sys/bitops.h> 53 54#include "ioconf.h" 55 56#include <sys/intr.h> 57#include <sys/bus.h> 58 59#include <dev/gpio/gpiovar.h> 60 61#include <powerpc/booke/cpuvar.h> 62#include <powerpc/booke/spr.h> 63#include <powerpc/booke/e500var.h> 64#include <powerpc/booke/e500reg.h> 65 66struct pq3gpio_group { 67#if 0 68 SIMPLEQ_ENTRY(pq3gpio_group) gc_link; 69 struct pq3gpio_softc *gc_softc; 70#endif 71 struct gpio_chipset_tag gc_tag; 72 gpio_pin_t gc_pins[32]; 73 bus_space_tag_t gc_bst; 74 bus_space_handle_t gc_bsh; 75 bus_size_t gc_reg; 76}; 77 78struct pq3gpio_softc { 79 device_t sc_dev; 80 bus_space_tag_t sc_bst; 81 bus_space_handle_t sc_bsh; 82 SIMPLEQ_HEAD(,pq3gpio_group) sc_gpios; 83}; 84 85static int 86pq3gpio_pin_read(void *v, int num) 87{ 88 struct pq3gpio_group * const gc = v; 89 90 uint32_t data = bus_space_read_4(gc->gc_bst, gc->gc_bsh, gc->gc_reg); 91 92 return (data >> (gc->gc_pins[num].pin_num ^ 31)) & 1; 93} 94 95static void 96pq3gpio_pin_write(void *v, int num, int val) 97{ 98 struct pq3gpio_group * const gc = v; 99 const u_int mask = 1 << (gc->gc_pins[num].pin_num ^ 31); 100 101 val = val ? mask : 0; 102 u_int data = bus_space_read_4(gc->gc_bst, gc->gc_bsh, gc->gc_reg); 103 if ((data & mask) != val) { 104 data = (data & ~mask) | val; 105 bus_space_write_4(gc->gc_bst, gc->gc_bsh, gc->gc_reg, data); 106 } 107} 108 109static void 110pq3gpio_pin_ctl(void *v, int num, int ctl) 111{ 112 struct pq3gpio_group * const gc = v; 113 const u_int mask = 1 << (gc->gc_pins[num].pin_num ^ 31); 114 uint32_t old, new; 115 116 old = bus_space_read_4(gc->gc_bst, gc->gc_bsh, GPDIR); 117 new = old; 118 switch (ctl & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { 119 case GPIO_PIN_OUTPUT: new |= mask; break; 120 case GPIO_PIN_INPUT: new &= ~mask; break; 121 default: return; 122 } 123 if (old != new) 124 bus_space_write_4(gc->gc_bst, gc->gc_bsh, GPDIR, new); 125} 126 127static void 128pq3gpio_group_create(device_t self, bus_space_tag_t bst, bus_space_handle_t bsh, 129 bus_size_t reg, uint32_t pinmask, int pincaps) 130{ 131 struct pq3gpio_group * const gc = kmem_zalloc(sizeof(*gc), KM_SLEEP); 132 133 gc->gc_bst = bst; 134 gc->gc_bsh = bsh; 135 gc->gc_reg = reg; 136 gc->gc_tag.gp_cookie = gc; 137#if 0 138 gc->gc_tag.gp_gc_open = pq3gpio_gc_open; 139 gc->gc_tag.gp_gc_close = pq3gpio_gc_close; 140#endif 141 gc->gc_tag.gp_pin_read = pq3gpio_pin_read; 142 gc->gc_tag.gp_pin_write = pq3gpio_pin_write; 143 gc->gc_tag.gp_pin_ctl = pq3gpio_pin_ctl; 144 145 u_int data = bus_space_read_4(gc->gc_bst, gc->gc_bsh, reg); 146 u_int mask = __BIT(31); 147 gpio_pin_t *pin = gc->gc_pins; 148 for (u_int i = 0; mask != 0; i++, mask >>= 1) { 149 if (mask & pinmask) { 150 pin->pin_num = i; 151 pin->pin_caps = pincaps; 152 pin->pin_flags = pincaps; 153 pin->pin_state = (data & mask) != 0; 154 pin++; 155 } 156 } 157 158 struct gpiobus_attach_args gba = { 159 .gba_gc = &gc->gc_tag, 160 .gba_pins = gc->gc_pins, 161 .gba_npins = pin - gc->gc_pins, 162 }; 163 164 config_found_ia(self, "gpiobus", &gba, gpiobus_print); 165} 166 167#ifdef MPC8536 168static void 169pq3gpio_mpc8536_attach(device_t self, bus_space_tag_t bst, 170 bus_space_handle_t bsh, u_int svr) 171{ 172 static const uint8_t gpio2pmuxcr_map[] = { 173 [0] = ilog2(PMUXCR_PCI_REQGNT3), 174 [1] = ilog2(PMUXCR_PCI_REQGNT4), 175 [2] = ilog2(PMUXCR_PCI_REQGNT3), 176 [3] = ilog2(PMUXCR_PCI_REQGNT4), 177 [4] = ilog2(PMUXCR_SDHC_CD), 178 [5] = ilog2(PMUXCR_SDHC_WP), 179 [6] = ilog2(PMUXCR_USB1), 180 [7] = ilog2(PMUXCR_USB1), 181 [8] = ilog2(PMUXCR_USB2), 182 [9] = ilog2(PMUXCR_USB2), 183 [10] = ilog2(PMUXCR_DMA0), 184 [11] = ilog2(PMUXCR_DMA1), 185 [12] = ilog2(PMUXCR_DMA0), 186 [13] = ilog2(PMUXCR_DMA1), 187 [14] = ilog2(PMUXCR_DMA0), 188 [15] = ilog2(PMUXCR_DMA1), 189 }; 190 191 uint32_t pinmask = ~0; /* assume all bits are valid */ 192 uint32_t gpiomask = __BIT(31); 193 size_t pincnt = 32; 194 const uint32_t pmuxcr = bus_space_read_4(bst, bsh, PMUXCR); 195 for (size_t i = 0; i < __arraycount(gpio2pmuxcr_map); 196 i++, gpiomask >>= 1) { 197 if (pmuxcr & __BIT(gpio2pmuxcr_map[i])) { 198 pinmask &= ~gpiomask; 199 pincnt--; 200 } 201 } 202 203 /* 204 * Create GPIO pin groups 205 */ 206 aprint_normal_dev(self, "%zu input pins, %zu output pins\n", 207 pincnt, pincnt); 208 pq3gpio_group_create(self, bst, bsh, GPINDR, pinmask, GPIO_PIN_INPUT); 209 pq3gpio_group_create(self, bst, bsh, GPOUTDR, pinmask, GPIO_PIN_OUTPUT); 210} 211#endif /* MPC8536 */ 212 213#ifdef MPC8544 214static void 215pq3gpio_mpc8544_attach(device_t self, bus_space_tag_t bst, 216 bus_space_handle_t bsh, u_int svr) 217{ 218 /* 219 * Enable GPOUT 220 */ 221 uint32_t gpiocr = bus_space_read_4(bst, bsh, GPIOCR); 222 gpiocr |= GPIOCR_GPOUT; 223 bus_space_write_4(bst, bsh, GPIOCR, gpiocr); 224 225 aprint_normal_dev(self, "8 input pins, 8 output pins\n"); 226 227 /* 228 * Create GPIO pin groups 229 */ 230 pq3gpio_group_create(self, bst, bsh, GPINDR, 0xff000000, GPIO_PIN_INPUT); 231 pq3gpio_group_create(self, bst, bsh, GPOUTDR, 0xff000000, GPIO_PIN_OUTPUT); 232} 233#endif /* MPC8544 */ 234 235#if defined(MPC8548) || defined(MPC8555) 236static void 237pq3gpio_mpc8548_attach(device_t self, bus_space_tag_t bst, 238 bus_space_handle_t bsh, u_int svr) 239{ 240 const uint32_t pordevsr = bus_space_read_4(bst, bsh, PORDEVSR); 241 const uint32_t devdisr = bus_space_read_4(bst, bsh, DEVDISR); 242 uint32_t gpiocr = bus_space_read_4(bst, bsh, GPIOCR); 243 244 uint32_t inmask = 0; 245 uint32_t outmask = 0; 246 247 size_t ipins = 0; 248 size_t opins = 0; 249 250 aprint_normal_dev(self, "GPIOCR %#x, DEVDISR %#x, PORDEVSR %#x\n", 251 gpiocr, devdisr, pordevsr); 252 aprint_normal_dev(self, "GPINDR %#x, GPOUTDR %#x, GPPORCR %#x\n", 253 bus_space_read_4(bst, bsh, GPINDR), 254 bus_space_read_4(bst, bsh, GPOUTDR), 255 bus_space_read_4(bst, bsh, GPPORCR)); 256 257 /* 258 * Use PCI2 AD[15:0] as GPIO if PCI2 is disabled and 259 * PCI1 is either disabled or not 64bits wide. 260 */ 261 if ((devdisr & DEVDISR_PCI2) && 262 ((devdisr & DEVDISR_PCI1) || (pordevsr & PORDEVSR_PCI32))) { 263 gpiocr |= GPIOCR_PCIOUT; 264 gpiocr |= GPIOCR_PCIIN; 265 outmask |= 0x00ff0000; 266 inmask |= 0x00ff0000; 267 opins += 8; 268 ipins += 8; 269 } 270 if (devdisr & DEVDISR_TSEC2) { 271 gpiocr |= GPIOCR_TX2; 272 gpiocr |= GPIOCR_RX2; 273 outmask |= 0xff000000; 274 inmask |= 0xff000000; 275 opins += 8; 276 ipins += 8; 277 } 278 if (svr != (SVR_MPC8555v1 >> 16)) { 279 gpiocr |= GPIOCR_GPOUT; 280 outmask |= 0x000000ff; 281 opins += 8; 282 } 283#if 1 284 aprint_normal_dev(self, "GPIOCR: %#x\n", gpiocr); 285#else 286 bus_space_write_4(bst, bsh, GPIOCR, gpiocr); 287#endif 288 289 /* 290 * Create GPIO pin groups 291 */ 292 aprint_normal_dev(self, "%zu input pins, %zu output pins\n", 293 ipins, opins); 294 295 if (inmask) 296 pq3gpio_group_create(self, bst, bsh, GPINDR, inmask, GPIO_PIN_INPUT); 297 if (outmask) 298 pq3gpio_group_create(self, bst, bsh, GPOUTDR, outmask, GPIO_PIN_OUTPUT); 299} 300#endif /* MPC8548 */ 301 302#ifdef P2020 303static void 304pq3gpio_p20x0_attach(device_t self, bus_space_tag_t bst, 305 bus_space_handle_t bsh, u_int svr) 306{ 307 static const uint32_t gpio2pmuxcr_map[][2] = { 308 { __BIT(8), PMUXCR_SDHC_CD }, 309 { __BIT(9), PMUXCR_SDHC_WP }, 310 /* 311 * These are really two bits but the low bit MBZ so we ignore 312 * it. 313 */ 314 { __BIT(10), PMUXCR_TSEC3_TS }, 315 { __BIT(11), PMUXCR_TSEC3_TS }, 316 }; 317 318 uint32_t pinmask = 0xffff0000; /* assume all bits are valid */ 319 size_t pincnt = 16; 320 const uint32_t pmuxcr = bus_space_read_4(bst, bsh, PMUXCR); 321 for (size_t i = 0; i < __arraycount(gpio2pmuxcr_map); i++) { 322 if ((pmuxcr & gpio2pmuxcr_map[i][1]) == 0) { 323 pinmask &= ~gpio2pmuxcr_map[i][0]; 324 pincnt--; 325 } 326 } 327 328 /* 329 * Create GPIO pin groups 330 */ 331 aprint_normal_dev(self, "%zu input/output pins\n", 332 pincnt); 333 pq3gpio_group_create(self, bst, bsh, GPDAT, pinmask, 334 GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); 335} 336#endif /* P2020 */ 337 338static const struct { 339 uint16_t svr; 340 void (*attach)(device_t, bus_space_tag_t, bus_space_handle_t, u_int); 341} pq3gpio_svrs[] = { 342#ifdef MPC8548 343 { SVR_MPC8548v2 >> 16, pq3gpio_mpc8548_attach }, 344#endif 345#ifdef MPC8555 346 { SVR_MPC8555v1 >> 16, pq3gpio_mpc8548_attach }, 347#endif 348#ifdef MPC8544 349 { SVR_MPC8544v1 >> 16, pq3gpio_mpc8544_attach }, 350#endif 351#ifdef MPC8536 352 { SVR_MPC8536v1 >> 16, pq3gpio_mpc8536_attach }, 353#endif 354#ifdef P2020 355 { SVR_P2020v2 >> 16, pq3gpio_p20x0_attach }, 356#endif 357}; 358 359void 360pq3gpio_attach(device_t parent, device_t self, void *aux) 361{ 362 struct mainbus_attach_args * const ma = aux; 363 bus_space_tag_t bst = ma->ma_memt; 364 bus_space_handle_t bsh; 365 int error; 366 367 error = bus_space_map(bst, GLOBAL_BASE, GLOBAL_SIZE, 0, &bsh); 368 if (error) { 369 aprint_error_dev(self, 370 "can't map global registers for gpio: %d\n", 371 error); 372 return; 373 } 374 375 const uint16_t svr = e500_get_svr(); 376 for (u_int i = 0; i < __arraycount(pq3gpio_svrs); i++) { 377 if (pq3gpio_svrs[i].svr == svr) { 378 (*pq3gpio_svrs[i].attach)(self, bst, bsh, svr); 379 return; 380 } 381 } 382 aprint_normal_dev(self, 383 "0 input groups, 0 output groups (unknown svr %#x)\n", 384 svr); 385} 386