Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 3/4] pinctrl: add abx500 pinctrl driver core
From: Linus Walleij @ 2013-01-15  9:43 UTC (permalink / raw)
  To: linux-arm-kernel

From: Patrice Chotard <patrice.chotard@st.com>

This adds the AB8500 core driver, which will be utilized by
the follow-on drivers for different ABx500 variants.
Sselect the driver from the DBX500_SOC, as this chip is
powering and clocking that SoC.

Cc: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: Patrice Chotard <patrice.chotard@st.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
Hi Sam, it'd be great if you could ACK this so we could proceed
with rewriting the GPIO driver.
---
 arch/arm/mach-ux500/Kconfig            |    1 +
 arch/arm/mach-ux500/board-mop500.c     |   19 +-
 drivers/pinctrl/Kconfig                |    7 +
 drivers/pinctrl/Makefile               |    1 +
 drivers/pinctrl/pinctrl-abx500.c       | 1233 ++++++++++++++++++++++++++++++++
 drivers/pinctrl/pinctrl-abx500.h       |  229 ++++++
 include/linux/mfd/abx500/ab8500-gpio.h |   15 +-
 include/linux/mfd/abx500/ab8500.h      |    2 +-
 8 files changed, 1486 insertions(+), 21 deletions(-)
 create mode 100644 drivers/pinctrl/pinctrl-abx500.c
 create mode 100644 drivers/pinctrl/pinctrl-abx500.h

diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
index 5dea906..2c090d7 100644
--- a/arch/arm/mach-ux500/Kconfig
+++ b/arch/arm/mach-ux500/Kconfig
@@ -11,6 +11,7 @@ config UX500_SOC_COMMON
 	select COMMON_CLK
 	select PINCTRL
 	select PINCTRL_NOMADIK
+	select PINCTRL_ABX500
 	select PL310_ERRATA_753970 if CACHE_PL310
 
 config UX500_SOC_DB8500
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c
index d453522..b6f14ee 100644
--- a/arch/arm/mach-ux500/board-mop500.c
+++ b/arch/arm/mach-ux500/board-mop500.c
@@ -90,26 +90,9 @@ static struct platform_device snowball_gpio_en_3v3_regulator_dev = {
        },
 };
 
