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 <autoconf.h>
14#include <platsupport/gen_config.h>
15#include <stdint.h>
16#include <platsupport/mux.h>
17#include <platsupport/gpio.h>
18#include <platsupport/plat/gpio.h>
19#include <utils/util.h>
20#include "../../services.h"
21#include "mux.h"
22
23#define BITFIELD_SHIFT(x, bits)    ((x) * (bits))
24#define BITFIELD_MASK(x, bits)     (MASK(bits) << BITFIELD_SHIFT(x, bits))
25
26#define EINTCON_LOW  0x0
27#define EINTCON_HIGH 0x1
28#define EINTCON_FALL 0x2
29#define EINTCON_RISE 0x3
30#define EINTCON_EDGE 0x4
31#define EINTCON_MASK 0x7
32#define EINTCON_BITS 4
33
34#define PORTS_PER_BANK 56
35#define GPX_IDX_OFFSET 96
36
37static volatile struct mux_bank *_bank[GPIO_NBANKS];
38
39static struct mux_bank **mux_priv_get_banks(const mux_sys_t *mux)
40{
41    assert(mux);
42    return (struct mux_bank **)mux->priv;
43}
44
45static struct mux_cfg *get_mux_cfg(const mux_sys_t *mux, int port)
46{
47    struct mux_bank **bank;
48    int b, p;
49    bank = mux_priv_get_banks(mux);
50    b = GPIOPORT_GET_BANK(port);
51    p = GPIOPORT_GET_PORT(port);
52    assert(b >= 0 && b < GPIO_NBANKS);
53    return &bank[b]->gp[p];
54}
55
56static void exynos_mux_set_con(struct mux_cfg *_cfg, int pin, int func)
57{
58    volatile struct mux_cfg *cfg = (volatile struct mux_cfg *)_cfg;
59    uint32_t v;
60    v = cfg->con;
61    v &= ~BITFIELD_MASK(pin, 4);
62    v |= func << BITFIELD_SHIFT(pin, 4);
63    ZF_LOGD("con.%d @ 0x%08x : 0x%08x->0x%08x\n", pin, (uint32_t)&cfg->con, cfg->con, v);
64    cfg->con = v;
65    cfg->conpdn |= 0x3 << BITFIELD_SHIFT(pin, 2);
66}
67
68static void exynos_mux_set_dat(struct mux_cfg *_cfg, int pin, int val)
69{
70    volatile struct mux_cfg *cfg = (volatile struct mux_cfg *)_cfg;
71    uint32_t v;
72    v = cfg->dat;
73    v &= ~BITFIELD_MASK(pin, 1);
74    if (val) {
75        v |= BIT(BITFIELD_SHIFT(pin, 1));
76    }
77    ZF_LOGD("dat.%d @ 0x%08x : 0x%08x->0x%08x\n", pin, (uint32_t)&cfg->dat, cfg->dat, v);
78    cfg->dat = v;
79}
80
81static int exynos_mux_get_dat(struct mux_cfg *_cfg, int pin)
82{
83    volatile struct mux_cfg *cfg = (volatile struct mux_cfg *)_cfg;
84    uint32_t val;
85    val = cfg->dat;
86    val &= BITFIELD_MASK(pin, 1);
87    return !!val;
88}
89
90static void exynos_mux_set_pud(struct mux_cfg *cfg, int pin, int pud)
91{
92    uint32_t v;
93    v = cfg->pud;
94    v &= ~BITFIELD_MASK(pin, 2);
95    v |= pud << BITFIELD_SHIFT(pin, 2);
96    ZF_LOGD("pud.%d @ 0x%08x : 0x%08x->0x%08x\n", pin, (uint32_t)&cfg->pud, cfg->pud, v);
97    cfg->pud = v;
98    cfg->pudpdn = v;
99}
100
101static void exynos_mux_set_drv(struct mux_cfg *_cfg, int pin, int _drv)
102{
103    volatile struct mux_cfg *cfg = (volatile struct mux_cfg *)_cfg;
104    uint32_t v;
105    int drv;
106    if (_drv < 1) {
107        _drv = 1;
108    } else if (_drv > 4) {
109        _drv = 4;
110    }
111    switch (_drv) {
112    case 1:
113        drv = DRV1X;
114        break;
115    case 2:
116        drv = DRV2X;
117        break;
118    case 3:
119        drv = DRV3X;
120        break;
121    case 4:
122        drv = DRV4X;
123        break;
124    default:
125        assert(!"Invalid drive strength");
126        drv = 0;
127    }
128    v = cfg->drv;
129    v &= BITFIELD_MASK(pin, 2);
130    v |= drv << BITFIELD_SHIFT(pin, 2);
131    ZF_LOGD("drv @ 0x%08x : 0x%08x->0x%08x\n", (uint32_t)&cfg->drv, cfg->drv, v);
132    cfg->drv = v;
133}
134
135static void exynos_mux_configure(struct mux_cfg *cfg, int pin,
136                                 int con, int pud, int drv)
137{
138    exynos_mux_set_pud(cfg, pin, pud);
139    exynos_mux_set_drv(cfg, pin, drv);
140    exynos_mux_set_con(cfg, pin, con);
141}
142
143static int exynos_mux_feature_enable(const mux_sys_t *mux, mux_feature_t mux_feature,
144                                     UNUSED enum mux_gpio_dir mgd)
145{
146    if (mux_feature < 0 || mux_feature >= NMUX_FEATURES) {
147        ZF_LOGE("Invalid mux feature provided: %zd", mux_feature);
148        return -1;
149    }
150    struct mux_feature_data *data = feature_data[mux_feature];
151    (void)mux;
152    for (; data->port != GPIOPORT_NONE; data++) {
153        struct mux_cfg  *cfg;
154        /* Apply */
155        ZF_LOGD("Enabling feature: bank %d, port %d, pin %d\n",
156                GPIOPORT_GET_BANK(data->port),
157                GPIOPORT_GET_PORT(data->port),
158                data->pin);
159
160        cfg = get_mux_cfg(mux, data->port);
161        assert(cfg);
162
163        exynos_mux_configure(cfg, data->pin,
164                             MUXVALUE_CON(data->value),
165                             MUXVALUE_PUD(data->value),
166                             MUXVALUE_DRV(data->value));
167        ZF_LOGD("con.%d @ 0x%08x : 0x%08x (conpdn:0x%08x)\n", data->pin, (uint32_t)&cfg->con, cfg->con, cfg->conpdn);
168
169    }
170    return 0;
171}
172
173static int exynos_mux_init_common(mux_sys_t *mux)
174{
175    mux->priv = &_bank;
176    mux->feature_enable = &exynos_mux_feature_enable;
177    return 0;
178}
179
180int exynos_mux_init(void *gpioleft, void *gpioright, void *gpioc2c,
181                    void *gpioaudio, mux_sys_t *mux)
182{
183    if (gpioleft) {
184        _bank[GPIO_LEFT_BANK ] = gpioleft;
185    }
186    if (gpioright) {
187        _bank[GPIO_RIGHT_BANK] = gpioright;
188    }
189    if (gpioc2c) {
190        _bank[GPIO_C2C_BANK  ] = gpioc2c;
191    }
192    if (gpioaudio) {
193        _bank[GPIO_AUDIO_BANK] = gpioaudio;
194    }
195    return exynos_mux_init_common(mux);
196}
197
198int mux_sys_init(ps_io_ops_t *io_ops, UNUSED void *dependencies, mux_sys_t *mux)
199{
200
201    MAP_IF_NULL(io_ops, EXYNOS_GPIOLEFT,  _bank[GPIO_LEFT_BANK]);
202    MAP_IF_NULL(io_ops, EXYNOS_GPIORIGHT, _bank[GPIO_RIGHT_BANK]);
203    MAP_IF_NULL(io_ops, EXYNOS_GPIOC2C,   _bank[GPIO_C2C_BANK]);
204    MAP_IF_NULL(io_ops, EXYNOS_GPIOAUDIO, _bank[GPIO_AUDIO_BANK]);
205    return exynos_mux_init_common(mux);
206}
207
208/****************** GPIO ******************/
209
210static inline mux_sys_t *gpio_sys_get_mux(const gpio_sys_t *gpio_sys)
211{
212    assert(gpio_sys);
213    assert(gpio_sys->priv);
214    return (mux_sys_t *)gpio_sys->priv;
215}
216
217static inline mux_sys_t *gpio_get_mux(const gpio_t *gpio)
218{
219    assert(gpio);
220    return gpio_sys_get_mux(gpio->gpio_sys);
221}
222
223static struct mux_cfg *get_gpio_cfg(gpio_t *gpio)
224{
225    mux_sys_t *mux;
226    assert(gpio);
227    mux = gpio_get_mux(gpio);
228    return get_mux_cfg(mux, GPIOID_PORT(gpio->id));
229}
230
231static struct mux_bank *gpio_get_bank(gpio_t *gpio)
232{
233    struct mux_bank **banks;
234    mux_sys_t *mux;
235    int portid, bank;
236
237    portid = GPIOID_PORT(gpio->id);
238    bank = GPIOPORT_GET_BANK(portid);
239
240    assert(gpio);
241    mux = gpio_get_mux(gpio);
242    assert(mux);
243    banks = mux_priv_get_banks(mux);
244    assert(banks);
245
246    return banks[bank];
247}
248
249static int gpio_is_gpx(gpio_t *gpio)
250{
251    int portid;
252    portid = GPIOID_PORT(gpio->id);
253    return (portid >= GPX0 && portid <= GPX3);
254}
255
256static int gpio_get_xextint_idx(gpio_t *gpio)
257{
258    if (!gpio_is_gpx(gpio)) {
259        return -1;
260    } else {
261        int portid, port;
262        portid = GPIOID_PORT(gpio->id);
263        port = GPIOPORT_GET_PORT(portid);
264        return port - GPX_IDX_OFFSET;
265    }
266}
267
268static int gpio_get_extint_idx(gpio_t *gpio)
269{
270    int portid, port;
271    portid = GPIOID_PORT(gpio->id);
272    port = GPIOPORT_GET_PORT(portid);
273
274    /* Special cases. */
275    if (portid == GPV2 || portid == GPV3) {
276        return port - 1;
277    } else if (portid == GPV4) {
278        return port - 2;
279#ifdef CONFIG_PLAT_EXYNOS5
280        /* GPC4 on EXYNOS5 is very special indeed. */
281    } else if (portid == GPC4) {
282        return 13;
283#endif
284        /* General case */
285    } else if (port >= 0 && port <= PORTS_PER_BANK) {
286        return port;
287        /* All other cases, including GPX range */
288    } else {
289        return -1;
290    }
291}
292
293static int gpio_dir_get_intcon(enum gpio_dir dir)
294{
295    switch (dir) {
296    case GPIO_DIR_IRQ_LOW:
297        return 0x0;
298    case GPIO_DIR_IRQ_HIGH:
299        return 0x1;
300    case GPIO_DIR_IRQ_FALL:
301        return 0x2;
302    case GPIO_DIR_IRQ_RISE:
303        return 0x3;
304    case GPIO_DIR_IRQ_EDGE:
305        return 0x4;
306    default:
307        return -1;
308    }
309}
310
311static int exynos_pending_status(gpio_t *gpio, bool clear)
312{
313    volatile struct mux_bank *bank;
314    uint32_t pend;
315    int pin;
316
317    bank = gpio_get_bank(gpio);
318    assert(bank);
319
320    pin = GPIOID_PIN(gpio->id);
321    if (gpio_is_gpx(gpio)) {
322        int idx;
323        /* You HAD to be different GPX... */
324        idx = gpio_get_xextint_idx(gpio);
325        if (idx < 0) {
326            return -1;
327        }
328        pend = (bank->ext_xint_pend[idx] & ~bank->ext_xint_mask[idx]) & BIT(pin);
329        if (clear) {
330            bank->ext_xint_pend[idx] = BIT(pin);
331        }
332    } else {
333        int idx;
334        idx = gpio_get_extint_idx(gpio);
335        if (idx < 0) {
336            return -1;
337        }
338        pend = (bank->ext_int_pend[idx] & ~bank->ext_int_mask[idx]) & BIT(pin);
339        if (clear) {
340            bank->ext_int_pend[idx] = BIT(pin);
341        }
342    }
343    return pend;
344}
345
346static int exynos_gpio_int_configure(gpio_t *gpio, int int_con)
347{
348    volatile struct mux_bank *bank;
349    int pin;
350
351    /* Configure the int */
352    bank = gpio_get_bank(gpio);
353    assert(bank);
354
355    pin = GPIOID_PIN(gpio->id);
356    if (gpio_is_gpx(gpio)) {
357        /* You HAD to be different GPX... */
358        uint32_t v;
359        int idx;
360        idx = gpio_get_xextint_idx(gpio);
361        if (idx < 0) {
362            return -1;
363        }
364        v = bank->ext_xint_con[idx];
365        v &= BITFIELD_MASK(pin, 4);
366        v |= int_con << BITFIELD_SHIFT(pin, 4);
367        bank->ext_xint_con[idx] = v;
368        bank->ext_xint_mask[idx] &= ~BIT(pin);
369        bank->ext_xint_pend[idx] = BIT(pin); /* Set to clear */
370        bank->ext_xint_fltcon[idx][idx & 0x1] = 0;
371    } else {
372        uint32_t v;
373        int idx;
374        idx = gpio_get_extint_idx(gpio);
375        if (idx < 0) {
376            return -1;
377        }
378        v = bank->ext_int_con[idx];
379        v &= BITFIELD_MASK(pin, 4);
380        v |= int_con << BITFIELD_SHIFT(pin, 4);
381        bank->ext_int_con[idx] = v;
382        bank->ext_int_mask[idx] &= ~BIT(pin);
383        bank->ext_int_pend[idx] = BIT(pin); /* Set to clear */
384        /* These features are not supported yet */
385        bank->ext_int_fltcon[idx][idx & 0x1] = 0;
386        bank->ext_int_grppri_xa = 0;
387        bank->ext_int_priority_xa = 0;
388        bank->ext_int_service_xa = 0;
389        bank->ext_int_service_pend_xa = 0;
390        bank->ext_int_grpfixpri_xa = 0;
391        bank->ext_int_fixpri[idx] = 0;
392    }
393    return 0;
394}
395
396static int exynos_gpio_init(gpio_sys_t *gpio_sys, int id, enum gpio_dir dir, gpio_t *gpio)
397{
398    struct mux_cfg *cfg;
399    assert(gpio);
400
401    ZF_LOGD("Configuring GPIO on port %d pin %d\n", GPIOID_PORT(id), GPIOID_PIN(id));
402
403    gpio->id = id;
404    gpio->gpio_sys = gpio_sys;
405    cfg = get_gpio_cfg(gpio);
406    if (cfg == NULL) {
407        return -1;
408    }
409
410    if (dir == GPIO_DIR_IN) {
411        exynos_mux_configure(cfg, GPIOID_PIN(id), 0x0, PUD_PULLUP, 1);
412    } else if (dir == GPIO_DIR_OUT) {
413        exynos_mux_configure(cfg, GPIOID_PIN(id), 0x1, PUD_NONE, 1);
414    } else {
415        int con;
416        con = gpio_dir_get_intcon(dir);
417        if (con < 0) {
418            return -1;
419        }
420        exynos_mux_configure(cfg, GPIOID_PIN(id), 0xf, PUD_PULLUP, 1);
421        return exynos_gpio_int_configure(gpio, con);
422    }
423    return 0;
424}
425
426static int exynos_gpio_set_level(gpio_t *gpio, enum gpio_level level)
427{
428    struct mux_cfg *cfg;
429    cfg = get_gpio_cfg(gpio);
430    if (level == GPIO_LEVEL_HIGH) {
431        exynos_mux_set_dat(cfg, GPIOID_PIN(gpio->id), 1);
432    } else {
433        exynos_mux_set_dat(cfg, GPIOID_PIN(gpio->id), 0);
434    }
435    return 0;
436}
437
438static int exynos_gpio_read_level(gpio_t *gpio)
439{
440    struct mux_cfg *cfg;
441    cfg = get_gpio_cfg(gpio);
442    if (exynos_mux_get_dat(cfg, GPIOID_PIN(gpio->id))) {
443        return GPIO_LEVEL_HIGH;
444    } else {
445        return GPIO_LEVEL_LOW;
446    }
447}
448
449int exynos_gpio_sys_init(mux_sys_t *mux_sys, gpio_sys_t *gpio_sys)
450{
451    assert(gpio_sys);
452    assert(mux_sys);
453    if (!mux_sys_valid(mux_sys)) {
454        return -1;
455    } else {
456        /* GPIO is done through the MUX on exynos */
457        gpio_sys->priv = mux_sys;
458        gpio_sys->set_level = &exynos_gpio_set_level;
459        gpio_sys->read_level = &exynos_gpio_read_level;
460        gpio_sys->pending_status = &exynos_pending_status;
461        gpio_sys->init = &exynos_gpio_init;
462        return 0;
463    }
464}
465
466int gpio_sys_init(ps_io_ops_t *io_ops, gpio_sys_t *gpio_sys)
467{
468    assert(gpio_sys);
469    assert(io_ops);
470    return exynos_gpio_sys_init(&io_ops->mux_sys, gpio_sys);
471}
472