From 5c19689b5e1f02f85528e7258623cc17c191097b Mon Sep 17 00:00:00 2001 From: Evert Pap Date: Thu, 31 Mar 2016 15:54:38 +0200 Subject: dm: gpio: Add DM GPIO driver for MPC8xxx platforms This driver adds DM GPIO support for the NXP QorIQ T10xx series. ported from the linux kernel 4.5 * (b562e44f507e863c6792946e4e1b1449fbbac85d) * and removed the interrupt functionallity. This driver could also support the older platforms, as well as the new LayerScape (ARM) based platforms, but these platforms are not supported at this time. diff --git a/arch/powerpc/include/asm/arch-mpc85xx/gpio.h b/arch/powerpc/include/asm/arch-mpc85xx/gpio.h index da7352a..530175f 100644 --- a/arch/powerpc/include/asm/arch-mpc85xx/gpio.h +++ b/arch/powerpc/include/asm/arch-mpc85xx/gpio.h @@ -14,6 +14,10 @@ #ifndef __ASM_ARCH_MX85XX_GPIO_H #define __ASM_ARCH_MX85XX_GPIO_H +#ifdef CONFIG_MPC8XXX_GPIO +#include +#else #include +#endif #endif diff --git a/arch/powerpc/include/asm/immap_85xx.h b/arch/powerpc/include/asm/immap_85xx.h index 53ca6d9..746ad2a 100644 --- a/arch/powerpc/include/asm/immap_85xx.h +++ b/arch/powerpc/include/asm/immap_85xx.h @@ -3196,4 +3196,14 @@ struct ccsr_scfg { u32 res4[60]; u32 sparecr[8]; /* 0x500 Spare Control register(0-7) */ }; + +#if defined(CONFIG_PPC_T1013) || defined(CONFIG_PPC_T1014) ||\ + defined(CONFIG_PPC_T1020) || defined(CONFIG_PPC_T1022) ||\ + defined(CONFIG_PPC_T1023) || defined(CONFIG_PPC_T1024) ||\ + defined(CONFIG_PPC_T1040) || defined(CONFIG_PPC_T1042) ||\ +#define CONFIG_SYS_MPC8XXX_GPIO1_ADDR (CONFIG_SYS_IMMR + 0x130000) +#define CONFIG_SYS_MPC8XXX_GPIO2_ADDR (CONFIG_SYS_IMMR + 0x131000) +#define CONFIG_SYS_MPC8XXX_GPIO3_ADDR (CONFIG_SYS_IMMR + 0x132000) +#define CONFIG_SYS_MPC8XXX_GPIO4_ADDR (CONFIG_SYS_IMMR + 0x133000) +#endif #endif /*__IMMAP_85xx__*/ diff --git a/arch/powerpc/include/asm/mpc8xxx_gpio.h b/arch/powerpc/include/asm/mpc8xxx_gpio.h new file mode 100644 index 0000000..d4a5b7c --- /dev/null +++ b/arch/powerpc/include/asm/mpc8xxx_gpio.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2016 Scalys B.V. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _POWERPC_ASM_MPC8XXX_GPIO_H +#define _POWERPC_ASM_MPC8XXX_GPIO_H + +#define MPC8XXX_GPIO_NR(port, pin) ((((port)-1)*32)+((pin)&31)) +#define MPC8XXX_GPIO_TO_PORT(gpio) (gpio/32) +#define MPC8XXX_GPIO_TO_PIN(gpio) (gpio&31) + +static inline void mpc8xxx_gpio_set(uint32_t gpio, int value) +{ + int port, pin; + ccsr_gpio_t *gpio_regs; + uint32_t regval; + + port = MPC8XXX_GPIO_TO_PORT(gpio); + pin = MPC8XXX_GPIO_TO_PIN(gpio); + + switch (port) { +#ifdef CONFIG_SYS_MPC8XXX_GPIO1_ADDR + case 0: + gpio_regs = (ccsr_gpio_t *) CONFIG_SYS_MPC8XXX_GPIO1_ADDR; + break; +#endif +#ifdef CONFIG_SYS_MPC8XXX_GPIO2_ADDR + case 1: + gpio_regs = (ccsr_gpio_t *) CONFIG_SYS_MPC8XXX_GPIO2_ADDR; + break; +#endif +#ifdef CONFIG_SYS_MPC8XXX_GPIO3_ADDR + case 2: + gpio_regs = (ccsr_gpio_t *) CONFIG_SYS_MPC8XXX_GPIO3_ADDR; + break; +#endif +#ifdef CONFIG_SYS_MPC8XXX_GPIO4_ADDR + case 3: + gpio_regs = (ccsr_gpio_t *) CONFIG_SYS_MPC8XXX_GPIO4_ADDR; + break; +#endif + default: + return; + } + + /* Set output */ + regval = in_be32(&(gpio_regs->gpdat)); + regval |= (0x80000000 >> pin); + out_be32(&(gpio_regs->gpdat), regval); + + /* Set direction to acivate gpio pin */ + regval = in_be32(&(gpio_regs->gpdir)); + regval |= (0x80000000 >> pin); + out_be32(&(gpio_regs->gpdir), regval); +} + +static inline int mpc8xxx_gpio_get(uint32_t gpio, int value) +{ + int port, pin; + ccsr_gpio_t *gpio_regs; + uint32_t regval; + + port = MPC8XXX_GPIO_TO_PORT(gpio); + pin = MPC8XXX_GPIO_TO_PIN(gpio); + + switch (port) { +#ifdef CONFIG_SYS_MPC8XXX_GPIO1_ADDR + case 0: + gpio_regs = (ccsr_gpio_t *) CONFIG_SYS_MPC8XXX_GPIO1_ADDR; + break; +#endif +#ifdef CONFIG_SYS_MPC8XXX_GPIO2_ADDR + case 1: + gpio_regs = (ccsr_gpio_t *) CONFIG_SYS_MPC8XXX_GPIO2_ADDR; + break; +#endif +#ifdef CONFIG_SYS_MPC8XXX_GPIO3_ADDR + case 2: + gpio_regs = (ccsr_gpio_t *) CONFIG_SYS_MPC8XXX_GPIO3_ADDR; + break; +#endif +#ifdef CONFIG_SYS_MPC8XXX_GPIO4_ADDR + case 3: + gpio_regs = (ccsr_gpio_t *) CONFIG_SYS_MPC8XXX_GPIO4_ADDR; + break; +#endif + default: + return; + } + + /* Get inputs */ + regval = in_be32(&(gpio_regs->gpdat)); + regval <<= pin; + regval &= 1; + + return regval; +} + +#endif /* _POWERPC_ASM_MPC8XXX_GPIO_H */ diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index f56a606..2564dd2 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -28,6 +28,13 @@ config DWAPB_GPIO help Support for the Designware APB GPIO driver. +config MPC8XXX_GPIO + bool "NXP (Freescale) MPC8xxx driver" + depends on DM_GPIO + default n + help + Support for the NXP (Freescale) MPC/QorIQ GPIO controller + config ATMEL_PIO4 bool "ATMEL PIO4 driver" depends on DM diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 4f071c4..8a76a62 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_DA8XX_GPIO) += da8xx_gpio.o obj-$(CONFIG_DM644X_GPIO) += da8xx_gpio.o obj-$(CONFIG_ALTERA_PIO) += altera_pio.o obj-$(CONFIG_MPC83XX_GPIO) += mpc83xx_gpio.o +obj-$(CONFIG_MPC8XXX_GPIO) += gpio-mpc8xxx.o obj-$(CONFIG_SH_GPIO_PFC) += sh_pfc.o obj-$(CONFIG_OMAP_GPIO) += omap_gpio.o obj-$(CONFIG_DB8500_GPIO) += db8500_gpio.o diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c new file mode 100644 index 0000000..c5d72ef --- /dev/null +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -0,0 +1,178 @@ + +/* + * GPIOs on MPC512x/8349/8572/8610/T-series and compatible + * + * Driver ported from the linux kernel 4.5 (b562e44f507e863c6792946e4e1b1449fbbac85d) + * and removed the interrupt functionallity. + * + * Copyright (C) 2008 Peter Korsgaard + * Copyright (c) 2016 Scalys B.V. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#define MPC8XXX_GPIO_PINS 32 + +static inline u32 mpc8xxx_gpio2mask(unsigned int gpio) +{ + return 1u << (MPC8XXX_GPIO_PINS - 1 - gpio); +} + +static int mpc8xxx_dm_gpio_set(struct udevice *dev, unsigned pin, int val) +{ + struct mpc8xxx_gpio_platdata *plat = dev_get_platdata(dev); + +#if defined(CONFIG_MPC8572) || defined(CONFIG_MPC8536) + + if (val) { + plat->data |= mpc8xxx_gpio2mask(pin); + } else { + plat->data &= ~mpc8xxx_gpio2mask(pin); + } + + out_be32(&(plat->regs->gpdat), plat->data); +#else + if (val) { + setbits_be32(&(plat->regs->gpdat), mpc8xxx_gpio2mask(pin)); + } else { + clrbits_be32(&(plat->regs->gpdat), mpc8xxx_gpio2mask(pin)); + } +#endif + return 0; +} + +static int mpc8xxx_dm_gpio_dir_in(struct udevice *dev, unsigned int gpio) +{ + struct mpc8xxx_gpio_platdata *plat = dev_get_platdata(dev); + + clrbits_be32(&(plat->regs->gpdir), mpc8xxx_gpio2mask(gpio)); + + return 0; +} + +static int mpc8xxx_dm_gpio_dir_out(struct udevice *dev, unsigned int gpio, + int val) +{ + struct mpc8xxx_gpio_platdata *plat = dev_get_platdata(dev); + + mpc8xxx_dm_gpio_set(dev, gpio, val); + + setbits_be32(&(plat->regs->gpdir), mpc8xxx_gpio2mask(gpio)); + + return 0; +} + +static int mpc8xxx_dm_gpio_get(struct udevice *dev, unsigned int gpio) +{ + int ret = 0; + struct mpc8xxx_gpio_platdata *plat = dev_get_platdata(dev); + +#if defined(CONFIG_MPC8572) || defined(CONFIG_MPC8536) + uint32_t data_val, out_mask, out_shadow; + + /* Workaround GPIO 1 errata on MPC8572/MPC8536. The status of GPIOs + * defined as output cannot be determined by reading GPDAT register, + * so we use shadow data register instead. The status of input pins + * is determined by reading GPDAT register. + */ + out_mask = in_be32(&plat->regs->gpdir); + + data_val = in_be32(&plat->regs->gpdat) & ~out_mask; + out_shadow = plat->data & out_mask; + + ret = ! !((data_val | out_shadow) & mpc8xxx_gpio2mask(gpio)); +#else + if (in_be32(&plat->regs->gpdat) & mpc8xxx_gpio2mask(gpio)) { + ret = 1; + } else { + ret = 0; + } +#endif + return ret; +} + +static int mpc8xxx_dm_gpio_get_function(struct udevice *dev, unsigned gpio) +{ + int ret = GPIOF_UNUSED; + struct mpc8xxx_gpio_platdata *plat = dev_get_platdata(dev); + + if (in_be32(&plat->regs->gpdir) & mpc8xxx_gpio2mask(gpio)) { + ret = GPIOF_OUTPUT; + } else { + ret = GPIOF_INPUT; + } + return ret; +} + +static const struct udevice_id mpc8xxx_gpio_ids[] = { + {.compatible = "fsl,mpc8349-gpio",}, + {.compatible = "fsl,mpc8572-gpio",}, + {.compatible = "fsl,mpc8610-gpio",}, + {.compatible = "fsl,mpc5121-gpio",}, + {.compatible = "fsl,mpc5125-gpio",}, + {.compatible = "fsl,pq3-gpio",}, + {.compatible = "fsl,qoriq-gpio",}, + {} +}; + +static const struct dm_gpio_ops mpc8xxx_gpio_ops = { + .direction_input = mpc8xxx_dm_gpio_dir_in, + .direction_output = mpc8xxx_dm_gpio_dir_out, + .get_value = mpc8xxx_dm_gpio_get, + .set_value = mpc8xxx_dm_gpio_set, + .get_function = mpc8xxx_dm_gpio_get_function, +}; + +#ifdef SPL_OF_CONTROL +static int mpc8xxx_gpio_ofdata_to_platdata(struct udevice *dev) +{ + int register_address; + struct mpc8xxx_gpio_platdata *plat = dev_get_platdata(dev); + + register_address = + fdtdec_get_int(gd->fdt_blob, dev->of_offset, "reg", -1); + if (register_address == -1) { + debug("%s: Invalid register offset %d\n", __func__, + register_address); + return -EINVAL; + } + plat->regs = map_physmem(register_address, sizeof(ccsr_gpio_t), + MAP_NOCACHE); + plat->gpio_count = MPC8XXX_GPIO_PINS; + plat->bank_name = fdt_getprop(gd->fdt_blob, dev->of_offset, + "bank-name", NULL); + + return 0; +} +#endif + +static int mpc8xxx_gpio_probe(struct udevice *dev) +{ + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct mpc8xxx_gpio_platdata *plat = dev_get_platdata(dev); + + uc_priv->gpio_count = MPC8XXX_GPIO_PINS; + uc_priv->bank_name = plat->bank_name; + + return 0; +} + +U_BOOT_DRIVER(gpio_mpc8xxx) = { + .name = "gpio-mpc8xxx",.id = UCLASS_GPIO,.of_match = + mpc8xxx_gpio_ids,.ops = &mpc8xxx_gpio_ops, +#ifdef SPL_OF_CONTROL + .ofdata_to_platdata = mpc8xxx_gpio_ofdata_to_platdata, +#endif +.platdata_auto_alloc_size = + sizeof(struct mpc8xxx_gpio_platdata),.probe = mpc8xxx_gpio_probe,}; diff --git a/include/dm/platform_data/gpio_mpc8xxx.h b/include/dm/platform_data/gpio_mpc8xxx.h new file mode 100644 index 0000000..37e5241 --- /dev/null +++ b/include/dm/platform_data/gpio_mpc8xxx.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2016 Scalys B.V. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _MPC8XXX_GPIO_H +#define _MPC8XXX_GPIO_H + +struct mpc8xxx_gpio_platdata { + const char *bank_name; + ccsr_gpio_t *regs; + int gpio_count; +#if defined(CONFIG_MPC8572) || defined(CONFIG_MPC8536) + /* shadowed data register used to work around errata on + * MPC8572 and MPC8535 where it is not possible to read the + * state of an output pin */ + uint32_t data; +#endif +}; + +#endif -- cgit v0.10.2