File indexing completed on 2025-05-11 08:23:05
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028 #include <assert.h>
0029 #include <bsp/fatal.h>
0030 #include <bsp/fdt.h>
0031 #include <bsp/imx-gpio.h>
0032 #include <libfdt.h>
0033 #include <rtems.h>
0034 #include <rtems/sysinit.h>
0035
0036
0037
0038
0039 #define GPIO_ACTIVE_HIGH 0
0040 #define GPIO_ACTIVE_LOW 1
0041
0042
0043
0044
0045 #define IMX_GPIO_ALIAS_NAME "gpioXY"
0046
0047
0048
0049
0050
0051
0052 #define IMX_MAX_GPIO_MODULES 15
0053
0054 struct imx_gpio_regs {
0055 uint32_t dr;
0056 uint32_t gdir;
0057 uint32_t psr;
0058 uint32_t icr1;
0059 #define IMX_GPIO_ICR_LOW_LEVEL 0
0060 #define IMX_GPIO_ICR_HIGH_LEVEL 1
0061 #define IMX_GPIO_ICR_RISING_EDGE 2
0062 #define IMX_GPIO_ICR_FALLING_EDGE 3
0063 uint32_t icr2;
0064 uint32_t imr;
0065 uint32_t isr;
0066 uint32_t edge_sel;
0067 };
0068
0069 struct imx_gpio {
0070 char name[sizeof(IMX_GPIO_ALIAS_NAME)];
0071 struct imx_gpio_regs *regs;
0072 rtems_interrupt_lock lock;
0073 };
0074
0075
0076 struct imx_gpio imx_gpio[IMX_MAX_GPIO_MODULES];
0077
0078 const char *imx_gpio_get_name(struct imx_gpio *imx_gpio)
0079 {
0080 return imx_gpio->name;
0081 }
0082
0083 static void imx_gpio_attach(void)
0084 {
0085 size_t i;
0086 const void *fdt;
0087
0088 fdt = bsp_fdt_get();
0089
0090 memset(imx_gpio, 0, sizeof(imx_gpio));
0091
0092 for (i = 0; i < IMX_MAX_GPIO_MODULES; ++i) {
0093 const char *path;
0094 int node;
0095 const uint32_t *val;
0096 uint32_t gpio_regs = 0;
0097 int len;
0098
0099 memcpy(imx_gpio[i].name, IMX_GPIO_ALIAS_NAME, sizeof(IMX_GPIO_ALIAS_NAME));
0100 if (i < 10) {
0101 imx_gpio[i].name[sizeof(IMX_GPIO_ALIAS_NAME)-3] = (char)('0' + i);
0102 imx_gpio[i].name[sizeof(IMX_GPIO_ALIAS_NAME)-2] = '\0';
0103 } else {
0104 imx_gpio[i].name[sizeof(IMX_GPIO_ALIAS_NAME)-3] = (char)('0' + i / 10);
0105 imx_gpio[i].name[sizeof(IMX_GPIO_ALIAS_NAME)-2] = (char)('0' + i % 10);
0106 imx_gpio[i].name[sizeof(IMX_GPIO_ALIAS_NAME)-1] = '\0';
0107 }
0108
0109 path = fdt_get_alias(fdt, imx_gpio[i].name);
0110 if (path == NULL) {
0111 continue;
0112 }
0113
0114 node = fdt_path_offset(fdt, path);
0115 if (node < 0) {
0116 bsp_fatal(IMX_FATAL_GPIO_UNEXPECTED_FDT);
0117 }
0118
0119 val = fdt_getprop(fdt, node, "reg", &len);
0120 if (len > 0) {
0121 gpio_regs = fdt32_to_cpu(val[0]);
0122 } else {
0123 bsp_fatal(IMX_FATAL_GPIO_UNEXPECTED_FDT);
0124 }
0125
0126 imx_gpio[i].regs = (struct imx_gpio_regs *)gpio_regs;
0127 rtems_interrupt_lock_initialize(&imx_gpio[i].lock, imx_gpio[i].name);
0128 }
0129 }
0130
0131 struct imx_gpio *imx_gpio_get_by_index(unsigned idx)
0132 {
0133 if ((idx < IMX_MAX_GPIO_MODULES) && (imx_gpio[idx].regs != NULL)) {
0134 return &imx_gpio[idx];
0135 }
0136 return NULL;
0137 }
0138
0139 struct imx_gpio *imx_gpio_get_by_register(void *regs)
0140 {
0141 size_t i;
0142
0143 for (i = 0; i < IMX_MAX_GPIO_MODULES; ++i) {
0144 if (imx_gpio[i].regs == regs) {
0145 return &imx_gpio[i];
0146 }
0147 }
0148 return NULL;
0149 }
0150
0151 static void imx_gpio_direction_input(struct imx_gpio_pin *pin)
0152 {
0153 rtems_interrupt_lock_context lock_context;
0154 rtems_interrupt_lock_acquire(&pin->gpio->lock, &lock_context);
0155 pin->gpio->regs->gdir &= ~pin->mask;
0156 rtems_interrupt_lock_release(&pin->gpio->lock, &lock_context);
0157 }
0158
0159 static void imx_gpio_direction_output(struct imx_gpio_pin *pin)
0160 {
0161 rtems_interrupt_lock_context lock_context;
0162 rtems_interrupt_lock_acquire(&pin->gpio->lock, &lock_context);
0163 pin->gpio->regs->gdir |= pin->mask;
0164 rtems_interrupt_lock_release(&pin->gpio->lock, &lock_context);
0165 }
0166
0167 static void imx_gpio_set_interrupt_any_edge(struct imx_gpio_pin *pin)
0168 {
0169 rtems_interrupt_lock_context lock_context;
0170 rtems_interrupt_lock_acquire(&pin->gpio->lock, &lock_context);
0171 pin->gpio->regs->edge_sel |= pin->mask;
0172 rtems_interrupt_lock_release(&pin->gpio->lock, &lock_context);
0173 }
0174
0175 static void imx_gpio_set_interrupt_mode(struct imx_gpio_pin *pin, uint32_t mode)
0176 {
0177 size_t i;
0178
0179 for (i=0; i < 32; ++i) {
0180 if ((pin->mask & (1u << i)) != 0) {
0181 volatile uint32_t *icr;
0182 size_t shift;
0183 rtems_interrupt_lock_context lock_context;
0184
0185 if (i < 16) {
0186 icr = &pin->gpio->regs->icr1;
0187 shift = 2 * i;
0188 } else {
0189 icr = &pin->gpio->regs->icr2;
0190 shift = 2 * (i - 16);
0191 }
0192
0193 rtems_interrupt_lock_acquire(&pin->gpio->lock, &lock_context);
0194 *icr = (*icr & ~(3u << shift)) | (mode << shift);
0195 rtems_interrupt_lock_release(&pin->gpio->lock, &lock_context);
0196 }
0197 }
0198 }
0199
0200 rtems_status_code imx_gpio_init_from_fdt_property_pointer (
0201 struct imx_gpio_pin *pin,
0202 const uint32_t *prop_pointer,
0203 enum imx_gpio_mode mode,
0204 const uint32_t **next_prop_pointer
0205 )
0206 {
0207 int len;
0208 const uint32_t *val;
0209 rtems_status_code sc = RTEMS_SUCCESSFUL;
0210 const void *fdt;
0211 uint32_t gpio_regs;
0212 const unsigned pin_length_dwords = 3;
0213 uint32_t gpio_phandle;
0214 uint32_t pin_nr;
0215 uint32_t active_level;
0216 int cfgnode;
0217
0218 memset(pin, 0, sizeof(*pin));
0219
0220 fdt = bsp_fdt_get();
0221 if (sc == RTEMS_SUCCESSFUL) {
0222 pin_nr = fdt32_to_cpu(prop_pointer[1]);
0223 gpio_phandle = fdt32_to_cpu(prop_pointer[0]);
0224 active_level = fdt32_to_cpu(prop_pointer[2]);
0225
0226 cfgnode = fdt_node_offset_by_phandle(fdt, gpio_phandle);
0227
0228 val = fdt_getprop(fdt, cfgnode, "reg", &len);
0229 if (len > 0) {
0230 gpio_regs = fdt32_to_cpu(val[0]);
0231 } else {
0232 sc = RTEMS_UNSATISFIED;
0233 }
0234 }
0235 if (sc == RTEMS_SUCCESSFUL) {
0236 pin->gpio = imx_gpio_get_by_register((void *)gpio_regs);
0237 pin->mask = 1u << pin_nr;
0238 pin->shift = pin_nr;
0239 pin->mode = mode;
0240 pin->is_active_low = (active_level == GPIO_ACTIVE_LOW);
0241 }
0242 if (sc == RTEMS_SUCCESSFUL) {
0243 imx_gpio_init(pin);
0244 }
0245 if (sc == RTEMS_SUCCESSFUL && next_prop_pointer != NULL) {
0246 *next_prop_pointer = prop_pointer + pin_length_dwords;
0247 }
0248
0249 return sc;
0250 }
0251
0252 rtems_status_code imx_gpio_init_from_fdt_property (
0253 struct imx_gpio_pin *pin,
0254 int node_offset,
0255 const char *property,
0256 enum imx_gpio_mode mode,
0257 size_t index
0258 )
0259 {
0260 int len;
0261 const uint32_t *val;
0262 rtems_status_code sc = RTEMS_SUCCESSFUL;
0263 const void *fdt;
0264 const unsigned pin_length_dwords = 3;
0265 const unsigned pin_length_bytes = pin_length_dwords * 4;
0266
0267 memset(pin, 0, sizeof(*pin));
0268
0269 fdt = bsp_fdt_get();
0270 val = fdt_getprop(fdt, node_offset, property, &len);
0271 if (val == NULL || (len % pin_length_bytes != 0) ||
0272 (index >= len / pin_length_bytes)) {
0273 sc = RTEMS_UNSATISFIED;
0274 }
0275 if (sc == RTEMS_SUCCESSFUL) {
0276 sc = imx_gpio_init_from_fdt_property_pointer(
0277 pin,
0278 val + index * pin_length_dwords,
0279 mode,
0280 NULL);
0281 }
0282
0283 return sc;
0284 }
0285
0286 rtems_vector_number imx_gpio_get_irq_of_node(
0287 const void *fdt,
0288 int node,
0289 size_t index
0290 )
0291 {
0292 const uint32_t *val;
0293 uint32_t pin;
0294 int parent;
0295 size_t parent_index;
0296 int len;
0297
0298 val = fdt_getprop(fdt, node, "interrupts", &len);
0299 if (val == NULL || len < (int) ((index + 1) * 8)) {
0300 return UINT32_MAX;
0301 }
0302 pin = fdt32_to_cpu(val[index * 2]);
0303 if (pin < 16) {
0304 parent_index = 0;
0305 } else {
0306 parent_index = 1;
0307 }
0308
0309 val = fdt_getprop(fdt, node, "interrupt-parent", &len);
0310 if (len != 4) {
0311 return UINT32_MAX;
0312 }
0313 parent = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(val[0]));
0314
0315 return imx_get_irq_of_node(fdt, parent, parent_index);
0316 }
0317
0318 void imx_gpio_init (struct imx_gpio_pin *pin)
0319 {
0320 switch (pin->mode) {
0321 case (IMX_GPIO_MODE_INTERRUPT_LOW):
0322 imx_gpio_direction_input(pin);
0323 imx_gpio_set_interrupt_mode(pin, IMX_GPIO_ICR_LOW_LEVEL);
0324 break;
0325 case (IMX_GPIO_MODE_INTERRUPT_HIGH):
0326 imx_gpio_direction_input(pin);
0327 imx_gpio_set_interrupt_mode(pin, IMX_GPIO_ICR_HIGH_LEVEL);
0328 break;
0329 case (IMX_GPIO_MODE_INTERRUPT_RISING):
0330 imx_gpio_direction_input(pin);
0331 imx_gpio_set_interrupt_mode(pin, IMX_GPIO_ICR_RISING_EDGE);
0332 break;
0333 case (IMX_GPIO_MODE_INTERRUPT_FALLING):
0334 imx_gpio_direction_input(pin);
0335 imx_gpio_set_interrupt_mode(pin, IMX_GPIO_ICR_FALLING_EDGE);
0336 break;
0337 case (IMX_GPIO_MODE_INTERRUPT_ANY_EDGE):
0338 imx_gpio_direction_input(pin);
0339 imx_gpio_set_interrupt_any_edge(pin);
0340
0341
0342 imx_gpio_set_interrupt_mode(pin, IMX_GPIO_ICR_FALLING_EDGE);
0343 break;
0344 case (IMX_GPIO_MODE_INPUT):
0345 imx_gpio_direction_input(pin);
0346 break;
0347 case (IMX_GPIO_MODE_OUTPUT):
0348 imx_gpio_direction_output(pin);
0349 break;
0350 default:
0351 assert(false);
0352 break;
0353 }
0354 }
0355
0356 void imx_gpio_set_output(struct imx_gpio_pin *pin, uint32_t set)
0357 {
0358 rtems_interrupt_lock_context lock_context;
0359 set <<= pin->shift;
0360 set &= pin->mask;
0361 rtems_interrupt_lock_acquire(&pin->gpio->lock, &lock_context);
0362 pin->gpio->regs->dr = (pin->gpio->regs->dr & ~pin->mask) | set;
0363 rtems_interrupt_lock_release(&pin->gpio->lock, &lock_context);
0364 }
0365
0366 void imx_gpio_toggle_output(struct imx_gpio_pin *pin)
0367 {
0368 rtems_interrupt_lock_context lock_context;
0369 rtems_interrupt_lock_acquire(&pin->gpio->lock, &lock_context);
0370 pin->gpio->regs->dr = (pin->gpio->regs->dr ^ pin->mask);
0371 rtems_interrupt_lock_release(&pin->gpio->lock, &lock_context);
0372 }
0373
0374 uint32_t imx_gpio_get_input(struct imx_gpio_pin *pin)
0375 {
0376 return (pin->gpio->regs->dr & pin->mask) >> pin->shift;
0377 }
0378
0379 void imx_gpio_int_disable(struct imx_gpio_pin *pin)
0380 {
0381 rtems_interrupt_lock_context lock_context;
0382 rtems_interrupt_lock_acquire(&pin->gpio->lock, &lock_context);
0383 pin->gpio->regs->imr &= ~pin->mask;
0384 rtems_interrupt_lock_release(&pin->gpio->lock, &lock_context);
0385 }
0386
0387 void imx_gpio_int_enable(struct imx_gpio_pin *pin)
0388 {
0389 rtems_interrupt_lock_context lock_context;
0390 rtems_interrupt_lock_acquire(&pin->gpio->lock, &lock_context);
0391 pin->gpio->regs->imr |= pin->mask;
0392 rtems_interrupt_lock_release(&pin->gpio->lock, &lock_context);
0393 }
0394
0395 uint32_t imx_gpio_get_isr(struct imx_gpio_pin *pin)
0396 {
0397 return (pin->gpio->regs->isr & pin->mask) >> pin->shift;
0398 }
0399
0400 void imx_gpio_clear_isr(struct imx_gpio_pin *pin, uint32_t clr)
0401 {
0402 pin->gpio->regs->isr = (clr << pin->shift) & pin->mask;
0403 }
0404
0405 RTEMS_SYSINIT_ITEM(
0406 imx_gpio_attach,
0407 RTEMS_SYSINIT_DEVICE_DRIVERS,
0408 RTEMS_SYSINIT_ORDER_FIRST
0409 );