1 /* 2 * Driver for Altera's PIO ip core 3 * 4 * Copyright (C) 2011 Missing Link Electronics 5 * Joachim Foerster <joachim@missinglinkelectronics.com> 6 * 7 * SPDX-License-Identifier: GPL-2.0+ 8 * 9 * To use this driver, in your board's config. header: 10 * #define CONFIG_ALTERA_PIO 11 * #define CONFIG_SYS_ALTERA_PIO_NUM <number-of-pio-cores> 12 * #define CONFIG_SYS_ALTERA_PIO_GPIO_NUM <total-number-of-gpios> 13 * And in your board's early setup routine: 14 * altera_pio_init(<baseaddr>, <width>, 'i'|'o'|'t', 15 * <reset-value>, <neg-mask>, "label"); 16 * - 'i'|'o'|'t': PIO is input-only/output-only/tri-state 17 * - <reset-value>: for correct initial status display, output-only 18 * - <neg-mask> is meant to be used to in cases of active-low 19 * GPIOs, such as LEDs and buttons (on/pressed == 0). Each bit 20 * which is 1 in <neg-mask> inverts the corresponding GPIO's value 21 * before set/after get. So: gpio_set_value(gpio, 1) => LED on . 22 * 23 * Do NOT define CONFIG_SYS_GPIO_BASE ! 24 * 25 * Optionally, in your board's config. header: 26 * - To force a GPIO numbering scheme like in Linux ... 27 * #define CONFIG_GPIO_DOWNTO_NUMBERING 28 * ... starting with 255 (default) 29 * #define CONFIG_GPIO_DOWNTO_MAX 255 30 */ 31 #include <common.h> 32 #include <asm/io.h> 33 #include <asm/gpio.h> 34 35 #ifdef CONFIG_GPIO_DOWNTO_NUMBERING 36 #ifndef CONFIG_GPIO_DOWNTO_MAX 37 #define CONFIG_GPIO_DOWNTO_MAX 255 38 #endif 39 #endif 40 41 #define ALTERA_PIO_DATA 0x0 42 #define ALTERA_PIO_DIR 0x4 43 44 #define GPIO_LABEL_SIZE 9 45 46 47 static struct altera_pio { 48 u32 base; 49 u8 width; 50 char iot; 51 u32 negmask; 52 u32 sh_data; 53 u32 sh_dir; 54 int gidx; 55 char label[GPIO_LABEL_SIZE]; 56 } pios[CONFIG_SYS_ALTERA_PIO_NUM]; 57 58 static int pio_num; 59 60 static struct altera_pio_gpio { 61 unsigned num; 62 struct altera_pio *pio; 63 char reqlabel[GPIO_LABEL_SIZE]; 64 } gpios[CONFIG_SYS_ALTERA_PIO_GPIO_NUM]; 65 66 static int pio_gpio_num; 67 68 69 static int altera_pio_gidx(unsigned gpio) 70 { 71 int i; 72 73 for (i = 0; i < pio_gpio_num; ++i) { 74 if (gpio == gpios[i].num) 75 break; 76 } 77 if (i >= pio_gpio_num) 78 return -1; 79 return i; 80 } 81 82 static struct altera_pio *altera_pio_get_and_mask(unsigned gpio, u32 *mask) 83 { 84 int gidx = altera_pio_gidx(gpio); 85 if (gidx < 0) 86 return NULL; 87 if (mask) 88 *mask = 1 << (gidx - gpios[gidx].pio->gidx); 89 return gpios[gidx].pio; 90 } 91 92 #define altera_pio_use_gidx(_gidx, _reqlabel) \ 93 { strncpy(gpios[_gidx].reqlabel, _reqlabel, GPIO_LABEL_SIZE); } 94 #define altera_pio_unuse_gidx(_gidx) { gpios[_gidx].reqlabel[0] = '\0'; } 95 #define altera_pio_is_gidx_used(_gidx) (gpios[_gidx].reqlabel[0] != '\0') 96 97 static int altera_pio_gpio_init(struct altera_pio *pio, u8 width) 98 { 99 u8 gidx = pio_gpio_num; 100 int i; 101 102 if (!width) 103 return -1; 104 if ((pio_gpio_num + width) > CONFIG_SYS_ALTERA_PIO_GPIO_NUM) 105 return -1; 106 107 for (i = 0; i < width; ++i) { 108 #ifdef CONFIG_GPIO_DOWNTO_NUMBERING 109 gpios[pio_gpio_num + i].num = \ 110 CONFIG_GPIO_DOWNTO_MAX + 1 - gidx - width + i; 111 #else 112 gpios[pio_gpio_num + i].num = pio_gpio_num + i; 113 #endif 114 gpios[pio_gpio_num + i].pio = pio; 115 altera_pio_unuse_gidx(pio_gpio_num + i); 116 } 117 pio_gpio_num += width; 118 return gidx; 119 } 120 121 int altera_pio_init(u32 base, u8 width, char iot, u32 rstval, u32 negmask, 122 const char *label) 123 { 124 if (pio_num >= CONFIG_SYS_ALTERA_PIO_NUM) 125 return -1; 126 127 pios[pio_num].base = base; 128 pios[pio_num].width = width; 129 pios[pio_num].iot = iot; 130 switch (iot) { 131 case 'i': 132 /* input only */ 133 pios[pio_num].sh_dir = 0; 134 pios[pio_num].sh_data = readl(base + ALTERA_PIO_DATA); 135 break; 136 case 'o': 137 /* output only */ 138 pios[pio_num].sh_dir = 0xffffffff & ((1 << width) - 1); 139 pios[pio_num].sh_data = rstval; 140 break; 141 case 't': 142 /* bidir, tri-state */ 143 pios[pio_num].sh_dir = readl(base + ALTERA_PIO_DIR); 144 pios[pio_num].sh_data = readl(base + ALTERA_PIO_DATA); 145 break; 146 default: 147 return -1; 148 } 149 pios[pio_num].negmask = negmask & ((1 << width) - 1); 150 pios[pio_num].gidx = altera_pio_gpio_init(&pios[pio_num], width); 151 if (pios[pio_num].gidx < 0) 152 return -1; 153 strncpy(pios[pio_num].label, label, GPIO_LABEL_SIZE); 154 return pio_num++; 155 } 156 157 void altera_pio_info(void) 158 { 159 int i; 160 int j; 161 int gidx; 162 u32 mask; 163 164 for (i = 0; i < pio_num; ++i) { 165 printf("Altera PIO % 2d, @0x%08x, " 166 "width: %u, label: %s\n", 167 i, pios[i].base, pios[i].width, pios[i].label); 168 gidx = pios[i].gidx; 169 for (j = gidx; j < (gidx + pios[i].width); ++j) { 170 mask = 1 << (j - gidx); 171 printf("\tGPIO % 4d: %s %s [%c] %s\n", 172 gpios[j].num, 173 gpios[j].pio->sh_dir & mask ? "out" : " in", 174 gpio_get_value(gpios[j].num) ? "set" : "clr", 175 altera_pio_is_gidx_used(j) ? 'x' : ' ', 176 gpios[j].reqlabel); 177 } 178 } 179 } 180 181 182 int gpio_request(unsigned gpio, const char *label) 183 { 184 int gidx = altera_pio_gidx(gpio); 185 if (gidx < 0) 186 return gidx; 187 if (altera_pio_is_gidx_used(gidx)) 188 return -1; 189 190 altera_pio_use_gidx(gidx, label); 191 return 0; 192 } 193 194 int gpio_free(unsigned gpio) 195 { 196 int gidx = altera_pio_gidx(gpio); 197 if (gidx < 0) 198 return gidx; 199 if (!altera_pio_is_gidx_used(gidx)) 200 return -1; 201 202 altera_pio_unuse_gidx(gidx); 203 return 0; 204 } 205 206 int gpio_direction_input(unsigned gpio) 207 { 208 u32 mask; 209 struct altera_pio *pio; 210 211 pio = altera_pio_get_and_mask(gpio, &mask); 212 if (!pio) 213 return -1; 214 if (pio->iot == 'o') 215 return -1; 216 217 writel(pio->sh_dir &= ~mask, pio->base + ALTERA_PIO_DIR); 218 return 0; 219 } 220 221 int gpio_direction_output(unsigned gpio, int value) 222 { 223 u32 mask; 224 struct altera_pio *pio; 225 226 pio = altera_pio_get_and_mask(gpio, &mask); 227 if (!pio) 228 return -1; 229 if (pio->iot == 'i') 230 return -1; 231 232 value = (pio->negmask & mask) ? !value : value; 233 if (value) 234 pio->sh_data |= mask; 235 else 236 pio->sh_data &= ~mask; 237 writel(pio->sh_data, pio->base + ALTERA_PIO_DATA); 238 writel(pio->sh_dir |= mask, pio->base + ALTERA_PIO_DIR); 239 return 0; 240 } 241 242 int gpio_get_value(unsigned gpio) 243 { 244 u32 mask; 245 struct altera_pio *pio; 246 u32 val; 247 248 pio = altera_pio_get_and_mask(gpio, &mask); 249 if (!pio) 250 return -1; 251 252 if ((pio->sh_dir & mask) || (pio->iot == 'o')) 253 val = pio->sh_data & mask; 254 else 255 val = readl(pio->base + ALTERA_PIO_DATA) & mask; 256 return (pio->negmask & mask) ? !val : val; 257 } 258 259 void gpio_set_value(unsigned gpio, int value) 260 { 261 u32 mask; 262 struct altera_pio *pio; 263 264 pio = altera_pio_get_and_mask(gpio, &mask); 265 if (!pio) 266 return; 267 if (pio->iot == 'i') 268 return; 269 270 value = (pio->negmask & mask) ? !value : value; 271 if (value) 272 pio->sh_data |= mask; 273 else 274 pio->sh_data &= ~mask; 275 writel(pio->sh_data, pio->base + ALTERA_PIO_DATA); 276 return; 277 } 278 279 int gpio_is_valid(int number) 280 { 281 int gidx = altera_pio_gidx(number); 282 283 if (gidx < 0) 284 return 1; 285 return 0; 286 } 287