1 /* 2 * Copyright (c) 2019, Linaro Limited 3 * Copyright (c) 2019, Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org> 4 * 5 * SPDX-License-Identifier: BSD-3-Clause 6 */ 7 8 #include <string.h> 9 #include <assert.h> 10 #include <lib/mmio.h> 11 #include <drivers/delay_timer.h> 12 #include <drivers/rpi3/gpio/rpi3_gpio.h> 13 14 static struct rpi3_gpio_params rpi3_gpio_params; 15 16 static int rpi3_gpio_get_direction(int gpio); 17 static void rpi3_gpio_set_direction(int gpio, int direction); 18 static int rpi3_gpio_get_value(int gpio); 19 static void rpi3_gpio_set_value(int gpio, int value); 20 static void rpi3_gpio_set_pull(int gpio, int pull); 21 22 static const gpio_ops_t rpi3_gpio_ops = { 23 .get_direction = rpi3_gpio_get_direction, 24 .set_direction = rpi3_gpio_set_direction, 25 .get_value = rpi3_gpio_get_value, 26 .set_value = rpi3_gpio_set_value, 27 .set_pull = rpi3_gpio_set_pull, 28 }; 29 30 /** 31 * Get selection of GPIO pinmux settings. 32 * 33 * @param gpio The pin number of GPIO. From 0 to 53. 34 * @return The selection of pinmux. RPI3_GPIO_FUNC_INPUT: input, 35 * RPI3_GPIO_FUNC_OUTPUT: output, 36 * RPI3_GPIO_FUNC_ALT0: alt-0, 37 * RPI3_GPIO_FUNC_ALT1: alt-1, 38 * RPI3_GPIO_FUNC_ALT2: alt-2, 39 * RPI3_GPIO_FUNC_ALT3: alt-3, 40 * RPI3_GPIO_FUNC_ALT4: alt-4, 41 * RPI3_GPIO_FUNC_ALT5: alt-5 42 */ 43 int rpi3_gpio_get_select(int gpio) 44 { 45 int ret; 46 uintptr_t reg_base = rpi3_gpio_params.reg_base; 47 int regN = gpio / 10; 48 int shift = 3 * (gpio % 10); 49 uintptr_t reg_sel = reg_base + RPI3_GPIO_GPFSEL(regN); 50 uint32_t sel = mmio_read_32(reg_sel); 51 52 ret = (sel >> shift) & 0x07; 53 54 return ret; 55 } 56 57 /** 58 * Set selection of GPIO pinmux settings. 59 * 60 * @param gpio The pin number of GPIO. From 0 to 53. 61 * @param fsel The selection of pinmux. RPI3_GPIO_FUNC_INPUT: input, 62 * RPI3_GPIO_FUNC_OUTPUT: output, 63 * RPI3_GPIO_FUNC_ALT0: alt-0, 64 * RPI3_GPIO_FUNC_ALT1: alt-1, 65 * RPI3_GPIO_FUNC_ALT2: alt-2, 66 * RPI3_GPIO_FUNC_ALT3: alt-3, 67 * RPI3_GPIO_FUNC_ALT4: alt-4, 68 * RPI3_GPIO_FUNC_ALT5: alt-5 69 */ 70 void rpi3_gpio_set_select(int gpio, int fsel) 71 { 72 uintptr_t reg_base = rpi3_gpio_params.reg_base; 73 int regN = gpio / 10; 74 int shift = 3 * (gpio % 10); 75 uintptr_t reg_sel = reg_base + RPI3_GPIO_GPFSEL(regN); 76 uint32_t sel = mmio_read_32(reg_sel); 77 uint32_t mask = U(0x07) << shift; 78 79 sel = (sel & (~mask)) | ((fsel << shift) & mask); 80 mmio_write_32(reg_sel, sel); 81 } 82 83 static int rpi3_gpio_get_direction(int gpio) 84 { 85 int result = rpi3_gpio_get_select(gpio); 86 87 if (result == RPI3_GPIO_FUNC_INPUT) 88 return GPIO_DIR_IN; 89 else if (result == RPI3_GPIO_FUNC_OUTPUT) 90 return GPIO_DIR_OUT; 91 92 return GPIO_DIR_IN; 93 } 94 95 static void rpi3_gpio_set_direction(int gpio, int direction) 96 { 97 switch (direction) { 98 case GPIO_DIR_IN: 99 rpi3_gpio_set_select(gpio, RPI3_GPIO_FUNC_INPUT); 100 break; 101 case GPIO_DIR_OUT: 102 rpi3_gpio_set_select(gpio, RPI3_GPIO_FUNC_OUTPUT); 103 break; 104 } 105 } 106 107 static int rpi3_gpio_get_value(int gpio) 108 { 109 uintptr_t reg_base = rpi3_gpio_params.reg_base; 110 int regN = gpio / 32; 111 int shift = gpio % 32; 112 uintptr_t reg_lev = reg_base + RPI3_GPIO_GPLEV(regN); 113 uint32_t value = mmio_read_32(reg_lev); 114 115 if ((value >> shift) & 0x01) 116 return GPIO_LEVEL_HIGH; 117 return GPIO_LEVEL_LOW; 118 } 119 120 static void rpi3_gpio_set_value(int gpio, int value) 121 { 122 uintptr_t reg_base = rpi3_gpio_params.reg_base; 123 int regN = gpio / 32; 124 int shift = gpio % 32; 125 uintptr_t reg_set = reg_base + RPI3_GPIO_GPSET(regN); 126 uintptr_t reg_clr = reg_base + RPI3_GPIO_GPSET(regN); 127 128 switch (value) { 129 case GPIO_LEVEL_LOW: 130 mmio_write_32(reg_clr, U(1) << shift); 131 break; 132 case GPIO_LEVEL_HIGH: 133 mmio_write_32(reg_set, U(1) << shift); 134 break; 135 } 136 } 137 138 static void rpi3_gpio_set_pull(int gpio, int pull) 139 { 140 uintptr_t reg_base = rpi3_gpio_params.reg_base; 141 int regN = gpio / 32; 142 int shift = gpio % 32; 143 uintptr_t reg_pud = reg_base + RPI3_GPIO_GPPUD; 144 uintptr_t reg_clk = reg_base + RPI3_GPIO_GPPUDCLK(regN); 145 146 switch (pull) { 147 case GPIO_PULL_NONE: 148 mmio_write_32(reg_pud, 0x0); 149 break; 150 case GPIO_PULL_UP: 151 mmio_write_32(reg_pud, 0x2); 152 break; 153 case GPIO_PULL_DOWN: 154 mmio_write_32(reg_pud, 0x1); 155 break; 156 } 157 mdelay(150); 158 mmio_write_32(reg_clk, U(1) << shift); 159 mdelay(150); 160 mmio_write_32(reg_clk, 0x0); 161 mmio_write_32(reg_pud, 0x0); 162 } 163 164 void rpi3_gpio_init(struct rpi3_gpio_params *params) 165 { 166 assert(params != 0); 167 memcpy(&rpi3_gpio_params, params, sizeof(struct rpi3_gpio_params)); 168 gpio_init(&rpi3_gpio_ops); 169 } 170