19901dcf6SCaesar Wang /* 29901dcf6SCaesar Wang * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. 39901dcf6SCaesar Wang * 482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 59901dcf6SCaesar Wang */ 69901dcf6SCaesar Wang #include <assert.h> 79901dcf6SCaesar Wang #include <debug.h> 89901dcf6SCaesar Wang #include <delay_timer.h> 99901dcf6SCaesar Wang #include <errno.h> 109901dcf6SCaesar Wang #include <gpio.h> 119901dcf6SCaesar Wang #include <mmio.h> 12ee1ebbd1SIsla Mitchell #include <plat_private.h> 139901dcf6SCaesar Wang #include <platform.h> 149901dcf6SCaesar Wang #include <platform_def.h> 159901dcf6SCaesar Wang #include <soc.h> 169901dcf6SCaesar Wang 179901dcf6SCaesar Wang uint32_t gpio_port[] = { 189901dcf6SCaesar Wang GPIO0_BASE, 199901dcf6SCaesar Wang GPIO1_BASE, 209901dcf6SCaesar Wang GPIO2_BASE, 219901dcf6SCaesar Wang GPIO3_BASE, 229901dcf6SCaesar Wang GPIO4_BASE, 239901dcf6SCaesar Wang }; 249901dcf6SCaesar Wang 25*2adcad64SLin Huang struct { 26*2adcad64SLin Huang uint32_t swporta_dr; 27*2adcad64SLin Huang uint32_t swporta_ddr; 28*2adcad64SLin Huang uint32_t inten; 29*2adcad64SLin Huang uint32_t intmask; 30*2adcad64SLin Huang uint32_t inttype_level; 31*2adcad64SLin Huang uint32_t int_polarity; 32*2adcad64SLin Huang uint32_t debounce; 33*2adcad64SLin Huang uint32_t ls_sync; 34*2adcad64SLin Huang } store_gpio[3]; 35*2adcad64SLin Huang 36*2adcad64SLin Huang static uint32_t store_grf_gpio[(GRF_GPIO2D_HE - GRF_GPIO2A_IOMUX) / 4 + 1]; 37*2adcad64SLin Huang 389901dcf6SCaesar Wang #define SWPORTA_DR 0x00 399901dcf6SCaesar Wang #define SWPORTA_DDR 0x04 40*2adcad64SLin Huang #define INTEN 0x30 41*2adcad64SLin Huang #define INTMASK 0x34 42*2adcad64SLin Huang #define INTTYPE_LEVEL 0x38 43*2adcad64SLin Huang #define INT_POLARITY 0x3c 44*2adcad64SLin Huang #define DEBOUNCE 0x48 45*2adcad64SLin Huang #define LS_SYNC 0x60 469901dcf6SCaesar Wang 47*2adcad64SLin Huang #define EXT_PORTA 0x50 489901dcf6SCaesar Wang #define PMU_GPIO_PORT0 0 499901dcf6SCaesar Wang #define PMU_GPIO_PORT1 1 50536c2492SCaesar Wang #define GPIO_PORT2 2 51536c2492SCaesar Wang #define GPIO_PORT3 3 52536c2492SCaesar Wang #define GPIO_PORT4 4 539901dcf6SCaesar Wang 549901dcf6SCaesar Wang #define PMU_GRF_GPIO0A_P 0x40 559901dcf6SCaesar Wang #define GRF_GPIO2A_P 0xe040 569901dcf6SCaesar Wang #define GPIO_P_MASK 0x03 579901dcf6SCaesar Wang 58536c2492SCaesar Wang #define GET_GPIO_PORT(pin) (pin / 32) 59536c2492SCaesar Wang #define GET_GPIO_NUM(pin) (pin % 32) 60536c2492SCaesar Wang #define GET_GPIO_BANK(pin) ((pin % 32) / 8) 61536c2492SCaesar Wang #define GET_GPIO_ID(pin) ((pin % 32) % 8) 62536c2492SCaesar Wang 63536c2492SCaesar Wang /* returns old clock state, enables clock, in order to do GPIO access */ 64536c2492SCaesar Wang static int gpio_get_clock(uint32_t gpio_number) 659901dcf6SCaesar Wang { 66536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio_number); 67536c2492SCaesar Wang uint32_t clock_state = 0; 689901dcf6SCaesar Wang 699901dcf6SCaesar Wang assert(port < 5); 709901dcf6SCaesar Wang 719901dcf6SCaesar Wang switch (port) { 72536c2492SCaesar Wang case PMU_GPIO_PORT0: 73536c2492SCaesar Wang clock_state = (mmio_read_32(PMUCRU_BASE + 74536c2492SCaesar Wang CRU_PMU_CLKGATE_CON(1)) >> 75536c2492SCaesar Wang PCLK_GPIO0_GATE_SHIFT) & 0x01; 769901dcf6SCaesar Wang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1), 77536c2492SCaesar Wang BITS_WITH_WMASK(0, CLK_GATE_MASK, 789901dcf6SCaesar Wang PCLK_GPIO0_GATE_SHIFT)); 799901dcf6SCaesar Wang break; 80536c2492SCaesar Wang case PMU_GPIO_PORT1: 81536c2492SCaesar Wang clock_state = (mmio_read_32(PMUCRU_BASE + 82536c2492SCaesar Wang CRU_PMU_CLKGATE_CON(1)) >> 83536c2492SCaesar Wang PCLK_GPIO1_GATE_SHIFT) & 0x01; 849901dcf6SCaesar Wang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1), 85536c2492SCaesar Wang BITS_WITH_WMASK(0, CLK_GATE_MASK, 869901dcf6SCaesar Wang PCLK_GPIO1_GATE_SHIFT)); 879901dcf6SCaesar Wang break; 88536c2492SCaesar Wang case GPIO_PORT2: 89536c2492SCaesar Wang clock_state = (mmio_read_32(CRU_BASE + 90536c2492SCaesar Wang CRU_CLKGATE_CON(31)) >> 91536c2492SCaesar Wang PCLK_GPIO2_GATE_SHIFT) & 0x01; 929901dcf6SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 93536c2492SCaesar Wang BITS_WITH_WMASK(0, CLK_GATE_MASK, 949901dcf6SCaesar Wang PCLK_GPIO2_GATE_SHIFT)); 959901dcf6SCaesar Wang break; 96536c2492SCaesar Wang case GPIO_PORT3: 97536c2492SCaesar Wang clock_state = (mmio_read_32(CRU_BASE + 98536c2492SCaesar Wang CRU_CLKGATE_CON(31)) >> 99536c2492SCaesar Wang PCLK_GPIO3_GATE_SHIFT) & 0x01; 1009901dcf6SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 101536c2492SCaesar Wang BITS_WITH_WMASK(0, CLK_GATE_MASK, 102536c2492SCaesar Wang PCLK_GPIO3_GATE_SHIFT)); 103536c2492SCaesar Wang break; 104536c2492SCaesar Wang case GPIO_PORT4: 105536c2492SCaesar Wang clock_state = (mmio_read_32(CRU_BASE + 106536c2492SCaesar Wang CRU_CLKGATE_CON(31)) >> 107536c2492SCaesar Wang PCLK_GPIO4_GATE_SHIFT) & 0x01; 108536c2492SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 109536c2492SCaesar Wang BITS_WITH_WMASK(0, CLK_GATE_MASK, 110536c2492SCaesar Wang PCLK_GPIO4_GATE_SHIFT)); 111536c2492SCaesar Wang break; 112536c2492SCaesar Wang default: 113536c2492SCaesar Wang break; 114536c2492SCaesar Wang } 115536c2492SCaesar Wang 116536c2492SCaesar Wang return clock_state; 117536c2492SCaesar Wang } 118536c2492SCaesar Wang 119536c2492SCaesar Wang /* restores old state of gpio clock */ 120536c2492SCaesar Wang void gpio_put_clock(uint32_t gpio_number, uint32_t clock_state) 121536c2492SCaesar Wang { 122536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio_number); 123536c2492SCaesar Wang 124536c2492SCaesar Wang switch (port) { 125536c2492SCaesar Wang case PMU_GPIO_PORT0: 126536c2492SCaesar Wang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1), 127536c2492SCaesar Wang BITS_WITH_WMASK(clock_state, CLK_GATE_MASK, 128536c2492SCaesar Wang PCLK_GPIO0_GATE_SHIFT)); 129536c2492SCaesar Wang break; 130536c2492SCaesar Wang case PMU_GPIO_PORT1: 131536c2492SCaesar Wang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1), 132536c2492SCaesar Wang BITS_WITH_WMASK(clock_state, CLK_GATE_MASK, 133536c2492SCaesar Wang PCLK_GPIO1_GATE_SHIFT)); 134536c2492SCaesar Wang break; 135536c2492SCaesar Wang case GPIO_PORT2: 136536c2492SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 137536c2492SCaesar Wang BITS_WITH_WMASK(clock_state, CLK_GATE_MASK, 138536c2492SCaesar Wang PCLK_GPIO2_GATE_SHIFT)); 139536c2492SCaesar Wang break; 140536c2492SCaesar Wang case GPIO_PORT3: 141536c2492SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 142536c2492SCaesar Wang BITS_WITH_WMASK(clock_state, CLK_GATE_MASK, 1439901dcf6SCaesar Wang PCLK_GPIO3_GATE_SHIFT)); 1449901dcf6SCaesar Wang 1459901dcf6SCaesar Wang break; 146536c2492SCaesar Wang case GPIO_PORT4: 1479901dcf6SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 148536c2492SCaesar Wang BITS_WITH_WMASK(clock_state, CLK_GATE_MASK, 1499901dcf6SCaesar Wang PCLK_GPIO4_GATE_SHIFT)); 1509901dcf6SCaesar Wang break; 1519901dcf6SCaesar Wang default: 1529901dcf6SCaesar Wang break; 1539901dcf6SCaesar Wang } 1549901dcf6SCaesar Wang } 1559901dcf6SCaesar Wang 156536c2492SCaesar Wang static int get_pull(int gpio) 1579901dcf6SCaesar Wang { 158536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio); 159536c2492SCaesar Wang uint32_t bank = GET_GPIO_BANK(gpio); 160536c2492SCaesar Wang uint32_t id = GET_GPIO_ID(gpio); 161536c2492SCaesar Wang uint32_t val, clock_state; 1629901dcf6SCaesar Wang 163536c2492SCaesar Wang assert((port < 5) && (bank < 4)); 1649901dcf6SCaesar Wang 165536c2492SCaesar Wang clock_state = gpio_get_clock(gpio); 166536c2492SCaesar Wang 167536c2492SCaesar Wang if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) { 168536c2492SCaesar Wang val = mmio_read_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P + 169536c2492SCaesar Wang port * 16 + bank * 4); 170536c2492SCaesar Wang val = (val >> (id * 2)) & GPIO_P_MASK; 171536c2492SCaesar Wang } else { 172536c2492SCaesar Wang val = mmio_read_32(GRF_BASE + GRF_GPIO2A_P + 173536c2492SCaesar Wang (port - 2) * 16 + bank * 4); 174536c2492SCaesar Wang val = (val >> (id * 2)) & GPIO_P_MASK; 175536c2492SCaesar Wang } 176536c2492SCaesar Wang gpio_put_clock(gpio, clock_state); 1779901dcf6SCaesar Wang 1789901dcf6SCaesar Wang /* 1799901dcf6SCaesar Wang * in gpio0a, gpio0b, gpio2c, gpio2d, 1809901dcf6SCaesar Wang * 00: Z 1819901dcf6SCaesar Wang * 01: pull down 1829901dcf6SCaesar Wang * 10: Z 1839901dcf6SCaesar Wang * 11: pull up 1849901dcf6SCaesar Wang * different with other gpio, so need to correct it 1859901dcf6SCaesar Wang */ 186536c2492SCaesar Wang if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) { 187536c2492SCaesar Wang if (val == 3) 188536c2492SCaesar Wang val = GPIO_PULL_UP; 189536c2492SCaesar Wang else if (val == 1) 190536c2492SCaesar Wang val = GPIO_PULL_DOWN; 191536c2492SCaesar Wang else 192536c2492SCaesar Wang val = 0; 193536c2492SCaesar Wang } 194536c2492SCaesar Wang 195536c2492SCaesar Wang return val; 196536c2492SCaesar Wang } 197536c2492SCaesar Wang 198536c2492SCaesar Wang static void set_pull(int gpio, int pull) 199536c2492SCaesar Wang { 200536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio); 201536c2492SCaesar Wang uint32_t bank = GET_GPIO_BANK(gpio); 202536c2492SCaesar Wang uint32_t id = GET_GPIO_ID(gpio); 203536c2492SCaesar Wang uint32_t clock_state; 204536c2492SCaesar Wang 205536c2492SCaesar Wang assert((port < 5) && (bank < 4)); 206536c2492SCaesar Wang 207536c2492SCaesar Wang clock_state = gpio_get_clock(gpio); 208536c2492SCaesar Wang 209536c2492SCaesar Wang /* 210536c2492SCaesar Wang * in gpio0a, gpio0b, gpio2c, gpio2d, 211536c2492SCaesar Wang * 00: Z 212536c2492SCaesar Wang * 01: pull down 213536c2492SCaesar Wang * 10: Z 214536c2492SCaesar Wang * 11: pull up 215536c2492SCaesar Wang * different with other gpio, so need to correct it 216536c2492SCaesar Wang */ 217536c2492SCaesar Wang if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) { 2189901dcf6SCaesar Wang if (pull == GPIO_PULL_UP) 2199901dcf6SCaesar Wang pull = 3; 2209901dcf6SCaesar Wang else if (pull == GPIO_PULL_DOWN) 2219901dcf6SCaesar Wang pull = 1; 2229901dcf6SCaesar Wang else 2239901dcf6SCaesar Wang pull = 0; 2249901dcf6SCaesar Wang } 2259901dcf6SCaesar Wang 2269901dcf6SCaesar Wang if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) { 2279901dcf6SCaesar Wang mmio_write_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P + 2289901dcf6SCaesar Wang port * 16 + bank * 4, 2299901dcf6SCaesar Wang BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2)); 2309901dcf6SCaesar Wang } else { 2319901dcf6SCaesar Wang mmio_write_32(GRF_BASE + GRF_GPIO2A_P + 2329901dcf6SCaesar Wang (port - 2) * 16 + bank * 4, 2339901dcf6SCaesar Wang BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2)); 2349901dcf6SCaesar Wang } 235536c2492SCaesar Wang gpio_put_clock(gpio, clock_state); 2369901dcf6SCaesar Wang } 2379901dcf6SCaesar Wang 2389901dcf6SCaesar Wang static void set_direction(int gpio, int direction) 2399901dcf6SCaesar Wang { 240536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio); 241536c2492SCaesar Wang uint32_t num = GET_GPIO_NUM(gpio); 242536c2492SCaesar Wang uint32_t clock_state; 2439901dcf6SCaesar Wang 2449901dcf6SCaesar Wang assert((port < 5) && (num < 32)); 2459901dcf6SCaesar Wang 246536c2492SCaesar Wang clock_state = gpio_get_clock(gpio); 2479901dcf6SCaesar Wang 2489901dcf6SCaesar Wang /* 2499901dcf6SCaesar Wang * in gpio.h 2509901dcf6SCaesar Wang * #define GPIO_DIR_OUT 0 2519901dcf6SCaesar Wang * #define GPIO_DIR_IN 1 2529901dcf6SCaesar Wang * but rk3399 gpio direction 1: output, 0: input 2539901dcf6SCaesar Wang * so need to revert direction value 2549901dcf6SCaesar Wang */ 2559901dcf6SCaesar Wang mmio_setbits_32(gpio_port[port] + SWPORTA_DDR, !direction << num); 256536c2492SCaesar Wang gpio_put_clock(gpio, clock_state); 2579901dcf6SCaesar Wang } 2589901dcf6SCaesar Wang 2599901dcf6SCaesar Wang static int get_direction(int gpio) 2609901dcf6SCaesar Wang { 261536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio); 262536c2492SCaesar Wang uint32_t num = GET_GPIO_NUM(gpio); 263536c2492SCaesar Wang int direction, clock_state; 2649901dcf6SCaesar Wang 2659901dcf6SCaesar Wang assert((port < 5) && (num < 32)); 2669901dcf6SCaesar Wang 267536c2492SCaesar Wang clock_state = gpio_get_clock(gpio); 2689901dcf6SCaesar Wang 2699901dcf6SCaesar Wang /* 2709901dcf6SCaesar Wang * in gpio.h 2719901dcf6SCaesar Wang * #define GPIO_DIR_OUT 0 2729901dcf6SCaesar Wang * #define GPIO_DIR_IN 1 2739901dcf6SCaesar Wang * but rk3399 gpio direction 1: output, 0: input 2749901dcf6SCaesar Wang * so need to revert direction value 2759901dcf6SCaesar Wang */ 2769901dcf6SCaesar Wang direction = !((mmio_read_32(gpio_port[port] + 2779901dcf6SCaesar Wang SWPORTA_DDR) >> num) & 0x1); 278536c2492SCaesar Wang gpio_put_clock(gpio, clock_state); 2799901dcf6SCaesar Wang 2809901dcf6SCaesar Wang return direction; 2819901dcf6SCaesar Wang } 2829901dcf6SCaesar Wang 2839901dcf6SCaesar Wang static int get_value(int gpio) 2849901dcf6SCaesar Wang { 285536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio); 286536c2492SCaesar Wang uint32_t num = GET_GPIO_NUM(gpio); 287536c2492SCaesar Wang int value, clock_state; 2889901dcf6SCaesar Wang 2899901dcf6SCaesar Wang assert((port < 5) && (num < 32)); 2909901dcf6SCaesar Wang 291536c2492SCaesar Wang clock_state = gpio_get_clock(gpio); 2929901dcf6SCaesar Wang value = (mmio_read_32(gpio_port[port] + EXT_PORTA) >> num) & 0x1; 293536c2492SCaesar Wang gpio_put_clock(gpio, clock_state); 2949901dcf6SCaesar Wang 2959901dcf6SCaesar Wang return value; 2969901dcf6SCaesar Wang } 2979901dcf6SCaesar Wang 2989901dcf6SCaesar Wang static void set_value(int gpio, int value) 2999901dcf6SCaesar Wang { 300536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio); 301536c2492SCaesar Wang uint32_t num = GET_GPIO_NUM(gpio); 302536c2492SCaesar Wang uint32_t clock_state; 3039901dcf6SCaesar Wang 3049901dcf6SCaesar Wang assert((port < 5) && (num < 32)); 3059901dcf6SCaesar Wang 306536c2492SCaesar Wang clock_state = gpio_get_clock(gpio); 3079901dcf6SCaesar Wang mmio_clrsetbits_32(gpio_port[port] + SWPORTA_DR, 1 << num, 3089901dcf6SCaesar Wang !!value << num); 309536c2492SCaesar Wang gpio_put_clock(gpio, clock_state); 3109901dcf6SCaesar Wang } 3119901dcf6SCaesar Wang 312*2adcad64SLin Huang void plat_rockchip_save_gpio(void) 313*2adcad64SLin Huang { 314*2adcad64SLin Huang int i; 315*2adcad64SLin Huang uint32_t cru_gate_save; 316*2adcad64SLin Huang 317*2adcad64SLin Huang cru_gate_save = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31)); 318*2adcad64SLin Huang 319*2adcad64SLin Huang /* 320*2adcad64SLin Huang * when shutdown logic, we need to save gpio2 ~ gpio4 register, 321*2adcad64SLin Huang * we need to enable gpio2 ~ gpio4 clock here, since it may be gating, 322*2adcad64SLin Huang * and we do not care gpio0 and gpio1 clock gate, since we never 323*2adcad64SLin Huang * gating them 324*2adcad64SLin Huang */ 325*2adcad64SLin Huang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 326*2adcad64SLin Huang BITS_WITH_WMASK(0, 0x07, PCLK_GPIO2_GATE_SHIFT)); 327*2adcad64SLin Huang 328*2adcad64SLin Huang /* 329*2adcad64SLin Huang * since gpio0, gpio1 are pmugpio, they will keep ther value 330*2adcad64SLin Huang * when shutdown logic power rail, so only need to save gpio2 ~ gpio4 331*2adcad64SLin Huang * register value 332*2adcad64SLin Huang */ 333*2adcad64SLin Huang for (i = 2; i < 5; i++) { 334*2adcad64SLin Huang store_gpio[i - 2].swporta_dr = 335*2adcad64SLin Huang mmio_read_32(gpio_port[i] + SWPORTA_DR); 336*2adcad64SLin Huang store_gpio[i - 2].swporta_ddr = 337*2adcad64SLin Huang mmio_read_32(gpio_port[i] + SWPORTA_DDR); 338*2adcad64SLin Huang store_gpio[i - 2].inten = 339*2adcad64SLin Huang mmio_read_32(gpio_port[i] + INTEN); 340*2adcad64SLin Huang store_gpio[i - 2].intmask = 341*2adcad64SLin Huang mmio_read_32(gpio_port[i] + INTMASK); 342*2adcad64SLin Huang store_gpio[i - 2].inttype_level = 343*2adcad64SLin Huang mmio_read_32(gpio_port[i] + INTTYPE_LEVEL); 344*2adcad64SLin Huang store_gpio[i - 2].int_polarity = 345*2adcad64SLin Huang mmio_read_32(gpio_port[i] + INT_POLARITY); 346*2adcad64SLin Huang store_gpio[i - 2].debounce = 347*2adcad64SLin Huang mmio_read_32(gpio_port[i] + DEBOUNCE); 348*2adcad64SLin Huang store_gpio[i - 2].ls_sync = 349*2adcad64SLin Huang mmio_read_32(gpio_port[i] + LS_SYNC); 350*2adcad64SLin Huang } 351*2adcad64SLin Huang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 352*2adcad64SLin Huang cru_gate_save | REG_SOC_WMSK); 353*2adcad64SLin Huang 354*2adcad64SLin Huang /* 355*2adcad64SLin Huang * gpio0, gpio1 in pmuiomux, they will keep ther value 356*2adcad64SLin Huang * when shutdown logic power rail, so only need to save gpio2 ~ gpio4 357*2adcad64SLin Huang * iomux register value 358*2adcad64SLin Huang */ 359*2adcad64SLin Huang for (i = 0; i < ARRAY_SIZE(store_grf_gpio); i++) 360*2adcad64SLin Huang store_grf_gpio[i] = 361*2adcad64SLin Huang mmio_read_32(GRF_BASE + GRF_GPIO2A_IOMUX + i * 4); 362*2adcad64SLin Huang } 363*2adcad64SLin Huang 364*2adcad64SLin Huang void plat_rockchip_restore_gpio(void) 365*2adcad64SLin Huang { 366*2adcad64SLin Huang int i; 367*2adcad64SLin Huang uint32_t cru_gate_save; 368*2adcad64SLin Huang 369*2adcad64SLin Huang for (i = 0; i < ARRAY_SIZE(store_grf_gpio); i++) 370*2adcad64SLin Huang mmio_write_32(GRF_BASE + GRF_GPIO2A_IOMUX + i * 4, 371*2adcad64SLin Huang REG_SOC_WMSK | store_grf_gpio[i]); 372*2adcad64SLin Huang 373*2adcad64SLin Huang cru_gate_save = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31)); 374*2adcad64SLin Huang 375*2adcad64SLin Huang /* 376*2adcad64SLin Huang * when shutdown logic, we need to save gpio2 ~ gpio4 register, 377*2adcad64SLin Huang * we need to enable gpio2 ~ gpio4 clock here, since it may be gating, 378*2adcad64SLin Huang * and we do not care gpio0 and gpio1 clock gate, since we never 379*2adcad64SLin Huang * gating them 380*2adcad64SLin Huang */ 381*2adcad64SLin Huang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 382*2adcad64SLin Huang BITS_WITH_WMASK(0, 0x07, PCLK_GPIO2_GATE_SHIFT)); 383*2adcad64SLin Huang 384*2adcad64SLin Huang for (i = 2; i < 5; i++) { 385*2adcad64SLin Huang mmio_write_32(gpio_port[i] + SWPORTA_DR, 386*2adcad64SLin Huang store_gpio[i - 2].swporta_dr); 387*2adcad64SLin Huang mmio_write_32(gpio_port[i] + SWPORTA_DDR, 388*2adcad64SLin Huang store_gpio[i - 2].swporta_ddr); 389*2adcad64SLin Huang mmio_write_32(gpio_port[i] + INTEN, store_gpio[i - 2].inten); 390*2adcad64SLin Huang mmio_write_32(gpio_port[i] + INTMASK, 391*2adcad64SLin Huang store_gpio[i - 2].intmask); 392*2adcad64SLin Huang mmio_write_32(gpio_port[i] + INTTYPE_LEVEL, 393*2adcad64SLin Huang store_gpio[i - 2].inttype_level); 394*2adcad64SLin Huang mmio_write_32(gpio_port[i] + INT_POLARITY, 395*2adcad64SLin Huang store_gpio[i - 2].int_polarity); 396*2adcad64SLin Huang mmio_write_32(gpio_port[i] + DEBOUNCE, 397*2adcad64SLin Huang store_gpio[i - 2].debounce); 398*2adcad64SLin Huang mmio_write_32(gpio_port[i] + LS_SYNC, 399*2adcad64SLin Huang store_gpio[i - 2].ls_sync); 400*2adcad64SLin Huang } 401*2adcad64SLin Huang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 402*2adcad64SLin Huang cru_gate_save | REG_SOC_WMSK); 403*2adcad64SLin Huang } 404*2adcad64SLin Huang 4059901dcf6SCaesar Wang const gpio_ops_t rk3399_gpio_ops = { 4069901dcf6SCaesar Wang .get_direction = get_direction, 4079901dcf6SCaesar Wang .set_direction = set_direction, 4089901dcf6SCaesar Wang .get_value = get_value, 4099901dcf6SCaesar Wang .set_value = set_value, 4109901dcf6SCaesar Wang .set_pull = set_pull, 411536c2492SCaesar Wang .get_pull = get_pull, 4129901dcf6SCaesar Wang }; 4139901dcf6SCaesar Wang 4149901dcf6SCaesar Wang void plat_rockchip_gpio_init(void) 4159901dcf6SCaesar Wang { 4169901dcf6SCaesar Wang gpio_init(&rk3399_gpio_ops); 4179901dcf6SCaesar Wang } 418