1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2016
4 * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
5 *
6 * based on arch/powerpc/include/asm/mpc85xx_gpio.h, which is
7 *
8 * Copyright 2010 eXMeritus, A Boeing Company
9 * Copyright 2020-2021 NXP
10 */
11
12#include <common.h>
13#include <dm.h>
14#include <mapmem.h>
15#include <asm/gpio.h>
16#include <asm/io.h>
17#include <dm/of_access.h>
18
19struct mpc8xxx_gpio_data {
20	/* The bank's register base in memory */
21	struct ccsr_gpio __iomem *base;
22	/* The address of the registers; used to identify the bank */
23	phys_addr_t addr;
24	/* The GPIO count of the bank */
25	uint gpio_count;
26	/* The GPDAT register cannot be used to determine the value of output
27	 * pins on MPC8572/MPC8536, so we shadow it and use the shadowed value
28	 * for output pins
29	 */
30	u32 dat_shadow;
31	ulong type;
32	bool  little_endian;
33};
34
35enum {
36	MPC8XXX_GPIO_TYPE,
37	MPC5121_GPIO_TYPE,
38};
39
40inline u32 gpio_mask(uint gpio)
41{
42	return (1U << (31 - (gpio)));
43}
44
45static inline u32 mpc8xxx_gpio_get_val(struct udevice *dev, u32 mask)
46{
47	struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
48
49	if (data->little_endian)
50		return in_le32(&data->base->gpdat) & mask;
51	else
52		return in_be32(&data->base->gpdat) & mask;
53}
54
55static inline u32 mpc8xxx_gpio_get_dir(struct udevice *dev, u32 mask)
56{
57	struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
58
59	if (data->little_endian)
60		return in_le32(&data->base->gpdir) & mask;
61	else
62		return in_be32(&data->base->gpdir) & mask;
63}
64
65static inline int mpc8xxx_gpio_open_drain_val(struct udevice *dev, u32 mask)
66{
67	struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
68
69	if (data->little_endian)
70		return in_le32(&data->base->gpodr) & mask;
71	else
72		return in_be32(&data->base->gpodr) & mask;
73}
74
75static inline void mpc8xxx_gpio_open_drain_on(struct udevice *dev, u32
76					      gpios)
77{
78	struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
79	/* GPODR register 1 -> open drain on */
80	if (data->little_endian)
81		setbits_le32(&data->base->gpodr, gpios);
82	else
83		setbits_be32(&data->base->gpodr, gpios);
84}
85
86static inline void mpc8xxx_gpio_open_drain_off(struct udevice *dev,
87					       u32 gpios)
88{
89	struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
90	/* GPODR register 0 -> open drain off (actively driven) */
91	if (data->little_endian)
92		clrbits_le32(&data->base->gpodr, gpios);
93	else
94		clrbits_be32(&data->base->gpodr, gpios);
95}
96
97static int mpc8xxx_gpio_direction_input(struct udevice *dev, uint gpio)
98{
99	struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
100	u32 mask = gpio_mask(gpio);
101
102	/* GPDIR register 0 -> input */
103	if (data->little_endian)
104		clrbits_le32(&data->base->gpdir, mask);
105	else
106		clrbits_be32(&data->base->gpdir, mask);
107
108	return 0;
109}
110
111static int mpc8xxx_gpio_set_value(struct udevice *dev, uint gpio, int value)
112{
113	struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
114	struct ccsr_gpio *base = data->base;
115	u32 mask = gpio_mask(gpio);
116	u32 gpdir;
117
118	if (value) {
119		data->dat_shadow |= mask;
120	} else {
121		data->dat_shadow &= ~mask;
122	}
123
124	if (data->little_endian)
125		gpdir = in_le32(&base->gpdir);
126	else
127		gpdir = in_be32(&base->gpdir);
128
129	gpdir |= gpio_mask(gpio);
130
131	if (data->little_endian) {
132		out_le32(&base->gpdat, gpdir & data->dat_shadow);
133		out_le32(&base->gpdir, gpdir);
134	} else {
135		out_be32(&base->gpdat, gpdir & data->dat_shadow);
136		out_be32(&base->gpdir, gpdir);
137	}
138
139	return 0;
140}
141
142static int mpc8xxx_gpio_direction_output(struct udevice *dev, uint gpio,
143					 int value)
144{
145	struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
146
147	/* GPIO 28..31 are input only on MPC5121 */
148	if (data->type == MPC5121_GPIO_TYPE && gpio >= 28)
149		return -EINVAL;
150
151	return mpc8xxx_gpio_set_value(dev, gpio, value);
152}
153
154static int mpc8xxx_gpio_get_value(struct udevice *dev, uint gpio)
155{
156	struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
157
158	if (!!mpc8xxx_gpio_get_dir(dev, gpio_mask(gpio))) {
159		/* Output -> use shadowed value */
160		return !!(data->dat_shadow & gpio_mask(gpio));
161	}
162
163	/* Input -> read value from GPDAT register */
164	return !!mpc8xxx_gpio_get_val(dev, gpio_mask(gpio));
165}
166
167static int mpc8xxx_gpio_get_function(struct udevice *dev, uint gpio)
168{
169	int dir;
170
171	dir = !!mpc8xxx_gpio_get_dir(dev, gpio_mask(gpio));
172	return dir ? GPIOF_OUTPUT : GPIOF_INPUT;
173}
174
175#if CONFIG_IS_ENABLED(OF_CONTROL)
176static int mpc8xxx_gpio_of_to_plat(struct udevice *dev)
177{
178	struct mpc8xxx_gpio_plat *plat = dev_get_plat(dev);
179	struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
180
181	if (dev_read_bool(dev, "little-endian"))
182		data->little_endian = true;
183
184	plat->addr = dev_read_addr_size_index(dev, 0, (fdt_size_t *)&plat->size);
185	plat->ngpios = dev_read_u32_default(dev, "ngpios", 32);
186
187	return 0;
188}
189#endif
190
191static int mpc8xxx_gpio_plat_to_priv(struct udevice *dev)
192{
193	struct mpc8xxx_gpio_data *priv = dev_get_priv(dev);
194	struct mpc8xxx_gpio_plat *plat = dev_get_plat(dev);
195	unsigned long size = plat->size;
196	ulong driver_data = dev_get_driver_data(dev);
197
198	if (size == 0)
199		size = 0x100;
200
201	priv->addr = plat->addr;
202	priv->base = map_sysmem(plat->addr, size);
203
204	if (!priv->base)
205		return -ENOMEM;
206
207	priv->gpio_count = plat->ngpios;
208	priv->dat_shadow = 0;
209
210	priv->type = driver_data;
211
212	return 0;
213}
214
215static int mpc8xxx_gpio_probe(struct udevice *dev)
216{
217	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
218	struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
219	char name[32], *str;
220
221	mpc8xxx_gpio_plat_to_priv(dev);
222
223	snprintf(name, sizeof(name), "MPC@%.8llx",
224		 (unsigned long long)data->addr);
225	str = strdup(name);
226
227	if (!str)
228		return -ENOMEM;
229
230	if (device_is_compatible(dev, "fsl,qoriq-gpio")) {
231		if (data->little_endian)
232			out_le32(&data->base->gpibe, 0xffffffff);
233		else
234			out_be32(&data->base->gpibe, 0xffffffff);
235	}
236
237	uc_priv->bank_name = str;
238	uc_priv->gpio_count = data->gpio_count;
239
240	return 0;
241}
242
243static const struct dm_gpio_ops gpio_mpc8xxx_ops = {
244	.direction_input	= mpc8xxx_gpio_direction_input,
245	.direction_output	= mpc8xxx_gpio_direction_output,
246	.get_value		= mpc8xxx_gpio_get_value,
247	.set_value		= mpc8xxx_gpio_set_value,
248	.get_function		= mpc8xxx_gpio_get_function,
249};
250
251static const struct udevice_id mpc8xxx_gpio_ids[] = {
252	{ .compatible = "fsl,pq3-gpio", .data = MPC8XXX_GPIO_TYPE },
253	{ .compatible = "fsl,mpc8308-gpio", .data = MPC8XXX_GPIO_TYPE },
254	{ .compatible = "fsl,mpc8349-gpio", .data = MPC8XXX_GPIO_TYPE },
255	{ .compatible = "fsl,mpc8572-gpio", .data = MPC8XXX_GPIO_TYPE},
256	{ .compatible = "fsl,mpc8610-gpio", .data = MPC8XXX_GPIO_TYPE},
257	{ .compatible = "fsl,mpc5121-gpio", .data = MPC5121_GPIO_TYPE, },
258	{ .compatible = "fsl,qoriq-gpio", .data = MPC8XXX_GPIO_TYPE },
259	{ /* sentinel */ }
260};
261
262U_BOOT_DRIVER(gpio_mpc8xxx) = {
263	.name	= "gpio_mpc8xxx",
264	.id	= UCLASS_GPIO,
265	.ops	= &gpio_mpc8xxx_ops,
266#if CONFIG_IS_ENABLED(OF_CONTROL)
267	.of_to_plat = mpc8xxx_gpio_of_to_plat,
268	.plat_auto	= sizeof(struct mpc8xxx_gpio_plat),
269	.of_match = mpc8xxx_gpio_ids,
270#endif
271	.probe	= mpc8xxx_gpio_probe,
272	.priv_auto	= sizeof(struct mpc8xxx_gpio_data),
273};
274