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