1 /* kernel headers */ 2 #include <minix/syslib.h> 3 #include <minix/drvlib.h> 4 #include <minix/log.h> 5 #include <minix/mmio.h> 6 #include <minix/gpio.h> 7 #include <minix/clkconf.h> 8 #include <minix/type.h> 9 #include <minix/board.h> 10 11 /* system headers */ 12 #include <sys/mman.h> 13 #include <sys/types.h> 14 15 /* usr headers */ 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <stdarg.h> 19 #include <string.h> 20 #include <errno.h> 21 #include <assert.h> 22 23 /* local headers */ 24 #include "gpio_omap.h" 25 26 /* used for logging */ 27 static struct log log = { 28 .name = "gpio_omap", 29 .log_level = LEVEL_INFO, 30 .log_func = default_log 31 }; 32 33 struct gpio_driver 34 { 35 /* request access to a gpio */ 36 int (*claim) (char *owner, int nr, struct gpio ** gpio); 37 38 /* Configure the GPIO for a certain purpose */ 39 int (*pin_mode) (struct gpio * gpio, int mode); 40 41 /* Set the value for a GPIO */ 42 int (*set) (struct gpio * gpio, int value); 43 44 /* Read the current value of the GPIO */ 45 int (*read) (struct gpio * gpio, int *value); 46 47 /* Read and clear the value interrupt value of the GPIO */ 48 int (*intr_read) (struct gpio * gpio, int *value); 49 50 /* Interrupt hook */ 51 int (*message_hook) (message * m); 52 }; 53 54 static struct gpio_driver drv; 55 56 struct omap_gpio_bank 57 { 58 const char *name; 59 uint32_t register_address; 60 uint32_t irq_nr; /* irq number */ 61 uint32_t base_address; 62 int32_t disabled; 63 int irq_id; /* original hook id??? */ 64 int irq_hook_id; /* hook id */ 65 uint32_t inter_values; /* values when the interrupt was called */ 66 }; 67 68 static struct omap_gpio_bank *omap_gpio_banks; 69 70 static struct omap_gpio_bank am335x_gpio_banks[] = { 71 { 72 .name = "GPIO0", 73 .register_address = AM335X_GPIO0_BASE, 74 .irq_nr = AM335X_GPIO0A_IRQ, 75 .base_address = 0, 76 .disabled = 0, 77 .irq_id = AM335X_GPIO0A_IRQ_HOOK_ID, 78 .irq_hook_id = AM335X_GPIO0A_IRQ_HOOK_ID, 79 80 }, 81 { 82 .name = "GPIO1", 83 .register_address = AM335X_GPIO1_BASE, 84 .irq_nr = AM335X_GPIO1A_IRQ, 85 .base_address = 0, 86 .disabled = 0, 87 .irq_id = AM335X_GPIO1A_IRQ_HOOK_ID, 88 .irq_hook_id = AM335X_GPIO1A_IRQ_HOOK_ID, 89 90 }, 91 { 92 .name = "GPIO2", 93 .register_address = AM335X_GPIO2_BASE, 94 .irq_nr = AM335X_GPIO2A_IRQ, 95 .base_address = 0, 96 .disabled = 0, 97 .irq_id = AM335X_GPIO2A_IRQ_HOOK_ID, 98 .irq_hook_id = AM335X_GPIO2A_IRQ_HOOK_ID, 99 100 }, 101 { 102 .name = "GPIO3", 103 .register_address = AM335X_GPIO3_BASE, 104 .irq_nr = AM335X_GPIO3A_IRQ, 105 .base_address = 0, 106 .disabled = 0, 107 .irq_id = AM335X_GPIO3A_IRQ_HOOK_ID, 108 .irq_hook_id = AM335X_GPIO3A_IRQ_HOOK_ID, 109 110 }, 111 {NULL, 0, 0, 0, 0, 0, 0, 0 } 112 }; 113 114 static struct omap_gpio_bank dm37xx_gpio_banks[] = { 115 { 116 .name = "GPIO1", 117 .register_address = DM37XX_GPIO1_BASE, 118 .irq_nr = DM37XX_GPIO1_IRQ, 119 .base_address = 0, 120 .disabled = 0, 121 .irq_id = DM37XX_GPIO1_IRQ_HOOK_ID, 122 .irq_hook_id = DM37XX_GPIO1_IRQ_HOOK_ID, 123 }, 124 { 125 .name = "GPIO2", 126 .register_address = DM37XX_GPIO2_BASE, 127 .irq_nr = DM37XX_GPIO2_IRQ, 128 .base_address = 0, 129 .disabled = 0, 130 .irq_id = DM37XX_GPIO2_IRQ_HOOK_ID, 131 .irq_hook_id = DM37XX_GPIO2_IRQ_HOOK_ID, 132 }, 133 { 134 .name = "GPIO3", 135 .register_address = DM37XX_GPIO3_BASE, 136 .irq_nr = DM37XX_GPIO3_IRQ, 137 .base_address = 0, 138 .disabled = 0, 139 .irq_id = DM37XX_GPIO3_IRQ_HOOK_ID, 140 .irq_hook_id = DM37XX_GPIO3_IRQ_HOOK_ID, 141 }, 142 { 143 .name = "GPIO4", 144 .register_address = DM37XX_GPIO4_BASE, 145 .irq_nr = DM37XX_GPIO4_IRQ, 146 .base_address = 0, 147 .disabled = 0, 148 .irq_id = DM37XX_GPIO4_IRQ_HOOK_ID, 149 .irq_hook_id = DM37XX_GPIO4_IRQ_HOOK_ID, 150 }, 151 { 152 .name = "GPIO5", 153 .register_address = DM37XX_GPIO5_BASE, 154 .irq_nr = DM37XX_GPIO5_IRQ, 155 .base_address = 0, 156 .disabled = 0, 157 .irq_id = DM37XX_GPIO5_IRQ_HOOK_ID, 158 .irq_hook_id = DM37XX_GPIO5_IRQ_HOOK_ID, 159 }, 160 { 161 .name = "GPIO6", 162 .register_address = DM37XX_GPIO6_BASE, 163 .irq_nr = DM37XX_GPIO6_IRQ, 164 .base_address = 0, 165 .disabled = 0, 166 .irq_id = DM37XX_GPIO6_IRQ_HOOK_ID, 167 .irq_hook_id = DM37XX_GPIO6_IRQ_HOOK_ID, 168 }, 169 {NULL, 0, 0, 0, 0, 0, 0, 0 } 170 }; 171 172 static int nbanks; /* number of banks */ 173 174 /* 175 * Defines the set of registers. There is a lot of commonality between the 176 * AM335X and DM37XX gpio registers. To avoid ifdefs everywhere, we define 177 * a central register set and only use ifdefs where they differ. 178 */ 179 typedef struct gpio_omap_registers { 180 vir_bytes REVISION; 181 vir_bytes IRQENABLE; 182 vir_bytes IRQSTATUS; 183 vir_bytes DATAOUT; 184 vir_bytes DATAIN; 185 vir_bytes OE; 186 vir_bytes RISINGDETECT; 187 vir_bytes FALLINGDETECT; 188 vir_bytes CLEARDATAOUT; 189 vir_bytes SETDATAOUT; 190 } gpio_omap_regs_t; 191 192 /* Define the registers for each chip */ 193 194 gpio_omap_regs_t gpio_omap_dm37xx = { 195 .REVISION = DM37XX_GPIO_REVISION, 196 .IRQENABLE = DM37XX_GPIO_IRQENABLE1, 197 .IRQSTATUS = DM37XX_GPIO_IRQSTATUS1, 198 .DATAOUT = DM37XX_GPIO_DATAOUT, 199 .DATAIN = DM37XX_GPIO_DATAIN, 200 .OE = DM37XX_GPIO_OE, 201 .RISINGDETECT = DM37XX_GPIO_RISINGDETECT1, 202 .FALLINGDETECT = DM37XX_GPIO_FALLINGDETECT1, 203 .CLEARDATAOUT = DM37XX_GPIO_CLEARDATAOUT, 204 .SETDATAOUT = DM37XX_GPIO_SETDATAOUT 205 }; 206 207 gpio_omap_regs_t gpio_omap_am335x = { 208 .REVISION = AM335X_GPIO_REVISION, 209 .IRQENABLE = AM335X_GPIO_IRQSTATUS_SET_0, 210 .IRQSTATUS = AM335X_GPIO_IRQSTATUS_0, 211 .DATAOUT = AM335X_GPIO_DATAOUT, 212 .DATAIN = AM335X_GPIO_DATAIN, 213 .OE = AM335X_GPIO_OE, 214 .RISINGDETECT = AM335X_GPIO_RISINGDETECT, 215 .FALLINGDETECT = AM335X_GPIO_FALLINGDETECT, 216 .CLEARDATAOUT = AM335X_GPIO_CLEARDATAOUT, 217 .SETDATAOUT = AM335X_GPIO_SETDATAOUT 218 }; 219 220 static gpio_omap_regs_t *regs; 221 222 223 static struct omap_gpio_bank * 224 omap_gpio_bank_get(int gpio_nr) 225 { 226 struct omap_gpio_bank *bank; 227 assert(gpio_nr >= 0 && gpio_nr <= 32 * nbanks); 228 bank = &omap_gpio_banks[gpio_nr / 32]; 229 return bank; 230 } 231 232 static int 233 omap_gpio_claim(char *owner, int nr, struct gpio **gpio) 234 { 235 log_trace(&log, "%s s claiming %d\n", owner, nr); 236 237 if (nr < 0 && nr >= 32 * nbanks) { 238 log_warn(&log, "%s is claiming unknown GPIO number %d\n", 239 owner, nr); 240 return EINVAL; 241 } 242 243 if (omap_gpio_bank_get(nr)->disabled == 1) { 244 log_warn(&log, "%s is claiming GPIO %d from disabled bank\n", 245 owner, nr); 246 return EINVAL; 247 } 248 249 struct gpio *tmp = malloc(sizeof(struct gpio)); 250 memset(tmp, 0, sizeof(*tmp)); 251 252 tmp->nr = nr; 253 *gpio = tmp; 254 return OK; 255 } 256 257 static int 258 omap_gpio_pin_mode(struct gpio *gpio, int mode) 259 { 260 struct omap_gpio_bank *bank; 261 assert(gpio != NULL); 262 gpio->mode = mode; 263 264 bank = omap_gpio_bank_get(gpio->nr); 265 log_debug(&log, 266 "pin mode bank %s, base address 0x%x -> register address (0x%x,0x%x,0x%x)\n", 267 bank->name, bank->base_address, bank->register_address, regs->OE, 268 bank->register_address + regs->OE); 269 270 if (mode == GPIO_MODE_OUTPUT) { 271 set32(bank->base_address + regs->OE, BIT(gpio->nr % 32), 0); 272 } else { 273 set32(bank->base_address + regs->FALLINGDETECT, 274 BIT(gpio->nr % 32), 0xffffffff); 275 set32(bank->base_address + regs->IRQENABLE, BIT(gpio->nr % 32), 276 0xffffffff); 277 set32(bank->base_address + regs->OE, BIT(gpio->nr % 32), 278 0xffffffff); 279 } 280 return 0; 281 } 282 283 static int 284 omap_gpio_set(struct gpio *gpio, int value) 285 { 286 struct omap_gpio_bank *bank; 287 assert(gpio != NULL); 288 assert(gpio->nr >= 0 && gpio->nr <= 32 * nbanks); 289 290 bank = omap_gpio_bank_get(gpio->nr); 291 if (value == 1) { 292 write32(bank->base_address + regs->SETDATAOUT, 293 BIT(gpio->nr % 32)); 294 } else { 295 write32(bank->base_address + regs->CLEARDATAOUT, 296 BIT(gpio->nr % 32)); 297 } 298 return OK; 299 } 300 301 static int 302 omap_gpio_read(struct gpio *gpio, int *value) 303 { 304 struct omap_gpio_bank *bank; 305 assert(gpio != NULL); 306 assert(gpio->nr >= 0 && gpio->nr <= 32 * nbanks); 307 308 bank = omap_gpio_bank_get(gpio->nr); 309 log_trace(&log, "mode=%d OU/IN 0x%08x 0x%08x\n", gpio->mode, 310 read32(bank->base_address + regs->DATAIN), 311 read32(bank->base_address + regs->DATAOUT)); 312 313 if (gpio->mode == GPIO_MODE_INPUT) { 314 *value = 315 (read32(bank->base_address + 316 regs->DATAIN) >> (gpio->nr % 32)) & 0x1; 317 } else { 318 *value = 319 (read32(bank->base_address + 320 regs->DATAOUT) >> (gpio->nr % 32)) & 0x1; 321 } 322 323 return OK; 324 } 325 326 static int 327 omap_gpio_intr_read(struct gpio *gpio, int *value) 328 { 329 struct omap_gpio_bank *bank; 330 assert(gpio != NULL); 331 assert(gpio->nr >= 0 && gpio->nr <= 32 * nbanks); 332 333 bank = omap_gpio_bank_get(gpio->nr); 334 /* TODO: check if interrupt where enabled?? */ 335 336 *value = (bank->inter_values >> (gpio->nr % 32)) & 0x1; 337 /* clear the data */ 338 bank->inter_values &= ~(1 << (gpio->nr % 32)); 339 340 return OK; 341 } 342 343 static int 344 omap_message_hook(message * m) 345 { 346 unsigned long irq_set, i; 347 struct omap_gpio_bank *bank; 348 349 switch (_ENDPOINT_P(m->m_source)) { 350 case HARDWARE: 351 /* Hardware interrupt return a "set" if pending interrupts */ 352 irq_set = m->m_notify.interrupts; 353 log_debug(&log, "HW message 0X%08llx\n", m->m_notify.interrupts); 354 bank = &omap_gpio_banks[0]; 355 for (i = 0; omap_gpio_banks[i].name != NULL; i++) { 356 bank = &omap_gpio_banks[i]; 357 358 if (irq_set & (1 << (bank->irq_id))) { 359 log_trace(&log, "Interrupt for bank %s\n", 360 bank->name); 361 bank->inter_values |= 362 read32(bank->base_address + 363 regs->IRQSTATUS); 364 /* clear the interrupts */ 365 write32(bank->base_address + regs->IRQSTATUS, 366 0xffffffff); 367 if (sys_irqenable(&bank->irq_hook_id) != OK) { 368 log_warn(&log, 369 "Failed to enable irq for bank %s\n", 370 bank->name); 371 } 372 } 373 } 374 return OK; 375 default: 376 log_debug(&log, "Unknown message\n"); 377 break; 378 } 379 return OK; 380 } 381 382 static int revision_matches(u32_t board_id,u32_t rev) { 383 /* figures out if the collected resition matches the one expected 384 * from the board */ 385 if (BOARD_IS_BBXM(board_id)){ 386 if( 387 DM37XX_GPIO_REVISION_MAJOR(rev) != 2 388 || DM37XX_GPIO_REVISION_MINOR(rev) != 5 389 ) { 390 return 0; 391 } 392 } else if (BOARD_IS_BB(board_id)){ 393 if ( 394 AM335X_GPIO_REVISION_MAJOR(rev) != 0 395 || AM335X_GPIO_REVISION_MINOR(rev) != 1 396 ) { 397 return 0; 398 } 399 } 400 return 1; 401 } 402 403 static int 404 omap_gpio_init(struct gpio_driver *gpdrv) 405 { 406 u32_t revision; 407 int i; 408 struct minix_mem_range mr; 409 struct omap_gpio_bank *bank; 410 struct machine machine; 411 sys_getmachine(&machine); 412 413 nbanks =0; 414 omap_gpio_banks = NULL; 415 if (BOARD_IS_BBXM(machine.board_id)){ 416 omap_gpio_banks = dm37xx_gpio_banks; 417 regs = &gpio_omap_dm37xx; 418 } else if (BOARD_IS_BB(machine.board_id)){ 419 omap_gpio_banks = am335x_gpio_banks; 420 regs = &gpio_omap_am335x; 421 } 422 423 bank = &omap_gpio_banks[0]; 424 for (i = 0; omap_gpio_banks[i].name != NULL; i++) { 425 nbanks++; 426 bank = &omap_gpio_banks[i]; 427 mr.mr_base = bank->register_address; 428 mr.mr_limit = bank->register_address + 0x400; 429 430 if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) { 431 log_warn(&log, 432 "Unable to request permission to map memory\n"); 433 return EPERM; /* fixme */ 434 } 435 436 /* Set the base address to use */ 437 bank->base_address = 438 (uint32_t) vm_map_phys(SELF, 439 (void *) bank->register_address, 0x400); 440 441 if (bank->base_address == (uint32_t) MAP_FAILED) { 442 log_warn(&log, "Unable to map GPIO memory\n"); 443 return EPERM; /* fixme */ 444 } 445 446 revision = read32(bank->base_address + regs->REVISION); 447 /* test if we can access it */ 448 if (! revision_matches(machine.board_id,revision)) { 449 log_warn(&log, 450 "Failed to read the revision of GPIO bank %s.. disabling\n", 451 bank->name); 452 log_warn(&log, "Got 0x%x\n", revision); 453 bank->disabled = 1; 454 } else { 455 bank->disabled = 0; 456 } 457 458 if (sys_irqsetpolicy(bank->irq_nr, 0, 459 &bank->irq_hook_id) != OK) { 460 log_warn(&log, 461 "GPIO: couldn't set IRQ policy for bank %s\n", 462 bank->name); 463 continue; 464 }; 465 if (bank->irq_id != bank->irq_hook_id) { 466 log_debug(&log, "requested id %d but got id %d\n", 467 bank->irq_id, bank->irq_hook_id); 468 } 469 if (sys_irqenable(&bank->irq_hook_id) != OK) { 470 log_warn(&log, 471 "GPIO: couldn't enable interrupt for %s\n", 472 bank->name); 473 }; 474 log_trace(&log, "bank %s mapped on 0x%x with irq hook id %d\n", 475 bank->name, bank->base_address, bank->irq_hook_id); 476 477 }; 478 479 clkconf_init(); 480 481 if (BOARD_IS_BBXM(machine.board_id)){ 482 /* enable the interface and functional clock on GPIO bank 1 , this only 483 applies to the Beagelboard XM */ 484 clkconf_set(CM_FCLKEN_WKUP, BIT(3), 0xffffffff); 485 clkconf_set(CM_ICLKEN_WKUP, BIT(3), 0xffffffff); 486 } 487 clkconf_release(); 488 489 490 gpdrv->claim = omap_gpio_claim; 491 gpdrv->pin_mode = omap_gpio_pin_mode; 492 gpdrv->set = omap_gpio_set; 493 gpdrv->read = omap_gpio_read; 494 gpdrv->intr_read = omap_gpio_intr_read; 495 gpdrv->message_hook = omap_message_hook; 496 return 0; 497 } 498 499 int 500 gpio_init() 501 { 502 return omap_gpio_init(&drv); 503 } 504 505 /* request access to a gpio */ 506 int 507 gpio_claim(char *owner, int nr, struct gpio **gpio) 508 { 509 return drv.claim(owner, nr, gpio); 510 } 511 512 /* Configure the GPIO for a certain purpose */ 513 int 514 gpio_pin_mode(struct gpio *gpio, int mode) 515 { 516 return drv.pin_mode(gpio, mode); 517 } 518 519 /* Set the value for a GPIO */ 520 int 521 gpio_set(struct gpio *gpio, int value) 522 { 523 return drv.set(gpio, value); 524 } 525 526 /* Read the current value of the GPIO */ 527 int 528 gpio_read(struct gpio *gpio, int *value) 529 { 530 return drv.read(gpio, value); 531 } 532 533 /* Read and clear the value interrupt value of the GPIO */ 534 int 535 gpio_intr_read(struct gpio *gpio, int *value) 536 { 537 return drv.intr_read(gpio, value); 538 } 539 540 /* Interrupt hook */ 541 int 542 gpio_intr_message(message * m) 543 { 544 return drv.message_hook(m); 545 } 546 547 int 548 gpio_release(void) 549 { 550 return OK; 551 } 552