iPXE
dwgpio.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2025 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26#include <stdlib.h>
27#include <string.h>
28#include <errno.h>
29#include <ipxe/devtree.h>
30#include <ipxe/fdt.h>
31#include <ipxe/gpio.h>
32#include "dwgpio.h"
33
34/** @file
35 *
36 * Synopsys DesignWare GPIO driver
37 *
38 */
39
40/******************************************************************************
41 *
42 * GPIO port group
43 *
44 ******************************************************************************
45 */
46
47/**
48 * Probe port group
49 *
50 * @v dt Devicetree device
51 * @v offset Starting node offset
52 * @ret rc Return status code
53 */
54static int dwgpio_group_probe ( struct dt_device *dt, unsigned int offset ) {
55 struct dwgpio_group *group;
56 int rc;
57
58 /* Allocate and initialise structure */
59 group = zalloc ( sizeof ( *group ) );
60 if ( ! group ) {
61 rc = -ENOMEM;
62 goto err_alloc;
63 }
64 dt_set_drvdata ( dt, group );
65
66 /* Map registers */
67 group->regs = dt_ioremap ( dt, offset, 0, 0 );
68 if ( ! group->regs ) {
69 rc = -ENODEV;
70 goto err_ioremap;
71 }
72
73 /* Probe child ports */
74 if ( ( rc = dt_probe_children ( dt, offset ) ) != 0 )
75 goto err_children;
76
77 return 0;
78
79 dt_remove_children ( dt );
80 err_children:
81 iounmap ( group->regs );
82 err_ioremap:
83 free ( group );
84 err_alloc:
85 return rc;
86}
87
88/**
89 * Remove port group
90 *
91 * @v dt Devicetree device
92 */
93static void dwgpio_group_remove ( struct dt_device *dt ) {
94 struct dwgpio_group *group = dt_get_drvdata ( dt );
95
96 /* Remove child ports */
97 dt_remove_children ( dt );
98
99 /* Unmap registers */
100 iounmap ( group->regs );
101
102 /* Free device */
103 free ( group );
104}
105
106/** DesignWare GPIO port group compatible model identifiers */
107static const char * dwgpio_group_ids[] = {
108 DT_ID ( "snps,dw-apb-gpio", "DesignWare GPIO" ),
109};
110
111/** DesignWare GPIO port group devicetree driver */
112struct dt_driver dwgpio_group_driver __dt_driver = {
113 .name = "dwgpio-group",
114 .ids = dwgpio_group_ids,
115 .id_count = ( sizeof ( dwgpio_group_ids ) /
116 sizeof ( dwgpio_group_ids[0] ) ),
119};
120
121/******************************************************************************
122 *
123 * GPIO port
124 *
125 ******************************************************************************
126 */
127
128/**
129 * Dump GPIO port status
130 *
131 * @v dwgpio DesignWare GPIO port
132 */
133static inline void dwgpio_dump ( struct dwgpio *dwgpio ) {
134
135 DBGC2 ( dwgpio, "DWGPIO %s dr %#08x ddr %#08x ctl %#08x\n",
139}
140
141/**
142 * Get current GPIO input value
143 *
144 * @v gpios GPIO controller
145 * @v gpio GPIO pin
146 * @ret active Pin is in the active state
147 */
148static int dwgpio_in ( struct gpios *gpios, struct gpio *gpio ) {
149 struct dwgpio *dwgpio = gpios->priv;
151
152 /* Read external port status */
153 ext = readl ( dwgpio->ext );
154 return ( ( ( ext >> gpio->index ) ^ gpio->config ) & 1 );
155}
156
157/**
158 * Set current GPIO output value
159 *
160 * @v gpios GPIO controller
161 * @v gpio GPIO pin
162 * @v active Set pin to active state
163 */
164static void dwgpio_out ( struct gpios *gpios, struct gpio *gpio, int active ) {
165 struct dwgpio *dwgpio = gpios->priv;
166 uint32_t mask = ( 1UL << gpio->index );
167 uint32_t dr;
168
169 /* Update data register */
171 dr &= ~mask;
172 if ( ( ( !! active ) ^ gpio->config ) & 1 )
173 dr |= mask;
176}
177
178/**
179 * Configure GPIO pin
180 *
181 * @v gpios GPIO controller
182 * @v gpio GPIO pin
183 * @v config Configuration
184 * @ret rc Return status code
185 */
186static int dwgpio_config ( struct gpios *gpios, struct gpio *gpio,
187 unsigned int config ) {
188 struct dwgpio *dwgpio = gpios->priv;
189 uint32_t mask = ( 1UL << gpio->index );
192
193 /* Update data direction and control registers */
196 ctl &= ~mask;
197 ddr &= ~mask;
198 if ( config & GPIO_CFG_OUTPUT )
199 ddr |= mask;
203
204 return 0;
205}
206
207/** GPIO operations */
209 .in = dwgpio_in,
210 .out = dwgpio_out,
211 .config = dwgpio_config,
212};
213
214/**
215 * Probe port
216 *
217 * @v dt Devicetree device
218 * @v offset Starting node offset
219 * @ret rc Return status code
220 */
221static int dwgpio_probe ( struct dt_device *dt, unsigned int offset ) {
222 struct dt_device *parent;
223 struct dwgpio_group *group;
224 struct dwgpio *dwgpio;
225 struct gpios *gpios;
228 int rc;
229
230 /* Get number of GPIOs */
231 if ( ( rc = fdt_u32 ( &sysfdt, offset, "nr-gpios-snps",
232 &count ) ) != 0 ) {
233 goto err_count;
234 }
236
237 /* Allocate and initialise device */
238 gpios = alloc_gpios ( count, sizeof ( *dwgpio ) );
239 if ( ! gpios ) {
240 rc = -ENOMEM;
241 goto err_alloc;
242 }
243 dt_set_drvdata ( dt, gpios );
244 gpios->dev = &dt->dev;
246 dwgpio = gpios->priv;
247 dwgpio->name = dt->name;
248
249 /* Identify group */
250 parent = dt_parent ( dt );
251 if ( parent->driver != &dwgpio_group_driver ) {
252 DBGC ( dwgpio, "DWGPIO %s has invalid parent %s\n",
253 dwgpio->name, parent->name );
254 rc = -EINVAL;
255 goto err_parent;
256 }
257 group = dt_get_drvdata ( parent );
258
259 /* Identify port */
260 if ( ( rc = fdt_reg ( &sysfdt, offset, &port ) ) != 0 ) {
261 DBGC ( dwgpio, "DWGPIO %s could not get port number: %s\n",
262 dwgpio->name, strerror ( rc ) );
263 goto err_port;
264 }
265 dwgpio->port = port;
266 DBGC ( dwgpio, "DWGPIO %s is %s port %d (%d GPIOs)\n",
267 dwgpio->name, parent->name, dwgpio->port, gpios->count );
268
269 /* Map registers */
270 dwgpio->swport = ( group->regs + DWGPIO_SWPORT ( port ) );
271 dwgpio->ext = ( group->regs + DWGPIO_EXT_PORT ( port ) );
273
274 /* Record original register values */
278
279 /* Register GPIO controller */
280 if ( ( rc = gpios_register ( gpios ) ) != 0 ) {
281 DBGC ( dwgpio, "DWGPIO %s could not register: %s\n",
282 dwgpio->name, strerror ( rc ) );
283 goto err_register;
284 }
285
286 return 0;
287
289 err_register:
290 err_port:
291 err_parent:
293 gpios_put ( gpios );
294 err_alloc:
295 err_count:
296 return rc;
297}
298
299/**
300 * Remove port
301 *
302 * @v dt Devicetree device
303 */
304static void dwgpio_remove ( struct dt_device *dt ) {
305 struct gpios *gpios = dt_get_drvdata ( dt );
306 struct dwgpio *dwgpio = gpios->priv;
307
308 /* Unregister GPIO controller */
310
311 /* Restore original register values */
315
316 /* Free GPIO device */
318 gpios_put ( gpios );
319}
320
321/** DesignWare GPIO port compatible model identifiers */
322static const char * dwgpio_ids[] = {
323 DT_ID ( "snps,dw-apb-gpio-port", "DesignWare GPIO port" ),
324};
325
326/** DesignWare GPIO port devicetree driver */
327struct dt_driver dwgpio_driver __dt_driver = {
328 .name = "dwgpio",
329 .ids = dwgpio_ids,
330 .id_count = ( sizeof ( dwgpio_ids ) / sizeof ( dwgpio_ids[0] ) ),
333};
u8 port
Port number.
Definition CIB_PRM.h:3
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned int uint32_t
Definition stdint.h:12
unsigned long long uint64_t
Definition stdint.h:13
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
uint16_t offset
Offset to command line.
Definition bzimage.h:3
void * dt_ioremap(struct dt_device *dt, unsigned int offset, unsigned int index, size_t len)
Map devicetree range.
Definition devtree.c:52
int dt_probe_children(struct dt_device *parent, unsigned int offset)
Probe devicetree children.
Definition devtree.c:264
void dt_remove_children(struct dt_device *parent)
Remove devicetree children.
Definition devtree.c:310
Devicetree bus.
static void * dt_get_drvdata(struct dt_device *dt)
Get devicetree driver-private data.
Definition devtree.h:82
#define DT_ID(_name, _desc)
Definition devtree.h:31
static void dt_set_drvdata(struct dt_device *dt, void *priv)
Set devicetree driver-private data.
Definition devtree.h:72
static struct dt_device * dt_parent(struct dt_device *dt)
Get devicetree parent device.
Definition devtree.h:92
#define __dt_driver
Declare a devicetree driver.
Definition devtree.h:64
static int dwgpio_in(struct gpios *gpios, struct gpio *gpio)
Get current GPIO input value.
Definition dwgpio.c:148
static void dwgpio_group_remove(struct dt_device *dt)
Remove port group.
Definition dwgpio.c:93
static void dwgpio_dump(struct dwgpio *dwgpio)
Dump GPIO port status.
Definition dwgpio.c:133
static void dwgpio_remove(struct dt_device *dt)
Remove port.
Definition dwgpio.c:304
static int dwgpio_group_probe(struct dt_device *dt, unsigned int offset)
Probe port group.
Definition dwgpio.c:54
static const char * dwgpio_ids[]
DesignWare GPIO port compatible model identifiers.
Definition dwgpio.c:322
static int dwgpio_config(struct gpios *gpios, struct gpio *gpio, unsigned int config)
Configure GPIO pin.
Definition dwgpio.c:186
static struct gpio_operations dwgpio_operations
GPIO operations.
Definition dwgpio.c:208
static int dwgpio_probe(struct dt_device *dt, unsigned int offset)
Probe port.
Definition dwgpio.c:221
static const char * dwgpio_group_ids[]
DesignWare GPIO port group compatible model identifiers.
Definition dwgpio.c:107
static void dwgpio_out(struct gpios *gpios, struct gpio *gpio, int active)
Set current GPIO output value.
Definition dwgpio.c:164
Synopsys DesignWare GPIO driver.
#define DWGPIO_SWPORT_DR
Data register.
Definition dwgpio.h:30
#define DWGPIO_SWPORT_DDR
Data direction register.
Definition dwgpio.h:37
#define DWGPIO_MAX_COUNT
Maximum number of GPIOs per port.
Definition dwgpio.h:13
#define DWGPIO_EXT_PORT(x)
External port.
Definition dwgpio.h:52
#define DWGPIO_SWPORT(x)
Software port.
Definition dwgpio.h:19
#define DWGPIO_SWPORT_CTL
Control register.
Definition dwgpio.h:45
uint16_t ext
Extended status.
Definition ena.h:9
uint16_t group
Type of event.
Definition ena.h:1
Error codes.
int fdt_reg(struct fdt *fdt, unsigned int offset, uint64_t *region)
Get unsized single-entry region address.
Definition fdt.c:844
int fdt_u32(struct fdt *fdt, unsigned int offset, const char *name, uint32_t *value)
Get 32-bit integer property.
Definition fdt.c:664
struct fdt sysfdt
The system flattened device tree (if present)
Definition fdt.c:45
static unsigned long dr[NUM_HWBP]
Hardware breakpoint addresses (debug registers 0-3)
Definition gdbmach.c:73
int gpios_register(struct gpios *gpios)
Register GPIO controller.
Definition gpio.c:78
struct gpios * alloc_gpios(unsigned int count, size_t priv_len)
Allocate GPIO controller.
Definition gpio.c:46
void gpios_unregister(struct gpios *gpios)
Unregister GPIO controller.
Definition gpio.c:94
General purpose I/O.
static void gpios_nullify(struct gpios *gpios)
Stop using a GPIO controller.
Definition gpio.h:152
#define GPIO_CFG_OUTPUT
GPIO is an output.
Definition gpio.h:34
static void gpios_init(struct gpios *gpios, struct gpio_operations *op)
Initialise a GPIO controller.
Definition gpio.h:139
static void gpios_put(struct gpios *gpios)
Drop reference to GPIO controller.
Definition gpio.h:106
#define DBGC2(...)
Definition compiler.h:522
#define DBGC(...)
Definition compiler.h:505
static unsigned int count
Number of entries.
Definition dwmac.h:220
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define EINVAL
Invalid argument.
Definition errno.h:429
#define ENOMEM
Not enough space.
Definition errno.h:535
#define ENODEV
No such device.
Definition errno.h:510
Flattened Device Tree.
void iounmap(volatile const void *io_addr)
Unmap I/O address.
String functions.
void * zalloc(size_t size)
Allocate cleared memory.
Definition malloc.c:662
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
A devicetree device.
Definition devtree.h:17
struct dt_driver * driver
Driver for this device.
Definition devtree.h:25
struct device dev
Generic device.
Definition devtree.h:21
const char * name
Device name.
Definition devtree.h:19
A devicetree driver.
Definition devtree.h:37
int(* probe)(struct dt_device *dt, unsigned int offset)
Probe device.
Definition devtree.h:51
A DesignWare GPIO port group.
Definition dwgpio.h:55
A DesignWare GPIO port.
Definition dwgpio.h:61
unsigned int port
Port index.
Definition dwgpio.h:65
void * ext
External port register.
Definition dwgpio.h:69
uint32_t ctl
Original control register value.
Definition dwgpio.h:76
const char * name
Device name.
Definition dwgpio.h:63
void * swport
Software port registers.
Definition dwgpio.h:67
uint32_t ddr
Original data direction register value.
Definition dwgpio.h:74
uint32_t dr
Original data register value.
Definition dwgpio.h:72
GPIO operations.
Definition gpio.h:57
A GPIO pin.
Definition gpio.h:18
unsigned int config
Configuration.
Definition gpio.h:24
unsigned int index
Pin index.
Definition gpio.h:22
A GPIO controller.
Definition gpio.h:37
void * priv
Driver-private data.
Definition gpio.h:53
unsigned int count
Number of GPIOs.
Definition gpio.h:45
struct device * dev
Generic device.
Definition gpio.h:43
#define readl
Definition w89c840.c:157
#define writel
Definition w89c840.c:160
static struct xen_remove_from_physmap * remove
Definition xenmem.h:40