-static struct ab8500_gpio_platform_data ab8500_gpio_pdata = {
+static struct abx500_gpio_platform_data ab8500_gpio_pdata = {
 	.gpio_base		= MOP500_AB8500_PIN_GPIO(1),
 	.irq_base		= MOP500_AB8500_VIR_GPIO_IRQ_BASE,
-	/* config_reg is the initial configuration of ab8500 pins.
-	 * The pins can be configured as GPIO or alt functions based
-	 * on value present in GpioSel1 to GpioSel6 and AlternatFunction
-	 * register. This is the array of 7 configuration settings.
-	 * One has to compile time decide these settings. Below is the
-	 * explanation of these setting
-	 * GpioSel1 = 0x00 => Pins GPIO1 to GPIO8 are not used as GPIO
-	 * GpioSel2 = 0x1E => Pins GPIO10 to GPIO13 are configured as GPIO
-	 * GpioSel3 = 0x80 => Pin GPIO24 is configured as GPIO
-	 * GpioSel4 = 0x01 => Pin GPIo25 is configured as GPIO
-	 * GpioSel5 = 0x7A => Pins GPIO34, GPIO36 to GPIO39 are conf as GPIO
-	 * GpioSel6 = 0x00 => Pins GPIO41 & GPIo42 are not configured as GPIO
-	 * AlternaFunction = 0x00 => If Pins GPIO10 to 13 are not configured
-	 * as GPIO then this register selectes the alternate fucntions
-	 */
-	.config_reg		= {0x00, 0x1E, 0x80, 0x01,
-					0x7A, 0x00, 0x00},
 };
 
 /* ab8500-codec */
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index c31aeb0..ec819d8 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -26,6 +26,13 @@ config DEBUG_PINCTRL
 	help
 	  Say Y here to add some extra checks and diagnostics to PINCTRL calls.
 
+config PINCTRL_ABX500
+	bool "ST-Ericsson ABx500 family Mixed Signal Circuit gpio functions"
+	depends on AB8500_CORE
+	select GENERIC_PINCONF
+	help
+	  Select this to enable the ABx500 family IC GPIO driver
+
 config PINCTRL_AT91
 	bool "AT91 pinctrl driver"
 	depends on OF
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index fc4606f..d10bf87 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -9,6 +9,7 @@ ifeq ($(CONFIG_OF),y)
 obj-$(CONFIG_PINCTRL)		+= devicetree.o
 endif
 obj-$(CONFIG_GENERIC_PINCONF)	+= pinconf-generic.o
+obj-$(CONFIG_PINCTRL_ABX500)	+= pinctrl-abx500.o
 obj-$(CONFIG_PINCTRL_AT91)	+= pinctrl-at91.o
 obj-$(CONFIG_PINCTRL_BCM2835)	+= pinctrl-bcm2835.o
 obj-$(CONFIG_PINCTRL_IMX)	+= pinctrl-imx.o
diff --git a/drivers/pinctrl/pinctrl-abx500.c b/drivers/pinctrl/pinctrl-abx500.c
new file mode 100644
index 0000000..ac89e10
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-abx500.c
@@ -0,0 +1,1233 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2013
+ *
+ * Author: Patrice Chotard <patrice.chotard@st.com>
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500/ab8500-gpio.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+
+#include "pinctrl-abx500.h"
+
+/*
+ * The AB9540 and AB8540 GPIO support are extended versions
+ * of the AB8500 GPIO support.
+ * The AB9540 supports an additional (7th) register so that
+ * more GPIO may be configured and used.
+ * The AB8540 supports 4 new gpios (GPIOx_VBAT) that have
+ * internal pull-up and pull-down capabilities.
+ */
+
+/*
+ * GPIO registers offset
+ * Bank: 0x10
+ */
+#define AB8500_GPIO_SEL1_REG	0x00
+#define AB8500_GPIO_SEL2_REG	0x01
+#define AB8500_GPIO_SEL3_REG	0x02
+#define AB8500_GPIO_SEL4_REG	0x03
+#define AB8500_GPIO_SEL5_REG	0x04
+#define AB8500_GPIO_SEL6_REG	0x05
+#define AB9540_GPIO_SEL7_REG	0x06
+
+#define AB8500_GPIO_DIR1_REG	0x10
+#define AB8500_GPIO_DIR2_REG	0x11
+#define AB8500_GPIO_DIR3_REG	0x12
+#define AB8500_GPIO_DIR4_REG	0x13
+#define AB8500_GPIO_DIR5_REG	0x14
+#define AB8500_GPIO_DIR6_REG	0x15
+#define AB9540_GPIO_DIR7_REG	0x16
+
+#define AB8500_GPIO_OUT1_REG	0x20
+#define AB8500_GPIO_OUT2_REG	0x21
+#define AB8500_GPIO_OUT3_REG	0x22
+#define AB8500_GPIO_OUT4_REG	0x23
+#define AB8500_GPIO_OUT5_REG	0x24
+#define AB8500_GPIO_OUT6_REG	0x25
+#define AB9540_GPIO_OUT7_REG	0x26
+
+#define AB8500_GPIO_PUD1_REG	0x30
+#define AB8500_GPIO_PUD2_REG	0x31
+#define AB8500_GPIO_PUD3_REG	0x32
+#define AB8500_GPIO_PUD4_REG	0x33
+#define AB8500_GPIO_PUD5_REG	0x34
+#define AB8500_GPIO_PUD6_REG	0x35
+#define AB9540_GPIO_PUD7_REG	0x36
+
+#define AB8500_GPIO_IN1_REG	0x40
+#define AB8500_GPIO_IN2_REG	0x41
+#define AB8500_GPIO_IN3_REG	0x42
+#define AB8500_GPIO_IN4_REG	0x43
+#define AB8500_GPIO_IN5_REG	0x44
+#define AB8500_GPIO_IN6_REG	0x45
+#define AB9540_GPIO_IN7_REG	0x46
+#define AB8540_GPIO_VINSEL_REG	0x47
+#define AB8540_GPIO_PULL_UPDOWN_REG	0x48
+#define AB8500_GPIO_ALTFUN_REG	0x50
+#define AB8500_NUM_VIR_GPIO_IRQ	16
+#define AB8540_GPIO_PULL_UPDOWN_MASK	0x03
+#define AB8540_GPIO_VINSEL_MASK	0x03
+#define AB8540_GPIOX_VBAT_START	51
+#define AB8540_GPIOX_VBAT_END	54
+
+enum abx500_gpio_action {
+	NONE,
+	STARTUP,
+	SHUTDOWN,
+	MASK,
+	UNMASK
+};
+
+struct abx500_pinctrl {
+	struct device *dev;
+	struct pinctrl_dev *pctldev;
+	struct abx500_pinctrl_soc_data *soc;
+	struct gpio_chip chip;
+	struct ab8500 *parent;
+	struct mutex lock;
+	u32 irq_base;
+	enum abx500_gpio_action irq_action;
+	u16 rising;
+	u16 falling;
+	struct abx500_gpio_irq_cluster *irq_cluster;
+	int irq_cluster_size;
+	int irq_gpio_rising_offset;
+	int irq_gpio_falling_offset;
+	int irq_gpio_factor;
+};
+
+/**
+ * to_abx500_pinctrl() - get the pointer to abx500_pinctrl
+ * @chip:	Member of the structure abx500_pinctrl
+ */
+static inline struct abx500_pinctrl *to_abx500_pinctrl(struct gpio_chip *chip)
+{
+	return container_of(chip, struct abx500_pinctrl, chip);
+}
+
+static int abx500_gpio_get_bit(struct gpio_chip *chip, u8 reg,
+					unsigned offset, bool *bit)
+{
+	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	u8 pos = offset % 8;
+	u8 val;
+	int ret;
+
+	reg += offset / 8;
+	ret = abx500_get_register_interruptible(pct->dev,
+						AB8500_MISC, reg, &val);
+
+	*bit = !!(val & BIT(pos));
+
+	if (ret < 0)
+		dev_err(pct->dev,
+			"%s read reg =%x, offset=%x failed\n",
+			__func__, reg, offset);
+
+	return ret;
+}
+
+static int abx500_gpio_set_bits(struct gpio_chip *chip, u8 reg,
+					unsigned offset, int val)
+{
+	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	u8 pos = offset % 8;
+	int ret;
+
+	reg += offset / 8;
+	ret = abx500_mask_and_set_register_interruptible(pct->dev,
+				AB8500_MISC, reg, 1 << pos, val << pos);
+	if (ret < 0)
+		dev_err(pct->dev, "%s write failed\n", __func__);
+	return ret;
+}
+/**
+ * abx500_gpio_get() - Get the particular GPIO value
+ * @chip: Gpio device
+ * @offset: GPIO number to read
+ */
+static int abx500_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	u8 mask = 1 << (offset % 8);
+	u8 reg = AB8500_GPIO_IN1_REG + (offset / 8);
+	int ret;
+	u8 data;
+	ret = abx500_get_register_interruptible(pct->dev, AB8500_MISC,
+						reg, &data);
+	if (ret < 0) {
+		dev_err(pct->dev, "%s read failed\n", __func__);
+		return ret;
+	}
+	return (data & mask) >> (offset % 8);
+}
+
+static void abx500_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+{
+	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	int ret;
+	/* Write the data */
+	ret = abx500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val);
+	if (ret < 0)
+		dev_err(pct->dev, "%s write failed\n", __func__);
+}
+
+static int abx500_config_pull_updown(struct abx500_pinctrl *pct,
+				int offset, enum abx500_gpio_pull_updown val)
+{
+	u8 pos;
+	int ret;
+	struct pullud *pullud;
+
+	if (!pct->soc->pullud) {
+		dev_err(pct->dev, "%s AB chip doesn't support pull up/down feature",
+				__func__);
+		ret = -EPERM;
+		goto out;
+	}
+
+	pullud = pct->soc->pullud;
+
+	if ((offset < pullud->first_pin)
+		|| (offset > pullud->last_pin)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	pos = offset << 1;
+
+	ret = abx500_mask_and_set_register_interruptible(pct->dev,
+			AB8500_MISC, AB8540_GPIO_PULL_UPDOWN_REG,
+			AB8540_GPIO_PULL_UPDOWN_MASK << pos, val << pos);
+
+out:
+	if (ret < 0)
+		dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
+	return ret;
+}
+
+static int abx500_gpio_direction_output(struct gpio_chip *chip,
+					unsigned offset,
+					int val)
+{
+	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	struct pullud *pullud = pct->soc->pullud;
+	unsigned gpio;
+	int ret;
+	/* set direction as output */
+	ret = abx500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 1);
+	if (ret < 0)
+		return ret;
+
+	/* disable pull down */
+	ret = abx500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG, offset, 1);
+	if (ret < 0)
+		return ret;
+
+	/* if supported, disable both pull down and pull up */
+	gpio = offset + 1;
+	if (pullud && gpio >= pullud->first_pin && gpio <= pullud->last_pin) {
+		ret = abx500_config_pull_updown(pct,
+				offset,
+				ABX500_GPIO_PULL_NONE);
+		if (ret < 0)
+			return ret;
+	}
+	/* set the output as 1 or 0 */
+	return abx500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val);
+}
+
+static int abx500_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+	/* set the register as input */
+	return abx500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 0);
+}
+
+static int abx500_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	int base = pct->irq_base;
+	int i;
+
+	for (i = 0; i < pct->irq_cluster_size; i++) {
+		struct abx500_gpio_irq_cluster *cluster =
+			&pct->irq_cluster[i];
+
+		if (offset >= cluster->start && offset <= cluster->end)
+			return base + offset - cluster->start;
+
+		/* Advance by the number of gpios in this cluster */
+		base += cluster->end + cluster->offset - cluster->start + 1;
+	}
+
+	return -EINVAL;
+}
+
+static int abx500_set_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
+		unsigned gpio, int alt_setting)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+	struct alternate_functions af = pct->soc->alternate_functions[gpio];
+	int ret;
+	int val;
+	unsigned offset;
+	const char *modes[] = {
+		[ABX500_DEFAULT]	= "default",
+		[ABX500_ALT_A]		= "altA",
+		[ABX500_ALT_B]		= "altB",
+		[ABX500_ALT_C]		= "altC",
+	};
+
+	/* sanity check */
+	if (((alt_setting == ABX500_ALT_A) && (af.gpiosel_bit == UNUSED)) ||
+	    ((alt_setting == ABX500_ALT_B) && (af.alt_bit1 == UNUSED)) ||
+	    ((alt_setting == ABX500_ALT_C) && (af.alt_bit2 == UNUSED))) {
+		dev_dbg(pct->dev, "pin %d doesn't support %s mode\n", gpio,
+				modes[alt_setting]);
+		return -EINVAL;
+	}
+
+	/* on ABx5xx, there is no GPIO0, so adjust the offset */
+	offset = gpio - 1;
+	switch (alt_setting) {
+	case ABX500_DEFAULT:
+		/*
+		 * for ABx5xx family, default mode is always selected by
+		 * writing 0 to GPIOSELx register, except for pins which
+		 * support at least ALT_B mode, default mode is selected
+		 * by writing 1 to GPIOSELx register
+		 */
+		val = 0;
+		if (af.alt_bit1 != UNUSED)
+			val++;
+
+		ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
+					   offset, val);
+		break;
+	case ABX500_ALT_A:
+		/*
+		 * for ABx5xx family, alt_a mode is always selected by
+		 * writing 1 to GPIOSELx register, except for pins which
+		 * support at least ALT_B mode, alt_a mode is selected
+		 * by writing 0 to GPIOSELx register and 0 in ALTFUNC
+		 * register
+		 */
+		if (af.alt_bit1 != UNUSED) {
+			ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
+					offset, 0);
+			ret = abx500_gpio_set_bits(chip,
+					AB8500_GPIO_ALTFUN_REG,
+					af.alt_bit1,
+					!!(af.alta_val && BIT(0)));
+			if (af.alt_bit2 != UNUSED)
+				ret = abx500_gpio_set_bits(chip,
+					AB8500_GPIO_ALTFUN_REG,
+					af.alt_bit2,
+					!!(af.alta_val && BIT(1)));
+		} else
+			ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
+					offset, 1);
+		break;
+	case ABX500_ALT_B:
+		ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
+				offset, 0);
+		ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
+				af.alt_bit1, !!(af.altb_val && BIT(0)));
+		if (af.alt_bit2 != UNUSED)
+			ret = abx500_gpio_set_bits(chip,
+					AB8500_GPIO_ALTFUN_REG,
+					af.alt_bit2,
+					!!(af.altb_val && BIT(1)));
+		break;
+	case ABX500_ALT_C:
+		ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
+				offset, 0);
+		ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
+				af.alt_bit2, !!(af.altc_val && BIT(0)));
+		ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
+				af.alt_bit2, !!(af.altc_val && BIT(1)));
+		break;
+
+	default:
+		dev_dbg(pct->dev, "unknow alt_setting %d\n", alt_setting);
+		return -EINVAL;
+	}
+	return ret;
+}
+
+static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
+		unsigned gpio)
+{
+	u8 mode;
+	bool bit_mode;
+	bool alt_bit1;
+	bool alt_bit2;
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+	struct alternate_functions af = pct->soc->alternate_functions[gpio];
+
+	/*
+	 * if gpiosel_bit is set to unused,
+	 * it means no GPIO or special case
+	 */
+	if (af.gpiosel_bit == UNUSED)
+		return ABX500_DEFAULT;
+
+	/* read GpioSelx register */
+	abx500_gpio_get_bit(chip, AB8500_GPIO_SEL1_REG + (gpio / 8),
+			af.gpiosel_bit, &bit_mode);
+	mode = bit_mode;
+
+	/* sanity check */
+	if ((af.alt_bit1 < UNUSED) || (af.alt_bit1 > 7) ||
+	    (af.alt_bit2 < UNUSED) || (af.alt_bit2 > 7)) {
+		dev_err(pct->dev,
+			"alt_bitX value not in correct range (-1 to 7)\n");
+		return -EINVAL;
+	}
+	/* if alt_bit2 is used, alt_bit1 must be used too */
+	if ((af.alt_bit2 != UNUSED) && (af.alt_bit1 == UNUSED)) {
+		dev_err(pct->dev,
+			"if alt_bit2 is used, alt_bit1 can't be unused\n");
+		return -EINVAL;
+	}
+
+	/* check if pin use AlternateFunction register */
+	if ((af.alt_bit1 == UNUSED) && (af.alt_bit1 == UNUSED))
+		return mode;
+	/*
+	 * if pin GPIOSEL bit is set and pin supports alternate function,
+	 * it means DEFAULT mode
+	 */
+	if (mode)
+		return ABX500_DEFAULT;
+	/*
+	 * pin use the AlternatFunction register
+	 * read alt_bit1 value
+	 */
+	abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG,
+			    af.alt_bit1, &alt_bit1);
+
+	if (af.alt_bit2 != UNUSED)
+		/* read alt_bit2 value */
+		abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG, af.alt_bit2,
+				&alt_bit2);
+	else
+		alt_bit2 = 0;
+
+	mode = (alt_bit2 << 1) + alt_bit1;
+	if (mode == af.alta_val)
+		return ABX500_ALT_A;
+	else if (mode == af.altb_val)
+		return ABX500_ALT_B;
+	else
+		return ABX500_ALT_C;
+}
+
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/seq_file.h>
+
+static void abx500_gpio_dbg_show_one(struct seq_file *s,
+	struct pinctrl_dev *pctldev, struct gpio_chip *chip,
+	unsigned offset, unsigned gpio)
+{
+	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	const char *label = gpiochip_is_requested(chip, offset - 1);
+	u8 gpio_offset = offset - 1;
+	int mode = -1;
+	bool is_out;
+	bool pull;
+	const char *modes[] = {
+		[ABX500_DEFAULT]	= "default",
+		[ABX500_ALT_A]		= "altA",
+		[ABX500_ALT_B]		= "altB",
+		[ABX500_ALT_C]		= "altC",
+	};
+
+	abx500_gpio_get_bit(chip, AB8500_GPIO_DIR1_REG, gpio_offset, &is_out);
+	abx500_gpio_get_bit(chip, AB8500_GPIO_PUD1_REG, gpio_offset, &pull);
+
+	if (pctldev)
+		mode = abx500_get_mode(pctldev, chip, offset);
+
+	seq_printf(s, " gpio-%-3d (%-20.20s) %-3s %-9s %s",
+		   gpio, label ?: "(none)",
+		   is_out ? "out" : "in ",
+		   is_out ?
+		   (chip->get
+		   ? (chip->get(chip, offset) ? "hi" : "lo")
+		   : "?  ")
+		   : (pull ? "pull up" : "pull down"),
+		   (mode < 0) ? "unknown" : modes[mode]);
+
+	if (label && !is_out) {
+		int irq = gpio_to_irq(gpio);
+		struct irq_desc	*desc = irq_to_desc(irq);
+
+		if (irq >= 0 && desc->action) {
+			char *trigger;
+			int irq_offset = irq - pct->irq_base;
+
+			if (pct->rising & BIT(irq_offset))
+				trigger = "edge-rising";
+			else if (pct->falling & BIT(irq_offset))
+				trigger = "edge-falling";
+			else
+				trigger = "edge-undefined";
+
+			seq_printf(s, " irq-%d %s", irq, trigger);
+		}
+	}
+}
+
+static void abx500_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+	unsigned i;
+	unsigned gpio = chip->base;
+	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	struct pinctrl_dev *pctldev = pct->pctldev;
+
+	for (i = 0; i < chip->ngpio; i++, gpio++) {
+		/* On AB8500, there is no GPIO0, the first is the GPIO 1 */
+		abx500_gpio_dbg_show_one(s, pctldev, chip, i + 1, gpio);
+		seq_printf(s, "\n");
+	}
+}
+
+#else
+static inline void abx500_gpio_dbg_show_one(struct seq_file *s,
+					 struct pinctrl_dev *pctldev,
+					 struct gpio_chip *chip,
+					 unsigned offset, unsigned gpio)
+{
+}
+#define abx500_gpio_dbg_show	NULL
+#endif
+
+int abx500_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+	int gpio = chip->base + offset;
+
+	return pinctrl_request_gpio(gpio);
+}
+
+void abx500_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+	int gpio = chip->base + offset;
+
+	pinctrl_free_gpio(gpio);
+}
+
+static struct gpio_chip abx500gpio_chip = {
+	.label			= "abx500-gpio",
+	.owner			= THIS_MODULE,
+	.request		= abx500_gpio_request,
+	.free			= abx500_gpio_free,
+	.direction_input	= abx500_gpio_direction_input,
+	.get			= abx500_gpio_get,
+	.direction_output	= abx500_gpio_direction_output,
+	.set			= abx500_gpio_set,
+	.to_irq			= abx500_gpio_to_irq,
+	.dbg_show		= abx500_gpio_dbg_show,
+};
+
+static unsigned int irq_to_rising(unsigned int irq)
+{
+	struct abx500_pinctrl *pct = irq_get_chip_data(irq);
+	int offset = irq - pct->irq_base;
+	int new_irq;
+
+	new_irq = offset * pct->irq_gpio_factor
+		+ pct->irq_gpio_rising_offset
+		+ pct->parent->irq_base;
+
+	return new_irq;
+}
+
+static unsigned int irq_to_falling(unsigned int irq)
+{
+	struct abx500_pinctrl *pct = irq_get_chip_data(irq);
+	int offset = irq - pct->irq_base;
+	int new_irq;
+
+	new_irq = offset * pct->irq_gpio_factor
+		+ pct->irq_gpio_falling_offset
+		+ pct->parent->irq_base;
+	return new_irq;
+
+}
+
+static unsigned int rising_to_irq(unsigned int irq, void *dev)
+{
+	struct abx500_pinctrl *pct = dev;
+	int offset, new_irq;
+
+	offset = irq - pct->irq_gpio_rising_offset
+		- pct->parent->irq_base;
+	new_irq = (offset / pct->irq_gpio_factor)
+		+ pct->irq_base;
+
+	return new_irq;
+}
+
+static unsigned int falling_to_irq(unsigned int irq, void *dev)
+{
+	struct abx500_pinctrl *pct = dev;
+	int offset, new_irq;
+
+	offset = irq - pct->irq_gpio_falling_offset
+		- pct->parent->irq_base;
+	new_irq = (offset / pct->irq_gpio_factor)
+		+ pct->irq_base;
+
+	return new_irq;
+}
+
+/*
+ * IRQ handler
+ */
+
+static irqreturn_t handle_rising(int irq, void *dev)
+{
+
+	handle_nested_irq(rising_to_irq(irq , dev));
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t handle_falling(int irq, void *dev)
+{
+
+	handle_nested_irq(falling_to_irq(irq, dev));
+	return IRQ_HANDLED;
+}
+
+static void abx500_gpio_irq_lock(struct irq_data *data)
+{
+	struct abx500_pinctrl *pct = irq_data_get_irq_chip_data(data);
+	mutex_lock(&pct->lock);
+}
+
+static void abx500_gpio_irq_sync_unlock(struct irq_data *data)
+{
+	struct abx500_pinctrl *pct = irq_data_get_irq_chip_data(data);
+	unsigned int irq = data->irq;
+	int offset = irq - pct->irq_base;
+	bool rising = pct->rising & BIT(offset);
+	bool falling = pct->falling & BIT(offset);
+	int ret;
+
+	switch (pct->irq_action)	{
+	case STARTUP:
+		if (rising)
+			ret = request_threaded_irq(irq_to_rising(irq),
+					NULL, handle_rising,
+					IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND,
+					"abx500-gpio-r", pct);
+		if (falling)
+			ret = request_threaded_irq(irq_to_falling(irq),
+				       NULL, handle_falling,
+				       IRQF_TRIGGER_FALLING | IRQF_NO_SUSPEND,
+				       "abx500-gpio-f", pct);
+		break;
+	case SHUTDOWN:
+		if (rising)
+			free_irq(irq_to_rising(irq), pct);
+		if (falling)
+			free_irq(irq_to_falling(irq), pct);
+		break;
+	case MASK:
+		if (rising)
+			disable_irq(irq_to_rising(irq));
+		if (falling)
+			disable_irq(irq_to_falling(irq));
+		break;
+	case UNMASK:
+		if (rising)
+			enable_irq(irq_to_rising(irq));
+		if (falling)
+			enable_irq(irq_to_falling(irq));
+		break;
+	case NONE:
+		break;
+	}
+	pct->irq_action = NONE;
+	pct->rising &= ~(BIT(offset));
+	pct->falling &= ~(BIT(offset));
+	mutex_unlock(&pct->lock);
+}
+
+
+static void abx500_gpio_irq_mask(struct irq_data *data)
+{
+	struct abx500_pinctrl *pct = irq_data_get_irq_chip_data(data);
+	pct->irq_action = MASK;
+}
+
+static void abx500_gpio_irq_unmask(struct irq_data *data)
+{
+	struct abx500_pinctrl *pct =  irq_data_get_irq_chip_data(data);
+	pct->irq_action = UNMASK;
+}
+
+static int abx500_gpio_irq_set_type(struct irq_data *data, unsigned int type)
+{
+	struct abx500_pinctrl *pct = irq_data_get_irq_chip_data(data);
+	unsigned int irq = data->irq;
+	int offset = irq - pct->irq_base;
+
+	if (type == IRQ_TYPE_EDGE_BOTH) {
+		pct->rising =  BIT(offset);
+		pct->falling = BIT(offset);
+	} else if (type == IRQ_TYPE_EDGE_RISING) {
+		pct->rising =  BIT(offset);
+	} else  {
+		pct->falling = BIT(offset);
+	}
+	return 0;
+}
+
+static unsigned int abx500_gpio_irq_startup(struct irq_data *data)
+{
+	struct abx500_pinctrl *pct = irq_data_get_irq_chip_data(data);
+	pct->irq_action = STARTUP;
+	return 0;
+}
+
+static void abx500_gpio_irq_shutdown(struct irq_data *data)
+{
+	struct abx500_pinctrl *pct = irq_data_get_irq_chip_data(data);
+	pct->irq_action = SHUTDOWN;
+}
+
+static struct irq_chip abx500_gpio_irq_chip = {
+	.name			= "abx500-gpio",
+	.irq_startup		= abx500_gpio_irq_startup,
+	.irq_shutdown		= abx500_gpio_irq_shutdown,
+	.irq_bus_lock		= abx500_gpio_irq_lock,
+	.irq_bus_sync_unlock	= abx500_gpio_irq_sync_unlock,
+	.irq_mask		= abx500_gpio_irq_mask,
+	.irq_unmask		= abx500_gpio_irq_unmask,
+	.irq_set_type		= abx500_gpio_irq_set_type,
+};
+
+static int abx500_gpio_irq_init(struct abx500_pinctrl *pct)
+{
+	u32 base = pct->irq_base;
+	int irq;
+
+	for (irq = base; irq < base + AB8500_NUM_VIR_GPIO_IRQ ; irq++) {
+		irq_set_chip_data(irq, pct);
+		irq_set_chip_and_handler(irq, &abx500_gpio_irq_chip,
+				handle_simple_irq);
+		irq_set_nested_thread(irq, 1);
+#ifdef CONFIG_ARM
+		set_irq_flags(irq, IRQF_VALID);
+#else
+		irq_set_noprobe(irq);
+#endif
+	}
+
+	return 0;
+}
+
+static void abx500_gpio_irq_remove(struct abx500_pinctrl *pct)
+{
+	int base = pct->irq_base;
+	int irq;
+
+	for (irq = base; irq < base + AB8500_NUM_VIR_GPIO_IRQ; irq++) {
+#ifdef CONFIG_ARM
+		set_irq_flags(irq, 0);
+#endif
+		irq_set_chip_and_handler(irq, NULL, NULL);
+		irq_set_chip_data(irq, NULL);
+	}
+}
+
+static int abx500_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+
+	return pct->soc->nfunctions;
+}
+
+static const char *abx500_pmx_get_func_name(struct pinctrl_dev *pctldev,
+					 unsigned function)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+
+	return pct->soc->functions[function].name;
+}
+
+static int abx500_pmx_get_func_groups(struct pinctrl_dev *pctldev,
+				   unsigned function,
+				   const char * const **groups,
+				   unsigned * const num_groups)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+
+	*groups = pct->soc->functions[function].groups;
+	*num_groups = pct->soc->functions[function].ngroups;
+
+	return 0;
+}
+
+static void abx500_disable_lazy_irq(struct gpio_chip *chip, unsigned gpio)
+{
+	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	int irq;
+	int offset;
+	bool rising;
+	bool falling;
+
+	/*
+	 * check if gpio has interrupt capability and convert
+	 * gpio number to irq
+	 * On ABx5xx, there is no GPIO0, GPIO1 is the
+	 * first one, so adjust gpio number
+	 */
+	gpio--;
+	irq =  gpio_to_irq(gpio + chip->base);
+	if (irq < 0)
+		return;
+
+	offset = irq - pct->irq_base;
+	rising = pct->rising & BIT(offset);
+	falling = pct->falling & BIT(offset);
+
+	/* nothing to do ?*/
+	if (!rising && !falling)
+		return;
+
+	if (rising) {
+		disable_irq(irq_to_rising(irq));
+		free_irq(irq_to_rising(irq), pct);
+	}
+	if (falling) {
+		disable_irq(irq_to_falling(irq));
+		free_irq(irq_to_falling(irq), pct);
+	}
+}
+
+static int abx500_pmx_enable(struct pinctrl_dev *pctldev, unsigned function,
+			  unsigned group)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+	struct gpio_chip *chip = &pct->chip;
+	const struct abx500_pingroup *g;
+	int i;
+	int ret = 0;
+
+	g = &pct->soc->groups[group];
+	if (g->altsetting < 0)
+		return -EINVAL;
+
+	dev_dbg(pct->dev, "enable group %s, %u pins\n", g->name, g->npins);
+
+	for (i = 0; i < g->npins; i++) {
+		dev_dbg(pct->dev, "setting pin %d to altsetting %d\n",
+			g->pins[i], g->altsetting);
+
+		abx500_disable_lazy_irq(chip, g->pins[i]);
+		ret = abx500_set_mode(pctldev, chip, g->pins[i], g->altsetting);
+	}
+	return ret;
+}
+
+static void abx500_pmx_disable(struct pinctrl_dev *pctldev,
+			    unsigned function, unsigned group)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+	const struct abx500_pingroup *g;
+
+	g = &pct->soc->groups[group];
+	if (g->altsetting < 0)
+		return;
+
+	/* Poke out the mux, set the pin to some default state? */
+	dev_dbg(pct->dev, "disable group %s, %u pins\n", g->name, g->npins);
+}
+
+int abx500_gpio_request_enable(struct pinctrl_dev *pctldev,
+			    struct pinctrl_gpio_range *range,
+			    unsigned offset)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+	u8 reg = AB8500_GPIO_SEL1_REG + (offset / 8);
+	u8 pos = offset % 8;
+	int ret;
+
+	if (!range) {
+		dev_err(pct->dev, "invalid range\n");
+		return -EINVAL;
+	}
+	if (!range->gc) {
+		dev_err(pct->dev, "missing GPIO chip in range\n");
+		return -EINVAL;
+	}
+	dev_dbg(pct->dev, "enable pin %u as GPIO\n", offset);
+
+	/*
+	 * by default, for ABx5xx family, GPIO mode is selected by
+	 * writing 1 in GPIOSELx registers
+	 */
+	ret = abx500_mask_and_set_register_interruptible(pct->dev,
+		AB8500_MISC, reg, 1 << pos, 1 << pos);
+
+	if (ret < 0) {
+		dev_err(pct->dev, "%s write failed\n", __func__);
+		return ret;
+	}
+	return ret;
+}
+
+static void abx500_gpio_disable_free(struct pinctrl_dev *pctldev,
+			   struct pinctrl_gpio_range *range,
+			   unsigned offset)
+{
+}
+
+static struct pinmux_ops abx500_pinmux_ops = {
+	.get_functions_count = abx500_pmx_get_funcs_cnt,
+	.get_function_name = abx500_pmx_get_func_name,
+	.get_function_groups = abx500_pmx_get_func_groups,
+	.enable = abx500_pmx_enable,
+	.disable = abx500_pmx_disable,
+	.gpio_request_enable = abx500_gpio_request_enable,
+	.gpio_disable_free = abx500_gpio_disable_free,
+};
+
+static int abx500_get_groups_cnt(struct pinctrl_dev *pctldev)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+
+	return pct->soc->ngroups;
+}
+
+static const char *abx500_get_group_name(struct pinctrl_dev *pctldev,
+				       unsigned selector)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+
+	return pct->soc->groups[selector].name;
+}
+
+static int abx500_get_group_pins(struct pinctrl_dev *pctldev,
+		unsigned selector,
+		const unsigned **pins,
+		unsigned *num_pins)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+
+	*pins = pct->soc->groups[selector].pins;
+	*num_pins = pct->soc->groups[selector].npins;
+	return 0;
+}
+
+static void abx500_pin_dbg_show(struct pinctrl_dev *pctldev,
+		struct seq_file *s, unsigned offset)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+	struct gpio_chip *chip = &pct->chip;
+
+	abx500_gpio_dbg_show_one(s, pctldev, chip, offset,
+				 chip->base + offset - 1);
+}
+
+static struct pinctrl_ops abx500_pinctrl_ops = {
+	.get_groups_count = abx500_get_groups_cnt,
+	.get_group_name = abx500_get_group_name,
+	.get_group_pins = abx500_get_group_pins,
+	.pin_dbg_show = abx500_pin_dbg_show,
+};
+
+int abx500_pin_config_get(struct pinctrl_dev *pctldev,
+		       unsigned pin,
+		       unsigned long *config)
+{
+	/* Not implemented */
+	return -EINVAL;
+}
+
+int abx500_pin_config_set(struct pinctrl_dev *pctldev,
+		       unsigned pin,
+		       unsigned long config)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+	struct pullud *pullud = pct->soc->pullud;
+	struct gpio_chip *chip = &pct->chip;
+	unsigned offset;
+	int ret;
+	enum pin_config_param param = pinconf_to_config_param(config);
+	enum pin_config_param argument = pinconf_to_config_argument(config);
+
+	dev_dbg(chip->dev, "pin %d [%#lx]: %s %s\n",
+		pin, config, (param == PIN_CONFIG_OUTPUT) ? "output " : "input",
+		(param == PIN_CONFIG_OUTPUT) ? (argument ? "high" : "low") :
+		(argument ? "pull up" : "pull down"));
+	/* on ABx500, there is no GPIO0, so adjust the offset */
+	offset = pin - 1;
+
+	switch (param) {
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		/*
+		 * if argument = 1 set the pull down
+		 * else clear the pull down
+		 */
+		ret = abx500_gpio_direction_input(chip, offset);
+		/* check if pin supports pull updown feature */
+		if (pullud && pin >= pullud->first_pin	&& pin <= pullud->last_pin)
+			ret = abx500_config_pull_updown(pct,
+				offset,
+				argument ? ABX500_GPIO_PULL_DOWN : ABX500_GPIO_PULL_NONE);
+		else
+			ret = abx500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG,
+				offset, argument ? 0 : 1);
+	break;
+	case PIN_CONFIG_OUTPUT:
+		ret = abx500_gpio_direction_output(chip, offset, argument);
+	break;
+	default:
+		dev_err(chip->dev, "illegal configuration requested\n");
+		return -EINVAL;
+	}
+	return ret;
+}
+
+static struct pinconf_ops abx500_pinconf_ops = {
+	.pin_config_get = abx500_pin_config_get,
+	.pin_config_set = abx500_pin_config_set,
+};
+
+static struct pinctrl_desc abx500_pinctrl_desc = {
+	.name = "pinctrl-abx500",
+	.pctlops = &abx500_pinctrl_ops,
+	.pmxops = &abx500_pinmux_ops,
+	.confops = &abx500_pinconf_ops,
+	.owner = THIS_MODULE,
+};
+
+static int abx500_get_gpio_num(struct abx500_pinctrl_soc_data *soc)
+{
+	unsigned int lowest = 0;
+	unsigned int highest = 0;
+	unsigned int npins = 0;
+	int i;
+
+	/*
+	 * Compute number of GPIOs from the last SoC gpio range descriptors
+	 * These ranges may include "holes" but the GPIO number space shall
+	 * still be homogeneous, so we need to detect and account for any
+	 * such holes so that these are included in the number of GPIO pins.
+	 */
+	for (i = 0; i < soc->gpio_num_ranges; i++) {
+		unsigned gstart;
+		unsigned gend;
+		const struct abx500_pinrange *p;
+
+		p = &soc->gpio_ranges[i];
+		gstart = p->offset;
+		gend = p->offset + p->npins - 1;
+
+		if (i == 0) {
+			/* First iteration, set start values */
+			lowest = gstart;
+			highest = gend;
+		} else {
+			if (gstart < lowest)
+				lowest = gstart;
+			if (gend > highest)
+				highest = gend;
+		}
+	}
+	/* this gives the absolute number of pins */
+	npins = highest - lowest + 1;
+	return npins;
+}
+
+static int __devinit abx500_gpio_probe(struct platform_device *pdev)
+{
+	struct ab8500_platform_data *abx500_pdata =
+				dev_get_platdata(pdev->dev.parent);
+	struct abx500_gpio_platform_data *pdata;
+	struct abx500_pinctrl *pct;
+	const struct platform_device_id *platid = platform_get_device_id(pdev);
+	int ret;
+	int i;
+
+	pdata = abx500_pdata->gpio;
+	if (!pdata)	{
+		dev_err(&pdev->dev, "gpio platform data missing\n");
+		return -ENODEV;
+	}
+
+	pct = devm_kzalloc(&pdev->dev, sizeof(struct abx500_pinctrl),
+				   GFP_KERNEL);
+	if (pct == NULL) {
+		dev_err(&pdev->dev,
+			"failed to allocate memory for pct\n");
+		return -ENOMEM;
+	}
+
+	pct->dev = &pdev->dev;
+	pct->parent = dev_get_drvdata(pdev->dev.parent);
+	pct->chip = abx500gpio_chip;
+	pct->chip.dev = &pdev->dev;
+	pct->chip.base = pdata->gpio_base;
+	pct->irq_base = pdata->irq_base;
+
+	/* initialize the lock */
+	mutex_init(&pct->lock);
+
+	/* Poke in other ASIC variants here */
+	switch (platid->driver_data) {
+	case PINCTRL_AB8500:
+		abx500_pinctrl_ab8500_init(&pct->soc);
+		break;
+	case PINCTRL_AB8540:
+		abx500_pinctrl_ab8540_init(&pct->soc);
+		break;
+	case PINCTRL_AB9540:
+		abx500_pinctrl_ab9540_init(&pct->soc);
+		break;
+	case PINCTRL_AB8505:
+		abx500_pinctrl_ab8505_init(&pct->soc);
+		break;
+	default:
+		dev_err(&pdev->dev, "Unsupported pinctrl sub driver (%d)\n",
+				(int) platid->driver_data);
+		return -EINVAL;
+	}
+
+	if (!pct->soc) {
+		dev_err(&pdev->dev, "Invalid SOC data\n");
+		return -EINVAL;
+	}
+
+	pct->chip.ngpio = abx500_get_gpio_num(pct->soc);
+	pct->irq_cluster = pct->soc->gpio_irq_cluster;
+	pct->irq_cluster_size = pct->soc->ngpio_irq_cluster;
+	pct->irq_gpio_rising_offset = pct->soc->irq_gpio_rising_offset;
+	pct->irq_gpio_falling_offset = pct->soc->irq_gpio_falling_offset;
+	pct->irq_gpio_factor = pct->soc->irq_gpio_factor;
+
+	ret = abx500_gpio_irq_init(pct);
+	if (ret)
+		goto out_free;
+	ret = gpiochip_add(&pct->chip);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to add gpiochip: %d\n",
+				ret);
+		goto out_rem_irq;
+	}
+	dev_info(&pdev->dev, "added gpiochip\n");
+
+	abx500_pinctrl_desc.pins = pct->soc->pins;
+	abx500_pinctrl_desc.npins = pct->soc->npins;
+	pct->pctldev = pinctrl_register(&abx500_pinctrl_desc, &pdev->dev, pct);
+	if (!pct->pctldev) {
+		dev_err(&pdev->dev,
+			"could not register abx500 pinctrl driver\n");
+		goto out_rem_chip;
+	}
+	dev_info(&pdev->dev, "registered pin controller\n");
+
+	/* We will handle a range of GPIO pins */
+	for (i = 0; i < pct->soc->gpio_num_ranges; i++) {
+		const struct abx500_pinrange *p = &pct->soc->gpio_ranges[i];
+
+		ret = gpiochip_add_pin_range(&pct->chip,
+					dev_name(&pdev->dev),
+					p->offset, p->offset, p->npins);
+		if (ret < 0)
+			return ret;
+	}
+
+	platform_set_drvdata(pdev, pct);
+	dev_info(&pdev->dev, "initialized abx500 pinctrl driver\n");
+
+	return 0;
+
+out_rem_chip:
+	ret = gpiochip_remove(&pct->chip);
+	if (ret)
+		dev_info(&pdev->dev, "failed to remove gpiochip\n");
+out_rem_irq:
+	abx500_gpio_irq_remove(pct);
+out_free:
+	mutex_destroy(&pct->lock);
+	return ret;
+}
+
+/*
+ * abx500_gpio_remove() - remove Ab8500-gpio driver
+ * @pdev :	Platform device registered
+ */
+static int __devexit abx500_gpio_remove(struct platform_device *pdev)
+{
+	struct abx500_pinctrl *pct = platform_get_drvdata(pdev);
+	int ret;
+
+	ret = gpiochip_remove(&pct->chip);
+	if (ret < 0) {
+		dev_err(pct->dev, "unable to remove gpiochip: %d\n",
+			ret);
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, NULL);
+	mutex_destroy(&pct->lock);
+	kfree(pct);
+
+	return 0;
+}
+
+static const struct platform_device_id abx500_pinctrl_id[] = {
+	{ "pinctrl-ab8500", PINCTRL_AB8500 },
+	{ "pinctrl-ab8540", PINCTRL_AB8540 },
+	{ "pinctrl-ab9540", PINCTRL_AB9540 },
+	{ "pinctrl-ab8505", PINCTRL_AB8505 },
+	{ },
+};
+
+static struct platform_driver abx500_gpio_driver = {
+	.driver = {
+		.name = "abx500-gpio",
+		.owner = THIS_MODULE,
+	},
+	.probe = abx500_gpio_probe,
+	.remove = __devexit_p(abx500_gpio_remove),
+	.id_table = abx500_pinctrl_id,
+};
+
+static int __init abx500_gpio_init(void)
+{
+	return platform_driver_register(&abx500_gpio_driver);
+}
+core_initcall(abx500_gpio_init);
+
+MODULE_AUTHOR("Patrice Chotard <patrice.chotard@st.com>");
+MODULE_DESCRIPTION("Driver allows to use AxB5xx unused pins to be used as GPIO");
+MODULE_ALIAS("platform:abx500-gpio");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-abx500.h b/drivers/pinctrl/pinctrl-abx500.h
new file mode 100644
index 0000000..359cb30
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-abx500.h
@@ -0,0 +1,229 @@
+#ifndef PINCTRL_PINCTRL_ABx5O0_H
+#define PINCTRL_PINCTRL_ABx500_H
+
+/* Package definitions */
+#define PINCTRL_AB8500	0
+#define PINCTRL_AB8540	1
+#define PINCTRL_AB9540	2
+#define PINCTRL_AB8505	3
+
+/* pins alternate function */
+enum abx500_pin_func {
+	ABX500_DEFAULT,
+	ABX500_ALT_A,
+	ABX500_ALT_B,
+	ABX500_ALT_C,
+};
+
+/**
+ * struct abx500_function - ABx500 pinctrl mux function
+ * @name: The name of the function, exported to pinctrl core.
+ * @groups: An array of pin groups that may select this function.
+ * @ngroups: The number of entries in @groups.
+ */
+struct abx500_function {
+	const char *name;
+	const char * const *groups;
+	unsigned ngroups;
+};
+
+/**
+ * struct abx500_pingroup - describes a ABx500 pin group
+ * @name: the name of this specific pin group
+ * @pins: an array of discrete physical pins used in this group, taken
+ *	from the driver-local pin enumeration space
+ * @num_pins: the number of pins in this group array, i.e. the number of
+ *	elements in .pins so we can iterate over that array
+ * @altsetting: the altsetting to apply to all pins in this group to
+ *	configure them to be used by a function
+ */
+struct abx500_pingroup {
+	const char *name;
+	const unsigned int *pins;
+	const unsigned npins;
+	int altsetting;
+};
+
+#define ALTERNATE_FUNCTIONS(pin, sel_bit, alt1, alt2, alta, altb, altc)	\
+{									\
+	.pin_number = pin,						\
+	.gpiosel_bit = sel_bit,						\
+	.alt_bit1 = alt1,						\
+	.alt_bit2 = alt2,						\
+	.alta_val = alta,						\
+	.altb_val = altb,						\
+	.altc_val = altc,						\
+}
+
+#define UNUSED -1
+/**
+ * struct alternate_functions
+ * @pin_number:		The pin number
+ * @gpiosel_bit:	Control bit in GPIOSEL register,
+ * @alt_bit1:		First AlternateFunction bit used to select the
+ *			alternate function
+ * @alt_bit2:		Second AlternateFunction bit used to select the
+ *			alternate function
+ *
+ *			these 3 following fields are necessary due to none
+ *			coherency on how to select the altA, altB and altC
+ *			function between the ABx500 SOC family when using
+ *			alternatfunc register.
+ * @alta_val:		value to write in alternatfunc to select altA function
+ * @altb_val:		value to write in alternatfunc to select altB function
+ * @altc_val:		value to write in alternatfunc to select altC function
+ */
+struct alternate_functions {
+	unsigned pin_number;
+	s8 gpiosel_bit;
+	s8 alt_bit1;
+	s8 alt_bit2;
+	u8 alta_val;
+	u8 altb_val;
+	u8 altc_val;
+};
+
+/**
+ * struct pullud - specific pull up/down feature
+ * @first_pin:		The pin number of the first pins which support
+ *			specific pull up/down
+ * @last_pin:		The pin number of the last pins
+ */
+struct pullud {
+	unsigned first_pin;
+	unsigned last_pin;
+};
+
+#define GPIO_IRQ_CLUSTER(a, b, c)	\
+{					\
+	.start = a,			\
+	.end = b,			\
+	.offset = c,			\
+}
+
+/**
+ * struct abx500_gpio_irq_cluster - indicates GPIOs which are interrupt
+ *			capable
+ * @start:		The pin number of the first pin interrupt capable
+ * @end:		The pin number of the last pin interrupt capable
+ * @offset:		offset used to compute specific setting strategy of
+ *			the interrupt line
+ */
+
+struct abx500_gpio_irq_cluster {
+	int start;
+	int end;
+	int offset;
+};
+
+/**
+ * struct abx500_pinrange - map pin numbers to GPIO offsets
+ * @offset:		offset into the GPIO local numberspace, incidentally
+ *			identical to the offset into the local pin numberspace
+ * @npins:		number of pins to map from both offsets
+ */
+struct abx500_pinrange {
+	unsigned int offset;
+	unsigned int npins;
+};
+
+#define ABX500_PINRANGE(a, b) { .offset = a, .npins = b }
+
+/**
+ * struct abx500_pinctrl_soc_data - ABx500 pin controller per-SoC configuration
+ * @gpio_ranges:	An array of GPIO ranges for this SoC
+ * @gpio_num_ranges:	The number of GPIO ranges for this SoC
+ * @pins:		An array describing all pins the pin controller affects.
+ *			All pins which are also GPIOs must be listed first within the
+ *			array, and be numbered identically to the GPIO controller's
+ *			numbering.
+ * @npins:		The number of entries in @pins.
+ * @functions:		The functions supported on this SoC.
+ * @nfunction:		The number of entries in @functions.
+ * @groups:		An array describing all pin groups the pin SoC supports.
+ * @ngroups:		The number of entries in @groups.
+ * @alternate_functions: array describing pins which supports alternate and
+ *			how to set it.
+ * @pullud:		array describing pins which supports pull up/down
+ *			specific registers.
+ * @gpio_irq_cluster:	An array of GPIO interrupt capable for this SoC
+ * @ngpio_irq_cluster:	The number of GPIO inetrrupt capable for this SoC
+ * @irq_gpio_rising_offset: Interrupt offset used as base to compute specific
+ *			setting strategy of the rising interrupt line
+ * @irq_gpio_falling_offset: Interrupt offset used as base to compute specific
+ *			setting strategy of the falling interrupt line
+ * @irq_gpio_factor:	Factor used to compute specific setting strategy of
+ *			the interrupt line
+ */
+
+struct abx500_pinctrl_soc_data {
+	const struct abx500_pinrange *gpio_ranges;
+	unsigned gpio_num_ranges;
+	const struct pinctrl_pin_desc *pins;
+	unsigned npins;
+	const struct abx500_function *functions;
+	unsigned nfunctions;
+	const struct abx500_pingroup *groups;
+	unsigned ngroups;
+	struct alternate_functions *alternate_functions;
+	struct pullud *pullud;
+	struct abx500_gpio_irq_cluster *gpio_irq_cluster;
+	unsigned ngpio_irq_cluster;
+	int irq_gpio_rising_offset;
+	int irq_gpio_falling_offset;
+	int irq_gpio_factor;
+};
+
+#ifdef CONFIG_PINCTRL_AB8500
+
+void abx500_pinctrl_ab8500_init(struct abx500_pinctrl_soc_data **soc);
+
+#else
+
+static inline void
+abx500_pinctrl_ab8500_init(struct abx500_pinctrl_soc_data **soc)
+{
+}
+
+#endif
+
+#ifdef CONFIG_PINCTRL_AB8540
+
+void abx500_pinctrl_ab8540_init(struct abx500_pinctrl_soc_data **soc);
+
+#else
+
+static inline void
+abx500_pinctrl_ab8540_init(struct abx500_pinctrl_soc_data **soc)
+{
+}
+
+#endif
+
+#ifdef CONFIG_PINCTRL_AB9540
+
+void abx500_pinctrl_ab9540_init(struct abx500_pinctrl_soc_data **soc);
+
+#else
+
+static inline void
+abx500_pinctrl_ab9540_init(struct abx500_pinctrl_soc_data **soc)
+{
+}
+
+#endif
+
+#ifdef CONFIG_PINCTRL_AB8505
+
+void abx500_pinctrl_ab8505_init(struct abx500_pinctrl_soc_data **soc);
+
+#else
+
+static inline void
+abx500_pinctrl_ab8505_init(struct abx500_pinctrl_soc_data **soc)
+{
+}
+
+#endif
+
+#endif /* PINCTRL_PINCTRL_ABx500_H */
diff --git a/include/linux/mfd/abx500/ab8500-gpio.h b/include/linux/mfd/abx500/ab8500-gpio.h
index 2387c20..e8c8281 100644
--- a/include/linux/mfd/abx500/ab8500-gpio.h
+++ b/include/linux/mfd/abx500/ab8500-gpio.h
@@ -14,10 +14,21 @@
  * registers.
  */
 
