19901dcf6SCaesar Wang /* 29901dcf6SCaesar Wang * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. 39901dcf6SCaesar Wang * 49901dcf6SCaesar Wang * Redistribution and use in source and binary forms, with or without 59901dcf6SCaesar Wang * modification, are permitted provided that the following conditions are met: 69901dcf6SCaesar Wang * 79901dcf6SCaesar Wang * Redistributions of source code must retain the above copyright notice, this 89901dcf6SCaesar Wang * list of conditions and the following disclaimer. 99901dcf6SCaesar Wang * 109901dcf6SCaesar Wang * Redistributions in binary form must reproduce the above copyright notice, 119901dcf6SCaesar Wang * this list of conditions and the following disclaimer in the documentation 129901dcf6SCaesar Wang * and/or other materials provided with the distribution. 139901dcf6SCaesar Wang * 149901dcf6SCaesar Wang * Neither the name of ARM nor the names of its contributors may be used 159901dcf6SCaesar Wang * to endorse or promote products derived from this software without specific 169901dcf6SCaesar Wang * prior written permission. 179901dcf6SCaesar Wang * 189901dcf6SCaesar Wang * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 199901dcf6SCaesar Wang * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 209901dcf6SCaesar Wang * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 219901dcf6SCaesar Wang * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 229901dcf6SCaesar Wang * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 239901dcf6SCaesar Wang * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 249901dcf6SCaesar Wang * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 259901dcf6SCaesar Wang * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 269901dcf6SCaesar Wang * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 279901dcf6SCaesar Wang * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 289901dcf6SCaesar Wang * POSSIBILITY OF SUCH DAMAGE. 299901dcf6SCaesar Wang */ 309901dcf6SCaesar Wang #include <assert.h> 319901dcf6SCaesar Wang #include <debug.h> 329901dcf6SCaesar Wang #include <delay_timer.h> 339901dcf6SCaesar Wang #include <errno.h> 349901dcf6SCaesar Wang #include <gpio.h> 359901dcf6SCaesar Wang #include <mmio.h> 369901dcf6SCaesar Wang #include <platform.h> 379901dcf6SCaesar Wang #include <platform_def.h> 389901dcf6SCaesar Wang #include <plat_private.h> 399901dcf6SCaesar Wang #include <soc.h> 409901dcf6SCaesar Wang 419901dcf6SCaesar Wang uint32_t gpio_port[] = { 429901dcf6SCaesar Wang GPIO0_BASE, 439901dcf6SCaesar Wang GPIO1_BASE, 449901dcf6SCaesar Wang GPIO2_BASE, 459901dcf6SCaesar Wang GPIO3_BASE, 469901dcf6SCaesar Wang GPIO4_BASE, 479901dcf6SCaesar Wang }; 489901dcf6SCaesar Wang 499901dcf6SCaesar Wang #define SWPORTA_DR 0x00 509901dcf6SCaesar Wang #define SWPORTA_DDR 0x04 519901dcf6SCaesar Wang #define EXT_PORTA 0x50 529901dcf6SCaesar Wang 539901dcf6SCaesar Wang #define PMU_GPIO_PORT0 0 549901dcf6SCaesar Wang #define PMU_GPIO_PORT1 1 55*536c2492SCaesar Wang #define GPIO_PORT2 2 56*536c2492SCaesar Wang #define GPIO_PORT3 3 57*536c2492SCaesar Wang #define GPIO_PORT4 4 589901dcf6SCaesar Wang 599901dcf6SCaesar Wang #define PMU_GRF_GPIO0A_P 0x40 609901dcf6SCaesar Wang #define GRF_GPIO2A_P 0xe040 619901dcf6SCaesar Wang #define GPIO_P_MASK 0x03 629901dcf6SCaesar Wang 63*536c2492SCaesar Wang #define GET_GPIO_PORT(pin) (pin / 32) 64*536c2492SCaesar Wang #define GET_GPIO_NUM(pin) (pin % 32) 65*536c2492SCaesar Wang #define GET_GPIO_BANK(pin) ((pin % 32) / 8) 66*536c2492SCaesar Wang #define GET_GPIO_ID(pin) ((pin % 32) % 8) 67*536c2492SCaesar Wang 68*536c2492SCaesar Wang /* returns old clock state, enables clock, in order to do GPIO access */ 69*536c2492SCaesar Wang static int gpio_get_clock(uint32_t gpio_number) 709901dcf6SCaesar Wang { 71*536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio_number); 72*536c2492SCaesar Wang uint32_t clock_state = 0; 739901dcf6SCaesar Wang 749901dcf6SCaesar Wang assert(port < 5); 759901dcf6SCaesar Wang 769901dcf6SCaesar Wang switch (port) { 77*536c2492SCaesar Wang case PMU_GPIO_PORT0: 78*536c2492SCaesar Wang clock_state = (mmio_read_32(PMUCRU_BASE + 79*536c2492SCaesar Wang CRU_PMU_CLKGATE_CON(1)) >> 80*536c2492SCaesar Wang PCLK_GPIO0_GATE_SHIFT) & 0x01; 819901dcf6SCaesar Wang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1), 82*536c2492SCaesar Wang BITS_WITH_WMASK(0, CLK_GATE_MASK, 839901dcf6SCaesar Wang PCLK_GPIO0_GATE_SHIFT)); 849901dcf6SCaesar Wang break; 85*536c2492SCaesar Wang case PMU_GPIO_PORT1: 86*536c2492SCaesar Wang clock_state = (mmio_read_32(PMUCRU_BASE + 87*536c2492SCaesar Wang CRU_PMU_CLKGATE_CON(1)) >> 88*536c2492SCaesar Wang PCLK_GPIO1_GATE_SHIFT) & 0x01; 899901dcf6SCaesar Wang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1), 90*536c2492SCaesar Wang BITS_WITH_WMASK(0, CLK_GATE_MASK, 919901dcf6SCaesar Wang PCLK_GPIO1_GATE_SHIFT)); 929901dcf6SCaesar Wang break; 93*536c2492SCaesar Wang case GPIO_PORT2: 94*536c2492SCaesar Wang clock_state = (mmio_read_32(CRU_BASE + 95*536c2492SCaesar Wang CRU_CLKGATE_CON(31)) >> 96*536c2492SCaesar Wang PCLK_GPIO2_GATE_SHIFT) & 0x01; 979901dcf6SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 98*536c2492SCaesar Wang BITS_WITH_WMASK(0, CLK_GATE_MASK, 999901dcf6SCaesar Wang PCLK_GPIO2_GATE_SHIFT)); 1009901dcf6SCaesar Wang break; 101*536c2492SCaesar Wang case GPIO_PORT3: 102*536c2492SCaesar Wang clock_state = (mmio_read_32(CRU_BASE + 103*536c2492SCaesar Wang CRU_CLKGATE_CON(31)) >> 104*536c2492SCaesar Wang PCLK_GPIO3_GATE_SHIFT) & 0x01; 1059901dcf6SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 106*536c2492SCaesar Wang BITS_WITH_WMASK(0, CLK_GATE_MASK, 107*536c2492SCaesar Wang PCLK_GPIO3_GATE_SHIFT)); 108*536c2492SCaesar Wang break; 109*536c2492SCaesar Wang case GPIO_PORT4: 110*536c2492SCaesar Wang clock_state = (mmio_read_32(CRU_BASE + 111*536c2492SCaesar Wang CRU_CLKGATE_CON(31)) >> 112*536c2492SCaesar Wang PCLK_GPIO4_GATE_SHIFT) & 0x01; 113*536c2492SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 114*536c2492SCaesar Wang BITS_WITH_WMASK(0, CLK_GATE_MASK, 115*536c2492SCaesar Wang PCLK_GPIO4_GATE_SHIFT)); 116*536c2492SCaesar Wang break; 117*536c2492SCaesar Wang default: 118*536c2492SCaesar Wang break; 119*536c2492SCaesar Wang } 120*536c2492SCaesar Wang 121*536c2492SCaesar Wang return clock_state; 122*536c2492SCaesar Wang } 123*536c2492SCaesar Wang 124*536c2492SCaesar Wang /* restores old state of gpio clock */ 125*536c2492SCaesar Wang void gpio_put_clock(uint32_t gpio_number, uint32_t clock_state) 126*536c2492SCaesar Wang { 127*536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio_number); 128*536c2492SCaesar Wang 129*536c2492SCaesar Wang switch (port) { 130*536c2492SCaesar Wang case PMU_GPIO_PORT0: 131*536c2492SCaesar Wang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1), 132*536c2492SCaesar Wang BITS_WITH_WMASK(clock_state, CLK_GATE_MASK, 133*536c2492SCaesar Wang PCLK_GPIO0_GATE_SHIFT)); 134*536c2492SCaesar Wang break; 135*536c2492SCaesar Wang case PMU_GPIO_PORT1: 136*536c2492SCaesar Wang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1), 137*536c2492SCaesar Wang BITS_WITH_WMASK(clock_state, CLK_GATE_MASK, 138*536c2492SCaesar Wang PCLK_GPIO1_GATE_SHIFT)); 139*536c2492SCaesar Wang break; 140*536c2492SCaesar Wang case GPIO_PORT2: 141*536c2492SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 142*536c2492SCaesar Wang BITS_WITH_WMASK(clock_state, CLK_GATE_MASK, 143*536c2492SCaesar Wang PCLK_GPIO2_GATE_SHIFT)); 144*536c2492SCaesar Wang break; 145*536c2492SCaesar Wang case GPIO_PORT3: 146*536c2492SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 147*536c2492SCaesar Wang BITS_WITH_WMASK(clock_state, CLK_GATE_MASK, 1489901dcf6SCaesar Wang PCLK_GPIO3_GATE_SHIFT)); 1499901dcf6SCaesar Wang 1509901dcf6SCaesar Wang break; 151*536c2492SCaesar Wang case GPIO_PORT4: 1529901dcf6SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 153*536c2492SCaesar Wang BITS_WITH_WMASK(clock_state, CLK_GATE_MASK, 1549901dcf6SCaesar Wang PCLK_GPIO4_GATE_SHIFT)); 1559901dcf6SCaesar Wang break; 1569901dcf6SCaesar Wang default: 1579901dcf6SCaesar Wang break; 1589901dcf6SCaesar Wang } 1599901dcf6SCaesar Wang } 1609901dcf6SCaesar Wang 161*536c2492SCaesar Wang static int get_pull(int gpio) 1629901dcf6SCaesar Wang { 163*536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio); 164*536c2492SCaesar Wang uint32_t bank = GET_GPIO_BANK(gpio); 165*536c2492SCaesar Wang uint32_t id = GET_GPIO_ID(gpio); 166*536c2492SCaesar Wang uint32_t val, clock_state; 1679901dcf6SCaesar Wang 168*536c2492SCaesar Wang assert((port < 5) && (bank < 4)); 1699901dcf6SCaesar Wang 170*536c2492SCaesar Wang clock_state = gpio_get_clock(gpio); 171*536c2492SCaesar Wang 172*536c2492SCaesar Wang if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) { 173*536c2492SCaesar Wang val = mmio_read_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P + 174*536c2492SCaesar Wang port * 16 + bank * 4); 175*536c2492SCaesar Wang val = (val >> (id * 2)) & GPIO_P_MASK; 176*536c2492SCaesar Wang } else { 177*536c2492SCaesar Wang val = mmio_read_32(GRF_BASE + GRF_GPIO2A_P + 178*536c2492SCaesar Wang (port - 2) * 16 + bank * 4); 179*536c2492SCaesar Wang val = (val >> (id * 2)) & GPIO_P_MASK; 180*536c2492SCaesar Wang } 181*536c2492SCaesar Wang gpio_put_clock(gpio, clock_state); 1829901dcf6SCaesar Wang 1839901dcf6SCaesar Wang /* 1849901dcf6SCaesar Wang * in gpio0a, gpio0b, gpio2c, gpio2d, 1859901dcf6SCaesar Wang * 00: Z 1869901dcf6SCaesar Wang * 01: pull down 1879901dcf6SCaesar Wang * 10: Z 1889901dcf6SCaesar Wang * 11: pull up 1899901dcf6SCaesar Wang * different with other gpio, so need to correct it 1909901dcf6SCaesar Wang */ 191*536c2492SCaesar Wang if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) { 192*536c2492SCaesar Wang if (val == 3) 193*536c2492SCaesar Wang val = GPIO_PULL_UP; 194*536c2492SCaesar Wang else if (val == 1) 195*536c2492SCaesar Wang val = GPIO_PULL_DOWN; 196*536c2492SCaesar Wang else 197*536c2492SCaesar Wang val = 0; 198*536c2492SCaesar Wang } 199*536c2492SCaesar Wang 200*536c2492SCaesar Wang return val; 201*536c2492SCaesar Wang } 202*536c2492SCaesar Wang 203*536c2492SCaesar Wang static void set_pull(int gpio, int pull) 204*536c2492SCaesar Wang { 205*536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio); 206*536c2492SCaesar Wang uint32_t bank = GET_GPIO_BANK(gpio); 207*536c2492SCaesar Wang uint32_t id = GET_GPIO_ID(gpio); 208*536c2492SCaesar Wang uint32_t clock_state; 209*536c2492SCaesar Wang 210*536c2492SCaesar Wang assert((port < 5) && (bank < 4)); 211*536c2492SCaesar Wang 212*536c2492SCaesar Wang clock_state = gpio_get_clock(gpio); 213*536c2492SCaesar Wang 214*536c2492SCaesar Wang /* 215*536c2492SCaesar Wang * in gpio0a, gpio0b, gpio2c, gpio2d, 216*536c2492SCaesar Wang * 00: Z 217*536c2492SCaesar Wang * 01: pull down 218*536c2492SCaesar Wang * 10: Z 219*536c2492SCaesar Wang * 11: pull up 220*536c2492SCaesar Wang * different with other gpio, so need to correct it 221*536c2492SCaesar Wang */ 222*536c2492SCaesar Wang if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) { 2239901dcf6SCaesar Wang if (pull == GPIO_PULL_UP) 2249901dcf6SCaesar Wang pull = 3; 2259901dcf6SCaesar Wang else if (pull == GPIO_PULL_DOWN) 2269901dcf6SCaesar Wang pull = 1; 2279901dcf6SCaesar Wang else 2289901dcf6SCaesar Wang pull = 0; 2299901dcf6SCaesar Wang } 2309901dcf6SCaesar Wang 2319901dcf6SCaesar Wang if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) { 2329901dcf6SCaesar Wang mmio_write_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P + 2339901dcf6SCaesar Wang port * 16 + bank * 4, 2349901dcf6SCaesar Wang BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2)); 2359901dcf6SCaesar Wang } else { 2369901dcf6SCaesar Wang mmio_write_32(GRF_BASE + GRF_GPIO2A_P + 2379901dcf6SCaesar Wang (port - 2) * 16 + bank * 4, 2389901dcf6SCaesar Wang BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2)); 2399901dcf6SCaesar Wang } 240*536c2492SCaesar Wang gpio_put_clock(gpio, clock_state); 2419901dcf6SCaesar Wang } 2429901dcf6SCaesar Wang 2439901dcf6SCaesar Wang static void set_direction(int gpio, int direction) 2449901dcf6SCaesar Wang { 245*536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio); 246*536c2492SCaesar Wang uint32_t num = GET_GPIO_NUM(gpio); 247*536c2492SCaesar Wang uint32_t clock_state; 2489901dcf6SCaesar Wang 2499901dcf6SCaesar Wang assert((port < 5) && (num < 32)); 2509901dcf6SCaesar Wang 251*536c2492SCaesar Wang clock_state = gpio_get_clock(gpio); 2529901dcf6SCaesar Wang 2539901dcf6SCaesar Wang /* 2549901dcf6SCaesar Wang * in gpio.h 2559901dcf6SCaesar Wang * #define GPIO_DIR_OUT 0 2569901dcf6SCaesar Wang * #define GPIO_DIR_IN 1 2579901dcf6SCaesar Wang * but rk3399 gpio direction 1: output, 0: input 2589901dcf6SCaesar Wang * so need to revert direction value 2599901dcf6SCaesar Wang */ 2609901dcf6SCaesar Wang mmio_setbits_32(gpio_port[port] + SWPORTA_DDR, !direction << num); 261*536c2492SCaesar Wang gpio_put_clock(gpio, clock_state); 2629901dcf6SCaesar Wang } 2639901dcf6SCaesar Wang 2649901dcf6SCaesar Wang static int get_direction(int gpio) 2659901dcf6SCaesar Wang { 266*536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio); 267*536c2492SCaesar Wang uint32_t num = GET_GPIO_NUM(gpio); 268*536c2492SCaesar Wang int direction, clock_state; 2699901dcf6SCaesar Wang 2709901dcf6SCaesar Wang assert((port < 5) && (num < 32)); 2719901dcf6SCaesar Wang 272*536c2492SCaesar Wang clock_state = gpio_get_clock(gpio); 2739901dcf6SCaesar Wang 2749901dcf6SCaesar Wang /* 2759901dcf6SCaesar Wang * in gpio.h 2769901dcf6SCaesar Wang * #define GPIO_DIR_OUT 0 2779901dcf6SCaesar Wang * #define GPIO_DIR_IN 1 2789901dcf6SCaesar Wang * but rk3399 gpio direction 1: output, 0: input 2799901dcf6SCaesar Wang * so need to revert direction value 2809901dcf6SCaesar Wang */ 2819901dcf6SCaesar Wang direction = !((mmio_read_32(gpio_port[port] + 2829901dcf6SCaesar Wang SWPORTA_DDR) >> num) & 0x1); 283*536c2492SCaesar Wang gpio_put_clock(gpio, clock_state); 2849901dcf6SCaesar Wang 2859901dcf6SCaesar Wang return direction; 2869901dcf6SCaesar Wang } 2879901dcf6SCaesar Wang 2889901dcf6SCaesar Wang static int get_value(int gpio) 2899901dcf6SCaesar Wang { 290*536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio); 291*536c2492SCaesar Wang uint32_t num = GET_GPIO_NUM(gpio); 292*536c2492SCaesar Wang int value, clock_state; 2939901dcf6SCaesar Wang 2949901dcf6SCaesar Wang assert((port < 5) && (num < 32)); 2959901dcf6SCaesar Wang 296*536c2492SCaesar Wang clock_state = gpio_get_clock(gpio); 2979901dcf6SCaesar Wang value = (mmio_read_32(gpio_port[port] + EXT_PORTA) >> num) & 0x1; 298*536c2492SCaesar Wang gpio_put_clock(gpio, clock_state); 2999901dcf6SCaesar Wang 3009901dcf6SCaesar Wang return value; 3019901dcf6SCaesar Wang } 3029901dcf6SCaesar Wang 3039901dcf6SCaesar Wang static void set_value(int gpio, int value) 3049901dcf6SCaesar Wang { 305*536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio); 306*536c2492SCaesar Wang uint32_t num = GET_GPIO_NUM(gpio); 307*536c2492SCaesar Wang uint32_t clock_state; 3089901dcf6SCaesar Wang 3099901dcf6SCaesar Wang assert((port < 5) && (num < 32)); 3109901dcf6SCaesar Wang 311*536c2492SCaesar Wang clock_state = gpio_get_clock(gpio); 3129901dcf6SCaesar Wang mmio_clrsetbits_32(gpio_port[port] + SWPORTA_DR, 1 << num, 3139901dcf6SCaesar Wang !!value << num); 314*536c2492SCaesar Wang gpio_put_clock(gpio, clock_state); 3159901dcf6SCaesar Wang } 3169901dcf6SCaesar Wang 3179901dcf6SCaesar Wang const gpio_ops_t rk3399_gpio_ops = { 3189901dcf6SCaesar Wang .get_direction = get_direction, 3199901dcf6SCaesar Wang .set_direction = set_direction, 3209901dcf6SCaesar Wang .get_value = get_value, 3219901dcf6SCaesar Wang .set_value = set_value, 3229901dcf6SCaesar Wang .set_pull = set_pull, 323*536c2492SCaesar Wang .get_pull = get_pull, 3249901dcf6SCaesar Wang }; 3259901dcf6SCaesar Wang 3269901dcf6SCaesar Wang void plat_rockchip_gpio_init(void) 3279901dcf6SCaesar Wang { 3289901dcf6SCaesar Wang gpio_init(&rk3399_gpio_ops); 3299901dcf6SCaesar Wang } 330