czw., 14 lut 2019 o 22:30 Shravan Kumar Ramani
napisał(a):
>
> This patch adds support for the GPIO controller used by Mellanox
> BlueField SOCs.
>
> Reviewed-by: David Woods
> Signed-off-by: Shravan Kumar Ramani
> ---
> drivers/gpio/Kconfig | 7 ++
> drivers/gpio/Makefile | 1 +
> drivers/gpio/gpio-mlxbf.c | 287
> ++
> 3 files changed, 295 insertions(+)
> create mode 100644 drivers/gpio/gpio-mlxbf.c
>
> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> index b5a2845..2bebe92 100644
> --- a/drivers/gpio/Kconfig
> +++ b/drivers/gpio/Kconfig
> @@ -1292,6 +1292,13 @@ config GPIO_MERRIFIELD
> help
> Say Y here to support Intel Merrifield GPIO.
>
> +config GPIO_MLXBF
> + tristate "Mellanox BlueField SoC GPIO"
> + depends on (MELLANOX_PLATFORM && ARM64 && ACPI) || COMPILE_TEST
> + select GPIO_GENERIC
You're not really depending on it.
> + help
> + Say Y here if you want GPIO support on Mellanox BlueField SoC.
> +
> config GPIO_ML_IOH
> tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support"
> depends on X86 || COMPILE_TEST
> diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
> index 37628f8..8d54279 100644
> --- a/drivers/gpio/Makefile
> +++ b/drivers/gpio/Makefile
> @@ -83,6 +83,7 @@ obj-$(CONFIG_GPIO_MENZ127)+= gpio-menz127.o
> obj-$(CONFIG_GPIO_MERRIFIELD) += gpio-merrifield.o
> obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o
> obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o
> +obj-$(CONFIG_GPIO_MLXBF) += gpio-mlxbf.o
> obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o
> obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o
> obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o
> diff --git a/drivers/gpio/gpio-mlxbf.c b/drivers/gpio/gpio-mlxbf.c
> new file mode 100644
> index 000..e5c50db
> --- /dev/null
> +++ b/drivers/gpio/gpio-mlxbf.c
> @@ -0,0 +1,287 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include
> +
> +/* Number of pins on BlueField */
> +#define MLXBF_GPIO_NR 54
> +
> +/* Pad Electrical Controls. */
> +#define GPIO_PAD_CONTROL__FIRST_WORD 0x0700
> +#define GPIO_PAD_CONTROL_1__FIRST_WORD 0x0708
> +#define GPIO_PAD_CONTROL_2__FIRST_WORD 0x0710
> +#define GPIO_PAD_CONTROL_3__FIRST_WORD 0x0718
> +
> +#define GPIO_PIN_DIR_I 0x1040
> +#define GPIO_PIN_DIR_O 0x1048
> +#define GPIO_PIN_STATE 0x1000
> +#define GPIO_SCRATCHPAD 0x20
> +
> +#ifdef CONFIG_PM
> +struct bluefield_context_save_regs {
> + u64 gpio_scratchpad;
> + u64 gpio_pad_control[MLXBF_GPIO_NR];
> + u64 gpio_pin_dir_i;
> + u64 gpio_pin_dir_o;
> +};
> +#endif
> +
> +/* Device state structure. */
> +struct gpio_state {
> + struct list_head node;
Why do you need that? You're not using it anywhere AFAICT.
> + struct platform_device *pdev;
You're not using this either.
> +
> + struct gpio_chip gc;
> +
> + /* Must hold this lock to modify shared data. */
> + spinlock_t lock;
> +
> + /* Memory Address */
> + void __iomem *dc_base;
> +
> +#ifdef CONFIG_PM
> + struct bluefield_context_save_regs csave_regs;
> +#endif
> +};
> +
> +/* GPIO driver set input pins */
> +static int gpio_bf_set_input(struct gpio_chip *chip, unsigned int offset)
> +{
> + struct gpio_state *gs = gpiochip_get_data(chip);
> + u64 in;
> + u64 out;
> +
> + if (offset > MLXBF_GPIO_NR - 1) {
> + dev_err(chip->parent, "gpio input pins: Invalid offset %d\n",
> + offset);
> + return -EINVAL;
> + }
You don't need that, the subsystem makes sure this doesn't happen.
Same elsewhere.
> +
> + out = readq(gs->dc_base + GPIO_PIN_DIR_O);
> + in = readq(gs->dc_base + GPIO_PIN_DIR_I);
> +
> + writeq(out & ~BIT(offset), gs->dc_base + GPIO_PIN_DIR_O);
> + writeq(in | BIT(offset), gs->dc_base + GPIO_PIN_DIR_I);
> +
If you used the mmio regmap in this driver you could avoid both the
locking (regmap uses a spinlock if fast_io is set to true) and manual
bit updating here. You would do something like:
regmap_update_bits(map, gs->dc_base + GPIO_PIN_DIR_O, out &
BIT(offset), ~BIT(offset)).
> + return 0;
> +}
> +
> +/* GPIO driver set output pins */
> +static int gpio_bf_set_output(struct gpio_chip *chip, unsigned int offset)
> +{
> + struct gpio_state *gs = gpiochip_get_data(chip);
> + u64 in;
> + u64 out;
> +
> + if (offset > MLXBF_GPIO_NR - 1) {
> + dev_err(chip->parent, "gpio output pins: Invalid offset %d\n",
> + offset);
> + return -EINVAL;
> + }
> +
> + out = readq(gs->dc_base + GPIO_PIN_DIR_O);
> + in = readq(gs->dc_base + GPIO_PIN_DIR_I);
> +
> + writeq(out |