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 
24 FILE_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  */
54 static 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  */
93 static 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 */
107 static const char * dwgpio_group_ids[] = {
108  "snps,dw-apb-gpio",
109 };
110 
111 /** DesignWare GPIO port group devicetree driver */
112 struct 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  */
133 static 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  */
148 static int dwgpio_in ( struct gpios *gpios, struct gpio *gpio ) {
149  struct dwgpio *dwgpio = gpios->priv;
150  uint32_t ext;
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  */
164 static 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;
174  writel ( dr, ( dwgpio->swport + DWGPIO_SWPORT_DR ) );
175  dwgpio_dump ( dwgpio );
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  */
186 static 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 );
190  uint32_t ddr;
191  uint32_t ctl;
192 
193  /* Update data direction and control registers */
196  ctl &= ~mask;
197  ddr &= ~mask;
198  if ( config & GPIO_CFG_OUTPUT )
199  ddr |= mask;
202  dwgpio_dump ( dwgpio );
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  */
221 static 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;
226  uint32_t count;
227  uint64_t port;
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 ) );
272  dwgpio_dump ( dwgpio );
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:
292  gpios_nullify ( gpios );
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  */
304 static 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 */
317  gpios_nullify ( gpios );
318  gpios_put ( gpios );
319 }
320 
321 /** DesignWare GPIO port compatible model identifiers */
322 static const char * dwgpio_ids[] = {
323  "snps,dw-apb-gpio-port",
324 };
325 
326 /** DesignWare GPIO port devicetree driver */
327 struct dt_driver dwgpio_driver __dt_driver = {
328  .name = "dwgpio",
329  .ids = dwgpio_ids,
330  .id_count = ( sizeof ( dwgpio_ids ) / sizeof ( dwgpio_ids[0] ) ),
331  .probe = dwgpio_probe,
333 };
#define EINVAL
Invalid argument.
Definition: errno.h:428
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
uint32_t ctl
Original control register value.
Definition: dwgpio.h:76
struct dt_driver dwgpio_group_driver __dt_driver
DesignWare GPIO port group devicetree driver.
Definition: dwgpio.c:112
const char * name
Device name.
Definition: dwgpio.h:63
void dt_remove_children(struct dt_device *parent)
Remove devicetree children.
Definition: devtree.c:310
uint32_t ddr
Original data direction register value.
Definition: dwgpio.h:74
Error codes.
static void gpios_put(struct gpios *gpios)
Drop reference to GPIO controller.
Definition: gpio.h:106
A devicetree driver.
Definition: devtree.h:31
#define DWGPIO_EXT_PORT(x)
External port.
Definition: dwgpio.h:52
General purpose I/O.
uint32_t readl(volatile uint32_t *io_addr)
Read 32-bit dword from memory-mapped device.
unsigned int index
Pin index.
Definition: gpio.h:22
#define DBGC(...)
Definition: compiler.h:505
unsigned long long uint64_t
Definition: stdint.h:13
struct device * dev
Generic device.
Definition: gpio.h:43
#define DWGPIO_SWPORT_CTL
Control register.
Definition: dwgpio.h:45
Synopsys DesignWare GPIO driver.
struct device dev
Generic device.
Definition: devtree.h:21
struct gpios * alloc_gpios(unsigned int count, size_t priv_len)
Allocate GPIO controller.
Definition: gpio.c:46
static int dwgpio_config(struct gpios *gpios, struct gpio *gpio, unsigned int config)
Configure GPIO pin.
Definition: dwgpio.c:186
static void dwgpio_out(struct gpios *gpios, struct gpio *gpio, int active)
Set current GPIO output value.
Definition: dwgpio.c:164
void * swport
Software port registers.
Definition: dwgpio.h:67
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
static int dwgpio_group_probe(struct dt_device *dt, unsigned int offset)
Probe port group.
Definition: dwgpio.c:54
int(* probe)(struct dt_device *dt, unsigned int offset)
Probe device.
Definition: devtree.h:45
#define ENOMEM
Not enough space.
Definition: errno.h:534
u8 port
Port number.
Definition: CIB_PRM.h:31
static struct dt_device * dt_parent(struct dt_device *dt)
Get devicetree parent device.
Definition: devtree.h:86
#define DWGPIO_MAX_COUNT
Maximum number of GPIOs per port.
Definition: dwgpio.h:13
uint16_t group
Type of event.
Definition: ena.h:12
A DesignWare GPIO port.
Definition: dwgpio.h:61
#define DWGPIO_SWPORT_DR
Data register.
Definition: dwgpio.h:30
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
int(* in)(struct gpios *gpios, struct gpio *gpio)
Get current GPIO input value.
Definition: gpio.h:65
int fdt_u32(struct fdt *fdt, unsigned int offset, const char *name, uint32_t *value)
Get 32-bit integer property.
Definition: fdt.c:663
Devicetree bus.
static const char * dwgpio_ids[]
DesignWare GPIO port compatible model identifiers.
Definition: dwgpio.c:322
static const char * dwgpio_group_ids[]
DesignWare GPIO port group compatible model identifiers.
Definition: dwgpio.c:107
void writel(uint32_t data, volatile uint32_t *io_addr)
Write 32-bit dword to memory-mapped device.
struct dt_driver * driver
Driver for this device.
Definition: devtree.h:25
void gpios_unregister(struct gpios *gpios)
Unregister GPIO controller.
Definition: gpio.c:94
A devicetree device.
Definition: devtree.h:17
#define DWGPIO_SWPORT(x)
Software port.
Definition: dwgpio.h:19
static unsigned int count
Number of entries.
Definition: dwmac.h:225
static int dwgpio_in(struct gpios *gpios, struct gpio *gpio)
Get current GPIO input value.
Definition: dwgpio.c:148
static void dwgpio_dump(struct dwgpio *dwgpio)
Dump GPIO port status.
Definition: dwgpio.c:133
GPIO operations.
Definition: gpio.h:57
A DesignWare GPIO port group.
Definition: dwgpio.h:55
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
static void dt_set_drvdata(struct dt_device *dt, void *priv)
Set devicetree driver-private data.
Definition: devtree.h:66
void * zalloc(size_t size)
Allocate cleared memory.
Definition: malloc.c:661
unsigned int config
Configuration.
Definition: gpio.h:24
uint32_t dr
Original data register value.
Definition: dwgpio.h:72
A GPIO controller.
Definition: gpio.h:37
#define ENODEV
No such device.
Definition: errno.h:509
#define GPIO_CFG_OUTPUT
GPIO is an output.
Definition: gpio.h:34
int dt_probe_children(struct dt_device *parent, unsigned int offset)
Probe devicetree children.
Definition: devtree.c:264
static unsigned long dr[NUM_HWBP]
Hardware breakpoint addresses (debug registers 0-3)
Definition: gdbmach.c:72
unsigned int uint32_t
Definition: stdint.h:12
static struct xen_remove_from_physmap * remove
Definition: xenmem.h:39
int fdt_reg(struct fdt *fdt, unsigned int offset, uint64_t *region)
Get unsized single-entry region address.
Definition: fdt.c:843
uint16_t ext
Extended status.
Definition: ena.h:20
const char * name
Device name.
Definition: devtree.h:19
int gpios_register(struct gpios *gpios)
Register GPIO controller.
Definition: gpio.c:78
static void gpios_init(struct gpios *gpios, struct gpio_operations *op)
Initialise a GPIO controller.
Definition: gpio.h:139
static void dwgpio_remove(struct dt_device *dt)
Remove port.
Definition: dwgpio.c:304
const char * name
Driver name.
Definition: devtree.h:33
#define DBGC2(...)
Definition: compiler.h:522
void * ext
External port register.
Definition: dwgpio.h:69
static void gpios_nullify(struct gpios *gpios)
Stop using a GPIO controller.
Definition: gpio.h:152
#define DWGPIO_SWPORT_DDR
Data direction register.
Definition: dwgpio.h:37
Flattened Device Tree.
void * dt_ioremap(struct dt_device *dt, unsigned int offset, unsigned int index, size_t len)
Map devicetree range.
Definition: devtree.c:52
void iounmap(volatile const void *io_addr)
Unmap I/O address.
static struct gpio_operations dwgpio_operations
GPIO operations.
Definition: dwgpio.c:208
A GPIO pin.
Definition: gpio.h:18
uint16_t offset
Offset to command line.
Definition: bzimage.h:8
static int dwgpio_probe(struct dt_device *dt, unsigned int offset)
Probe port.
Definition: dwgpio.c:221
unsigned int count
Number of GPIOs.
Definition: gpio.h:45
String functions.
unsigned int port
Port index.
Definition: dwgpio.h:65
static void * dt_get_drvdata(struct dt_device *dt)
Get devicetree driver-private data.
Definition: devtree.h:76
void * priv
Driver-private data.
Definition: gpio.h:53
static void dwgpio_group_remove(struct dt_device *dt)
Remove port group.
Definition: dwgpio.c:93
struct fdt sysfdt
The system flattened device tree (if present)
Definition: fdt.c:44