1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13#include <stdint.h> 14#include "mux.h" 15#include <utils/util.h> 16#include <platsupport/gpio.h> 17#include <platsupport/plat/gpio.h> 18#include "../../services.h" 19 20#define IMX6_GPIO1_PADDR 0x0209C000 21#define IMX6_GPIO2_PADDR 0x020A0000 22#define IMX6_GPIO3_PADDR 0x020A4000 23#define IMX6_GPIO4_PADDR 0x020A8000 24#define IMX6_GPIO5_PADDR 0x020AC000 25#define IMX6_GPIO6_PADDR 0x020B0000 26#define IMX6_GPIO7_PADDR 0x020B4000 27 28#define IMX6_GPIOX_SIZE 0x1000 29#define IMX6_GPIO1_SIZE IMX6_GPIOX_SIZE 30#define IMX6_GPIO2_SIZE IMX6_GPIOX_SIZE 31#define IMX6_GPIO3_SIZE IMX6_GPIOX_SIZE 32#define IMX6_GPIO4_SIZE IMX6_GPIOX_SIZE 33#define IMX6_GPIO5_SIZE IMX6_GPIOX_SIZE 34#define IMX6_GPIO6_SIZE IMX6_GPIOX_SIZE 35#define IMX6_GPIO7_SIZE IMX6_GPIOX_SIZE 36 37#define GPIO_ICFG_LOW 0x0 38#define GPIO_ICFG_HIGH 0x1 39#define GPIO_ICFG_RISE 0x2 40#define GPIO_ICFG_FALL 0x3 41#define GPIO_ICFG(f, v) (((v) & 0x3) << ((f) * 2)) 42#define GPIO_ICFG_MASK(f) GPIO_ICFG(f, 0x3) 43 44struct imx6_gpio_regs { 45 uint32_t data; /* +0x00 */ 46 uint32_t direction; /* +0x04 */ 47 uint32_t pad_status; /* +0x08 */ 48 uint32_t int_cfg; /* +0x0C */ 49 uint32_t int_mask; /* +0x14 */ 50 uint32_t int_status; /* +0x18 */ 51 uint32_t edge; /* +0x1C */ 52}; 53 54static struct imx6_gpio { 55 mux_sys_t *mux; 56 volatile struct imx6_gpio_regs *bank[GPIO_NBANKS]; 57} _gpio; 58 59volatile static struct imx6_gpio_regs *imx6_gpio_get_bank(gpio_t *gpio) 60{ 61 struct imx6_gpio *gpio_priv; 62 int port; 63 assert(gpio); 64 assert(gpio->gpio_sys); 65 assert(gpio->gpio_sys->priv); 66 gpio_priv = (struct imx6_gpio *)gpio->gpio_sys->priv; 67 port = GPIOID_PORT(gpio->id); 68 assert(port < GPIO_NBANKS); 69 assert(port >= 0); 70 return gpio_priv->bank[port]; 71} 72 73static int imx6_gpio_init(gpio_sys_t *gpio_sys, int id, enum gpio_dir dir, gpio_t *gpio) 74{ 75 volatile struct imx6_gpio_regs *bank; 76 struct imx6_gpio *gpio_priv; 77 uint32_t v; 78 int pin; 79 assert(gpio); 80 assert(gpio_sys); 81 gpio_priv = (struct imx6_gpio *)gpio_sys->priv; 82 assert(gpio_priv); 83 pin = GPIOID_PIN(id); 84 assert(pin < 32); 85 assert(pin >= 0); 86 87 gpio->id = id; 88 gpio->gpio_sys = gpio_sys; 89 90 bank = imx6_gpio_get_bank(gpio); 91 ZF_LOGD("Configuring GPIO on port %d pin %d\n", 92 GPIOID_PORT(id), GPIOID_PIN(id)); 93 94 /* MUX the GPIO */ 95 if (imx6_mux_enable_gpio(gpio_priv->mux, id)) { 96 ZF_LOGE("Invalid GPIO\n"); 97 return -1; 98 } 99 100 /* Set direction */ 101 v = bank->direction; 102 if (dir == GPIO_DIR_IN) { 103 v &= ~BIT(pin); 104 ZF_LOGD("configuring {%d,%d} for input %p => 0x%x->0x%x\n", 105 GPIOID_PORT(id), GPIOID_PIN(id), 106 &bank->direction, bank->direction, v); 107 } else { 108 v |= BIT(pin); 109 ZF_LOGD("configuring {%d,%d} for output %p => 0x%x->0x%x\n", 110 GPIOID_PORT(id), GPIOID_PIN(id), 111 &bank->direction, bank->direction, v); 112 } 113 bank->direction = v; 114 115 return 0; 116} 117 118static int imx6_gpio_set_level(gpio_t *gpio, enum gpio_level level) 119{ 120 volatile struct imx6_gpio_regs *bank; 121 uint32_t v; 122 int pin; 123 124 bank = imx6_gpio_get_bank(gpio); 125 pin = GPIOID_PIN(gpio->id); 126 assert(pin < 32); 127 assert(pin >= 0); 128 129 v = bank->data; 130 if (level == GPIO_LEVEL_HIGH) { 131 v |= (1U << pin); 132 } else { 133 v &= ~(1U << pin); 134 } 135 bank->data = v; 136 assert(bank->data == v); 137 138 return 0; 139} 140 141static int imx6_gpio_read_level(gpio_t *gpio) 142{ 143 volatile struct imx6_gpio_regs *bank; 144 uint32_t v; 145 int pin; 146 147 bank = imx6_gpio_get_bank(gpio); 148 pin = GPIOID_PIN(gpio->id); 149 assert(pin < 32); 150 assert(pin >= 0); 151 152 v = bank->data; 153 if (v & (1U << pin)) { 154 return GPIO_LEVEL_HIGH; 155 } 156 157 return GPIO_LEVEL_LOW; 158} 159 160int imx6_gpio_init_common(mux_sys_t *mux, gpio_sys_t *gpio_sys) 161{ 162 _gpio.mux = mux; 163 gpio_sys->priv = (void *)&_gpio; 164 gpio_sys->set_level = &imx6_gpio_set_level; 165 gpio_sys->read_level = &imx6_gpio_read_level; 166 gpio_sys->init = &imx6_gpio_init; 167 return 0; 168} 169 170int imx6_gpio_sys_init(void *bank1, void *bank2, void *bank3, 171 void *bank4, void *bank5, void *bank6, 172 void *bank7, 173 mux_sys_t *mux, gpio_sys_t *gpio_sys) 174{ 175 if (bank1 != NULL) { 176 _gpio.bank[GPIO_BANK1] = bank1; 177 } 178 if (bank2 != NULL) { 179 _gpio.bank[GPIO_BANK2] = bank2; 180 } 181 if (bank3 != NULL) { 182 _gpio.bank[GPIO_BANK3] = bank3; 183 } 184 if (bank4 != NULL) { 185 _gpio.bank[GPIO_BANK4] = bank4; 186 } 187 if (bank5 != NULL) { 188 _gpio.bank[GPIO_BANK5] = bank5; 189 } 190 if (bank6 != NULL) { 191 _gpio.bank[GPIO_BANK6] = bank6; 192 } 193 if (bank7 != NULL) { 194 _gpio.bank[GPIO_BANK7] = bank7; 195 } 196 return imx6_gpio_init_common(mux, gpio_sys); 197} 198 199int gpio_sys_init(ps_io_ops_t *io_ops, gpio_sys_t *gpio_sys) 200{ 201 MAP_IF_NULL(io_ops, IMX6_GPIO1, _gpio.bank[0]); 202 MAP_IF_NULL(io_ops, IMX6_GPIO2, _gpio.bank[1]); 203 MAP_IF_NULL(io_ops, IMX6_GPIO3, _gpio.bank[2]); 204 MAP_IF_NULL(io_ops, IMX6_GPIO4, _gpio.bank[3]); 205 MAP_IF_NULL(io_ops, IMX6_GPIO5, _gpio.bank[4]); 206 MAP_IF_NULL(io_ops, IMX6_GPIO6, _gpio.bank[5]); 207 MAP_IF_NULL(io_ops, IMX6_GPIO7, _gpio.bank[6]); 208 return imx6_gpio_init_common(&io_ops->mux_sys, gpio_sys); 209} 210