1*9901dcf6SCaesar Wang /* 2*9901dcf6SCaesar Wang * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. 3*9901dcf6SCaesar Wang * 4*9901dcf6SCaesar Wang * Redistribution and use in source and binary forms, with or without 5*9901dcf6SCaesar Wang * modification, are permitted provided that the following conditions are met: 6*9901dcf6SCaesar Wang * 7*9901dcf6SCaesar Wang * Redistributions of source code must retain the above copyright notice, this 8*9901dcf6SCaesar Wang * list of conditions and the following disclaimer. 9*9901dcf6SCaesar Wang * 10*9901dcf6SCaesar Wang * Redistributions in binary form must reproduce the above copyright notice, 11*9901dcf6SCaesar Wang * this list of conditions and the following disclaimer in the documentation 12*9901dcf6SCaesar Wang * and/or other materials provided with the distribution. 13*9901dcf6SCaesar Wang * 14*9901dcf6SCaesar Wang * Neither the name of ARM nor the names of its contributors may be used 15*9901dcf6SCaesar Wang * to endorse or promote products derived from this software without specific 16*9901dcf6SCaesar Wang * prior written permission. 17*9901dcf6SCaesar Wang * 18*9901dcf6SCaesar Wang * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19*9901dcf6SCaesar Wang * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*9901dcf6SCaesar Wang * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*9901dcf6SCaesar Wang * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22*9901dcf6SCaesar Wang * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23*9901dcf6SCaesar Wang * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24*9901dcf6SCaesar Wang * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25*9901dcf6SCaesar Wang * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26*9901dcf6SCaesar Wang * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27*9901dcf6SCaesar Wang * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28*9901dcf6SCaesar Wang * POSSIBILITY OF SUCH DAMAGE. 29*9901dcf6SCaesar Wang */ 30*9901dcf6SCaesar Wang #include <assert.h> 31*9901dcf6SCaesar Wang #include <debug.h> 32*9901dcf6SCaesar Wang #include <delay_timer.h> 33*9901dcf6SCaesar Wang #include <errno.h> 34*9901dcf6SCaesar Wang #include <gpio.h> 35*9901dcf6SCaesar Wang #include <mmio.h> 36*9901dcf6SCaesar Wang #include <platform.h> 37*9901dcf6SCaesar Wang #include <platform_def.h> 38*9901dcf6SCaesar Wang #include <plat_private.h> 39*9901dcf6SCaesar Wang #include <soc.h> 40*9901dcf6SCaesar Wang 41*9901dcf6SCaesar Wang uint32_t gpio_port[] = { 42*9901dcf6SCaesar Wang GPIO0_BASE, 43*9901dcf6SCaesar Wang GPIO1_BASE, 44*9901dcf6SCaesar Wang GPIO2_BASE, 45*9901dcf6SCaesar Wang GPIO3_BASE, 46*9901dcf6SCaesar Wang GPIO4_BASE, 47*9901dcf6SCaesar Wang }; 48*9901dcf6SCaesar Wang 49*9901dcf6SCaesar Wang #define SWPORTA_DR 0x00 50*9901dcf6SCaesar Wang #define SWPORTA_DDR 0x04 51*9901dcf6SCaesar Wang #define EXT_PORTA 0x50 52*9901dcf6SCaesar Wang 53*9901dcf6SCaesar Wang #define PMU_GPIO_PORT0 0 54*9901dcf6SCaesar Wang #define PMU_GPIO_PORT1 1 55*9901dcf6SCaesar Wang 56*9901dcf6SCaesar Wang #define PMU_GRF_GPIO0A_P 0x40 57*9901dcf6SCaesar Wang #define GRF_GPIO2A_P 0xe040 58*9901dcf6SCaesar Wang #define GPIO_P_MASK 0x03 59*9901dcf6SCaesar Wang 60*9901dcf6SCaesar Wang /* 61*9901dcf6SCaesar Wang * gpio clock disabled when not operate 62*9901dcf6SCaesar Wang * so need to enable gpio clock before operate gpio 63*9901dcf6SCaesar Wang * after setting, need to disable gpio clock 64*9901dcf6SCaesar Wang * gate 1: disable clock; 0: enable clock 65*9901dcf6SCaesar Wang */ 66*9901dcf6SCaesar Wang static void gpio_clk(int gpio, uint32_t gate) 67*9901dcf6SCaesar Wang { 68*9901dcf6SCaesar Wang uint32_t port = gpio / 32; 69*9901dcf6SCaesar Wang 70*9901dcf6SCaesar Wang assert(port < 5); 71*9901dcf6SCaesar Wang 72*9901dcf6SCaesar Wang switch (port) { 73*9901dcf6SCaesar Wang case 0: 74*9901dcf6SCaesar Wang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1), 75*9901dcf6SCaesar Wang BITS_WITH_WMASK(gate, CLK_GATE_MASK, 76*9901dcf6SCaesar Wang PCLK_GPIO0_GATE_SHIFT)); 77*9901dcf6SCaesar Wang break; 78*9901dcf6SCaesar Wang case 1: 79*9901dcf6SCaesar Wang mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1), 80*9901dcf6SCaesar Wang BITS_WITH_WMASK(gate, CLK_GATE_MASK, 81*9901dcf6SCaesar Wang PCLK_GPIO1_GATE_SHIFT)); 82*9901dcf6SCaesar Wang break; 83*9901dcf6SCaesar Wang case 2: 84*9901dcf6SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 85*9901dcf6SCaesar Wang BITS_WITH_WMASK(gate, CLK_GATE_MASK, 86*9901dcf6SCaesar Wang PCLK_GPIO2_GATE_SHIFT)); 87*9901dcf6SCaesar Wang break; 88*9901dcf6SCaesar Wang case 3: 89*9901dcf6SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 90*9901dcf6SCaesar Wang BITS_WITH_WMASK(gate, CLK_GATE_MASK, 91*9901dcf6SCaesar Wang PCLK_GPIO3_GATE_SHIFT)); 92*9901dcf6SCaesar Wang 93*9901dcf6SCaesar Wang break; 94*9901dcf6SCaesar Wang case 4: 95*9901dcf6SCaesar Wang mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), 96*9901dcf6SCaesar Wang BITS_WITH_WMASK(gate, CLK_GATE_MASK, 97*9901dcf6SCaesar Wang PCLK_GPIO4_GATE_SHIFT)); 98*9901dcf6SCaesar Wang break; 99*9901dcf6SCaesar Wang default: 100*9901dcf6SCaesar Wang break; 101*9901dcf6SCaesar Wang } 102*9901dcf6SCaesar Wang } 103*9901dcf6SCaesar Wang 104*9901dcf6SCaesar Wang static void set_pull(int gpio, int pull) 105*9901dcf6SCaesar Wang { 106*9901dcf6SCaesar Wang uint32_t port = gpio / 32; 107*9901dcf6SCaesar Wang uint32_t num = gpio % 32; 108*9901dcf6SCaesar Wang uint32_t bank = num / 8; 109*9901dcf6SCaesar Wang uint32_t id = num % 8; 110*9901dcf6SCaesar Wang 111*9901dcf6SCaesar Wang assert((port < 5) && (num < 32)); 112*9901dcf6SCaesar Wang 113*9901dcf6SCaesar Wang gpio_clk(gpio, 0); 114*9901dcf6SCaesar Wang 115*9901dcf6SCaesar Wang /* 116*9901dcf6SCaesar Wang * in gpio0a, gpio0b, gpio2c, gpio2d, 117*9901dcf6SCaesar Wang * 00: Z 118*9901dcf6SCaesar Wang * 01: pull down 119*9901dcf6SCaesar Wang * 10: Z 120*9901dcf6SCaesar Wang * 11: pull up 121*9901dcf6SCaesar Wang * different with other gpio, so need to correct it 122*9901dcf6SCaesar Wang */ 123*9901dcf6SCaesar Wang if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 2))) { 124*9901dcf6SCaesar Wang if (pull == GPIO_PULL_UP) 125*9901dcf6SCaesar Wang pull = 3; 126*9901dcf6SCaesar Wang else if (pull == GPIO_PULL_DOWN) 127*9901dcf6SCaesar Wang pull = 1; 128*9901dcf6SCaesar Wang else 129*9901dcf6SCaesar Wang pull = 0; 130*9901dcf6SCaesar Wang } 131*9901dcf6SCaesar Wang 132*9901dcf6SCaesar Wang if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) { 133*9901dcf6SCaesar Wang mmio_write_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P + 134*9901dcf6SCaesar Wang port * 16 + bank * 4, 135*9901dcf6SCaesar Wang BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2)); 136*9901dcf6SCaesar Wang } else { 137*9901dcf6SCaesar Wang mmio_write_32(GRF_BASE + GRF_GPIO2A_P + 138*9901dcf6SCaesar Wang (port - 2) * 16 + bank * 4, 139*9901dcf6SCaesar Wang BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2)); 140*9901dcf6SCaesar Wang } 141*9901dcf6SCaesar Wang gpio_clk(gpio, 1); 142*9901dcf6SCaesar Wang } 143*9901dcf6SCaesar Wang 144*9901dcf6SCaesar Wang static void set_direction(int gpio, int direction) 145*9901dcf6SCaesar Wang { 146*9901dcf6SCaesar Wang uint32_t port = gpio / 32; 147*9901dcf6SCaesar Wang uint32_t num = gpio % 32; 148*9901dcf6SCaesar Wang 149*9901dcf6SCaesar Wang assert((port < 5) && (num < 32)); 150*9901dcf6SCaesar Wang 151*9901dcf6SCaesar Wang gpio_clk(gpio, 0); 152*9901dcf6SCaesar Wang 153*9901dcf6SCaesar Wang /* 154*9901dcf6SCaesar Wang * in gpio.h 155*9901dcf6SCaesar Wang * #define GPIO_DIR_OUT 0 156*9901dcf6SCaesar Wang * #define GPIO_DIR_IN 1 157*9901dcf6SCaesar Wang * but rk3399 gpio direction 1: output, 0: input 158*9901dcf6SCaesar Wang * so need to revert direction value 159*9901dcf6SCaesar Wang */ 160*9901dcf6SCaesar Wang mmio_setbits_32(gpio_port[port] + SWPORTA_DDR, !direction << num); 161*9901dcf6SCaesar Wang gpio_clk(gpio, 1); 162*9901dcf6SCaesar Wang } 163*9901dcf6SCaesar Wang 164*9901dcf6SCaesar Wang static int get_direction(int gpio) 165*9901dcf6SCaesar Wang { 166*9901dcf6SCaesar Wang uint32_t port = gpio / 32; 167*9901dcf6SCaesar Wang uint32_t num = gpio % 32; 168*9901dcf6SCaesar Wang int direction; 169*9901dcf6SCaesar Wang 170*9901dcf6SCaesar Wang assert((port < 5) && (num < 32)); 171*9901dcf6SCaesar Wang 172*9901dcf6SCaesar Wang gpio_clk(gpio, 0); 173*9901dcf6SCaesar Wang 174*9901dcf6SCaesar Wang /* 175*9901dcf6SCaesar Wang * in gpio.h 176*9901dcf6SCaesar Wang * #define GPIO_DIR_OUT 0 177*9901dcf6SCaesar Wang * #define GPIO_DIR_IN 1 178*9901dcf6SCaesar Wang * but rk3399 gpio direction 1: output, 0: input 179*9901dcf6SCaesar Wang * so need to revert direction value 180*9901dcf6SCaesar Wang */ 181*9901dcf6SCaesar Wang direction = !((mmio_read_32(gpio_port[port] + 182*9901dcf6SCaesar Wang SWPORTA_DDR) >> num) & 0x1); 183*9901dcf6SCaesar Wang gpio_clk(gpio, 1); 184*9901dcf6SCaesar Wang 185*9901dcf6SCaesar Wang return direction; 186*9901dcf6SCaesar Wang } 187*9901dcf6SCaesar Wang 188*9901dcf6SCaesar Wang static int get_value(int gpio) 189*9901dcf6SCaesar Wang { 190*9901dcf6SCaesar Wang uint32_t port = gpio / 32; 191*9901dcf6SCaesar Wang uint32_t num = gpio % 32; 192*9901dcf6SCaesar Wang int value; 193*9901dcf6SCaesar Wang 194*9901dcf6SCaesar Wang assert((port < 5) && (num < 32)); 195*9901dcf6SCaesar Wang 196*9901dcf6SCaesar Wang gpio_clk(gpio, 0); 197*9901dcf6SCaesar Wang value = (mmio_read_32(gpio_port[port] + EXT_PORTA) >> num) & 0x1; 198*9901dcf6SCaesar Wang gpio_clk(gpio, 1); 199*9901dcf6SCaesar Wang 200*9901dcf6SCaesar Wang return value; 201*9901dcf6SCaesar Wang } 202*9901dcf6SCaesar Wang 203*9901dcf6SCaesar Wang static void set_value(int gpio, int value) 204*9901dcf6SCaesar Wang { 205*9901dcf6SCaesar Wang uint32_t port = gpio / 32; 206*9901dcf6SCaesar Wang uint32_t num = gpio % 32; 207*9901dcf6SCaesar Wang 208*9901dcf6SCaesar Wang assert((port < 5) && (num < 32)); 209*9901dcf6SCaesar Wang 210*9901dcf6SCaesar Wang gpio_clk(gpio, 0); 211*9901dcf6SCaesar Wang mmio_clrsetbits_32(gpio_port[port] + SWPORTA_DR, 1 << num, 212*9901dcf6SCaesar Wang !!value << num); 213*9901dcf6SCaesar Wang gpio_clk(gpio, 0); 214*9901dcf6SCaesar Wang } 215*9901dcf6SCaesar Wang 216*9901dcf6SCaesar Wang const gpio_ops_t rk3399_gpio_ops = { 217*9901dcf6SCaesar Wang .get_direction = get_direction, 218*9901dcf6SCaesar Wang .set_direction = set_direction, 219*9901dcf6SCaesar Wang .get_value = get_value, 220*9901dcf6SCaesar Wang .set_value = set_value, 221*9901dcf6SCaesar Wang .set_pull = set_pull, 222*9901dcf6SCaesar Wang }; 223*9901dcf6SCaesar Wang 224*9901dcf6SCaesar Wang void plat_rockchip_gpio_init(void) 225*9901dcf6SCaesar Wang { 226*9901dcf6SCaesar Wang gpio_init(&rk3399_gpio_ops); 227*9901dcf6SCaesar Wang } 228