blob: e9bd38f162c10c76460bc63f93c03a711cb4d38e [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +02002/*
3 * (C) Copyright 2016
Mario Sixd38826a2018-03-06 08:04:58 +01004 * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +02005 *
6 * based on arch/powerpc/include/asm/mpc85xx_gpio.h, which is
7 *
8 * Copyright 2010 eXMeritus, A Boeing Company
Biwen Li78118802021-02-05 19:01:47 +08009 * Copyright 2020-2021 NXP
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +020010 */
11
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +020012#include <dm.h>
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +020013#include <mapmem.h>
Mario Sixf9c7fde2018-01-15 11:07:49 +010014#include <asm/gpio.h>
hui.songd5d6b542020-09-24 21:40:50 +080015#include <asm/io.h>
16#include <dm/of_access.h>
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +020017
Mario Six3c216832018-01-15 11:07:48 +010018struct mpc8xxx_gpio_data {
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +020019 /* The bank's register base in memory */
20 struct ccsr_gpio __iomem *base;
21 /* The address of the registers; used to identify the bank */
Bin Meng271a87b2021-02-25 17:22:50 +080022 phys_addr_t addr;
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +020023 /* The GPIO count of the bank */
24 uint gpio_count;
25 /* The GPDAT register cannot be used to determine the value of output
26 * pins on MPC8572/MPC8536, so we shadow it and use the shadowed value
Mario Sixaadc5e62018-01-15 11:07:46 +010027 * for output pins
28 */
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +020029 u32 dat_shadow;
Mario Sixf9c7fde2018-01-15 11:07:49 +010030 ulong type;
hui.songd5d6b542020-09-24 21:40:50 +080031 bool little_endian;
Mario Sixf9c7fde2018-01-15 11:07:49 +010032};
33
34enum {
35 MPC8XXX_GPIO_TYPE,
36 MPC5121_GPIO_TYPE,
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +020037};
38
Mario Sixaadc5e62018-01-15 11:07:46 +010039inline u32 gpio_mask(uint gpio)
40{
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +020041 return (1U << (31 - (gpio)));
42}
43
hui.songd5d6b542020-09-24 21:40:50 +080044static inline u32 mpc8xxx_gpio_get_val(struct udevice *dev, u32 mask)
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +020045{
hui.songd5d6b542020-09-24 21:40:50 +080046 struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
47
48 if (data->little_endian)
49 return in_le32(&data->base->gpdat) & mask;
50 else
51 return in_be32(&data->base->gpdat) & mask;
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +020052}
53
hui.songd5d6b542020-09-24 21:40:50 +080054static inline u32 mpc8xxx_gpio_get_dir(struct udevice *dev, u32 mask)
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +020055{
hui.songd5d6b542020-09-24 21:40:50 +080056 struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
57
58 if (data->little_endian)
59 return in_le32(&data->base->gpdir) & mask;
60 else
61 return in_be32(&data->base->gpdir) & mask;
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +020062}
63
hui.songd5d6b542020-09-24 21:40:50 +080064static inline int mpc8xxx_gpio_open_drain_val(struct udevice *dev, u32 mask)
mario.six@gdsys.cc51781782016-05-25 15:15:22 +020065{
hui.songd5d6b542020-09-24 21:40:50 +080066 struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
67
68 if (data->little_endian)
69 return in_le32(&data->base->gpodr) & mask;
70 else
71 return in_be32(&data->base->gpodr) & mask;
mario.six@gdsys.cc51781782016-05-25 15:15:22 +020072}
73
hui.songd5d6b542020-09-24 21:40:50 +080074static inline void mpc8xxx_gpio_open_drain_on(struct udevice *dev, u32
mario.six@gdsys.cc51781782016-05-25 15:15:22 +020075 gpios)
76{
hui.songd5d6b542020-09-24 21:40:50 +080077 struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
mario.six@gdsys.cc51781782016-05-25 15:15:22 +020078 /* GPODR register 1 -> open drain on */
hui.songd5d6b542020-09-24 21:40:50 +080079 if (data->little_endian)
80 setbits_le32(&data->base->gpodr, gpios);
81 else
82 setbits_be32(&data->base->gpodr, gpios);
mario.six@gdsys.cc51781782016-05-25 15:15:22 +020083}
84
hui.songd5d6b542020-09-24 21:40:50 +080085static inline void mpc8xxx_gpio_open_drain_off(struct udevice *dev,
mario.six@gdsys.cc51781782016-05-25 15:15:22 +020086 u32 gpios)
87{
hui.songd5d6b542020-09-24 21:40:50 +080088 struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
mario.six@gdsys.cc51781782016-05-25 15:15:22 +020089 /* GPODR register 0 -> open drain off (actively driven) */
hui.songd5d6b542020-09-24 21:40:50 +080090 if (data->little_endian)
91 clrbits_le32(&data->base->gpodr, gpios);
92 else
93 clrbits_be32(&data->base->gpodr, gpios);
mario.six@gdsys.cc51781782016-05-25 15:15:22 +020094}
95
Mario Six3c216832018-01-15 11:07:48 +010096static int mpc8xxx_gpio_direction_input(struct udevice *dev, uint gpio)
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +020097{
Mario Six3c216832018-01-15 11:07:48 +010098 struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
Rasmus Villemoes1d7ad9f2020-01-28 12:04:33 +000099 u32 mask = gpio_mask(gpio);
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200100
Rasmus Villemoes1d7ad9f2020-01-28 12:04:33 +0000101 /* GPDIR register 0 -> input */
hui.songd5d6b542020-09-24 21:40:50 +0800102 if (data->little_endian)
103 clrbits_le32(&data->base->gpdir, mask);
104 else
105 clrbits_be32(&data->base->gpdir, mask);
Rasmus Villemoes1d7ad9f2020-01-28 12:04:33 +0000106
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200107 return 0;
108}
109
Mario Six3c216832018-01-15 11:07:48 +0100110static int mpc8xxx_gpio_set_value(struct udevice *dev, uint gpio, int value)
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200111{
Mario Six3c216832018-01-15 11:07:48 +0100112 struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
Rasmus Villemoesdd4cf532020-01-28 12:04:34 +0000113 struct ccsr_gpio *base = data->base;
114 u32 mask = gpio_mask(gpio);
115 u32 gpdir;
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200116
117 if (value) {
Rasmus Villemoesdd4cf532020-01-28 12:04:34 +0000118 data->dat_shadow |= mask;
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200119 } else {
Rasmus Villemoesdd4cf532020-01-28 12:04:34 +0000120 data->dat_shadow &= ~mask;
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200121 }
Rasmus Villemoesdd4cf532020-01-28 12:04:34 +0000122
hui.songd5d6b542020-09-24 21:40:50 +0800123 if (data->little_endian)
124 gpdir = in_le32(&base->gpdir);
125 else
126 gpdir = in_be32(&base->gpdir);
127
Rasmus Villemoesdd4cf532020-01-28 12:04:34 +0000128 gpdir |= gpio_mask(gpio);
hui.songd5d6b542020-09-24 21:40:50 +0800129
130 if (data->little_endian) {
131 out_le32(&base->gpdat, gpdir & data->dat_shadow);
132 out_le32(&base->gpdir, gpdir);
133 } else {
134 out_be32(&base->gpdat, gpdir & data->dat_shadow);
135 out_be32(&base->gpdir, gpdir);
136 }
Rasmus Villemoesdd4cf532020-01-28 12:04:34 +0000137
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200138 return 0;
139}
140
Mario Six3c216832018-01-15 11:07:48 +0100141static int mpc8xxx_gpio_direction_output(struct udevice *dev, uint gpio,
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200142 int value)
143{
Mario Sixf9c7fde2018-01-15 11:07:49 +0100144 struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
145
146 /* GPIO 28..31 are input only on MPC5121 */
147 if (data->type == MPC5121_GPIO_TYPE && gpio >= 28)
148 return -EINVAL;
149
Mario Six3c216832018-01-15 11:07:48 +0100150 return mpc8xxx_gpio_set_value(dev, gpio, value);
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200151}
152
Mario Six3c216832018-01-15 11:07:48 +0100153static int mpc8xxx_gpio_get_value(struct udevice *dev, uint gpio)
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200154{
Mario Six3c216832018-01-15 11:07:48 +0100155 struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200156
hui.songd5d6b542020-09-24 21:40:50 +0800157 if (!!mpc8xxx_gpio_get_dir(dev, gpio_mask(gpio))) {
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200158 /* Output -> use shadowed value */
159 return !!(data->dat_shadow & gpio_mask(gpio));
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200160 }
Mario Sixaadc5e62018-01-15 11:07:46 +0100161
162 /* Input -> read value from GPDAT register */
hui.songd5d6b542020-09-24 21:40:50 +0800163 return !!mpc8xxx_gpio_get_val(dev, gpio_mask(gpio));
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200164}
165
Mario Six3c216832018-01-15 11:07:48 +0100166static int mpc8xxx_gpio_get_function(struct udevice *dev, uint gpio)
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200167{
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200168 int dir;
169
hui.songd5d6b542020-09-24 21:40:50 +0800170 dir = !!mpc8xxx_gpio_get_dir(dev, gpio_mask(gpio));
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200171 return dir ? GPIOF_OUTPUT : GPIOF_INPUT;
172}
173
Hamish Martin4b689f02016-06-14 10:17:05 +1200174#if CONFIG_IS_ENABLED(OF_CONTROL)
Simon Glassd1998a92020-12-03 16:55:21 -0700175static int mpc8xxx_gpio_of_to_plat(struct udevice *dev)
Mario Sixaadc5e62018-01-15 11:07:46 +0100176{
Simon Glassc69cda22020-12-03 16:55:20 -0700177 struct mpc8xxx_gpio_plat *plat = dev_get_plat(dev);
hui.songd5d6b542020-09-24 21:40:50 +0800178 struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200179
Biwen Li78118802021-02-05 19:01:47 +0800180 if (dev_read_bool(dev, "little-endian"))
hui.songd5d6b542020-09-24 21:40:50 +0800181 data->little_endian = true;
182
Bin Meng271a87b2021-02-25 17:22:50 +0800183 plat->addr = dev_read_addr_size_index(dev, 0, (fdt_size_t *)&plat->size);
Mario Sixf5ac4f22018-01-15 11:07:50 +0100184 plat->ngpios = dev_read_u32_default(dev, "ngpios", 32);
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200185
Hamish Martin4b689f02016-06-14 10:17:05 +1200186 return 0;
187}
188#endif
189
Simon Glass8a8d24b2020-12-03 16:55:23 -0700190static int mpc8xxx_gpio_plat_to_priv(struct udevice *dev)
Hamish Martin4b689f02016-06-14 10:17:05 +1200191{
Mario Six3c216832018-01-15 11:07:48 +0100192 struct mpc8xxx_gpio_data *priv = dev_get_priv(dev);
Simon Glassc69cda22020-12-03 16:55:20 -0700193 struct mpc8xxx_gpio_plat *plat = dev_get_plat(dev);
Hamish Martin4b689f02016-06-14 10:17:05 +1200194 unsigned long size = plat->size;
Mario Sixf9c7fde2018-01-15 11:07:49 +0100195 ulong driver_data = dev_get_driver_data(dev);
Hamish Martin4b689f02016-06-14 10:17:05 +1200196
197 if (size == 0)
198 size = 0x100;
199
200 priv->addr = plat->addr;
Mario Sixf5ac4f22018-01-15 11:07:50 +0100201 priv->base = map_sysmem(plat->addr, size);
Hamish Martin4b689f02016-06-14 10:17:05 +1200202
203 if (!priv->base)
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200204 return -ENOMEM;
205
Hamish Martin4b689f02016-06-14 10:17:05 +1200206 priv->gpio_count = plat->ngpios;
207 priv->dat_shadow = 0;
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200208
Mario Six3c216832018-01-15 11:07:48 +0100209 priv->type = driver_data;
210
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200211 return 0;
212}
213
Mario Six3c216832018-01-15 11:07:48 +0100214static int mpc8xxx_gpio_probe(struct udevice *dev)
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200215{
216 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Mario Six3c216832018-01-15 11:07:48 +0100217 struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200218 char name[32], *str;
219
Simon Glass8a8d24b2020-12-03 16:55:23 -0700220 mpc8xxx_gpio_plat_to_priv(dev);
Hamish Martin4b689f02016-06-14 10:17:05 +1200221
Bin Meng271a87b2021-02-25 17:22:50 +0800222 snprintf(name, sizeof(name), "MPC@%.8llx",
223 (unsigned long long)data->addr);
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200224 str = strdup(name);
225
226 if (!str)
227 return -ENOMEM;
228
Biwen Li78118802021-02-05 19:01:47 +0800229 if (device_is_compatible(dev, "fsl,qoriq-gpio")) {
230 if (data->little_endian)
231 out_le32(&data->base->gpibe, 0xffffffff);
232 else
233 out_be32(&data->base->gpibe, 0xffffffff);
hui.songd5d6b542020-09-24 21:40:50 +0800234 }
235
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200236 uc_priv->bank_name = str;
237 uc_priv->gpio_count = data->gpio_count;
238
239 return 0;
240}
241
Mario Six3c216832018-01-15 11:07:48 +0100242static const struct dm_gpio_ops gpio_mpc8xxx_ops = {
243 .direction_input = mpc8xxx_gpio_direction_input,
244 .direction_output = mpc8xxx_gpio_direction_output,
245 .get_value = mpc8xxx_gpio_get_value,
246 .set_value = mpc8xxx_gpio_set_value,
Mario Six3c216832018-01-15 11:07:48 +0100247 .get_function = mpc8xxx_gpio_get_function,
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200248};
249
Mario Six3c216832018-01-15 11:07:48 +0100250static const struct udevice_id mpc8xxx_gpio_ids[] = {
Mario Sixf9c7fde2018-01-15 11:07:49 +0100251 { .compatible = "fsl,pq3-gpio", .data = MPC8XXX_GPIO_TYPE },
252 { .compatible = "fsl,mpc8308-gpio", .data = MPC8XXX_GPIO_TYPE },
253 { .compatible = "fsl,mpc8349-gpio", .data = MPC8XXX_GPIO_TYPE },
254 { .compatible = "fsl,mpc8572-gpio", .data = MPC8XXX_GPIO_TYPE},
255 { .compatible = "fsl,mpc8610-gpio", .data = MPC8XXX_GPIO_TYPE},
256 { .compatible = "fsl,mpc5121-gpio", .data = MPC5121_GPIO_TYPE, },
257 { .compatible = "fsl,qoriq-gpio", .data = MPC8XXX_GPIO_TYPE },
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200258 { /* sentinel */ }
259};
260
Mario Six3c216832018-01-15 11:07:48 +0100261U_BOOT_DRIVER(gpio_mpc8xxx) = {
262 .name = "gpio_mpc8xxx",
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200263 .id = UCLASS_GPIO,
Mario Six3c216832018-01-15 11:07:48 +0100264 .ops = &gpio_mpc8xxx_ops,
Hamish Martin4b689f02016-06-14 10:17:05 +1200265#if CONFIG_IS_ENABLED(OF_CONTROL)
Simon Glassd1998a92020-12-03 16:55:21 -0700266 .of_to_plat = mpc8xxx_gpio_of_to_plat,
Simon Glasscaa4daa2020-12-03 16:55:18 -0700267 .plat_auto = sizeof(struct mpc8xxx_gpio_plat),
Mario Six3c216832018-01-15 11:07:48 +0100268 .of_match = mpc8xxx_gpio_ids,
Hamish Martin4b689f02016-06-14 10:17:05 +1200269#endif
Mario Six3c216832018-01-15 11:07:48 +0100270 .probe = mpc8xxx_gpio_probe,
Simon Glass41575d82020-12-03 16:55:17 -0700271 .priv_auto = sizeof(struct mpc8xxx_gpio_data),
mario.six@gdsys.cc07d31f82016-05-25 15:15:20 +0200272};