From d1aef94b5af0d0191a8f53dfdd2a1d661a1c54cd Mon Sep 17 00:00:00 2001 From: Jianqun Xu Date: Wed, 27 May 2020 11:36:26 +0800 Subject: [PATCH] gpio/rockchip: rk_gpio support v2 gpio controller The v2 gpio controller add write enable bit for some register, such as data register, data direction register and so on. This patch support v2 gpio controller by redefine the read and write operation functions. Change-Id: I2adbcca06a37c48e6f494b89833cd034ba0dae29 Signed-off-by: Jianqun Xu --- arch/arm/include/asm/arch-rockchip/gpio.h | 36 +++++++++++++++++++++ drivers/gpio/Kconfig | 13 ++++++++ drivers/gpio/rk_gpio.c | 38 +++++++++++++++++++---- 3 files changed, 81 insertions(+), 6 deletions(-) diff --git a/arch/arm/include/asm/arch-rockchip/gpio.h b/arch/arm/include/asm/arch-rockchip/gpio.h index e39218d0a9..84b11b7dd5 100644 --- a/arch/arm/include/asm/arch-rockchip/gpio.h +++ b/arch/arm/include/asm/arch-rockchip/gpio.h @@ -7,6 +7,7 @@ #ifndef _ASM_ARCH_GPIO_H #define _ASM_ARCH_GPIO_H +#ifndef CONFIG_ROCKCHIP_GPIO_V2 struct rockchip_gpio_regs { u32 swport_dr; u32 swport_ddr; @@ -24,5 +25,40 @@ struct rockchip_gpio_regs { u32 ls_sync; }; check_member(rockchip_gpio_regs, ls_sync, 0x60); +#else +struct rockchip_gpio_regs { + u32 swport_dr_l; /* ADDRESS OFFSET: 0x0000 */ + u32 swport_dr_h; /* ADDRESS OFFSET: 0x0004 */ + u32 swport_ddr_l; /* ADDRESS OFFSET: 0x0008 */ + u32 swport_ddr_h; /* ADDRESS OFFSET: 0x000c */ + u32 int_en_l; /* ADDRESS OFFSET: 0x0010 */ + u32 int_en_h; /* ADDRESS OFFSET: 0x0014 */ + u32 int_mask_l; /* ADDRESS OFFSET: 0x0018 */ + u32 int_mask_h; /* ADDRESS OFFSET: 0x001c */ + u32 int_type_l; /* ADDRESS OFFSET: 0x0020 */ + u32 int_type_h; /* ADDRESS OFFSET: 0x0024 */ + u32 int_polarity_l; /* ADDRESS OFFSET: 0x0028 */ + u32 int_polarity_h; /* ADDRESS OFFSET: 0x002c */ + u32 int_bothedge_l; /* ADDRESS OFFSET: 0x0030 */ + u32 int_bothedge_h; /* ADDRESS OFFSET: 0x0034 */ + u32 debounce_l; /* ADDRESS OFFSET: 0x0038 */ + u32 debounce_h; /* ADDRESS OFFSET: 0x003c */ + u32 dbclk_div_en_l; /* ADDRESS OFFSET: 0x0040 */ + u32 dbclk_div_en_h; /* ADDRESS OFFSET: 0x0044 */ + u32 dbclk_div_con; /* ADDRESS OFFSET: 0x0048 */ + u32 reserved004c; /* ADDRESS OFFSET: 0x004c */ + u32 int_status; /* ADDRESS OFFSET: 0x0050 */ + u32 reserved0054; /* ADDRESS OFFSET: 0x0054 */ + u32 int_rawstatus; /* ADDRESS OFFSET: 0x0058 */ + u32 reserved005c; /* ADDRESS OFFSET: 0x005c */ + u32 port_eoi_l; /* ADDRESS OFFSET: 0x0060 */ + u32 port_eoi_h; /* ADDRESS OFFSET: 0x0064 */ + u32 reserved0068[2]; /* ADDRESS OFFSET: 0x0068 */ + u32 ext_port; /* ADDRESS OFFSET: 0x0070 */ + u32 reserved0074; /* ADDRESS OFFSET: 0x0074 */ + u32 ver_id; /* ADDRESS OFFSET: 0x0078 */ +}; +check_member(rockchip_gpio_regs, ver_id, 0x0078); +#endif #endif diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index ffeda9425a..e968e9edd4 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -144,6 +144,19 @@ config ROCKCHIP_GPIO The GPIOs for a device are defined in the device tree with one node for each bank. +config ROCKCHIP_GPIO_V2 + bool "Rockchip GPIO driver version 2.0" + depends on ROCKCHIP_GPIO + default n + help + Support GPIO access on Rockchip SoCs. The GPIOs are arranged into + a number of banks (different for each SoC type) each with 32 GPIOs. + The GPIOs for a device are defined in the device tree with one node + for each bank. + + Support version 2.0 GPIO controller, which support write enable bits + for some registers, such as dr, ddr. + config SANDBOX_GPIO bool "Enable sandbox GPIO driver" depends on SANDBOX && DM && DM_GPIO diff --git a/drivers/gpio/rk_gpio.c b/drivers/gpio/rk_gpio.c index eff0d2af63..c3f72c54e3 100644 --- a/drivers/gpio/rk_gpio.c +++ b/drivers/gpio/rk_gpio.c @@ -1,8 +1,9 @@ /* * (C) Copyright 2015 Google, Inc * - * (C) Copyright 2008-2014 Rockchip Electronics + * (C) Copyright 2008-2020 Rockchip Electronics * Peter, Software Engineering, . + * Jianqun Xu, Software Engineering, . * * SPDX-License-Identifier: GPL-2.0+ */ @@ -23,6 +24,30 @@ enum { #define OFFSET_TO_BIT(bit) (1UL << (bit)) +#ifdef CONFIG_ROCKCHIP_GPIO_V2 +#define REG_L(R) (R##_l) +#define REG_H(R) (R##_h) +#define READ_REG(REG) ((readl(REG_L(REG)) & 0xFFFF) | \ + ((readl(REG_H(REG)) & 0xFFFF) << 16)) +#define WRITE_REG(REG, VAL) \ +{\ + writel(((VAL) & 0xFFFF) | 0xFFFF0000, REG_L(REG)); \ + writel((((VAL) & 0xFFFF0000) >> 16) | 0xFFFF0000, REG_H(REG));\ +} +#define CLRBITS_LE32(REG, MASK) WRITE_REG(REG, READ_REG(REG) & ~(MASK)) +#define SETBITS_LE32(REG, MASK) WRITE_REG(REG, READ_REG(REG) | (MASK)) +#define CLRSETBITS_LE32(REG, MASK, VAL) WRITE_REG(REG, \ + (READ_REG(REG) & ~(MASK)) | (VAL)) + +#else +#define READ_REG(REG) readl(REG) +#define WRITE_REG(REG, VAL) writel(VAL, REG) +#define CLRBITS_LE32(REG, MASK) clrbits_le32(REG, MASK) +#define SETBITS_LE32(REG, MASK) setbits_le32(REG, MASK) +#define CLRSETBITS_LE32(REG, MASK, VAL) clrsetbits_le32(REG, MASK, VAL) +#endif + + struct rockchip_gpio_priv { struct rockchip_gpio_regs *regs; struct udevice *pinctrl; @@ -35,7 +60,7 @@ static int rockchip_gpio_direction_input(struct udevice *dev, unsigned offset) struct rockchip_gpio_priv *priv = dev_get_priv(dev); struct rockchip_gpio_regs *regs = priv->regs; - clrbits_le32(®s->swport_ddr, OFFSET_TO_BIT(offset)); + CLRBITS_LE32(®s->swport_ddr, OFFSET_TO_BIT(offset)); return 0; } @@ -47,8 +72,8 @@ static int rockchip_gpio_direction_output(struct udevice *dev, unsigned offset, struct rockchip_gpio_regs *regs = priv->regs; int mask = OFFSET_TO_BIT(offset); - clrsetbits_le32(®s->swport_dr, mask, value ? mask : 0); - setbits_le32(®s->swport_ddr, mask); + CLRSETBITS_LE32(®s->swport_dr, mask, value ? mask : 0); + SETBITS_LE32(®s->swport_ddr, mask); return 0; } @@ -68,7 +93,7 @@ static int rockchip_gpio_set_value(struct udevice *dev, unsigned offset, struct rockchip_gpio_regs *regs = priv->regs; int mask = OFFSET_TO_BIT(offset); - clrsetbits_le32(®s->swport_dr, mask, value ? mask : 0); + CLRSETBITS_LE32(®s->swport_dr, mask, value ? mask : 0); return 0; } @@ -90,7 +115,8 @@ static int rockchip_gpio_get_function(struct udevice *dev, unsigned offset) /* If it's not 0, then it is not a GPIO */ if (ret) return GPIOF_FUNC; - is_output = readl(®s->swport_ddr) & OFFSET_TO_BIT(offset); + + is_output = READ_REG(®s->swport_ddr) & OFFSET_TO_BIT(offset); return is_output ? GPIOF_OUTPUT : GPIOF_INPUT; #endif