1 /* 2 * GPIO driver for Ingenic JZ4780. 3 * (See below for additional copyright and licensing notices.) 4 * 5 * Copyright (C) 2017, 2023 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-jz4780.h" 36 37 /* 38 GPIO register offsets (x in A..F). 39 40 Register summary: 41 42 PxINT 0 (function/GPIO) 1 (interrupt) 43 PxMSK 0 (function) 1 (GPIO) 0 (IRQ enable)/1 (IRQ disable) 44 PxPAT1 0 (function 0/1) 1 (function 2/3) 0 (output) 1 (input) 0 (level trigger) 1 (edge trigger) 45 PxPAT0 0 (function 0) 0 (function 2) 0 (output value 0) 0 (low level) 0 (falling edge) 46 1 (function 1) 1 (function 3) 1 (output value 1) 1 (high level) 1 (rising edge) 47 */ 48 49 enum Regs 50 { 51 Pin_level = 0x000, // PxPIN (read-only) 52 53 Port_int = 0x010, // PxINT 54 Port_int_set = 0x014, // PxINTS 55 Port_int_clear = 0x018, // PxINTC 56 57 Irq_mask = 0x020, // PxMSK (for PxINT == 1) 58 Irq_mask_set = 0x024, // PxMSKS 59 Irq_mask_clear = 0x028, // PxMSKC 60 Port_gpio = 0x020, // PxMSK (for PxINT == 0) 61 Port_gpio_set = 0x024, // PxMSKS 62 Port_gpio_clear = 0x028, // PxMSKC 63 64 Port_trigger = 0x030, // PxPAT1 (for PxINT == 1) 65 Port_trigger_set = 0x034, // PxPAT1S 66 Port_trigger_clear = 0x038, // PxPAT1C 67 Port_dir = 0x030, // PxPAT1 (for PxINT == 0, PxMSK == 1) 68 Port_dir_set = 0x034, // PxPAT1S 69 Port_dir_clear = 0x038, // PxPAT1C 70 Port_group1 = 0x030, // PxPAT1 (for PxINT == 0, PxMSK == 0) 71 Port_group1_set = 0x034, // PxPAT1S 72 Port_group1_clear = 0x038, // PxPAT1C 73 74 Port_level = 0x040, // PxPAT0 (for PxINT == 1) 75 Port_level_set = 0x044, // PxPAT0S 76 Port_level_clear = 0x048, // PxPAT0C 77 Port_data = 0x040, // PxPAT0 (for PxINT == 0, PxMSK == 1, PxPAT1 == 0) 78 Port_data_set = 0x044, // PxPAT0S 79 Port_data_clear = 0x048, // PxPAT0C 80 Port_group0 = 0x040, // PxPAT0 (for PxINT == 0, PxMSK == 0) 81 Port_group0_set = 0x044, // PxPAT0S 82 Port_group0_clear = 0x048, // PxPAT0C 83 84 Irq_flag = 0x050, // PxFLG (read-only) 85 Irq_flag_clear = 0x058, // PxFLGC 86 87 Pull_disable = 0x070, // PxPE 88 Pull_disable_set = 0x074, // PxPES 89 Pull_disable_clear = 0x078, // PxPEC 90 }; 91 92 93 94 // IRQ control for each GPIO pin. 95 96 Gpio_jz4780_irq_pin::Gpio_jz4780_irq_pin(unsigned pin, Hw::Register_block<32> const ®s) 97 : _pin(pin), _regs(regs) 98 {} 99 100 void 101 Gpio_jz4780_irq_pin::write_reg_pin(unsigned reg) 102 { 103 // Write the pin bit to the register, setting or clearing the pin 104 // depending on the register chosen. 105 106 _regs[reg] = _pin_bit(_pin); 107 } 108 109 void Gpio_jz4780_irq_pin::do_mask() 110 { 111 // Set the interrupt bit in the PxIM register. 112 113 write_reg_pin(Irq_mask_set); 114 } 115 116 void Gpio_jz4780_irq_pin::do_unmask() 117 { 118 // Clear the interrupt bit in the PxIM register, first also clearing the 119 // flag bit in the PxFLG register to allow interrupts to be delivered. 120 121 write_reg_pin(Irq_flag_clear); 122 write_reg_pin(Irq_mask_clear); 123 } 124 125 bool Gpio_jz4780_irq_pin::do_set_mode(unsigned mode) 126 { 127 // Standard comment found for this method: 128 // this operation touches multiple mmio registers and is thus 129 // not atomic, that's why we first mask the IRQ and if it was 130 // enabled we unmask it after we have changed the mode 131 132 if (enabled()) 133 do_mask(); 134 135 // Do the PxINT, PxPAT1 and PxPAT0 configuration. 136 137 switch(mode) 138 { 139 case L4_IRQ_F_LEVEL_HIGH: 140 write_reg_pin(Port_int_set); 141 write_reg_pin(Port_trigger_clear); 142 write_reg_pin(Port_level_set); 143 break; 144 case L4_IRQ_F_LEVEL_LOW: 145 write_reg_pin(Port_int_set); 146 write_reg_pin(Port_trigger_clear); 147 write_reg_pin(Port_level_clear); 148 break; 149 case L4_IRQ_F_POS_EDGE: 150 write_reg_pin(Port_int_set); 151 write_reg_pin(Port_trigger_set); 152 write_reg_pin(Port_level_set); 153 break; 154 case L4_IRQ_F_NEG_EDGE: 155 write_reg_pin(Port_int_set); 156 write_reg_pin(Port_trigger_set); 157 write_reg_pin(Port_level_clear); 158 break; 159 160 default: 161 return false; 162 } 163 164 if (enabled()) 165 do_unmask(); 166 167 return true; 168 } 169 170 int Gpio_jz4780_irq_pin::clear() 171 { 172 // Obtain the flag status for the pin, clearing it if set. 173 174 l4_uint32_t e = _regs[Irq_flag] & (1UL << _pin); 175 if (e) 176 _regs[Irq_flag_clear] = e; 177 178 return (e >> _pin); 179 } 180 181 bool Gpio_jz4780_irq_pin::enabled() 182 { 183 return true; 184 } 185 186 187 188 // Initialise the GPIO controller. 189 190 Gpio_jz4780_chip::Gpio_jz4780_chip(l4_addr_t start, l4_addr_t end, 191 unsigned nr_pins, 192 l4_uint32_t pull_ups, l4_uint32_t pull_downs) 193 : _start(start), _end(end), 194 _nr_pins(nr_pins), 195 _pull_ups(pull_ups), _pull_downs(pull_downs) 196 { 197 _regs = new Hw::Mmio_register_block<32>(_start); 198 } 199 200 // Return the value of a pin. 201 202 int 203 Gpio_jz4780_chip::get(unsigned pin) 204 { 205 if (pin >= _nr_pins) 206 throw -L4_EINVAL; 207 208 l4_uint32_t val = _regs[Pin_level]; 209 return (val >> _pin_shift(pin)) & 1; 210 } 211 212 // Return multiple pin values. 213 214 unsigned 215 Gpio_jz4780_chip::multi_get(unsigned offset) 216 { 217 _reg_offset_check(offset); 218 return _regs[Pin_level]; 219 } 220 221 // Set the value of a pin. 222 223 void 224 Gpio_jz4780_chip::set(unsigned pin, int value) 225 { 226 if (pin >= _nr_pins) 227 throw -L4_EINVAL; 228 229 l4_uint32_t reg_set = value ? Port_data_set : Port_data_clear; 230 _regs[reg_set] = _pin_bit(pin); 231 } 232 233 // Set multiple pin values. 234 235 void 236 Gpio_jz4780_chip::multi_set(Pin_slice const &mask, unsigned data) 237 { 238 _reg_offset_check(mask.offset); 239 if (mask.mask & data) 240 _regs[Port_data_set] = (mask.mask & data); 241 if (mask.mask & ~data) 242 _regs[Port_data_clear] = (mask.mask & ~data); 243 } 244 245 // Set a pin up with the given mode and value (if appropriate). 246 247 void 248 Gpio_jz4780_chip::setup(unsigned pin, unsigned mode, int value) 249 { 250 if (pin >= _nr_pins) 251 throw -L4_EINVAL; 252 253 config(pin, mode); 254 255 if (mode == Output) 256 set(pin, value); 257 } 258 259 // Configuration of a pin using the generic input/output/IRQ mode. 260 261 void 262 Gpio_jz4780_chip::config(unsigned pin, unsigned mode) 263 { 264 switch (mode) 265 { 266 case Input: 267 _regs[Port_int_clear] = _pin_bit(pin); 268 _regs[Port_gpio_set] = _pin_bit(pin); 269 _regs[Port_dir_set] = _pin_bit(pin); 270 break; 271 case Output: 272 _regs[Port_int_clear] = _pin_bit(pin); 273 _regs[Port_gpio_set] = _pin_bit(pin); 274 _regs[Port_dir_clear] = _pin_bit(pin); 275 break; 276 case Irq: 277 _regs[Port_int_set] = _pin_bit(pin); 278 // Other details depend on the actual trigger mode. 279 break; 280 default: 281 break; 282 } 283 } 284 285 // Pull-up/down configuration for a pin. 286 287 void 288 Gpio_jz4780_chip::config_pull(unsigned pin, unsigned mode) 289 { 290 if (pin >= _nr_pins) 291 throw -L4_EINVAL; 292 293 switch (mode) 294 { 295 case Pull_none: 296 _regs[Pull_disable_set] = _pin_bit(pin); 297 break; 298 case Pull_down: 299 if (_pin_bit(pin) & _pull_downs) 300 _regs[Pull_disable_clear] = _pin_bit(pin); 301 break; 302 case Pull_up: 303 if (_pin_bit(pin) & _pull_ups) 304 _regs[Pull_disable_clear] = _pin_bit(pin); 305 break; 306 default: 307 // Invalid pull-up/down mode for pin. 308 throw -L4_EINVAL; 309 } 310 } 311 312 // Pin function configuration. 313 314 void 315 Gpio_jz4780_chip::config_pad(unsigned pin, unsigned func, unsigned value) 316 { 317 if (pin >= _nr_pins) 318 throw -L4_EINVAL; 319 320 if (value > 3) 321 throw -L4_EINVAL; 322 323 switch (func) 324 { 325 // Support two different outputs. 326 327 case Hw::Gpio_chip::Function_gpio: 328 _regs[Port_int_clear] = _pin_bit(pin); 329 _regs[Port_gpio_set] = _pin_bit(pin); 330 _regs[value & 1 ? Port_data_set : Port_data_clear] = _pin_bit(pin); 331 break; 332 333 // Support four different device functions. 334 335 case Hw::Gpio_chip::Function_alt: 336 _regs[Port_int_clear] = _pin_bit(pin); 337 _regs[Port_gpio_clear] = _pin_bit(pin); 338 _regs[value & 2 ? Port_group1_set : Port_group1_clear] = _pin_bit(pin); 339 _regs[value & 1 ? Port_group0_set : Port_group0_clear] = _pin_bit(pin); 340 break; 341 default: 342 throw -L4_EINVAL; 343 } 344 } 345 346 // Obtain a pin's configuration from a register in the supplied value. 347 348 void 349 Gpio_jz4780_chip::config_get(unsigned pin, unsigned reg, unsigned *value) 350 { 351 if (pin >= _nr_pins) 352 throw -L4_EINVAL; 353 354 *value = (_regs[reg] >> _pin_shift(pin)) & 1; 355 } 356 357 // Return function and function-specific configuration for a pin. 358 359 void 360 Gpio_jz4780_chip::config_pad_get(unsigned pin, unsigned *func, unsigned *value) 361 { 362 unsigned direction, gpio, group0, group1, interrupt, level, trigger; 363 364 config_get(pin, Port_int, &interrupt); 365 366 if (interrupt) 367 { 368 config_get(pin, Port_trigger, &trigger); 369 config_get(pin, Port_level, &level); 370 371 *func = Hw::Gpio_chip::Function_irq; 372 *value = (trigger ? (level ? L4_IRQ_F_POS_EDGE : L4_IRQ_F_NEG_EDGE) 373 : (level ? L4_IRQ_F_LEVEL_HIGH : L4_IRQ_F_LEVEL_LOW)); 374 return; 375 } 376 377 config_get(pin, Port_gpio, &gpio); 378 379 if (gpio) 380 { 381 config_get(pin, Port_dir, &direction); 382 383 *func = Hw::Gpio_chip::Function_gpio; 384 *value = direction ? Input : Output; 385 return; 386 } 387 388 *func = Hw::Gpio_chip::Function_alt; 389 390 config_get(pin, Port_group0, &group0); 391 config_get(pin, Port_group1, &group1); 392 393 *value = (group1 << 1) | group0; 394 } 395 396 // Obtain an IRQ abstraction for a pin. 397 398 Hw::Gpio_irq_pin * 399 Gpio_jz4780_chip::get_irq(unsigned pin) 400 { 401 if (pin >= _nr_pins) 402 throw -L4_EINVAL; 403 404 return new Gpio_jz4780_irq_pin(pin, _regs); 405 } 406 407 // Pin function configuration for multiple pins. 408 409 void 410 Gpio_jz4780_chip::multi_config_pad(Pin_slice const &mask, unsigned func, unsigned val) 411 { 412 unsigned m = mask.mask; 413 for (unsigned pin = mask.offset; pin < _nr_pins; ++pin, m >>= 1) 414 if (m & 1) 415 config_pad(pin, func, val); 416 } 417 418 // Set up multiple pins with the given mode. 419 420 void 421 Gpio_jz4780_chip::multi_setup(Pin_slice const &mask, unsigned mode, unsigned outvalues) 422 { 423 unsigned m = mask.mask; 424 for (unsigned pin = mask.offset; pin < _nr_pins; ++pin, m >>= 1, outvalues >>= 1) 425 if (m & 1) 426 setup(pin, mode, outvalues & 1); 427 } 428 429 430 431 // C language interface functions. 432 433 void *jz4780_gpio_init(l4_addr_t start, l4_addr_t end, unsigned pins, 434 l4_uint32_t pull_ups, l4_uint32_t pull_downs) 435 { 436 return (void *) new Gpio_jz4780_chip(start, end, pins, pull_ups, pull_downs); 437 } 438 439 void jz4780_gpio_setup(void *gpio, unsigned pin, unsigned mode, int value) 440 { 441 static_cast<Gpio_jz4780_chip *>(gpio)->setup(pin, mode, value); 442 } 443 444 void jz4780_gpio_config_pull(void *gpio, unsigned pin, unsigned mode) 445 { 446 static_cast<Gpio_jz4780_chip *>(gpio)->config_pull(pin, mode); 447 } 448 449 void jz4780_gpio_config_pad(void *gpio, unsigned pin, unsigned func, unsigned value) 450 { 451 static_cast<Gpio_jz4780_chip *>(gpio)->config_pad(pin, func, value); 452 } 453 454 void jz4780_gpio_config_get(void *gpio, unsigned pin, unsigned reg, unsigned *value) 455 { 456 static_cast<Gpio_jz4780_chip *>(gpio)->config_get(pin, reg, value); 457 } 458 459 void jz4780_gpio_config_pad_get(void *gpio, unsigned pin, unsigned *func, unsigned *value) 460 { 461 static_cast<Gpio_jz4780_chip *>(gpio)->config_pad_get(pin, func, value); 462 } 463 464 void jz4780_gpio_multi_setup(void *gpio, Pin_slice const *mask, unsigned mode, unsigned outvalues) 465 { 466 static_cast<Gpio_jz4780_chip *>(gpio)->multi_setup(*mask, mode, outvalues); 467 } 468 469 void jz4780_gpio_multi_config_pad(void *gpio, Pin_slice const *mask, unsigned func, unsigned value) 470 { 471 static_cast<Gpio_jz4780_chip *>(gpio)->multi_config_pad(*mask, func, value); 472 } 473 474 void jz4780_gpio_multi_set(void *gpio, Pin_slice const *mask, unsigned data) 475 { 476 static_cast<Gpio_jz4780_chip *>(gpio)->multi_set(*mask, data); 477 } 478 479 unsigned jz4780_gpio_multi_get(void *gpio, unsigned offset) 480 { 481 return static_cast<Gpio_jz4780_chip *>(gpio)->multi_get(offset); 482 } 483 484 int jz4780_gpio_get(void *gpio, unsigned pin) 485 { 486 return static_cast<Gpio_jz4780_chip *>(gpio)->get(pin); 487 } 488 489 void jz4780_gpio_set(void *gpio, unsigned pin, int value) 490 { 491 static_cast<Gpio_jz4780_chip *>(gpio)->set(pin, value); 492 } 493 494 void *jz4780_gpio_get_irq(void *gpio, unsigned pin) 495 { 496 return (void *) static_cast<Gpio_jz4780_chip *>(gpio)->get_irq(pin); 497 } 498 499 bool jz4780_gpio_irq_set_mode(void *gpio_irq, unsigned mode) 500 { 501 return static_cast<Hw::Gpio_irq_pin *>(gpio_irq)->do_set_mode(mode); 502 }