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