1 /*
2 * Copyright (c) 2024, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 /**
9 * \file gpio_pl061_drv.h
10 * \brief Driver for ARM Primecell GPIO Element
11 * As described in DDI0190
12 * https://developer.arm.com/documentation/ddi0190/latest/
13 */
14
15 #ifndef GPIO_PL061_DRV_H_
16 #define GPIO_PL061_DRV_H_
17
18 #ifdef __cplusplus
19 extern "C" {
20 #endif
21
22 #include <stdint.h>
23
24 #include "tfm_hal_device_header.h"
25
26 typedef __PACKED_STRUCT {
27 __IOM uint32_t gpiodata[256]; /*!< Offset: 0x000 (R/W) Data Register Array */
28 __IOM uint32_t gpiodir; /*!< Offset: 0x400 (R/W) Direction Register */
29 __IOM uint32_t gpiois; /*!< Offset: 0x404 (R/W) Interrupt Sense Register */
30 __IOM uint32_t gpioibe; /*!< Offset: 0x408 (R/W) Interrupt Both Edges Register */
31 __IOM uint32_t gpioiev; /*!< Offset: 0x40C (R/W) Interrupt Event Register */
32 __IOM uint32_t gpioie; /*!< Offset: 0x410 (R/W) Interrupt Event Register */
33 __IM uint32_t gpioris; /*!< Offset: 0x414 (R/O) Raw Interrupt Status Register */
34 __IM uint32_t gpiomis; /*!< Offset: 0x418 (R/O) Masked Interrupt Status Register */
35 __OM uint32_t gpioic; /*!< Offset: 0x41C (R/W) Interrupt Clear Register */
36 __IOM uint32_t gpioafsel; /*!< Offset: 0x420 (R/W) Mode Control Select Register */
37 const uint32_t reserved[751];
38 __IM uint32_t gpioperiphid[4]; /*!< Offset: 0xFE0 (R/O) Peripheral Identification */
39 __IM uint32_t gpiocellid[4]; /*!< Offset: 0xFF0 (R/O) Primecell Identification */
40 } pl061_regblk_t;
41
42 /**
43 * \brief Set all GPIO to given state for every HIGH bit in mask
44 *
45 * \param[in] pdev Pointer to the PL061 register block
46 * \param[in] mask Bitmask for writes to be masked
47 * \param[in] pins Bitmask for state of pins
48 */
49 __STATIC_FORCEINLINE
pl061_set_gpio(pl061_regblk_t * pdev,uint8_t mask,uint8_t pins)50 void pl061_set_gpio(pl061_regblk_t * pdev, uint8_t mask, uint8_t pins)
51 {
52 /* DDI0190: 3.3.1: Masked by address; Never write HIGH to INPUT */
53 pdev->gpiodata[mask] = pins & pdev->gpiodir;
54 }
55
56 /**
57 * \brief Set GPIO to HIGH state for every HIGH bit in mask
58 *
59 * \param[in] pdev Pointer to the PL061 register block
60 * \param[in] mask Bitmask for writes to be masked
61 */
62 __STATIC_FORCEINLINE
pl061_set_high(pl061_regblk_t * pdev,uint8_t mask)63 void pl061_set_high(pl061_regblk_t * pdev, uint8_t mask)
64 {
65 /* DDI0190: 3.3.1: Masked by address; Never write HIGH to INPUT */
66 pdev->gpiodata[mask] = UINT8_MAX & pdev->gpiodir;
67 }
68
69 /**
70 * \brief Set the GPIO to LOW for every HIGH bit in mask
71 *
72 * \param[in] pdev Pointer to the PL061 register block
73 * \param[in] mask Bitmask for writes to be masked
74 */
75 __STATIC_FORCEINLINE
gpio_set_low(pl061_regblk_t * pdev,uint8_t mask)76 void gpio_set_low(pl061_regblk_t * pdev, uint8_t mask)
77 {
78 /* DDI0190: 3.3.1: Masked by address */
79 pdev->gpiodata[mask] = 0u;
80 }
81
82 /**
83 * \brief Get the GPIO state for every HIGH bit in mask
84 *
85 * \param[in] pdev Pointer to the PL061 register block
86 * \param[in] mask Bitmask for reads to be masked
87 * \return uint8_t Masked state of GPIO
88 */
89 __STATIC_FORCEINLINE
pl061_get_gpio(pl061_regblk_t * pdev,uint8_t mask)90 uint8_t pl061_get_gpio(pl061_regblk_t * pdev, uint8_t mask)
91 {
92 /* DDI0190: 3.3.1: Masked by address */
93 return pdev->gpiodata[mask] & UINT8_MAX; /* only 8 bit wide */
94 }
95
96 /**
97 * \brief Set the GPIO direction to INPUT for every HIGH bit in mask
98 *
99 * \param[in] pdev Pointer to the PL061 register block
100 * \param[in] mask Bitmask for GPIO to be configured as INPUT
101 */
102 __STATIC_FORCEINLINE
pl061_set_input(pl061_regblk_t * pdev,uint8_t mask)103 void pl061_set_input(pl061_regblk_t * pdev, uint8_t mask)
104 {
105 pdev->gpiodir &= ~mask;
106 }
107
108 /**
109 * \brief Set GPIO direction to OUTPUT for every HIGH bit in mask
110 *
111 * \param[in] pdev Pointer to the PL061 register block
112 * \param[in] mask Bitmask for GPIO to be configured as OUTPUT
113 */
114 __STATIC_FORCEINLINE
pl061_set_output(pl061_regblk_t * pdev,uint8_t mask)115 void pl061_set_output(pl061_regblk_t * pdev, uint8_t mask)
116 {
117 pdev->gpiodir |= mask;
118 }
119
120 /**
121 * \brief Get peripheral ID from hardware
122 *
123 * \param pdev Pointer to the PL061 register block
124 * \return uint32_t
125 */
126 uint32_t pl061_get_perifid(pl061_regblk_t * pdev);
127
128 /**
129 * \brief Get primecell ID from hardware
130 *
131 * \param[in] pdev Pointer to the PL061 register block
132 * \return uint32_t - 0xB105_F00D
133 */
134 uint32_t pl061_get_cellid(pl061_regblk_t * pdev);
135
136 #ifdef __cplusplus
137 }
138 #endif
139
140 #endif /* GPIO_PL061_DRV_H_ */
141