blob: f7ffd8926aded4d054536e91988b6046f04d9671 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +02002/*
3 * (C) Copyright 2016
Mario Sixb4893582018-03-06 08:04:58 +01004 * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
mario.six@gdsys.cc5b59a352016-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 Lidb5d53b2021-02-05 19:01:47 +08009 * Copyright 2020-2021 NXP
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +020010 */
11
12#include <common.h>
13#include <dm.h>
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +020014#include <mapmem.h>
Mario Sixd7c6f712018-01-15 11:07:49 +010015#include <asm/gpio.h>
hui.songc615d0c2020-09-24 21:40:50 +080016#include <asm/io.h>
17#include <dm/of_access.h>
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +020018
Mario Sixd006f682018-01-15 11:07:48 +010019struct mpc8xxx_gpio_data {
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +020020 /* The bank's register base in memory */
21 struct ccsr_gpio __iomem *base;
22 /* The address of the registers; used to identify the bank */
Bin Meng09fb76d2021-02-25 17:22:50 +080023 phys_addr_t addr;
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +020024 /* 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
Mario Sixcc94b172018-01-15 11:07:46 +010028 * for output pins
29 */
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +020030 u32 dat_shadow;
Mario Sixd7c6f712018-01-15 11:07:49 +010031 ulong type;
hui.songc615d0c2020-09-24 21:40:50 +080032 bool little_endian;
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +020033};
34
Mario Sixd7c6f712018-01-15 11:07:49 +010035enum {
36 MPC8XXX_GPIO_TYPE,
37 MPC5121_GPIO_TYPE,
38};
39
Mario Sixcc94b172018-01-15 11:07:46 +010040inline u32 gpio_mask(uint gpio)
41{
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +020042 return (1U << (31 - (gpio)));
43}
44
hui.songc615d0c2020-09-24 21:40:50 +080045static inline u32 mpc8xxx_gpio_get_val(struct udevice *dev, u32 mask)
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +020046{
hui.songc615d0c2020-09-24 21:40:50 +080047 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;
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +020053}
54
hui.songc615d0c2020-09-24 21:40:50 +080055static inline u32 mpc8xxx_gpio_get_dir(struct udevice *dev, u32 mask)
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +020056{
hui.songc615d0c2020-09-24 21:40:50 +080057 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;
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +020063}
64
hui.songc615d0c2020-09-24 21:40:50 +080065static inline int mpc8xxx_gpio_open_drain_val(struct udevice *dev, u32 mask)
mario.six@gdsys.cc7b4cf8b2016-05-25 15:15:22 +020066{
hui.songc615d0c2020-09-24 21:40:50 +080067 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;
mario.six@gdsys.cc7b4cf8b2016-05-25 15:15:22 +020073}
74
hui.songc615d0c2020-09-24 21:40:50 +080075static inline void mpc8xxx_gpio_open_drain_on(struct udevice *dev, u32
mario.six@gdsys.cc7b4cf8b2016-05-25 15:15:22 +020076 gpios)
77{
hui.songc615d0c2020-09-24 21:40:50 +080078 struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
mario.six@gdsys.cc7b4cf8b2016-05-25 15:15:22 +020079 /* GPODR register 1 -> open drain on */
hui.songc615d0c2020-09-24 21:40:50 +080080 if (data->little_endian)
81 setbits_le32(&data->base->gpodr, gpios);
82 else
83 setbits_be32(&data->base->gpodr, gpios);
mario.six@gdsys.cc7b4cf8b2016-05-25 15:15:22 +020084}
85
hui.songc615d0c2020-09-24 21:40:50 +080086static inline void mpc8xxx_gpio_open_drain_off(struct udevice *dev,
mario.six@gdsys.cc7b4cf8b2016-05-25 15:15:22 +020087 u32 gpios)
88{
hui.songc615d0c2020-09-24 21:40:50 +080089 struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
mario.six@gdsys.cc7b4cf8b2016-05-25 15:15:22 +020090 /* GPODR register 0 -> open drain off (actively driven) */
hui.songc615d0c2020-09-24 21:40:50 +080091 if (data->little_endian)
92 clrbits_le32(&data->base->gpodr, gpios);
93 else
94 clrbits_be32(&data->base->gpodr, gpios);
mario.six@gdsys.cc7b4cf8b2016-05-25 15:15:22 +020095}
96
Mario Sixd006f682018-01-15 11:07:48 +010097static int mpc8xxx_gpio_direction_input(struct udevice *dev, uint gpio)
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +020098{
Mario Sixd006f682018-01-15 11:07:48 +010099 struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
Rasmus Villemoesbb36b0d2020-01-28 12:04:33 +0000100 u32 mask = gpio_mask(gpio);
101
102 /* GPDIR register 0 -> input */
hui.songc615d0c2020-09-24 21:40:50 +0800103 if (data->little_endian)
104 clrbits_le32(&data->base->gpdir, mask);
105 else
106 clrbits_be32(&data->base->gpdir, mask);
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200107
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200108 return 0;
109}
110
Mario Sixd006f682018-01-15 11:07:48 +0100111static int mpc8xxx_gpio_set_value(struct udevice *dev, uint gpio, int value)
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200112{
Mario Sixd006f682018-01-15 11:07:48 +0100113 struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
Rasmus Villemoes62985292020-01-28 12:04:34 +0000114 struct ccsr_gpio *base = data->base;
115 u32 mask = gpio_mask(gpio);
116 u32 gpdir;
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200117
118 if (value) {
Rasmus Villemoes62985292020-01-28 12:04:34 +0000119 data->dat_shadow |= mask;
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200120 } else {
Rasmus Villemoes62985292020-01-28 12:04:34 +0000121 data->dat_shadow &= ~mask;
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200122 }
Rasmus Villemoes62985292020-01-28 12:04:34 +0000123
hui.songc615d0c2020-09-24 21:40:50 +0800124 if (data->little_endian)
125 gpdir = in_le32(&base->gpdir);
126 else
127 gpdir = in_be32(&base->gpdir);
128
Rasmus Villemoes62985292020-01-28 12:04:34 +0000129 gpdir |= gpio_mask(gpio);
hui.songc615d0c2020-09-24 21:40:50 +0800130
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 }
Rasmus Villemoes62985292020-01-28 12:04:34 +0000138
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200139 return 0;
140}
141
Mario Sixd006f682018-01-15 11:07:48 +0100142static int mpc8xxx_gpio_direction_output(struct udevice *dev, uint gpio,
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200143 int value)
144{
Mario Sixd7c6f712018-01-15 11:07:49 +0100145 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
Mario Sixd006f682018-01-15 11:07:48 +0100151 return mpc8xxx_gpio_set_value(dev, gpio, value);
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200152}
153
Mario Sixd006f682018-01-15 11:07:48 +0100154static int mpc8xxx_gpio_get_value(struct udevice *dev, uint gpio)
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200155{
Mario Sixd006f682018-01-15 11:07:48 +0100156 struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200157
hui.songc615d0c2020-09-24 21:40:50 +0800158 if (!!mpc8xxx_gpio_get_dir(dev, gpio_mask(gpio))) {
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200159 /* Output -> use shadowed value */
160 return !!(data->dat_shadow & gpio_mask(gpio));
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200161 }
Mario Sixcc94b172018-01-15 11:07:46 +0100162
163 /* Input -> read value from GPDAT register */
hui.songc615d0c2020-09-24 21:40:50 +0800164 return !!mpc8xxx_gpio_get_val(dev, gpio_mask(gpio));
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200165}
166
Mario Sixd006f682018-01-15 11:07:48 +0100167static int mpc8xxx_gpio_get_function(struct udevice *dev, uint gpio)
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200168{
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200169 int dir;
170
hui.songc615d0c2020-09-24 21:40:50 +0800171 dir = !!mpc8xxx_gpio_get_dir(dev, gpio_mask(gpio));
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200172 return dir ? GPIOF_OUTPUT : GPIOF_INPUT;
173}
174
Hamish Martin47ca9fc2016-06-14 10:17:05 +1200175#if CONFIG_IS_ENABLED(OF_CONTROL)
Simon Glassaad29ae2020-12-03 16:55:21 -0700176static int mpc8xxx_gpio_of_to_plat(struct udevice *dev)
Mario Sixcc94b172018-01-15 11:07:46 +0100177{
Simon Glassfa20e932020-12-03 16:55:20 -0700178 struct mpc8xxx_gpio_plat *plat = dev_get_plat(dev);
hui.songc615d0c2020-09-24 21:40:50 +0800179 struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
hui.songc615d0c2020-09-24 21:40:50 +0800180
Biwen Lidb5d53b2021-02-05 19:01:47 +0800181 if (dev_read_bool(dev, "little-endian"))
hui.songc615d0c2020-09-24 21:40:50 +0800182 data->little_endian = true;
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200183
Bin Meng09fb76d2021-02-25 17:22:50 +0800184 plat->addr = dev_read_addr_size_index(dev, 0, (fdt_size_t *)&plat->size);
Mario Sixf99b6bf2018-01-15 11:07:50 +0100185 plat->ngpios = dev_read_u32_default(dev, "ngpios", 32);
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200186
Hamish Martin47ca9fc2016-06-14 10:17:05 +1200187 return 0;
188}
189#endif
190
Simon Glassb75b15b2020-12-03 16:55:23 -0700191static int mpc8xxx_gpio_plat_to_priv(struct udevice *dev)
Hamish Martin47ca9fc2016-06-14 10:17:05 +1200192{
Mario Sixd006f682018-01-15 11:07:48 +0100193 struct mpc8xxx_gpio_data *priv = dev_get_priv(dev);
Simon Glassfa20e932020-12-03 16:55:20 -0700194 struct mpc8xxx_gpio_plat *plat = dev_get_plat(dev);
Hamish Martin47ca9fc2016-06-14 10:17:05 +1200195 unsigned long size = plat->size;
Mario Sixd7c6f712018-01-15 11:07:49 +0100196 ulong driver_data = dev_get_driver_data(dev);
Hamish Martin47ca9fc2016-06-14 10:17:05 +1200197
198 if (size == 0)
199 size = 0x100;
200
201 priv->addr = plat->addr;
Mario Sixf99b6bf2018-01-15 11:07:50 +0100202 priv->base = map_sysmem(plat->addr, size);
Hamish Martin47ca9fc2016-06-14 10:17:05 +1200203
204 if (!priv->base)
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200205 return -ENOMEM;
206
Hamish Martin47ca9fc2016-06-14 10:17:05 +1200207 priv->gpio_count = plat->ngpios;
208 priv->dat_shadow = 0;
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200209
Mario Sixd006f682018-01-15 11:07:48 +0100210 priv->type = driver_data;
211
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200212 return 0;
213}
214
Mario Sixd006f682018-01-15 11:07:48 +0100215static int mpc8xxx_gpio_probe(struct udevice *dev)
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200216{
217 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Mario Sixd006f682018-01-15 11:07:48 +0100218 struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200219 char name[32], *str;
220
Simon Glassb75b15b2020-12-03 16:55:23 -0700221 mpc8xxx_gpio_plat_to_priv(dev);
Hamish Martin47ca9fc2016-06-14 10:17:05 +1200222
Bin Meng09fb76d2021-02-25 17:22:50 +0800223 snprintf(name, sizeof(name), "MPC@%.8llx",
224 (unsigned long long)data->addr);
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200225 str = strdup(name);
226
227 if (!str)
228 return -ENOMEM;
229
Biwen Lidb5d53b2021-02-05 19:01:47 +0800230 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);
hui.songc615d0c2020-09-24 21:40:50 +0800235 }
236
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200237 uc_priv->bank_name = str;
238 uc_priv->gpio_count = data->gpio_count;
239
240 return 0;
241}
242
Mario Sixd006f682018-01-15 11:07:48 +0100243static 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,
Mario Sixd006f682018-01-15 11:07:48 +0100248 .get_function = mpc8xxx_gpio_get_function,
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200249};
250
Mario Sixd006f682018-01-15 11:07:48 +0100251static const struct udevice_id mpc8xxx_gpio_ids[] = {
Mario Sixd7c6f712018-01-15 11:07:49 +0100252 { .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 },
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200259 { /* sentinel */ }
260};
261
Mario Sixd006f682018-01-15 11:07:48 +0100262U_BOOT_DRIVER(gpio_mpc8xxx) = {
263 .name = "gpio_mpc8xxx",
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200264 .id = UCLASS_GPIO,
Mario Sixd006f682018-01-15 11:07:48 +0100265 .ops = &gpio_mpc8xxx_ops,
Hamish Martin47ca9fc2016-06-14 10:17:05 +1200266#if CONFIG_IS_ENABLED(OF_CONTROL)
Simon Glassaad29ae2020-12-03 16:55:21 -0700267 .of_to_plat = mpc8xxx_gpio_of_to_plat,
Simon Glass71fa5b42020-12-03 16:55:18 -0700268 .plat_auto = sizeof(struct mpc8xxx_gpio_plat),
Mario Sixd006f682018-01-15 11:07:48 +0100269 .of_match = mpc8xxx_gpio_ids,
Hamish Martin47ca9fc2016-06-14 10:17:05 +1200270#endif
Mario Sixd006f682018-01-15 11:07:48 +0100271 .probe = mpc8xxx_gpio_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700272 .priv_auto = sizeof(struct mpc8xxx_gpio_data),
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200273};