-struct ab8500_gpio_platform_data {
+struct abx500_gpio_platform_data {
 	int gpio_base;
 	u32 irq_base;
-	u8  config_reg[8];
+};
+
+enum abx500_gpio_pull_updown {
+	ABX500_GPIO_PULL_DOWN = 0x0,
+	ABX500_GPIO_PULL_NONE = 0x1,
+	ABX500_GPIO_PULL_UP = 0x3,
+};
+
+enum abx500_gpio_vinsel {
+	ABX500_GPIO_VINSEL_VBAT = 0x0,
+	ABX500_GPIO_VINSEL_VIN_1V8 = 0x1,
+	ABX500_GPIO_VINSEL_VDD_BIF = 0x2,
 };
 
 #endif /* _AB8500_GPIO_H */
diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h
index e640ea0..fc05344 100644
--- a/include/linux/mfd/abx500/ab8500.h
+++ b/include/linux/mfd/abx500/ab8500.h
@@ -385,7 +385,7 @@ struct ab8500_platform_data {
 	struct ab8500_regulator_reg_init *regulator_reg_init;
 	int num_regulator;
 	struct regulator_init_data *regulator;
-	struct ab8500_gpio_platform_data *gpio;
+	struct abx500_gpio_platform_data *gpio;
 	struct ab8500_codec_platform_data *codec;
 };
 
-- 
1.7.11.3

^ permalink raw reply related

* [PATCH v5 07/14] KVM: ARM: World-switch implementation
From: Gleb Natapov @ 2013-01-15  9:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130108183924.46302.65998.stgit@ubuntu>

On Tue, Jan 08, 2013 at 01:39:24PM -0500, Christoffer Dall wrote:
> Provides complete world-switch implementation to switch to other guests
> running in non-secure modes. Includes Hyp exception handlers that
> capture necessary exception information and stores the information on
> the VCPU and KVM structures.
> 
> The following Hyp-ABI is also documented in the code:
> 
> Hyp-ABI: Calling HYP-mode functions from host (in SVC mode):
>    Switching to Hyp mode is done through a simple HVC #0 instruction. The
>    exception vector code will check that the HVC comes from VMID==0 and if
>    so will push the necessary state (SPSR, lr_usr) on the Hyp stack.
>    - r0 contains a pointer to a HYP function
>    - r1, r2, and r3 contain arguments to the above function.
>    - The HYP function will be called with its arguments in r0, r1 and r2.
>    On HYP function return, we return directly to SVC.
> 
> A call to a function executing in Hyp mode is performed like the following:
> 
>         <svc code>
>         ldr     r0, =BSYM(my_hyp_fn)
>         ldr     r1, =my_param
>         hvc #0  ; Call my_hyp_fn(my_param) from HYP mode
>         <svc code>
> 
> Otherwise, the world-switch is pretty straight-forward. All state that
> can be modified by the guest is first backed up on the Hyp stack and the
> VCPU values is loaded onto the hardware. State, which is not loaded, but
> theoretically modifiable by the guest is protected through the
> virtualiation features to generate a trap and cause software emulation.
> Upon guest returns, all state is restored from hardware onto the VCPU
> struct and the original state is restored from the Hyp-stack onto the
> hardware.
> 
> SMP support using the VMPIDR calculated on the basis of the host MPIDR
> and overriding the low bits with KVM vcpu_id contributed by Marc Zyngier.
> 
> Reuse of VMIDs has been implemented by Antonios Motakis and adapated from
> a separate patch into the appropriate patches introducing the
> functionality. Note that the VMIDs are stored per VM as required by the ARM
> architecture reference manual.
> 
> To support VFP/NEON we trap those instructions using the HPCTR. When
> we trap, we switch the FPU.  After a guest exit, the VFP state is
> returned to the host.  When disabling access to floating point
> instructions, we also mask FPEXC_EN in order to avoid the guest
> receiving Undefined instruction exceptions before we have a chance to
> switch back the floating point state.  We are reusing vfp_hard_struct,
> so we depend on VFPv3 being enabled in the host kernel, if not, we still
> trap cp10 and cp11 in order to inject an undefined instruction exception
> whenever the guest tries to use VFP/NEON. VFP/NEON developed by
> Antionios Motakis and Rusty Russell.
> 
> Aborts that are permission faults, and not stage-1 page table walk, do
> not report the faulting address in the HPFAR.  We have to resolve the
> IPA, and store it just like the HPFAR register on the VCPU struct. If
> the IPA cannot be resolved, it means another CPU is playing with the
> page tables, and we simply restart the guest.  This quirk was fixed by
> Marc Zyngier.
> 
> Reviewed-by: Marcelo Tosatti <mtosatti@redhat.com>
> Signed-off-by: Rusty Russell <rusty.russell@linaro.org>
> Signed-off-by: Antonios Motakis <a.motakis@virtualopensystems.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <c.dall@virtualopensystems.com>
> ---
>  arch/arm/include/asm/kvm_arm.h  |   51 ++++
>  arch/arm/include/asm/kvm_host.h |   10 +
>  arch/arm/kernel/asm-offsets.c   |   25 ++
>  arch/arm/kvm/arm.c              |  187 ++++++++++++++++
>  arch/arm/kvm/interrupts.S       |  396 +++++++++++++++++++++++++++++++++++
>  arch/arm/kvm/interrupts_head.S  |  443 +++++++++++++++++++++++++++++++++++++++
>  6 files changed, 1108 insertions(+), 4 deletions(-)
>  create mode 100644 arch/arm/kvm/interrupts_head.S
> 
> diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h
> index fb22ee8..a3262a2 100644
> --- a/arch/arm/include/asm/kvm_arm.h
> +++ b/arch/arm/include/asm/kvm_arm.h
> @@ -98,6 +98,18 @@
>  #define TTBCR_T0SZ	3
>  #define HTCR_MASK	(TTBCR_T0SZ | TTBCR_IRGN0 | TTBCR_ORGN0 | TTBCR_SH0)
>  
> +/* Hyp System Trap Register */
> +#define HSTR_T(x)	(1 << x)
> +#define HSTR_TTEE	(1 << 16)
> +#define HSTR_TJDBX	(1 << 17)
> +
> +/* Hyp Coprocessor Trap Register */
> +#define HCPTR_TCP(x)	(1 << x)
> +#define HCPTR_TCP_MASK	(0x3fff)
> +#define HCPTR_TASE	(1 << 15)
> +#define HCPTR_TTA	(1 << 20)
> +#define HCPTR_TCPAC	(1 << 31)
> +
>  /* Hyp Debug Configuration Register bits */
>  #define HDCR_TDRA	(1 << 11)
>  #define HDCR_TDOSA	(1 << 10)
> @@ -144,6 +156,45 @@
>  #else
>  #define VTTBR_X		(5 - KVM_T0SZ)
>  #endif
> +#define VTTBR_BADDR_SHIFT (VTTBR_X - 1)
> +#define VTTBR_BADDR_MASK  (((1LLU << (40 - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT)
> +#define VTTBR_VMID_SHIFT  (48LLU)
> +#define VTTBR_VMID_MASK	  (0xffLLU << VTTBR_VMID_SHIFT)
> +
> +/* Hyp Syndrome Register (HSR) bits */
> +#define HSR_EC_SHIFT	(26)
> +#define HSR_EC		(0x3fU << HSR_EC_SHIFT)
> +#define HSR_IL		(1U << 25)
> +#define HSR_ISS		(HSR_IL - 1)
> +#define HSR_ISV_SHIFT	(24)
> +#define HSR_ISV		(1U << HSR_ISV_SHIFT)
> +#define HSR_FSC		(0x3f)
> +#define HSR_FSC_TYPE	(0x3c)
> +#define HSR_WNR		(1 << 6)
> +
> +#define FSC_FAULT	(0x04)
> +#define FSC_PERM	(0x0c)
> +
> +/* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */
> +#define HPFAR_MASK	(~0xf)
>  
> +#define HSR_EC_UNKNOWN	(0x00)
> +#define HSR_EC_WFI	(0x01)
> +#define HSR_EC_CP15_32	(0x03)
> +#define HSR_EC_CP15_64	(0x04)
> +#define HSR_EC_CP14_MR	(0x05)
> +#define HSR_EC_CP14_LS	(0x06)
> +#define HSR_EC_CP_0_13	(0x07)
> +#define HSR_EC_CP10_ID	(0x08)
> +#define HSR_EC_JAZELLE	(0x09)
> +#define HSR_EC_BXJ	(0x0A)
> +#define HSR_EC_CP14_64	(0x0C)
> +#define HSR_EC_SVC_HYP	(0x11)
> +#define HSR_EC_HVC	(0x12)
> +#define HSR_EC_SMC	(0x13)
> +#define HSR_EC_IABT	(0x20)
> +#define HSR_EC_IABT_HYP	(0x21)
> +#define HSR_EC_DABT	(0x24)
> +#define HSR_EC_DABT_HYP	(0x25)
>  
>  #endif /* __ARM_KVM_ARM_H__ */
> diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> index 1de6f0d..ddb09da 100644
> --- a/arch/arm/include/asm/kvm_host.h
> +++ b/arch/arm/include/asm/kvm_host.h
> @@ -21,6 +21,7 @@
>  
>  #include <asm/kvm.h>
>  #include <asm/kvm_asm.h>
> +#include <asm/fpstate.h>
>  
>  #define KVM_MAX_VCPUS CONFIG_KVM_ARM_MAX_VCPUS
>  #define KVM_USER_MEM_SLOTS 32
> @@ -85,6 +86,14 @@ struct kvm_vcpu_arch {
>  	u32 hxfar;		/* Hyp Data/Inst Fault Address Register */
>  	u32 hpfar;		/* Hyp IPA Fault Address Register */
>  
> +	/* Floating point registers (VFP and Advanced SIMD/NEON) */
> +	struct vfp_hard_struct vfp_guest;
> +	struct vfp_hard_struct *vfp_host;
> +
> +	/*
> +	 * Anything that is not used directly from assembly code goes
> +	 * here.
> +	 */
>  	/* Interrupt related fields */
>  	u32 irq_lines;		/* IRQ and FIQ levels */
>  
> @@ -112,6 +121,7 @@ struct kvm_one_reg;
>  int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
>  int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
>  u64 kvm_call_hyp(void *hypfn, ...);
> +void force_vm_exit(const cpumask_t *mask);
>  
>  #define KVM_ARCH_WANT_MMU_NOTIFIER
>  struct kvm;
> diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
> index c985b48..c8b3272 100644
> --- a/arch/arm/kernel/asm-offsets.c
> +++ b/arch/arm/kernel/asm-offsets.c
> @@ -13,6 +13,9 @@
>  #include <linux/sched.h>
>  #include <linux/mm.h>
>  #include <linux/dma-mapping.h>
> +#ifdef CONFIG_KVM_ARM_HOST
> +#include <linux/kvm_host.h>
> +#endif
>  #include <asm/cacheflush.h>
>  #include <asm/glue-df.h>
>  #include <asm/glue-pf.h>
> @@ -146,5 +149,27 @@ int main(void)
>    DEFINE(DMA_BIDIRECTIONAL,	DMA_BIDIRECTIONAL);
>    DEFINE(DMA_TO_DEVICE,		DMA_TO_DEVICE);
>    DEFINE(DMA_FROM_DEVICE,	DMA_FROM_DEVICE);
> +#ifdef CONFIG_KVM_ARM_HOST
> +  DEFINE(VCPU_KVM,		offsetof(struct kvm_vcpu, kvm));
> +  DEFINE(VCPU_MIDR,		offsetof(struct kvm_vcpu, arch.midr));
> +  DEFINE(VCPU_CP15,		offsetof(struct kvm_vcpu, arch.cp15));
> +  DEFINE(VCPU_VFP_GUEST,	offsetof(struct kvm_vcpu, arch.vfp_guest));
> +  DEFINE(VCPU_VFP_HOST,		offsetof(struct kvm_vcpu, arch.vfp_host));
> +  DEFINE(VCPU_REGS,		offsetof(struct kvm_vcpu, arch.regs));
> +  DEFINE(VCPU_USR_REGS,		offsetof(struct kvm_vcpu, arch.regs.usr_regs));
> +  DEFINE(VCPU_SVC_REGS,		offsetof(struct kvm_vcpu, arch.regs.svc_regs));
> +  DEFINE(VCPU_ABT_REGS,		offsetof(struct kvm_vcpu, arch.regs.abt_regs));
> +  DEFINE(VCPU_UND_REGS,		offsetof(struct kvm_vcpu, arch.regs.und_regs));
> +  DEFINE(VCPU_IRQ_REGS,		offsetof(struct kvm_vcpu, arch.regs.irq_regs));
> +  DEFINE(VCPU_FIQ_REGS,		offsetof(struct kvm_vcpu, arch.regs.fiq_regs));
> +  DEFINE(VCPU_PC,		offsetof(struct kvm_vcpu, arch.regs.usr_regs.ARM_pc));
> +  DEFINE(VCPU_CPSR,		offsetof(struct kvm_vcpu, arch.regs.usr_regs.ARM_cpsr));
> +  DEFINE(VCPU_IRQ_LINES,	offsetof(struct kvm_vcpu, arch.irq_lines));
> +  DEFINE(VCPU_HSR,		offsetof(struct kvm_vcpu, arch.hsr));
> +  DEFINE(VCPU_HxFAR,		offsetof(struct kvm_vcpu, arch.hxfar));
> +  DEFINE(VCPU_HPFAR,		offsetof(struct kvm_vcpu, arch.hpfar));
> +  DEFINE(VCPU_HYP_PC,		offsetof(struct kvm_vcpu, arch.hyp_pc));
> +  DEFINE(KVM_VTTBR,		offsetof(struct kvm, arch.vttbr));
> +#endif
>    return 0; 
>  }
> diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
> index 9b4566e..c94d278 100644
> --- a/arch/arm/kvm/arm.c
> +++ b/arch/arm/kvm/arm.c
> @@ -40,6 +40,7 @@
>  #include <asm/kvm_arm.h>
>  #include <asm/kvm_asm.h>
>  #include <asm/kvm_mmu.h>
> +#include <asm/kvm_emulate.h>
>  
>  #ifdef REQUIRES_VIRT
>  __asm__(".arch_extension	virt");
> @@ -49,6 +50,10 @@ static DEFINE_PER_CPU(unsigned long, kvm_arm_hyp_stack_page);
>  static struct vfp_hard_struct __percpu *kvm_host_vfp_state;
>  static unsigned long hyp_default_vectors;
>  
> +/* The VMID used in the VTTBR */
> +static atomic64_t kvm_vmid_gen = ATOMIC64_INIT(1);
> +static u8 kvm_next_vmid;
> +static DEFINE_SPINLOCK(kvm_vmid_lock);
>  
>  int kvm_arch_hardware_enable(void *garbage)
>  {
> @@ -276,6 +281,8 @@ int __attribute_const__ kvm_target_cpu(void)
>  
>  int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
>  {
> +	/* Force users to call KVM_ARM_VCPU_INIT */
> +	vcpu->arch.target = -1;
>  	return 0;
>  }
>  
> @@ -286,6 +293,7 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
>  void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
>  {
>  	vcpu->cpu = cpu;
> +	vcpu->arch.vfp_host = this_cpu_ptr(kvm_host_vfp_state);
>  }
>  
>  void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
> @@ -318,12 +326,189 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
>  
>  int kvm_arch_vcpu_in_guest_mode(struct kvm_vcpu *v)
As far as I see the function is unused.

>  {
> +	return v->mode == IN_GUEST_MODE;
> +}
> +
> +/* Just ensure a guest exit from a particular CPU */
> +static void exit_vm_noop(void *info)
> +{
> +}
> +
> +void force_vm_exit(const cpumask_t *mask)
> +{
> +	smp_call_function_many(mask, exit_vm_noop, NULL, true);
> +}
There is make_all_cpus_request() for that. It actually sends IPIs only
to cpus that are running vcpus.

> +
> +/**
> + * need_new_vmid_gen - check that the VMID is still valid
> + * @kvm: The VM's VMID to checkt
> + *
> + * return true if there is a new generation of VMIDs being used
> + *
> + * The hardware supports only 256 values with the value zero reserved for the
> + * host, so we check if an assigned value belongs to a previous generation,
> + * which which requires us to assign a new value. If we're the first to use a
> + * VMID for the new generation, we must flush necessary caches and TLBs on all
> + * CPUs.
> + */
> +static bool need_new_vmid_gen(struct kvm *kvm)
> +{
> +	return unlikely(kvm->arch.vmid_gen != atomic64_read(&kvm_vmid_gen));
> +}
> +
> +/**
> + * update_vttbr - Update the VTTBR with a valid VMID before the guest runs
> + * @kvm	The guest that we are about to run
> + *
> + * Called from kvm_arch_vcpu_ioctl_run before entering the guest to ensure the
> + * VM has a valid VMID, otherwise assigns a new one and flushes corresponding
> + * caches and TLBs.
> + */
> +static void update_vttbr(struct kvm *kvm)
> +{
> +	phys_addr_t pgd_phys;
> +	u64 vmid;
> +
> +	if (!need_new_vmid_gen(kvm))
> +		return;
> +
> +	spin_lock(&kvm_vmid_lock);
> +
> +	/*
> +	 * We need to re-check the vmid_gen here to ensure that if another vcpu
> +	 * already allocated a valid vmid for this vm, then this vcpu should
> +	 * use the same vmid.
> +	 */
> +	if (!need_new_vmid_gen(kvm)) {
> +		spin_unlock(&kvm_vmid_lock);
> +		return;
> +	}
> +
> +	/* First user of a new VMID generation? */
> +	if (unlikely(kvm_next_vmid == 0)) {
> +		atomic64_inc(&kvm_vmid_gen);
> +		kvm_next_vmid = 1;
> +
> +		/*
> +		 * On SMP we know no other CPUs can use this CPU's or each
> +		 * other's VMID after force_vm_exit returns since the
> +		 * kvm_vmid_lock blocks them from reentry to the guest.
> +		 */
> +		force_vm_exit(cpu_all_mask);
> +		/*
> +		 * Now broadcast TLB + ICACHE invalidation over the inner
> +		 * shareable domain to make sure all data structures are
> +		 * clean.
> +		 */
> +		kvm_call_hyp(__kvm_flush_vm_context);
> +	}
> +
> +	kvm->arch.vmid_gen = atomic64_read(&kvm_vmid_gen);
> +	kvm->arch.vmid = kvm_next_vmid;
> +	kvm_next_vmid++;
> +
> +	/* update vttbr to be used with the new vmid */
> +	pgd_phys = virt_to_phys(kvm->arch.pgd);
> +	vmid = ((u64)(kvm->arch.vmid) << VTTBR_VMID_SHIFT) & VTTBR_VMID_MASK;
> +	kvm->arch.vttbr = pgd_phys & VTTBR_BADDR_MASK;
> +	kvm->arch.vttbr |= vmid;
> +
> +	spin_unlock(&kvm_vmid_lock);
> +}
> +
> +/*
> + * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on
> + * proper exit to QEMU.
> + */
> +static int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
> +		       int exception_index)
> +{
> +	run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
>  	return 0;
>  }
>  
> +/**
> + * kvm_arch_vcpu_ioctl_run - the main VCPU run function to execute guest code
> + * @vcpu:	The VCPU pointer
> + * @run:	The kvm_run structure pointer used for userspace state exchange
> + *
> + * This function is called through the VCPU_RUN ioctl called from user space. It
> + * will execute VM code in a loop until the time slice for the process is used
> + * or some emulation is needed from user space in which case the function will
> + * return with return value 0 and with the kvm_run structure filled in with the
> + * required data for the requested emulation.
> + */
>  int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  {
> -	return -EINVAL;
> +	int ret;
> +	sigset_t sigsaved;
> +
> +	/* Make sure they initialize the vcpu with KVM_ARM_VCPU_INIT */
> +	if (unlikely(vcpu->arch.target < 0))
> +		return -ENOEXEC;
> +
> +	if (vcpu->sigset_active)
> +		sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
> +
> +	ret = 1;
> +	run->exit_reason = KVM_EXIT_UNKNOWN;
> +	while (ret > 0) {
> +		/*
> +		 * Check conditions before entering the guest
> +		 */
> +		cond_resched();
> +
> +		update_vttbr(vcpu->kvm);
> +
> +		local_irq_disable();
> +
> +		/*
> +		 * Re-check atomic conditions
> +		 */
> +		if (signal_pending(current)) {
> +			ret = -EINTR;
> +			run->exit_reason = KVM_EXIT_INTR;
> +		}
> +
> +		if (ret <= 0 || need_new_vmid_gen(vcpu->kvm)) {
> +			local_irq_enable();
> +			continue;
> +		}
> +
> +		/**************************************************************
> +		 * Enter the guest
> +		 */
> +		trace_kvm_entry(*vcpu_pc(vcpu));
> +		kvm_guest_enter();
> +		vcpu->mode = IN_GUEST_MODE;
You need to set mode to IN_GUEST_MODE before disabling interrupt and
check that mode != EXITING_GUEST_MODE after disabling interrupt but
before entering the guest. This way you will catch kicks that were sent
between setting of the mode and disabling the interrupts. Also you need
to check vcpu->requests and exit if it is not empty. I see that you do
not use vcpu->requests at all, but you should since common kvm code
assumes that it is used. make_all_cpus_request() uses it for instance.

> +
> +		ret = kvm_call_hyp(__kvm_vcpu_run, vcpu);
You do not take kvm->srcu lock before entering the guest. It looks
wrong.

> +
> +		vcpu->mode = OUTSIDE_GUEST_MODE;
> +		kvm_guest_exit();
> +		trace_kvm_exit(*vcpu_pc(vcpu));
> +		/*
> +		 * We may have taken a host interrupt in HYP mode (ie
> +		 * while executing the guest). This interrupt is still
> +		 * pending, as we haven't serviced it yet!
> +		 *
> +		 * We're now back in SVC mode, with interrupts
> +		 * disabled.  Enabling the interrupts now will have
> +		 * the effect of taking the interrupt again, in SVC
> +		 * mode this time.
> +		 */
> +		local_irq_enable();
> +
> +		/*
> +		 * Back from guest
> +		 *************************************************************/
> +
> +		ret = handle_exit(vcpu, run, ret);
> +	}
> +
> +	if (vcpu->sigset_active)
> +		sigprocmask(SIG_SETMASK, &sigsaved, NULL);
> +	return ret;
>  }
>  
>  static int vcpu_interrupt_line(struct kvm_vcpu *vcpu, int number, bool level)
> diff --git a/arch/arm/kvm/interrupts.S b/arch/arm/kvm/interrupts.S
> index a923590..08adcd5 100644
> --- a/arch/arm/kvm/interrupts.S
> +++ b/arch/arm/kvm/interrupts.S
> @@ -20,9 +20,12 @@
>  #include <linux/const.h>
>  #include <asm/unified.h>
>  #include <asm/page.h>
> +#include <asm/ptrace.h>
>  #include <asm/asm-offsets.h>
>  #include <asm/kvm_asm.h>
>  #include <asm/kvm_arm.h>
> +#include <asm/vfpmacros.h>
> +#include "interrupts_head.S"
>  
>  	.text
>  
> @@ -31,36 +34,423 @@ __kvm_hyp_code_start:
>  
>  /********************************************************************
>   * Flush per-VMID TLBs
> + *
> + * void __kvm_tlb_flush_vmid(struct kvm *kvm);
> + *
> + * We rely on the hardware to broadcast the TLB invalidation to all CPUs
> + * inside the inner-shareable domain (which is the case for all v7
> + * implementations).  If we come across a non-IS SMP implementation, we'll
> + * have to use an IPI based mechanism. Until then, we stick to the simple
> + * hardware assisted version.
>   */
>  ENTRY(__kvm_tlb_flush_vmid)
> +	push	{r2, r3}
> +
> +	add	r0, r0, #KVM_VTTBR
> +	ldrd	r2, r3, [r0]
> +	mcrr	p15, 6, r2, r3, c2	@ Write VTTBR
> +	isb
> +	mcr     p15, 0, r0, c8, c3, 0	@ TLBIALLIS (rt ignored)
> +	dsb
> +	isb
> +	mov	r2, #0
> +	mov	r3, #0
> +	mcrr	p15, 6, r2, r3, c2	@ Back to VMID #0
> +	isb				@ Not necessary if followed by eret
> +
> +	pop	{r2, r3}
>  	bx	lr
>  ENDPROC(__kvm_tlb_flush_vmid)
>  
>  /********************************************************************
> - * Flush TLBs and instruction caches of current CPU for all VMIDs
> + * Flush TLBs and instruction caches of all CPUs inside the inner-shareable
> + * domain, for all VMIDs
> + *
> + * void __kvm_flush_vm_context(void);
>   */
>  ENTRY(__kvm_flush_vm_context)
> +	mov	r0, #0			@ rn parameter for c15 flushes is SBZ
> +
> +	/* Invalidate NS Non-Hyp TLB Inner Shareable (TLBIALLNSNHIS) */
> +	mcr     p15, 4, r0, c8, c3, 4
> +	/* Invalidate instruction caches Inner Shareable (ICIALLUIS) */
> +	mcr     p15, 0, r0, c7, c1, 0
> +	dsb
> +	isb				@ Not necessary if followed by eret
> +
>  	bx	lr
>  ENDPROC(__kvm_flush_vm_context)
>  
> +
>  /********************************************************************
>   *  Hypervisor world-switch code
> + *
> + *
> + * int __kvm_vcpu_run(struct kvm_vcpu *vcpu)
>   */
>  ENTRY(__kvm_vcpu_run)
> -	bx	lr
> +	@ Save the vcpu pointer
> +	mcr	p15, 4, vcpu, c13, c0, 2	@ HTPIDR
> +
> +	save_host_regs
> +
> +	@ Store hardware CP15 state and load guest state
> +	read_cp15_state store_to_vcpu = 0
> +	write_cp15_state read_from_vcpu = 1
> +
> +	@ If the host kernel has not been configured with VFPv3 support,
> +	@ then it is safer if we deny guests from using it as well.
> +#ifdef CONFIG_VFPv3
> +	@ Set FPEXC_EN so the guest doesn't trap floating point instructions
> +	VFPFMRX r2, FPEXC		@ VMRS
> +	push	{r2}
> +	orr	r2, r2, #FPEXC_EN
> +	VFPFMXR FPEXC, r2		@ VMSR
> +#endif
> +
> +	@ Configure Hyp-role
> +	configure_hyp_role vmentry
> +
> +	@ Trap coprocessor CRx accesses
> +	set_hstr vmentry
> +	set_hcptr vmentry, (HCPTR_TTA | HCPTR_TCP(10) | HCPTR_TCP(11))
> +	set_hdcr vmentry
> +
> +	@ Write configured ID register into MIDR alias
> +	ldr	r1, [vcpu, #VCPU_MIDR]
> +	mcr	p15, 4, r1, c0, c0, 0
> +
> +	@ Write guest view of MPIDR into VMPIDR
> +	ldr	r1, [vcpu, #CP15_OFFSET(c0_MPIDR)]
> +	mcr	p15, 4, r1, c0, c0, 5
> +
> +	@ Set up guest memory translation
> +	ldr	r1, [vcpu, #VCPU_KVM]
> +	add	r1, r1, #KVM_VTTBR
> +	ldrd	r2, r3, [r1]
> +	mcrr	p15, 6, r2, r3, c2	@ Write VTTBR
> +
> +	@ We're all done, just restore the GPRs and go to the guest
> +	restore_guest_regs
> +	clrex				@ Clear exclusive monitor
> +	eret
> +
> +__kvm_vcpu_return:
> +	/*
> +	 * return convention:
> +	 * guest r0, r1, r2 saved on the stack
> +	 * r0: vcpu pointer
> +	 * r1: exception code
> +	 */
> +	save_guest_regs
> +
> +	@ Set VMID == 0
> +	mov	r2, #0
> +	mov	r3, #0
> +	mcrr	p15, 6, r2, r3, c2	@ Write VTTBR
> +
> +	@ Don't trap coprocessor accesses for host kernel
> +	set_hstr vmexit
> +	set_hdcr vmexit
> +	set_hcptr vmexit, (HCPTR_TTA | HCPTR_TCP(10) | HCPTR_TCP(11))
> +
> +#ifdef CONFIG_VFPv3
> +	@ Save floating point registers we if let guest use them.
> +	tst	r2, #(HCPTR_TCP(10) | HCPTR_TCP(11))
> +	bne	after_vfp_restore
> +
> +	@ Switch VFP/NEON hardware state to the host's
> +	add	r7, vcpu, #VCPU_VFP_GUEST
> +	store_vfp_state r7
> +	add	r7, vcpu, #VCPU_VFP_HOST
> +	ldr	r7, [r7]
> +	restore_vfp_state r7
> +
> +after_vfp_restore:
> +	@ Restore FPEXC_EN which we clobbered on entry
> +	pop	{r2}
> +	VFPFMXR FPEXC, r2
> +#endif
> +
> +	@ Reset Hyp-role
> +	configure_hyp_role vmexit
> +
> +	@ Let host read hardware MIDR
> +	mrc	p15, 0, r2, c0, c0, 0
> +	mcr	p15, 4, r2, c0, c0, 0
> +
> +	@ Back to hardware MPIDR
> +	mrc	p15, 0, r2, c0, c0, 5
> +	mcr	p15, 4, r2, c0, c0, 5
> +
> +	@ Store guest CP15 state and restore host state
> +	read_cp15_state store_to_vcpu = 1
> +	write_cp15_state read_from_vcpu = 0
> +
> +	restore_host_regs
> +	clrex				@ Clear exclusive monitor
> +	mov	r0, r1			@ Return the return code
> +	bx	lr			@ return to IOCTL
>  
>  ENTRY(kvm_call_hyp)
> +	hvc	#0
>  	bx	lr
>  
>  
>  /********************************************************************
>   * Hypervisor exception vector and handlers
> + *
> + *
> + * The KVM/ARM Hypervisor ABI is defined as follows:
> + *
> + * Entry to Hyp mode from the host kernel will happen _only_ when an HVC
> + * instruction is issued since all traps are disabled when running the host
> + * kernel as per the Hyp-mode initialization at boot time.
> + *
> + * HVC instructions cause a trap to the vector page + offset 0x18 (see hyp_hvc
> + * below) when the HVC instruction is called from SVC mode (i.e. a guest or the
> + * host kernel) and they cause a trap to the vector page + offset 0xc when HVC
> + * instructions are called from within Hyp-mode.
> + *
> + * Hyp-ABI: Calling HYP-mode functions from host (in SVC mode):
> + *    Switching to Hyp mode is done through a simple HVC #0 instruction. The
> + *    exception vector code will check that the HVC comes from VMID==0 and if
> + *    so will push the necessary state (SPSR, lr_usr) on the Hyp stack.
> + *    - r0 contains a pointer to a HYP function
> + *    - r1, r2, and r3 contain arguments to the above function.
> + *    - The HYP function will be called with its arguments in r0, r1 and r2.
> + *    On HYP function return, we return directly to SVC.
> + *
> + * Note that the above is used to execute code in Hyp-mode from a host-kernel
> + * point of view, and is a different concept from performing a world-switch and
> + * executing guest code SVC mode (with a VMID != 0).
>   */
>  
> +/* Handle undef, svc, pabt, or dabt by crashing with a user notice */
> +.macro bad_exception exception_code, panic_str
> +	push	{r0-r2}
> +	mrrc	p15, 6, r0, r1, c2	@ Read VTTBR
> +	lsr	r1, r1, #16
> +	ands	r1, r1, #0xff
> +	beq	99f
> +
> +	load_vcpu			@ Load VCPU pointer
> +	.if \exception_code == ARM_EXCEPTION_DATA_ABORT
> +	mrc	p15, 4, r2, c5, c2, 0	@ HSR
> +	mrc	p15, 4, r1, c6, c0, 0	@ HDFAR
> +	str	r2, [vcpu, #VCPU_HSR]
> +	str	r1, [vcpu, #VCPU_HxFAR]
> +	.endif
> +	.if \exception_code == ARM_EXCEPTION_PREF_ABORT
> +	mrc	p15, 4, r2, c5, c2, 0	@ HSR
> +	mrc	p15, 4, r1, c6, c0, 2	@ HIFAR
> +	str	r2, [vcpu, #VCPU_HSR]
> +	str	r1, [vcpu, #VCPU_HxFAR]
> +	.endif
> +	mov	r1, #\exception_code
> +	b	__kvm_vcpu_return
> +
> +	@ We were in the host already. Let's craft a panic-ing return to SVC.
> +99:	mrs	r2, cpsr
> +	bic	r2, r2, #MODE_MASK
> +	orr	r2, r2, #SVC_MODE
> +THUMB(	orr	r2, r2, #PSR_T_BIT	)
> +	msr	spsr_cxsf, r2
> +	mrs	r1, ELR_hyp
> +	ldr	r2, =BSYM(panic)
> +	msr	ELR_hyp, r2
> +	ldr	r0, =\panic_str
> +	eret
> +.endm
> +
> +	.text
> +
>  	.align 5
>  __kvm_hyp_vector:
>  	.globl __kvm_hyp_vector
> -	nop
> +
> +	@ Hyp-mode exception vector
> +	W(b)	hyp_reset
> +	W(b)	hyp_undef
> +	W(b)	hyp_svc
> +	W(b)	hyp_pabt
> +	W(b)	hyp_dabt
> +	W(b)	hyp_hvc
> +	W(b)	hyp_irq
> +	W(b)	hyp_fiq
> +
> +	.align
> +hyp_reset:
> +	b	hyp_reset
> +
> +	.align
> +hyp_undef:
> +	bad_exception ARM_EXCEPTION_UNDEFINED, und_die_str
> +
> +	.align
> +hyp_svc:
> +	bad_exception ARM_EXCEPTION_HVC, svc_die_str
> +
> +	.align
> +hyp_pabt:
> +	bad_exception ARM_EXCEPTION_PREF_ABORT, pabt_die_str
> +
> +	.align
> +hyp_dabt:
> +	bad_exception ARM_EXCEPTION_DATA_ABORT, dabt_die_str
> +
> +	.align
> +hyp_hvc:
> +	/*
> +	 * Getting here is either becuase of a trap from a guest or from calling
> +	 * HVC from the host kernel, which means "switch to Hyp mode".
> +	 */
> +	push	{r0, r1, r2}
> +
> +	@ Check syndrome register
> +	mrc	p15, 4, r1, c5, c2, 0	@ HSR
> +	lsr	r0, r1, #HSR_EC_SHIFT
> +#ifdef CONFIG_VFPv3
> +	cmp	r0, #HSR_EC_CP_0_13
> +	beq	switch_to_guest_vfp
> +#endif
> +	cmp	r0, #HSR_EC_HVC
> +	bne	guest_trap		@ Not HVC instr.
> +
> +	/*
> +	 * Let's check if the HVC came from VMID 0 and allow simple
> +	 * switch to Hyp mode
> +	 */
> +	mrrc    p15, 6, r0, r2, c2
> +	lsr     r2, r2, #16
> +	and     r2, r2, #0xff
> +	cmp     r2, #0
> +	bne	guest_trap		@ Guest called HVC
> +
> +host_switch_to_hyp:
> +	pop	{r0, r1, r2}
> +
> +	push	{lr}
> +	mrs	lr, SPSR
> +	push	{lr}
> +
> +	mov	lr, r0
> +	mov	r0, r1
> +	mov	r1, r2
> +	mov	r2, r3
> +
> +THUMB(	orr	lr, #1)
> +	blx	lr			@ Call the HYP function
> +
> +	pop	{lr}
> +	msr	SPSR_csxf, lr
> +	pop	{lr}
> +	eret
> +
> +guest_trap:
> +	load_vcpu			@ Load VCPU pointer to r0
> +	str	r1, [vcpu, #VCPU_HSR]
> +
> +	@ Check if we need the fault information
> +	lsr	r1, r1, #HSR_EC_SHIFT
> +	cmp	r1, #HSR_EC_IABT
> +	mrceq	p15, 4, r2, c6, c0, 2	@ HIFAR
> +	beq	2f
> +	cmp	r1, #HSR_EC_DABT
> +	bne	1f
> +	mrc	p15, 4, r2, c6, c0, 0	@ HDFAR
> +
> +2:	str	r2, [vcpu, #VCPU_HxFAR]
> +
> +	/*
> +	 * B3.13.5 Reporting exceptions taken to the Non-secure PL2 mode:
> +	 *
> +	 * Abort on the stage 2 translation for a memory access from a
> +	 * Non-secure PL1 or PL0 mode:
> +	 *
> +	 * For any Access flag fault or Translation fault, and also for any
> +	 * Permission fault on the stage 2 translation of a memory access
> +	 * made as part of a translation table walk for a stage 1 translation,
> +	 * the HPFAR holds the IPA that caused the fault. Otherwise, the HPFAR
> +	 * is UNKNOWN.
> +	 */
> +
> +	/* Check for permission fault, and S1PTW */
> +	mrc	p15, 4, r1, c5, c2, 0	@ HSR
> +	and	r0, r1, #HSR_FSC_TYPE
> +	cmp	r0, #FSC_PERM
> +	tsteq	r1, #(1 << 7)		@ S1PTW
> +	mrcne	p15, 4, r2, c6, c0, 4	@ HPFAR
> +	bne	3f
> +
> +	/* Resolve IPA using the xFAR */
> +	mcr	p15, 0, r2, c7, c8, 0	@ ATS1CPR
> +	isb
> +	mrrc	p15, 0, r0, r1, c7	@ PAR
> +	tst	r0, #1
> +	bne	4f			@ Failed translation
> +	ubfx	r2, r0, #12, #20
> +	lsl	r2, r2, #4
> +	orr	r2, r2, r1, lsl #24
> +
> +3:	load_vcpu			@ Load VCPU pointer to r0
> +	str	r2, [r0, #VCPU_HPFAR]
> +
> +1:	mov	r1, #ARM_EXCEPTION_HVC
> +	b	__kvm_vcpu_return
> +
> +4:	pop	{r0, r1, r2}		@ Failed translation, return to guest
> +	eret
> +
> +/*
> + * If VFPv3 support is not available, then we will not switch the VFP
> + * registers; however cp10 and cp11 accesses will still trap and fallback
> + * to the regular coprocessor emulation code, which currently will
> + * inject an undefined exception to the guest.
> + */
> +#ifdef CONFIG_VFPv3
> +switch_to_guest_vfp:
> +	load_vcpu			@ Load VCPU pointer to r0
> +	push	{r3-r7}
> +
> +	@ NEON/VFP used.  Turn on VFP access.
> +	set_hcptr vmexit, (HCPTR_TCP(10) | HCPTR_TCP(11))
> +
> +	@ Switch VFP/NEON hardware state to the guest's
> +	add	r7, r0, #VCPU_VFP_HOST
> +	ldr	r7, [r7]
> +	store_vfp_state r7
> +	add	r7, r0, #VCPU_VFP_GUEST
> +	restore_vfp_state r7
> +
> +	pop	{r3-r7}
> +	pop	{r0-r2}
> +	eret
> +#endif
> +
> +	.align
> +hyp_irq:
> +	push	{r0, r1, r2}
> +	mov	r1, #ARM_EXCEPTION_IRQ
> +	load_vcpu			@ Load VCPU pointer to r0
> +	b	__kvm_vcpu_return
> +
> +	.align
> +hyp_fiq:
> +	b	hyp_fiq
> +
> +	.ltorg
>  
>  __kvm_hyp_code_end:
>  	.globl	__kvm_hyp_code_end
> +
> +	.section ".rodata"
> +
> +und_die_str:
> +	.ascii	"unexpected undefined exception in Hyp mode at: %#08x"
> +pabt_die_str:
> +	.ascii	"unexpected prefetch abort in Hyp mode at: %#08x"
> +dabt_die_str:
> +	.ascii	"unexpected data abort in Hyp mode at: %#08x"
> +svc_die_str:
> +	.ascii	"unexpected HVC/SVC trap in Hyp mode at: %#08x"
> diff --git a/arch/arm/kvm/interrupts_head.S b/arch/arm/kvm/interrupts_head.S
> new file mode 100644
> index 0000000..f59a580
> --- /dev/null
> +++ b/arch/arm/kvm/interrupts_head.S
> @@ -0,0 +1,443 @@
> +#define VCPU_USR_REG(_reg_nr)	(VCPU_USR_REGS + (_reg_nr * 4))
> +#define VCPU_USR_SP		(VCPU_USR_REG(13))
> +#define VCPU_USR_LR		(VCPU_USR_REG(14))
> +#define CP15_OFFSET(_cp15_reg_idx) (VCPU_CP15 + (_cp15_reg_idx * 4))
> +
> +/*
> + * Many of these macros need to access the VCPU structure, which is always
> + * held in r0. These macros should never clobber r1, as it is used to hold the
> + * exception code on the return path (except of course the macro that switches
> + * all the registers before the final jump to the VM).
> + */
> +vcpu	.req	r0		@ vcpu pointer always in r0
> +
> +/* Clobbers {r2-r6} */
> +.macro store_vfp_state vfp_base
> +	@ The VFPFMRX and VFPFMXR macros are the VMRS and VMSR instructions
> +	VFPFMRX	r2, FPEXC
> +	@ Make sure VFP is enabled so we can touch the registers.
> +	orr	r6, r2, #FPEXC_EN
> +	VFPFMXR	FPEXC, r6
> +
> +	VFPFMRX	r3, FPSCR
> +	tst	r2, #FPEXC_EX		@ Check for VFP Subarchitecture
> +	beq	1f
> +	@ If FPEXC_EX is 0, then FPINST/FPINST2 reads are upredictable, so
> +	@ we only need to save them if FPEXC_EX is set.
> +	VFPFMRX r4, FPINST
> +	tst	r2, #FPEXC_FP2V
> +	VFPFMRX r5, FPINST2, ne		@ vmrsne
> +	bic	r6, r2, #FPEXC_EX	@ FPEXC_EX disable
> +	VFPFMXR	FPEXC, r6
> +1:
> +	VFPFSTMIA \vfp_base, r6		@ Save VFP registers
> +	stm	\vfp_base, {r2-r5}	@ Save FPEXC, FPSCR, FPINST, FPINST2
> +.endm
> +
> +/* Assume FPEXC_EN is on and FPEXC_EX is off, clobbers {r2-r6} */
> +.macro restore_vfp_state vfp_base
> +	VFPFLDMIA \vfp_base, r6		@ Load VFP registers
> +	ldm	\vfp_base, {r2-r5}	@ Load FPEXC, FPSCR, FPINST, FPINST2
> +
> +	VFPFMXR FPSCR, r3
> +	tst	r2, #FPEXC_EX		@ Check for VFP Subarchitecture
> +	beq	1f
> +	VFPFMXR FPINST, r4
> +	tst	r2, #FPEXC_FP2V
> +	VFPFMXR FPINST2, r5, ne
> +1:
> +	VFPFMXR FPEXC, r2	@ FPEXC	(last, in case !EN)
> +.endm
> +
> +/* These are simply for the macros to work - value don't have meaning */
> +.equ usr, 0
> +.equ svc, 1
> +.equ abt, 2
> +.equ und, 3
> +.equ irq, 4
> +.equ fiq, 5
> +
> +.macro push_host_regs_mode mode
> +	mrs	r2, SP_\mode
> +	mrs	r3, LR_\mode
> +	mrs	r4, SPSR_\mode
> +	push	{r2, r3, r4}
> +.endm
> +
> +/*
> + * Store all host persistent registers on the stack.
> + * Clobbers all registers, in all modes, except r0 and r1.
> + */
> +.macro save_host_regs
> +	/* Hyp regs. Only ELR_hyp (SPSR_hyp already saved) */
> +	mrs	r2, ELR_hyp
> +	push	{r2}
> +
> +	/* usr regs */
> +	push	{r4-r12}	@ r0-r3 are always clobbered
> +	mrs	r2, SP_usr
> +	mov	r3, lr
> +	push	{r2, r3}
> +
> +	push_host_regs_mode svc
> +	push_host_regs_mode abt
> +	push_host_regs_mode und
> +	push_host_regs_mode irq
> +
> +	/* fiq regs */
> +	mrs	r2, r8_fiq
> +	mrs	r3, r9_fiq
> +	mrs	r4, r10_fiq
> +	mrs	r5, r11_fiq
> +	mrs	r6, r12_fiq
> +	mrs	r7, SP_fiq
> +	mrs	r8, LR_fiq
> +	mrs	r9, SPSR_fiq
> +	push	{r2-r9}
> +.endm
> +
> +.macro pop_host_regs_mode mode
> +	pop	{r2, r3, r4}
> +	msr	SP_\mode, r2
> +	msr	LR_\mode, r3
> +	msr	SPSR_\mode, r4
> +.endm
> +
> +/*
> + * Restore all host registers from the stack.
> + * Clobbers all registers, in all modes, except r0 and r1.
> + */
> +.macro restore_host_regs
> +	pop	{r2-r9}
> +	msr	r8_fiq, r2
> +	msr	r9_fiq, r3
> +	msr	r10_fiq, r4
> +	msr	r11_fiq, r5
> +	msr	r12_fiq, r6
> +	msr	SP_fiq, r7
> +	msr	LR_fiq, r8
> +	msr	SPSR_fiq, r9
> +
> +	pop_host_regs_mode irq
> +	pop_host_regs_mode und
> +	pop_host_regs_mode abt
> +	pop_host_regs_mode svc
> +
> +	pop	{r2, r3}
> +	msr	SP_usr, r2
> +	mov	lr, r3
> +	pop	{r4-r12}
> +
> +	pop	{r2}
> +	msr	ELR_hyp, r2
> +.endm
> +
> +/*
> + * Restore SP, LR and SPSR for a given mode. offset is the offset of
> + * this mode's registers from the VCPU base.
> + *
> + * Assumes vcpu pointer in vcpu reg
> + *
> + * Clobbers r1, r2, r3, r4.
> + */
> +.macro restore_guest_regs_mode mode, offset
> +	add	r1, vcpu, \offset
> +	ldm	r1, {r2, r3, r4}
> +	msr	SP_\mode, r2
> +	msr	LR_\mode, r3
> +	msr	SPSR_\mode, r4
> +.endm
> +
> +/*
> + * Restore all guest registers from the vcpu struct.
> + *
> + * Assumes vcpu pointer in vcpu reg
> + *
> + * Clobbers *all* registers.
> + */
> +.macro restore_guest_regs
> +	restore_guest_regs_mode svc, #VCPU_SVC_REGS
> +	restore_guest_regs_mode abt, #VCPU_ABT_REGS
> +	restore_guest_regs_mode und, #VCPU_UND_REGS
> +	restore_guest_regs_mode irq, #VCPU_IRQ_REGS
> +
> +	add	r1, vcpu, #VCPU_FIQ_REGS
> +	ldm	r1, {r2-r9}
> +	msr	r8_fiq, r2
> +	msr	r9_fiq, r3
> +	msr	r10_fiq, r4
> +	msr	r11_fiq, r5
> +	msr	r12_fiq, r6
> +	msr	SP_fiq, r7
> +	msr	LR_fiq, r8
> +	msr	SPSR_fiq, r9
> +
> +	@ Load return state
> +	ldr	r2, [vcpu, #VCPU_PC]
> +	ldr	r3, [vcpu, #VCPU_CPSR]
> +	msr	ELR_hyp, r2
> +	msr	SPSR_cxsf, r3
> +
> +	@ Load user registers
> +	ldr	r2, [vcpu, #VCPU_USR_SP]
> +	ldr	r3, [vcpu, #VCPU_USR_LR]
> +	msr	SP_usr, r2
> +	mov	lr, r3
> +	add	vcpu, vcpu, #(VCPU_USR_REGS)
> +	ldm	vcpu, {r0-r12}
> +.endm
> +
> +/*
> + * Save SP, LR and SPSR for a given mode. offset is the offset of
> + * this mode's registers from the VCPU base.
> + *
> + * Assumes vcpu pointer in vcpu reg
> + *
> + * Clobbers r2, r3, r4, r5.
> + */
> +.macro save_guest_regs_mode mode, offset
> +	add	r2, vcpu, \offset
> +	mrs	r3, SP_\mode
> +	mrs	r4, LR_\mode
> +	mrs	r5, SPSR_\mode
> +	stm	r2, {r3, r4, r5}
> +.endm
> +
> +/*
> + * Save all guest registers to the vcpu struct
> + * Expects guest's r0, r1, r2 on the stack.
> + *
> + * Assumes vcpu pointer in vcpu reg
> + *
> + * Clobbers r2, r3, r4, r5.
> + */
> +.macro save_guest_regs
> +	@ Store usr registers
> +	add	r2, vcpu, #VCPU_USR_REG(3)
> +	stm	r2, {r3-r12}
> +	add	r2, vcpu, #VCPU_USR_REG(0)
> +	pop	{r3, r4, r5}		@ r0, r1, r2
> +	stm	r2, {r3, r4, r5}
> +	mrs	r2, SP_usr
> +	mov	r3, lr
> +	str	r2, [vcpu, #VCPU_USR_SP]
> +	str	r3, [vcpu, #VCPU_USR_LR]
> +
> +	@ Store return state
> +	mrs	r2, ELR_hyp
> +	mrs	r3, spsr
> +	str	r2, [vcpu, #VCPU_PC]
> +	str	r3, [vcpu, #VCPU_CPSR]
> +
> +	@ Store other guest registers
> +	save_guest_regs_mode svc, #VCPU_SVC_REGS
> +	save_guest_regs_mode abt, #VCPU_ABT_REGS
> +	save_guest_regs_mode und, #VCPU_UND_REGS
> +	save_guest_regs_mode irq, #VCPU_IRQ_REGS
> +.endm
> +
> +/* Reads cp15 registers from hardware and stores them in memory
> + * @store_to_vcpu: If 0, registers are written in-order to the stack,
> + * 		   otherwise to the VCPU struct pointed to by vcpup
> + *
> + * Assumes vcpu pointer in vcpu reg
> + *
> + * Clobbers r2 - r12
> + */
> +.macro read_cp15_state store_to_vcpu
> +	mrc	p15, 0, r2, c1, c0, 0	@ SCTLR
> +	mrc	p15, 0, r3, c1, c0, 2	@ CPACR
> +	mrc	p15, 0, r4, c2, c0, 2	@ TTBCR
> +	mrc	p15, 0, r5, c3, c0, 0	@ DACR
> +	mrrc	p15, 0, r6, r7, c2	@ TTBR 0
> +	mrrc	p15, 1, r8, r9, c2	@ TTBR 1
> +	mrc	p15, 0, r10, c10, c2, 0	@ PRRR
> +	mrc	p15, 0, r11, c10, c2, 1	@ NMRR
> +	mrc	p15, 2, r12, c0, c0, 0	@ CSSELR
> +
> +	.if \store_to_vcpu == 0
> +	push	{r2-r12}		@ Push CP15 registers
> +	.else
> +	str	r2, [vcpu, #CP15_OFFSET(c1_SCTLR)]
> +	str	r3, [vcpu, #CP15_OFFSET(c1_CPACR)]
> +	str	r4, [vcpu, #CP15_OFFSET(c2_TTBCR)]
> +	str	r5, [vcpu, #CP15_OFFSET(c3_DACR)]
> +	add	vcpu, vcpu, #CP15_OFFSET(c2_TTBR0)
> +	strd	r6, r7, [vcpu]
> +	add	vcpu, vcpu, #CP15_OFFSET(c2_TTBR1) - CP15_OFFSET(c2_TTBR0)
> +	strd	r8, r9, [vcpu]
> +	sub	vcpu, vcpu, #CP15_OFFSET(c2_TTBR1)
> +	str	r10, [vcpu, #CP15_OFFSET(c10_PRRR)]
> +	str	r11, [vcpu, #CP15_OFFSET(c10_NMRR)]
> +	str	r12, [vcpu, #CP15_OFFSET(c0_CSSELR)]
> +	.endif
> +
> +	mrc	p15, 0, r2, c13, c0, 1	@ CID
> +	mrc	p15, 0, r3, c13, c0, 2	@ TID_URW
> +	mrc	p15, 0, r4, c13, c0, 3	@ TID_URO
> +	mrc	p15, 0, r5, c13, c0, 4	@ TID_PRIV
> +	mrc	p15, 0, r6, c5, c0, 0	@ DFSR
> +	mrc	p15, 0, r7, c5, c0, 1	@ IFSR
> +	mrc	p15, 0, r8, c5, c1, 0	@ ADFSR
> +	mrc	p15, 0, r9, c5, c1, 1	@ AIFSR
> +	mrc	p15, 0, r10, c6, c0, 0	@ DFAR
> +	mrc	p15, 0, r11, c6, c0, 2	@ IFAR
> +	mrc	p15, 0, r12, c12, c0, 0	@ VBAR
> +
> +	.if \store_to_vcpu == 0
> +	push	{r2-r12}		@ Push CP15 registers
> +	.else
> +	str	r2, [vcpu, #CP15_OFFSET(c13_CID)]
> +	str	r3, [vcpu, #CP15_OFFSET(c13_TID_URW)]
> +	str	r4, [vcpu, #CP15_OFFSET(c13_TID_URO)]
> +	str	r5, [vcpu, #CP15_OFFSET(c13_TID_PRIV)]
> +	str	r6, [vcpu, #CP15_OFFSET(c5_DFSR)]
> +	str	r7, [vcpu, #CP15_OFFSET(c5_IFSR)]
> +	str	r8, [vcpu, #CP15_OFFSET(c5_ADFSR)]
> +	str	r9, [vcpu, #CP15_OFFSET(c5_AIFSR)]
> +	str	r10, [vcpu, #CP15_OFFSET(c6_DFAR)]
> +	str	r11, [vcpu, #CP15_OFFSET(c6_IFAR)]
> +	str	r12, [vcpu, #CP15_OFFSET(c12_VBAR)]
> +	.endif
> +.endm
> +
> +/*
> + * Reads cp15 registers from memory and writes them to hardware
> + * @read_from_vcpu: If 0, registers are read in-order from the stack,
> + *		    otherwise from the VCPU struct pointed to by vcpup
> + *
> + * Assumes vcpu pointer in vcpu reg
> + */
> +.macro write_cp15_state read_from_vcpu
> +	.if \read_from_vcpu == 0
> +	pop	{r2-r12}
> +	.else
> +	ldr	r2, [vcpu, #CP15_OFFSET(c13_CID)]
> +	ldr	r3, [vcpu, #CP15_OFFSET(c13_TID_URW)]
> +	ldr	r4, [vcpu, #CP15_OFFSET(c13_TID_URO)]
> +	ldr	r5, [vcpu, #CP15_OFFSET(c13_TID_PRIV)]
> +	ldr	r6, [vcpu, #CP15_OFFSET(c5_DFSR)]
> +	ldr	r7, [vcpu, #CP15_OFFSET(c5_IFSR)]
> +	ldr	r8, [vcpu, #CP15_OFFSET(c5_ADFSR)]
> +	ldr	r9, [vcpu, #CP15_OFFSET(c5_AIFSR)]
> +	ldr	r10, [vcpu, #CP15_OFFSET(c6_DFAR)]
> +	ldr	r11, [vcpu, #CP15_OFFSET(c6_IFAR)]
> +	ldr	r12, [vcpu, #CP15_OFFSET(c12_VBAR)]
> +	.endif
> +
> +	mcr	p15, 0, r2, c13, c0, 1	@ CID
> +	mcr	p15, 0, r3, c13, c0, 2	@ TID_URW
> +	mcr	p15, 0, r4, c13, c0, 3	@ TID_URO
> +	mcr	p15, 0, r5, c13, c0, 4	@ TID_PRIV
> +	mcr	p15, 0, r6, c5, c0, 0	@ DFSR
> +	mcr	p15, 0, r7, c5, c0, 1	@ IFSR
> +	mcr	p15, 0, r8, c5, c1, 0	@ ADFSR
> +	mcr	p15, 0, r9, c5, c1, 1	@ AIFSR
> +	mcr	p15, 0, r10, c6, c0, 0	@ DFAR
> +	mcr	p15, 0, r11, c6, c0, 2	@ IFAR
> +	mcr	p15, 0, r12, c12, c0, 0	@ VBAR
> +
> +	.if \read_from_vcpu == 0
> +	pop	{r2-r12}
> +	.else
> +	ldr	r2, [vcpu, #CP15_OFFSET(c1_SCTLR)]
> +	ldr	r3, [vcpu, #CP15_OFFSET(c1_CPACR)]
> +	ldr	r4, [vcpu, #CP15_OFFSET(c2_TTBCR)]
> +	ldr	r5, [vcpu, #CP15_OFFSET(c3_DACR)]
> +	add	vcpu, vcpu, #CP15_OFFSET(c2_TTBR0)
> +	ldrd	r6, r7, [vcpu]
> +	add	vcpu, vcpu, #CP15_OFFSET(c2_TTBR1) - CP15_OFFSET(c2_TTBR0)
> +	ldrd	r8, r9, [vcpu]
> +	sub	vcpu, vcpu, #CP15_OFFSET(c2_TTBR1)
> +	ldr	r10, [vcpu, #CP15_OFFSET(c10_PRRR)]
> +	ldr	r11, [vcpu, #CP15_OFFSET(c10_NMRR)]
> +	ldr	r12, [vcpu, #CP15_OFFSET(c0_CSSELR)]
> +	.endif
> +
> +	mcr	p15, 0, r2, c1, c0, 0	@ SCTLR
> +	mcr	p15, 0, r3, c1, c0, 2	@ CPACR
> +	mcr	p15, 0, r4, c2, c0, 2	@ TTBCR
> +	mcr	p15, 0, r5, c3, c0, 0	@ DACR
> +	mcrr	p15, 0, r6, r7, c2	@ TTBR 0
> +	mcrr	p15, 1, r8, r9, c2	@ TTBR 1
> +	mcr	p15, 0, r10, c10, c2, 0	@ PRRR
> +	mcr	p15, 0, r11, c10, c2, 1	@ NMRR
> +	mcr	p15, 2, r12, c0, c0, 0	@ CSSELR
> +.endm
> +
> +/*
> + * Save the VGIC CPU state into memory
> + *
> + * Assumes vcpu pointer in vcpu reg
> + */
> +.macro save_vgic_state
> +.endm
> +
> +/*
> + * Restore the VGIC CPU state from memory
> + *
> + * Assumes vcpu pointer in vcpu reg
> + */
> +.macro restore_vgic_state
> +.endm
> +
> +.equ vmentry,	0
> +.equ vmexit,	1
> +
> +/* Configures the HSTR (Hyp System Trap Register) on entry/return
> + * (hardware reset value is 0) */
> +.macro set_hstr operation
> +	mrc	p15, 4, r2, c1, c1, 3
> +	ldr	r3, =HSTR_T(15)
> +	.if \operation == vmentry
> +	orr	r2, r2, r3		@ Trap CR{15}
> +	.else
> +	bic	r2, r2, r3		@ Don't trap any CRx accesses
> +	.endif
> +	mcr	p15, 4, r2, c1, c1, 3
> +.endm
> +
> +/* Configures the HCPTR (Hyp Coprocessor Trap Register) on entry/return
> + * (hardware reset value is 0). Keep previous value in r2. */
> +.macro set_hcptr operation, mask
> +	mrc	p15, 4, r2, c1, c1, 2
> +	ldr	r3, =\mask
> +	.if \operation == vmentry
> +	orr	r3, r2, r3		@ Trap coproc-accesses defined in mask
> +	.else
> +	bic	r3, r2, r3		@ Don't trap defined coproc-accesses
> +	.endif
> +	mcr	p15, 4, r3, c1, c1, 2
> +.endm
> +
> +/* Configures the HDCR (Hyp Debug Configuration Register) on entry/return
> + * (hardware reset value is 0) */
> +.macro set_hdcr operation
> +	mrc	p15, 4, r2, c1, c1, 1
> +	ldr	r3, =(HDCR_TPM|HDCR_TPMCR)
> +	.if \operation == vmentry
> +	orr	r2, r2, r3		@ Trap some perfmon accesses
> +	.else
> +	bic	r2, r2, r3		@ Don't trap any perfmon accesses
> +	.endif
> +	mcr	p15, 4, r2, c1, c1, 1
> +.endm
> +
> +/* Enable/Disable: stage-2 trans., trap interrupts, trap wfi, trap smc */
> +.macro configure_hyp_role operation
> +	mrc	p15, 4, r2, c1, c1, 0	@ HCR
> +	bic	r2, r2, #HCR_VIRT_EXCP_MASK
> +	ldr	r3, =HCR_GUEST_MASK
> +	.if \operation == vmentry
> +	orr	r2, r2, r3
> +	ldr	r3, [vcpu, #VCPU_IRQ_LINES]
irq_lines are accessed atomically from vcpu_interrupt_line(), but there
is no memory barriers or atomic operations here. Looks suspicious though
I am not familiar with ARM memory model. As far as I understand
different translation regimes are used to access this memory, so who
knows what this does to access ordering.


> +	orr	r2, r2, r3
> +	.else
> +	bic	r2, r2, r3
> +	.endif
> +	mcr	p15, 4, r2, c1, c1, 0
> +.endm
> +
> +.macro load_vcpu
> +	mrc	p15, 4, vcpu, c13, c0, 2	@ HTPIDR
> +.endm
> 
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
			Gleb.

^ permalink raw reply

* [PATCH 4/4] pinctrl/abx500: add AB8500 pinctrl driver
From: Linus Walleij @ 2013-01-15  9:43 UTC (permalink / raw)
  To: linux-arm-kernel

From: Patrice Chotard <patrice.chotard@st.com>

This adds a subdriver for the AB8500 pinctrl portions.

Signed-off-by: Patrice Chotard <patrice.chotard@st.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
 arch/arm/mach-ux500/Kconfig      |   1 +
 drivers/pinctrl/Kconfig          |   4 +
 drivers/pinctrl/Makefile         |   1 +
 drivers/pinctrl/pinctrl-ab8500.c | 477 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 483 insertions(+)
 create mode 100644 drivers/pinctrl/pinctrl-ab8500.c

diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
index 2c090d7..31f1b5a 100644
--- a/arch/arm/mach-ux500/Kconfig
+++ b/arch/arm/mach-ux500/Kconfig
@@ -19,6 +19,7 @@ config UX500_SOC_DB8500
 	select CPU_FREQ_TABLE if CPU_FREQ
 	select MFD_DB8500_PRCMU
 	select PINCTRL_DB8500
+	select PINCTRL_AB8500
 	select REGULATOR
 	select REGULATOR_DB8500_PRCMU
 
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index ec819d8..223f40a 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -33,6 +33,10 @@ config PINCTRL_ABX500
 	help
 	  Select this to enable the ABx500 family IC GPIO driver
 
+config PINCTRL_AB8500
+	bool "AB8500 pin controller driver"
+	depends on PINCTRL_ABX500 && ARCH_U8500
+
 config PINCTRL_AT91
 	bool "AT91 pinctrl driver"
 	depends on OF
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index d10bf87..b7985b9 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_PINCTRL)		+= devicetree.o
 endif
 obj-$(CONFIG_GENERIC_PINCONF)	+= pinconf-generic.o
 obj-$(CONFIG_PINCTRL_ABX500)	+= pinctrl-abx500.o
+obj-$(CONFIG_PINCTRL_AB8500)	+= pinctrl-ab8500.o
 obj-$(CONFIG_PINCTRL_AT91)	+= pinctrl-at91.o
 obj-$(CONFIG_PINCTRL_BCM2835)	+= pinctrl-bcm2835.o
 obj-$(CONFIG_PINCTRL_IMX)	+= pinctrl-imx.o
diff --git a/drivers/pinctrl/pinctrl-ab8500.c b/drivers/pinctrl/pinctrl-ab8500.c
new file mode 100644
index 0000000..385ad1d
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-ab8500.c
@@ -0,0 +1,477 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Patrice Chotard <patrice.chotard@stericsson.com> for ST-Ericsson.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include "pinctrl-abx500.h"
+
+/* All the pins that can be used for GPIO and some other functions */
+#define ABX500_GPIO(offset)		(offset)
+
+#define AB8500_PIN_T10		ABX500_GPIO(1)
+#define AB8500_PIN_T9		ABX500_GPIO(2)
+#define AB8500_PIN_U9		ABX500_GPIO(3)
+#define AB8500_PIN_W2		ABX500_GPIO(4)
+/* hole */
+#define AB8500_PIN_Y18		ABX500_GPIO(6)
+#define AB8500_PIN_AA20		ABX500_GPIO(7)
+#define AB8500_PIN_W18		ABX500_GPIO(8)
+#define AB8500_PIN_AA19		ABX500_GPIO(9)
+#define AB8500_PIN_U17		ABX500_GPIO(10)
+#define AB8500_PIN_AA18		ABX500_GPIO(11)
+#define AB8500_PIN_U16		ABX500_GPIO(12)
+#define AB8500_PIN_W17		ABX500_GPIO(13)
+#define AB8500_PIN_F14		ABX500_GPIO(14)
+#define AB8500_PIN_B17		ABX500_GPIO(15)
+#define AB8500_PIN_F15		ABX500_GPIO(16)
+#define AB8500_PIN_P5		ABX500_GPIO(17)
+#define AB8500_PIN_R5		ABX500_GPIO(18)
+#define AB8500_PIN_U5		ABX500_GPIO(19)
+#define AB8500_PIN_T5		ABX500_GPIO(20)
+#define AB8500_PIN_H19		ABX500_GPIO(21)
+#define AB8500_PIN_G20		ABX500_GPIO(22)
+#define AB8500_PIN_G19		ABX500_GPIO(23)
+#define AB8500_PIN_T14		ABX500_GPIO(24)
+#define AB8500_PIN_R16		ABX500_GPIO(25)
+#define AB8500_PIN_M16		ABX500_GPIO(26)
+#define AB8500_PIN_J6		ABX500_GPIO(27)
+#define AB8500_PIN_K6		ABX500_GPIO(28)
+#define AB8500_PIN_G6		ABX500_GPIO(29)
+#define AB8500_PIN_H6		ABX500_GPIO(30)
+#define AB8500_PIN_F5		ABX500_GPIO(31)
+#define AB8500_PIN_G5		ABX500_GPIO(32)
+/* hole */
+#define AB8500_PIN_R17		ABX500_GPIO(34)
+#define AB8500_PIN_W15		ABX500_GPIO(35)
+#define AB8500_PIN_A17		ABX500_GPIO(36)
+#define AB8500_PIN_E15		ABX500_GPIO(37)
+#define AB8500_PIN_C17		ABX500_GPIO(38)
+#define AB8500_PIN_E16		ABX500_GPIO(39)
+#define AB8500_PIN_T19		ABX500_GPIO(40)
+#define AB8500_PIN_U19		ABX500_GPIO(41)
+#define AB8500_PIN_U2		ABX500_GPIO(42)
+
+/* indicates the highest GPIO number */
+#define AB8500_GPIO_MAX_NUMBER	42
+
+/*
+ * The names of the pins are denoted by GPIO number and ball name, even
+ * though they can be used for other things than GPIO, this is the first
+ * column in the table of the data sheet and often used on schematics and
+ * such.
+ */
+static const struct pinctrl_pin_desc ab8500_ranges_pins[] = {
+	PINCTRL_PIN(AB8500_PIN_T10, "GPIO1_T10"),
+	PINCTRL_PIN(AB8500_PIN_T9, "GPIO2_T9"),
+	PINCTRL_PIN(AB8500_PIN_U9, "GPIO3_U9"),
+	PINCTRL_PIN(AB8500_PIN_W2, "GPIO4_W2"),
+	/* hole */
+	PINCTRL_PIN(AB8500_PIN_Y18, "GPIO6_Y18"),
+	PINCTRL_PIN(AB8500_PIN_AA20, "GPIO7_AA20"),
+	PINCTRL_PIN(AB8500_PIN_W18, "GPIO8_W18"),
+	PINCTRL_PIN(AB8500_PIN_AA19, "GPIO9_AA19"),
+	PINCTRL_PIN(AB8500_PIN_U17, "GPIO10_U17"),
+	PINCTRL_PIN(AB8500_PIN_AA18, "GPIO11_AA18"),
+	PINCTRL_PIN(AB8500_PIN_U16, "GPIO12_U16"),
+	PINCTRL_PIN(AB8500_PIN_W17, "GPIO13_W17"),
+	PINCTRL_PIN(AB8500_PIN_F14, "GPIO14_F14"),
+	PINCTRL_PIN(AB8500_PIN_B17, "GPIO15_B17"),
+	PINCTRL_PIN(AB8500_PIN_F15, "GPIO16_F15"),
+	PINCTRL_PIN(AB8500_PIN_P5, "GPIO17_P5"),
+	PINCTRL_PIN(AB8500_PIN_R5, "GPIO18_R5"),
+	PINCTRL_PIN(AB8500_PIN_U5, "GPIO19_U5"),
+	PINCTRL_PIN(AB8500_PIN_T5, "GPIO20_T5"),
+	PINCTRL_PIN(AB8500_PIN_H19, "GPIO21_H19"),
+	PINCTRL_PIN(AB8500_PIN_G20, "GPIO22_G20"),
+	PINCTRL_PIN(AB8500_PIN_G19, "GPIO23_G19"),
+	PINCTRL_PIN(AB8500_PIN_T14, "GPIO24_T14"),
+	PINCTRL_PIN(AB8500_PIN_R16, "GPIO25_R16"),
+	PINCTRL_PIN(AB8500_PIN_M16, "GPIO26_M16"),
+	PINCTRL_PIN(AB8500_PIN_J6, "GPIO27_J6"),
+	PINCTRL_PIN(AB8500_PIN_K6, "GPIO28_K6"),
+	PINCTRL_PIN(AB8500_PIN_G6, "GPIO29_G6"),
+	PINCTRL_PIN(AB8500_PIN_H6, "GPIO30_H6"),
+	PINCTRL_PIN(AB8500_PIN_F5, "GPIO31_F5"),
+	PINCTRL_PIN(AB8500_PIN_G5, "GPIO32_G5"),
+	/* hole */
+	PINCTRL_PIN(AB8500_PIN_R17, "GPIO34_R17"),
+	PINCTRL_PIN(AB8500_PIN_W15, "GPIO35_W15"),
+	PINCTRL_PIN(AB8500_PIN_A17, "GPIO36_A17"),
+	PINCTRL_PIN(AB8500_PIN_E15, "GPIO37_E15"),
+	PINCTRL_PIN(AB8500_PIN_C17, "GPIO38_C17"),
+	PINCTRL_PIN(AB8500_PIN_E16, "GPIO39_E16"),
+	PINCTRL_PIN(AB8500_PIN_T19, "GPIO40_T19"),
+	PINCTRL_PIN(AB8500_PIN_U19, "GPIO41_U19"),
+	PINCTRL_PIN(AB8500_PIN_U2, "GPIO42_U2"),
+};
+
+/*
+ * Maps local GPIO offsets to local pin numbers
+ */
+static const struct abx500_pinrange ab8500_pinranges[] = {
+	ABX500_PINRANGE(1, 4),
+	ABX500_PINRANGE(6, 27),
+	ABX500_PINRANGE(34, 9),
+};
+
+/*
+ * Read the pin group names like this:
+ * sysclkreq2_d_1 = first groups of pins for sysclkreq2 on default function
+ *
+ * The groups are arranged as sets per altfunction column, so we can
+ * mux in one group at a time by selecting the same altfunction for them
+ * all. When functions require pins on different altfunctions, you need
+ * to combine several groups.
+ */
+
+/* default column */
+static const unsigned sysclkreq2_d_1_pins[] = { AB8500_PIN_T10 };
+static const unsigned sysclkreq3_d_1_pins[] = { AB8500_PIN_T9 };
+static const unsigned sysclkreq4_d_1_pins[] = { AB8500_PIN_U9 };
+static const unsigned sysclkreq6_d_1_pins[] = { AB8500_PIN_W2 };
+static const unsigned ycbcr0123_d_1_pins[] = { AB8500_PIN_Y18, AB8500_PIN_AA20,
+					AB8500_PIN_W18, AB8500_PIN_AA19};
+static const unsigned gpio10_d_1_pins[] = { AB8500_PIN_U17 };
+static const unsigned gpio11_d_1_pins[] = { AB8500_PIN_AA18 };
+static const unsigned gpio12_d_1_pins[] = { AB8500_PIN_U16 };
+static const unsigned gpio13_d_1_pins[] = { AB8500_PIN_W17 };
+static const unsigned pwmout1_d_1_pins[] = { AB8500_PIN_F14 };
+static const unsigned pwmout2_d_1_pins[] = { AB8500_PIN_B17 };
+static const unsigned pwmout3_d_1_pins[] = { AB8500_PIN_F15 };
+
+/* audio data interface 1*/
+static const unsigned adi1_d_1_pins[] = { AB8500_PIN_P5, AB8500_PIN_R5,
+					AB8500_PIN_U5, AB8500_PIN_T5 };
+/* USBUICC */
+static const unsigned usbuicc_d_1_pins[] = { AB8500_PIN_H19, AB8500_PIN_G20,
+					AB8500_PIN_G19 };
+static const unsigned sysclkreq7_d_1_pins[] = { AB8500_PIN_T14 };
+static const unsigned sysclkreq8_d_1_pins[] = { AB8500_PIN_R16 };
+static const unsigned gpio26_d_1_pins[] = { AB8500_PIN_M16 };
+/* Digital microphone 1 and 2 */
+static const unsigned dmic12_d_1_pins[] = { AB8500_PIN_J6, AB8500_PIN_K6 };
+/* Digital microphone 3 and 4 */
+static const unsigned dmic34_d_1_pins[] = { AB8500_PIN_G6, AB8500_PIN_H6 };
+/* Digital microphone 5 and 6 */
+static const unsigned dmic56_d_1_pins[] = { AB8500_PIN_F5, AB8500_PIN_G5 };
+static const unsigned extcpena_d_1_pins[] = { AB8500_PIN_R17 };
+static const unsigned gpio35_d_1_pins[] = { AB8500_PIN_W15 };
+/* APE SPI */
+static const unsigned apespi_d_1_pins[] = { AB8500_PIN_A17, AB8500_PIN_E15,
+					AB8500_PIN_C17, AB8500_PIN_E16};
+/* modem SDA/SCL */
+static const unsigned modsclsda_d_1_pins[] = { AB8500_PIN_T19, AB8500_PIN_U19 };
+static const unsigned sysclkreq5_d_1_pins[] = { AB8500_PIN_U2 };
+
+/* Altfunction A column */
+static const unsigned gpio1_a_1_pins[] = { AB8500_PIN_T10 };
+static const unsigned gpio2_a_1_pins[] = { AB8500_PIN_T9 };
+static const unsigned gpio3_a_1_pins[] = { AB8500_PIN_U9 };
+static const unsigned gpio4_a_1_pins[] = { AB8500_PIN_W2 };
+static const unsigned gpio6_a_1_pins[] = { AB8500_PIN_Y18 };
+static const unsigned gpio7_a_1_pins[] = { AB8500_PIN_AA20 };
+static const unsigned gpio8_a_1_pins[] = { AB8500_PIN_W18 };
+static const unsigned gpio9_a_1_pins[] = { AB8500_PIN_AA19 };
+/* YCbCr4 YCbCr5 YCbCr6 YCbCr7*/
+static const unsigned ycbcr4567_a_1_pins[] = { AB8500_PIN_U17, AB8500_PIN_AA18,
+					AB8500_PIN_U16, AB8500_PIN_W17};
+static const unsigned gpio14_a_1_pins[] = { AB8500_PIN_F14 };
+static const unsigned gpio15_a_1_pins[] = { AB8500_PIN_B17 };
+static const unsigned gpio16_a_1_pins[] = { AB8500_PIN_F15 };
+static const unsigned gpio17_a_1_pins[] = { AB8500_PIN_P5 };
+static const unsigned gpio18_a_1_pins[] = { AB8500_PIN_R5 };
+static const unsigned gpio19_a_1_pins[] = { AB8500_PIN_U5 };
+static const unsigned gpio20_a_1_pins[] = { AB8500_PIN_T5 };
+static const unsigned gpio21_a_1_pins[] = { AB8500_PIN_H19 };
+static const unsigned gpio22_a_1_pins[] = { AB8500_PIN_G20 };
+static const unsigned gpio23_a_1_pins[] = { AB8500_PIN_G19 };
+static const unsigned gpio24_a_1_pins[] = { AB8500_PIN_T14 };
+static const unsigned gpio25_a_1_pins[] = { AB8500_PIN_R16 };
+static const unsigned gpio27_a_1_pins[] = { AB8500_PIN_J6 };
+static const unsigned gpio28_a_1_pins[] = { AB8500_PIN_K6 };
+static const unsigned gpio29_a_1_pins[] = { AB8500_PIN_G6 };
+static const unsigned gpio30_a_1_pins[] = { AB8500_PIN_H6 };
+static const unsigned gpio31_a_1_pins[] = { AB8500_PIN_F5 };
+static const unsigned gpio32_a_1_pins[] = { AB8500_PIN_G5 };
+static const unsigned gpio34_a_1_pins[] = { AB8500_PIN_R17 };
+static const unsigned gpio36_a_1_pins[] = { AB8500_PIN_A17 };
+static const unsigned gpio37_a_1_pins[] = { AB8500_PIN_E15 };
+static const unsigned gpio38_a_1_pins[] = { AB8500_PIN_C17 };
+static const unsigned gpio39_a_1_pins[] = { AB8500_PIN_E16 };
+static const unsigned gpio40_a_1_pins[] = { AB8500_PIN_T19 };
+static const unsigned gpio41_a_1_pins[] = { AB8500_PIN_U19 };
+static const unsigned gpio42_a_1_pins[] = { AB8500_PIN_U2 };
+
+/* Altfunction B colum */
+static const unsigned hiqclkena_b_1_pins[] = { AB8500_PIN_U17 };
+static const unsigned usbuiccpd_b_1_pins[] = { AB8500_PIN_AA18 };
+static const unsigned i2ctrig1_b_1_pins[] = { AB8500_PIN_U16 };
+static const unsigned i2ctrig2_b_1_pins[] = { AB8500_PIN_W17 };
+
+/* Altfunction C column */
+static const unsigned usbvdat_c_1_pins[] = { AB8500_PIN_W17 };
+
+
+#define AB8500_PIN_GROUP(a, b) { .name = #a, .pins = a##_pins,		\
+			.npins = ARRAY_SIZE(a##_pins), .altsetting = b }
+
+static const struct abx500_pingroup ab8500_ranges_groups[] = {
+	/* default column */
+	AB8500_PIN_GROUP(sysclkreq2_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(sysclkreq3_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(sysclkreq4_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(sysclkreq6_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(ycbcr0123_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(gpio10_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(gpio11_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(gpio12_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(gpio13_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(pwmout1_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(pwmout2_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(pwmout3_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(adi1_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(usbuicc_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(sysclkreq7_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(sysclkreq8_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(gpio26_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(dmic12_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(dmic34_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(dmic56_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(extcpena_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(gpio35_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(apespi_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(modsclsda_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(sysclkreq5_d_1, ABX500_DEFAULT),
+	/* Altfunction A column */
+	AB8500_PIN_GROUP(gpio1_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio2_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio3_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio4_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio6_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio7_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio8_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio9_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(ycbcr4567_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio14_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio15_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio16_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio17_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio18_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio19_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio20_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio21_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio22_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio23_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio24_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio25_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio27_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio28_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio29_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio30_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio31_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio32_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio34_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio36_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio37_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio38_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio39_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio40_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio41_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio42_a_1, ABX500_ALT_A),
+	/* Altfunction B column */
+	AB8500_PIN_GROUP(hiqclkena_b_1, ABX500_ALT_B),
+	AB8500_PIN_GROUP(usbuiccpd_b_1, ABX500_ALT_B),
+	AB8500_PIN_GROUP(i2ctrig1_b_1, ABX500_ALT_B),
+	AB8500_PIN_GROUP(i2ctrig2_b_1, ABX500_ALT_B),
+	/* Altfunction C column */
+	AB8500_PIN_GROUP(usbvdat_c_1, ABX500_ALT_C),
+};
+
+/* We use this macro to define the groups applicable to a function */
+#define AB8500_FUNC_GROUPS(a, b...)	   \
+static const char * const a##_groups[] = { b };
+
+AB8500_FUNC_GROUPS(sysclkreq, "sysclkreq2_d_1", "sysclkreq3_d_1",
+		"sysclkreq4_d_1", "sysclkreq5_d_1", "sysclkreq6_d_1",
+		"sysclkreq7_d_1", "sysclkreq8_d_1");
+AB8500_FUNC_GROUPS(ycbcr, "ycbcr0123_d_1", "ycbcr4567_a_1");
+AB8500_FUNC_GROUPS(gpio, "gpio1_a_1", "gpio2_a_1", "gpio3_a_1", "gpio4_a_1",
+		"gpio6_a_1", "gpio7_a_1", "gpio8_a_1", "gpio9_a_1",
+		"gpio10_d_1", "gpio11_d_1", "gpio12_d_1", "gpio13_d_1",
+		"gpio14_a_1", "gpio15_a_1", "gpio16_a_1", "gpio17_a_1",
+		"gpio18_a_1", "gpio19_a_1", "gpio20_a_1", "gpio21_a_1",
+		"gpio22_a_1", "gpio23_a_1", "gpio24_a_1", "gpio25_a_1",
+		"gpio26_d_1", "gpio27_a_1", "gpio28_a_1", "gpio29_a_1",
+		"gpio30_a_1", "gpio31_a_1", "gpio32_a_1", "gpio34_a_1",
+		"gpio35_d_1", "gpio36_a_1", "gpio37_a_1", "gpio38_a_1",
+		"gpio39_a_1", "gpio40_a_1", "gpio41_a_1", "gpio42_a_1");
+AB8500_FUNC_GROUPS(pwmout, "pwmout1_d_1", "pwmout2_d_1", "pwmout3_d_1");
+AB8500_FUNC_GROUPS(adi1, "adi1_d_1");
+AB8500_FUNC_GROUPS(usbuicc, "usbuicc_d_1", "usbuiccpd_b_1");
+AB8500_FUNC_GROUPS(dmic, "dmic12_d_1", "dmic34_d_1", "dmic56_d_1");
+AB8500_FUNC_GROUPS(extcpena, "extcpena_d_1");
+AB8500_FUNC_GROUPS(apespi, "apespi_d_1");
+AB8500_FUNC_GROUPS(modsclsda, "modsclsda_d_1");
+AB8500_FUNC_GROUPS(hiqclkena, "hiqclkena_b_1");
+AB8500_FUNC_GROUPS(i2ctrig, "i2ctrig1_b_1", "i2ctrig2_b_1");
+AB8500_FUNC_GROUPS(usbvdat, "usbvdat_c_1");
+
+#define FUNCTION(fname)					\
+	{						\
+		.name = #fname,				\
+		.groups = fname##_groups,		\
+		.ngroups = ARRAY_SIZE(fname##_groups),	\
+	}
+
+static const struct abx500_function ab8500_ranges_functions[] = {
+	FUNCTION(sysclkreq),
+	FUNCTION(ycbcr),
+	FUNCTION(gpio),
+	FUNCTION(pwmout),
+	FUNCTION(adi1),
+	FUNCTION(usbuicc),
+	FUNCTION(dmic),
+	FUNCTION(extcpena),
+	FUNCTION(apespi),
+	FUNCTION(modsclsda),
+	FUNCTION(hiqclkena),
+	FUNCTION(i2ctrig),
+	FUNCTION(usbvdat),
+};
+
+/*
+ * this table translates what's is in the AB8500 specification regarding the
+ * balls alternate functions (as for DB, default, ALT_A, ALT_B and ALT_C).
+ * ALTERNATE_FUNCTIONS(GPIO_NUMBER, GPIOSEL bit, ALTERNATFUNC bit1, ALTERNATEFUNC bit2, ALTA val, ALTB val, ALTC val),
+ *
+ * example :
+ *
+ *	ALTERNATE_FUNCTIONS(13,     4,      3,      4, 0, 1 ,2),
+ *	means that pin AB8500_PIN_W17 (pin 13) supports 4 mux (default/ALT_A,
+ *	ALT_B and ALT_C), so GPIOSEL and ALTERNATFUNC registers are used to select
+ *	the mux.  ALTA, ALTB and ALTC val indicates values to write in
+ *	ALTERNATFUNC register. We need to specifies these values as SOC
+ *	designers didn't apply the same logic on how to select mux in the ABx500
+ *	family ....
+ *	As this pins supports at least ALT_B mux, default mux is
+ *	selected by writing 1 in GPIOSEL bit :
+ *
+ *		| GPIOSEL bit=4 | alternatfunc bit2=4 | alternatfunc bit1=3
+ *	default	|       1       |          0          |          0
+ *	alt_A	|       0       |          0          |          0
+ *	alt_B	|       0       |          0          |          1
+ *	alt_C	|       0       |          1          |          0
+ *
+ *	ALTERNATE_FUNCTIONS(8,      7, UNUSED, UNUSED),
+ *	means that pin AB8500_PIN_W18 (pin 8) supports 2 mux, so only GPIOSEL
+ *	register is used to select the mux. As this pins doesn't support at
+ *	least ALT_B mux, default mux is by writing 0 in GPIOSEL bit :
+ *
+ *		| GPIOSEL bit=7 | alternatfunc bit2=  | alternatfunc bit1=
+ *	default	|       0       |          0          |          0
+ *	alt_A	|       1       |          0          |          0
+ */
+
+struct alternate_functions ab8500_alternate_functions[AB8500_GPIO_MAX_NUMBER + 1] = {
+	ALTERNATE_FUNCTIONS(0, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO0 */
+	ALTERNATE_FUNCTIONS(1,	    0, UNUSED, UNUSED, 0, 0, 0), /* GPIO1, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(2,      1, UNUSED, UNUSED, 0, 0, 0), /* GPIO2, altA controlled by bit 1 */
+	ALTERNATE_FUNCTIONS(3,      2, UNUSED, UNUSED, 0, 0, 0), /* GPIO3, altA controlled by bit 2*/
+	ALTERNATE_FUNCTIONS(4,      3, UNUSED, UNUSED, 0, 0, 0), /* GPIO4, altA controlled by bit 3*/
+	/* bit 4 reserved */
+	ALTERNATE_FUNCTIONS(5, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO5 */
+	ALTERNATE_FUNCTIONS(6,      5, UNUSED, UNUSED, 0, 0, 0), /* GPIO6, altA controlled by bit 5*/
+	ALTERNATE_FUNCTIONS(7,      6, UNUSED, UNUSED, 0, 0, 0), /* GPIO7, altA controlled by bit 6*/
+	ALTERNATE_FUNCTIONS(8,      7, UNUSED, UNUSED, 0, 0, 0), /* GPIO8, altA controlled by bit 7*/
+
+	ALTERNATE_FUNCTIONS(9,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO9, altA controlled by bit 0*/
+	ALTERNATE_FUNCTIONS(10,     1,      0, UNUSED, 0, 1, 0), /* GPIO10, altA and altB controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(11,     2,      1, UNUSED, 0, 1, 0), /* GPIO11, altA and altB controlled by bit 1 */
+	ALTERNATE_FUNCTIONS(12,     3,      2, UNUSED, 0, 1, 0), /* GPIO12, altA and altB controlled by bit 2 */
+	ALTERNATE_FUNCTIONS(13,     4,      3,      4, 0, 1, 2), /* GPIO13, altA altB and altC controlled by bit 3 and 4 */
+	ALTERNATE_FUNCTIONS(14,     5, UNUSED, UNUSED, 0, 0, 0), /* GPIO14, altA controlled by bit 5 */
+	ALTERNATE_FUNCTIONS(15,     6, UNUSED, UNUSED, 0, 0, 0), /* GPIO15, altA controlled by bit 6 */
+	ALTERNATE_FUNCTIONS(16,     7, UNUSED, UNUSED, 0, 0, 0), /* GPIO16, altA controlled by bit 7 */
+	/*
+	 * pins 17 to 20 are special case, only bit 0 is used to select
+	 * alternate function for these 4 pins.
+	 * bits 1 to 3 are reserved
+	 */
+	ALTERNATE_FUNCTIONS(17,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO17, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(18,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO18, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(19,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO19, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(20,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO20, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(21,      4, UNUSED, UNUSED, 0, 0, 0), /* GPIO21, altA controlled by bit 4 */
+	ALTERNATE_FUNCTIONS(22,      5, UNUSED, UNUSED, 0, 0, 0), /* GPIO22, altA controlled by bit 5 */
+	ALTERNATE_FUNCTIONS(23,      6, UNUSED, UNUSED, 0, 0, 0), /* GPIO23, altA controlled by bit 6 */
+	ALTERNATE_FUNCTIONS(24,      7, UNUSED, UNUSED, 0, 0, 0), /* GPIO24, altA controlled by bit 7 */
+
+	ALTERNATE_FUNCTIONS(25,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO25, altA controlled by bit 0 */
+	/* pin 26 special case, no alternate function, bit 1 reserved */
+	ALTERNATE_FUNCTIONS(26, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* GPIO26 */
+	ALTERNATE_FUNCTIONS(27,      2, UNUSED, UNUSED, 0, 0, 0), /* GPIO27, altA controlled by bit 2 */
+	ALTERNATE_FUNCTIONS(28,      3, UNUSED, UNUSED, 0, 0, 0), /* GPIO28, altA controlled by bit 3 */
+	ALTERNATE_FUNCTIONS(29,      4, UNUSED, UNUSED, 0, 0, 0), /* GPIO29, altA controlled by bit 4 */
+	ALTERNATE_FUNCTIONS(30,      5, UNUSED, UNUSED, 0, 0, 0), /* GPIO30, altA controlled by bit 5 */
+	ALTERNATE_FUNCTIONS(31,      6, UNUSED, UNUSED, 0, 0, 0), /* GPIO31, altA controlled by bit 6 */
+	ALTERNATE_FUNCTIONS(32,      7, UNUSED, UNUSED, 0, 0, 0), /* GPIO32, altA controlled by bit 7 */
+
+	ALTERNATE_FUNCTIONS(33, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO33 */
+	ALTERNATE_FUNCTIONS(34,      1, UNUSED, UNUSED, 0, 0, 0), /* GPIO34, altA controlled by bit 1 */
+	/* pin 35 special case, no alternate function, bit 2 reserved */
+	ALTERNATE_FUNCTIONS(35, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* GPIO35 */
+	ALTERNATE_FUNCTIONS(36,      3, UNUSED, UNUSED, 0, 0, 0), /* GPIO36, altA controlled by bit 3 */
+	ALTERNATE_FUNCTIONS(37,      4, UNUSED, UNUSED, 0, 0, 0), /* GPIO37, altA controlled by bit 4 */
+	ALTERNATE_FUNCTIONS(38,      5, UNUSED, UNUSED, 0, 0, 0), /* GPIO38, altA controlled by bit 5 */
+	ALTERNATE_FUNCTIONS(39,      6, UNUSED, UNUSED, 0, 0, 0), /* GPIO39, altA controlled by bit 6 */
+	ALTERNATE_FUNCTIONS(40,      7, UNUSED, UNUSED, 0, 0, 0), /* GPIO40, altA controlled by bit 7 */
+
+	ALTERNATE_FUNCTIONS(41,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO41, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(42,      1, UNUSED, UNUSED, 0, 0, 0), /* GPIO42, altA controlled by bit 1 */
+};
+
+/*
+ * Only some GPIOs are interrupt capable, and they are
+ * organized in discontiguous clusters:
+ *
+ *	GPIO6 to GPIO13
+ *	GPIO24 and GPIO25
+ *	GPIO36 to GPIO41
+ */
+struct abx500_gpio_irq_cluster ab8500_gpio_irq_cluster[] = {
+	GPIO_IRQ_CLUSTER(5, 12, 0), /* GPIO numbers start from 1 */
+	GPIO_IRQ_CLUSTER(23, 24, 0),
+	GPIO_IRQ_CLUSTER(35, 40, 0),
+};
+
+static struct abx500_pinctrl_soc_data ab8500_ranges_soc = {
+	.gpio_ranges = ab8500_pinranges,
+	.gpio_num_ranges = ARRAY_SIZE(ab8500_pinranges),
+	.pins = ab8500_ranges_pins,
+	.npins = ARRAY_SIZE(ab8500_ranges_pins),
+	.functions = ab8500_ranges_functions,
+	.nfunctions = ARRAY_SIZE(ab8500_ranges_functions),
+	.groups = ab8500_ranges_groups,
+	.ngroups = ARRAY_SIZE(ab8500_ranges_groups),
+	.alternate_functions = ab8500_alternate_functions,
+	.gpio_irq_cluster = ab8500_gpio_irq_cluster,
+	.ngpio_irq_cluster = ARRAY_SIZE(ab8500_gpio_irq_cluster),
+	.irq_gpio_rising_offset = AB8500_INT_GPIO6R,
+	.irq_gpio_falling_offset = AB8500_INT_GPIO6F,
+	.irq_gpio_factor = 1,
+};
+
+void __devinit
+abx500_pinctrl_ab8500_init(struct abx500_pinctrl_soc_data **soc)
+{
+	*soc = &ab8500_ranges_soc;
+}
-- 
1.7.11.3

^ permalink raw reply related

* [PATCH 1/6] arm: mvebu: Add support for USB host controllers in Armada 370/XP
From: Ezequiel Garcia @ 2013-01-15  9:54 UTC (permalink / raw)
  To: linux-arm-kernel

The Armada 370 and Armada XP SoC has an Orion EHCI USB controller.
This patch adds support for this controller in Armada 370
and Armada XP SoC common device tree files.

Cc: Lior Amsalem <alior@marvell.com>
Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
 arch/arm/boot/dts/armada-370-xp.dtsi |   15 +++++++++++++++
 arch/arm/boot/dts/armada-370.dtsi    |    9 +++++++++
 arch/arm/boot/dts/armada-xp.dtsi     |   17 +++++++++++++++++
 arch/arm/mach-mvebu/Kconfig          |    1 +
 4 files changed, 42 insertions(+), 0 deletions(-)

diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi b/arch/arm/boot/dts/armada-370-xp.dtsi
index 28276fe..fa025c4 100644
--- a/arch/arm/boot/dts/armada-370-xp.dtsi
+++ b/arch/arm/boot/dts/armada-370-xp.dtsi
@@ -145,6 +145,21 @@
 			clocks = <&gateclk 17>;
 			status = "disabled";
 		};
+
+		usb at d0050000 {
+			compatible = "marvell,orion-ehci";
+			reg = <0xd0050000 0x500>;
+			interrupts = <45>;
+			status = "disabled";
+		};
+
+		usb at d0051000 {
+			compatible = "marvell,orion-ehci";
+			reg = <0xd0051000 0x500>;
+			interrupts = <46>;
+			status = "disabled";
+		};
+
 	};
 };
 
diff --git a/arch/arm/boot/dts/armada-370.dtsi b/arch/arm/boot/dts/armada-370.dtsi
index 88f9bab..8188d13 100644
--- a/arch/arm/boot/dts/armada-370.dtsi
+++ b/arch/arm/boot/dts/armada-370.dtsi
@@ -144,5 +144,14 @@
 				dmacap,memset;
 			};
 		};
+
+		usb at d0050000 {
+			clocks = <&coreclk 0>;
+		};
+
+		usb at d0051000 {
+			clocks = <&coreclk 0>;
+		};
+
 	};
 };
diff --git a/arch/arm/boot/dts/armada-xp.dtsi b/arch/arm/boot/dts/armada-xp.dtsi
index 390ba98..1443949 100644
--- a/arch/arm/boot/dts/armada-xp.dtsi
+++ b/arch/arm/boot/dts/armada-xp.dtsi
@@ -134,5 +134,22 @@
 				dmacap,memset;
 			};
 		};
+
+		usb at d0050000 {
+			clocks = <&gateclk 18>;
+		};
+
+		usb at d0051000 {
+			clocks = <&gateclk 19>;
+		};
+
+		usb at d0052000 {
+			compatible = "marvell,orion-ehci";
+			reg = <0xd0052000 0x500>;
+			interrupts = <47>;
+			clocks = <&gateclk 20>;
+			status = "disabled";
+		};
+
 	};
 };
diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig
index 440b13e..5e4fcde 100644
--- a/arch/arm/mach-mvebu/Kconfig
+++ b/arch/arm/mach-mvebu/Kconfig
@@ -24,6 +24,7 @@ config MACH_ARMADA_370_XP
 	select HAVE_SMP
 	select CACHE_L2X0
 	select CPU_PJ4B
+	select USB_ARCH_HAS_EHCI if USB_SUPPORT
 
 config MACH_ARMADA_370
 	bool "Marvell Armada 370 boards"
-- 
1.7.8.6

^ permalink raw reply related

* [PATCH 2/6] arm: mvebu: Enable USB controllers on Armada 370 evaluation board
From: Ezequiel Garcia @ 2013-01-15  9:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358243670-11935-1-git-send-email-ezequiel.garcia@free-electrons.com>

Cc: Lior Amsalem <alior@marvell.com>
Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: Gregory CLEMENT <gregory.clement@free-electrons.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
 arch/arm/boot/dts/armada-370-db.dts |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/arch/arm/boot/dts/armada-370-db.dts b/arch/arm/boot/dts/armada-370-db.dts
index 8e66a7c..3d93902 100644
--- a/arch/arm/boot/dts/armada-370-db.dts
+++ b/arch/arm/boot/dts/armada-370-db.dts
@@ -74,5 +74,13 @@
 			status = "disabled";
 			/* No CD or WP GPIOs */
 		};
+
+		usb at d0050000 {
+			status = "okay";
+		};
+
+		usb at d0051000 {
+			status = "okay";
+		};
 	};
 };
-- 
1.7.8.6

^ permalink raw reply related

* [PATCH 3/6] arm: mvebu: Enable USB controllers on Armada 370 Mirabox board
From: Ezequiel Garcia @ 2013-01-15  9:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358243670-11935-1-git-send-email-ezequiel.garcia@free-electrons.com>

Cc: Lior Amsalem <alior@marvell.com>
Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: Gregory CLEMENT <gregory.clement@free-electrons.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
 arch/arm/boot/dts/armada-370-mirabox.dts |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/arch/arm/boot/dts/armada-370-mirabox.dts b/arch/arm/boot/dts/armada-370-mirabox.dts
index 1864820..dd0c57d 100644
--- a/arch/arm/boot/dts/armada-370-mirabox.dts
+++ b/arch/arm/boot/dts/armada-370-mirabox.dts
@@ -62,5 +62,13 @@
 			 * Wifi/Bluetooth chip
 			 */
 		};
+
+		usb at d0050000 {
+			status = "okay";
+		};
+
+		usb at d0051000 {
+			status = "okay";
+		};
 	};
 };
-- 
1.7.8.6

^ permalink raw reply related

* [PATCH 4/6] arm: mvebu: Enable USB controllers on Armada XP evaluation board
From: Ezequiel Garcia @ 2013-01-15  9:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358243670-11935-1-git-send-email-ezequiel.garcia@free-electrons.com>

Cc: Lior Amsalem <alior@marvell.com>
Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: Gregory CLEMENT <gregory.clement@free-electrons.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
 arch/arm/boot/dts/armada-xp-db.dts |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/arch/arm/boot/dts/armada-xp-db.dts b/arch/arm/boot/dts/armada-xp-db.dts
index c7035c5..c84e1fe 100644
--- a/arch/arm/boot/dts/armada-xp-db.dts
+++ b/arch/arm/boot/dts/armada-xp-db.dts
@@ -97,5 +97,17 @@
 			status = "okay";
 			/* No CD or WP GPIOs */
 		};
+
+		usb at d0050000 {
+			status = "okay";
+		};
+
+		usb at d0051000 {
+			status = "okay";
+		};
+
+		usb at d0052000 {
+			status = "okay";
+		};
 	};
 };
-- 
1.7.8.6

^ permalink raw reply related

* [PATCH 5/6] arm: mvebu: Enable USB controllers on Armada XP OpenBlocks AX3-4 board
From: Ezequiel Garcia @ 2013-01-15  9:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358243670-11935-1-git-send-email-ezequiel.garcia@free-electrons.com>

Cc: Lior Amsalem <alior@marvell.com>
Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: Gregory CLEMENT <gregory.clement@free-electrons.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
 arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts |    9 +++++++++
 1 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts b/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts
index b24644f..55f5b6f 100644
--- a/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts
+++ b/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts
@@ -127,5 +127,14 @@
 			nr-ports = <2>;
 			status = "okay";
 		};
+		usb at d0050000 {
+			status = "okay";
+		};
+		usb at d0051000 {
+			status = "okay";
+		};
+		usb at d0052000 {
+			status = "okay";
+		};
 	};
 };
-- 
1.7.8.6

^ permalink raw reply related

* [PATCH 6/6] arm: mvebu: Update defconfig to select USB support
From: Ezequiel Garcia @ 2013-01-15  9:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358243670-11935-1-git-send-email-ezequiel.garcia@free-electrons.com>

Cc: Lior Amsalem <alior@marvell.com>
Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Cc: Gregory CLEMENT <gregory.clement@free-electrons.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
 arch/arm/configs/mvebu_defconfig |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/arch/arm/configs/mvebu_defconfig b/arch/arm/configs/mvebu_defconfig
index c3c6326..f8d0183 100644
--- a/arch/arm/configs/mvebu_defconfig
+++ b/arch/arm/configs/mvebu_defconfig
@@ -42,7 +42,10 @@ CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_DW=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
-# CONFIG_USB_SUPPORT is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
 CONFIG_MMC=y
 CONFIG_MMC_MVSDIO=y
 CONFIG_RTC_CLASS=y
-- 
1.7.8.6

^ permalink raw reply related

* [PATCH v5 06/14] KVM: ARM: Inject IRQs and FIQs from userspace
From: Gleb Natapov @ 2013-01-15  9:56 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130108183917.46302.55603.stgit@ubuntu>

On Tue, Jan 08, 2013 at 01:39:17PM -0500, Christoffer Dall wrote:
> From: Christoffer Dall <cdall@cs.columbia.edu>
> 
> All interrupt injection is now based on the VM ioctl KVM_IRQ_LINE.  This
> works semantically well for the GIC as we in fact raise/lower a line on
> a machine component (the gic).  The IOCTL uses the follwing struct.
> 
> struct kvm_irq_level {
> 	union {
> 		__u32 irq;     /* GSI */
> 		__s32 status;  /* not used for KVM_IRQ_LEVEL */
> 	};
> 	__u32 level;           /* 0 or 1 */
> };
> 
> ARM can signal an interrupt either at the CPU level, or at the in-kernel irqchip
CPU level interrupt should use KVM_INTERRUPT instead.

> (GIC), and for in-kernel irqchip can tell the GIC to use PPIs designated for
> specific cpus.  The irq field is interpreted like this:
> 
Haven't read about GIC yet. Is PPI an interrupt that device can send
directly to a specific CPU? Can we model that with irq routing like we do
for MSI?

>  ?bits:  | 31 ... 24 | 23  ... 16 | 15    ...    0 |
>   field: | irq_type  | vcpu_index |   irq_number   |
> 
> The irq_type field has the following values:
> - irq_type[0]: out-of-kernel GIC: irq_number 0 is IRQ, irq_number 1 is FIQ
> - irq_type[1]: in-kernel GIC: SPI, irq_number between 32 and 1019 (incl.)
>                (the vcpu_index field is ignored)
> - irq_type[2]: in-kernel GIC: PPI, irq_number between 16 and 31 (incl.)
> 
> The irq_number thus corresponds to the irq ID in as in the GICv2 specs.
> 
> This is documented in Documentation/kvm/api.txt.
> 
> Reviewed-by: Marcelo Tosatti <mtosatti@redhat.com>
> Signed-off-by: Christoffer Dall <c.dall@virtualopensystems.com>
> ---
>  Documentation/virtual/kvm/api.txt |   25 ++++++++++++--
>  arch/arm/include/asm/kvm_arm.h    |    1 +
>  arch/arm/include/uapi/asm/kvm.h   |   21 ++++++++++++
>  arch/arm/kvm/arm.c                |   65 +++++++++++++++++++++++++++++++++++++
>  arch/arm/kvm/trace.h              |   25 ++++++++++++++
>  include/uapi/linux/kvm.h          |    1 +
>  6 files changed, 134 insertions(+), 4 deletions(-)
> 
> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> index 4237c27..5050492 100644
> --- a/Documentation/virtual/kvm/api.txt
> +++ b/Documentation/virtual/kvm/api.txt
> @@ -615,15 +615,32 @@ created.
>  4.25 KVM_IRQ_LINE
>  
>  Capability: KVM_CAP_IRQCHIP
> -Architectures: x86, ia64
> +Architectures: x86, ia64, arm
>  Type: vm ioctl
>  Parameters: struct kvm_irq_level
>  Returns: 0 on success, -1 on error
>  
>  Sets the level of a GSI input to the interrupt controller model in the kernel.
> -Requires that an interrupt controller model has been previously created with
> -KVM_CREATE_IRQCHIP.  Note that edge-triggered interrupts require the level
> -to be set to 1 and then back to 0.
> +On some architectures it is required that an interrupt controller model has
> +been previously created with KVM_CREATE_IRQCHIP.  Note that edge-triggered
> +interrupts require the level to be set to 1 and then back to 0.
> +
> +ARM can signal an interrupt either at the CPU level, or at the in-kernel irqchip
> +(GIC), and for in-kernel irqchip can tell the GIC to use PPIs designated for
> +specific cpus.  The irq field is interpreted like this:
> +
> + ?bits:  | 31 ... 24 | 23  ... 16 | 15    ...    0 |
> +  field: | irq_type  | vcpu_index |     irq_id     |
> +
> +The irq_type field has the following values:
> +- irq_type[0]: out-of-kernel GIC: irq_id 0 is IRQ, irq_id 1 is FIQ
> +- irq_type[1]: in-kernel GIC: SPI, irq_id between 32 and 1019 (incl.)
> +               (the vcpu_index field is ignored)
> +- irq_type[2]: in-kernel GIC: PPI, irq_id between 16 and 31 (incl.)
> +
> +(The irq_id field thus corresponds nicely to the IRQ ID in the ARM GIC specs)
> +
> +In both cases, level is used to raise/lower the line.
>  
>  struct kvm_irq_level {
>  	union {
> diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h
> index 613afe2..fb22ee8 100644
> --- a/arch/arm/include/asm/kvm_arm.h
> +++ b/arch/arm/include/asm/kvm_arm.h
> @@ -68,6 +68,7 @@
>  #define HCR_GUEST_MASK (HCR_TSC | HCR_TSW | HCR_TWI | HCR_VM | HCR_BSU_IS | \
>  			HCR_FB | HCR_TAC | HCR_AMO | HCR_IMO | HCR_FMO | \
>  			HCR_SWIO | HCR_TIDCP)
> +#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
>  
>  /* Hyp System Control Register (HSCTLR) bits */
>  #define HSCTLR_TE	(1 << 30)
> diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
> index c6298b1..4cf6d8f 100644
> --- a/arch/arm/include/uapi/asm/kvm.h
> +++ b/arch/arm/include/uapi/asm/kvm.h
> @@ -23,6 +23,7 @@
>  #include <asm/ptrace.h>
>  
>  #define __KVM_HAVE_GUEST_DEBUG
> +#define __KVM_HAVE_IRQ_LINE
>  
>  #define KVM_REG_SIZE(id)						\
>  	(1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT))
> @@ -103,4 +104,24 @@ struct kvm_arch_memory_slot {
>  #define KVM_REG_ARM_CORE		(0x0010 << KVM_REG_ARM_COPROC_SHIFT)
>  #define KVM_REG_ARM_CORE_REG(name)	(offsetof(struct kvm_regs, name) / 4)
>  
> +/* KVM_IRQ_LINE irq field index values */
> +#define KVM_ARM_IRQ_TYPE_SHIFT		24
> +#define KVM_ARM_IRQ_TYPE_MASK		0xff
> +#define KVM_ARM_IRQ_VCPU_SHIFT		16
> +#define KVM_ARM_IRQ_VCPU_MASK		0xff
> +#define KVM_ARM_IRQ_NUM_SHIFT		0
> +#define KVM_ARM_IRQ_NUM_MASK		0xffff
> +
> +/* irq_type field */
> +#define KVM_ARM_IRQ_TYPE_CPU		0
> +#define KVM_ARM_IRQ_TYPE_SPI		1
> +#define KVM_ARM_IRQ_TYPE_PPI		2
> +
> +/* out-of-kernel GIC cpu interrupt injection irq_number field */
> +#define KVM_ARM_IRQ_CPU_IRQ		0
> +#define KVM_ARM_IRQ_CPU_FIQ		1
> +
> +/* Highest supported SPI, from VGIC_NR_IRQS */
> +#define KVM_ARM_IRQ_GIC_MAX		127
> +
>  #endif /* __ARM_KVM_H__ */
> diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
> index ab82039..9b4566e 100644
> --- a/arch/arm/kvm/arm.c
> +++ b/arch/arm/kvm/arm.c
> @@ -24,6 +24,7 @@
>  #include <linux/fs.h>
>  #include <linux/mman.h>
>  #include <linux/sched.h>
> +#include <linux/kvm.h>
>  #include <trace/events/kvm.h>
>  
>  #define CREATE_TRACE_POINTS
> @@ -284,6 +285,7 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
>  
>  void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
>  {
> +	vcpu->cpu = cpu;
>  }
>  
>  void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
> @@ -324,6 +326,69 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  	return -EINVAL;
>  }
>  
> +static int vcpu_interrupt_line(struct kvm_vcpu *vcpu, int number, bool level)
> +{
> +	int bit_index;
> +	bool set;
> +	unsigned long *ptr;
> +
> +	if (number == KVM_ARM_IRQ_CPU_IRQ)
> +		bit_index = __ffs(HCR_VI);
> +	else /* KVM_ARM_IRQ_CPU_FIQ */
> +		bit_index = __ffs(HCR_VF);
> +
> +	ptr = (unsigned long *)&vcpu->arch.irq_lines;
> +	if (level)
> +		set = test_and_set_bit(bit_index, ptr);
> +	else
> +		set = test_and_clear_bit(bit_index, ptr);
> +
> +	/*
> +	 * If we didn't change anything, no need to wake up or kick other CPUs
> +	 */
> +	if (set == level)
> +		return 0;
> +
> +	/*
> +	 * The vcpu irq_lines field was updated, wake up sleeping VCPUs and
> +	 * trigger a world-switch round on the running physical CPU to set the
> +	 * virtual IRQ/FIQ fields in the HCR appropriately.
> +	 */
> +	kvm_vcpu_kick(vcpu);
> +
> +	return 0;
> +}
> +
> +int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level)
> +{
> +	u32 irq = irq_level->irq;
> +	unsigned int irq_type, vcpu_idx, irq_num;
> +	int nrcpus = atomic_read(&kvm->online_vcpus);
> +	struct kvm_vcpu *vcpu = NULL;
> +	bool level = irq_level->level;
> +
> +	irq_type = (irq >> KVM_ARM_IRQ_TYPE_SHIFT) & KVM_ARM_IRQ_TYPE_MASK;
> +	vcpu_idx = (irq >> KVM_ARM_IRQ_VCPU_SHIFT) & KVM_ARM_IRQ_VCPU_MASK;
> +	irq_num = (irq >> KVM_ARM_IRQ_NUM_SHIFT) & KVM_ARM_IRQ_NUM_MASK;
> +
> +	trace_kvm_irq_line(irq_type, vcpu_idx, irq_num, irq_level->level);
> +
> +	if (irq_type != KVM_ARM_IRQ_TYPE_CPU)
> +		return -EINVAL;
> +
> +	if (vcpu_idx >= nrcpus)
> +		return -EINVAL;
> +
> +	vcpu = kvm_get_vcpu(kvm, vcpu_idx);
> +	if (!vcpu)
> +		return -EINVAL;
> +
> +	if (irq_num > KVM_ARM_IRQ_CPU_FIQ)
> +		return -EINVAL;
> +
> +	return vcpu_interrupt_line(vcpu, irq_num, level);
> +}
> +
>  long kvm_arch_vcpu_ioctl(struct file *filp,
>  			 unsigned int ioctl, unsigned long arg)
>  {
> diff --git a/arch/arm/kvm/trace.h b/arch/arm/kvm/trace.h
> index 862b2cc..105d1f7 100644
> --- a/arch/arm/kvm/trace.h
> +++ b/arch/arm/kvm/trace.h
> @@ -39,6 +39,31 @@ TRACE_EVENT(kvm_exit,
>  	TP_printk("PC: 0x%08lx", __entry->vcpu_pc)
>  );
>  
> +TRACE_EVENT(kvm_irq_line,
> +	TP_PROTO(unsigned int type, int vcpu_idx, int irq_num, int level),
> +	TP_ARGS(type, vcpu_idx, irq_num, level),
> +
> +	TP_STRUCT__entry(
> +		__field(	unsigned int,	type		)
> +		__field(	int,		vcpu_idx	)
> +		__field(	int,		irq_num		)
> +		__field(	int,		level		)
> +	),
> +
> +	TP_fast_assign(
> +		__entry->type		= type;
> +		__entry->vcpu_idx	= vcpu_idx;
> +		__entry->irq_num	= irq_num;
> +		__entry->level		= level;
> +	),
> +
> +	TP_printk("Inject %s interrupt (%d), vcpu->idx: %d, num: %d, level: %d",
> +		  (__entry->type == KVM_ARM_IRQ_TYPE_CPU) ? "CPU" :
> +		  (__entry->type == KVM_ARM_IRQ_TYPE_PPI) ? "VGIC PPI" :
> +		  (__entry->type == KVM_ARM_IRQ_TYPE_SPI) ? "VGIC SPI" : "UNKNOWN",
> +		  __entry->type, __entry->vcpu_idx, __entry->irq_num, __entry->level)
> +);
> +
>  TRACE_EVENT(kvm_unmap_hva,
>  	TP_PROTO(unsigned long hva),
>  	TP_ARGS(hva),
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index 24978d5..dc63665 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -115,6 +115,7 @@ struct kvm_irq_level {
>  	 * ACPI gsi notion of irq.
>  	 * For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47..
>  	 * For X86 (standard AT mode) PIC0/1: irq 0-15. IOAPIC0: 0-23..
> +	 * For ARM: See Documentation/virtual/kvm/api.txt
>  	 */
>  	union {
>  		__u32 irq;
> 
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
			Gleb.

^ permalink raw reply

* [PATCH 0/6] arm: mvebu: Add support for USB host controllers in Armada 370/XP
From: Ezequiel Garcia @ 2013-01-15  9:59 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

This small patch set enables USB support on Armada 370 and Armada XP platforms.
It's based on Jason Cooper's mvebu/dt branch.

Any comments or feedback are welcome.

Ezequiel Garcia (6):
 arm: mvebu: Add support for USB host controllers in Armada 370/XP
 arm: mvebu: Enable USB controllers on Armada 370 evaluation board
 arm: mvebu: Enable USB controllers on Armada 370 Mirabox board
 arm: mvebu: Enable USB controllers on Armada XP evaluation board
 arm: mvebu: Enable USB controllers on Armada XP OpenBlocks AX3-4 board
 arm: mvebu: Update defconfig to select USB support

 arch/arm/boot/dts/armada-370-db.dts              |    8 ++++++++
 arch/arm/boot/dts/armada-370-mirabox.dts         |    8 ++++++++
 arch/arm/boot/dts/armada-370-xp.dtsi             |   15 +++++++++++++++
 arch/arm/boot/dts/armada-370.dtsi                |    9 +++++++++
 arch/arm/boot/dts/armada-xp-db.dts               |   12 ++++++++++++
 arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts |    9 +++++++++
 arch/arm/boot/dts/armada-xp.dtsi                 |   17 +++++++++++++++++
 arch/arm/configs/mvebu_defconfig                 |    5 ++++-
 arch/arm/mach-mvebu/Kconfig                      |    1 +
 9 files changed, 83 insertions(+), 1 deletions(-)
 
Thanks!

-- 
Ezequiel Garc?a, Free Electrons
Embedded Linux, Kernel and Android Engineering
http://free-electrons.com

^ permalink raw reply

* [PATCH v5 6/9] ARM: davinci: Remoteproc driver support for OMAP-L138 DSP
From: Ohad Ben-Cohen @ 2013-01-15 10:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <13514BD7FAEBA745BBD7D8A672905C14311FE538@DFLE08.ent.ti.com>

Hi Rob,

On Sat, Jan 12, 2013 at 4:26 AM, Tivy, Robert <rtivy@ti.com> wrote:
> Is FW_CONFIG above supposed to be FW_LOADER?

That FW_CONFIG is completely bogus of course. care to fix it in your series?

> We're currently handling the CHIPINT lines as "level"s, since they're completely controlled by SW.  The interruptor raises the line and the interruptee lowers (clears) it.  In a situation where every interrupt is considered to be a signal of new data arrival we need to make sure that the other side has "seen" the previous interrupt before we raise another one.

What if we don't ? Can the DSP side just go over the vrings until no
new msg is left (similar to what you do on the Linux side) ?

> Is this suggesting that there be separate platform device instances for each different potential fw, and that each platform device instance hardcodes the fw filename?

In principle this same driver can drive many instances of remote
processors you may have on your board. E.g. in OMAP the same driver
controls both the M3s and the DSP. pdata is then used to hold
information specific to the hw instance.

I'm not sure if there's (or will be) any DaVinci platform with several
remote processors but it's a better practice to write the code as if
there is/will be - it's usually cleaner and will just work in case a
platform with multiple rprocs does show up one day.

> Sekhar asked that there not be a default fw name, so there's conflicting feedback on this point.  I prefer to have a default name plus the module parameter override (but don't have much opinion on whether it should be davinci-specific (and passed with davinci_remoteproc.ko) or general (and passed with remoteproc.ko), please advise).
>
> Since the fw file (i.e., DSP program) is typically paired with a particular Linux app, I like the ability to specify the fw filename at runtime, depending on the Linux app I need to run.

Sure, no reason why not to allow users to override the default fw name.

Thanks,
Ohad.

^ permalink raw reply

* [PATCH v2] arch/arm/mach-s5pv210: adding ifdef CONFIG_CPU_S5PV210 to fix compiling issue
From: Chen Gang @ 2013-01-15 10:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <50EAC016.6090707@asianux.com>

Hello kgene.kim

  when you have free time, please give a glance for this patch.

  I sent it according to script/get_maintainter.pl.
  if I sent to an incorrect member, please tell me, thanks.


  Regards

gchen.


? 2013?01?07? 20:31, Chen Gang ??:
> 
>   if not define CONFIG_CPU_S5PV210
> 
>     it will define NULL in common.h for:
>       s5pv210_map_io, s5pv210_init_clocks, s5pv210_init, s5pv210_init_uarts
> 
>     so need using #ifdef CONFIG_CPU_S5PV210 for them too, in common.c.
>       or compiling issue will occur.
> 
> 
> Signed-off-by: Chen Gang <gang.chen@asianux.com>
> ---
>  arch/arm/mach-s5pv210/common.c |    9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/arch/arm/mach-s5pv210/common.c b/arch/arm/mach-s5pv210/common.c
> index 9dfe93e..5c88f88 100644
> --- a/arch/arm/mach-s5pv210/common.c
> +++ b/arch/arm/mach-s5pv210/common.c
> @@ -167,6 +167,8 @@ void __init s5pv210_init_io(struct map_desc *mach_desc, int size)
>  	s3c_init_cpu(samsung_cpu_id, cpu_ids, ARRAY_SIZE(cpu_ids));
>  }
>  
> +#ifdef CONFIG_CPU_S5PV210
> +
>  void __init s5pv210_map_io(void)
>  {
>  	/* initialise device information early */
> @@ -209,6 +211,9 @@ void __init s5pv210_init_clocks(int xtal)
>  	s5pv210_setup_clocks();
>  }
>  
> +#endif /* CONFIG_CPU_S5PV210 */
> +
> +
>  void __init s5pv210_init_irq(void)
>  {
>  	u32 vic[4];	/* S5PV210 supports 4 VIC */
> @@ -227,6 +232,8 @@ struct bus_type s5pv210_subsys = {
>  	.dev_name	= "s5pv210-core",
>  };
>  
> +#ifdef CONFIG_CPU_S5PV210
> +
>  static struct device s5pv210_dev = {
>  	.bus	= &s5pv210_subsys,
>  };
> @@ -249,3 +256,5 @@ void __init s5pv210_init_uarts(struct s3c2410_uartcfg *cfg, int no)
>  {
>  	s3c24xx_init_uartdevs("s5pv210-uart", s5p_uart_resources, cfg, no);
>  }
> +
> +#endif /* CONFIG_CPU_S5PV210 */
> 


-- 
Chen Gang

Asianux Corporation

^ permalink raw reply

* [PATCH v5 6/9] ARM: davinci: Remoteproc driver support for OMAP-L138 DSP
From: Ohad Ben-Cohen @ 2013-01-15 10:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <50F51E43.2090605@ti.com>

On Tue, Jan 15, 2013 at 11:15 AM, Sekhar Nori <nsekhar@ti.com> wrote:
> Right, and platform data is not the way to achieve this.

How do you suggest to handle platforms with multiple different remote
processors (driven by the same driver) ?

Requiring the user to indicate the fw name for each processor is
somewhat error prone/cumbersome.

Thanks,
Ohad.

^ permalink raw reply

* [PATCHv3 0/7] Add pinctrl driver for Allwinner A1X SoCs
From: Maxime Ripard @ 2013-01-15 10:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1357681398-23956-1-git-send-email-maxime.ripard@free-electrons.com>

Hi Linus,

On 08/01/2013 22:43, Maxime Ripard wrote:
> Hi everyone,
> 
> This patch set adds a pinctrl driver for the IP found in the Allwinner A10
> and A13, and the SoC-specific bits for the A13. It also adds the documentation
> for the device tree bindings.
> 
> This patch set has been tested on a Olimex A13-Olinuxino.
> 
> Thanks,
> Maxime

Are you ok with this version or do you have additionnal comments ?

Thanks,
Maxime

-- 
Maxime Ripard, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

^ permalink raw reply

* [PATCH 1/6] arm: mvebu: Add support for USB host controllers in Armada 370/XP
From: Florian Fainelli @ 2013-01-15 10:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358243670-11935-1-git-send-email-ezequiel.garcia@free-electrons.com>

Hello Ezequiel,

Le 01/15/13 10:54, Ezequiel Garcia a ?crit :
> diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig
> index 440b13e..5e4fcde 100644
> --- a/arch/arm/mach-mvebu/Kconfig
> +++ b/arch/arm/mach-mvebu/Kconfig
> @@ -24,6 +24,7 @@ config MACH_ARMADA_370_XP
>   	select HAVE_SMP
>   	select CACHE_L2X0
>   	select CPU_PJ4B
> +	select USB_ARCH_HAS_EHCI if USB_SUPPORT

I do not think this is actually required because ARCH_MVEBU selects 
PLAT_ORION and in drivers/usb/host/Kconfig, USB_ARCH_HAS_EHCI is default 
y if PLAT_ORION. Having USB_ARCH_HAS_EHCI without USB_SUPPORT enabled is 
pretty harmless.
--
Florian

^ permalink raw reply

* [PATCHv2 04/11] arm: arch_timer: standardise counter reading
From: Mark Rutland @ 2013-01-15 10:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <50F01255.4060805@ti.com>

On Fri, Jan 11, 2013 at 01:23:33PM +0000, Santosh Shilimkar wrote:
> On Wednesday 09 January 2013 09:37 PM, Mark Rutland wrote:
> > We're currently inconsistent with respect to our accesses to the
> > physical and virtual counters, mixing and matching the two.
> >
> > This patch introduces and uses a function for accessing the correct
> > counter based on whether we're using physical or virtual interrupts.
> > All current accesses to the counter accessors are redirected through
> > it.
> >
> > Signed-off-by: Mark Rutland <mark.rutland@arm.com>
> > Acked-by: Catalin Marinas <catalin.marinas@arm.com>
> > Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> > ---
> >   arch/arm/kernel/arch_timer.c |   48 ++++++++++-------------------------------
> >   1 files changed, 12 insertions(+), 36 deletions(-)
> >
> > diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
> > index 498c29f..0d2681c 100644
> > --- a/arch/arm/kernel/arch_timer.c
> > +++ b/arch/arm/kernel/arch_timer.c
> > @@ -272,51 +272,32 @@ static int arch_timer_available(void)
> >   	return 0;
> >   }
> >
> > -static u32 notrace arch_counter_get_cntpct32(void)
> > +u64 arch_timer_read_counter(void)
> >   {
> > -	cycle_t cnt = arch_counter_get_cntpct();
> > -
> > -	/*
> > -	 * The sched_clock infrastructure only knows about counters
> > -	 * with at most 32bits. Forget about the upper 24 bits for the
> > -	 * time being...
> > -	 */
> > -	return (u32)cnt;
> > +	if (arch_timer_use_virtual)
> > +		return arch_counter_get_cntvct();
> > +	else
> > +		return arch_counter_get_cntpct();
> >   }
> >
> 
> [...]
> 
> > @@ -489,18 +470,13 @@ int __init arch_timer_of_register(void)
> >
> >   int __init arch_timer_sched_clock_init(void)
> >   {
> > -	u32 (*cnt32)(void);
> >   	int err;
> >
> >   	err = arch_timer_available();
> >   	if (err)
> >   		return err;
> >
> > -	if (arch_timer_use_virtual)
> > -		cnt32 = arch_counter_get_cntvct32;
> > -	else
> > -		cnt32 = arch_counter_get_cntpct32;
> > -
> > -	setup_sched_clock(cnt32, 32, arch_timer_rate);
> > +	setup_sched_clock(arch_timer_read_counter32,
> > +			  32, arch_timer_rate);
> >   	return 0;
> >   }
> >
> I think the original idea had merit since the check was needed
> in init code instead of proposed one which has if check for
> every counter read function. No ?
> 

The original idea was good in that it avoided the check on each read path, but
in several places the logic got duplicated (e.g. for choosing which
width-altering wrapper in the above block). I'd like ensure this logic is
consolidated.

I'll change arch_timer_read_counter to a function pointer, and set this in
arch_timer_of_register before registering anything. Everything would still be
indirected through it, but it won't have to do a check on every read.

Thanks,
Mark.

^ permalink raw reply

* [PATCH 1/1] clk-divider: fix is_power_of_two()
From: James Hogan @ 2013-01-15 10:28 UTC (permalink / raw)
  To: linux-arm-kernel

The macro is_power_of_two() in clk-divider.c was defined as !(i & ~i)
which is always true. Correct it to !(i & (i - 1)).

Also add brackets around the macro arguments in div_mask and
is_power_of_two, as well as around the is_power_of_two expression as a
whole to avoid any future operator precedence problems.

Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Mike Turquette <mturquette@linaro.org>
---
I haven't tested this other than with a couple of compile time asserts.

 drivers/clk/clk-divider.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index a9204c6..13bca0c 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -29,8 +29,8 @@
 
 #define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
 
-#define div_mask(d)	((1 << (d->width)) - 1)
-#define is_power_of_two(i)	!(i & ~i)
+#define div_mask(d)	((1 << ((d)->width)) - 1)
+#define is_power_of_two(i)	(!((i) & ((i) - 1)))
 
 static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
 {
-- 
1.7.7.6

^ permalink raw reply related

* [PATCH v5 04/12] ARM: KVM: Initial VGIC infrastructure code
From: Marc Zyngier @ 2013-01-15 10:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CANM98q+y4GoHmqh-CS+fDnfbDbBQHQOY05urer5DMgy9b1X5ng@mail.gmail.com>

On 14/01/13 21:08, Christoffer Dall wrote:
> On Mon, Jan 14, 2013 at 10:31 AM, Will Deacon <will.deacon@arm.com> wrote:

>> As I mentioned previously, I suspect that this doesn't work with big-endian
>> systems. Whilst that's reasonable for the moment, a comment would be useful
>> for the unlucky soul that decides to do that work in future (or add
>> accessors for mmio->data as I suggested before).
>>
> admittedly this really hurts my brain, but I think there's actually no
> problem with endianness: whatever comes in mmio->data will have native
> endianness and the vgic is always little-endian, so a guest would have
> to make sure to do its own endianness conversion before writing data,
> or did I get this backwards? (some nasty feeling about if the OS is
> compiled in another endianness than the hardware everything may
> break).
> 
> Anyhow, I think there's another bug in this code though. Please take a
> look and see if you agree:
> 
> commit 3cab2b93a6f6acd3c043e584f23b94ab8f1bbd66
> Author: Christoffer Dall <c.dall@virtualopensystems.com>
> Date:   Mon Jan 14 15:55:18 2013 -0500
> 
>     KVM: ARM: Limit vgic read/writes to load/store length
> 
>     The vgic read/write operations did not consider ldrb/strb masks, and
>     would therefore unintentionally overwrite parts of a register.
> 
>     Consider for example a store of a single byte to a word-aligned address
>     of one of the priority registers, that would cause the 3 most
>     significant bytes to be overwritten with zeros.
> 
>     Cc: Marc Zyniger <marc.zyngier@arm.com>
>     Cc: Will Deacon <will.deacon@arm.com>
>     Signed-off-by: Christoffer Dall <c.dall@virtualopensystems.com>

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

> 
> diff --git a/arch/arm/kvm/vgic.c b/arch/arm/kvm/vgic.c
> index 25daa07..5c1bcf5 100644
> --- a/arch/arm/kvm/vgic.c
> +++ b/arch/arm/kvm/vgic.c
> @@ -233,6 +233,16 @@ static void vgic_cpu_irq_clear(struct kvm_vcpu
> *vcpu, int irq)
>  			  vcpu->arch.vgic_cpu.pending_shared);
>  }
> 
> +static u32 mmio_data_read(struct kvm_exit_mmio *mmio, u32 mask)
> +{
> +	return *((u32 *)mmio->data) & mask;
> +}
> +
> +static void mmio_data_write(struct kvm_exit_mmio *mmio, u32 mask, u32 value)
> +{
> +	*((u32 *)mmio->data) = value & mask;
> +}
> +
>  /**
>   * vgic_reg_access - access vgic register
>   * @mmio:   pointer to the data describing the mmio access
> @@ -247,8 +257,8 @@ static void vgic_cpu_irq_clear(struct kvm_vcpu
> *vcpu, int irq)
>  static void vgic_reg_access(struct kvm_exit_mmio *mmio, u32 *reg,
>  			    phys_addr_t offset, int mode)
>  {
> -	int shift = (offset & 3) * 8;
> -	u32 mask;
> +	int word_offset = (offset & 3) * 8;
> +	u32 mask = (1UL << (mmio->len * 8)) - 1;
>  	u32 regval;
> 
>  	/*
> @@ -256,7 +266,6 @@ static void vgic_reg_access(struct kvm_exit_mmio
> *mmio, u32 *reg,
>  	 * directly (ARM ARM B3.12.7 "Prioritization of aborts").
>  	 */
> 
> -	mask = (~0U) >> shift;
>  	if (reg) {
>  		regval = *reg;
>  	} else {
> @@ -265,7 +274,7 @@ static void vgic_reg_access(struct kvm_exit_mmio
> *mmio, u32 *reg,
>  	}
> 
>  	if (mmio->is_write) {
> -		u32 data = (*((u32 *)mmio->data) & mask) << shift;
> +		u32 data = mmio_data_read(mmio, mask) << word_offset;
>  		switch (ACCESS_WRITE_MASK(mode)) {
>  		case ACCESS_WRITE_IGNORED:
>  			return;
> @@ -279,7 +288,7 @@ static void vgic_reg_access(struct kvm_exit_mmio
> *mmio, u32 *reg,
>  			break;
> 
>  		case ACCESS_WRITE_VALUE:
> -			regval = (regval & ~(mask << shift)) | data;
> +			regval = (regval & ~(mask << word_offset)) | data;
>  			break;
>  		}
>  		*reg = regval;
> @@ -290,7 +299,7 @@ static void vgic_reg_access(struct kvm_exit_mmio
> *mmio, u32 *reg,
>  			/* fall through */
> 
>  		case ACCESS_READ_VALUE:
> -			*((u32 *)mmio->data) = (regval >> shift) & mask;
> +			mmio_data_write(mmio, mask, regval >> word_offset);
>  		}
>  	}
>  }
> @@ -702,6 +711,12 @@ bool vgic_handle_mmio(struct kvm_vcpu *vcpu,
> struct kvm_run *run,
>  	    (mmio->phys_addr + mmio->len) > (base + KVM_VGIC_V2_DIST_SIZE))
>  		return false;
> 
> +	/* We don't support ldrd / strd or ldm / stm to the emulated vgic */
> +	if (mmio->len > 4) {
> +		kvm_inject_dabt(vcpu, mmio->phys_addr);
> +		return true;
> +	}
> +
>  	range = find_matching_range(vgic_ranges, mmio, base);
>  	if (unlikely(!range || !range->handle_mmio)) {
>  		pr_warn("Unhandled access %d %08llx %d\n",
> --
> 
> Thanks,
> -Christoffer
> 


-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply

* [PATCH V2 3/3] ARM: davinci: da850: add NAND driver entries
From: Kumar, Anil @ 2013-01-15 10:36 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <50EEB1C1.9060306@ti.com>

On Thu, Jan 10, 2013 at 17:49:13, Nori, Sekhar wrote:
> On 1/10/2013 1:07 PM, Kumar, Anil wrote:
> > On Wed, Jan 09, 2013 at 18:17:46, Nori, Sekhar wrote:
> 
> > I do not think that it is good idea to move NAND pin mux information
> > into da850.dtsi because this information is evm specific.
> > if we will use this approach then we must use the same approach for
> > other modules also as ASoC etc.   
> 
> Why do you consider this EVM specific. IOW, which pins do you see
> changing on another board? BTW, if there are additional pins needed than
> what are listed, we can always add more pinux entries in the .dts files.
> The pins present in dtsi file should the base case.
 
Ok, we can use this approach for DaVinci as its SoC modules do not
have multiple pin configuration option. I will do the changes in 
next patch series.

Thanks,
Anil

^ permalink raw reply

* [PATCHv2 04/11] arm: arch_timer: standardise counter reading
From: Santosh Shilimkar @ 2013-01-15 10:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130115102519.GG7990@e106331-lin.cambridge.arm.com>

On Tuesday 15 January 2013 03:55 PM, Mark Rutland wrote:
> On Fri, Jan 11, 2013 at 01:23:33PM +0000, Santosh Shilimkar wrote:
>> On Wednesday 09 January 2013 09:37 PM, Mark Rutland wrote:
>>> We're currently inconsistent with respect to our accesses to the
>>> physical and virtual counters, mixing and matching the two.
>>>
>>> This patch introduces and uses a function for accessing the correct
>>> counter based on whether we're using physical or virtual interrupts.
>>> All current accesses to the counter accessors are redirected through
>>> it.
>>>
>>> Signed-off-by: Mark Rutland <mark.rutland@arm.com>
>>> Acked-by: Catalin Marinas <catalin.marinas@arm.com>
>>> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
>>> ---
>>>    arch/arm/kernel/arch_timer.c |   48 ++++++++++-------------------------------
>>>    1 files changed, 12 insertions(+), 36 deletions(-)
>>>
>>> diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
>>> index 498c29f..0d2681c 100644
>>> --- a/arch/arm/kernel/arch_timer.c
>>> +++ b/arch/arm/kernel/arch_timer.c
>>> @@ -272,51 +272,32 @@ static int arch_timer_available(void)
>>>    	return 0;
>>>    }
>>>
>>> -static u32 notrace arch_counter_get_cntpct32(void)
>>> +u64 arch_timer_read_counter(void)
>>>    {
>>> -	cycle_t cnt = arch_counter_get_cntpct();
>>> -
>>> -	/*
>>> -	 * The sched_clock infrastructure only knows about counters
>>> -	 * with at most 32bits. Forget about the upper 24 bits for the
>>> -	 * time being...
>>> -	 */
>>> -	return (u32)cnt;
>>> +	if (arch_timer_use_virtual)
>>> +		return arch_counter_get_cntvct();
>>> +	else
>>> +		return arch_counter_get_cntpct();
>>>    }
>>>
>>
>> [...]
>>
>>> @@ -489,18 +470,13 @@ int __init arch_timer_of_register(void)
>>>
>>>    int __init arch_timer_sched_clock_init(void)
>>>    {
>>> -	u32 (*cnt32)(void);
>>>    	int err;
>>>
>>>    	err = arch_timer_available();
>>>    	if (err)
>>>    		return err;
>>>
>>> -	if (arch_timer_use_virtual)
>>> -		cnt32 = arch_counter_get_cntvct32;
>>> -	else
>>> -		cnt32 = arch_counter_get_cntpct32;
>>> -
>>> -	setup_sched_clock(cnt32, 32, arch_timer_rate);
>>> +	setup_sched_clock(arch_timer_read_counter32,
>>> +			  32, arch_timer_rate);
>>>    	return 0;
>>>    }
>>>
>> I think the original idea had merit since the check was needed
>> in init code instead of proposed one which has if check for
>> every counter read function. No ?
>>
>
> The original idea was good in that it avoided the check on each read path, but
> in several places the logic got duplicated (e.g. for choosing which
> width-altering wrapper in the above block). I'd like ensure this logic is
> consolidated.
>
> I'll change arch_timer_read_counter to a function pointer, and set this in
> arch_timer_of_register before registering anything. Everything would still be
> indirected through it, but it won't have to do a check on every read.
>
Sounds good

^ permalink raw reply

* [PATCH 0/2] ARM: Exynos5 : Add Power domain device tree support for MFC and GSC
From: Prasanna Kumar @ 2013-01-15 10:47 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1357733733-18769-1-git-send-email-prasanna.ps@samsung.com>

Hello all,

Any comments for this patch set ?

On Wed, Jan 9, 2013 at 5:45 PM, Prasanna Kumar <prasanna.ps@samsung.com>wrote:

> Hello all,
>
> This patch set adds device tree support for power domains (Gscaler and
> MFC) of exynos5
>
> Prasanna Kumar (2):
>   arm: exynos5: Enable PM generic domain support in Kconfig
>   ARM: dts: exynos5: Set up power domain for  MFC and G-scaler
>
>  arch/arm/boot/dts/exynos5250.dtsi |   15 +++++++++++++++
>  arch/arm/mach-exynos/Kconfig      |    1 +
>  2 files changed, 16 insertions(+), 0 deletions(-)
>
> --
> 1.7.5.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe
> linux-samsung-soc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>



-- 
Thanks
Prasanna Kumar
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130115/95ecf67f/attachment-0001.html>

^ permalink raw reply

* [PATCH 1/6] arm: mvebu: Add support for USB host controllers in Armada 370/XP
From: Ezequiel Garcia @ 2013-01-15 10:49 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <50F52E1F.8010702@openwrt.org>

Hi Florian,

On 01/15/2013 07:23 AM, Florian Fainelli wrote:
> Le 01/15/13 10:54, Ezequiel Garcia a ?crit :
>> diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig
>> index 440b13e..5e4fcde 100644
>> --- a/arch/arm/mach-mvebu/Kconfig
>> +++ b/arch/arm/mach-mvebu/Kconfig
>> @@ -24,6 +24,7 @@ config MACH_ARMADA_370_XP
>>       select HAVE_SMP
>>       select CACHE_L2X0
>>       select CPU_PJ4B
>> +    select USB_ARCH_HAS_EHCI if USB_SUPPORT
> 
> I do not think this is actually required because ARCH_MVEBU selects PLAT_ORION and in drivers/usb/host/Kconfig, USB_ARCH_HAS_EHCI is default y if PLAT_ORION. Having USB_ARCH_HAS_EHCI without USB_SUPPORT enabled is pretty harmless.

Yes, you're right, this is not needed.

Nice catch and thanks for the review,

-- 
Ezequiel Garc?a, Free Electrons
Embedded Linux, Kernel and Android Engineering
http://free-electrons.com

^ permalink raw reply

* Early kernel hang with big DTB appended
From: Sascha Hauer @ 2013-01-15 10:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <alpine.LFD.2.02.1301141655570.6300@xanadu.home>

On Mon, Jan 14, 2013 at 05:13:09PM -0500, Nicolas Pitre wrote:
> On Fri, 11 Jan 2013, Sascha Hauer wrote:
> 
> > On Thu, Jan 03, 2013 at 04:55:00PM +0100, Tomasz Figa wrote:
> > > Hi,
> > > 
> > > I'm observing strange behavior when booting 3.8-rc1 and -rc2 with appended 
> > > DTB. The kernel hangs very early when the DTB is bigger than some 
> > > threshold somewhere around 24 KiB. With fullest possible low level UART 
> > > debugging (and printk patched to use printascii) I'm receiving following 
> > > output:
> > > 
> > > Uncompressing Linux... done, booting the kernel.
> > > Booting Linux on physical CPU 0xa00
> > > Linux version 3.8.0-rc1-00073-gdf6efca-dirty (t.figa at amdc1227) (gcc 
> > > version 4.5.2 (Gentoo 4.5.2 p1.2, pie-0.4.5) ) #2 SMP PREEMPT Thu Jan 3 
> > > 15:37:35 CET 2013
> > > CPU: ARMv7 Processor [413fc090] revision 0 (ARMv7), cr=10c53c7d
> > > CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
> > > 
> > > I tested on two Exynos-based boards (exynos4210-trats and one internal 
> > > exynos4412-based board) and same happens on both.
> > > 
> > > Do you have any ideas?
> > 
> > Another thing besides the things already mentioned is that the dtb may
> > not cross a 1MiB boundary. The Kernel uses a single 1Mib section
> > (aligned to 1Mib) to initially map the dtb. Once you cross that boundary
> > parts of the dtb won't be accessible for the Kernel anymore.
> 
> Crap.  You're right.  This patch should fix this issue.

Just successfully tested with a devicetree explicitly located just before a 1MiB
boundary, so:

Tested-by: Sascha Hauer <s.hauer@pengutronix.de>

Sascha

> 
> @Tomasz: please could you confirm this fixes your initial problem?
> 
> 
> diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
> index 4eee351f46..61fcb18c7e 100644
> --- a/arch/arm/kernel/head.S
> +++ b/arch/arm/kernel/head.S
> @@ -246,6 +246,7 @@ __create_page_tables:
>  
>  	/*
>  	 * Then map boot params address in r2 if specified.
> +	 * We map 2 sections in case the ATAGs/DTB crosses a section boundary.
>  	 */
>  	mov	r0, r2, lsr #SECTION_SHIFT
>  	movs	r0, r0, lsl #SECTION_SHIFT
> @@ -253,6 +254,8 @@ __create_page_tables:
>  	addne	r3, r3, #PAGE_OFFSET
>  	addne	r3, r4, r3, lsr #(SECTION_SHIFT - PMD_ORDER)
>  	orrne	r6, r7, r0
> +	strne	r6, [r3], #1 << PMD_ORDER
> +	addne	r6, r6, #1 << SECTION_SHIFT
>  	strne	r6, [r3]
>  
>  #ifdef CONFIG_DEBUG_LL
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply

* [PATCH v5 07/12] ARM: KVM: VGIC virtual CPU interface management
From: Marc Zyngier @ 2013-01-15 11:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CANM98qJ_Pb5bT0k7bAhv6i1YTj6GxvNE6vvY49OZrqsKpF3xOA@mail.gmail.com>

On 14/01/13 22:02, Christoffer Dall wrote:
> On Mon, Jan 14, 2013 at 10:42 AM, Will Deacon <will.deacon@arm.com> wrote:
>> On Tue, Jan 08, 2013 at 06:42:11PM +0000, Christoffer Dall wrote:
>>> From: Marc Zyngier <marc.zyngier@arm.com>
>>>
>>> Add VGIC virtual CPU interface code, picking pending interrupts
>>> from the distributor and stashing them in the VGIC control interface
>>> list registers.
>>>
>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>> Signed-off-by: Christoffer Dall <c.dall@virtualopensystems.com>
>>> ---
>>>  arch/arm/include/asm/kvm_vgic.h |   30 ++++
>>>  arch/arm/kvm/vgic.c             |  327 +++++++++++++++++++++++++++++++++++++++
>>>  2 files changed, 356 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/arch/arm/include/asm/kvm_vgic.h b/arch/arm/include/asm/kvm_vgic.h
>>> index 9ff0d9c..b3133c4 100644
>>> --- a/arch/arm/include/asm/kvm_vgic.h
>>> +++ b/arch/arm/include/asm/kvm_vgic.h
>>> @@ -110,8 +110,33 @@ struct vgic_dist {
>>>  };
>>>
>>>  struct vgic_cpu {
>>> +#ifdef CONFIG_KVM_ARM_VGIC
>>> +       /* per IRQ to LR mapping */
>>> +       u8              vgic_irq_lr_map[VGIC_NR_IRQS];
>>> +
>>> +       /* Pending interrupts on this VCPU */
>>> +       DECLARE_BITMAP( pending_percpu, VGIC_NR_PRIVATE_IRQS);
>>> +       DECLARE_BITMAP( pending_shared, VGIC_NR_SHARED_IRQS);
>>> +
>>> +       /* Bitmap of used/free list registers */
>>> +       DECLARE_BITMAP( lr_used, 64);
>>> +
>>> +       /* Number of list registers on this CPU */
>>> +       int             nr_lr;
>>> +
>>> +       /* CPU vif control registers for world switch */
>>> +       u32             vgic_hcr;
>>> +       u32             vgic_vmcr;
>>> +       u32             vgic_misr;      /* Saved only */
>>> +       u32             vgic_eisr[2];   /* Saved only */
>>> +       u32             vgic_elrsr[2];  /* Saved only */
>>> +       u32             vgic_apr;
>>> +       u32             vgic_lr[64];    /* A15 has only 4... */
>>
>> Have a #define for the maximum number of list registers.
>>
>>> +#endif
>>>  };
>>>
>>> +#define LR_EMPTY       0xff
>>> +
>>>  struct kvm;
>>>  struct kvm_vcpu;
>>>  struct kvm_run;
>>> @@ -119,9 +144,14 @@ struct kvm_exit_mmio;
>>>
>>>  #ifdef CONFIG_KVM_ARM_VGIC
>>>  int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr);
>>> +void kvm_vgic_sync_to_cpu(struct kvm_vcpu *vcpu);
>>> +void kvm_vgic_sync_from_cpu(struct kvm_vcpu *vcpu);
>>
>> Same comment as for the arch timer (flush/sync).
>>
>>> +int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
>>>  bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run,
>>>                       struct kvm_exit_mmio *mmio);
>>>
>>> +#define irqchip_in_kernel(k)   (!!((k)->arch.vgic.vctrl_base))
>>> +
>>>  #else
>>>  static inline int kvm_vgic_hyp_init(void)
>>>  {
>>> diff --git a/arch/arm/kvm/vgic.c b/arch/arm/kvm/vgic.c
>>> index bd2bd7f..58237d5 100644
>>> --- a/arch/arm/kvm/vgic.c
>>> +++ b/arch/arm/kvm/vgic.c
>>> @@ -152,6 +152,34 @@ static int vgic_irq_is_enabled(struct kvm_vcpu *vcpu, int irq)
>>>         return vgic_bitmap_get_irq_val(&dist->irq_enabled, vcpu->vcpu_id, irq);
>>>  }
>>>
>>> +static int vgic_irq_is_active(struct kvm_vcpu *vcpu, int irq)
>>> +{
>>> +       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>>> +
>>> +       return vgic_bitmap_get_irq_val(&dist->irq_active, vcpu->vcpu_id, irq);
>>> +}
>>> +
>>> +static void vgic_irq_set_active(struct kvm_vcpu *vcpu, int irq)
>>> +{
>>> +       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>>> +
>>> +       vgic_bitmap_set_irq_val(&dist->irq_active, vcpu->vcpu_id, irq, 1);
>>> +}
>>> +
>>> +static void vgic_irq_clear_active(struct kvm_vcpu *vcpu, int irq)
>>> +{
>>> +       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>>> +
>>> +       vgic_bitmap_set_irq_val(&dist->irq_active, vcpu->vcpu_id, irq, 0);
>>> +}
>>> +
>>> +static int vgic_dist_irq_is_pending(struct kvm_vcpu *vcpu, int irq)
>>> +{
>>> +       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>>> +
>>> +       return vgic_bitmap_get_irq_val(&dist->irq_state, vcpu->vcpu_id, irq);
>>> +}
>>> +
>>>  static void vgic_dist_irq_set(struct kvm_vcpu *vcpu, int irq)
>>>  {
>>>         struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>>> @@ -711,7 +739,30 @@ static void vgic_dispatch_sgi(struct kvm_vcpu *vcpu, u32 reg)
>>>
>>>  static int compute_pending_for_cpu(struct kvm_vcpu *vcpu)
>>>  {
>>> -       return 0;
>>> +       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>>> +       unsigned long *pending, *enabled, *pend_percpu, *pend_shared;
>>> +       unsigned long pending_private, pending_shared;
>>> +       int vcpu_id;
>>> +
>>> +       vcpu_id = vcpu->vcpu_id;
>>> +       pend_percpu = vcpu->arch.vgic_cpu.pending_percpu;
>>> +       pend_shared = vcpu->arch.vgic_cpu.pending_shared;
>>> +
>>> +       pending = vgic_bitmap_get_cpu_map(&dist->irq_state, vcpu_id);
>>> +       enabled = vgic_bitmap_get_cpu_map(&dist->irq_enabled, vcpu_id);
>>> +       bitmap_and(pend_percpu, pending, enabled, VGIC_NR_PRIVATE_IRQS);
>>> +
>>> +       pending = vgic_bitmap_get_shared_map(&dist->irq_state);
>>> +       enabled = vgic_bitmap_get_shared_map(&dist->irq_enabled);
>>> +       bitmap_and(pend_shared, pending, enabled, VGIC_NR_SHARED_IRQS);
>>> +       bitmap_and(pend_shared, pend_shared,
>>> +                  vgic_bitmap_get_shared_map(&dist->irq_spi_target[vcpu_id]),
>>> +                  VGIC_NR_SHARED_IRQS);
>>> +
>>> +       pending_private = find_first_bit(pend_percpu, VGIC_NR_PRIVATE_IRQS);
>>> +       pending_shared = find_first_bit(pend_shared, VGIC_NR_SHARED_IRQS);
>>> +       return (pending_private < VGIC_NR_PRIVATE_IRQS ||
>>> +               pending_shared < VGIC_NR_SHARED_IRQS);
>>>  }
>>>
>>>  /*
>>> @@ -737,6 +788,280 @@ static void vgic_update_state(struct kvm *kvm)
>>>         }
>>>  }
>>>
>>> +#define LR_CPUID(lr)   \
>>> +       (((lr) & GICH_LR_PHYSID_CPUID) >> GICH_LR_PHYSID_CPUID_SHIFT)
>>> +#define MK_LR_PEND(src, irq)   \
>>> +       (GICH_LR_PENDING_BIT | ((src) << GICH_LR_PHYSID_CPUID_SHIFT) | (irq))
>>> +/*
>>> + * Queue an interrupt to a CPU virtual interface. Return true on success,
>>> + * or false if it wasn't possible to queue it.
>>> + */
>>> +static bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
>>> +{
>>> +       struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>>> +       int lr;
>>> +
>>> +       /* Sanitize the input... */
>>> +       BUG_ON(sgi_source_id & ~7);
>>> +       BUG_ON(sgi_source_id && irq > 15);
>>
>> You can use your new NR_SGIS definition here.
>>
> 
> This should address the remaining comments:
> 
> commit 43957095ec5476beb198f4c4630dfc3e2f3951db
> Author: Christoffer Dall <c.dall@virtualopensystems.com>
> Date:   Mon Jan 14 16:59:38 2013 -0500
> 
>     KVM: ARM: vgic: Define VGIC_MAX_LRS
> 
>     Define maximum number of link registers we can handle instead of using
>     literals in the code.  If an architecture reports more link registers
>     than we support, only use the number we can support.
> 
>     Signed-off-by: Christoffer Dall <c.dall@virtualopensystems.com>
> 
> diff --git a/arch/arm/include/asm/kvm_vgic.h b/arch/arm/include/asm/kvm_vgic.h
> index 1ace491..f9d1977 100644
> --- a/arch/arm/include/asm/kvm_vgic.h
> +++ b/arch/arm/include/asm/kvm_vgic.h
> @@ -33,6 +33,7 @@
>  #define VGIC_NR_PRIVATE_IRQS	(VGIC_NR_SGIS + VGIC_NR_PPIS)
>  #define VGIC_NR_SHARED_IRQS	(VGIC_NR_IRQS - VGIC_NR_PRIVATE_IRQS)
>  #define VGIC_MAX_CPUS		KVM_MAX_VCPUS
> +#define VGIC_MAX_LRS		64

Consider this instead (for the reason below)
#define VGIC_MAX_LRS	(1 << 7)

>  /* Sanity checks... */
>  #if (VGIC_MAX_CPUS > 8)
> @@ -120,7 +121,7 @@ struct vgic_cpu {
>  	DECLARE_BITMAP(	pending_shared, VGIC_NR_SHARED_IRQS);
> 
>  	/* Bitmap of used/free list registers */
> -	DECLARE_BITMAP(	lr_used, 64);
> +	DECLARE_BITMAP(	lr_used, VGIC_MAX_LRS);
> 
>  	/* Number of list registers on this CPU */
>  	int		nr_lr;
> @@ -132,7 +133,7 @@ struct vgic_cpu {
>  	u32		vgic_eisr[2];	/* Saved only */
>  	u32		vgic_elrsr[2];	/* Saved only */
>  	u32		vgic_apr;
> -	u32		vgic_lr[64];	/* A15 has only 4... */
> +	u32		vgic_lr[VGIC_MAX_LRS];
>  #endif
>  };
> 
> diff --git a/arch/arm/kvm/vgic.c b/arch/arm/kvm/vgic.c
> index a0d283c..90a99fd 100644
> --- a/arch/arm/kvm/vgic.c
> +++ b/arch/arm/kvm/vgic.c
> @@ -1345,6 +1345,8 @@ int kvm_vgic_hyp_init(void)
> 
>  	vgic_nr_lr = readl_relaxed(vgic_vctrl_base + GICH_VTR);
>  	vgic_nr_lr = (vgic_nr_lr & 0x1f) + 1;

There is a bug here. It should be:
        vgic_nr_lr = (vgic_nr_lr & 0x2f) + 1;

> +	if (vgic_nr_lr > VGIC_MAX_LRS)
> +		vgic_nr_lr = VGIC_MAX_LRS; /* TODO: Clear remaining LRs */

Why? VGIC_MAX_LRS isn't a configurable value, but a maximum value
defined by the specification. This is the maximum you can fit in a 6 bit
field, plus one (1 << 7, exactly).

>  	ret = create_hyp_io_mappings(vgic_vctrl_base,
>  				     vgic_vctrl_base + resource_size(&vctrl_res),
> --
> 
> Thanks,
> -Christoffer
> 


-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox