1 /*******************************************************************************
2  * Copyright 2019-2020 Microchip FPGA Embedded Systems Solutions.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  *
24  *
25  * PolarFire SoC Microprocessor Subsystem GPIO bare metal software driver
26  * public API.
27  *
28  * This driver is based on SmartFusion2 MSS GPIO driver v2.1.102
29  *
30  */
31 
32 /*=========================================================================*//**
33   @mainpage PolarFire SoC MSS GPIO Bare Metal Driver
34 
35   ==============================================================================
36   Introduction
37   ==============================================================================
38   The PolarFire SoC Microprocessor Subsystem (MSS) includes three blocks of
39   general  purpose input/outputs (GPIO). The GPIO0, GPIO1 and GPIO2 blocks have
40   14, 24 and 32 GPIO ports respectively. This software driver provides a set of
41   functions for controlling the MSS GPIO blocks as part of a bare metal system
42   where no operating system is available. This driver can be adapted for use as
43   part of an operating system but the implementation of the adaptation layer
44   between this driver and the operating system's driver model is outside the
45   scope of this driver.
46 
47   ==============================================================================
48   Hardware Flow Dependencies
49   ==============================================================================
50   The configuration of all features of the MSS GPIO peripherals is covered by
51   this driver with the exception of the PolarFire SoC IOMUX configuration.
52   PolarFire SoC allows multiple non-concurrent uses of some external pins
53   through IOMUX configuration. This feature allows optimization of external pin
54   usage by assigning external pins for use by either the microprocessor
55   subsystem or the FPGA fabric. The MSS GPIO signals are routed through
56   IOMUXs to the PolarFire SoC device external pins. The MSS GPIO serial
57   signals may also be routed through IOMUXs to the PolarFire SoC FPGA fabric.
58   For more information on IOMUX, refer to the IOMUX section of the PolarFire SoC
59   Microprocessor Subsystem (MSS) User's Guide.
60 
61   The IOMUXs are configured using the PolarFire SoC MSS configurator tool. You
62   must ensure that the MSS GPIO peripherals are enabled and configured in the
63   PolarFire SoC MSS configurator if you wish to use them. For more information
64   on IOMUXs, refer to the IOMUX section of the PolarFire SoC microprocessor
65   Subsystem (MSS) User's Guide.
66 
67   On PolarFire SoC an AXI switch forms a bus matrix interconnect among multiple
68   masters and multiple slaves. Five RISC-V CPUs connect to the Master ports
69   M10 to M14 of the AXI switch. By default, all the APB peripherals are
70   accessible on AXI-Slave 5 of the AXI switch via the AXI to AHB and AHB to APB
71   bridges (referred as main APB bus). However, to support logical separation in
72   the Asymmetric Multi-Processing (AMP) mode of operation, the APB peripherals
73   can alternatively be accessed on the AXI-Slave 6 via the AXI to AHB and AHB to
74   APB bridges (referred as the AMP APB bus).
75 
76   Application must make sure that the desired GPIO instance is appropriately
77   configured on one of the APB bus described above by configuring the PolarFire
78   SoC system registers (SYSREG) as per the application need and that the
79   appropriate data structures are provided to this driver as parameter to the
80   functions provided by this driver.
81 
82   The base address and register addresses are defined in this driver as
83   constants. The interrupt number assignment for the MSS GPIO peripherals are
84   defined as constants in the MPFS HAL. You must ensure that the latest MPFS HAL
85   is included in the project settings of the SoftConsole tool chain and that it
86   is generated into your project.
87 
88   ==============================================================================
89   Theory of Operation
90   ==============================================================================
91   The MSS GPIO driver functions are grouped into the following categories:
92     - Initialization
93     - Configuration
94     - Reading and setting GPIO state
95     - Interrupt control
96 
97   --------------------------------
98   Initialization
99   --------------------------------
100   The MSS GPIO driver is initialized through a call to the MSS_GPIO_init()
101   function. The MSS_GPIO_init() function must be called before any other MSS
102   GPIO driver functions can be called.
103 
104   --------------------------------
105   Configuration
106   --------------------------------
107   Each GPIO port is individually configured through a call to the
108   MSS_GPIO_config() function. Configuration includes deciding if a GPIO port
109   will be used as an input, an output or both. GPIO ports configured as inputs
110   can be further configured to generate interrupts based on the input's state.
111   Interrupts can be level or edge sensitive. The MSS_GPIO_config_byte() function
112   can be used to configure eight consecutive GPIO ports identically. The
113   MSS_GPIO_config_byte() function can be used to configure all available GPIO
114   ports identically.
115 
116   --------------------------------
117   Reading and Setting GPIO State
118   --------------------------------
119   The state of the GPIO ports can be read and set using the following functions:
120     - MSS_GPIO_get_inputs()
121     - MSS_GPIO_get_outputs()
122     - MSS_GPIO_set_outputs()
123     - MSS_GPIO_set_output()
124     - MSS_GPIO_drive_inout()
125 
126   --------------------------------
127   Interrupt Control
128   --------------------------------
129   Interrupts generated by GPIO ports configured as inputs are controlled using
130   the following functions:
131     - MSS_GPIO_enable_irq()
132     - MSS_GPIO_disable_irq()
133     - MSS_GPIO_clear_irq()
134     - MSS_GPIO_get_irq()
135     - MSS_GPIO_enable_nondirect_irq()
136     - MSS_GPIO_disable_nondirect_irq()
137 
138   The GPIO interrupts are multiplexed. Total GPIO interrupt inputs on PLIC are
139   41.
140 
141   41 = (14 from GPIO0 + 24 from GPIO1 + 3 non direct interrupts)
142   GPIO2 interrupts are not available by default. Setting the corresponding bit
143   in GPIO_INTERRUPT_FAB_CR(31:0) system register will enable GPIO2(31:0)
144   corresponding interrupt on PLIC. e.g. If GPIO_INTERRUPT_FAB_CR bit0 is set
145   then GPIO2 bit0 interrupt is available on the direct input pin on the PLIC.
146   In this case GPIO0 bit 0 interrupt will not be available on the direct input
147   pin on the PLIC however, the GPIO0 non-direct input will be asserted as OR of
148   all the GPIO0 interrupts which don't have a direct interrupt input on PLIC are
149   connected to corresponding non-direct input pin. The table below explains all
150   the GPIO direct and non-direct interrupt connectivity options.
151 
152   | PLIC | GPIO_INTERRUPT_FAB_CR = 0 | GPIO_INTERRUPT_FAB_CR = 1 |
153   |------|---------------------------|---------------------------|
154   |   0  |      GPIO0 bit 0          |        GPIO2 bit 0        |
155   |   1  |      GPIO0 bit 1          |        GPIO2 bit 1        |
156   |  ... |         ...               |        ...                |
157   |  12  |      GPIO0 bit 12         |        GPIO2 bit 12       |
158   |  13  |      GPIO0 bit 13         |        GPIO2 bit 13       |
159   |  14  |      GPIO1 bit 0          |        GPIO2 bit 14       |
160   |  15  |      GPIO1 bit 1          |        GPIO2 bit 15       |
161   |  ... |          ...              |             ...           |
162   |  30  |      GPIO1  bit 16        |        GPIO2 bit 30       |
163   |  31  |      GPIO1  bit 17        |        GPIO2 bit 31       |
164 
165 
166   | PLIC |                           Interrupt source                           |
167   |------|----------------------------------------------------------------------|
168   |  32  |                             GPIO1 bit 18                             |
169   |  33  |                             GPIO1 bit 19                             |
170   |  34  |                             GPIO1 bit 20                             |
171   |  35  |                             GPIO1 bit 21                             |
172   |  36  |                             GPIO1 bit 22                             |
173   |  37  |                             GPIO1 bit 23                             |
174   |  38  | OR of all GPIO0 interrupts who don't have a direct connection enabled|
175   |  39  | OR of all GPIO1 interrupts who don't have a direct connection enabled|
176   |  40  | OR of all GPIO2 interrupts who don't have a direct connection enabled|
177 
178 
179     NOTE: GPIO_INTERRUPT_FAB_CR controls the multiplexing in above table. It is
180     your responsibility to set up the GPIO_INTERRUPT_FAB_CR bits in application
181     code. you must make sure that you are using the valid combination of
182     GPIO0/1/2 interrupt per above table.
183 
184  *//*=========================================================================*/
185 #ifndef MSS_GPIO_H_
186 #define MSS_GPIO_H_
187 
188 #ifdef __cplusplus
189 extern "C" {
190 #endif
191 
192 #include <stdint.h>
193 
194 /*-------------------------------------------------------------------------*//**
195   The mss_gpio_id_t enumeration is used to identify individual GPIO ports as an
196   argument to functions:
197     - MSS_GPIO_config()
198     - MSS_GPIO_set_output() and MSS_GPIO_drive_inout()
199     - MSS_GPIO_enable_irq(), MSS_GPIO_disable_irq() and MSS_GPIO_clear_irq()
200 
201   Note that the GPIO0, GPIO1 and GPIO2 blocks have 14, 24 and 32 GPIO ports
202   respectively.
203  */
204 typedef enum mss_gpio_id
205 {
206     MSS_GPIO_0 = 0,
207     MSS_GPIO_1 = 1,
208     MSS_GPIO_2 = 2,
209     MSS_GPIO_3 = 3,
210     MSS_GPIO_4 = 4,
211     MSS_GPIO_5 = 5,
212     MSS_GPIO_6 = 6,
213     MSS_GPIO_7 = 7,
214     MSS_GPIO_8 = 8,
215     MSS_GPIO_9 = 9,
216     MSS_GPIO_10 = 10,
217     MSS_GPIO_11 = 11,
218     MSS_GPIO_12 = 12,
219     MSS_GPIO_13 = 13,
220     MSS_GPIO_14 = 14,
221     MSS_GPIO_15 = 15,
222     MSS_GPIO_16 = 16,
223     MSS_GPIO_17 = 17,
224     MSS_GPIO_18 = 18,
225     MSS_GPIO_19 = 19,
226     MSS_GPIO_20 = 20,
227     MSS_GPIO_21 = 21,
228     MSS_GPIO_22 = 22,
229     MSS_GPIO_23 = 23,
230     MSS_GPIO_24 = 24,
231     MSS_GPIO_25 = 25,
232     MSS_GPIO_26 = 26,
233     MSS_GPIO_27 = 27,
234     MSS_GPIO_28 = 28,
235     MSS_GPIO_29 = 29,
236     MSS_GPIO_30 = 30,
237     MSS_GPIO_31 = 31
238 } mss_gpio_id_t;
239 
240 /*-------------------------------------------------------------------------*//**
241   The mss_gpio_inout_state_t enumeration is used to specify the output state of
242   an INOUT GPIO port as an argument to the MSS_GPIO_drive_inout() function.
243  */
244 typedef enum mss_gpio_inout_state
245 {
246     MSS_GPIO_DRIVE_LOW = 0,
247     MSS_GPIO_DRIVE_HIGH,
248     MSS_GPIO_HIGH_Z
249 } mss_gpio_inout_state_t;
250 
251 /*-------------------------------------------------------------------------*//**
252   The mss_gpio_byte_num_t enumeration is used to specify the set of the 8
253   consecutive GPIO ports that are to be configured as an argument to the
254   MSS_GPIO_config_byte() function.
255  */
256 typedef enum mss_gpio_byte_num
257 {
258     MSS_GPIO_BYTE_0 = 0,
259     MSS_GPIO_BYTE_1,
260     MSS_GPIO_BYTE_2,
261     MSS_GPIO_BYTE_3,
262     MSS_GPIO_BYTE_INVALID,
263 } mss_gpio_byte_num_t;
264 
265 /*-------------------------------------------------------------------------*//**
266   GPIO Instance Identification
267   ============================
268   These constants are provided for the application use. These constants must be
269   passed as a first parameter of all the APIs provided by this driver. The
270   GPIO0_LO, GPIO1_LO, GPIO2_LO represent the GPIO0, GPIO1 and GPIO2 hardware
271   blocks when they are connected on the main APB bus. The GPIO0_HI, GPIO1_HI,
272   GPIO2_HI represent the GPIO0, GPIO1 and GPIO2 hardware blocks when they are
273   connected on the AMP APB bus.
274 
275   | Constant | Description                           |
276   |----------|---------------------------------------|
277   | GPIO0_LO | GPIO0 block connected on main APB bus |
278   | GPIO1_LO | GPIO1 block connected on main APB bus |
279   | GPIO2_LO | GPIO2 block connected on main APB bus |
280   | GPIO0_HI | GPIO0 block connected on AMP APB bus  |
281   | GPIO1_HI | GPIO1 block connected on AMP APB bus  |
282   | GPIO2_HI | GPIO2 block connected on AMP APB bus  |
283 
284  */
285 #define GPIO0_LO                        ((GPIO_TypeDef*)0x20120000UL)
286 #define GPIO1_LO                        ((GPIO_TypeDef*)0x20121000UL)
287 #define GPIO2_LO                        ((GPIO_TypeDef*)0x20122000UL)
288 #define GPIO0_HI                        ((GPIO_TypeDef*)0x28120000UL)
289 #define GPIO1_HI                        ((GPIO_TypeDef*)0x28121000UL)
290 #define GPIO2_HI                        ((GPIO_TypeDef*)0x28122000UL)
291 
292 /*-------------------------------------------------------------------------*//**
293   GPIO Port Masks
294   ===============
295   These constant definitions are used as an argument to the
296   MSS_GPIO_set_outputs() function to identify GPIO ports. A logical OR of these
297   constants can be used to specify multiple GPIO ports.
298   These definitions can also be used to identify GPIO ports through logical
299   operations on the return value of the MSS_GPIO_get_inputs() function.
300 
301   | Constant         | Description           |
302   |------------------|-----------------------|
303   | MSS_GPIO_0_MASK  | GPIO port 0-bit mask  |
304   | MSS_GPIO_1_MASK  | GPIO port 1-bit mask  |
305   | MSS_GPIO_2_MASK  | GPIO port 2-bit mask  |
306   | MSS_GPIO_3_MASK  | GPIO port 3-bit mask  |
307   | MSS_GPIO_4_MASK  | GPIO port 4-bit mask  |
308   | MSS_GPIO_5_MASK  | GPIO port 5-bit mask  |
309   | MSS_GPIO_6_MASK  | GPIO port 6-bit mask  |
310   | MSS_GPIO_7_MASK  | GPIO port 7-bit mask  |
311   | MSS_GPIO_8_MASK  | GPIO port 8-bit mask  |
312   | MSS_GPIO_9_MASK  | GPIO port 9-bit mask  |
313   | MSS_GPIO_10_MASK | GPIO port 10-bit mask |
314   | MSS_GPIO_11_MASK | GPIO port 11-bit mask |
315   | MSS_GPIO_12_MASK | GPIO port 12-bit mask |
316   | MSS_GPIO_13_MASK | GPIO port 13-bit mask |
317   | MSS_GPIO_14_MASK | GPIO port 14-bit mask |
318   | MSS_GPIO_15_MASK | GPIO port 15-bit mask |
319   | MSS_GPIO_16_MASK | GPIO port 16-bit mask |
320   | MSS_GPIO_17_MASK | GPIO port 17-bit mask |
321   | MSS_GPIO_18_MASK | GPIO port 18-bit mask |
322   | MSS_GPIO_19_MASK | GPIO port 19-bit mask |
323   | MSS_GPIO_20_MASK | GPIO port 20-bit mask |
324   | MSS_GPIO_21_MASK | GPIO port 21-bit mask |
325   | MSS_GPIO_22_MASK | GPIO port 22-bit mask |
326   | MSS_GPIO_23_MASK | GPIO port 23-bit mask |
327   | MSS_GPIO_24_MASK | GPIO port 24-bit mask |
328   | MSS_GPIO_25_MASK | GPIO port 25-bit mask |
329   | MSS_GPIO_26_MASK | GPIO port 26-bit mask |
330   | MSS_GPIO_27_MASK | GPIO port 27-bit mask |
331   | MSS_GPIO_28_MASK | GPIO port 28-bit mask |
332   | MSS_GPIO_29_MASK | GPIO port 29-bit mask |
333   | MSS_GPIO_30_MASK | GPIO port 30-bit mask |
334   | MSS_GPIO_31_MASK | GPIO port 31-bit mask |
335 
336  */
337 #define MSS_GPIO_0_MASK         0x00000001UL
338 #define MSS_GPIO_1_MASK         0x00000002UL
339 #define MSS_GPIO_2_MASK         0x00000004UL
340 #define MSS_GPIO_3_MASK         0x00000008UL
341 #define MSS_GPIO_4_MASK         0x00000010UL
342 #define MSS_GPIO_5_MASK         0x00000020UL
343 #define MSS_GPIO_6_MASK         0x00000040UL
344 #define MSS_GPIO_7_MASK         0x00000080UL
345 #define MSS_GPIO_8_MASK         0x00000100UL
346 #define MSS_GPIO_9_MASK         0x00000200UL
347 #define MSS_GPIO_10_MASK        0x00000400UL
348 #define MSS_GPIO_11_MASK        0x00000800UL
349 #define MSS_GPIO_12_MASK        0x00001000UL
350 #define MSS_GPIO_13_MASK        0x00002000UL
351 #define MSS_GPIO_14_MASK        0x00004000UL
352 #define MSS_GPIO_15_MASK        0x00008000UL
353 #define MSS_GPIO_16_MASK        0x00010000UL
354 #define MSS_GPIO_17_MASK        0x00020000UL
355 #define MSS_GPIO_18_MASK        0x00040000UL
356 #define MSS_GPIO_19_MASK        0x00080000UL
357 #define MSS_GPIO_20_MASK        0x00100000UL
358 #define MSS_GPIO_21_MASK        0x00200000UL
359 #define MSS_GPIO_22_MASK        0x00400000UL
360 #define MSS_GPIO_23_MASK        0x00800000UL
361 #define MSS_GPIO_24_MASK        0x01000000UL
362 #define MSS_GPIO_25_MASK        0x02000000UL
363 #define MSS_GPIO_26_MASK        0x04000000UL
364 #define MSS_GPIO_27_MASK        0x08000000UL
365 #define MSS_GPIO_28_MASK        0x10000000UL
366 #define MSS_GPIO_29_MASK        0x20000000UL
367 #define MSS_GPIO_30_MASK        0x40000000UL
368 #define MSS_GPIO_31_MASK        0x80000000UL
369 
370 /*-------------------------------------------------------------------------*//**
371   GPIO Port I/O Mode
372   ==================
373   These constant definitions are used as an argument to the MSS_GPIO_config()
374   function to specify the I/O mode of each GPIO port.
375 
376   | Constant             | Description                |
377   |----------------------|----------------------------|
378   | MSS_GPIO_INPUT_MODE  | Input port only            |
379   | MSS_GPIO_OUTPUT_MODE | Output port only           |
380   | MSS_GPIO_INOUT_MODE  | Both input and output port |
381 
382  */
383 #define MSS_GPIO_INPUT_MODE              0x0000000002UL
384 #define MSS_GPIO_OUTPUT_MODE             0x0000000005UL
385 #define MSS_GPIO_INOUT_MODE              0x0000000003UL
386 
387 /*-------------------------------------------------------------------------*//**
388   GPIO Interrupt Mode
389   ===================
390   These constant definitions are used as an argument to the MSS_GPIO_config()
391   function to specify the interrupt mode of each GPIO port.
392 
393   | Constant                   | Description                                         |
394   |----------------------------|-----------------------------------------------------|
395   | MSS_GPIO_IRQ_LEVEL_HIGH    | Interrupt on GPIO input level High                  |
396   | MSS_GPIO_IRQ_LEVEL_LOW     | Interrupt on GPIO input level Low                   |
397   | MSS_GPIO_IRQ_EDGE_POSITIVE | Interrupt on GPIO input positive edge               |
398   | MSS_GPIO_IRQ_EDGE_NEGATIVE | Interrupt on GPIO input negative edge               |
399   | MSS_GPIO_IRQ_EDGE_BOTH     | Interrupt on GPIO input positive and negative edges |
400 
401  */
402 #define MSS_GPIO_IRQ_LEVEL_HIGH           0x0000000000UL
403 #define MSS_GPIO_IRQ_LEVEL_LOW            0x0000000020UL
404 #define MSS_GPIO_IRQ_EDGE_POSITIVE        0x0000000040UL
405 #define MSS_GPIO_IRQ_EDGE_NEGATIVE        0x0000000060UL
406 #define MSS_GPIO_IRQ_EDGE_BOTH            0x0000000080UL
407 
408 /*------------------------Private data structures-----------------------------*/
409 /*----------------------------------- GPIO -----------------------------------*/
410 /*----------------------------------------------------------------------------*/
411 typedef struct
412 {
413     volatile uint32_t GPIO_CFG[32];
414     volatile uint32_t GPIO_IRQ;
415     volatile const uint32_t GPIO_IN;
416     volatile uint32_t GPIO_OUT;
417     volatile uint32_t GPIO_CFG_ALL;
418     volatile uint32_t GPIO_CFG_BYTE[4];
419     volatile uint32_t GPIO_CLR_BITS;
420     volatile uint32_t GPIO_SET_BITS;
421 
422 } GPIO_TypeDef;
423 
424 /*--------------------------------Public APIs---------------------------------*/
425 
426 /*-------------------------------------------------------------------------*//**
427   The MSS_GPIO_init() function initializes the PolarFire SoC MSS GPIO block. It
428   resets the MSS GPIO hardware block and it also clears any pending MSS GPIO
429   interrupts in the  interrupt controller. When the function exits,
430   it takes the MSS GPIO block out of reset.
431 
432   @param gpio
433     The gpio parameter specifies the GPIO block that needs to be configured
434 
435   @return
436     This function does not return a value.
437 
438   Example:
439   @code
440       #include "mss_gpio.h"
441       int main(void)
442       {
443         MSS_GPIO_init(GPIO0_LO);
444         MSS_GPIO_config(GPIO0_LO, MSS_GPIO_4, MSS_GPIO_INPUT_MODE |
445                         MSS_GPIO_IRQ_EDGE_POSITIVE );
446         return (0u);
447       }
448   @endcode
449  */
450 void MSS_GPIO_init
451 (
452     GPIO_TypeDef * gpio
453 );
454 
455 /*-------------------------------------------------------------------------*//**
456   The MSS_GPIO_config() function is used to configure an individual GPIO port.
457 
458   @param gpio
459     The gpio parameter specifies the GPIO block that needs to be configured
460 
461   @param port_id
462     The port_id parameter identifies the GPIO port to be configured. An
463     enumeration item of the form MSS_GPIO_n, where n is the number of the GPIO
464     port, is used to identify the GPIO port. For example, MSS_GPIO_0 identifies
465     the first GPIO port and MSS_GPIO_31 is the last one.
466 
467   @param config
468     The config parameter specifies the configuration to be applied to the GPIO
469     port identified by the port_id parameter. It is a logical OR of the required
470     I/O mode and the required interrupt mode. The interrupt mode is not relevant
471     if the GPIO is configured as an output only.
472        These I/O mode constants are allowed:
473            - MSS_GPIO_INPUT_MODE
474            - MSS_GPIO_OUTPUT_MODE
475            - MSS_GPIO_INOUT_MODE
476        These interrupt mode constants are allowed:
477            - MSS_GPIO_IRQ_LEVEL_HIGH
478            - MSS_GPIO_IRQ_LEVEL_LOW
479            - MSS_GPIO_IRQ_EDGE_POSITIVE
480            - MSS_GPIO_IRQ_EDGE_NEGATIVE
481            - MSS_GPIO_IRQ_EDGE_BOTH
482 
483    @return
484     This function does not return any value.
485 
486   Example:
487   The following call will configure GPIO 4 on GPIO0 hardware block on main APB
488   bus as an input generating interrupts on a Low to High transition of the input
489   @code
490       #include "mss_gpio.h"
491       int main(void)
492       {
493         MSS_GPIO_init(GPIO0_LO);
494         MSS_GPIO_config(GPIO0_LO, MSS_GPIO_4, MSS_GPIO_INPUT_MODE |
495                         MSS_GPIO_IRQ_EDGE_POSITIVE );
496         return (0u);
497       }
498   @endcode
499  */
500 void MSS_GPIO_config
501 (
502     GPIO_TypeDef * gpio,
503     mss_gpio_id_t port_id,
504     uint32_t config
505 );
506 
507 /*-------------------------------------------------------------------------*//**
508   The MSS_GPIO_set_outputs() function is used to set the state of all GPIO ports
509   configured as outputs.
510 
511   @param gpio
512     The gpio parameter specifies the GPIO block that needs to be configured
513 
514   @param value
515     The value parameter specifies the state of the GPIO ports configured as
516     outputs. It is a bit mask of the form (MSS_GPIO_n_MASK | MSS_GPIO_m_MASK)
517     where n and m are numbers identifying GPIOs. For example, (MSS_GPIO_0_MASK |
518     MSS_GPIO_1_MASK | MSS_GPIO_2_MASK ) specifies that the first, second and
519     third GPIO outputs must be set High and all other GPIO outputs set Low. The
520     driver provides 32 mask constants, MSS_GPIO_0_MASK to MSS_GPIO_31_MASK
521     inclusive, for this purpose.
522 
523   @return
524     This function does not return any value.
525 
526   Example 1:
527     Set GPIOs outputs 0 and 8 high and all other GPIO outputs low.
528     @code
529       #include "mss_gpio.h"
530       int main(void)
531       {
532         MSS_GPIO_init(GPIO0_LO);
533         MSS_GPIO_config(GPIO0_LO, MSS_GPIO_4, MSS_GPIO_INPUT_MODE |
534                         MSS_GPIO_IRQ_EDGE_POSITIVE );
535         MSS_GPIO_set_outputs(GPIO0_LO, MSS_GPIO_0_MASK | MSS_GPIO_8_MASK );
536         return (0u);
537       }
538 
539     @endcode
540 
541   Example 2:
542     Set GPIOs outputs 2 and 4 low without affecting other GPIO outputs.
543     @code
544       #include "mss_gpio.h"
545       int main(void)
546       {
547          uint32_t gpio_outputs;
548          MSS_GPIO_init(GPIO0_LO);
549          MSS_GPIO_config(GPIO0_LO, MSS_GPIO_4, MSS_GPIO_INPUT_MODE |
550                           MSS_GPIO_IRQ_EDGE_POSITIVE );
551 
552          gpio_outputs = MSS_GPIO_get_outputs();
553          gpio_outputs &= ~( MSS_GPIO_2_MASK | MSS_GPIO_4_MASK );
554          MSS_GPIO_set_outputs(GPIO0_LO, gpio_outputs );
555 
556          return (0u);
557       }
558 
559     @endcode
560 
561   @see MSS_GPIO_get_outputs()
562  */
563 static inline void
MSS_GPIO_set_outputs(GPIO_TypeDef * gpio,uint32_t value)564 MSS_GPIO_set_outputs
565 (
566     GPIO_TypeDef * gpio,
567     uint32_t value
568 )
569 {
570     gpio->GPIO_OUT = value;
571 }
572 
573 /*-------------------------------------------------------------------------*//**
574   The MSS_GPIO_config_all() function is used to configure all the ports of the
575   GPIO block. This function will apply the same configuration values to all the
576   GPIO ports.
577 
578   @param gpio
579     The gpio parameter specifies the GPIO block that needs to be configured
580 
581   @param config
582     The config parameter specifies the configuration to be applied to the all
583     the GPIO ports. It is a logical OR of the required I/O mode and the required
584     interrupt mode. The interrupt mode is not relevant if the GPIO is configured
585     as an output only.
586        These I/O mode constants are allowed:
587            - MSS_GPIO_INPUT_MODE
588            - MSS_GPIO_OUTPUT_MODE
589            - MSS_GPIO_INOUT_MODE
590        These interrupt mode constants are allowed:
591            - MSS_GPIO_IRQ_LEVEL_HIGH
592            - MSS_GPIO_IRQ_LEVEL_LOW
593            - MSS_GPIO_IRQ_EDGE_POSITIVE
594            - MSS_GPIO_IRQ_EDGE_NEGATIVE
595            - MSS_GPIO_IRQ_EDGE_BOTH
596 
597   @return
598     This function does not return any value.
599 
600   Example:
601     @code
602       #include "mss_gpio.h"
603       int main(void)
604       {
605         MSS_GPIO_init(GPIO0_LO);
606         MSS_GPIO_config_all(GPIO0_LO, MSS_GPIO_INPUT_MODE |
607                             MSS_GPIO_IRQ_EDGE_POSITIVE );
608         return (0u);
609       }
610     @endcode
611  */
612 void MSS_GPIO_config_all
613 (
614     GPIO_TypeDef * gpio,
615     uint32_t config
616 );
617 
618 /*-------------------------------------------------------------------------*//**
619   The MSS_GPIO_config_byte() function is used to byte wise (consecutive 8 ports)
620   configure the gpio ports.
621 
622   @param gpio
623     The gpio parameter specifies the GPIO block that needs to be configured.
624 
625   @param byte_num
626     The byte_num parameter specifies the byte (consecutive 8 ports) which needs
627     to be configured. The value 0 indicates the bunch from gpio port0 to gpio
628     port7. Value of 3 indicates  the bunch from gpio port25 to gpio port31.
629     When you use this function, you must make sure that the gpio ports that
630     you are trying to configure do exist for that GPIO hardware block.
631     GPIO0 has 14 ports.GPIO1 has 24 ports.GPIO3 has 32 ports.
632 
633   @param config
634     The config parameter specifies the configuration to be applied to the GPIO
635     byte identified by the byte_num parameter. It is a logical OR of the
636     required I/O mode and the required interrupt mode. The interrupt mode is not
637     relevant if the GPIO is configured as an output only.
638        These I/O mode constants are allowed:
639            - MSS_GPIO_INPUT_MODE
640            - MSS_GPIO_OUTPUT_MODE
641            - MSS_GPIO_INOUT_MODE
642        These interrupt mode constants are allowed:
643            - MSS_GPIO_IRQ_LEVEL_HIGH
644            - MSS_GPIO_IRQ_LEVEL_LOW
645            - MSS_GPIO_IRQ_EDGE_POSITIVE
646            - MSS_GPIO_IRQ_EDGE_NEGATIVE
647            - MSS_GPIO_IRQ_EDGE_BOTH
648 
649   @return
650     This function does not return any value.
651 
652   Example:
653     @code
654       #include "mss_gpio.h"
655       int main(void)
656       {
657         MSS_GPIO_init(GPIO0_LO);
658         MSS_GPIO_config_byte(GPIO0_LO, MSS_GPIO_BYTE_1, MSS_GPIO_INPUT_MODE |
659                             MSS_GPIO_IRQ_EDGE_POSITIVE );
660         return (0u);
661       }
662     @endcode
663  */
664 void MSS_GPIO_config_byte
665 (
666     GPIO_TypeDef * gpio,
667     mss_gpio_byte_num_t byte_num,
668     uint32_t config
669 );
670 
671 /*-------------------------------------------------------------------------*//**
672   The MSS_GPIO_set_output() function is used to set the state of a single GPIO
673   port configured as an output.
674 
675   @param gpio
676     The gpio parameter specifies the GPIO block that needs to be configured
677 
678   @param port_id
679     The port_id parameter identifies the GPIO port that is to have its output
680     set. An enumeration item of the form MSS_GPIO_n, where n is the number of
681     the GPIO port, is used to identify the GPIO port. For example, MSS_GPIO_0
682     identifies the first GPIO port and MSS_GPIO_31 is the last one.
683 
684   @param value
685     The value parameter specifies the desired state for the GPIO output. A value
686     of 0 will set the output Low and a value of 1 will set the output High.
687 
688   @return
689     This function does not return a value.
690 
691   Example:
692   The following call will set GPIO output 12 High, leaving all other GPIO
693   outputs unaffected:
694   @code
695       #include "mss_gpio.h"
696       int main(void)
697       {
698         MSS_GPIO_init(GPIO0_LO);
699         MSS_GPIO_config_all(GPIO0_LO, MSS_GPIO_INOUT_MODE);
700         MSS_GPIO_set_output(GPIO0_LO, MSS_GPIO_13, 1);
701         return (0u);
702       }
703   @endcode
704  */
705 void MSS_GPIO_set_output
706 (
707     GPIO_TypeDef *      gpio,
708     mss_gpio_id_t       port_id,
709     uint8_t             value
710 );
711 
712 /*-------------------------------------------------------------------------*//**
713   The MSS_GPIO_get_inputs() function is used to read the current state all GPIO
714   ports configured as inputs.
715 
716   @param gpio
717     The gpio parameter specifies the GPIO block that needs to be configured
718 
719   @return
720     This function returns a 32-bit unsigned integer where each bit represents
721     the state of a GPIO input. The least significant bit represents the state of
722     GPIO input 0 and the most significant bit the state of GPIO input 31.
723 
724   Example:
725     Read and assign the current state of the GPIO outputs to a variable.
726     @code
727       #include "mss_gpio.h"
728       int main(void)
729       {
730         uint32_t gpio_inputs;
731         MSS_GPIO_init(GPIO0_LO);
732         MSS_GPIO_config_all(GPIO0_LO, MSS_GPIO_INOUT_MODE);
733         gpio_inputs = MSS_GPIO_get_inputs(GPIO0_LO);
734         return (0u);
735       }
736     @endcode
737  */
738 static inline uint32_t
MSS_GPIO_get_inputs(GPIO_TypeDef const * gpio)739 MSS_GPIO_get_inputs( GPIO_TypeDef const * gpio )
740 {
741     return gpio->GPIO_IN;
742 }
743 
744 /*-------------------------------------------------------------------------*//**
745   The MSS_GPIO_enable_nondirect_irq() function is used to enable the non-direct
746   interrupt input at the PLIC.
747 
748   @param gpio
749     The gpio parameter specifies the GPIO block that needs to be configured
750 
751   @return
752     This function does not return any value.
753 
754   Example:
755     Read and assign the current state of the GPIO outputs to a variable.
756     @code
757       #include "mss_gpio.h"
758       int main(void)
759       {
760         uint32_t gpio_inputs;
761         MSS_GPIO_init(GPIO0_LO);
762         MSS_GPIO_config_all(GPIO0_LO, MSS_GPIO_INOUT_MODE |
763                                         MSS_GPIO_IRQ_EDGE_POSITIVE);
764         MSS_GPIO_enable_nondirect_irq(GPIO1_LO);
765         return (0u);
766       }
767 
768     @endcode
769  */
770 void
771 MSS_GPIO_enable_nondirect_irq
772 (
773     GPIO_TypeDef const * gpio
774 );
775 
776 /*-------------------------------------------------------------------------*//**
777   The MSS_GPIO_disable_nondirect_irq() function is used to disable the
778   non-direct interrupt input at the PLIC.
779 
780   @param gpio
781     The gpio parameter specifies the GPIO block that needs to be configured
782 
783   @return
784     This function does not return any value.
785 
786   Example:
787     @code
788       #include "mss_gpio.h"
789       int main(void)
790       {
791         uint32_t gpio_inputs;
792         MSS_GPIO_init(GPIO0_LO);
793         MSS_GPIO_config_all(GPIO0_LO, MSS_GPIO_INOUT_MODE |
794                                         MSS_GPIO_IRQ_EDGE_POSITIVE);
795         MSS_GPIO_disable_nondirect_irq(GPIO1_LO);
796         return (0u);
797       }
798     @endcode
799  */
800 void
801 MSS_GPIO_disable_nondirect_irq
802 (
803     GPIO_TypeDef const * gpio
804 );
805 
806 /*-------------------------------------------------------------------------*//**
807   The MSS_GPIO_get_outputs() function is used to read the current state of all
808   GPIO ports configured as outputs.
809 
810   @param gpio
811     The gpio parameter specifies the GPIO block that needs to be configured
812 
813   @return
814      This function returns a 32-bit unsigned integer where each bit represents
815      the state of a GPIO output. The least significant bit represents the state
816      of GPIO output 0 and the most significant bit the state of GPIO output 31.
817 
818   Example:
819     Read and assign the current state of the GPIO outputs to a variable.
820     @code
821       #include "mss_gpio.h"
822       int main(void)
823       {
824          uint32_t gpio_outputs;
825          MSS_GPIO_init(GPIO0_LO);
826          MSS_GPIO_config(GPIO0_LO, MSS_GPIO_4, MSS_GPIO_INPUT_MODE |
827                           MSS_GPIO_IRQ_EDGE_POSITIVE );
828 
829          gpio_outputs = MSS_GPIO_get_outputs();
830          gpio_outputs &= ~( MSS_GPIO_2_MASK | MSS_GPIO_4_MASK );
831          MSS_GPIO_set_outputs(  gpio_outputs );
832 
833          return (0u);
834       }
835     @endcode
836  */
837 static inline uint32_t
MSS_GPIO_get_outputs(GPIO_TypeDef const * gpio)838 MSS_GPIO_get_outputs( GPIO_TypeDef const * gpio )
839 {
840     return gpio->GPIO_OUT;
841 }
842 
843 /*-------------------------------------------------------------------------*//**
844   The MSS_GPIO_get_irq() function is used to read the current value of the IRQ
845   register. The GPIO interrupts are multiplexed. The GPIO interrupts which are
846   not available on the direct GPIO interrupt line on the PLIC are ORed and
847   routed to the non-direct interrupt line on the PLIC for the corresponding
848   GPIO hardware block. When the non-direct interrupt is asserted, this function
849   can be used to determine which exact GPIO bit(s) caused the interrupt.
850 
851   @param gpio
852     The gpio parameter specifies the GPIO block that needs to be configured
853 
854   @return
855      This function returns a 32-bit unsigned integer value of the IRQ register.
856 
857   Example:
858     In the non-direct interrupt ISR, read the IRQ register to know which are
859     the GPIO port causing the interrupt.
860 
861     @code
862     uint8_t gpio2_non_direct_plic_IRQHandler(void)
863     {
864         uint32_t intr_num = 0;
865         intr_num = MSS_GPIO_get_irq(GPIO2_LO);
866 
867         for(int cnt=0; cnt<32; cnt++)
868         {
869             if (1u == (intr_num & 0x00000001U))
870             {
871                 MSS_GPIO_clear_irq(GPIO0_LO, (mss_gpio_id_t)cnt);
872             }
873 
874             intr_num >>= 1u;
875         }
876 
877         return EXT_IRQ_KEEP_ENABLED;
878     }
879     @endcode
880  */
881 static inline uint32_t
MSS_GPIO_get_irq(GPIO_TypeDef const * gpio)882 MSS_GPIO_get_irq( GPIO_TypeDef const * gpio )
883 {
884     return gpio->GPIO_IRQ;
885 }
886 
887 /*-------------------------------------------------------------------------*//**
888   The MSS_GPIO_drive_inout() function is used to set the output state of a
889   single GPIO port configured as an INOUT. An INOUT GPIO can be in one of three
890   states:
891     - High
892     - Low
893     - High impedance
894 
895   An INOUT output would typically be used where several devices can drive the
896   state of a shared signal line. The High and Low states are equivalent to the
897   High and Low states of a GPIO configured as an output. The High impedance
898   state is used to prevent the GPIO from driving its output state onto the
899   signal line, while at the same time allowing the input state of the GPIO to
900   be read.
901 
902   @param gpio
903     The gpio parameter specifies the GPIO block that needs to be configured
904 
905   @param port_id
906     The port_id parameter identifies the GPIO port for which you want to change
907     the output state. An enumeration item of the form MSS_GPIO_n, where n is the
908     number of the GPIO port, is used to identify the GPIO port. For example,
909     MSS_GPIO_0 identifies the first GPIO port and MSS_GPIO_31 is the last one.
910 
911   @param inout_state
912     The inout_state parameter specifies the state of the GPIO port identified by
913     the port_id parameter. Allowed values of type mss_gpio_inout_state_t are as
914     follows:
915         - MSS_GPIO_DRIVE_HIGH
916         - MSS_GPIO_DRIVE_LOW
917         - MSS_GPIO_HIGH_Z  (High impedance)
918 
919   @return
920     This function does not return a value.
921 
922   Example:
923     The call to MSS_GPIO_drive_inout() below will set the GPIO 7 output to the
924     high impedance state.
925     @code
926       #include "mss_gpio.h"
927       int main(void)
928       {
929         uint32_t gpio_inputs;
930         MSS_GPIO_init(GPIO0_LO);
931         MSS_GPIO_config_all(GPIO0_LO, MSS_GPIO_INOUT_MODE |
932                                         MSS_GPIO_IRQ_EDGE_POSITIVE);
933         MSS_GPIO_drive_inout(GPIO0_LO, MSS_GPIO_7, MSS_GPIO_HIGH_Z);
934         return (0u);
935       }
936     @endcode
937  */
938 void MSS_GPIO_drive_inout
939 (
940     GPIO_TypeDef *          gpio,
941     mss_gpio_id_t           port_id,
942     mss_gpio_inout_state_t  inout_state
943 );
944 
945 /*-------------------------------------------------------------------------*//**
946   The MSS_GPIO_enable_irq() function is used to enable interrupt generation for
947   the specified GPIO input. Interrupts are generated based on the state of the
948   GPIO input and the interrupt mode configured for it by MSS_GPIO_config(). This
949   function enables the corresponding GPIO direct interrupt on the PLIC as well.
950 
951   @param gpio
952     The gpio parameter specifies the GPIO block that needs to be configured
953 
954   @param port_id
955     The port_id parameter identifies the GPIO port for which you want to enable
956     interrupt generation. An enumeration item of the form MSS_GPIO_n, where n is
957     the number of the GPIO port, is used to identify the GPIO port. For example,
958     MSS_GPIO_0 identifies the first GPIO port and MSS_GPIO_31 is the last one in
959     GPIO2 block.
960 
961   @return
962     This function does not return a value.
963 
964   Example:
965     The call to MSS_GPIO_enable_irq() below will allow GPIO 8 to generate
966     interrupts.
967     @code
968       #include "mss_gpio.h"
969       int main(void)
970       {
971         uint32_t gpio_inputs;
972         MSS_GPIO_init(GPIO0_LO);
973         MSS_GPIO_config_all(GPIO0_LO, MSS_GPIO_INOUT_MODE |
974                                         MSS_GPIO_IRQ_EDGE_POSITIVE);
975         MSS_GPIO_enable_irq(GPIO0_LO, MSS_GPIO_8);
976         return (0u);
977       }
978 
979     @endcode
980  */
981 void MSS_GPIO_enable_irq
982 (
983     GPIO_TypeDef * gpio,
984     mss_gpio_id_t port_id
985 );
986 
987 /*-------------------------------------------------------------------------*//**
988   The MSS_GPIO_disable_irq() function is used to disable interrupt generation
989   for the specified GPIO input. This function disables the corresponding GPIO
990   direct interrupt on the PLIC as well.
991 
992   @param gpio
993     The gpio parameter specifies the GPIO block that needs to be configured
994 
995   @param port_id
996     The port_id parameter identifies the GPIO port for which you want to disable
997     interrupt generation. An enumeration item of the form MSS_GPIO_n, where n is
998     the number of the GPIO port, is used to identify the GPIO port. For example,
999     MSS_GPIO_0 identifies the first GPIO port and MSS_GPIO_31 is the last one.
1000 
1001   @return
1002     This function does not return a value.
1003 
1004   Example:
1005     The call to MSS_GPIO_disable_irq() below will prevent GPIO 8 from generating
1006     interrupts.
1007     @code
1008     MSS_GPIO_disable_irq( MSS_GPIO_8 );
1009     @endcode
1010  */
1011 void MSS_GPIO_disable_irq
1012 (
1013     GPIO_TypeDef * gpio,
1014     mss_gpio_id_t port_id
1015 );
1016 
1017 /*-------------------------------------------------------------------------*//**
1018   The MSS_GPIO_clear_irq() function is used to clear a pending interrupt from
1019   the specified GPIO input.
1020 
1021   Note: The MSS_GPIO_clear_irq() function must be called as part of any GPIO
1022         interrupt service routine (ISR) in order to prevent the same interrupt
1023         event retriggering a call to the GPIO ISR.
1024 
1025   @param gpio
1026     The gpio parameter specifies the GPIO block that needs to be configured
1027 
1028   @param port_id
1029     The port_id parameter identifies the GPIO port for which you want to clear
1030     the interrupt. An enumeration item of the form MSS_GPIO_n, where n is the
1031     number of the GPIO port, is used to identify the GPIO port. For example,
1032     MSS_GPIO_0 identifies the first GPIO port and MSS_GPIO_31 is the last one.
1033 
1034   @return
1035     This function does not return a value.
1036 
1037   Example:
1038     The example below demonstrates the use of the MSS_GPIO_clear_irq() function
1039     as part of the GPIO 9 interrupt service routine.
1040 
1041     @code
1042     uint8_t gpio2_non_direct_plic_IRQHandler(void)
1043     {
1044         uint32_t intr_num = 0;
1045         intr_num = MSS_GPIO_get_irq(GPIO2_LO);
1046 
1047         for(int cnt=0; cnt<32; cnt++)
1048         {
1049             if (1u == (intr_num & 0x00000001U))
1050             {
1051                 MSS_GPIO_clear_irq(GPIO0_LO, (mss_gpio_id_t)cnt);
1052             }
1053 
1054             intr_num >>= 1u;
1055         }
1056 
1057         return EXT_IRQ_KEEP_ENABLED;
1058     }
1059     @endcode
1060  */
1061 void MSS_GPIO_clear_irq
1062 (
1063     GPIO_TypeDef * gpio,
1064     mss_gpio_id_t port_id
1065 );
1066 
1067 #ifdef __cplusplus
1068 }
1069 #endif
1070 
1071 #endif /* MSS_GPIO_H_ */
1072