Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCHv3 3/8] rtc: add STM32 RTC driver
From: Amelie Delaunay @ 2017-01-05 13:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1483623809-29937-1-git-send-email-amelie.delaunay@st.com>

This patch adds support for the STM32 RTC.

Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
---
 drivers/rtc/Kconfig     |  11 +
 drivers/rtc/Makefile    |   1 +
 drivers/rtc/rtc-stm32.c | 776 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 788 insertions(+)
 create mode 100644 drivers/rtc/rtc-stm32.c

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index e859d14..11eb28a 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1706,6 +1706,17 @@ config RTC_DRV_PIC32
 	   This driver can also be built as a module. If so, the module
 	   will be called rtc-pic32
 
+config RTC_DRV_STM32
+	tristate "STM32 RTC"
+	select REGMAP_MMIO
+	depends on ARCH_STM32 || COMPILE_TEST
+	help
+	   If you say yes here you get support for the STM32 On-Chip
+	   Real Time Clock.
+
+	   This driver can also be built as a module, if so, the module
+	   will be called "rtc-stm32".
+
 comment "HID Sensor RTC drivers"
 
 config RTC_DRV_HID_SENSOR_TIME
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 1ac694a..87bd9cc 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -144,6 +144,7 @@ obj-$(CONFIG_RTC_DRV_SNVS)	+= rtc-snvs.o
 obj-$(CONFIG_RTC_DRV_SPEAR)	+= rtc-spear.o
 obj-$(CONFIG_RTC_DRV_STARFIRE)	+= rtc-starfire.o
 obj-$(CONFIG_RTC_DRV_STK17TA8)	+= rtc-stk17ta8.o
+obj-$(CONFIG_RTC_DRV_STM32) 	+= rtc-stm32.o
 obj-$(CONFIG_RTC_DRV_STMP)	+= rtc-stmp3xxx.o
 obj-$(CONFIG_RTC_DRV_ST_LPC)	+= rtc-st-lpc.o
 obj-$(CONFIG_RTC_DRV_SUN4V)	+= rtc-sun4v.o
diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c
new file mode 100644
index 0000000..fdd3a31
--- /dev/null
+++ b/drivers/rtc/rtc-stm32.c
@@ -0,0 +1,776 @@
+/*
+ * Copyright (C) Amelie Delaunay 2016
+ * Author:  Amelie Delaunay <amelie.delaunay@st.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/bcd.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/ioport.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+#include <linux/spinlock.h>
+
+#define DRIVER_NAME "stm32_rtc"
+
+/* STM32 RTC registers */
+#define STM32_RTC_TR		0x00
+#define STM32_RTC_DR		0x04
+#define STM32_RTC_CR		0x08
+#define STM32_RTC_ISR		0x0C
+#define STM32_RTC_PRER		0x10
+#define STM32_RTC_ALRMAR	0x1C
+#define STM32_RTC_WPR		0x24
+
+/* STM32_RTC_TR bit fields  */
+#define STM32_RTC_TR_SEC_SHIFT		0
+#define STM32_RTC_TR_SEC		GENMASK(6, 0)
+#define STM32_RTC_TR_MIN_SHIFT		8
+#define STM32_RTC_TR_MIN		GENMASK(14, 8)
+#define STM32_RTC_TR_HOUR_SHIFT		16
+#define STM32_RTC_TR_HOUR		GENMASK(21, 16)
+
+/* STM32_RTC_DR bit fields */
+#define STM32_RTC_DR_DATE_SHIFT		0
+#define STM32_RTC_DR_DATE		GENMASK(5, 0)
+#define STM32_RTC_DR_MONTH_SHIFT	8
+#define STM32_RTC_DR_MONTH		GENMASK(12, 8)
+#define STM32_RTC_DR_WDAY_SHIFT		13
+#define STM32_RTC_DR_WDAY		GENMASK(15, 13)
+#define STM32_RTC_DR_YEAR_SHIFT		16
+#define STM32_RTC_DR_YEAR		GENMASK(23, 16)
+
+/* STM32_RTC_CR bit fields */
+#define STM32_RTC_CR_FMT		BIT(6)
+#define STM32_RTC_CR_ALRAE		BIT(8)
+#define STM32_RTC_CR_ALRAIE		BIT(12)
+
+/* STM32_RTC_ISR bit fields */
+#define STM32_RTC_ISR_ALRAWF		BIT(0)
+#define STM32_RTC_ISR_INITS		BIT(4)
+#define STM32_RTC_ISR_RSF		BIT(5)
+#define STM32_RTC_ISR_INITF		BIT(6)
+#define STM32_RTC_ISR_INIT		BIT(7)
+#define STM32_RTC_ISR_ALRAF		BIT(8)
+
+/* STM32_RTC_PRER bit fields */
+#define STM32_RTC_PRER_PRED_S_SHIFT	0
+#define STM32_RTC_PRER_PRED_S		GENMASK(14, 0)
+#define STM32_RTC_PRER_PRED_A_SHIFT	16
+#define STM32_RTC_PRER_PRED_A		GENMASK(22, 16)
+
+/* STM32_RTC_ALRMAR and STM32_RTC_ALRMBR bit fields */
+#define STM32_RTC_ALRMXR_SEC_SHIFT	0
+#define STM32_RTC_ALRMXR_SEC		GENMASK(6, 0)
+#define STM32_RTC_ALRMXR_SEC_MASK	BIT(7)
+#define STM32_RTC_ALRMXR_MIN_SHIFT	8
+#define STM32_RTC_ALRMXR_MIN		GENMASK(14, 8)
+#define STM32_RTC_ALRMXR_MIN_MASK	BIT(15)
+#define STM32_RTC_ALRMXR_HOUR_SHIFT	16
+#define STM32_RTC_ALRMXR_HOUR		GENMASK(21, 16)
+#define STM32_RTC_ALRMXR_PM		BIT(22)
+#define STM32_RTC_ALRMXR_HOUR_MASK	BIT(23)
+#define STM32_RTC_ALRMXR_DATE_SHIFT	24
+#define STM32_RTC_ALRMXR_DATE		GENMASK(29, 24)
+#define STM32_RTC_ALRMXR_WDSEL		BIT(30)
+#define STM32_RTC_ALRMXR_WDAY_SHIFT	24
+#define STM32_RTC_ALRMXR_WDAY		GENMASK(27, 24)
+#define STM32_RTC_ALRMXR_DATE_MASK	BIT(31)
+
+/* STM32_RTC_WPR key constants */
+#define RTC_WPR_1ST_KEY			0xCA
+#define RTC_WPR_2ND_KEY			0x53
+#define RTC_WPR_WRONG_KEY		0xFF
+
+/*
+ * RTC registers are protected agains parasitic write access.
+ * PWR_CR_DBP bit must be set to enable write access to RTC registers.
+ */
+/* STM32_PWR_CR */
+#define PWR_CR				0x00
+/* STM32_PWR_CR bit field */
+#define PWR_CR_DBP			BIT(8)
+
+static struct regmap *dbp;
+
+struct stm32_rtc {
+	struct rtc_device *rtc_dev;
+	void __iomem *base;
+	struct clk *ck_rtc;
+	spinlock_t lock; /* Protects registers accesses */
+	int irq_alarm;
+};
+
+static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc)
+{
+	writel_relaxed(RTC_WPR_1ST_KEY, rtc->base + STM32_RTC_WPR);
+	writel_relaxed(RTC_WPR_2ND_KEY, rtc->base + STM32_RTC_WPR);
+}
+
+static void stm32_rtc_wpr_lock(struct stm32_rtc *rtc)
+{
+	writel_relaxed(RTC_WPR_WRONG_KEY, rtc->base + STM32_RTC_WPR);
+}
+
+static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc)
+{
+	unsigned int isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
+
+	if (!(isr & STM32_RTC_ISR_INITF)) {
+		isr |= STM32_RTC_ISR_INIT;
+		writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
+
+		/*
+		 * It takes around 2 ck_rtc clock cycles to enter in
+		 * initialization phase mode (and have INITF flag set). As
+		 * slowest ck_rtc frequency may be 32kHz and highest should be
+		 * 1MHz, we poll every 10 us with a timeout of 100ms.
+		 */
+		return readl_relaxed_poll_timeout_atomic(
+					rtc->base + STM32_RTC_ISR,
+					isr, (isr & STM32_RTC_ISR_INITF),
+					10, 100000);
+	}
+
+	return 0;
+}
+
+static void stm32_rtc_exit_init_mode(struct stm32_rtc *rtc)
+{
+	unsigned int isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
+
+	isr &= ~STM32_RTC_ISR_INIT;
+	writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
+}
+
+static int stm32_rtc_wait_sync(struct stm32_rtc *rtc)
+{
+	unsigned int isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
+
+	isr &= ~STM32_RTC_ISR_RSF;
+	writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
+
+	/*
+	 * Wait for RSF to be set to ensure the calendar registers are
+	 * synchronised, it takes around 2 ck_rtc clock cycles
+	 */
+	return readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
+						 isr,
+						 (isr & STM32_RTC_ISR_RSF),
+						 10, 100000);
+}
+
+static irqreturn_t stm32_rtc_alarm_irq(int irq, void *dev_id)
+{
+	struct stm32_rtc *rtc = (struct stm32_rtc *)dev_id;
+	unsigned int isr, cr;
+
+	mutex_lock(&rtc->rtc_dev->ops_lock);
+
+	isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
+	cr = readl_relaxed(rtc->base + STM32_RTC_CR);
+
+	if ((isr & STM32_RTC_ISR_ALRAF) &&
+	    (cr & STM32_RTC_CR_ALRAIE)) {
+		/* Alarm A flag - Alarm interrupt */
+		dev_dbg(&rtc->rtc_dev->dev, "Alarm occurred\n");
+
+		/* Pass event to the kernel */
+		rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
+
+		/* Clear event flag, otherwise new events won't be received */
+		writel_relaxed(isr & ~STM32_RTC_ISR_ALRAF,
+			       rtc->base + STM32_RTC_ISR);
+	}
+
+	mutex_unlock(&rtc->rtc_dev->ops_lock);
+
+	return IRQ_HANDLED;
+}
+
+/* Convert rtc_time structure from bin to bcd format */
+static void tm2bcd(struct rtc_time *tm)
+{
+	tm->tm_sec = bin2bcd(tm->tm_sec);
+	tm->tm_min = bin2bcd(tm->tm_min);
+	tm->tm_hour = bin2bcd(tm->tm_hour);
+
+	tm->tm_mday = bin2bcd(tm->tm_mday);
+	tm->tm_mon = bin2bcd(tm->tm_mon + 1);
+	tm->tm_year = bin2bcd(tm->tm_year - 100);
+	/*
+	 * Number of days since Sunday
+	 * - on kernel side, 0=Sunday...6=Saturday
+	 * - on rtc side, 0=invalid,1=Monday...7=Sunday
+	 */
+	tm->tm_wday = (!tm->tm_wday) ? 7 : tm->tm_wday;
+}
+
+/* Convert rtc_time structure from bcd to bin format */
+static void bcd2tm(struct rtc_time *tm)
+{
+	tm->tm_sec = bcd2bin(tm->tm_sec);
+	tm->tm_min = bcd2bin(tm->tm_min);
+	tm->tm_hour = bcd2bin(tm->tm_hour);
+
+	tm->tm_mday = bcd2bin(tm->tm_mday);
+	tm->tm_mon = bcd2bin(tm->tm_mon) - 1;
+	tm->tm_year = bcd2bin(tm->tm_year) + 100;
+	/*
+	 * Number of days since Sunday
+	 * - on kernel side, 0=Sunday...6=Saturday
+	 * - on rtc side, 0=invalid,1=Monday...7=Sunday
+	 */
+	tm->tm_wday %= 7;
+}
+
+static int stm32_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct stm32_rtc *rtc = dev_get_drvdata(dev);
+	unsigned int tr, dr;
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&rtc->lock, irqflags);
+
+	/* Time and Date in BCD format */
+	tr = readl_relaxed(rtc->base + STM32_RTC_TR);
+	dr = readl_relaxed(rtc->base + STM32_RTC_DR);
+
+	spin_unlock_irqrestore(&rtc->lock, irqflags);
+
+	tm->tm_sec = (tr & STM32_RTC_TR_SEC) >> STM32_RTC_TR_SEC_SHIFT;
+	tm->tm_min = (tr & STM32_RTC_TR_MIN) >> STM32_RTC_TR_MIN_SHIFT;
+	tm->tm_hour = (tr & STM32_RTC_TR_HOUR) >> STM32_RTC_TR_HOUR_SHIFT;
+
+	tm->tm_mday = (dr & STM32_RTC_DR_DATE) >> STM32_RTC_DR_DATE_SHIFT;
+	tm->tm_mon = (dr & STM32_RTC_DR_MONTH) >> STM32_RTC_DR_MONTH_SHIFT;
+	tm->tm_year = (dr & STM32_RTC_DR_YEAR) >> STM32_RTC_DR_YEAR_SHIFT;
+	tm->tm_wday = (dr & STM32_RTC_DR_WDAY) >> STM32_RTC_DR_WDAY_SHIFT;
+
+	/* We don't report tm_yday and tm_isdst */
+
+	bcd2tm(tm);
+
+	if (rtc_valid_tm(tm) < 0) {
+		dev_err(dev, "%s: rtc_time is not valid.\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int stm32_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct stm32_rtc *rtc = dev_get_drvdata(dev);
+	unsigned int tr, dr;
+	unsigned long irqflags;
+	int ret = 0;
+
+	if (rtc_valid_tm(tm) < 0) {
+		dev_err(dev, "%s: rtc_time is not valid.\n", __func__);
+		return -EINVAL;
+	}
+
+	tm2bcd(tm);
+
+	/* Time in BCD format */
+	tr = ((tm->tm_sec << STM32_RTC_TR_SEC_SHIFT) & STM32_RTC_TR_SEC) |
+	     ((tm->tm_min << STM32_RTC_TR_MIN_SHIFT) & STM32_RTC_TR_MIN) |
+	     ((tm->tm_hour << STM32_RTC_TR_HOUR_SHIFT) & STM32_RTC_TR_HOUR);
+
+	/* Date in BCD format */
+	dr = ((tm->tm_mday << STM32_RTC_DR_DATE_SHIFT) & STM32_RTC_DR_DATE) |
+	     ((tm->tm_mon << STM32_RTC_DR_MONTH_SHIFT) & STM32_RTC_DR_MONTH) |
+	     ((tm->tm_year << STM32_RTC_DR_YEAR_SHIFT) & STM32_RTC_DR_YEAR) |
+	     ((tm->tm_wday << STM32_RTC_DR_WDAY_SHIFT) & STM32_RTC_DR_WDAY);
+
+	spin_lock_irqsave(&rtc->lock, irqflags);
+
+	stm32_rtc_wpr_unlock(rtc);
+
+	ret = stm32_rtc_enter_init_mode(rtc);
+	if (ret) {
+		dev_err(dev, "Can't enter in init mode. Set time aborted.\n");
+		goto end;
+	}
+
+	writel_relaxed(tr, rtc->base + STM32_RTC_TR);
+	writel_relaxed(dr, rtc->base + STM32_RTC_DR);
+
+	stm32_rtc_exit_init_mode(rtc);
+
+	ret = stm32_rtc_wait_sync(rtc);
+end:
+	stm32_rtc_wpr_lock(rtc);
+
+	spin_unlock_irqrestore(&rtc->lock, irqflags);
+
+	return ret;
+}
+
+static int stm32_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct stm32_rtc *rtc = dev_get_drvdata(dev);
+	struct rtc_time *tm = &alrm->time;
+	unsigned int alrmar, cr, isr;
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&rtc->lock, irqflags);
+
+	alrmar = readl_relaxed(rtc->base + STM32_RTC_ALRMAR);
+	cr = readl_relaxed(rtc->base + STM32_RTC_CR);
+	isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
+
+	spin_unlock_irqrestore(&rtc->lock, irqflags);
+
+	if (alrmar & STM32_RTC_ALRMXR_DATE_MASK) {
+		/*
+		 * Date/day doesn't matter in Alarm comparison so alarm
+		 * triggers every day
+		 */
+		tm->tm_mday = -1;
+		tm->tm_wday = -1;
+	} else {
+		if (alrmar & STM32_RTC_ALRMXR_WDSEL) {
+			/* Alarm is set to a day of week */
+			tm->tm_mday = -1;
+			tm->tm_wday = (alrmar & STM32_RTC_ALRMXR_WDAY) >>
+				      STM32_RTC_ALRMXR_WDAY_SHIFT;
+			tm->tm_wday %= 7;
+		} else {
+			/* Alarm is set to a day of month */
+			tm->tm_wday = -1;
+			tm->tm_mday = (alrmar & STM32_RTC_ALRMXR_DATE) >>
+				       STM32_RTC_ALRMXR_DATE_SHIFT;
+		}
+	}
+
+	if (alrmar & STM32_RTC_ALRMXR_HOUR_MASK) {
+		/* Hours don't matter in Alarm comparison */
+		tm->tm_hour = -1;
+	} else {
+		tm->tm_hour = (alrmar & STM32_RTC_ALRMXR_HOUR) >>
+			       STM32_RTC_ALRMXR_HOUR_SHIFT;
+		if (alrmar & STM32_RTC_ALRMXR_PM)
+			tm->tm_hour += 12;
+	}
+
+	if (alrmar & STM32_RTC_ALRMXR_MIN_MASK) {
+		/* Minutes don't matter in Alarm comparison */
+		tm->tm_min = -1;
+	} else {
+		tm->tm_min = (alrmar & STM32_RTC_ALRMXR_MIN) >>
+			      STM32_RTC_ALRMXR_MIN_SHIFT;
+	}
+
+	if (alrmar & STM32_RTC_ALRMXR_SEC_MASK) {
+		/* Seconds don't matter in Alarm comparison */
+		tm->tm_sec = -1;
+	} else {
+		tm->tm_sec = (alrmar & STM32_RTC_ALRMXR_SEC) >>
+			      STM32_RTC_ALRMXR_SEC_SHIFT;
+	}
+
+	bcd2tm(tm);
+
+	alrm->enabled = (cr & STM32_RTC_CR_ALRAE) ? 1 : 0;
+	alrm->pending = (isr & STM32_RTC_ISR_ALRAF) ? 1 : 0;
+
+	return 0;
+}
+
+static int stm32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+	struct stm32_rtc *rtc = dev_get_drvdata(dev);
+	unsigned long irqflags;
+	unsigned int isr, cr;
+
+	spin_lock_irqsave(&rtc->lock, irqflags);
+
+	cr = readl_relaxed(rtc->base + STM32_RTC_CR);
+
+	stm32_rtc_wpr_unlock(rtc);
+
+	/* We expose Alarm A to the kernel */
+	if (enabled)
+		cr |= (STM32_RTC_CR_ALRAIE | STM32_RTC_CR_ALRAE);
+	else
+		cr &= ~(STM32_RTC_CR_ALRAIE | STM32_RTC_CR_ALRAE);
+	writel_relaxed(cr, rtc->base + STM32_RTC_CR);
+
+	/* Clear event irqflags, otherwise new events won't be received */
+	isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
+	isr &= ~STM32_RTC_ISR_ALRAF;
+	writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
+
+	stm32_rtc_wpr_lock(rtc);
+
+	spin_unlock_irqrestore(&rtc->lock, irqflags);
+
+	return 0;
+}
+
+static int stm32_rtc_valid_alrm(struct stm32_rtc *rtc, struct rtc_time *tm)
+{
+	unsigned int cur_day, cur_mon, cur_year, cur_hour, cur_min, cur_sec;
+	unsigned int dr = readl_relaxed(rtc->base + STM32_RTC_DR);
+	unsigned int tr = readl_relaxed(rtc->base + STM32_RTC_TR);
+
+	cur_day = (dr & STM32_RTC_DR_DATE) >> STM32_RTC_DR_DATE_SHIFT;
+	cur_mon = (dr & STM32_RTC_DR_MONTH) >> STM32_RTC_DR_MONTH_SHIFT;
+	cur_year = (dr & STM32_RTC_DR_YEAR) >> STM32_RTC_DR_YEAR_SHIFT;
+	cur_sec = (tr & STM32_RTC_TR_SEC) >> STM32_RTC_TR_SEC_SHIFT;
+	cur_min = (tr & STM32_RTC_TR_MIN) >> STM32_RTC_TR_MIN_SHIFT;
+	cur_hour = (tr & STM32_RTC_TR_HOUR) >> STM32_RTC_TR_HOUR_SHIFT;
+
+	/*
+	 * Assuming current date is M-D-Y H:M:S.
+	 * RTC alarm can't be set on a specific month and year.
+	 * So the valid alarm range is:
+	 *	M-D-Y H:M:S < alarm <= (M+1)-D-Y H:M:S
+	 * with a specific case for December...
+	 */
+	if ((((tm->tm_year > cur_year) &&
+	      (tm->tm_mon == 0x1) && (cur_mon == 0x12)) ||
+	     ((tm->tm_year == cur_year) &&
+	      (tm->tm_mon <= cur_mon + 1))) &&
+	    ((tm->tm_mday < cur_day) ||
+	     ((tm->tm_mday == cur_day) &&
+	     ((tm->tm_hour < cur_hour) ||
+	      ((tm->tm_hour == cur_hour) && (tm->tm_min < cur_min)) ||
+	      ((tm->tm_hour == cur_hour) && (tm->tm_min == cur_min) &&
+	       (tm->tm_sec <= cur_sec))))))
+		return 0;
+
+	return -EINVAL;
+}
+
+static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct stm32_rtc *rtc = dev_get_drvdata(dev);
+	struct rtc_time *tm = &alrm->time;
+	unsigned long irqflags;
+	unsigned int cr, isr, alrmar;
+	int ret = 0;
+
+	if (rtc_valid_tm(tm)) {
+		dev_err(dev, "Alarm time not valid.\n");
+		return -EINVAL;
+	}
+
+	tm2bcd(tm);
+
+	/*
+	 * RTC alarm can't be set on a specific date, unless this date is
+	 * up to the same day of month next month.
+	 */
+	if (stm32_rtc_valid_alrm(rtc, tm) < 0) {
+		dev_err(dev, "Alarm can be set only on upcoming month.\n");
+		return -EINVAL;
+	}
+
+	alrmar = 0;
+	/* tm_year and tm_mon are not used because not supported by RTC */
+	alrmar |= (tm->tm_mday << STM32_RTC_ALRMXR_DATE_SHIFT) &
+		  STM32_RTC_ALRMXR_DATE;
+	/* 24-hour format */
+	alrmar &= ~STM32_RTC_ALRMXR_PM;
+	alrmar |= (tm->tm_hour << STM32_RTC_ALRMXR_HOUR_SHIFT) &
+		  STM32_RTC_ALRMXR_HOUR;
+	alrmar |= (tm->tm_min << STM32_RTC_ALRMXR_MIN_SHIFT) &
+		  STM32_RTC_ALRMXR_MIN;
+	alrmar |= (tm->tm_sec << STM32_RTC_ALRMXR_SEC_SHIFT) &
+		  STM32_RTC_ALRMXR_SEC;
+
+	spin_lock_irqsave(&rtc->lock, irqflags);
+
+	stm32_rtc_wpr_unlock(rtc);
+
+	/* Disable Alarm */
+	cr = readl_relaxed(rtc->base + STM32_RTC_CR);
+	cr &= ~STM32_RTC_CR_ALRAE;
+	writel_relaxed(cr, rtc->base + STM32_RTC_CR);
+
+	/*
+	 * Poll Alarm write flag to be sure that Alarm update is allowed: it
+	 * takes around 2 ck_rtc clock cycles
+	 */
+	ret = readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
+						isr,
+						(isr & STM32_RTC_ISR_ALRAWF),
+						10, 100000);
+
+	if (ret) {
+		dev_err(dev, "Alarm update not allowed\n");
+		goto end;
+	}
+
+	/* Write to Alarm register */
+	writel_relaxed(alrmar, rtc->base + STM32_RTC_ALRMAR);
+
+	if (alrm->enabled)
+		stm32_rtc_alarm_irq_enable(dev, 1);
+	else
+		stm32_rtc_alarm_irq_enable(dev, 0);
+
+end:
+	stm32_rtc_wpr_lock(rtc);
+
+	spin_unlock_irqrestore(&rtc->lock, irqflags);
+
+	return ret;
+}
+
+static const struct rtc_class_ops stm32_rtc_ops = {
+	.read_time	= stm32_rtc_read_time,
+	.set_time	= stm32_rtc_set_time,
+	.read_alarm	= stm32_rtc_read_alarm,
+	.set_alarm	= stm32_rtc_set_alarm,
+	.alarm_irq_enable = stm32_rtc_alarm_irq_enable,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id stm32_rtc_of_match[] = {
+	{ .compatible = "st,stm32-rtc" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, stm32_rtc_of_match);
+#endif
+
+static int stm32_rtc_init(struct platform_device *pdev,
+			  struct stm32_rtc *rtc)
+{
+	unsigned int prer, pred_a, pred_s, pred_a_max, pred_s_max, cr;
+	unsigned int rate;
+	unsigned long irqflags;
+	int ret = 0;
+
+	rate = clk_get_rate(rtc->ck_rtc);
+
+	/* Find prediv_a and prediv_s to obtain the 1Hz calendar clock */
+	pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT;
+	pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT;
+
+	for (pred_a = pred_a_max; pred_a >= 0; pred_a--) {
+		pred_s = (rate / (pred_a + 1)) - 1;
+
+		if (((pred_s + 1) * (pred_a + 1)) == rate)
+			break;
+	}
+
+	/*
+	 * Can't find a 1Hz, so give priority to RTC power consumption
+	 * by choosing the higher possible value for prediv_a
+	 */
+	if ((pred_s > pred_s_max) || (pred_a > pred_a_max)) {
+		pred_a = pred_a_max;
+		pred_s = (rate / (pred_a + 1)) - 1;
+
+		dev_warn(&pdev->dev, "ck_rtc is %s\n",
+			 (rate - ((pred_a + 1) * (pred_s + 1)) < 0) ?
+			 "fast" : "slow");
+	}
+
+	spin_lock_irqsave(&rtc->lock, irqflags);
+
+	stm32_rtc_wpr_unlock(rtc);
+
+	ret = stm32_rtc_enter_init_mode(rtc);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"Can't enter in init mode. Prescaler config failed.\n");
+		goto end;
+	}
+
+	prer = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) & STM32_RTC_PRER_PRED_S;
+	writel_relaxed(prer, rtc->base + STM32_RTC_PRER);
+	prer |= (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & STM32_RTC_PRER_PRED_A;
+	writel_relaxed(prer, rtc->base + STM32_RTC_PRER);
+
+	/* Force 24h time format */
+	cr = readl_relaxed(rtc->base + STM32_RTC_CR);
+	cr &= ~STM32_RTC_CR_FMT;
+	writel_relaxed(cr, rtc->base + STM32_RTC_CR);
+
+	stm32_rtc_exit_init_mode(rtc);
+
+	ret = stm32_rtc_wait_sync(rtc);
+end:
+	stm32_rtc_wpr_lock(rtc);
+
+	spin_unlock_irqrestore(&rtc->lock, irqflags);
+
+	return ret;
+}
+
+static int stm32_rtc_probe(struct platform_device *pdev)
+{
+	struct stm32_rtc *rtc;
+	struct resource *res;
+	int ret;
+
+	rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
+	if (!rtc)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	rtc->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(rtc->base))
+		return PTR_ERR(rtc->base);
+
+	dbp = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "st,syscfg");
+	if (IS_ERR(dbp)) {
+		dev_err(&pdev->dev, "no st,syscfg\n");
+		return PTR_ERR(dbp);
+	}
+
+	spin_lock_init(&rtc->lock);
+
+	rtc->ck_rtc = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(rtc->ck_rtc)) {
+		dev_err(&pdev->dev, "no ck_rtc clock");
+		return PTR_ERR(rtc->ck_rtc);
+	}
+
+	ret = clk_prepare_enable(rtc->ck_rtc);
+	if (ret)
+		return ret;
+
+	regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, PWR_CR_DBP);
+
+	/*
+	 * After a system reset, RTC_ISR.INITS flag can be read to check if
+	 * the calendar has been initalized or not. INITS flag is reset by a
+	 * power-on reset (no vbat, no power-supply). It is not reset if
+	 * ck_rtc parent clock has changed (so RTC prescalers need to be
+	 * changed). That's why we cannot rely on this flag to know if RTC
+	 * init has to be done.
+	 */
+	ret = stm32_rtc_init(pdev, rtc);
+	if (ret)
+		goto err;
+
+	rtc->irq_alarm = platform_get_irq(pdev, 0);
+	if (rtc->irq_alarm <= 0) {
+		dev_err(&pdev->dev, "no alarm irq\n");
+		ret = rtc->irq_alarm;
+		goto err;
+	}
+
+	platform_set_drvdata(pdev, rtc);
+
+	ret = device_init_wakeup(&pdev->dev, true);
+	if (ret)
+		dev_warn(&pdev->dev,
+			 "alarm won't be able to wake up the system");
+
+	rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name,
+			&stm32_rtc_ops, THIS_MODULE);
+	if (IS_ERR(rtc->rtc_dev)) {
+		ret = PTR_ERR(rtc->rtc_dev);
+		dev_err(&pdev->dev, "rtc device registration failed, err=%d\n",
+			ret);
+		goto err;
+	}
+
+	/* Handle RTC alarm interrupts */
+	ret = devm_request_threaded_irq(&pdev->dev, rtc->irq_alarm, NULL,
+					stm32_rtc_alarm_irq,
+					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+					pdev->name, rtc);
+	if (ret) {
+		dev_err(&pdev->dev, "IRQ%d (alarm interrupt) already claimed\n",
+			rtc->irq_alarm);
+		goto err;
+	}
+
+	/*
+	 * If INITS flag is reset (calendar year field set to 0x00), calendar
+	 * must be initialized
+	 */
+	if (!(readl_relaxed(rtc->base + STM32_RTC_ISR) & STM32_RTC_ISR_INITS))
+		dev_warn(&pdev->dev, "Date/Time must be initialized\n");
+
+	return 0;
+err:
+	clk_disable_unprepare(rtc->ck_rtc);
+
+	regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
+
+	device_init_wakeup(&pdev->dev, false);
+
+	return ret;
+}
+
+static int __exit stm32_rtc_remove(struct platform_device *pdev)
+{
+	struct stm32_rtc *rtc = platform_get_drvdata(pdev);
+	unsigned int cr;
+
+	/* Disable interrupts */
+	stm32_rtc_wpr_unlock(rtc);
+	cr = readl_relaxed(rtc->base + STM32_RTC_CR);
+	cr &= ~STM32_RTC_CR_ALRAIE;
+	writel_relaxed(cr, rtc->base + STM32_RTC_CR);
+	stm32_rtc_wpr_lock(rtc);
+
+	clk_disable_unprepare(rtc->ck_rtc);
+
+	/* Enable backup domain write protection */
+	regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
+
+	device_init_wakeup(&pdev->dev, false);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int stm32_rtc_suspend(struct device *dev)
+{
+	struct stm32_rtc *rtc = dev_get_drvdata(dev);
+
+	if (device_may_wakeup(dev))
+		return enable_irq_wake(rtc->irq_alarm);
+
+	return 0;
+}
+
+static int stm32_rtc_resume(struct device *dev)
+{
+	struct stm32_rtc *rtc = dev_get_drvdata(dev);
+	int ret = 0;
+
+	ret = stm32_rtc_wait_sync(rtc);
+	if (ret < 0)
+		return ret;
+
+	if (device_may_wakeup(dev))
+		return disable_irq_wake(rtc->irq_alarm);
+
+	return ret;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(stm32_rtc_pm_ops,
+			 stm32_rtc_suspend, stm32_rtc_resume);
+
+static struct platform_driver stm32_rtc_driver = {
+	.probe		= stm32_rtc_probe,
+	.remove		= stm32_rtc_remove,
+	.driver		= {
+		.name	= DRIVER_NAME,
+		.pm	= &stm32_rtc_pm_ops,
+		.of_match_table = stm32_rtc_of_match,
+	},
+};
+
+module_platform_driver(stm32_rtc_driver);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 Real Time Clock driver");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1

^ permalink raw reply related

* [PATCHv3 2/8] dt-bindings: document the STM32 RTC bindings
From: Amelie Delaunay @ 2017-01-05 13:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1483623809-29937-1-git-send-email-amelie.delaunay@st.com>

This patch adds documentation of device tree bindings for the STM32 RTC.

Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
Acked-by: Rob Herring <robh@kernel.org>
---
 .../devicetree/bindings/rtc/st,stm32-rtc.txt       | 27 ++++++++++++++++++++++
 1 file changed, 27 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt

diff --git a/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt
new file mode 100644
index 0000000..e2837b9
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt
@@ -0,0 +1,27 @@
+STM32 Real Time Clock
+
+Required properties:
+- compatible: "st,stm32-rtc".
+- reg: address range of rtc register set.
+- clocks: reference to the clock entry ck_rtc.
+- interrupt-parent: phandle for the interrupt controller.
+- interrupts: rtc alarm interrupt.
+- st,syscfg: phandle for pwrcfg, mandatory to disable/enable backup domain
+  (RTC registers) write protection.
+
+Optional properties (to override default ck_rtc parent clock):
+- assigned-clocks: reference to the ck_rtc clock entry.
+- assigned-clock-parents: phandle of the new parent clock of ck_rtc.
+
+Example:
+
+	rtc: rtc at 40002800 {
+		compatible = "st,stm32-rtc";
+		reg = <0x40002800 0x400>;
+		clocks = <&rcc 1 CLK_RTC>;
+		assigned-clocks = <&rcc 1 CLK_RTC>;
+		assigned-clock-parents = <&rcc 1 CLK_LSE>;
+		interrupt-parent = <&exti>;
+		interrupts = <17 1>;
+		st,syscfg = <&pwrcfg>;
+	};
-- 
1.9.1

^ permalink raw reply related

* [PATCHv3 1/8] ARM: dts: stm32: set HSE_RTC clock frequency to 1 MHz on stm32f429
From: Amelie Delaunay @ 2017-01-05 13:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1483623809-29937-1-git-send-email-amelie.delaunay@st.com>

This patch set HSE_RTC clock frequency to 1 MHz, as the clock supplied to
the RTC must be 1 MHz.

Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
---
 arch/arm/boot/dts/stm32f429.dtsi | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
index b077f99..d195ccf 100644
--- a/arch/arm/boot/dts/stm32f429.dtsi
+++ b/arch/arm/boot/dts/stm32f429.dtsi
@@ -371,6 +371,8 @@
 			reg = <0x40023800 0x400>;
 			clocks = <&clk_hse>, <&clk_i2s_ckin>;
 			st,syscfg = <&pwrcfg>;
+			assigned-clocks = <&rcc 1 CLK_HSE_RTC>;
+			assigned-clock-rates = <1000000>;
 		};
 
 		dma1: dma-controller at 40026000 {
-- 
1.9.1

^ permalink raw reply related

* [PATCHv3 0/8] Add support for STM32 RTC
From: Amelie Delaunay @ 2017-01-05 13:43 UTC (permalink / raw)
  To: linux-arm-kernel

v3:
- rework set_alarm
- return platform_get_irq error code instead of -ENOENT

v2:
- remove clock-names and interrupt-names from bindings
- remove unuseful headers
- clean stm32_rtc structure
- replace stm32_rtc_readl/_writel by readl/writel_relaxed
- use threaded IRQ
- rework set_alarm
- add various comments
- select COMPILE_TEST and REGMAP_MMIO

This patchset adds support for the STM32 Real-Time Clock.
This RTC is an independent BCD timer/counter and provides a time-of-day
clock/calendar with programmable alarm interrupt.
RTC calendar can be driven by three clock sources LSE, LSI or HSE.

Amelie Delaunay (8):
  ARM: dts: stm32: set HSE_RTC clock frequency to 1 MHz on stm32f429
  dt-bindings: document the STM32 RTC bindings
  rtc: add STM32 RTC driver
  ARM: dts: stm32: Add RTC support for STM32F429 MCU
  ARM: dts: stm32: enable RTC on stm32f429-disco
  ARM: dts: stm32: enable RTC on stm32f469-disco
  ARM: dts: stm32: enable RTC on stm32429i-eval
  ARM: configs: stm32: Add RTC support in STM32 defconfig

 .../devicetree/bindings/rtc/st,stm32-rtc.txt       |  27 +
 arch/arm/boot/dts/stm32429i-eval.dts               |   4 +
 arch/arm/boot/dts/stm32f429-disco.dts              |   6 +
 arch/arm/boot/dts/stm32f429.dtsi                   |  16 +
 arch/arm/boot/dts/stm32f469-disco.dts              |   4 +
 arch/arm/configs/stm32_defconfig                   |   2 +
 drivers/rtc/Kconfig                                |  11 +
 drivers/rtc/Makefile                               |   1 +
 drivers/rtc/rtc-stm32.c                            | 776 +++++++++++++++++++++
 9 files changed, 847 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt
 create mode 100644 drivers/rtc/rtc-stm32.c

-- 
1.9.1

^ permalink raw reply

* [PATCHv2 0/5] Support for Marvell switches with integrated CPUs
From: Andrew Lunn @ 2017-01-05 13:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <185147a37cab4d7eaea5f79d86cc9451@svr-chch-ex1.atlnz.lc>

> I'd love to see a switchdev driver but it's a huge task (and no I'm not 
> committing to writing it). As it stands Marvell ship a switch SDK 
> largely executes in userspace with a small kernel module providing some 
> linkage to the underlying hardware.

Is there any similarity to the mv88e6xxx family?

If it was similar registers, just a different access mechanising, we
could probably extend the mv88e6xxx to support MMIO as well as MDIO.

   Andrew

^ permalink raw reply

* [PATCH v2 5/5] drm/rockchip: Implement CRC debugfs API
From: Tomeu Vizoso @ 2017-01-05 13:06 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170105130648.3139-1-tomeu.vizoso@collabora.com>

Implement the .set_crc_source() callback and call the DP helpers
accordingly to start and stop CRC capture.

This is only done if this CRTC is currently using the eDP connector.

Signed-off-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
---

 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 48 +++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index fb5f001f51c3..5e19bef6d5b4 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -19,6 +19,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_flip_work.h>
 #include <drm/drm_plane_helper.h>
+#include <drm/bridge/analogix_dp.h>
 
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -1105,6 +1106,52 @@ static void vop_crtc_destroy_state(struct drm_crtc *crtc,
 	kfree(s);
 }
 
+static struct drm_connector *vop_get_edp_connector(struct vop *vop)
+{
+	struct drm_crtc *crtc = &vop->crtc;
+	struct drm_connector *connector;
+
+	mutex_lock(&crtc->dev->mode_config.mutex);
+	drm_for_each_connector(connector, crtc->dev)
+		if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+			mutex_unlock(&crtc->dev->mode_config.mutex);
+			return connector;
+		}
+	mutex_unlock(&crtc->dev->mode_config.mutex);
+
+	return NULL;
+}
+
+static int vop_crtc_set_crc_source(struct drm_crtc *crtc,
+				   const char *source_name, size_t *values_cnt)
+{
+	struct vop *vop = to_vop(crtc);
+	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state);
+	struct drm_connector *connector;
+	int ret;
+
+	connector = vop_get_edp_connector(vop);
+	if (!connector)
+		return -EINVAL;
+
+	*values_cnt = 3;
+
+	if (source_name &&
+	    strcmp(source_name, "auto") == 0) {
+
+		if (s->output_type != DRM_MODE_CONNECTOR_eDP)
+			return -EINVAL;
+
+		ret = analogix_dp_start_crc(connector);
+	} else if (!source_name)
+
+		ret = analogix_dp_stop_crc(connector);
+	else
+		ret = -EINVAL;
+
+	return ret;
+}
+
 static const struct drm_crtc_funcs vop_crtc_funcs = {
 	.set_config = drm_atomic_helper_set_config,
 	.page_flip = drm_atomic_helper_page_flip,
@@ -1112,6 +1159,7 @@ static const struct drm_crtc_funcs vop_crtc_funcs = {
 	.reset = vop_crtc_reset,
 	.atomic_duplicate_state = vop_crtc_duplicate_state,
 	.atomic_destroy_state = vop_crtc_destroy_state,
+	.set_crc_source = vop_crtc_set_crc_source,
 };
 
 static void vop_fb_unref_worker(struct drm_flip_work *work, void *val)
-- 
2.9.3

^ permalink raw reply related

* [PATCH v2 0/5] drm/dp: Implement CRC debugfs API
From: Tomeu Vizoso @ 2017-01-05 13:06 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

this series builds up on the API for exposing captured CRCs through
debugfs.

It adds new DP helpers for starting and stopping CRC capture and gets
the Rockchip driver to use it.

Also had to add a connector backpointer to the drm_dp_aux struct so we could
wait for the right vblank and store the CRCs afterwards, I will be glad
to hear about better alternatives.

Thanks,

Tomeu


Tomeu Vizoso (5):
  drm/dp: add connector backpointer to drm_dp_aux
  drm/bridge: analogix_dp: set connector to drm_dp_aux
  drm/dp: add helpers for capture of frame CRCs
  drm/bridge: analogix_dp: add helpers for capture of frame CRCs
  drm/rockchip: Implement CRC debugfs API

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  34 ++++--
 drivers/gpu/drm/drm_dp_helper.c                    | 120 +++++++++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c        |  48 +++++++++
 include/drm/bridge/analogix_dp.h                   |   3 +
 include/drm/drm_dp_helper.h                        |   9 ++
 5 files changed, 206 insertions(+), 8 deletions(-)

-- 
2.9.3

^ permalink raw reply

* [PATCH 1/5] ARM: dts: armada388-clearfog: add phy reset gpio-hog
From: Gregory CLEMENT @ 2017-01-05 13:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170105103134.GS14217@n2100.armlinux.org.uk>

Hi Russell King,
 
 On jeu., janv. 05 2017, Russell King - ARM Linux <linux@armlinux.org.uk> wrote:

> On Thu, Jan 05, 2017 at 11:29:48AM +0100, Gregory CLEMENT wrote:
>> Hi Russell King,
>>  
>>  On jeu., janv. 05 2017, Russell King - ARM Linux <linux@armlinux.org.uk> wrote:
>> 
>> > On Wed, Jan 04, 2017 at 05:26:08PM +0100, Gregory CLEMENT wrote:
>> >> Hi Russell,
>> >>  
>> >>  On lun., janv. 02 2017, Russell King <rmk+kernel@armlinux.org.uk> wrote:
>> >> 
>> >> 
>> >> It would be nice to have some word here about this patch. Especially why
>> >> we need it now. I guess it is for being less dependent on the
>> >> initialization done by the bootloader but maybe you have other reasons.
>> >
>> > I'm not sure I follow.  This is adding it to the new platform, not the
>> > old one.  I guess I should've rolled this into the patch creating the
>> > clearfog-base dts file, and this question wouldn't have come up.
>> >
>> 
>> Indeed I missed the fact that it was on the new board as all the other
>> patches were related to the common part.
>> 
>> Do you agree that I squash this patch into the "ARM: dts:
>> armada388-clearfog: add base model DTS file" patch?
>
> Yep, thanks.

It's done and it is also part of mvebu/for-next now.

Gregory

>
> -- 
> RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
> FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
> according to speedtest.net.

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

^ permalink raw reply

* [PATCH v3] ARM: dts: turris-omnia: add support for ethernet switch
From: Gregory CLEMENT @ 2017-01-05 12:57 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170103193501.4827-1-uwe@kleine-koenig.org>

Hi Uwe,
 
 On mar., janv. 03 2017, Uwe Kleine-K?nig <uwe@kleine-koenig.org> wrote:

> The Turris Omnia features a Marvell MV88E6176 ethernet switch. Add it to
> the dts.
>
> Signed-off-by: Uwe Kleine-K?nig <uwe@kleine-koenig.org>

Applied on mvebu/dt with Reviewed-by flag from Andrew Lunn
<andrew@lunn.ch> and Tested-by flag from Andreas F?rber.

Thanks,

Gregory
> ---
> Changes since (implicit) v1:
>  - drop mdio bus and per port phy-handle as they match the default
>    setup.
>
> Changes since v2:
>  - Fix switch type in comment and commit log
>  - drop 2nd cpu port
>
>  arch/arm/boot/dts/armada-385-turris-omnia.dts | 58 +++++++++++++++++++++++++--
>  1 file changed, 55 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm/boot/dts/armada-385-turris-omnia.dts b/arch/arm/boot/dts/armada-385-turris-omnia.dts
> index ab49acb2d452..28eede180e4f 100644
> --- a/arch/arm/boot/dts/armada-385-turris-omnia.dts
> +++ b/arch/arm/boot/dts/armada-385-turris-omnia.dts
> @@ -122,7 +122,7 @@
>  	pinctrl-names = "default";
>  	pinctrl-0 = <&ge0_rgmii_pins>;
>  	status = "okay";
> -	phy-mode = "rgmii-id";
> +	phy-mode = "rgmii";
>  
>  	fixed-link {
>  		speed = <1000>;
> @@ -135,7 +135,7 @@
>  	pinctrl-names = "default";
>  	pinctrl-0 = <&ge1_rgmii_pins>;
>  	status = "okay";
> -	phy-mode = "rgmii-id";
> +	phy-mode = "rgmii";
>  
>  	fixed-link {
>  		speed = <1000>;
> @@ -273,7 +273,59 @@
>  		/* irq is connected to &pcawan pin 7 */
>  	};
>  
> -	/* Switch MV88E7176 at address 0x10 */
> +	/* Switch MV88E6176 at address 0x10 */
> +	switch at 10 {
> +		compatible = "marvell,mv88e6085";
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		dsa,member = <0 0>;
> +
> +		reg = <0x10>;
> +
> +		ports {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +
> +			ports at 0 {
> +				reg = <0>;
> +				label = "lan0";
> +			};
> +
> +			ports at 1 {
> +				reg = <1>;
> +				label = "lan1";
> +			};
> +
> +			ports at 2 {
> +				reg = <2>;
> +				label = "lan2";
> +			};
> +
> +			ports at 3 {
> +				reg = <3>;
> +				label = "lan3";
> +			};
> +
> +			ports at 4 {
> +				reg = <4>;
> +				label = "lan4";
> +			};
> +
> +			ports at 5 {
> +				reg = <5>;
> +				label = "cpu";
> +				ethernet = <&eth1>;
> +				phy-mode = "rgmii-id";
> +
> +				fixed-link {
> +					speed = <1000>;
> +					full-duplex;
> +				};
> +			};
> +
> +			/* port 6 is connected to eth0 */
> +		};
> +	};
>  };
>  
>  &pinctrl {
> -- 
> 2.11.0
>

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

^ permalink raw reply

* [PATCH 3/8] ARM: dts: armada-388-clearfog: Utilize new DSA binding
From: Gregory CLEMENT @ 2017-01-05 12:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <5a40436a-ebad-8a94-c5c5-546ba33ba545@gmail.com>

Hi Florian,
 
 On mer., janv. 04 2017, Florian Fainelli <f.fainelli@gmail.com> wrote:

> On 01/04/2017 09:23 AM, Gregory CLEMENT wrote:
>> Hi Florian,
>>  
>>  On lun., janv. 02 2017, Florian Fainelli <f.fainelli@gmail.com> wrote:
>> 
>>> Utilize the new DSA binding, introduced with commit 8c5ad1d6179d ("net:
>>> dsa: Document new binding"). The legacy binding node is kept included, but is
>>> marked disabled.
>>>
>> 
>> I tested this patch on mvebu/dt (I needed to reduce the context to apply
>> the patch due to the changes made by Russell King on this file). I also
>> set the status of the old binding to "disable" (instead of "okay").
>
> Yes, that needs fixing, thanks for mentioning that.
>
>> 
>> It seems to work with the limited test did:
>> ifconfig eth1 up
>> udhcpc -i lan1
>> iperf -c mylaptop
>> 
>> (same for lan4)
>> 
>> However is there a way to be sure that the new binding is used?
>
> The best way is probably to make sure that your switch device appears
> parented to the MDIO bus driver under /sys/class/mdio_bus/*mvmdio*.
> Alternatively, if you see a message like:
>
> DSA: switch 0 0 parsed
>
> in your dmesg, that would also be indicative of using the new binding
> and corresponding code.

So it's OK I had this message.

Gregory


>
> Thanks a lot for trying that out!
> -- 
> Florian

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

^ permalink raw reply

* [PATCH v5 1/4] clk: rockchip: add dt-binding header for rk3328
From: Heiko Stuebner @ 2017-01-05 12:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <6625105.hZYF0iglUL@phil>

Am Donnerstag, 5. Januar 2017, 13:39:38 CET schrieb Heiko Stuebner:
> Am Donnerstag, 29. Dezember 2016, 10:45:08 CET schrieb Elaine Zhang:
> > Add the dt-bindings header for the rk3328, that gets shared between
> > the clock controller and the clock references in the dts.
> > Add softreset ID for rk3328.
> > 
> > Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
> 
> applied, after moving the clock-ids a bit more together [0],
> as limiting the number of empty entries in the clk-id array saves us a bit
> of space. But please double check and shout if something looks wrong :-)

forgot to add, that I also moved your mac2phy clock-ids into the regular sclk-
area, as we want to add them via the muxgrf clktype.


> Thanks
> Heiko
> 
> [0]
> https://git.kernel.org/cgit/linux/kernel/git/mmind/linux-rockchip.git/commi
> t/?id=6cc1aef0ad0daea0c6ba5432a8a6fe1c30661e4c

^ permalink raw reply

* [PATCH v5 4/4] clk: rockchip: add clock controller for rk3328
From: Heiko Stuebner @ 2017-01-05 12:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1482979511-6847-5-git-send-email-zhangqing@rock-chips.com>

Am Donnerstag, 29. Dezember 2016, 10:45:11 CET schrieb Elaine Zhang:
> Add the clock tree definition for the new rk3328 SoC.
> 
> Changes in v5:
>   fix up some code style, remove grf clk init and cru dump.
> Changes in v4:
>   adjust the pacth 3 and 4 order.
> Changes in v3:
>   fix up the pll parent only xin24m.
> Changes in v2:
>   fix up these *_sample error description.
> 
> Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>

applied for 4.11.

You might also want to readd your mac2phy grf clocks via the newly
introduced muxgrf clock-type [0] in a follow-up-patch.

Heiko

[0] https://git.kernel.org/cgit/linux/kernel/git/mmind/linux-rockchip.git/commit/?id=cb1d9f6ddaa436f2dce2710740b7a3546700949c

^ permalink raw reply

* [PATCH v6 05/14] ACPI: platform-msi: retrieve dev id from IORT
From: Hanjun Guo @ 2017-01-05 12:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170104191805.GE8604@red-moon>

Hi Lorenzo,

On 2017/1/5 3:18, Lorenzo Pieralisi wrote:
> On Mon, Jan 02, 2017 at 09:31:36PM +0800, Hanjun Guo wrote:
>> For devices connecting to ITS, it needs dev id to identify
>> itself, and this dev id is represented in the IORT table in
>> named componant node [1] for platform devices, so in this
>> patch we will scan the IORT to retrieve device's dev id.
>>
>> Introduce iort_pmsi_get_dev_id() with pointer dev passed
>> in for that purpose.
>>
>> [1]: https://static.docs.arm.com/den0049/b/DEN0049B_IO_Remapping_Table.pdf
>>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> Tested-by: Sinan Kaya <okaya@codeaurora.org>
>> Tested-by: Majun <majun258@huawei.com>
>> Tested-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
>> Cc: Marc Zyngier <marc.zyngier@arm.com>
>> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
>> Cc: Tomasz Nowicki <tn@semihalf.com>
>> Cc: Thomas Gleixner <tglx@linutronix.de>
>> ---
>>  drivers/acpi/arm64/iort.c                     | 26 ++++++++++++++++++++++++++
>>  drivers/irqchip/irq-gic-v3-its-platform-msi.c |  4 +++-
>>  include/linux/acpi_iort.h                     |  8 ++++++++
>>  3 files changed, 37 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
>> index 174e983..ab7bae7 100644
>> --- a/drivers/acpi/arm64/iort.c
>> +++ b/drivers/acpi/arm64/iort.c
>> @@ -444,6 +444,32 @@ u32 iort_msi_map_rid(struct device *dev, u32 req_id)
>>  }
>>
>>  /**
>> + * iort_pmsi_get_dev_id() - Get the device id for a device
>> + * @dev: The device for which the mapping is to be done.
>> + * @dev_id: The device ID found.
>> + *
>> + * Returns: 0 for successful find a dev id, errors otherwise
>> + */
>> +int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id)
>> +{
>> +	struct acpi_iort_node *node;
>> +
>> +	if (!iort_table)
>> +		return -ENODEV;
>> +
>> +	node = iort_find_dev_node(dev);
>> +	if (!node) {
>> +		dev_err(dev, "can't find related IORT node\n");
>> +		return -ENODEV;
>> +	}
>> +
>> +	if(!iort_node_get_id(node, dev_id, IORT_MSI_TYPE, 0))
>
> I disagree with this approach. For named components we know that
> there are always two steps involved (second optional):
>
> (1) Retrieve the initial id (this may well provide the final mapping)
> (2) Map the id (optional if (1) represents the map type we need)
>
> That's the reason why I kept iort_node_get_id() and iort_node_map_rid()
> separated.
>
> Now, what we can do is to create an iort_node_map_id() function that is
> PCI agnostic (ie rename rid to id :)), whose rid_in is either a PCI RID
> or the outcome of a previous call to iort_node_get_id() for named
> components, that's in my opinion cleaner.

iort_node_map_rid() was designed for that purpose, and we can use it
for platform device, the issue that we need to pass a req id
unconditionally which is not needed for platform device, Tomasz
proposed a similar solution to rework iort_node_map_rid(), and
I think it makes sense.

>
> It would be even cleaner if you passed a type_mask (or write a
> wrapper function for that) that is:
>
> (IORT_MSI_TYPE | IORT_IOMMU_TYPE)

Sorry, I got little lost here, could you explain it in detail?

>
> and we just use the returned parent pointer to check if the mapping
> providing the initial id correspond to the type we are looking for (eg
> ITS) or we need to map the retrieved initial id any further, with
> iort_node_map_id(), to get to the final identifier.
>
> Thoughts ?

I think rework iort_node_map_rid() and not extend iort_node_get_id()
is the right direction, could you explain a bit more then I can demo
the code?

Thanks
Hanjun

^ permalink raw reply

* [PATCH v5 2/4] dt-bindings: add bindings for rk3328 clock controller
From: Heiko Stuebner @ 2017-01-05 12:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1482979511-6847-3-git-send-email-zhangqing@rock-chips.com>

Am Donnerstag, 29. Dezember 2016, 10:45:09 CET schrieb Elaine Zhang:
> Add devicetree bindings for Rockchip cru which found on
> Rockchip SoCs.
> 
> Changes in v4:
>   dropping the "rockchip,cru" and "syscon" properties for bindings of rk3328
> 
> Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>

applied for 4.11 with Rob's Ack

^ permalink raw reply

* [PATCH v3] ARM: dts: turris-omnia: add support for ethernet switch
From: Andreas Färber @ 2017-01-05 12:40 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170104134131.GJ10768@lunn.ch>

Am 04.01.2017 um 14:41 schrieb Andrew Lunn:
> On Wed, Jan 04, 2017 at 11:49:12AM +0100, Andreas F?rber wrote:
>> Am 03.01.2017 um 20:35 schrieb Uwe Kleine-K?nig:
>>> The Turris Omnia features a Marvell MV88E6176 ethernet switch. Add it to
>>> the dts.
>>>
>>> Signed-off-by: Uwe Kleine-K?nig <uwe@kleine-koenig.org>
>>
>> It's still not working for me on next-20170104 with this v3.
>> Are there any other patches needed?
[...]
>> I've been using the WAN port (eth2) just fine. (=eth1 in OpenWrt)
>>
>> With this patch, eth0 and eth1 are shown as UP by default. If however I
>> enslave eth0 and eth1 in a br-lan bridge, as seen under OpenWrt for
>> eth0+eth2, then eth1 is DOWN while eth0 remains UP, and br-lan remains
>> DOWN. Same issue if I drop eth0 from the bridge - after a reboot eth1 is
>> UP but br-lan is still DOWN.
>> I had to manually enable CONFIG_BRIDGE, so maybe I'm missing more kernel
>> options? Or did you simply not try using a bridge?
> 
> That is not how you use DSA. It is very different to how OpenWRT
> swconfig works. The mainline kernel philosophy is that switch
> interfaces are just normal linux interfaces.
> 
> You need eth0 up, in order that the slave interfaces work. But then
> you can use the slave interfaces just like normal Linux
> interfaces. You can put an IP address on them. You can put them into a
> bridge, etc. But leave eth0 alone, other than having it up.

Thanks, s/eth0/eth1/g here.

There were two hurdles, for one only eth0..eth2 were shown in our yast
tool (https://bugzilla.opensuse.org/show_bug.cgi?id=1018271), and for
another the interface name in manually written config files needed to be
just lan0 instead of lan0 at eth1 as shown in ip a.

A br-lan bridge across lan0..lan4 works as expected. Great!

Tested-by: Andreas F?rber <afaerber@suse.de>

Unrelated remaining issue is still the misconfigured stdout-path.

Regards,
Andreas

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 N?rnberg, Germany
GF: Felix Imend?rffer, Jane Smithard, Graham Norton
HRB 21284 (AG N?rnberg)

^ permalink raw reply

* [PATCH v5 1/4] clk: rockchip: add dt-binding header for rk3328
From: Heiko Stuebner @ 2017-01-05 12:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1482979511-6847-2-git-send-email-zhangqing@rock-chips.com>

Am Donnerstag, 29. Dezember 2016, 10:45:08 CET schrieb Elaine Zhang:
> Add the dt-bindings header for the rk3328, that gets shared between
> the clock controller and the clock references in the dts.
> Add softreset ID for rk3328.
> 
> Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>

applied, after moving the clock-ids a bit more together [0],
as limiting the number of empty entries in the clk-id array saves us a bit of
space. But please double check and shout if something looks wrong :-)


Thanks
Heiko

[0] https://git.kernel.org/cgit/linux/kernel/git/mmind/linux-rockchip.git/commit/?id=6cc1aef0ad0daea0c6ba5432a8a6fe1c30661e4c

^ permalink raw reply

* [PATCH 02/10] iommu/of: Prepare for deferred IOMMU configuration
From: Lorenzo Pieralisi @ 2017-01-05 12:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <003601d2672e$91744b40$b45ce1c0$@codeaurora.org>

On Thu, Jan 05, 2017 at 02:04:37PM +0530, Sricharan wrote:
> Hi Robin/Lorenzo,
> 
> >Hi Robin,Lorenzo,
> >
> >>On Wed, Nov 30, 2016 at 04:42:27PM +0000, Robin Murphy wrote:
> >>> On 30/11/16 16:17, Lorenzo Pieralisi wrote:
> >>> > Sricharan, Robin,
> >>> >
> >>> > I gave this series a go on ACPI and apart from an SMMU v3 fix-up
> >>> > it seems to work, more thorough testing required though.
> >>> >
> >>> > A key question below.
> >>> >
> >>> > On Wed, Nov 30, 2016 at 05:52:16AM +0530, Sricharan R wrote:
> >>> >> From: Robin Murphy <robin.murphy@arm.com>
> >>> >>
> >>> >> IOMMU configuration represents unchanging properties of the hardware,
> >>> >> and as such should only need happen once in a device's lifetime, but
> >>> >> the necessary interaction with the IOMMU device and driver complicates
> >>> >> exactly when that point should be.
> >>> >>
> >>> >> Since the only reasonable tool available for handling the inter-device
> >>> >> dependency is probe deferral, we need to prepare of_iommu_configure()
> >>> >> to run later than it is currently called (i.e. at driver probe rather
> >>> >> than device creation), to handle being retried, and to tell whether a
> >>> >> not-yet present IOMMU should be waited for or skipped (by virtue of
> >>> >> having declared a built-in driver or not).
> >>> >>
> >>> >> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
> >>> >> ---
> >>> >>  drivers/iommu/of_iommu.c | 30 +++++++++++++++++++++++++++++-
> >>> >>  1 file changed, 29 insertions(+), 1 deletion(-)
> >>> >>
> >>> >> diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
> >>> >> index ee49081..349bd1d 100644
> >>> >> --- a/drivers/iommu/of_iommu.c
> >>> >> +++ b/drivers/iommu/of_iommu.c
> >>> >> @@ -104,12 +104,20 @@ int of_get_dma_window(struct device_node *dn, const char *prefix, int index,
> >>> >>  	int err;
> >>> >>
> >>> >>  	ops = iommu_get_instance(fwnode);
> >>> >> -	if (!ops || !ops->of_xlate)
> >>> >> +	if ((ops && !ops->of_xlate) ||
> >>> >> +	    (!ops && !of_match_node(&__iommu_of_table, iommu_spec->np)))
> >>> >
> >>> > IIUC of_match_node() here is there to check there is a driver compiled
> >>> > in for this device_node (aka compatible string in OF world), correct ?
> >>>
> >>> Yes - specifically, it's checking the magic table for a matching
> >>> IOMMU_OF_DECLARE entry.
> >>>
> >>> > If that's the case (and I think that's what Sricharan was referring to
> >>> > in his ACPI query) I need to cook-up something on the ACPI side to
> >>> > emulate the OF linker table behaviour (or anyway to detect a driver is
> >>> > actually in the kernel), it is not that difficult but it is key to know,
> >>> > I will give it some thought to make it as clean as possible.
> >>>
> >>> I didn't think this would be a concern for ACPI, since IORT works much
> >>> the same way the current of_iommu_init_fn/of_platform_device_create()
> >>> bodges in drivers so for DT. If you can only discover SMMUs from IORT,
> >>> then iort_init_platform_devices() will have already created every SMMU
> >>> that's going to exist before discovering other devices from wherever
> >>> they come from, thus you could never get into the situation of probing a
> >>> device without its SMMU being ready (if it's ever going to be). Is that
> >>> not right?
> >>
> >>It is right, my point and question is: we are probing a device and we
> >>have to know whether it is worth deferring its IOMMU DMA setup. On DT,
> >>through of_match_node(&__iommu_of_table, iommu_device_node) we check at
> >>once that:
> >>
> >>1 - A device for the IOMMU exists
> >>
> >>AND
> >>
> >>2 - A driver for the IOMMU is compiled in the kernel
> >>
> >>Is this correct ? As you said (1) is not a concern on ACPI IORT (because
> >>we create the IOMMU device before _any_ other device so either the IOMMU
> >>device is there or it will never be by the time master devices are
> >>probed), but for (2) I need to slightly change how the IORT linker entry
> >>work to make sure we can detect a driver is actually compiled in the
> >>kernel, it is easy, I was just asking if my understanding was correct
> >>and I think that was what Sricharan was referring to in his query.
> >>
> >
> >Yes right, this was what i was looking for in the ACPI case and putting this
> >in the iort_iommu_xlate was needed to return EPROBE_DEFER when the
> >driver is not yet been probed.
> 
> With the thinking of taking this series through, would it be fine if i
> cleanup the pci configure hanging outside and push it in to
> of/acpi_iommu configure respectively ? This time with all neeeded for
> ACPI added as well.  Also on the last post of V4, Lorenzo commented
> that it worked for him, although still the of_match_node equivalent in
> ACPI has to be added. If i can get that, then i will add that as well
> to make this complete.

Question: I had a look into this and instead of fiddling about with the
linker script entries in ACPI (ie IORT_ACPI_DECLARE - which I hope this
patchset would help remove entirely), I think that the only check we
need in IORT is, depending on what type of SMMU a given device is
connected to, to check if the respective SMMU driver is compiled in the
kernel and it will be probed, _eventually_.

As Robin said, by the time a device is probed the respective SMMU
devices are already created and registered with IORT kernel code or
they will never be, so to understand if we should defer probing
SMMU device creation is _not_ really a problem in ACPI.

To check if a SMMU driver is enabled, do we really need a linker
table ?

Would not a check based on eg:

/**
 * @type: IOMMU IORT node type of the IOMMU a device is connected to
 */
static bool iort_iommu_driver_enabled(u8 type)
{
	switch (type) {
	case ACPI_IORT_SMMU_V3:
		return IS_ENABLED(CONFIG_ARM_SMMU_V3);
	case ACPI_IORT_SMMU:
		return IS_ENABLED(CONFIG_ARM_SMMU);
	default:
		pr_warn("Unknown IORT SMMU type\n");
		return false;
	}
}

be sufficient (it is a bit gross, agreed, but it is to understand if
that's all we need) ? Is there anything I am missing ?

Let me know, I will put together a patch for you I really do not
want to block your series for this trivial niggle.

Thanks,
Lorenzo

^ permalink raw reply

* [RFC PATCH] usb: dwc3: host: add support for OTG in DWC3 host driver
From: Manish Narani @ 2017-01-05 12:24 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <87o9znvtl3.fsf@linux.intel.com>

Hi Felipe,

> -----Original Message-----
> From: Felipe Balbi [mailto:balbi at kernel.org]
> Sent: Wednesday, January 04, 2017 7:03 PM
> 
> Hi,
> 
> Manish Narani <manish.narani@xilinx.com> writes:
> > This patch adds support for OTG host mode initialization in DWC3 host
> > driver. Before the host initialization sequence begins. The driver has
> > to make sure the no OTG peripheral mode is enabled.
> >
> > Signed-off-by: Manish Narani <mnarani@xilinx.com>
> > ---
> >  drivers/usb/dwc3/host.c | 14 ++++++++++++++
> >  1 file changed, 14 insertions(+)
> >
> > diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index
> > 487f0ff..4caa3fe 100644
> > --- a/drivers/usb/dwc3/host.c
> > +++ b/drivers/usb/dwc3/host.c
> > @@ -16,6 +16,8 @@
> >   */
> >
> >  #include <linux/platform_device.h>
> > +#include <linux/usb.h>
> > +#include <linux/usb/hcd.h>
> >
> >  #include "core.h"
> >
> > @@ -111,6 +113,18 @@ int dwc3_host_init(struct dwc3 *dwc)
> >  	phy_create_lookup(dwc->usb3_generic_phy, "usb3-phy",
> >  			  dev_name(dwc->dev));
> >
> > +	if (dwc->dr_mode == USB_DR_MODE_OTG) {
> > +		struct usb_phy *phy;
> > +		/* Switch otg to host mode */
> > +		phy = usb_get_phy(USB_PHY_TYPE_USB3);
> > +		if (!IS_ERR(phy)) {
> > +			if (phy && phy->otg)
> > +				otg_set_host(phy->otg,
> > +						(struct usb_bus *)(long)1);
> > +			usb_put_phy(phy);
> > +		}
> > +	}
> 
> NAK. Don't change default mode for everybody. Default mode should actually
> be peripheral, but let's not touch whatever HW designer has set; at least for
> now.

Yes, The default mode is Peripheral. The above is to initialize the host related stuff in OTG driver before sensing the OTG ID and get to the respective mode.

- Manish

^ permalink raw reply

* [PATCH 2/2] arm64: mm: enable CONFIG_HOLES_IN_ZONE for NUMA
From: Robert Richter @ 2017-01-05 12:22 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170105120819.GH679@arm.com>

On 05.01.17 12:08:20, Will Deacon wrote:
> On Thu, Jan 05, 2017 at 12:24:07PM +0100, Robert Richter wrote:
> > On 04.01.17 14:02:23, Will Deacon wrote:
> > > Using early_pfn_valid feels like a bodge to me, since having pfn_valid
> > > return false for something that early_pfn_valid says is valid (and is
> > > therefore initialised in the memmap) makes the NOMAP semantics even more
> > > confusing.
> > 
> > The concern I have had with HOLES_IN_ZONE is that it enables
> > pfn_valid_within() for arm64. This means that each pfn of a section is
> > checked which is done only once for the section otherwise. With up to
> > 2^18 pages per section we traverse the memblock list by that factor
> > more often. There could be a performance regression.
> 
> There could be, but we're trying to fix a bug here. I wouldn't have
> thought that walking over pfns like that is done very often.

The bug happens on a small number of machines depending on the memory
layout. The fix affects all systems. And right know the impact is
unclear.

> > I haven't numbers yet, since the fix causes another kernel crash. And,
> > this is the next problem I have. The crash doesn't happen otherwise. So,
> > either it uncovers another bug or the fix is incomplete. Though the
> > changes look like it should work. This needs more investigation.
> 
> I really can't see how the fix causes a crash, and I couldn't reproduce
> it on any of my boards, nor could any of the Linaro folk afaik. Are you
> definitely running mainline with just these two patches from Ard?

Yes, just both patches applied. Various other solutions were working.

-Robert

^ permalink raw reply

* [PATCHv2] ARM: dts: socfpga: Add NAND device tree for Arria10
From: Dinh Nguyen @ 2017-01-05 12:16 UTC (permalink / raw)
  To: linux-arm-kernel

From: Graham Moore <grmoore@opensource.altera.com>

Add socfpga_arria10_socdk_nand.dts board file for supporting NAND.

Signed-off-by: Graham Moore <grmoore@opensource.altera.com>
Signed-off-by: Dinh Nguyen <dinguyen@kernel.org>
---
v2: move nand dts node to socfpga_arria10.dtsi
---
 arch/arm/boot/dts/Makefile                       |  1 +
 arch/arm/boot/dts/socfpga_arria10.dtsi           | 13 ++++++++++
 arch/arm/boot/dts/socfpga_arria10_socdk_nand.dts | 31 ++++++++++++++++++++++++
 3 files changed, 45 insertions(+)
 create mode 100644 arch/arm/boot/dts/socfpga_arria10_socdk_nand.dts

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index cccdbcb..380d9bb 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -717,6 +717,7 @@ dtb-$(CONFIG_ARCH_SHMOBILE_MULTI) += \
 	sh73a0-kzm9g.dtb
 dtb-$(CONFIG_ARCH_SOCFPGA) += \
 	socfpga_arria5_socdk.dtb \
+	socfpga_arria10_socdk_nand.dtb \
 	socfpga_arria10_socdk_qspi.dtb \
 	socfpga_arria10_socdk_sdmmc.dtb \
 	socfpga_cyclone5_mcvevk.dtb \
diff --git a/arch/arm/boot/dts/socfpga_arria10.dtsi b/arch/arm/boot/dts/socfpga_arria10.dtsi
index 3ceb4e4..1139d3b2 100644
--- a/arch/arm/boot/dts/socfpga_arria10.dtsi
+++ b/arch/arm/boot/dts/socfpga_arria10.dtsi
@@ -614,6 +614,19 @@
 			status = "disabled";
 		};
 
+		nand: nand at ffb90000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "denali,denali-nand-dt", "altr,socfpga-denali-nand";
+			reg = <0xffb90000 0x72000>,
+			      <0xffb80000 0x10000>;
+			reg-names = "nand_data", "denali_reg";
+			interrupts = <0 99 4>;
+			dma-mask = <0xffffffff>;
+			clocks = <&nand_clk>;
+			status = "disabled";
+		};
+
 		ocram: sram at ffe00000 {
 			compatible = "mmio-sram";
 			reg = <0xffe00000 0x40000>;
diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk_nand.dts b/arch/arm/boot/dts/socfpga_arria10_socdk_nand.dts
new file mode 100644
index 0000000..d14f9cc
--- /dev/null
+++ b/arch/arm/boot/dts/socfpga_arria10_socdk_nand.dts
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Altera Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/dts-v1/;
+#include "socfpga_arria10_socdk.dtsi"
+
+&nand {
+	status = "okay";
+
+	partition at nand-boot {
+		label = "Boot and fpga data";
+		reg = <0x0 0x1C00000>;
+	};
+	partition at nand-rootfs {
+		label = "Root Filesystem - JFFS2";
+		reg = <0x1C00000 0x6400000>;
+	};
+};
-- 
2.7.4

^ permalink raw reply related

* [PATCH v5 13/17] irqdomain: irq_domain_check_msi_remap
From: Auger Eric @ 2017-01-05 12:08 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <eca92fdb-9d90-4d4b-baa5-2f4109ee1961@arm.com>

Hi Marc,

On 05/01/2017 12:57, Marc Zyngier wrote:
> On 05/01/17 11:29, Auger Eric wrote:
>> Hi Marc,
>>
>> On 05/01/2017 12:25, Marc Zyngier wrote:
>>> On 05/01/17 10:45, Auger Eric wrote:
>>>> Hi Marc,
>>>>
>>>> On 04/01/2017 16:27, Marc Zyngier wrote:
>>>>> On 04/01/17 14:11, Auger Eric wrote:
>>>>>> Hi Marc,
>>>>>>
>>>>>> On 04/01/2017 14:46, Marc Zyngier wrote:
>>>>>>> Hi Eric,
>>>>>>>
>>>>>>> On 04/01/17 13:32, Eric Auger wrote:
>>>>>>>> This new function checks whether all platform and PCI
>>>>>>>> MSI domains implement IRQ remapping. This is useful to
>>>>>>>> understand whether VFIO passthrough is safe with respect
>>>>>>>> to interrupts.
>>>>>>>>
>>>>>>>> On ARM typically an MSI controller can sit downstream
>>>>>>>> to the IOMMU without preventing VFIO passthrough.
>>>>>>>> As such any assigned device can write into the MSI doorbell.
>>>>>>>> In case the MSI controller implements IRQ remapping, assigned
>>>>>>>> devices will not be able to trigger interrupts towards the
>>>>>>>> host. On the contrary, the assignment must be emphasized as
>>>>>>>> unsafe with respect to interrupts.
>>>>>>>>
>>>>>>>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>>>>>>>>
>>>>>>>> ---
>>>>>>>>
>>>>>>>> v4 -> v5:
>>>>>>>> - Handle DOMAIN_BUS_FSL_MC_MSI domains
>>>>>>>> - Check parents
>>>>>>>> ---
>>>>>>>>  include/linux/irqdomain.h |  1 +
>>>>>>>>  kernel/irq/irqdomain.c    | 41 +++++++++++++++++++++++++++++++++++++++++
>>>>>>>>  2 files changed, 42 insertions(+)
>>>>>>>>
>>>>>>>> diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
>>>>>>>> index ab017b2..281a40f 100644
>>>>>>>> --- a/include/linux/irqdomain.h
>>>>>>>> +++ b/include/linux/irqdomain.h
>>>>>>>> @@ -219,6 +219,7 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
>>>>>>>>  					 void *host_data);
>>>>>>>>  extern struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec,
>>>>>>>>  						   enum irq_domain_bus_token bus_token);
>>>>>>>> +extern bool irq_domain_check_msi_remap(void);
>>>>>>>>  extern void irq_set_default_host(struct irq_domain *host);
>>>>>>>>  extern int irq_domain_alloc_descs(int virq, unsigned int nr_irqs,
>>>>>>>>  				  irq_hw_number_t hwirq, int node,
>>>>>>>> diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
>>>>>>>> index 8c0a0ae..700caea 100644
>>>>>>>> --- a/kernel/irq/irqdomain.c
>>>>>>>> +++ b/kernel/irq/irqdomain.c
>>>>>>>> @@ -278,6 +278,47 @@ struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec,
>>>>>>>>  EXPORT_SYMBOL_GPL(irq_find_matching_fwspec);
>>>>>>>>  
>>>>>>>>  /**
>>>>>>>> + * irq_domain_is_msi_remap - Check if @domain or any parent
>>>>>>>> + * has MSI remapping support
>>>>>>>> + * @domain: domain pointer
>>>>>>>> + */
>>>>>>>> +static bool irq_domain_is_msi_remap(struct irq_domain *domain)
>>>>>>>> +{
>>>>>>>> +	struct irq_domain *h = domain;
>>>>>>>> +
>>>>>>>> +	for (; h; h = h->parent) {
>>>>>>>> +		if (h->flags & IRQ_DOMAIN_FLAG_MSI_REMAP)
>>>>>>>> +			return true;
>>>>>>>> +	}
>>>>>>>> +	return false;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +/**
>>>>>>>> + * irq_domain_check_msi_remap() - Checks whether all MSI
>>>>>>>> + * irq domains implement IRQ remapping
>>>>>>>> + */
>>>>>>>> +bool irq_domain_check_msi_remap(void)
>>>>>>>> +{
>>>>>>>> +	struct irq_domain *h;
>>>>>>>> +	bool ret = true;
>>>>>>>> +
>>>>>>>> +	mutex_lock(&irq_domain_mutex);
>>>>>>>> +	list_for_each_entry(h, &irq_domain_list, link) {
>>>>>>>> +		if (((h->bus_token & DOMAIN_BUS_PCI_MSI) ||
>>>>>>>> +		     (h->bus_token & DOMAIN_BUS_PLATFORM_MSI) ||
>>>>>>>> +		     (h->bus_token & DOMAIN_BUS_FSL_MC_MSI)) &&
>>>>>>>> +		     !irq_domain_is_msi_remap(h)) {
>>>>>>>
>>>>>>> (h->bus_token & DOMAIN_BUS_PCI_MSI) and co looks quite wrong. bus_token
>>>>>>> is not a bitmap, and DOMAIN_BUS_* not a single bit value (see enum
>>>>>>> irq_domain_bus_token). Surely this should read
>>>>>>> (h->bus_token == DOMAIN_BUS_PCI_MSI).
>>>>>> Oh I did not notice that. Thanks.
>>>>>>
>>>>>> Any other comments on the irqdomain side? Do you think the current
>>>>>> approach consisting in looking at those bus tokens and their parents
>>>>>> looks good?
>>>>>
>>>>> To be completely honest, I don't like it much, as having to enumerate
>>>>> all the bus types can come up with could become quite a burden in the
>>>>> long run. I'd rather be able to identify MSI capable domains by
>>>>> construction. I came up with the following approach (fully untested):
>>>>>
>>>>> diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
>>>>> index 281a40f..7779796 100644
>>>>> --- a/include/linux/irqdomain.h
>>>>> +++ b/include/linux/irqdomain.h
>>>>> @@ -183,8 +183,11 @@ enum {
>>>>>  	/* Irq domain is an IPI domain with single virq */
>>>>>  	IRQ_DOMAIN_FLAG_IPI_SINGLE	= (1 << 3),
>>>>>  
>>>>> +	/* Irq domain implements MSIs */
>>>>> +	IRQ_DOMAIN_FLAG_MSI		= (1 << 4),
>>>>> +
>>>>>  	/* Irq domain is MSI remapping capable */
>>>>> -	IRQ_DOMAIN_FLAG_MSI_REMAP	= (1 << 4),
>>>>> +	IRQ_DOMAIN_FLAG_MSI_REMAP	= (1 << 5),
>>>>>  
>>>>>  	/*
>>>>>  	 * Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved
>>>>> @@ -450,6 +453,11 @@ static inline bool irq_domain_is_ipi_single(struct irq_domain *domain)
>>>>>  {
>>>>>  	return domain->flags & IRQ_DOMAIN_FLAG_IPI_SINGLE;
>>>>>  }
>>>>> +
>>>>> +static inline bool irq_domain_is_msi(struct irq_domain *domain)
>>>>> +{
>>>>> +	return domain->flags & IRQ_DOMAIN_FLAG_MSI;
>>>>> +}
>>>>>  #else	/* CONFIG_IRQ_DOMAIN_HIERARCHY */
>>>>>  static inline void irq_domain_activate_irq(struct irq_data *data) { }
>>>>>  static inline void irq_domain_deactivate_irq(struct irq_data *data) { }
>>>>> @@ -481,6 +489,11 @@ static inline bool irq_domain_is_ipi_single(struct irq_domain *domain)
>>>>>  {
>>>>>  	return false;
>>>>>  }
>>>>> +
>>>>> +static inline bool irq_domain_is_msi(struct irq_domain *domain)
>>>>> +{
>>>>> +	return false;
>>>>> +}
>>>>>  #endif	/* CONFIG_IRQ_DOMAIN_HIERARCHY */
>>>>>  
>>>>>  #else /* CONFIG_IRQ_DOMAIN */
>>>>> diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
>>>>> index 700caea..33b6921 100644
>>>>> --- a/kernel/irq/irqdomain.c
>>>>> +++ b/kernel/irq/irqdomain.c
>>>>> @@ -304,10 +304,7 @@ bool irq_domain_check_msi_remap(void)
>>>>>  
>>>>>  	mutex_lock(&irq_domain_mutex);
>>>>>  	list_for_each_entry(h, &irq_domain_list, link) {
>>>>> -		if (((h->bus_token & DOMAIN_BUS_PCI_MSI) ||
>>>>> -		     (h->bus_token & DOMAIN_BUS_PLATFORM_MSI) ||
>>>>> -		     (h->bus_token & DOMAIN_BUS_FSL_MC_MSI)) &&
>>>>> -		     !irq_domain_is_msi_remap(h)) {
>>>>> +		if (irq_domain_is_msi(h) && !irq_domain_is_msi_remap(h)) {
>>>>>  			ret = false;
>>>>>  			goto out;
>>>>>  		}
>>>>> diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
>>>>> index ee23006..b637263 100644
>>>>> --- a/kernel/irq/msi.c
>>>>> +++ b/kernel/irq/msi.c
>>>>> @@ -270,7 +270,7 @@ struct irq_domain *msi_create_irq_domain(struct fwnode_handle *fwnode,
>>>>>  	if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS)
>>>>>  		msi_domain_update_chip_ops(info);
>>>>>  
>>>>> -	return irq_domain_create_hierarchy(parent, 0, 0, fwnode,
>>>>> +	return irq_domain_create_hierarchy(parent, IRQ_DOMAIN_FLAG_MSI, 0, fwnode,
>>>>>  					   &msi_domain_ops, info);
>>>>>  }
>>>>>  
>>>>>
>>>>>
>>>>> Thoughts?
>>>>
>>>> Don't we need to set the IRQ_DOMAIN_FLAG_MSI flag in
>>>> platform_msi_create_device_domain too (drivers/base/platform-msi.c)?
>> was mentioning platform_msi_create_*device*_domain.
>> it calls irq_domain_create_hierarchy and looks to be MSI irq domain
>> related. But I don't have a full understanding of the whole irq domain
>> hierarchy.
> 
> Ah, sorry - I blame the ARM coffee.
> 
> This function builds a domain for a single device on top of the MSI
> domain that has been already created (see the dev->msi_domain passed to
> irq_domain_create_hierarchy). The structure looks like this:
> 
> device-domain -> platform MSI domain -> HW MSI domain -> whatever
> 
> So what we're *really* interested in is the platform MSI domain, which
> is going to carry the IRQ_DOMAIN_FLAG_MSI flag. The device-domain only
> describes a portion of it, and can safely be ignored.
> 
> In the end, what matters for this patch is that we can prove that from
> any domain carrying the IRQ_DOMAIN_FLAG_MSI flag, we can find a domain
> carrying the IRQ_DOMAIN_FLAG_MSI_REMAP flag. If that property holds,
> we're safe. Otherwise, we disable the Guest MSI feature.
> 
> Does it make sense?
Yes it makes sense. Thank you for the explanation!

Eric
> 
> Thanks,
> 
> 	M.
> 

^ permalink raw reply

* [PATCH 2/2] arm64: mm: enable CONFIG_HOLES_IN_ZONE for NUMA
From: Will Deacon @ 2017-01-05 12:08 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170105112407.GU4930@rric.localdomain>

On Thu, Jan 05, 2017 at 12:24:07PM +0100, Robert Richter wrote:
> On 04.01.17 14:02:23, Will Deacon wrote:
> > Using early_pfn_valid feels like a bodge to me, since having pfn_valid
> > return false for something that early_pfn_valid says is valid (and is
> > therefore initialised in the memmap) makes the NOMAP semantics even more
> > confusing.
> 
> The concern I have had with HOLES_IN_ZONE is that it enables
> pfn_valid_within() for arm64. This means that each pfn of a section is
> checked which is done only once for the section otherwise. With up to
> 2^18 pages per section we traverse the memblock list by that factor
> more often. There could be a performance regression.

There could be, but we're trying to fix a bug here. I wouldn't have
thought that walking over pfns like that is done very often.

> I haven't numbers yet, since the fix causes another kernel crash. And,
> this is the next problem I have. The crash doesn't happen otherwise. So,
> either it uncovers another bug or the fix is incomplete. Though the
> changes look like it should work. This needs more investigation.

I really can't see how the fix causes a crash, and I couldn't reproduce
it on any of my boards, nor could any of the Linaro folk afaik. Are you
definitely running mainline with just these two patches from Ard?

Will

^ permalink raw reply

* [PATCH v5 13/17] irqdomain: irq_domain_check_msi_remap
From: Marc Zyngier @ 2017-01-05 11:57 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1e881510-bc18-ae97-ec2f-feadcba54150@redhat.com>

On 05/01/17 11:29, Auger Eric wrote:
> Hi Marc,
> 
> On 05/01/2017 12:25, Marc Zyngier wrote:
>> On 05/01/17 10:45, Auger Eric wrote:
>>> Hi Marc,
>>>
>>> On 04/01/2017 16:27, Marc Zyngier wrote:
>>>> On 04/01/17 14:11, Auger Eric wrote:
>>>>> Hi Marc,
>>>>>
>>>>> On 04/01/2017 14:46, Marc Zyngier wrote:
>>>>>> Hi Eric,
>>>>>>
>>>>>> On 04/01/17 13:32, Eric Auger wrote:
>>>>>>> This new function checks whether all platform and PCI
>>>>>>> MSI domains implement IRQ remapping. This is useful to
>>>>>>> understand whether VFIO passthrough is safe with respect
>>>>>>> to interrupts.
>>>>>>>
>>>>>>> On ARM typically an MSI controller can sit downstream
>>>>>>> to the IOMMU without preventing VFIO passthrough.
>>>>>>> As such any assigned device can write into the MSI doorbell.
>>>>>>> In case the MSI controller implements IRQ remapping, assigned
>>>>>>> devices will not be able to trigger interrupts towards the
>>>>>>> host. On the contrary, the assignment must be emphasized as
>>>>>>> unsafe with respect to interrupts.
>>>>>>>
>>>>>>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>>>>>>>
>>>>>>> ---
>>>>>>>
>>>>>>> v4 -> v5:
>>>>>>> - Handle DOMAIN_BUS_FSL_MC_MSI domains
>>>>>>> - Check parents
>>>>>>> ---
>>>>>>>  include/linux/irqdomain.h |  1 +
>>>>>>>  kernel/irq/irqdomain.c    | 41 +++++++++++++++++++++++++++++++++++++++++
>>>>>>>  2 files changed, 42 insertions(+)
>>>>>>>
>>>>>>> diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
>>>>>>> index ab017b2..281a40f 100644
>>>>>>> --- a/include/linux/irqdomain.h
>>>>>>> +++ b/include/linux/irqdomain.h
>>>>>>> @@ -219,6 +219,7 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
>>>>>>>  					 void *host_data);
>>>>>>>  extern struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec,
>>>>>>>  						   enum irq_domain_bus_token bus_token);
>>>>>>> +extern bool irq_domain_check_msi_remap(void);
>>>>>>>  extern void irq_set_default_host(struct irq_domain *host);
>>>>>>>  extern int irq_domain_alloc_descs(int virq, unsigned int nr_irqs,
>>>>>>>  				  irq_hw_number_t hwirq, int node,
>>>>>>> diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
>>>>>>> index 8c0a0ae..700caea 100644
>>>>>>> --- a/kernel/irq/irqdomain.c
>>>>>>> +++ b/kernel/irq/irqdomain.c
>>>>>>> @@ -278,6 +278,47 @@ struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec,
>>>>>>>  EXPORT_SYMBOL_GPL(irq_find_matching_fwspec);
>>>>>>>  
>>>>>>>  /**
>>>>>>> + * irq_domain_is_msi_remap - Check if @domain or any parent
>>>>>>> + * has MSI remapping support
>>>>>>> + * @domain: domain pointer
>>>>>>> + */
>>>>>>> +static bool irq_domain_is_msi_remap(struct irq_domain *domain)
>>>>>>> +{
>>>>>>> +	struct irq_domain *h = domain;
>>>>>>> +
>>>>>>> +	for (; h; h = h->parent) {
>>>>>>> +		if (h->flags & IRQ_DOMAIN_FLAG_MSI_REMAP)
>>>>>>> +			return true;
>>>>>>> +	}
>>>>>>> +	return false;
>>>>>>> +}
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * irq_domain_check_msi_remap() - Checks whether all MSI
>>>>>>> + * irq domains implement IRQ remapping
>>>>>>> + */
>>>>>>> +bool irq_domain_check_msi_remap(void)
>>>>>>> +{
>>>>>>> +	struct irq_domain *h;
>>>>>>> +	bool ret = true;
>>>>>>> +
>>>>>>> +	mutex_lock(&irq_domain_mutex);
>>>>>>> +	list_for_each_entry(h, &irq_domain_list, link) {
>>>>>>> +		if (((h->bus_token & DOMAIN_BUS_PCI_MSI) ||
>>>>>>> +		     (h->bus_token & DOMAIN_BUS_PLATFORM_MSI) ||
>>>>>>> +		     (h->bus_token & DOMAIN_BUS_FSL_MC_MSI)) &&
>>>>>>> +		     !irq_domain_is_msi_remap(h)) {
>>>>>>
>>>>>> (h->bus_token & DOMAIN_BUS_PCI_MSI) and co looks quite wrong. bus_token
>>>>>> is not a bitmap, and DOMAIN_BUS_* not a single bit value (see enum
>>>>>> irq_domain_bus_token). Surely this should read
>>>>>> (h->bus_token == DOMAIN_BUS_PCI_MSI).
>>>>> Oh I did not notice that. Thanks.
>>>>>
>>>>> Any other comments on the irqdomain side? Do you think the current
>>>>> approach consisting in looking at those bus tokens and their parents
>>>>> looks good?
>>>>
>>>> To be completely honest, I don't like it much, as having to enumerate
>>>> all the bus types can come up with could become quite a burden in the
>>>> long run. I'd rather be able to identify MSI capable domains by
>>>> construction. I came up with the following approach (fully untested):
>>>>
>>>> diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
>>>> index 281a40f..7779796 100644
>>>> --- a/include/linux/irqdomain.h
>>>> +++ b/include/linux/irqdomain.h
>>>> @@ -183,8 +183,11 @@ enum {
>>>>  	/* Irq domain is an IPI domain with single virq */
>>>>  	IRQ_DOMAIN_FLAG_IPI_SINGLE	= (1 << 3),
>>>>  
>>>> +	/* Irq domain implements MSIs */
>>>> +	IRQ_DOMAIN_FLAG_MSI		= (1 << 4),
>>>> +
>>>>  	/* Irq domain is MSI remapping capable */
>>>> -	IRQ_DOMAIN_FLAG_MSI_REMAP	= (1 << 4),
>>>> +	IRQ_DOMAIN_FLAG_MSI_REMAP	= (1 << 5),
>>>>  
>>>>  	/*
>>>>  	 * Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved
>>>> @@ -450,6 +453,11 @@ static inline bool irq_domain_is_ipi_single(struct irq_domain *domain)
>>>>  {
>>>>  	return domain->flags & IRQ_DOMAIN_FLAG_IPI_SINGLE;
>>>>  }
>>>> +
>>>> +static inline bool irq_domain_is_msi(struct irq_domain *domain)
>>>> +{
>>>> +	return domain->flags & IRQ_DOMAIN_FLAG_MSI;
>>>> +}
>>>>  #else	/* CONFIG_IRQ_DOMAIN_HIERARCHY */
>>>>  static inline void irq_domain_activate_irq(struct irq_data *data) { }
>>>>  static inline void irq_domain_deactivate_irq(struct irq_data *data) { }
>>>> @@ -481,6 +489,11 @@ static inline bool irq_domain_is_ipi_single(struct irq_domain *domain)
>>>>  {
>>>>  	return false;
>>>>  }
>>>> +
>>>> +static inline bool irq_domain_is_msi(struct irq_domain *domain)
>>>> +{
>>>> +	return false;
>>>> +}
>>>>  #endif	/* CONFIG_IRQ_DOMAIN_HIERARCHY */
>>>>  
>>>>  #else /* CONFIG_IRQ_DOMAIN */
>>>> diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
>>>> index 700caea..33b6921 100644
>>>> --- a/kernel/irq/irqdomain.c
>>>> +++ b/kernel/irq/irqdomain.c
>>>> @@ -304,10 +304,7 @@ bool irq_domain_check_msi_remap(void)
>>>>  
>>>>  	mutex_lock(&irq_domain_mutex);
>>>>  	list_for_each_entry(h, &irq_domain_list, link) {
>>>> -		if (((h->bus_token & DOMAIN_BUS_PCI_MSI) ||
>>>> -		     (h->bus_token & DOMAIN_BUS_PLATFORM_MSI) ||
>>>> -		     (h->bus_token & DOMAIN_BUS_FSL_MC_MSI)) &&
>>>> -		     !irq_domain_is_msi_remap(h)) {
>>>> +		if (irq_domain_is_msi(h) && !irq_domain_is_msi_remap(h)) {
>>>>  			ret = false;
>>>>  			goto out;
>>>>  		}
>>>> diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
>>>> index ee23006..b637263 100644
>>>> --- a/kernel/irq/msi.c
>>>> +++ b/kernel/irq/msi.c
>>>> @@ -270,7 +270,7 @@ struct irq_domain *msi_create_irq_domain(struct fwnode_handle *fwnode,
>>>>  	if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS)
>>>>  		msi_domain_update_chip_ops(info);
>>>>  
>>>> -	return irq_domain_create_hierarchy(parent, 0, 0, fwnode,
>>>> +	return irq_domain_create_hierarchy(parent, IRQ_DOMAIN_FLAG_MSI, 0, fwnode,
>>>>  					   &msi_domain_ops, info);
>>>>  }
>>>>  
>>>>
>>>>
>>>> Thoughts?
>>>
>>> Don't we need to set the IRQ_DOMAIN_FLAG_MSI flag in
>>> platform_msi_create_device_domain too (drivers/base/platform-msi.c)?
> was mentioning platform_msi_create_*device*_domain.
> it calls irq_domain_create_hierarchy and looks to be MSI irq domain
> related. But I don't have a full understanding of the whole irq domain
> hierarchy.

Ah, sorry - I blame the ARM coffee.

This function builds a domain for a single device on top of the MSI
domain that has been already created (see the dev->msi_domain passed to
irq_domain_create_hierarchy). The structure looks like this:

device-domain -> platform MSI domain -> HW MSI domain -> whatever

So what we're *really* interested in is the platform MSI domain, which
is going to carry the IRQ_DOMAIN_FLAG_MSI flag. The device-domain only
describes a portion of it, and can safely be ignored.

In the end, what matters for this patch is that we can prove that from
any domain carrying the IRQ_DOMAIN_FLAG_MSI flag, we can find a domain
carrying the IRQ_DOMAIN_FLAG_MSI_REMAP flag. If that property holds,
we're safe. Otherwise, we disable the Guest MSI feature.

Does it make sense?

Thanks,

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

^ permalink raw reply

* [PATCH 4/4] watchdog: tangox: Use watchdog core to install restart handler
From: Marc Gonzalez @ 2017-01-05 11:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <yw1xmvf5ohx2.fsf@unicorn.mansr.com>

On 05/01/2017 12:38, M?ns Rullg?rd wrote:

> Marc Gonzalez writes:
> 
>> Guenter, patch c7ef68c32265 states "Fixes: a3e376d26ace".
>> Is that true? I mean, they seem quite orthogonal; then again I know
>> nothing of this framework.
> 
> I don't see the relation of either of those to this patch.

There is none. I just happened to git log the file because
of this proposed patch.

^ permalink raw reply

* [PATCH 08/12] ARM: dts: socfpga: Add NAND device tree for Arria10
From: Dinh Nguyen @ 2017-01-05 11:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <73a8b5ga1v.fsf@pengutronix.de>



On 01/05/2017 02:55 AM, Steffen Trumtrar wrote:

>> +#include "socfpga_arria10_socdk.dtsi"
>> +
>> +/ {
>> +	soc {
>> +		nand: nand at ffb90000 {
>> +			#address-cells = <1>;
>> +			#size-cells = <1>;
>> +			status = "okay";
>> +
>> +			compatible = "denali,denali-nand-dt", "altr,socfpga-denali-nand";
>> +			reg = <0xffb90000 0x72000>, <0xffb80000 0x10000>;
>> +			reg-names = "nand_data", "denali_reg";
>> +			interrupts = <0 99 4>;
>> +			dma-mask = <0xffffffff>;
>> +			clocks = <&nand_clk>;
> 
> This belongs into the socfpga_arria10.dtsi.
> 

Ah yes, you're right. Thanks for the review.

Dinh

^ 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