1 /* 2 * GPIO driver for Ingenic JZ4730. 3 * (See below for additional copyright and licensing notices.) 4 * 5 * (c) 2017, 2018 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_flag = 0x028, // PxGPFR 50 }; 51 52 53 54 // Select the appropriate register and pin where two bits are assigned per pin, 55 // thus requiring two 32-bit registers to hold the configuration of 32 pins. 56 57 static 58 uint32_t 59 _select_bank_for_pin(uint32_t reg_upper, uint32_t reg_lower, uint8_t pin, uint8_t *pin_out) 60 { 61 if (pin < 16) 62 { 63 *pin_out = pin; 64 return reg_lower; 65 } 66 else 67 { 68 *pin_out = pin - 16; 69 return reg_upper; 70 } 71 } 72 73 74 75 // IRQ control for each GPIO pin. 76 77 Gpio_jz4730_irq_pin::Gpio_jz4730_irq_pin(unsigned pin, Hw::Register_block<32> const ®s) 78 : _pin(pin), _regs(regs) 79 {} 80 81 void 82 Gpio_jz4730_irq_pin::write_reg_pin(unsigned reg) 83 { 84 // Write the pin bit to the register, setting or clearing the pin 85 // depending on the register chosen. 86 87 _regs[reg] = _pin_bit(_pin); 88 } 89 90 void 91 Gpio_jz4730_irq_pin::clear_reg_pin(unsigned reg) 92 { 93 // Clear the pin bit in the register. 94 95 _regs[reg] = _regs[reg] & ~(_pin_bit(_pin)); 96 } 97 98 void 99 Gpio_jz4730_irq_pin::set_reg_pin(unsigned reg) 100 { 101 // Set the pin bit in the register. 102 103 _regs[reg] = _regs[reg] | _pin_bit(_pin); 104 } 105 106 // Clear the pin bits in the appropriate register. 107 108 void 109 Gpio_jz4730_irq_pin::clear_reg_pins(uint32_t reg_upper, uint32_t reg_lower) 110 { 111 uint8_t pin_out; 112 uint32_t reg = _select_bank_for_pin(reg_upper, reg_lower, _pin, &pin_out); 113 114 _regs[reg] = _regs[reg] & ~(3 << (pin_out << 1)); 115 } 116 117 // Clear and set the given value in the pin bits of the appropriate register. 118 119 void 120 Gpio_jz4730_irq_pin::set_reg_pins(uint32_t reg_upper, uint32_t reg_lower, uint8_t value) 121 { 122 uint8_t pin_out; 123 uint32_t reg = _select_bank_for_pin(reg_upper, reg_lower, _pin, &pin_out); 124 125 _regs[reg] = (_regs[reg] & ~(3 << (pin_out << 1))) | (value << (pin_out << 1)); 126 } 127 128 void Gpio_jz4730_irq_pin::do_mask() 129 { 130 // Set the interrupt bit in the PxGPIER register. 131 132 clear_reg_pin(Irq_enable); 133 } 134 135 void Gpio_jz4730_irq_pin::do_unmask() 136 { 137 // Set the interrupt bit in the PxGPIER register, first also clearing the 138 // flag bit in the PxGPFR register to allow interrupts to be delivered. 139 140 clear_reg_pin(Irq_flag); 141 set_reg_pin(Irq_enable); 142 } 143 144 bool Gpio_jz4730_irq_pin::do_set_mode(unsigned mode) 145 { 146 // Standard comment found for this method: 147 // this operation touches multiple mmio registers and is thus 148 // not atomic, that's why we first mask the IRQ and if it was 149 // enabled we unmask it after we have changed the mode 150 151 if (enabled()) 152 do_mask(); 153 154 // Do the PxGPDUR/PxGPDLR configuration. 155 156 switch(mode) 157 { 158 case L4_IRQ_F_LEVEL_HIGH: 159 set_reg_pins(Irq_detect_upper, Irq_detect_lower, 1); 160 break; 161 case L4_IRQ_F_LEVEL_LOW: 162 set_reg_pins(Irq_detect_upper, Irq_detect_lower, 0); 163 break; 164 case L4_IRQ_F_POS_EDGE: 165 set_reg_pins(Irq_detect_upper, Irq_detect_lower, 3); 166 break; 167 case L4_IRQ_F_NEG_EDGE: 168 set_reg_pins(Irq_detect_upper, Irq_detect_lower, 2); 169 break; 170 171 default: 172 return false; 173 } 174 175 // Do the PxGPDIR, PxGPAUR/PxGPALR configuration. 176 177 clear_reg_pin(Port_direction); 178 clear_reg_pins(Port_function_upper, Port_function_lower); 179 180 if (enabled()) 181 do_unmask(); 182 183 return true; 184 } 185 186 int Gpio_jz4730_irq_pin::clear() 187 { 188 // Obtain the flag status for the pin, clearing it if set. 189 190 l4_uint32_t e = _regs[Irq_flag] & (1UL << _pin); 191 if (e) 192 clear_reg_pin(Irq_flag); 193 194 return (e >> _pin); 195 } 196 197 bool Gpio_jz4730_irq_pin::enabled() 198 { 199 return true; 200 } 201 202 203 204 // Return two bitmaps for the given bitmap and value. 205 206 static 207 void 208 _get_bitmaps(uint32_t bitmap, uint8_t value, uint32_t *upper, uint32_t *lower) 209 { 210 uint32_t mask = 0x80000000; 211 212 *upper = 0; *lower = 0; 213 214 while (mask != 0x8000) 215 { 216 *upper = (*upper << 2) | (bitmap & mask ? value : 0); 217 mask >>= 1; 218 } 219 220 while (mask != 0) 221 { 222 *lower = (*lower << 2) | (bitmap & mask ? value : 0); 223 mask >>= 1; 224 } 225 } 226 227 228 229 // Initialise the GPIO controller. 230 231 Gpio_jz4730_chip::Gpio_jz4730_chip(l4_addr_t start, l4_addr_t end, 232 unsigned nr_pins) 233 : _start(start), _end(end), 234 _nr_pins(nr_pins) 235 { 236 _regs = new Hw::Mmio_register_block<32>(_start); 237 } 238 239 // Return the value of a pin. 240 241 int 242 Gpio_jz4730_chip::get(unsigned pin) 243 { 244 if (pin >= _nr_pins) 245 throw -L4_EINVAL; 246 247 l4_uint32_t val = _regs[Port_data]; 248 return (val >> _pin_shift(pin)) & 1; 249 } 250 251 // Return multiple pin values. 252 253 unsigned 254 Gpio_jz4730_chip::multi_get(unsigned offset) 255 { 256 _reg_offset_check(offset); 257 return _regs[Port_data]; 258 } 259 260 // Set the value of a pin. 261 262 void 263 Gpio_jz4730_chip::set(unsigned pin, int value) 264 { 265 if (pin >= _nr_pins) 266 throw -L4_EINVAL; 267 268 if (value) 269 _regs[Port_data] = _regs[Port_data] | _pin_bit(pin); 270 else 271 _regs[Port_data] = _regs[Port_data] & ~_pin_bit(pin); 272 } 273 274 // Set multiple pin values. 275 276 void 277 Gpio_jz4730_chip::multi_set(Pin_slice const &mask, unsigned data) 278 { 279 _reg_offset_check(mask.offset); 280 _regs[Port_data] = (_regs[Port_data] & ~(mask.mask)) | data; 281 } 282 283 // Set a pin up with the given mode and value (if appropriate). 284 285 void 286 Gpio_jz4730_chip::setup(unsigned pin, unsigned mode, int value) 287 { 288 if (pin >= _nr_pins) 289 throw -L4_EINVAL; 290 291 config(pin, mode); 292 293 if (mode == Output) 294 set(pin, value); 295 } 296 297 // Configuration of a pin using the generic input/output/IRQ mode. 298 299 void 300 Gpio_jz4730_chip::config(unsigned pin, unsigned mode) 301 { 302 _config(_pin_bit(pin), mode); 303 } 304 305 void 306 Gpio_jz4730_chip::_config(unsigned bitmap, unsigned mode) 307 { 308 uint32_t upper_mask, lower_mask; 309 unsigned bitmap_values = bitmap; 310 311 switch (mode) 312 { 313 case Input: 314 case Irq: 315 // Clear the direction flags below. 316 bitmap_values = 0; 317 // Fall through to the next case to complete the operation. 318 319 case Output: 320 // Clear the flags if set immediately above; otherwise, set them. 321 _regs[Port_direction] = (_regs[Port_direction] & ~bitmap) | bitmap_values; 322 323 // Clear the port function for the bits. 324 _get_bitmaps(bitmap, 3, &upper_mask, &lower_mask); 325 _regs[Port_function_upper] = (_regs[Port_function_upper] & ~upper_mask); 326 _regs[Port_function_lower] = (_regs[Port_function_lower] & ~lower_mask); 327 break; 328 329 default: 330 break; 331 } 332 } 333 334 // Pull-up configuration for a pin. 335 336 void 337 Gpio_jz4730_chip::config_pull(unsigned pin, unsigned mode) 338 { 339 if (pin >= _nr_pins) 340 throw -L4_EINVAL; 341 342 _config_pull(_pin_bit(pin), mode); 343 } 344 345 void 346 Gpio_jz4730_chip::_config_pull(unsigned bitmap, unsigned mode) 347 { 348 switch (mode) 349 { 350 case Pull_none: 351 _regs[Pull_enable] = _regs[Pull_enable] & ~bitmap; 352 break; 353 case Pull_up: 354 _regs[Pull_enable] = _regs[Pull_enable] | bitmap; 355 break; 356 default: 357 // Invalid pull-up/down mode for pin. 358 throw -L4_EINVAL; 359 } 360 } 361 362 // Pin function configuration. 363 364 void 365 Gpio_jz4730_chip::config_pad(unsigned pin, unsigned func, unsigned value) 366 { 367 if (pin >= _nr_pins) 368 throw -L4_EINVAL; 369 370 _config_pad(_pin_bit(pin), func, value); 371 } 372 373 void 374 Gpio_jz4730_chip::_config_pad(unsigned bitmap, unsigned func, unsigned value) 375 { 376 uint32_t upper_mask = 0, lower_mask = 0, upper = 0, lower = 0; 377 378 if (value > 3) 379 throw -L4_EINVAL; 380 381 switch (func) 382 { 383 case Hw::Gpio_chip::Function_alt: 384 _get_bitmaps(bitmap, value, &upper, &lower); 385 // Fall through to the next case to complete the operation. 386 387 case Hw::Gpio_chip::Function_gpio: 388 _get_bitmaps(bitmap, 3, &upper_mask, &lower_mask); 389 _regs[Port_function_upper] = (_regs[Port_function_upper] & ~upper_mask) | upper; 390 _regs[Port_function_lower] = (_regs[Port_function_lower] & ~lower_mask) | lower; 391 break; 392 393 default: 394 throw -L4_EINVAL; 395 } 396 } 397 398 // Obtain a pin's configuration from a register in the supplied value. 399 400 void 401 Gpio_jz4730_chip::config_get(unsigned pin, unsigned reg, unsigned *value) 402 { 403 if (pin >= _nr_pins) 404 throw -L4_EINVAL; 405 406 *value = (_regs[reg] >> _pin_shift(pin)) & 1; 407 } 408 409 // Obtain an IRQ abstraction for a pin. 410 411 Hw::Gpio_irq_pin * 412 Gpio_jz4730_chip::get_irq(unsigned pin) 413 { 414 if (pin >= _nr_pins) 415 throw -L4_EINVAL; 416 417 return new Gpio_jz4730_irq_pin(pin, _regs); 418 } 419 420 // Pull-up function configuration for multiple pins. 421 422 void 423 Gpio_jz4730_chip::multi_config_pull(Pin_slice const &mask, unsigned mode) 424 { 425 _config_pull(mask.mask << mask.offset, mode); 426 } 427 428 // Pin function configuration for multiple pins. 429 430 void 431 Gpio_jz4730_chip::multi_config_pad(Pin_slice const &mask, unsigned func, unsigned val) 432 { 433 _config_pad(mask.mask << mask.offset, func, val); 434 } 435 436 // Set up multiple pins with the given mode. 437 438 void 439 Gpio_jz4730_chip::multi_setup(Pin_slice const &mask, unsigned mode, unsigned outvalues) 440 { 441 _config(mask.mask << mask.offset, mode); 442 443 if (mode == Output) 444 multi_set(mask, outvalues); 445 } 446 447 448 449 // C language interface functions. 450 451 void *jz4730_gpio_init(l4_addr_t start, l4_addr_t end, unsigned pins) 452 { 453 return (void *) new Gpio_jz4730_chip(start, end, pins); 454 } 455 456 void jz4730_gpio_setup(void *gpio, unsigned pin, unsigned mode, int value) 457 { 458 static_cast<Gpio_jz4730_chip *>(gpio)->setup(pin, mode, value); 459 } 460 461 void jz4730_gpio_config_pull(void *gpio, unsigned pin, unsigned mode) 462 { 463 static_cast<Gpio_jz4730_chip *>(gpio)->config_pull(pin, mode); 464 } 465 466 void jz4730_gpio_config_pad(void *gpio, unsigned pin, unsigned func, unsigned value) 467 { 468 static_cast<Gpio_jz4730_chip *>(gpio)->config_pad(pin, func, value); 469 } 470 471 void jz4730_gpio_config_get(void *gpio, unsigned pin, unsigned reg, unsigned *value) 472 { 473 static_cast<Gpio_jz4730_chip *>(gpio)->config_get(pin, reg, value); 474 } 475 476 void jz4730_gpio_multi_setup(void *gpio, Pin_slice const *mask, unsigned mode, unsigned outvalues) 477 { 478 static_cast<Gpio_jz4730_chip *>(gpio)->multi_setup(*mask, mode, outvalues); 479 } 480 481 void jz4730_gpio_multi_config_pull(void *gpio, Pin_slice const *mask, unsigned mode) 482 { 483 static_cast<Gpio_jz4730_chip *>(gpio)->multi_config_pull(*mask, mode); 484 } 485 486 void jz4730_gpio_multi_config_pad(void *gpio, Pin_slice const *mask, unsigned func, unsigned value) 487 { 488 static_cast<Gpio_jz4730_chip *>(gpio)->multi_config_pad(*mask, func, value); 489 } 490 491 void jz4730_gpio_multi_set(void *gpio, Pin_slice const *mask, unsigned data) 492 { 493 static_cast<Gpio_jz4730_chip *>(gpio)->multi_set(*mask, data); 494 } 495 496 unsigned jz4730_gpio_multi_get(void *gpio, unsigned offset) 497 { 498 return static_cast<Gpio_jz4730_chip *>(gpio)->multi_get(offset); 499 } 500 501 int jz4730_gpio_get(void *gpio, unsigned pin) 502 { 503 return static_cast<Gpio_jz4730_chip *>(gpio)->get(pin); 504 } 505 506 void jz4730_gpio_set(void *gpio, unsigned pin, int value) 507 { 508 static_cast<Gpio_jz4730_chip *>(gpio)->set(pin, value); 509 } 510 511 void *jz4730_gpio_get_irq(void *gpio, unsigned pin) 512 { 513 return (void *) static_cast<Gpio_jz4730_chip *>(gpio)->get_irq(pin); 514 } 515 516 bool jz4730_gpio_irq_set_mode(void *gpio_irq, unsigned mode) 517 { 518 return static_cast<Hw::Gpio_irq_pin *>(gpio_irq)->do_set_mode(mode); 519 }