19901dcf6SCaesar Wang /* 29901dcf6SCaesar Wang * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. 39901dcf6SCaesar Wang * 4*82cb2c1aSdp-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> 129901dcf6SCaesar Wang #include <platform.h> 139901dcf6SCaesar Wang #include <platform_def.h> 149901dcf6SCaesar Wang #include <plat_private.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 259901dcf6SCaesar Wang #define SWPORTA_DR 0x00 269901dcf6SCaesar Wang #define SWPORTA_DDR 0x04 279901dcf6SCaesar Wang #define EXT_PORTA 0x50 289901dcf6SCaesar Wang 299901dcf6SCaesar Wang #define PMU_GPIO_PORT0 0 309901dcf6SCaesar Wang #define PMU_GPIO_PORT1 1 31536c2492SCaesar Wang #define GPIO_PORT2 2 32536c2492SCaesar Wang #define GPIO_PORT3 3 33536c2492SCaesar Wang #define GPIO_PORT4 4 349901dcf6SCaesar Wang 359901dcf6SCaesar Wang #define PMU_GRF_GPIO0A_P 0x40 369901dcf6SCaesar Wang #define GRF_GPIO2A_P 0xe040 379901dcf6SCaesar Wang #define GPIO_P_MASK 0x03 389901dcf6SCaesar Wang 39536c2492SCaesar Wang #define GET_GPIO_PORT(pin) (pin / 32) 40536c2492SCaesar Wang #define GET_GPIO_NUM(pin) (pin % 32) 41536c2492SCaesar Wang #define GET_GPIO_BANK(pin) ((pin % 32) / 8) 42536c2492SCaesar Wang #define GET_GPIO_ID(pin) ((pin % 32) % 8) 43536c2492SCaesar Wang 44536c2492SCaesar Wang /* returns old clock state, enables clock, in order to do GPIO access */ 45536c2492SCaesar Wang static int gpio_get_clock(uint32_t gpio_number) 469901dcf6SCaesar Wang { 47536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio_number); 48536c2492SCaesar Wang uint32_t clock_state = 0; 499901dcf6SCaesar Wang 509901dcf6SCaesar Wang assert(port < 5); 519901dcf6SCaesar Wang 529901dcf6SCaesar Wang switch (port) { 53536c2492SCaesar Wang case PMU_GPIO_PORT0: 54536c2492SCaesar Wang clock_state = (mmio_read_32(PMUCRU_BASE + 55536c2492SCaesar Wang CRU_PMU_CLKGATE_CON(1)) >> 56536c2492SCaesar Wang PCLK_GPIO0_GATE_SHIFT) & 0x01; 579901dcf6SCaesar Wang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1), 58536c2492SCaesar Wang BITS_WITH_WMASK(0, CLK_GATE_MASK, 599901dcf6SCaesar Wang PCLK_GPIO0_GATE_SHIFT)); 609901dcf6SCaesar Wang break; 61536c2492SCaesar Wang case PMU_GPIO_PORT1: 62536c2492SCaesar Wang clock_state = (mmio_read_32(PMUCRU_BASE + 63536c2492SCaesar Wang CRU_PMU_CLKGATE_CON(1)) >> 64536c2492SCaesar Wang PCLK_GPIO1_GATE_SHIFT) & 0x01; 659901dcf6SCaesar Wang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1), 66536c2492SCaesar Wang BITS_WITH_WMASK(0, CLK_GATE_MASK, 679901dcf6SCaesar Wang PCLK_GPIO1_GATE_SHIFT)); 689901dcf6SCaesar Wang break; 69536c2492SCaesar Wang case GPIO_PORT2: 70536c2492SCaesar Wang clock_state = (mmio_read_32(CRU_BASE + 71536c2492SCaesar Wang CRU_CLKGATE_CON(31)) >> 72536c2492SCaesar Wang PCLK_GPIO2_GATE_SHIFT) & 0x01; 739901dcf6SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 74536c2492SCaesar Wang BITS_WITH_WMASK(0, CLK_GATE_MASK, 759901dcf6SCaesar Wang PCLK_GPIO2_GATE_SHIFT)); 769901dcf6SCaesar Wang break; 77536c2492SCaesar Wang case GPIO_PORT3: 78536c2492SCaesar Wang clock_state = (mmio_read_32(CRU_BASE + 79536c2492SCaesar Wang CRU_CLKGATE_CON(31)) >> 80536c2492SCaesar Wang PCLK_GPIO3_GATE_SHIFT) & 0x01; 819901dcf6SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 82536c2492SCaesar Wang BITS_WITH_WMASK(0, CLK_GATE_MASK, 83536c2492SCaesar Wang PCLK_GPIO3_GATE_SHIFT)); 84536c2492SCaesar Wang break; 85536c2492SCaesar Wang case GPIO_PORT4: 86536c2492SCaesar Wang clock_state = (mmio_read_32(CRU_BASE + 87536c2492SCaesar Wang CRU_CLKGATE_CON(31)) >> 88536c2492SCaesar Wang PCLK_GPIO4_GATE_SHIFT) & 0x01; 89536c2492SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 90536c2492SCaesar Wang BITS_WITH_WMASK(0, CLK_GATE_MASK, 91536c2492SCaesar Wang PCLK_GPIO4_GATE_SHIFT)); 92536c2492SCaesar Wang break; 93536c2492SCaesar Wang default: 94536c2492SCaesar Wang break; 95536c2492SCaesar Wang } 96536c2492SCaesar Wang 97536c2492SCaesar Wang return clock_state; 98536c2492SCaesar Wang } 99536c2492SCaesar Wang 100536c2492SCaesar Wang /* restores old state of gpio clock */ 101536c2492SCaesar Wang void gpio_put_clock(uint32_t gpio_number, uint32_t clock_state) 102536c2492SCaesar Wang { 103536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio_number); 104536c2492SCaesar Wang 105536c2492SCaesar Wang switch (port) { 106536c2492SCaesar Wang case PMU_GPIO_PORT0: 107536c2492SCaesar Wang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1), 108536c2492SCaesar Wang BITS_WITH_WMASK(clock_state, CLK_GATE_MASK, 109536c2492SCaesar Wang PCLK_GPIO0_GATE_SHIFT)); 110536c2492SCaesar Wang break; 111536c2492SCaesar Wang case PMU_GPIO_PORT1: 112536c2492SCaesar Wang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1), 113536c2492SCaesar Wang BITS_WITH_WMASK(clock_state, CLK_GATE_MASK, 114536c2492SCaesar Wang PCLK_GPIO1_GATE_SHIFT)); 115536c2492SCaesar Wang break; 116536c2492SCaesar Wang case GPIO_PORT2: 117536c2492SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 118536c2492SCaesar Wang BITS_WITH_WMASK(clock_state, CLK_GATE_MASK, 119536c2492SCaesar Wang PCLK_GPIO2_GATE_SHIFT)); 120536c2492SCaesar Wang break; 121536c2492SCaesar Wang case GPIO_PORT3: 122536c2492SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 123536c2492SCaesar Wang BITS_WITH_WMASK(clock_state, CLK_GATE_MASK, 1249901dcf6SCaesar Wang PCLK_GPIO3_GATE_SHIFT)); 1259901dcf6SCaesar Wang 1269901dcf6SCaesar Wang break; 127536c2492SCaesar Wang case GPIO_PORT4: 1289901dcf6SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 129536c2492SCaesar Wang BITS_WITH_WMASK(clock_state, CLK_GATE_MASK, 1309901dcf6SCaesar Wang PCLK_GPIO4_GATE_SHIFT)); 1319901dcf6SCaesar Wang break; 1329901dcf6SCaesar Wang default: 1339901dcf6SCaesar Wang break; 1349901dcf6SCaesar Wang } 1359901dcf6SCaesar Wang } 1369901dcf6SCaesar Wang 137536c2492SCaesar Wang static int get_pull(int gpio) 1389901dcf6SCaesar Wang { 139536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio); 140536c2492SCaesar Wang uint32_t bank = GET_GPIO_BANK(gpio); 141536c2492SCaesar Wang uint32_t id = GET_GPIO_ID(gpio); 142536c2492SCaesar Wang uint32_t val, clock_state; 1439901dcf6SCaesar Wang 144536c2492SCaesar Wang assert((port < 5) && (bank < 4)); 1459901dcf6SCaesar Wang 146536c2492SCaesar Wang clock_state = gpio_get_clock(gpio); 147536c2492SCaesar Wang 148536c2492SCaesar Wang if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) { 149536c2492SCaesar Wang val = mmio_read_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P + 150536c2492SCaesar Wang port * 16 + bank * 4); 151536c2492SCaesar Wang val = (val >> (id * 2)) & GPIO_P_MASK; 152536c2492SCaesar Wang } else { 153536c2492SCaesar Wang val = mmio_read_32(GRF_BASE + GRF_GPIO2A_P + 154536c2492SCaesar Wang (port - 2) * 16 + bank * 4); 155536c2492SCaesar Wang val = (val >> (id * 2)) & GPIO_P_MASK; 156536c2492SCaesar Wang } 157536c2492SCaesar Wang gpio_put_clock(gpio, clock_state); 1589901dcf6SCaesar Wang 1599901dcf6SCaesar Wang /* 1609901dcf6SCaesar Wang * in gpio0a, gpio0b, gpio2c, gpio2d, 1619901dcf6SCaesar Wang * 00: Z 1629901dcf6SCaesar Wang * 01: pull down 1639901dcf6SCaesar Wang * 10: Z 1649901dcf6SCaesar Wang * 11: pull up 1659901dcf6SCaesar Wang * different with other gpio, so need to correct it 1669901dcf6SCaesar Wang */ 167536c2492SCaesar Wang if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) { 168536c2492SCaesar Wang if (val == 3) 169536c2492SCaesar Wang val = GPIO_PULL_UP; 170536c2492SCaesar Wang else if (val == 1) 171536c2492SCaesar Wang val = GPIO_PULL_DOWN; 172536c2492SCaesar Wang else 173536c2492SCaesar Wang val = 0; 174536c2492SCaesar Wang } 175536c2492SCaesar Wang 176536c2492SCaesar Wang return val; 177536c2492SCaesar Wang } 178536c2492SCaesar Wang 179536c2492SCaesar Wang static void set_pull(int gpio, int pull) 180536c2492SCaesar Wang { 181536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio); 182536c2492SCaesar Wang uint32_t bank = GET_GPIO_BANK(gpio); 183536c2492SCaesar Wang uint32_t id = GET_GPIO_ID(gpio); 184536c2492SCaesar Wang uint32_t clock_state; 185536c2492SCaesar Wang 186536c2492SCaesar Wang assert((port < 5) && (bank < 4)); 187536c2492SCaesar Wang 188536c2492SCaesar Wang clock_state = gpio_get_clock(gpio); 189536c2492SCaesar Wang 190536c2492SCaesar Wang /* 191536c2492SCaesar Wang * in gpio0a, gpio0b, gpio2c, gpio2d, 192536c2492SCaesar Wang * 00: Z 193536c2492SCaesar Wang * 01: pull down 194536c2492SCaesar Wang * 10: Z 195536c2492SCaesar Wang * 11: pull up 196536c2492SCaesar Wang * different with other gpio, so need to correct it 197536c2492SCaesar Wang */ 198536c2492SCaesar Wang if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) { 1999901dcf6SCaesar Wang if (pull == GPIO_PULL_UP) 2009901dcf6SCaesar Wang pull = 3; 2019901dcf6SCaesar Wang else if (pull == GPIO_PULL_DOWN) 2029901dcf6SCaesar Wang pull = 1; 2039901dcf6SCaesar Wang else 2049901dcf6SCaesar Wang pull = 0; 2059901dcf6SCaesar Wang } 2069901dcf6SCaesar Wang 2079901dcf6SCaesar Wang if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) { 2089901dcf6SCaesar Wang mmio_write_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P + 2099901dcf6SCaesar Wang port * 16 + bank * 4, 2109901dcf6SCaesar Wang BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2)); 2119901dcf6SCaesar Wang } else { 2129901dcf6SCaesar Wang mmio_write_32(GRF_BASE + GRF_GPIO2A_P + 2139901dcf6SCaesar Wang (port - 2) * 16 + bank * 4, 2149901dcf6SCaesar Wang BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2)); 2159901dcf6SCaesar Wang } 216536c2492SCaesar Wang gpio_put_clock(gpio, clock_state); 2179901dcf6SCaesar Wang } 2189901dcf6SCaesar Wang 2199901dcf6SCaesar Wang static void set_direction(int gpio, int direction) 2209901dcf6SCaesar Wang { 221536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio); 222536c2492SCaesar Wang uint32_t num = GET_GPIO_NUM(gpio); 223536c2492SCaesar Wang uint32_t clock_state; 2249901dcf6SCaesar Wang 2259901dcf6SCaesar Wang assert((port < 5) && (num < 32)); 2269901dcf6SCaesar Wang 227536c2492SCaesar Wang clock_state = gpio_get_clock(gpio); 2289901dcf6SCaesar Wang 2299901dcf6SCaesar Wang /* 2309901dcf6SCaesar Wang * in gpio.h 2319901dcf6SCaesar Wang * #define GPIO_DIR_OUT 0 2329901dcf6SCaesar Wang * #define GPIO_DIR_IN 1 2339901dcf6SCaesar Wang * but rk3399 gpio direction 1: output, 0: input 2349901dcf6SCaesar Wang * so need to revert direction value 2359901dcf6SCaesar Wang */ 2369901dcf6SCaesar Wang mmio_setbits_32(gpio_port[port] + SWPORTA_DDR, !direction << num); 237536c2492SCaesar Wang gpio_put_clock(gpio, clock_state); 2389901dcf6SCaesar Wang } 2399901dcf6SCaesar Wang 2409901dcf6SCaesar Wang static int get_direction(int gpio) 2419901dcf6SCaesar Wang { 242536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio); 243536c2492SCaesar Wang uint32_t num = GET_GPIO_NUM(gpio); 244536c2492SCaesar Wang int direction, clock_state; 2459901dcf6SCaesar Wang 2469901dcf6SCaesar Wang assert((port < 5) && (num < 32)); 2479901dcf6SCaesar Wang 248536c2492SCaesar Wang clock_state = gpio_get_clock(gpio); 2499901dcf6SCaesar Wang 2509901dcf6SCaesar Wang /* 2519901dcf6SCaesar Wang * in gpio.h 2529901dcf6SCaesar Wang * #define GPIO_DIR_OUT 0 2539901dcf6SCaesar Wang * #define GPIO_DIR_IN 1 2549901dcf6SCaesar Wang * but rk3399 gpio direction 1: output, 0: input 2559901dcf6SCaesar Wang * so need to revert direction value 2569901dcf6SCaesar Wang */ 2579901dcf6SCaesar Wang direction = !((mmio_read_32(gpio_port[port] + 2589901dcf6SCaesar Wang SWPORTA_DDR) >> num) & 0x1); 259536c2492SCaesar Wang gpio_put_clock(gpio, clock_state); 2609901dcf6SCaesar Wang 2619901dcf6SCaesar Wang return direction; 2629901dcf6SCaesar Wang } 2639901dcf6SCaesar Wang 2649901dcf6SCaesar Wang static int get_value(int gpio) 2659901dcf6SCaesar Wang { 266536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio); 267536c2492SCaesar Wang uint32_t num = GET_GPIO_NUM(gpio); 268536c2492SCaesar Wang int value, clock_state; 2699901dcf6SCaesar Wang 2709901dcf6SCaesar Wang assert((port < 5) && (num < 32)); 2719901dcf6SCaesar Wang 272536c2492SCaesar Wang clock_state = gpio_get_clock(gpio); 2739901dcf6SCaesar Wang value = (mmio_read_32(gpio_port[port] + EXT_PORTA) >> num) & 0x1; 274536c2492SCaesar Wang gpio_put_clock(gpio, clock_state); 2759901dcf6SCaesar Wang 2769901dcf6SCaesar Wang return value; 2779901dcf6SCaesar Wang } 2789901dcf6SCaesar Wang 2799901dcf6SCaesar Wang static void set_value(int gpio, int value) 2809901dcf6SCaesar Wang { 281536c2492SCaesar Wang uint32_t port = GET_GPIO_PORT(gpio); 282536c2492SCaesar Wang uint32_t num = GET_GPIO_NUM(gpio); 283536c2492SCaesar Wang uint32_t clock_state; 2849901dcf6SCaesar Wang 2859901dcf6SCaesar Wang assert((port < 5) && (num < 32)); 2869901dcf6SCaesar Wang 287536c2492SCaesar Wang clock_state = gpio_get_clock(gpio); 2889901dcf6SCaesar Wang mmio_clrsetbits_32(gpio_port[port] + SWPORTA_DR, 1 << num, 2899901dcf6SCaesar Wang !!value << num); 290536c2492SCaesar Wang gpio_put_clock(gpio, clock_state); 2919901dcf6SCaesar Wang } 2929901dcf6SCaesar Wang 2939901dcf6SCaesar Wang const gpio_ops_t rk3399_gpio_ops = { 2949901dcf6SCaesar Wang .get_direction = get_direction, 2959901dcf6SCaesar Wang .set_direction = set_direction, 2969901dcf6SCaesar Wang .get_value = get_value, 2979901dcf6SCaesar Wang .set_value = set_value, 2989901dcf6SCaesar Wang .set_pull = set_pull, 299536c2492SCaesar Wang .get_pull = get_pull, 3009901dcf6SCaesar Wang }; 3019901dcf6SCaesar Wang 3029901dcf6SCaesar Wang void plat_rockchip_gpio_init(void) 3039901dcf6SCaesar Wang { 3049901dcf6SCaesar Wang gpio_init(&rk3399_gpio_ops); 3059901dcf6SCaesar Wang } 306