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