pl061_gpio.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. /*
  2. * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. *
  6. * ARM PL061 GPIO Driver.
  7. * Reference to ARM DDI 0190B document.
  8. *
  9. */
  10. #include <assert.h>
  11. #include <errno.h>
  12. #include <common/debug.h>
  13. #include <drivers/arm/pl061_gpio.h>
  14. #include <drivers/gpio.h>
  15. #include <lib/cassert.h>
  16. #include <lib/mmio.h>
  17. #include <lib/utils.h>
  18. #if !PLAT_PL061_MAX_GPIOS
  19. # define PLAT_PL061_MAX_GPIOS 32
  20. #endif /* PLAT_PL061_MAX_GPIOS */
  21. CASSERT(PLAT_PL061_MAX_GPIOS > 0, assert_plat_pl061_max_gpios);
  22. #define MAX_GPIO_DEVICES ((PLAT_PL061_MAX_GPIOS + \
  23. (GPIOS_PER_PL061 - 1)) / GPIOS_PER_PL061)
  24. #define PL061_GPIO_DIR 0x400
  25. #define GPIOS_PER_PL061 8
  26. static int pl061_get_direction(int gpio);
  27. static void pl061_set_direction(int gpio, int direction);
  28. static int pl061_get_value(int gpio);
  29. static void pl061_set_value(int gpio, int value);
  30. static uintptr_t pl061_reg_base[MAX_GPIO_DEVICES];
  31. static const gpio_ops_t pl061_gpio_ops = {
  32. .get_direction = pl061_get_direction,
  33. .set_direction = pl061_set_direction,
  34. .get_value = pl061_get_value,
  35. .set_value = pl061_set_value,
  36. };
  37. static int pl061_get_direction(int gpio)
  38. {
  39. uintptr_t base_addr;
  40. unsigned int data, offset;
  41. assert((gpio >= 0) && (gpio < PLAT_PL061_MAX_GPIOS));
  42. base_addr = pl061_reg_base[gpio / GPIOS_PER_PL061];
  43. offset = gpio % GPIOS_PER_PL061;
  44. data = mmio_read_8(base_addr + PL061_GPIO_DIR);
  45. if (data & BIT(offset))
  46. return GPIO_DIR_OUT;
  47. return GPIO_DIR_IN;
  48. }
  49. static void pl061_set_direction(int gpio, int direction)
  50. {
  51. uintptr_t base_addr;
  52. unsigned int data, offset;
  53. assert((gpio >= 0) && (gpio < PLAT_PL061_MAX_GPIOS));
  54. base_addr = pl061_reg_base[gpio / GPIOS_PER_PL061];
  55. offset = gpio % GPIOS_PER_PL061;
  56. if (direction == GPIO_DIR_OUT) {
  57. data = mmio_read_8(base_addr + PL061_GPIO_DIR) | BIT(offset);
  58. mmio_write_8(base_addr + PL061_GPIO_DIR, data);
  59. } else {
  60. data = mmio_read_8(base_addr + PL061_GPIO_DIR) & ~BIT(offset);
  61. mmio_write_8(base_addr + PL061_GPIO_DIR, data);
  62. }
  63. }
  64. /*
  65. * The offset of GPIODATA register is 0.
  66. * The values read from GPIODATA are determined for each bit, by the mask bit
  67. * derived from the address used to access the data register, PADDR[9:2].
  68. * Bits that are 1 in the address mask cause the corresponding bits in GPIODATA
  69. * to be read, and bits that are 0 in the address mask cause the corresponding
  70. * bits in GPIODATA to be read as 0, regardless of their value.
  71. */
  72. static int pl061_get_value(int gpio)
  73. {
  74. uintptr_t base_addr;
  75. unsigned int offset;
  76. assert((gpio >= 0) && (gpio < PLAT_PL061_MAX_GPIOS));
  77. base_addr = pl061_reg_base[gpio / GPIOS_PER_PL061];
  78. offset = gpio % GPIOS_PER_PL061;
  79. if (mmio_read_8(base_addr + BIT(offset + 2)))
  80. return GPIO_LEVEL_HIGH;
  81. return GPIO_LEVEL_LOW;
  82. }
  83. /*
  84. * In order to write GPIODATA, the corresponding bits in the mask, resulting
  85. * from the address bus, PADDR[9:2], must be HIGH. Otherwise the bit values
  86. * remain unchanged by the write.
  87. */
  88. static void pl061_set_value(int gpio, int value)
  89. {
  90. uintptr_t base_addr;
  91. int offset;
  92. assert((gpio >= 0) && (gpio < PLAT_PL061_MAX_GPIOS));
  93. base_addr = pl061_reg_base[gpio / GPIOS_PER_PL061];
  94. offset = gpio % GPIOS_PER_PL061;
  95. if (value == GPIO_LEVEL_HIGH)
  96. mmio_write_8(base_addr + BIT(offset + 2), BIT(offset));
  97. else
  98. mmio_write_8(base_addr + BIT(offset + 2), 0);
  99. }
  100. /*
  101. * Register the PL061 GPIO controller with a base address and the offset
  102. * of start pin in this GPIO controller.
  103. * This function is called after pl061_gpio_ops_init().
  104. */
  105. void pl061_gpio_register(uintptr_t base_addr, int gpio_dev)
  106. {
  107. assert((gpio_dev >= 0) && (gpio_dev < MAX_GPIO_DEVICES));
  108. pl061_reg_base[gpio_dev] = base_addr;
  109. }
  110. /*
  111. * Initialize PL061 GPIO controller with the total GPIO numbers in SoC.
  112. */
  113. void pl061_gpio_init(void)
  114. {
  115. gpio_init(&pl061_gpio_ops);
  116. }