1 /* 2 * GPIO driver for Ingenic JZ4730. 3 * (See below for additional copyright and licensing notices.) 4 * 5 * Copyright (C) 2017, 2018, 2023, 2024 Paul Boddie <paul@boddie.org.uk> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 of 10 * the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 * Boston, MA 02110-1301, USA 21 * 22 * 23 * Subject to other copyrights, being derived from the bcm2835.cc and 24 * omap.cc GPIO driver implementations. 25 * 26 * This file is part of TUD:OS and distributed under the terms of the 27 * GNU General Public License 2. 28 * Please see the COPYING-GPL-2 file for details. 29 */ 30 31 #include <l4/sys/icu.h> 32 #include <l4/util/util.h> 33 #include <l4/devices/hw_mmio_register_block.h> 34 35 #include "gpio-jz4730.h" 36 37 // GPIO register offsets (x in A..D). 38 39 enum Regs 40 { 41 Port_data = 0x000, // PxGPDR 42 Port_direction = 0x004, // PxGPDIR 43 Pull_enable = 0x00c, // PxGPPUR 44 Port_function_lower = 0x010, // PxGPALR 45 Port_function_upper = 0x014, // PxGPAUR 46 Irq_detect_lower = 0x018, // PxGPDLR 47 Irq_detect_upper = 0x01c, // PxGPDUR 48 Irq_enable = 0x020, // PxGPIER 49 Irq_mask = 0x024, // PxGPIM 50 Irq_flag = 0x028, // PxGPFR 51 }; 52 53 54 55 // JZ4730 pull-up/down configuration. 56 57 static struct gpio_port gpio_ports[] = { 58 {0x3fa32e0f, 0x000001f0}, 59 {0xf2000fff, 0x0dfff000}, 60 {0xffffffff, 0x00000000}, 61 {0xffffffff, 0x00000000}, 62 }; 63 64 65 66 // Select the appropriate register and pin where two bits are assigned per pin, 67 // thus requiring two 32-bit registers to hold the configuration of 32 pins. 68 69 static 70 uint32_t 71 _select_bank_for_pin(uint32_t reg_upper, uint32_t reg_lower, uint8_t pin, uint8_t *pin_out) 72 { 73 if (pin < 16) 74 { 75 *pin_out = pin; 76 return reg_lower; 77 } 78 else 79 { 80 *pin_out = pin - 16; 81 return reg_upper; 82 } 83 } 84 85 // IRQ control for each GPIO pin. 86 87 Gpio_jz4730_irq_pin::Gpio_jz4730_irq_pin(unsigned pin, Hw::Register_block<32> const ®s) 88 : _pin(pin), _regs(regs) 89 {} 90 91 void 92 Gpio_jz4730_irq_pin::write_reg_pin(unsigned reg) 93 { 94 // Write the pin bit to the register, setting or clearing the pin 95 // depending on the register chosen. 96 97 _regs[reg] = _pin_bit(_pin); 98 } 99 100 void 101 Gpio_jz4730_irq_pin::clear_reg_pin(unsigned reg) 102 { 103 // Clear the pin bit in the register. 104 105 _regs[reg] = _regs[reg] & ~(_pin_bit(_pin)); 106 } 107 108 void 109 Gpio_jz4730_irq_pin::set_reg_pin(unsigned reg) 110 { 111 // Set the pin bit in the register. 112 113 _regs[reg] = _regs[reg] | _pin_bit(_pin); 114 } 115 116 // Clear the pin bits in the appropriate register. 117 118 void 119 Gpio_jz4730_irq_pin::clear_reg_pins(uint32_t reg_upper, uint32_t reg_lower) 120 { 121 uint8_t pin_out; 122 uint32_t reg = _select_bank_for_pin(reg_upper, reg_lower, _pin, &pin_out); 123 124 _regs[reg] = _regs[reg] & ~(3 << (pin_out << 1)); 125 } 126 127 // Clear and set the given value in the pin bits of the appropriate register. 128 129 void 130 Gpio_jz4730_irq_pin::set_reg_pins(uint32_t reg_upper, uint32_t reg_lower, uint8_t value) 131 { 132 uint8_t pin_out; 133 uint32_t reg = _select_bank_for_pin(reg_upper, reg_lower, _pin, &pin_out); 134 135 _regs[reg] = (_regs[reg] & ~(3 << (pin_out << 1))) | (value << (pin_out << 1)); 136 } 137 138 void Gpio_jz4730_irq_pin::do_mask() 139 { 140 // Set the interrupt bit in the PxGPIER register. 141 142 /* NOTE: This should use the Irq_mask/PxGPIM register, with the enable 143 register actually setting IRQ mode. */ 144 145 clear_reg_pin(Irq_enable); 146 } 147 148 void Gpio_jz4730_irq_pin::do_unmask() 149 { 150 // Set the interrupt bit in the PxGPIER register, first also clearing the 151 // flag bit in the PxGPFR register to allow interrupts to be delivered. 152 153 /* NOTE: This should use the Irq_mask/PxGPIM register, with the enable 154 register actually setting IRQ mode. */ 155 156 clear_reg_pin(Irq_flag); 157 set_reg_pin(Irq_enable); 158 } 159 160 bool Gpio_jz4730_irq_pin::do_set_mode(unsigned mode) 161 { 162 // Standard comment found for this method: 163 // this operation touches multiple mmio registers and is thus 164 // not atomic, that's why we first mask the IRQ and if it was 165 // enabled we unmask it after we have changed the mode 166 167 if (enabled()) 168 do_mask(); 169 170 // Do the PxGPDUR/PxGPDLR configuration. 171 172 switch(mode) 173 { 174 case L4_IRQ_F_LEVEL_HIGH: 175 set_reg_pins(Irq_detect_upper, Irq_detect_lower, 1); 176 break; 177 case L4_IRQ_F_LEVEL_LOW: 178 set_reg_pins(Irq_detect_upper, Irq_detect_lower, 0); 179 break; 180 case L4_IRQ_F_POS_EDGE: 181 set_reg_pins(Irq_detect_upper, Irq_detect_lower, 3); 182 break; 183 case L4_IRQ_F_NEG_EDGE: 184 set_reg_pins(Irq_detect_upper, Irq_detect_lower, 2); 185 break; 186 187 default: 188 return false; 189 } 190 191 // Do the PxGPDIR, PxGPAUR/PxGPALR configuration. 192 193 clear_reg_pin(Port_direction); 194 clear_reg_pins(Port_function_upper, Port_function_lower); 195 196 if (enabled()) 197 do_unmask(); 198 199 return true; 200 } 201 202 int Gpio_jz4730_irq_pin::clear() 203 { 204 // Obtain the flag status for the pin, clearing it if set. 205 206 l4_uint32_t e = _regs[Irq_flag] & (1UL << _pin); 207 if (e) 208 clear_reg_pin(Irq_flag); 209 210 return (e >> _pin); 211 } 212 213 bool Gpio_jz4730_irq_pin::enabled() 214 { 215 return true; 216 } 217 218 219 220 // Return two bitmaps for the given bitmap and value. 221 222 static 223 void 224 _get_bitmaps(uint32_t bitmap, uint8_t value, uint32_t *upper, uint32_t *lower) 225 { 226 uint32_t mask = 0x80000000; 227 228 *upper = 0; *lower = 0; 229 230 while (mask != 0x8000) 231 { 232 *upper = (*upper << 2) | (bitmap & mask ? value : 0); 233 mask >>= 1; 234 } 235 236 while (mask != 0) 237 { 238 *lower = (*lower << 2) | (bitmap & mask ? value : 0); 239 mask >>= 1; 240 } 241 } 242 243 244 245 // Initialise the GPIO controller. 246 247 Gpio_jz4730_chip::Gpio_jz4730_chip(l4_addr_t start, uint8_t port_number) 248 : Hw::Gpio_chip(32) 249 { 250 _start = start + port_number * 0x30; 251 _regs = new Hw::Mmio_register_block<32>(_start); 252 _pull_config = &gpio_ports[port_number]; 253 } 254 255 // Return the value of a pin. 256 257 int 258 Gpio_jz4730_chip::get(unsigned pin) 259 { 260 if (pin >= _nr_pins) 261 throw -L4_EINVAL; 262 263 l4_uint32_t val = _regs[Port_data]; 264 return (val >> _pin_shift(pin)) & 1; 265 } 266 267 // Return multiple pin values. 268 269 unsigned 270 Gpio_jz4730_chip::multi_get(unsigned offset) 271 { 272 _reg_offset_check(offset); 273 return _regs[Port_data]; 274 } 275 276 // Set the value of a pin. 277 278 void 279 Gpio_jz4730_chip::set(unsigned pin, int value) 280 { 281 if (pin >= _nr_pins) 282 throw -L4_EINVAL; 283 284 if (value) 285 _regs[Port_data] = _regs[Port_data] | _pin_bit(pin); 286 else 287 _regs[Port_data] = _regs[Port_data] & ~_pin_bit(pin); 288 } 289 290 // Set multiple pin values. 291 292 void 293 Gpio_jz4730_chip::multi_set(Pin_slice const &mask, unsigned data) 294 { 295 _reg_offset_check(mask.offset); 296 _regs[Port_data] = (_regs[Port_data] & ~(mask.mask)) | data; 297 } 298 299 // Set a pin up with the given mode and value (if appropriate). 300 301 void 302 Gpio_jz4730_chip::setup(unsigned pin, unsigned mode, int value) 303 { 304 if (pin >= _nr_pins) 305 throw -L4_EINVAL; 306 307 config(pin, mode); 308 309 if (mode == Output) 310 set(pin, value); 311 } 312 313 // Configuration of a pin using the generic input/output/IRQ mode. 314 315 void 316 Gpio_jz4730_chip::config(unsigned pin, unsigned mode) 317 { 318 _config(_pin_bit(pin), mode); 319 } 320 321 void 322 Gpio_jz4730_chip::_config(unsigned bitmap, unsigned mode) 323 { 324 uint32_t upper_mask, lower_mask; 325 326 switch (mode) 327 { 328 case Input: 329 case Irq: 330 // Clear the direction flags. 331 _regs[Port_direction] = _regs[Port_direction] & ~bitmap; 332 333 // Clear the port function for the bits. 334 _get_bitmaps(bitmap, 3, &upper_mask, &lower_mask); 335 _regs[Port_function_upper] = (_regs[Port_function_upper] & ~upper_mask); 336 _regs[Port_function_lower] = (_regs[Port_function_lower] & ~lower_mask); 337 break; 338 339 case Output: 340 // Set the direction flags. 341 _regs[Port_direction] = _regs[Port_direction] | bitmap; 342 343 // Clear the port function for the bits. 344 _get_bitmaps(bitmap, 3, &upper_mask, &lower_mask); 345 _regs[Port_function_upper] = (_regs[Port_function_upper] & ~upper_mask); 346 _regs[Port_function_lower] = (_regs[Port_function_lower] & ~lower_mask); 347 break; 348 349 default: 350 break; 351 } 352 } 353 354 // Pull-up configuration for a pin. 355 356 void 357 Gpio_jz4730_chip::config_pull(unsigned pin, unsigned mode) 358 { 359 if (pin >= _nr_pins) 360 throw -L4_EINVAL; 361 362 _config_pull(_pin_bit(pin), mode); 363 } 364 365 void 366 Gpio_jz4730_chip::_config_pull(unsigned bitmap, unsigned mode) 367 { 368 switch (mode) 369 { 370 case Pull_none: 371 _regs[Pull_enable] = _regs[Pull_enable] & ~bitmap; 372 break; 373 case Pull_down: 374 _regs[Pull_enable] = _regs[Pull_enable] | (bitmap & _pull_config->pull_downs); 375 break; 376 case Pull_up: 377 _regs[Pull_enable] = _regs[Pull_enable] | (bitmap & _pull_config->pull_ups); 378 break; 379 default: 380 // Invalid pull-up/down mode for pin. 381 throw -L4_EINVAL; 382 } 383 } 384 385 // Pin function configuration. 386 387 void 388 Gpio_jz4730_chip::config_pad(unsigned pin, unsigned func, unsigned value) 389 { 390 if (pin >= _nr_pins) 391 throw -L4_EINVAL; 392 393 _config_pad(_pin_bit(pin), func, value); 394 } 395 396 void 397 Gpio_jz4730_chip::_config_pad(unsigned bitmap, unsigned func, unsigned value) 398 { 399 uint32_t upper_mask = 0, lower_mask = 0, upper = 0, lower = 0; 400 401 if (value > 3) 402 throw -L4_EINVAL; 403 404 switch (func) 405 { 406 case Hw::Gpio_chip::Function_alt: 407 _get_bitmaps(bitmap, value, &upper, &lower); 408 _get_bitmaps(bitmap, 3, &upper_mask, &lower_mask); 409 _regs[Port_function_upper] = (_regs[Port_function_upper] & ~upper_mask) | upper; 410 _regs[Port_function_lower] = (_regs[Port_function_lower] & ~lower_mask) | lower; 411 break; 412 413 case Hw::Gpio_chip::Function_gpio: 414 _get_bitmaps(bitmap, 3, &upper_mask, &lower_mask); 415 _regs[Port_function_upper] = _regs[Port_function_upper] & ~upper_mask; 416 _regs[Port_function_lower] = _regs[Port_function_lower] & ~lower_mask; 417 break; 418 419 default: 420 throw -L4_EINVAL; 421 } 422 } 423 424 // Obtain a pin's configuration from a register in the supplied value. 425 426 void 427 Gpio_jz4730_chip::config_get(unsigned pin, unsigned reg, unsigned *value) 428 { 429 if (pin >= _nr_pins) 430 throw -L4_EINVAL; 431 432 *value = (_regs[reg] >> _pin_shift(pin)) & 1; 433 } 434 435 // Return function and function-specific configuration for a pin. 436 437 void 438 Gpio_jz4730_chip::config_pad_get(unsigned pin, unsigned *func, unsigned *value) 439 { 440 unsigned detect, direction, pin_function, interrupt; 441 442 // Get the pin function using the awkward register pairing. 443 444 _get_pin_value(pin, Port_function_upper, Port_function_lower, &pin_function); 445 446 if (pin_function) 447 { 448 *func = Hw::Gpio_chip::Function_alt; 449 *value = pin_function; 450 return; 451 } 452 453 config_get(pin, Irq_enable, &interrupt); 454 455 if (interrupt) 456 { 457 _get_pin_value(pin, Irq_detect_upper, Irq_detect_lower, &detect); 458 459 *func = Hw::Gpio_chip::Function_irq; 460 461 switch (detect) 462 { 463 case 0: *value = L4_IRQ_F_LEVEL_LOW; break; 464 case 1: *value = L4_IRQ_F_LEVEL_HIGH; break; 465 case 2: *value = L4_IRQ_F_NEG_EDGE; break; 466 default: case 3: *value = L4_IRQ_F_POS_EDGE; break; 467 } 468 return; 469 } 470 471 config_get(pin, Port_direction, &direction); 472 473 *func = Hw::Gpio_chip::Function_gpio; 474 *value = direction ? Output : Input; 475 } 476 477 void 478 Gpio_jz4730_chip::_get_pin_value(unsigned pin, uint32_t reg_upper, 479 uint32_t reg_lower, unsigned *value) 480 { 481 uint8_t pin_out; 482 483 if (pin >= _nr_pins) 484 throw -L4_EINVAL; 485 486 uint32_t reg = _select_bank_for_pin(reg_upper, reg_lower, pin, &pin_out); 487 488 *value = (_regs[reg] & (3 << (pin_out << 1))) >> (pin_out << 1); 489 } 490 491 // Obtain an IRQ abstraction for a pin. 492 493 Hw::Gpio_irq_pin * 494 Gpio_jz4730_chip::get_irq(unsigned pin) 495 { 496 if (pin >= _nr_pins) 497 throw -L4_EINVAL; 498 499 return new Gpio_jz4730_irq_pin(pin, _regs); 500 } 501 502 // Pull-up function configuration for multiple pins. 503 504 void 505 Gpio_jz4730_chip::multi_config_pull(Pin_slice const &mask, unsigned mode) 506 { 507 _config_pull(mask.mask << mask.offset, mode); 508 } 509 510 // Pin function configuration for multiple pins. 511 512 void 513 Gpio_jz4730_chip::multi_config_pad(Pin_slice const &mask, unsigned func, unsigned val) 514 { 515 _config_pad(mask.mask << mask.offset, func, val); 516 } 517 518 // Set up multiple pins with the given mode. 519 520 void 521 Gpio_jz4730_chip::multi_setup(Pin_slice const &mask, unsigned mode, unsigned outvalues) 522 { 523 _config(mask.mask << mask.offset, mode); 524 525 if (mode == Output) 526 multi_set(mask, outvalues); 527 } 528 529 Hw::Gpio_chip *jz4730_gpio_chip(l4_addr_t start, uint8_t port_number, bool shadow) 530 { 531 (void) shadow; 532 return new Gpio_jz4730_chip(start, port_number); 533 } 534 535 536 537 // C language interface functions. 538 539 void *jz4730_gpio_init(l4_addr_t start, uint8_t port_number) 540 { 541 return (void *) jz4730_gpio_chip(start, port_number, false); 542 } 543 544 void jz4730_gpio_setup(void *gpio, unsigned pin, unsigned mode, int value) 545 { 546 static_cast<Gpio_jz4730_chip *>(gpio)->setup(pin, mode, value); 547 } 548 549 void jz4730_gpio_config_pull(void *gpio, unsigned pin, unsigned mode) 550 { 551 static_cast<Gpio_jz4730_chip *>(gpio)->config_pull(pin, mode); 552 } 553 554 void jz4730_gpio_config_pad(void *gpio, unsigned pin, unsigned func, unsigned value) 555 { 556 static_cast<Gpio_jz4730_chip *>(gpio)->config_pad(pin, func, value); 557 } 558 559 void jz4730_gpio_config_get(void *gpio, unsigned pin, unsigned reg, unsigned *value) 560 { 561 static_cast<Gpio_jz4730_chip *>(gpio)->config_get(pin, reg, value); 562 } 563 564 void jz4730_gpio_config_pad_get(void *gpio, unsigned pin, unsigned *func, unsigned *value) 565 { 566 static_cast<Gpio_jz4730_chip *>(gpio)->config_pad_get(pin, func, value); 567 } 568 569 void jz4730_gpio_multi_setup(void *gpio, Pin_slice const *mask, unsigned mode, unsigned outvalues) 570 { 571 static_cast<Gpio_jz4730_chip *>(gpio)->multi_setup(*mask, mode, outvalues); 572 } 573 574 void jz4730_gpio_multi_config_pull(void *gpio, Pin_slice const *mask, unsigned mode) 575 { 576 static_cast<Gpio_jz4730_chip *>(gpio)->multi_config_pull(*mask, mode); 577 } 578 579 void jz4730_gpio_multi_config_pad(void *gpio, Pin_slice const *mask, unsigned func, unsigned value) 580 { 581 static_cast<Gpio_jz4730_chip *>(gpio)->multi_config_pad(*mask, func, value); 582 } 583 584 void jz4730_gpio_multi_set(void *gpio, Pin_slice const *mask, unsigned data) 585 { 586 static_cast<Gpio_jz4730_chip *>(gpio)->multi_set(*mask, data); 587 } 588 589 unsigned jz4730_gpio_multi_get(void *gpio, unsigned offset) 590 { 591 return static_cast<Gpio_jz4730_chip *>(gpio)->multi_get(offset); 592 } 593 594 int jz4730_gpio_get(void *gpio, unsigned pin) 595 { 596 return static_cast<Gpio_jz4730_chip *>(gpio)->get(pin); 597 } 598 599 void jz4730_gpio_set(void *gpio, unsigned pin, int value) 600 { 601 static_cast<Gpio_jz4730_chip *>(gpio)->set(pin, value); 602 } 603 604 void *jz4730_gpio_get_irq(void *gpio, unsigned pin) 605 { 606 return (void *) static_cast<Gpio_jz4730_chip *>(gpio)->get_irq(pin); 607 } 608 609 bool jz4730_gpio_irq_set_mode(void *gpio_irq, unsigned mode) 610 { 611 return static_cast<Hw::Gpio_irq_pin *>(gpio_irq)->do_set_mode(mode); 612 }