1 /*******************************************************************************
2  * Copyright 2019-2020 Microchip FPGA Embedded Systems Solutions.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * PolarFire SoC microprocessor subsystem GPIO bare metal driver implementation.
7  *
8  * This driver is based on SmartFusion2 MSS GPIO driver v2.1.102
9  *
10  */
11 
12 #include "mpfs_hal/mss_hal.h"
13 #include "mss_gpio.h"
14 
15 #ifdef __cplusplus
16 extern "C" {
17 #endif
18 
19 /*-------------------------------------------------------------------------*//**
20  * Defines.
21  */
22 #define GPIO_INT_ENABLE_MASK                ((uint32_t)0x00000008)
23 #define OUTPUT_BUFFER_ENABLE_MASK           ((uint32_t)0x00000004)
24 
25 /*These constants define the number of GPIO bits available on each GPIO
26  * hardware block*/
27 #define NB_OF_GPIO_GPIO0                    ((uint32_t)14)
28 #define NB_OF_GPIO_GPIO1                    ((uint32_t)24)
29 #define NB_OF_GPIO_GPIO2                    ((uint32_t)32)
30 
31 /*This constant indicates the total number of GPIO interrupt inputs at the PLIC
32  * (includes the direct and non-direct GPIO interrupts)*/
33 #define NB_OF_GPIO_INTR                     ((uint32_t)41)
34 
35 /*-------------------------------------------------------------------------*//**
36  * Lookup table of GPIO interrupt number indexed on GPIO ID.
37  * The GPIO interrupts are multiplexed. Total GPIO interrupts are 41.
38  * 41 = (14 from GPIO0 + 24 from GPIO1 + 3 non direct interrupts)
39  * GPIO2 interrupts are not available by default. Setting the corresponding bit
40  * in GPIO_INTERRUPT_FAB_CR(31:0) will enable GPIO2(31:0) corresponding
41  * interrupt on PLIC.
42  *
43  * PLIC       GPIO_INTERRUPT_FAB_CR
44                 0               1
45     0       GPIO0 bit 0     GPIO2 bit 0
46     1       GPIO0 bit 1     GPIO2 bit 1
47     .
48     .
49     12      GPIO0 bit 12    GPIO2 bit 12
50     13      GPIO0 bit 13    GPIO2 bit 13
51     14      GPIO1 bit 0     GPIO2 bit 14
52     15      GPIO1 bit 1     GPIO2 bit 15
53     .
54     .
55     .
56     30      GPIO1 bit 16    GPIO2 bit 30
57     31      GPIO1 bit 17    GPIO2 bit 31
58     32          GPIO1 bit 18
59     33          GPIO1 bit 19
60     34          GPIO1 bit 20
61     35          GPIO1 bit 21
62     36          GPIO1 bit 22
63     37          GPIO1 bit 23
64     38  Or of all GPIO0 interrupts who do not have a direct connection enabled
65     39  Or of all GPIO1 interrupts who do not have a direct connection enabled
66     40  Or of all GPIO2 interrupts who do not have a direct connection enabled
67  *
68  */
69 static const PLIC_IRQn_Type g_gpio_irqn_lut[NB_OF_GPIO_INTR] =
70 {
71     GPIO0_BIT0_or_GPIO2_BIT0_PLIC_0,
72     GPIO0_BIT1_or_GPIO2_BIT1_PLIC_1,
73     GPIO0_BIT2_or_GPIO2_BIT2_PLIC_2,
74     GPIO0_BIT3_or_GPIO2_BIT3_PLIC_3,
75     GPIO0_BIT4_or_GPIO2_BIT4_PLIC_4,
76     GPIO0_BIT5_or_GPIO2_BIT5_PLIC_5,
77     GPIO0_BIT6_or_GPIO2_BIT6_PLIC_6,
78     GPIO0_BIT7_or_GPIO2_BIT7_PLIC_7,
79     GPIO0_BIT8_or_GPIO2_BIT8_PLIC_8,
80     GPIO0_BIT9_or_GPIO2_BIT9_PLIC_9,
81     GPIO0_BIT10_or_GPIO2_BIT10_PLIC_10,
82     GPIO0_BIT11_or_GPIO2_BIT11_PLIC_11,
83     GPIO0_BIT12_or_GPIO2_BIT12_PLIC_12,
84     GPIO0_BIT13_or_GPIO2_BIT13_PLIC_13,
85 
86     GPIO1_BIT0_or_GPIO2_BIT14_PLIC_14,
87     GPIO1_BIT1_or_GPIO2_BIT15_PLIC_15,
88     GPIO1_BIT2_or_GPIO2_BIT16_PLIC_16,
89     GPIO1_BIT3_or_GPIO2_BIT17_PLIC_17,
90     GPIO1_BIT4_or_GPIO2_BIT18_PLIC_18,
91     GPIO1_BIT5_or_GPIO2_BIT19_PLIC_19,
92     GPIO1_BIT6_or_GPIO2_BIT20_PLIC_20,
93     GPIO1_BIT7_or_GPIO2_BIT21_PLIC_21,
94     GPIO1_BIT8_or_GPIO2_BIT22_PLIC_22,
95     GPIO1_BIT9_or_GPIO2_BIT23_PLIC_23,
96     GPIO1_BIT10_or_GPIO2_BIT24_PLIC_24,
97     GPIO1_BIT11_or_GPIO2_BIT25_PLIC_25,
98     GPIO1_BIT12_or_GPIO2_BIT26_PLIC_26,
99     GPIO1_BIT13_or_GPIO2_BIT27_PLIC_27,
100     GPIO1_BIT14_or_GPIO2_BIT28_PLIC_28,
101     GPIO1_BIT15_or_GPIO2_BIT29_PLIC_29,
102     GPIO1_BIT16_or_GPIO2_BIT30_PLIC_30,
103     GPIO1_BIT17_or_GPIO2_BIT31_PLIC_31,
104 
105     GPIO1_BIT18_PLIC_32,
106     GPIO1_BIT19_PLIC_33,
107     GPIO1_BIT20_PLIC_34,
108     GPIO1_BIT21_PLIC_35,
109     GPIO1_BIT22_PLIC_36,
110     GPIO1_BIT23_PLIC_37,
111 
112     GPIO0_NON_DIRECT_PLIC,
113     GPIO1_NON_DIRECT_PLIC,
114     GPIO2_NON_DIRECT_PLIC
115 };
116 
117 /*-------------------------------------------------------------------------*//**
118  * Local functions
119  */
120 static uint8_t gpio_number_validate(GPIO_TypeDef const * gpio, mss_gpio_id_t gpio_idx);
121 
122 /*-------------------------------------------------------------------------*//**
123  * MSS_GPIO_init
124  * See "mss_gpio.h" for details of how to use this function.
125  */
126 void
MSS_GPIO_init(GPIO_TypeDef * gpio)127 MSS_GPIO_init
128 (
129     GPIO_TypeDef * gpio
130 )
131 {
132     /* clear all pending interrupts*/
133     gpio->GPIO_IRQ = 0xFFFFFFFFU;
134 }
135 
136 /*-------------------------------------------------------------------------*//**
137  * MSS_GPIO_config
138  * See "mss_gpio.h" for details of how to use this function.
139  */
MSS_GPIO_config(GPIO_TypeDef * gpio,mss_gpio_id_t port_id,uint32_t config)140 void MSS_GPIO_config
141 (
142     GPIO_TypeDef * gpio,
143     mss_gpio_id_t port_id,
144     uint32_t config
145 )
146 {
147     if (0U == gpio_number_validate(gpio, port_id))
148     {
149         gpio->GPIO_CFG[port_id] = config;
150     }
151     else
152     {
153         ASSERT(0); /*LDRA warning*/
154     }
155 }
156 
157 /*-------------------------------------------------------------------------*//**
158  * MSS_GPIO_config_byte
159  * See "mss_gpio.h" for details of how to use this function.
160  */
MSS_GPIO_config_byte(GPIO_TypeDef * gpio,mss_gpio_byte_num_t byte_num,uint32_t config)161 void MSS_GPIO_config_byte
162 (
163     GPIO_TypeDef * gpio,
164     mss_gpio_byte_num_t byte_num,
165     uint32_t config
166 )
167 {
168     if (((GPIO0_LO == gpio) || (GPIO0_HI == gpio)) &&
169                                                  (byte_num >= MSS_GPIO_BYTE_1))
170     {
171         ASSERT(0);
172     }
173     else if (((GPIO1_LO == gpio) || (GPIO1_HI == gpio)) &&
174                                                   (byte_num > MSS_GPIO_BYTE_2))
175     {
176         ASSERT(0);
177     }
178     else if (((GPIO2_LO == gpio) || (GPIO2_HI == gpio)) &&
179                                                   (byte_num > MSS_GPIO_BYTE_3))
180     {
181         ASSERT(0);
182     }
183     else
184     {
185         gpio->GPIO_CFG_BYTE[byte_num] = config;
186     }
187 }
188 
189 /*-------------------------------------------------------------------------*//**
190  * MSS_GPIO_config_all
191  * See "mss_gpio.h" for details of how to use this function.
192  */
MSS_GPIO_config_all(GPIO_TypeDef * gpio,uint32_t config)193 void MSS_GPIO_config_all
194 (
195     GPIO_TypeDef * gpio,
196     uint32_t config
197 )
198 {
199     gpio->GPIO_CFG_ALL = config;
200 }
201 
202 /*-------------------------------------------------------------------------*//**
203  * MSS_GPIO_set_output
204  * See "mss_gpio.h" for details of how to use this function.
205  */
MSS_GPIO_set_output(GPIO_TypeDef * gpio,mss_gpio_id_t port_id,uint8_t value)206 void MSS_GPIO_set_output
207 (
208     GPIO_TypeDef * gpio,
209     mss_gpio_id_t port_id,
210     uint8_t value
211 )
212 {
213     uint32_t gpio_setting;
214 
215     if (0U == gpio_number_validate(gpio, port_id))
216     {
217         /* Setting the bit in GPIO_SET_BITS (offset 0xA4) sets the corresponding
218          * output port.
219          * Setting the bit in GPIO_CLR_BITS (offset 0xA0) clears the
220          * corresponding output port.*/
221 
222         if (value > 0u)
223         {
224             gpio->GPIO_SET_BITS = ((uint32_t)0x01 << port_id);
225         }
226         else
227         {
228             gpio->GPIO_CLR_BITS = ((uint32_t)0x01 << port_id);
229         }
230     }
231     else
232     {
233         ASSERT(0); /*LDRA warning*/
234     }
235 }
236 
237 /*-------------------------------------------------------------------------*//**
238  * MSS_GPIO_drive_inout
239  * See "mss_gpio.h" for details of how to use this function.
240  */
MSS_GPIO_drive_inout(GPIO_TypeDef * gpio,mss_gpio_id_t port_id,mss_gpio_inout_state_t inout_state)241 void MSS_GPIO_drive_inout
242 (
243     GPIO_TypeDef * gpio,
244     mss_gpio_id_t port_id,
245     mss_gpio_inout_state_t inout_state
246 )
247 {
248     uint32_t outputs_state;
249     uint32_t config;
250 
251     if (0U == gpio_number_validate(gpio, port_id))
252     {
253         switch (inout_state)
254         {
255             case MSS_GPIO_DRIVE_HIGH:
256                 /* Set output high */
257                 gpio->GPIO_SET_BITS = ((uint32_t)1 << port_id);
258 
259                 /* Enable output buffer */
260                 config = gpio->GPIO_CFG[port_id];
261                 config |= OUTPUT_BUFFER_ENABLE_MASK;
262                 gpio->GPIO_CFG[port_id] = config;
263             break;
264 
265             case MSS_GPIO_DRIVE_LOW:
266                 /* Set output low */
267                 gpio->GPIO_CLR_BITS = (uint32_t)1 << port_id;
268                 /* Enable output buffer */
269                 config = gpio->GPIO_CFG[port_id];
270                 config |= OUTPUT_BUFFER_ENABLE_MASK;
271                 gpio->GPIO_CFG[port_id] = config;
272             break;
273 
274             case MSS_GPIO_HIGH_Z:
275                 /* Disable output buffer */
276                 config = gpio->GPIO_CFG[port_id];
277                 config &= ~OUTPUT_BUFFER_ENABLE_MASK;
278                 gpio->GPIO_CFG[port_id] = config;
279             break;
280 
281             default:
282                 ASSERT(0);
283             break;
284         }
285     }
286     else
287     {
288         ASSERT(0); /*LDRA warning*/
289     }
290 }
291 
292 /*-------------------------------------------------------------------------*//**
293  * MSS_GPIO_enable_irq
294  * See "mss_gpio.h" for details of how to use this function.
295  */
MSS_GPIO_enable_irq(GPIO_TypeDef * gpio,mss_gpio_id_t port_id)296 void MSS_GPIO_enable_irq
297 (
298     GPIO_TypeDef * gpio,
299     mss_gpio_id_t port_id
300 )
301 {
302     uint32_t cfg_value;
303 
304     if (0U == gpio_number_validate(gpio, port_id))
305     {
306         cfg_value = gpio->GPIO_CFG[(uint8_t)port_id];
307         gpio->GPIO_CFG[(uint8_t)port_id] = (cfg_value | GPIO_INT_ENABLE_MASK);
308 
309         if ((GPIO0_LO == gpio) || (GPIO0_HI == gpio))
310         {
311             PLIC_EnableIRQ(g_gpio_irqn_lut[port_id]);
312         }
313         else if ((GPIO1_LO == gpio) || (GPIO1_HI == gpio))
314         {
315             PLIC_EnableIRQ(g_gpio_irqn_lut[port_id +
316                                            GPIO1_BIT0_or_GPIO2_BIT14_PLIC_14]);
317         }
318         else if ((GPIO2_LO == gpio) || (GPIO2_HI == gpio))
319         {
320             PLIC_EnableIRQ(g_gpio_irqn_lut[port_id]);
321         }
322         else
323         {
324             ASSERT(0); /*LDRA warning*/
325         }
326     }
327     else
328     {
329         ASSERT(0); /*LDRA warning*/
330     }
331 }
332 
333 /*-------------------------------------------------------------------------*//**
334  * MSS_GPIO_disable_irq
335  * See "mss_gpio.h" for details of how to use this function.
336  */
337 
MSS_GPIO_disable_irq(GPIO_TypeDef * gpio,mss_gpio_id_t port_id)338 void MSS_GPIO_disable_irq
339 (
340     GPIO_TypeDef * gpio,
341     mss_gpio_id_t port_id
342 )
343 {
344     uint32_t cfg_value;
345 
346     if (0U == gpio_number_validate(gpio, port_id))
347     {
348         cfg_value = gpio->GPIO_CFG[(uint8_t)port_id];
349         gpio->GPIO_CFG[(uint8_t)port_id] = (cfg_value & (~GPIO_INT_ENABLE_MASK));
350 
351         if ((GPIO0_LO == gpio) || (GPIO0_HI == gpio))
352         {
353             PLIC_DisableIRQ(g_gpio_irqn_lut[port_id]);
354         }
355         else if ((GPIO1_LO == gpio) || (GPIO1_HI == gpio))
356         {
357             PLIC_DisableIRQ(g_gpio_irqn_lut[port_id +
358                                             GPIO1_BIT0_or_GPIO2_BIT14_PLIC_14]);
359         }
360         else if ((GPIO2_LO == gpio) || (GPIO2_HI == gpio))
361         {
362             PLIC_DisableIRQ(GPIO2_NON_DIRECT_PLIC);
363         }
364         else
365         {
366             ASSERT(0); /*LDRA warning*/
367         }
368     }
369     else
370     {
371         ASSERT(0); /*LDRA warning*/
372     }
373 }
374 
375 /*-------------------------------------------------------------------------*//**
376  * MSS_GPIO_enable_nondirect_irq
377  * See "mss_gpio.h" for details of how to use this function.
378  */
379 void
MSS_GPIO_enable_nondirect_irq(GPIO_TypeDef const * gpio)380 MSS_GPIO_enable_nondirect_irq
381 (
382     GPIO_TypeDef const * gpio
383 )
384 {
385     if ((GPIO0_LO == gpio) || (GPIO0_HI == gpio))
386     {
387         PLIC_EnableIRQ(GPIO0_NON_DIRECT_PLIC);
388     }
389     else if ((GPIO1_LO == gpio) || (GPIO1_HI == gpio))
390     {
391         PLIC_EnableIRQ(GPIO1_NON_DIRECT_PLIC);
392     }
393     else if ((GPIO2_LO == gpio) || (GPIO2_HI == gpio))
394     {
395         PLIC_EnableIRQ(GPIO2_NON_DIRECT_PLIC);
396     }
397     else
398     {
399         ASSERT(0); /*LDRA warning*/
400     }
401 }
402 
403 /*-------------------------------------------------------------------------*//**
404  * MSS_GPIO_disable_nondirect_irq
405  * See "mss_gpio.h" for details of how to use this function.
406  */
407 void
MSS_GPIO_disable_nondirect_irq(GPIO_TypeDef const * gpio)408 MSS_GPIO_disable_nondirect_irq
409 (
410     GPIO_TypeDef const * gpio
411 )
412 {
413     if ((GPIO0_LO == gpio) || (GPIO0_HI == gpio))
414     {
415         PLIC_DisableIRQ(GPIO0_NON_DIRECT_PLIC);
416     }
417     else if ((GPIO1_LO == gpio) || (GPIO1_HI == gpio))
418     {
419         PLIC_DisableIRQ(GPIO1_NON_DIRECT_PLIC);
420     }
421     else if ((GPIO2_LO == gpio) || (GPIO2_HI == gpio))
422     {
423         PLIC_DisableIRQ(GPIO2_NON_DIRECT_PLIC);
424     }
425     else
426     {
427         ASSERT(0); /*LDRA warning*/
428     }
429 }
430 
431 /*-------------------------------------------------------------------------*//**
432  * MSS_GPIO_clear_irq
433  * See "mss_gpio.h" for details of how to use this function.
434  */
MSS_GPIO_clear_irq(GPIO_TypeDef * gpio,mss_gpio_id_t port_id)435 void MSS_GPIO_clear_irq
436 (
437     GPIO_TypeDef * gpio,
438     mss_gpio_id_t port_id
439 )
440 {
441     if (0U == gpio_number_validate(gpio, port_id))
442     {
443         gpio->GPIO_IRQ = ((uint32_t)1) << port_id;
444         __asm("fence");
445     }
446     else
447     {
448         ASSERT(0); /*LDRA warning*/
449     }
450 }
451 
gpio_number_validate(GPIO_TypeDef const * gpio,mss_gpio_id_t gpio_idx)452 static uint8_t gpio_number_validate(GPIO_TypeDef const * gpio, mss_gpio_id_t gpio_idx)
453 {
454     uint8_t ret;
455 
456     if (((GPIO0_LO == gpio) || (GPIO0_HI == gpio)) &&
457                                                 (gpio_idx >= NB_OF_GPIO_GPIO0))
458     {
459         ret = 1u;
460     }
461     else if (((GPIO1_LO == gpio) || (GPIO1_HI == gpio)) &&
462                                                 (gpio_idx >= NB_OF_GPIO_GPIO1))
463     {
464         ret = 1u;
465     }
466     else if (((GPIO2_LO == gpio) || (GPIO2_HI == gpio)) &&
467                                                 (gpio_idx >= NB_OF_GPIO_GPIO2))
468     {
469         ret = 1u;
470     }
471     else
472     {
473         ret = 0u;
474     }
475 
476     return ret;
477 }
478 
479 #ifdef __cplusplus
480 }
481 #endif
482