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 */ 6*09d40e0eSAntonio Nino Diaz 79901dcf6SCaesar Wang #include <assert.h> 89901dcf6SCaesar Wang #include <errno.h> 9*09d40e0eSAntonio Nino Diaz 109901dcf6SCaesar Wang #include <platform_def.h> 11*09d40e0eSAntonio Nino Diaz 12*09d40e0eSAntonio Nino Diaz #include <common/debug.h> 13*09d40e0eSAntonio Nino Diaz #include <drivers/delay_timer.h> 14*09d40e0eSAntonio Nino Diaz #include <drivers/gpio.h> 15*09d40e0eSAntonio Nino Diaz #include <lib/mmio.h> 16*09d40e0eSAntonio Nino Diaz #include <plat/common/platform.h> 17*09d40e0eSAntonio Nino Diaz 18*09d40e0eSAntonio Nino Diaz #include <plat_private.h> 199901dcf6SCaesar Wang #include <soc.h> 209901dcf6SCaesar Wang 219901dcf6SCaesar Wang uint32_t gpio_port[] = { 229901dcf6SCaesar Wang GPIO0_BASE, 239901dcf6SCaesar Wang GPIO1_BASE, 249901dcf6SCaesar Wang GPIO2_BASE, 259901dcf6SCaesar Wang GPIO3_BASE, 269901dcf6SCaesar Wang GPIO4_BASE, 279901dcf6SCaesar Wang }; 289901dcf6SCaesar Wang 292adcad64SLin Huang struct { 302adcad64SLin Huang uint32_t swporta_dr; 312adcad64SLin Huang uint32_t swporta_ddr; 322adcad64SLin Huang uint32_t inten; 332adcad64SLin Huang uint32_t intmask; 342adcad64SLin Huang uint32_t inttype_level; 352adcad64SLin Huang uint32_t int_polarity; 362adcad64SLin Huang uint32_t debounce; 372adcad64SLin Huang uint32_t ls_sync; 382adcad64SLin Huang } store_gpio[3]; 392adcad64SLin Huang 402adcad64SLin Huang static uint32_t store_grf_gpio[(GRF_GPIO2D_HE - GRF_GPIO2A_IOMUX) / 4 + 1]; 412adcad64SLin Huang 429901dcf6SCaesar Wang #define SWPORTA_DR 0x00 439901dcf6SCaesar Wang #define SWPORTA_DDR 0x04 442adcad64SLin Huang #define INTEN 0x30 452adcad64SLin Huang #define INTMASK 0x34 462adcad64SLin Huang #define INTTYPE_LEVEL 0x38 472adcad64SLin Huang #define INT_POLARITY 0x3c 482adcad64SLin Huang #define DEBOUNCE 0x48 492adcad64SLin Huang #define LS_SYNC 0x60 509901dcf6SCaesar Wang 512adcad64SLin Huang #define EXT_PORTA 0x50 529901dcf6SCaesar Wang #define PMU_GPIO_PORT0 0 539901dcf6SCaesar Wang #define PMU_GPIO_PORT1 1 54536c2492SCaesar Wang #define GPIO_PORT2 2 55536c2492SCaesar Wang #define GPIO_PORT3 3 56536c2492SCaesar Wang #define GPIO_PORT4 4 579901dcf6SCaesar Wang 589901dcf6SCaesar Wang #define PMU_GRF_GPIO0A_P 0x40 599901dcf6SCaesar Wang #define GRF_GPIO2A_P 0xe040 609901dcf6SCaesar Wang #define GPIO_P_MASK 0x03 619901dcf6SCaesar Wang 62536c2492SCaesar Wang #define GET_GPIO_PORT(pin) (pin / 32) 63536c2492SCaesar Wang #define GET_GPIO_NUM(pin) (pin % 32) 64536c2492SCaesar Wang #define GET_GPIO_BANK(pin) ((pin % 32) / 8) 65536c2492SCaesar Wang #define GET_GPIO_ID(pin) ((pin % 32) % 8) 66536c2492SCaesar Wang 67536c2492SCaesar Wang /* returns old clock state, enables clock, in order to do GPIO access */ 68536c2492SCaesar Wang static int gpio_get_clock(uint32_t gpio_number) 699901dcf6SCaesar Wang { 70536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio_number); 71536c2492SCaesar Wang uint32_t clock_state = 0; 729901dcf6SCaesar Wang 739901dcf6SCaesar Wang assert(port < 5); 749901dcf6SCaesar Wang 759901dcf6SCaesar Wang switch (port) { 76536c2492SCaesar Wang case PMU_GPIO_PORT0: 77536c2492SCaesar Wang clock_state = (mmio_read_32(PMUCRU_BASE + 78536c2492SCaesar Wang CRU_PMU_CLKGATE_CON(1)) >> 79536c2492SCaesar Wang PCLK_GPIO0_GATE_SHIFT) & 0x01; 809901dcf6SCaesar Wang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1), 81536c2492SCaesar Wang BITS_WITH_WMASK(0, CLK_GATE_MASK, 829901dcf6SCaesar Wang PCLK_GPIO0_GATE_SHIFT)); 839901dcf6SCaesar Wang break; 84536c2492SCaesar Wang case PMU_GPIO_PORT1: 85536c2492SCaesar Wang clock_state = (mmio_read_32(PMUCRU_BASE + 86536c2492SCaesar Wang CRU_PMU_CLKGATE_CON(1)) >> 87536c2492SCaesar Wang PCLK_GPIO1_GATE_SHIFT) & 0x01; 889901dcf6SCaesar Wang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1), 89536c2492SCaesar Wang BITS_WITH_WMASK(0, CLK_GATE_MASK, 909901dcf6SCaesar Wang PCLK_GPIO1_GATE_SHIFT)); 919901dcf6SCaesar Wang break; 92536c2492SCaesar Wang case GPIO_PORT2: 93536c2492SCaesar Wang clock_state = (mmio_read_32(CRU_BASE + 94536c2492SCaesar Wang CRU_CLKGATE_CON(31)) >> 95536c2492SCaesar Wang PCLK_GPIO2_GATE_SHIFT) & 0x01; 969901dcf6SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 97536c2492SCaesar Wang BITS_WITH_WMASK(0, CLK_GATE_MASK, 989901dcf6SCaesar Wang PCLK_GPIO2_GATE_SHIFT)); 999901dcf6SCaesar Wang break; 100536c2492SCaesar Wang case GPIO_PORT3: 101536c2492SCaesar Wang clock_state = (mmio_read_32(CRU_BASE + 102536c2492SCaesar Wang CRU_CLKGATE_CON(31)) >> 103536c2492SCaesar Wang PCLK_GPIO3_GATE_SHIFT) & 0x01; 1049901dcf6SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 105536c2492SCaesar Wang BITS_WITH_WMASK(0, CLK_GATE_MASK, 106536c2492SCaesar Wang PCLK_GPIO3_GATE_SHIFT)); 107536c2492SCaesar Wang break; 108536c2492SCaesar Wang case GPIO_PORT4: 109536c2492SCaesar Wang clock_state = (mmio_read_32(CRU_BASE + 110536c2492SCaesar Wang CRU_CLKGATE_CON(31)) >> 111536c2492SCaesar Wang PCLK_GPIO4_GATE_SHIFT) & 0x01; 112536c2492SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 113536c2492SCaesar Wang BITS_WITH_WMASK(0, CLK_GATE_MASK, 114536c2492SCaesar Wang PCLK_GPIO4_GATE_SHIFT)); 115536c2492SCaesar Wang break; 116536c2492SCaesar Wang default: 117536c2492SCaesar Wang break; 118536c2492SCaesar Wang } 119536c2492SCaesar Wang 120536c2492SCaesar Wang return clock_state; 121536c2492SCaesar Wang } 122536c2492SCaesar Wang 123536c2492SCaesar Wang /* restores old state of gpio clock */ 124536c2492SCaesar Wang void gpio_put_clock(uint32_t gpio_number, uint32_t clock_state) 125536c2492SCaesar Wang { 126536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio_number); 127536c2492SCaesar Wang 128536c2492SCaesar Wang switch (port) { 129536c2492SCaesar Wang case PMU_GPIO_PORT0: 130536c2492SCaesar Wang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1), 131536c2492SCaesar Wang BITS_WITH_WMASK(clock_state, CLK_GATE_MASK, 132536c2492SCaesar Wang PCLK_GPIO0_GATE_SHIFT)); 133536c2492SCaesar Wang break; 134536c2492SCaesar Wang case PMU_GPIO_PORT1: 135536c2492SCaesar Wang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1), 136536c2492SCaesar Wang BITS_WITH_WMASK(clock_state, CLK_GATE_MASK, 137536c2492SCaesar Wang PCLK_GPIO1_GATE_SHIFT)); 138536c2492SCaesar Wang break; 139536c2492SCaesar Wang case GPIO_PORT2: 140536c2492SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 141536c2492SCaesar Wang BITS_WITH_WMASK(clock_state, CLK_GATE_MASK, 142536c2492SCaesar Wang PCLK_GPIO2_GATE_SHIFT)); 143536c2492SCaesar Wang break; 144536c2492SCaesar Wang case GPIO_PORT3: 145536c2492SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 146536c2492SCaesar Wang BITS_WITH_WMASK(clock_state, CLK_GATE_MASK, 1479901dcf6SCaesar Wang PCLK_GPIO3_GATE_SHIFT)); 1489901dcf6SCaesar Wang 1499901dcf6SCaesar Wang break; 150536c2492SCaesar Wang case GPIO_PORT4: 1519901dcf6SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 152536c2492SCaesar Wang BITS_WITH_WMASK(clock_state, CLK_GATE_MASK, 1539901dcf6SCaesar Wang PCLK_GPIO4_GATE_SHIFT)); 1549901dcf6SCaesar Wang break; 1559901dcf6SCaesar Wang default: 1569901dcf6SCaesar Wang break; 1579901dcf6SCaesar Wang } 1589901dcf6SCaesar Wang } 1599901dcf6SCaesar Wang 160536c2492SCaesar Wang static int get_pull(int gpio) 1619901dcf6SCaesar Wang { 162536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio); 163536c2492SCaesar Wang uint32_t bank = GET_GPIO_BANK(gpio); 164536c2492SCaesar Wang uint32_t id = GET_GPIO_ID(gpio); 165536c2492SCaesar Wang uint32_t val, clock_state; 1669901dcf6SCaesar Wang 167536c2492SCaesar Wang assert((port < 5) && (bank < 4)); 1689901dcf6SCaesar Wang 169536c2492SCaesar Wang clock_state = gpio_get_clock(gpio); 170536c2492SCaesar Wang 171536c2492SCaesar Wang if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) { 172536c2492SCaesar Wang val = mmio_read_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P + 173536c2492SCaesar Wang port * 16 + bank * 4); 174536c2492SCaesar Wang val = (val >> (id * 2)) & GPIO_P_MASK; 175536c2492SCaesar Wang } else { 176536c2492SCaesar Wang val = mmio_read_32(GRF_BASE + GRF_GPIO2A_P + 177536c2492SCaesar Wang (port - 2) * 16 + bank * 4); 178536c2492SCaesar Wang val = (val >> (id * 2)) & GPIO_P_MASK; 179536c2492SCaesar Wang } 180536c2492SCaesar Wang gpio_put_clock(gpio, clock_state); 1819901dcf6SCaesar Wang 1829901dcf6SCaesar Wang /* 1839901dcf6SCaesar Wang * in gpio0a, gpio0b, gpio2c, gpio2d, 1849901dcf6SCaesar Wang * 00: Z 1859901dcf6SCaesar Wang * 01: pull down 1869901dcf6SCaesar Wang * 10: Z 1879901dcf6SCaesar Wang * 11: pull up 1889901dcf6SCaesar Wang * different with other gpio, so need to correct it 1899901dcf6SCaesar Wang */ 190536c2492SCaesar Wang if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) { 191536c2492SCaesar Wang if (val == 3) 192536c2492SCaesar Wang val = GPIO_PULL_UP; 193536c2492SCaesar Wang else if (val == 1) 194536c2492SCaesar Wang val = GPIO_PULL_DOWN; 195536c2492SCaesar Wang else 196536c2492SCaesar Wang val = 0; 197536c2492SCaesar Wang } 198536c2492SCaesar Wang 199536c2492SCaesar Wang return val; 200536c2492SCaesar Wang } 201536c2492SCaesar Wang 202536c2492SCaesar Wang static void set_pull(int gpio, int pull) 203536c2492SCaesar Wang { 204536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio); 205536c2492SCaesar Wang uint32_t bank = GET_GPIO_BANK(gpio); 206536c2492SCaesar Wang uint32_t id = GET_GPIO_ID(gpio); 207536c2492SCaesar Wang uint32_t clock_state; 208536c2492SCaesar Wang 209536c2492SCaesar Wang assert((port < 5) && (bank < 4)); 210536c2492SCaesar Wang 211536c2492SCaesar Wang clock_state = gpio_get_clock(gpio); 212536c2492SCaesar Wang 213536c2492SCaesar Wang /* 214536c2492SCaesar Wang * in gpio0a, gpio0b, gpio2c, gpio2d, 215536c2492SCaesar Wang * 00: Z 216536c2492SCaesar Wang * 01: pull down 217536c2492SCaesar Wang * 10: Z 218536c2492SCaesar Wang * 11: pull up 219536c2492SCaesar Wang * different with other gpio, so need to correct it 220536c2492SCaesar Wang */ 221536c2492SCaesar Wang if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) { 2229901dcf6SCaesar Wang if (pull == GPIO_PULL_UP) 2239901dcf6SCaesar Wang pull = 3; 2249901dcf6SCaesar Wang else if (pull == GPIO_PULL_DOWN) 2259901dcf6SCaesar Wang pull = 1; 2269901dcf6SCaesar Wang else 2279901dcf6SCaesar Wang pull = 0; 2289901dcf6SCaesar Wang } 2299901dcf6SCaesar Wang 2309901dcf6SCaesar Wang if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) { 2319901dcf6SCaesar Wang mmio_write_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P + 2329901dcf6SCaesar Wang port * 16 + bank * 4, 2339901dcf6SCaesar Wang BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2)); 2349901dcf6SCaesar Wang } else { 2359901dcf6SCaesar Wang mmio_write_32(GRF_BASE + GRF_GPIO2A_P + 2369901dcf6SCaesar Wang (port - 2) * 16 + bank * 4, 2379901dcf6SCaesar Wang BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2)); 2389901dcf6SCaesar Wang } 239536c2492SCaesar Wang gpio_put_clock(gpio, clock_state); 2409901dcf6SCaesar Wang } 2419901dcf6SCaesar Wang 2429901dcf6SCaesar Wang static void set_direction(int gpio, int direction) 2439901dcf6SCaesar Wang { 244536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio); 245536c2492SCaesar Wang uint32_t num = GET_GPIO_NUM(gpio); 246536c2492SCaesar Wang uint32_t clock_state; 2479901dcf6SCaesar Wang 2489901dcf6SCaesar Wang assert((port < 5) && (num < 32)); 2499901dcf6SCaesar Wang 250536c2492SCaesar Wang clock_state = gpio_get_clock(gpio); 2519901dcf6SCaesar Wang 2529901dcf6SCaesar Wang /* 2539901dcf6SCaesar Wang * in gpio.h 2549901dcf6SCaesar Wang * #define GPIO_DIR_OUT 0 2559901dcf6SCaesar Wang * #define GPIO_DIR_IN 1 2569901dcf6SCaesar Wang * but rk3399 gpio direction 1: output, 0: input 2579901dcf6SCaesar Wang * so need to revert direction value 2589901dcf6SCaesar Wang */ 2599901dcf6SCaesar Wang mmio_setbits_32(gpio_port[port] + SWPORTA_DDR, !direction << num); 260536c2492SCaesar Wang gpio_put_clock(gpio, clock_state); 2619901dcf6SCaesar Wang } 2629901dcf6SCaesar Wang 2639901dcf6SCaesar Wang static int get_direction(int gpio) 2649901dcf6SCaesar Wang { 265536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio); 266536c2492SCaesar Wang uint32_t num = GET_GPIO_NUM(gpio); 267536c2492SCaesar Wang int direction, clock_state; 2689901dcf6SCaesar Wang 2699901dcf6SCaesar Wang assert((port < 5) && (num < 32)); 2709901dcf6SCaesar Wang 271536c2492SCaesar Wang clock_state = gpio_get_clock(gpio); 2729901dcf6SCaesar Wang 2739901dcf6SCaesar Wang /* 2749901dcf6SCaesar Wang * in gpio.h 2759901dcf6SCaesar Wang * #define GPIO_DIR_OUT 0 2769901dcf6SCaesar Wang * #define GPIO_DIR_IN 1 2779901dcf6SCaesar Wang * but rk3399 gpio direction 1: output, 0: input 2789901dcf6SCaesar Wang * so need to revert direction value 2799901dcf6SCaesar Wang */ 2809901dcf6SCaesar Wang direction = !((mmio_read_32(gpio_port[port] + 2819901dcf6SCaesar Wang SWPORTA_DDR) >> num) & 0x1); 282536c2492SCaesar Wang gpio_put_clock(gpio, clock_state); 2839901dcf6SCaesar Wang 2849901dcf6SCaesar Wang return direction; 2859901dcf6SCaesar Wang } 2869901dcf6SCaesar Wang 2879901dcf6SCaesar Wang static int get_value(int gpio) 2889901dcf6SCaesar Wang { 289536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio); 290536c2492SCaesar Wang uint32_t num = GET_GPIO_NUM(gpio); 291536c2492SCaesar Wang int value, clock_state; 2929901dcf6SCaesar Wang 2939901dcf6SCaesar Wang assert((port < 5) && (num < 32)); 2949901dcf6SCaesar Wang 295536c2492SCaesar Wang clock_state = gpio_get_clock(gpio); 2969901dcf6SCaesar Wang value = (mmio_read_32(gpio_port[port] + EXT_PORTA) >> num) & 0x1; 297536c2492SCaesar Wang gpio_put_clock(gpio, clock_state); 2989901dcf6SCaesar Wang 2999901dcf6SCaesar Wang return value; 3009901dcf6SCaesar Wang } 3019901dcf6SCaesar Wang 3029901dcf6SCaesar Wang static void set_value(int gpio, int value) 3039901dcf6SCaesar Wang { 304536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio); 305536c2492SCaesar Wang uint32_t num = GET_GPIO_NUM(gpio); 306536c2492SCaesar Wang uint32_t clock_state; 3079901dcf6SCaesar Wang 3089901dcf6SCaesar Wang assert((port < 5) && (num < 32)); 3099901dcf6SCaesar Wang 310536c2492SCaesar Wang clock_state = gpio_get_clock(gpio); 3119901dcf6SCaesar Wang mmio_clrsetbits_32(gpio_port[port] + SWPORTA_DR, 1 << num, 3129901dcf6SCaesar Wang !!value << num); 313536c2492SCaesar Wang gpio_put_clock(gpio, clock_state); 3149901dcf6SCaesar Wang } 3159901dcf6SCaesar Wang 3162adcad64SLin Huang void plat_rockchip_save_gpio(void) 3172adcad64SLin Huang { 3182adcad64SLin Huang int i; 3192adcad64SLin Huang uint32_t cru_gate_save; 3202adcad64SLin Huang 3212adcad64SLin Huang cru_gate_save = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31)); 3222adcad64SLin Huang 3232adcad64SLin Huang /* 3242adcad64SLin Huang * when shutdown logic, we need to save gpio2 ~ gpio4 register, 3252adcad64SLin Huang * we need to enable gpio2 ~ gpio4 clock here, since it may be gating, 3262adcad64SLin Huang * and we do not care gpio0 and gpio1 clock gate, since we never 3272adcad64SLin Huang * gating them 3282adcad64SLin Huang */ 3292adcad64SLin Huang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 3302adcad64SLin Huang BITS_WITH_WMASK(0, 0x07, PCLK_GPIO2_GATE_SHIFT)); 3312adcad64SLin Huang 3322adcad64SLin Huang /* 3332adcad64SLin Huang * since gpio0, gpio1 are pmugpio, they will keep ther value 3342adcad64SLin Huang * when shutdown logic power rail, so only need to save gpio2 ~ gpio4 3352adcad64SLin Huang * register value 3362adcad64SLin Huang */ 3372adcad64SLin Huang for (i = 2; i < 5; i++) { 3382adcad64SLin Huang store_gpio[i - 2].swporta_dr = 3392adcad64SLin Huang mmio_read_32(gpio_port[i] + SWPORTA_DR); 3402adcad64SLin Huang store_gpio[i - 2].swporta_ddr = 3412adcad64SLin Huang mmio_read_32(gpio_port[i] + SWPORTA_DDR); 3422adcad64SLin Huang store_gpio[i - 2].inten = 3432adcad64SLin Huang mmio_read_32(gpio_port[i] + INTEN); 3442adcad64SLin Huang store_gpio[i - 2].intmask = 3452adcad64SLin Huang mmio_read_32(gpio_port[i] + INTMASK); 3462adcad64SLin Huang store_gpio[i - 2].inttype_level = 3472adcad64SLin Huang mmio_read_32(gpio_port[i] + INTTYPE_LEVEL); 3482adcad64SLin Huang store_gpio[i - 2].int_polarity = 3492adcad64SLin Huang mmio_read_32(gpio_port[i] + INT_POLARITY); 3502adcad64SLin Huang store_gpio[i - 2].debounce = 3512adcad64SLin Huang mmio_read_32(gpio_port[i] + DEBOUNCE); 3522adcad64SLin Huang store_gpio[i - 2].ls_sync = 3532adcad64SLin Huang mmio_read_32(gpio_port[i] + LS_SYNC); 3542adcad64SLin Huang } 3552adcad64SLin Huang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 3562adcad64SLin Huang cru_gate_save | REG_SOC_WMSK); 3572adcad64SLin Huang 3582adcad64SLin Huang /* 3592adcad64SLin Huang * gpio0, gpio1 in pmuiomux, they will keep ther value 3602adcad64SLin Huang * when shutdown logic power rail, so only need to save gpio2 ~ gpio4 3612adcad64SLin Huang * iomux register value 3622adcad64SLin Huang */ 3632adcad64SLin Huang for (i = 0; i < ARRAY_SIZE(store_grf_gpio); i++) 3642adcad64SLin Huang store_grf_gpio[i] = 3652adcad64SLin Huang mmio_read_32(GRF_BASE + GRF_GPIO2A_IOMUX + i * 4); 3662adcad64SLin Huang } 3672adcad64SLin Huang 3682adcad64SLin Huang void plat_rockchip_restore_gpio(void) 3692adcad64SLin Huang { 3702adcad64SLin Huang int i; 3712adcad64SLin Huang uint32_t cru_gate_save; 3722adcad64SLin Huang 3732adcad64SLin Huang for (i = 0; i < ARRAY_SIZE(store_grf_gpio); i++) 3742adcad64SLin Huang mmio_write_32(GRF_BASE + GRF_GPIO2A_IOMUX + i * 4, 3752adcad64SLin Huang REG_SOC_WMSK | store_grf_gpio[i]); 3762adcad64SLin Huang 3772adcad64SLin Huang cru_gate_save = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31)); 3782adcad64SLin Huang 3792adcad64SLin Huang /* 3802adcad64SLin Huang * when shutdown logic, we need to save gpio2 ~ gpio4 register, 3812adcad64SLin Huang * we need to enable gpio2 ~ gpio4 clock here, since it may be gating, 3822adcad64SLin Huang * and we do not care gpio0 and gpio1 clock gate, since we never 3832adcad64SLin Huang * gating them 3842adcad64SLin Huang */ 3852adcad64SLin Huang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 3862adcad64SLin Huang BITS_WITH_WMASK(0, 0x07, PCLK_GPIO2_GATE_SHIFT)); 3872adcad64SLin Huang 3882adcad64SLin Huang for (i = 2; i < 5; i++) { 3892adcad64SLin Huang mmio_write_32(gpio_port[i] + SWPORTA_DR, 3902adcad64SLin Huang store_gpio[i - 2].swporta_dr); 3912adcad64SLin Huang mmio_write_32(gpio_port[i] + SWPORTA_DDR, 3922adcad64SLin Huang store_gpio[i - 2].swporta_ddr); 3932adcad64SLin Huang mmio_write_32(gpio_port[i] + INTEN, store_gpio[i - 2].inten); 3942adcad64SLin Huang mmio_write_32(gpio_port[i] + INTMASK, 3952adcad64SLin Huang store_gpio[i - 2].intmask); 3962adcad64SLin Huang mmio_write_32(gpio_port[i] + INTTYPE_LEVEL, 3972adcad64SLin Huang store_gpio[i - 2].inttype_level); 3982adcad64SLin Huang mmio_write_32(gpio_port[i] + INT_POLARITY, 3992adcad64SLin Huang store_gpio[i - 2].int_polarity); 4002adcad64SLin Huang mmio_write_32(gpio_port[i] + DEBOUNCE, 4012adcad64SLin Huang store_gpio[i - 2].debounce); 4022adcad64SLin Huang mmio_write_32(gpio_port[i] + LS_SYNC, 4032adcad64SLin Huang store_gpio[i - 2].ls_sync); 4042adcad64SLin Huang } 4052adcad64SLin Huang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 4062adcad64SLin Huang cru_gate_save | REG_SOC_WMSK); 4072adcad64SLin Huang } 4082adcad64SLin Huang 4099901dcf6SCaesar Wang const gpio_ops_t rk3399_gpio_ops = { 4109901dcf6SCaesar Wang .get_direction = get_direction, 4119901dcf6SCaesar Wang .set_direction = set_direction, 4129901dcf6SCaesar Wang .get_value = get_value, 4139901dcf6SCaesar Wang .set_value = set_value, 4149901dcf6SCaesar Wang .set_pull = set_pull, 415536c2492SCaesar Wang .get_pull = get_pull, 4169901dcf6SCaesar Wang }; 4179901dcf6SCaesar Wang 4189901dcf6SCaesar Wang void plat_rockchip_gpio_init(void) 4199901dcf6SCaesar Wang { 4209901dcf6SCaesar Wang gpio_init(&rk3399_gpio_ops); 4219901dcf6SCaesar Wang } 422