1*aa22c0f3STomasz Duszynski /* SPDX-License-Identifier: BSD-3-Clause
2*aa22c0f3STomasz Duszynski * Copyright(C) 2021 Marvell.
3*aa22c0f3STomasz Duszynski */
4*aa22c0f3STomasz Duszynski
5*aa22c0f3STomasz Duszynski #include <fcntl.h>
6*aa22c0f3STomasz Duszynski #include <pthread.h>
7*aa22c0f3STomasz Duszynski #include <sys/ioctl.h>
8*aa22c0f3STomasz Duszynski #include <sys/mman.h>
9*aa22c0f3STomasz Duszynski #include <sys/queue.h>
10*aa22c0f3STomasz Duszynski #include <unistd.h>
11*aa22c0f3STomasz Duszynski
12*aa22c0f3STomasz Duszynski #include <rte_rawdev_pmd.h>
13*aa22c0f3STomasz Duszynski
14*aa22c0f3STomasz Duszynski #include <roc_api.h>
15*aa22c0f3STomasz Duszynski
16*aa22c0f3STomasz Duszynski #include "cnxk_gpio.h"
17*aa22c0f3STomasz Duszynski
18*aa22c0f3STomasz Duszynski #define OTX_IOC_MAGIC 0xF2
19*aa22c0f3STomasz Duszynski #define OTX_IOC_SET_GPIO_HANDLER \
20*aa22c0f3STomasz Duszynski _IOW(OTX_IOC_MAGIC, 1, struct otx_gpio_usr_data)
21*aa22c0f3STomasz Duszynski #define OTX_IOC_CLR_GPIO_HANDLER \
22*aa22c0f3STomasz Duszynski _IO(OTX_IOC_MAGIC, 2)
23*aa22c0f3STomasz Duszynski
24*aa22c0f3STomasz Duszynski struct otx_gpio_usr_data {
25*aa22c0f3STomasz Duszynski uint64_t isr_base;
26*aa22c0f3STomasz Duszynski uint64_t sp;
27*aa22c0f3STomasz Duszynski uint64_t cpu;
28*aa22c0f3STomasz Duszynski uint64_t gpio_num;
29*aa22c0f3STomasz Duszynski };
30*aa22c0f3STomasz Duszynski
31*aa22c0f3STomasz Duszynski struct cnxk_gpio_irq_stack {
32*aa22c0f3STomasz Duszynski LIST_ENTRY(cnxk_gpio_irq_stack) next;
33*aa22c0f3STomasz Duszynski void *sp_buffer;
34*aa22c0f3STomasz Duszynski int cpu;
35*aa22c0f3STomasz Duszynski int inuse;
36*aa22c0f3STomasz Duszynski };
37*aa22c0f3STomasz Duszynski
38*aa22c0f3STomasz Duszynski struct cnxk_gpio_irqchip {
39*aa22c0f3STomasz Duszynski int fd;
40*aa22c0f3STomasz Duszynski /* serialize access to this struct */
41*aa22c0f3STomasz Duszynski pthread_mutex_t lock;
42*aa22c0f3STomasz Duszynski LIST_HEAD(, cnxk_gpio_irq_stack) stacks;
43*aa22c0f3STomasz Duszynski
44*aa22c0f3STomasz Duszynski struct cnxk_gpiochip *gpiochip;
45*aa22c0f3STomasz Duszynski };
46*aa22c0f3STomasz Duszynski
47*aa22c0f3STomasz Duszynski static struct cnxk_gpio_irqchip *irqchip;
48*aa22c0f3STomasz Duszynski
49*aa22c0f3STomasz Duszynski static void
cnxk_gpio_irq_stack_free(int cpu)50*aa22c0f3STomasz Duszynski cnxk_gpio_irq_stack_free(int cpu)
51*aa22c0f3STomasz Duszynski {
52*aa22c0f3STomasz Duszynski struct cnxk_gpio_irq_stack *stack;
53*aa22c0f3STomasz Duszynski
54*aa22c0f3STomasz Duszynski LIST_FOREACH(stack, &irqchip->stacks, next) {
55*aa22c0f3STomasz Duszynski if (stack->cpu == cpu)
56*aa22c0f3STomasz Duszynski break;
57*aa22c0f3STomasz Duszynski }
58*aa22c0f3STomasz Duszynski
59*aa22c0f3STomasz Duszynski if (!stack)
60*aa22c0f3STomasz Duszynski return;
61*aa22c0f3STomasz Duszynski
62*aa22c0f3STomasz Duszynski if (stack->inuse)
63*aa22c0f3STomasz Duszynski stack->inuse--;
64*aa22c0f3STomasz Duszynski
65*aa22c0f3STomasz Duszynski if (stack->inuse == 0) {
66*aa22c0f3STomasz Duszynski LIST_REMOVE(stack, next);
67*aa22c0f3STomasz Duszynski rte_free(stack->sp_buffer);
68*aa22c0f3STomasz Duszynski rte_free(stack);
69*aa22c0f3STomasz Duszynski }
70*aa22c0f3STomasz Duszynski }
71*aa22c0f3STomasz Duszynski
72*aa22c0f3STomasz Duszynski static void *
cnxk_gpio_irq_stack_alloc(int cpu)73*aa22c0f3STomasz Duszynski cnxk_gpio_irq_stack_alloc(int cpu)
74*aa22c0f3STomasz Duszynski {
75*aa22c0f3STomasz Duszynski #define ARM_STACK_ALIGNMENT (2 * sizeof(void *))
76*aa22c0f3STomasz Duszynski #define IRQ_STACK_SIZE 0x200000
77*aa22c0f3STomasz Duszynski
78*aa22c0f3STomasz Duszynski struct cnxk_gpio_irq_stack *stack;
79*aa22c0f3STomasz Duszynski
80*aa22c0f3STomasz Duszynski LIST_FOREACH(stack, &irqchip->stacks, next) {
81*aa22c0f3STomasz Duszynski if (stack->cpu == cpu)
82*aa22c0f3STomasz Duszynski break;
83*aa22c0f3STomasz Duszynski }
84*aa22c0f3STomasz Duszynski
85*aa22c0f3STomasz Duszynski if (stack) {
86*aa22c0f3STomasz Duszynski stack->inuse++;
87*aa22c0f3STomasz Duszynski return (char *)stack->sp_buffer + IRQ_STACK_SIZE;
88*aa22c0f3STomasz Duszynski }
89*aa22c0f3STomasz Duszynski
90*aa22c0f3STomasz Duszynski stack = rte_malloc(NULL, sizeof(*stack), 0);
91*aa22c0f3STomasz Duszynski if (!stack)
92*aa22c0f3STomasz Duszynski return NULL;
93*aa22c0f3STomasz Duszynski
94*aa22c0f3STomasz Duszynski stack->sp_buffer =
95*aa22c0f3STomasz Duszynski rte_zmalloc(NULL, IRQ_STACK_SIZE * 2, ARM_STACK_ALIGNMENT);
96*aa22c0f3STomasz Duszynski if (!stack->sp_buffer) {
97*aa22c0f3STomasz Duszynski rte_free(stack);
98*aa22c0f3STomasz Duszynski return NULL;
99*aa22c0f3STomasz Duszynski }
100*aa22c0f3STomasz Duszynski
101*aa22c0f3STomasz Duszynski stack->cpu = cpu;
102*aa22c0f3STomasz Duszynski stack->inuse = 1;
103*aa22c0f3STomasz Duszynski LIST_INSERT_HEAD(&irqchip->stacks, stack, next);
104*aa22c0f3STomasz Duszynski
105*aa22c0f3STomasz Duszynski return (char *)stack->sp_buffer + IRQ_STACK_SIZE;
106*aa22c0f3STomasz Duszynski }
107*aa22c0f3STomasz Duszynski
108*aa22c0f3STomasz Duszynski static void
cnxk_gpio_irq_handler(int gpio_num)109*aa22c0f3STomasz Duszynski cnxk_gpio_irq_handler(int gpio_num)
110*aa22c0f3STomasz Duszynski {
111*aa22c0f3STomasz Duszynski struct cnxk_gpiochip *gpiochip = irqchip->gpiochip;
112*aa22c0f3STomasz Duszynski struct cnxk_gpio *gpio;
113*aa22c0f3STomasz Duszynski
114*aa22c0f3STomasz Duszynski if (gpio_num >= gpiochip->num_gpios)
115*aa22c0f3STomasz Duszynski goto out;
116*aa22c0f3STomasz Duszynski
117*aa22c0f3STomasz Duszynski gpio = gpiochip->gpios[gpio_num];
118*aa22c0f3STomasz Duszynski if (likely(gpio->handler))
119*aa22c0f3STomasz Duszynski gpio->handler(gpio_num, gpio->data);
120*aa22c0f3STomasz Duszynski
121*aa22c0f3STomasz Duszynski out:
122*aa22c0f3STomasz Duszynski roc_atf_ret();
123*aa22c0f3STomasz Duszynski }
124*aa22c0f3STomasz Duszynski
125*aa22c0f3STomasz Duszynski int
cnxk_gpio_irq_init(struct cnxk_gpiochip * gpiochip)126*aa22c0f3STomasz Duszynski cnxk_gpio_irq_init(struct cnxk_gpiochip *gpiochip)
127*aa22c0f3STomasz Duszynski {
128*aa22c0f3STomasz Duszynski if (irqchip)
129*aa22c0f3STomasz Duszynski return 0;
130*aa22c0f3STomasz Duszynski
131*aa22c0f3STomasz Duszynski irqchip = rte_zmalloc(NULL, sizeof(*irqchip), 0);
132*aa22c0f3STomasz Duszynski if (!irqchip)
133*aa22c0f3STomasz Duszynski return -ENOMEM;
134*aa22c0f3STomasz Duszynski
135*aa22c0f3STomasz Duszynski irqchip->fd = open("/dev/otx-gpio-ctr", O_RDWR | O_SYNC);
136*aa22c0f3STomasz Duszynski if (irqchip->fd < 0) {
137*aa22c0f3STomasz Duszynski rte_free(irqchip);
138*aa22c0f3STomasz Duszynski return -errno;
139*aa22c0f3STomasz Duszynski }
140*aa22c0f3STomasz Duszynski
141*aa22c0f3STomasz Duszynski pthread_mutex_init(&irqchip->lock, NULL);
142*aa22c0f3STomasz Duszynski LIST_INIT(&irqchip->stacks);
143*aa22c0f3STomasz Duszynski irqchip->gpiochip = gpiochip;
144*aa22c0f3STomasz Duszynski
145*aa22c0f3STomasz Duszynski return 0;
146*aa22c0f3STomasz Duszynski }
147*aa22c0f3STomasz Duszynski
148*aa22c0f3STomasz Duszynski void
cnxk_gpio_irq_fini(void)149*aa22c0f3STomasz Duszynski cnxk_gpio_irq_fini(void)
150*aa22c0f3STomasz Duszynski {
151*aa22c0f3STomasz Duszynski if (!irqchip)
152*aa22c0f3STomasz Duszynski return;
153*aa22c0f3STomasz Duszynski
154*aa22c0f3STomasz Duszynski close(irqchip->fd);
155*aa22c0f3STomasz Duszynski rte_free(irqchip);
156*aa22c0f3STomasz Duszynski irqchip = NULL;
157*aa22c0f3STomasz Duszynski }
158*aa22c0f3STomasz Duszynski
159*aa22c0f3STomasz Duszynski int
cnxk_gpio_irq_request(int gpio,int cpu)160*aa22c0f3STomasz Duszynski cnxk_gpio_irq_request(int gpio, int cpu)
161*aa22c0f3STomasz Duszynski {
162*aa22c0f3STomasz Duszynski struct otx_gpio_usr_data data;
163*aa22c0f3STomasz Duszynski void *sp;
164*aa22c0f3STomasz Duszynski int ret;
165*aa22c0f3STomasz Duszynski
166*aa22c0f3STomasz Duszynski pthread_mutex_lock(&irqchip->lock);
167*aa22c0f3STomasz Duszynski
168*aa22c0f3STomasz Duszynski sp = cnxk_gpio_irq_stack_alloc(cpu);
169*aa22c0f3STomasz Duszynski if (!sp) {
170*aa22c0f3STomasz Duszynski ret = -ENOMEM;
171*aa22c0f3STomasz Duszynski goto out_unlock;
172*aa22c0f3STomasz Duszynski }
173*aa22c0f3STomasz Duszynski
174*aa22c0f3STomasz Duszynski data.isr_base = (uint64_t)cnxk_gpio_irq_handler;
175*aa22c0f3STomasz Duszynski data.sp = (uint64_t)sp;
176*aa22c0f3STomasz Duszynski data.cpu = (uint64_t)cpu;
177*aa22c0f3STomasz Duszynski data.gpio_num = (uint64_t)gpio;
178*aa22c0f3STomasz Duszynski
179*aa22c0f3STomasz Duszynski mlockall(MCL_CURRENT | MCL_FUTURE);
180*aa22c0f3STomasz Duszynski ret = ioctl(irqchip->fd, OTX_IOC_SET_GPIO_HANDLER, &data);
181*aa22c0f3STomasz Duszynski if (ret) {
182*aa22c0f3STomasz Duszynski ret = -errno;
183*aa22c0f3STomasz Duszynski goto out_free_stack;
184*aa22c0f3STomasz Duszynski }
185*aa22c0f3STomasz Duszynski
186*aa22c0f3STomasz Duszynski pthread_mutex_unlock(&irqchip->lock);
187*aa22c0f3STomasz Duszynski
188*aa22c0f3STomasz Duszynski return 0;
189*aa22c0f3STomasz Duszynski
190*aa22c0f3STomasz Duszynski out_free_stack:
191*aa22c0f3STomasz Duszynski cnxk_gpio_irq_stack_free(cpu);
192*aa22c0f3STomasz Duszynski out_unlock:
193*aa22c0f3STomasz Duszynski pthread_mutex_unlock(&irqchip->lock);
194*aa22c0f3STomasz Duszynski
195*aa22c0f3STomasz Duszynski return ret;
196*aa22c0f3STomasz Duszynski }
197*aa22c0f3STomasz Duszynski
198*aa22c0f3STomasz Duszynski int
cnxk_gpio_irq_free(int gpio)199*aa22c0f3STomasz Duszynski cnxk_gpio_irq_free(int gpio)
200*aa22c0f3STomasz Duszynski {
201*aa22c0f3STomasz Duszynski int ret;
202*aa22c0f3STomasz Duszynski
203*aa22c0f3STomasz Duszynski pthread_mutex_lock(&irqchip->lock);
204*aa22c0f3STomasz Duszynski
205*aa22c0f3STomasz Duszynski ret = ioctl(irqchip->fd, OTX_IOC_CLR_GPIO_HANDLER, gpio);
206*aa22c0f3STomasz Duszynski if (ret) {
207*aa22c0f3STomasz Duszynski pthread_mutex_unlock(&irqchip->lock);
208*aa22c0f3STomasz Duszynski return -errno;
209*aa22c0f3STomasz Duszynski }
210*aa22c0f3STomasz Duszynski
211*aa22c0f3STomasz Duszynski cnxk_gpio_irq_stack_free(irqchip->gpiochip->gpios[gpio]->cpu);
212*aa22c0f3STomasz Duszynski
213*aa22c0f3STomasz Duszynski pthread_mutex_unlock(&irqchip->lock);
214*aa22c0f3STomasz Duszynski
215*aa22c0f3STomasz Duszynski return 0;
216*aa22c0f3STomasz Duszynski }
217