Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 2/2] drm: zte: add initial vou drm driver
From: Shawn Guo @ 2016-09-23  7:24 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1474615449-16893-1-git-send-email-shawn.guo@linaro.org>

It adds the initial ZTE VOU display controller DRM driver.  There are
still some features to be added, like overlay plane, scaling, and more
output devices support.  But it's already useful with dual CRTCs and
HDMI monitor working.

It's been tested on Debian Jessie LXDE desktop with modesetting driver.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 drivers/gpu/drm/Kconfig          |   2 +
 drivers/gpu/drm/Makefile         |   1 +
 drivers/gpu/drm/zte/Kconfig      |   8 +
 drivers/gpu/drm/zte/Makefile     |   8 +
 drivers/gpu/drm/zte/zx_crtc.c    | 711 +++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/zte/zx_crtc.h    |  47 +++
 drivers/gpu/drm/zte/zx_drm_drv.c | 258 ++++++++++++++
 drivers/gpu/drm/zte/zx_drm_drv.h |  22 ++
 drivers/gpu/drm/zte/zx_hdmi.c    | 540 +++++++++++++++++++++++++++++
 drivers/gpu/drm/zte/zx_plane.c   | 362 ++++++++++++++++++++
 drivers/gpu/drm/zte/zx_plane.h   |  26 ++
 11 files changed, 1985 insertions(+)
 create mode 100644 drivers/gpu/drm/zte/Kconfig
 create mode 100644 drivers/gpu/drm/zte/Makefile
 create mode 100644 drivers/gpu/drm/zte/zx_crtc.c
 create mode 100644 drivers/gpu/drm/zte/zx_crtc.h
 create mode 100644 drivers/gpu/drm/zte/zx_drm_drv.c
 create mode 100644 drivers/gpu/drm/zte/zx_drm_drv.h
 create mode 100644 drivers/gpu/drm/zte/zx_hdmi.c
 create mode 100644 drivers/gpu/drm/zte/zx_plane.c
 create mode 100644 drivers/gpu/drm/zte/zx_plane.h

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 483059a22b1b..a91f8cecbe0f 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -223,6 +223,8 @@ source "drivers/gpu/drm/hisilicon/Kconfig"
 
 source "drivers/gpu/drm/mediatek/Kconfig"
 
+source "drivers/gpu/drm/zte/Kconfig"
+
 # Keep legacy drivers last
 
 menuconfig DRM_LEGACY
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 439d89b25ae0..fe461c94d266 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -85,3 +85,4 @@ obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/
 obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/
 obj-$(CONFIG_DRM_ARCPGU)+= arc/
 obj-y			+= hisilicon/
+obj-$(CONFIG_DRM_ZTE)	+= zte/
diff --git a/drivers/gpu/drm/zte/Kconfig b/drivers/gpu/drm/zte/Kconfig
new file mode 100644
index 000000000000..4065b2840f1c
--- /dev/null
+++ b/drivers/gpu/drm/zte/Kconfig
@@ -0,0 +1,8 @@
+config DRM_ZTE
+	tristate "DRM Support for ZTE SoCs"
+	depends on DRM && ARCH_ZX
+	select DRM_KMS_CMA_HELPER
+	select DRM_KMS_FB_HELPER
+	select DRM_KMS_HELPER
+	help
+	  Choose this option to enable DRM on ZTE ZX SoCs.
diff --git a/drivers/gpu/drm/zte/Makefile b/drivers/gpu/drm/zte/Makefile
new file mode 100644
index 000000000000..b40968dc749f
--- /dev/null
+++ b/drivers/gpu/drm/zte/Makefile
@@ -0,0 +1,8 @@
+zxdrm-y := \
+	zx_drm_drv.o \
+	zx_crtc.o \
+	zx_plane.o \
+	zx_hdmi.o
+
+obj-$(CONFIG_DRM_ZTE) += zxdrm.o
+
diff --git a/drivers/gpu/drm/zte/zx_crtc.c b/drivers/gpu/drm/zte/zx_crtc.c
new file mode 100644
index 000000000000..531541482e1f
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_crtc.c
@@ -0,0 +1,711 @@
+/*
+ * Copyright 2016 Linaro Ltd.
+ * Copyright 2016 ZTE Corporation.
+ *
+ * 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 <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_of.h>
+#include <drm/drm_plane_helper.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/of_address.h>
+#include <video/videomode.h>
+
+#include "zx_drm_drv.h"
+#include "zx_crtc.h"
+#include "zx_plane.h"
+
+/* OSD (GPC_GLOBAL) registers */
+#define OSD_INT_STA			0x04
+#define OSD_INT_CLRSTA			0x08
+#define OSD_INT_MSK			0x0c
+#define OSD_INT_AUX_UPT			BIT(14)
+#define OSD_INT_MAIN_UPT		BIT(13)
+#define OSD_INT_GL1_LBW			BIT(10)
+#define OSD_INT_GL0_LBW			BIT(9)
+#define OSD_INT_VL2_LBW			BIT(8)
+#define OSD_INT_VL1_LBW			BIT(7)
+#define OSD_INT_VL0_LBW			BIT(6)
+#define OSD_INT_BUS_ERR			BIT(3)
+#define OSD_INT_CFG_ERR			BIT(2)
+#define OSD_INT_ERROR (\
+	OSD_INT_GL1_LBW | OSD_INT_GL0_LBW | \
+	OSD_INT_VL2_LBW | OSD_INT_VL1_LBW | OSD_INT_VL0_LBW | \
+	OSD_INT_BUS_ERR | OSD_INT_CFG_ERR \
+)
+#define OSD_INT_ENABLE (OSD_INT_ERROR | OSD_INT_AUX_UPT | OSD_INT_MAIN_UPT)
+#define OSD_CTRL0			0x10
+#define OSD_CTRL0_GL0_EN		BIT(7)
+#define OSD_CTRL0_GL0_SEL		BIT(6)
+#define OSD_CTRL0_GL1_EN		BIT(5)
+#define OSD_CTRL0_GL1_SEL		BIT(4)
+#define OSD_RST_CLR			0x1c
+#define RST_PER_FRAME			BIT(19)
+
+/* Main/Aux channel registers */
+#define OSD_MAIN_CHN			0x470
+#define OSD_AUX_CHN			0x4d0
+#define CHN_CTRL0			0x00
+#define CHN_ENABLE			BIT(0)
+#define CHN_CTRL1			0x04
+#define CHN_SCREEN_W_SHIFT		18
+#define CHN_SCREEN_W_MASK		(0x1fff << CHN_SCREEN_W_SHIFT)
+#define CHN_SCREEN_H_SHIFT		5
+#define CHN_SCREEN_H_MASK		(0x1fff << CHN_SCREEN_H_SHIFT)
+#define CHN_UPDATE			0x08
+
+/* TIMING_CTRL registers */
+#define VOU_TIMING_CTRL			0x1000
+#define TIMING_TC_ENABLE		0x04
+#define AUX_TC_EN			BIT(1)
+#define MAIN_TC_EN			BIT(0)
+#define FIR_MAIN_ACTIVE			0x08
+#define FIR_AUX_ACTIVE			0x0c
+#define FIR_MAIN_H_TIMING		0x10
+#define FIR_MAIN_V_TIMING		0x14
+#define FIR_AUX_H_TIMING		0x18
+#define FIR_AUX_V_TIMING		0x1c
+#define SYNC_WIDE_SHIFT			22
+#define SYNC_WIDE_MASK			(0x3ff << SYNC_WIDE_SHIFT)
+#define BACK_PORCH_SHIFT		11
+#define BACK_PORCH_MASK			(0x7ff << BACK_PORCH_SHIFT)
+#define FRONT_PORCH_SHIFT		0
+#define FRONT_PORCH_MASK		(0x7ff << FRONT_PORCH_SHIFT)
+#define TIMING_CTRL			0x20
+#define AUX_POL_SHIFT			3
+#define AUX_POL_MASK			(0x7 << AUX_POL_SHIFT)
+#define MAIN_POL_SHIFT			0
+#define MAIN_POL_MASK			(0x7 << MAIN_POL_SHIFT)
+#define POL_DE_SHIFT			2
+#define POL_VSYNC_SHIFT			1
+#define POL_HSYNC_SHIFT			0
+#define TIMING_INT_CTRL			0x24
+#define TIMING_INT_STATE		0x28
+#define TIMING_INT_AUX_FRAME		BIT(3)
+#define TIMING_INT_MAIN_FRAME		BIT(1)
+#define TIMING_INT_AUX_FRAME_SEL_VSW	(0x2 << 10)
+#define TIMING_INT_MAIN_FRAME_SEL_VSW	(0x2 << 6)
+#define TIMING_INT_ENABLE (\
+	TIMING_INT_MAIN_FRAME_SEL_VSW | TIMING_INT_AUX_FRAME_SEL_VSW | \
+	TIMING_INT_MAIN_FRAME | TIMING_INT_AUX_FRAME \
+)
+#define TIMING_MAIN_SHIFT		0x2c
+#define TIMING_AUX_SHIFT		0x30
+#define H_SHIFT_VAL			0x0048
+#define TIMING_MAIN_PI_SHIFT		0x68
+#define TIMING_AUX_PI_SHIFT		0x6c
+#define H_PI_SHIFT_VAL			0x000f
+
+/* DTRC registers */
+#define DTRC				0x5000
+#define DTRC_F0_CTRL			0x2c
+#define DTRC_F1_CTRL			0x5c
+#define DTRC_DECOMPRESS_BYPASS		BIT(17)
+#define DTRC_DETILE_CTRL		0x68
+#define TILE2RASTESCAN_BYPASS_MODE	BIT(30)
+#define DETILE_ARIDR_MODE_MASK		(0x3 << 0)
+#define DETILE_ARID_ALL			0
+#define DETILE_ARID_IN_ARIDR		1
+#define DETILE_ARID_BYP_BUT_ARIDR	2
+#define DETILE_ARID_IN_ARIDR2		3
+#define DTRC_ARID			0x6c
+#define DTRC_DEC2DDR_ARID		0x70
+
+/* VOU_CTRL registers */
+#define VOU_CTRL			0x6000
+#define VOU_INF_EN			0x00
+#define VOU_INF_CH_SEL			0x04
+#define VOU_INF_DATA_SEL		0x08
+#define VOU_SOFT_RST			0x14
+#define VOU_CLK_SEL			0x18
+#define VOU_CLK_GL1_SEL			BIT(5)
+#define VOU_CLK_GL0_SEL			BIT(4)
+#define VOU_CLK_REQEN			0x20
+#define VOU_CLK_EN			0x24
+
+/* OTFPPU_CTRL registers */
+#define OTFPPU_CTRL			0xa000
+#define OTFPPU_RSZ_DATA_SOURCE		0x04
+
+#define GL_NUM				2
+#define VL_NUM				3
+
+enum vou_chn_type {
+	VOU_CHN_MAIN,
+	VOU_CHN_AUX,
+};
+
+struct zx_crtc {
+	struct drm_crtc crtc;
+	struct drm_plane *primary;
+	struct device *dev;
+	void __iomem *chnreg;
+	enum vou_chn_type chn_type;
+	struct clk *pixclk;
+};
+
+#define to_zx_crtc(x)	container_of(crtc, struct zx_crtc, crtc)
+
+struct zx_vou {
+	struct device *dev;
+	void __iomem *mmio;	/* Same as OSD address */
+	void __iomem *timing;
+	void __iomem *vouctl;
+	void __iomem *otfppu;
+	void __iomem *dtrc;
+	struct clk *axi_clk;
+	struct clk *ppu_clk;
+	struct clk *main_clk;
+	struct clk *aux_clk;
+	struct zx_crtc *main_crtc;
+	struct zx_crtc *aux_crtc;
+};
+
+struct zx_layer_data gl_data[GL_NUM] = {
+	{
+		.layer_offset = 0x130,
+		.csc_offset = 0x580,
+		.hbsc_offset = 0x820,
+		.rsz_offset = 0xa600,
+	}, {
+		.layer_offset = 0x200,
+		.csc_offset = 0x5d0,
+		.hbsc_offset = 0x860,
+		.rsz_offset = 0xa800,
+	},
+};
+
+/* Video layers have no CSC block */
+struct zx_layer_data vl_data[VL_NUM] = {
+	{
+		.layer_offset = 0x040,
+		.hbsc_offset = 0x760,
+		.rsz_offset = 0xaa00,
+	}, {
+		.layer_offset = 0x090,
+		.hbsc_offset = 0x7a0,
+		.rsz_offset = 0xac00,
+	}, {
+		.layer_offset = 0x0e0,
+		.hbsc_offset = 0x7e0,
+		.rsz_offset = 0xae00,
+	},
+};
+
+static inline bool is_main_crtc(struct drm_crtc *crtc)
+{
+	struct zx_crtc *zcrtc = to_zx_crtc(crtc);
+
+	return zcrtc->chn_type == VOU_CHN_MAIN;
+}
+
+void vou_inf_enable(struct vou_inf *inf)
+{
+	struct drm_encoder *encoder = inf->encoder;
+	struct drm_device *drm = encoder->dev;
+	struct zx_drm_private *priv = drm->dev_private;
+	struct zx_vou *vou = priv->vou;
+	bool is_main = is_main_crtc(encoder->crtc);
+	u32 data_sel_shift = inf->id << 1;
+	u32 val;
+
+	/* Select data format */
+	val = readl(vou->vouctl + VOU_INF_DATA_SEL);
+	val &= ~(0x3 << data_sel_shift);
+	val |= inf->data_sel << data_sel_shift;
+	writel(val, vou->vouctl + VOU_INF_DATA_SEL);
+
+	/* Select channel */
+	val = readl(vou->vouctl + VOU_INF_CH_SEL);
+	if (is_main)
+		val &= ~(1 << inf->id);
+	else
+		val |= 1 << inf->id;
+	writel(val, vou->vouctl + VOU_INF_CH_SEL);
+
+	/* Select interface clocks */
+	val = readl(vou->vouctl + VOU_CLK_SEL);
+	if (is_main)
+		val &= ~inf->clocks_sel_bits;
+	else
+		val |= inf->clocks_sel_bits;
+	writel(val, vou->vouctl + VOU_CLK_SEL);
+
+	/* Enable interface clocks */
+	val = readl(vou->vouctl + VOU_CLK_EN);
+	val |= inf->clocks_en_bits;
+	writel(val, vou->vouctl + VOU_CLK_EN);
+
+	/* Enable the device */
+	val = readl(vou->vouctl + VOU_INF_EN);
+	val |= 1 << inf->id;
+	writel(val, vou->vouctl + VOU_INF_EN);
+}
+
+void vou_inf_disable(struct vou_inf *inf)
+{
+	struct drm_encoder *encoder = inf->encoder;
+	struct drm_device *drm = encoder->dev;
+	struct zx_drm_private *priv = drm->dev_private;
+	struct zx_vou *vou = priv->vou;
+	u32 val;
+
+	/* Disable the device */
+	val = readl(vou->vouctl + VOU_INF_EN);
+	val &= ~(1 << inf->id);
+	writel(val, vou->vouctl + VOU_INF_EN);
+
+	/* Disable interface clocks */
+	val = readl(vou->vouctl + VOU_CLK_EN);
+	val &= ~inf->clocks_en_bits;
+	writel(val, vou->vouctl + VOU_CLK_EN);
+}
+
+static inline void vou_chn_set_update(struct zx_crtc *zcrtc)
+{
+	writel(1, zcrtc->chnreg + CHN_UPDATE);
+}
+
+static void zx_crtc_enable(struct drm_crtc *crtc)
+{
+	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+	struct zx_crtc *zcrtc = to_zx_crtc(crtc);
+	struct zx_vou *vou = dev_get_drvdata(zcrtc->dev);
+	bool is_main = is_main_crtc(crtc);
+	struct videomode vm;
+	u32 pol = 0;
+	u32 val;
+
+	drm_display_mode_to_videomode(mode, &vm);
+
+	/* Set up timing parameters */
+	val = (vm.vactive - 1) << 16;
+	val |= (vm.hactive - 1) & 0xffff;
+	writel(val, vou->timing + (is_main ? FIR_MAIN_ACTIVE : FIR_AUX_ACTIVE));
+
+	val = ((vm.hsync_len - 1) << SYNC_WIDE_SHIFT) & SYNC_WIDE_MASK;
+	val |= ((vm.hback_porch - 1) << BACK_PORCH_SHIFT) & BACK_PORCH_MASK;
+	val |= ((vm.hfront_porch - 1) << FRONT_PORCH_SHIFT) & FRONT_PORCH_MASK;
+	writel(val, vou->timing + (is_main ? FIR_MAIN_H_TIMING :
+					     FIR_AUX_H_TIMING));
+
+	val = ((vm.vsync_len - 1) << SYNC_WIDE_SHIFT) & SYNC_WIDE_MASK;
+	val |= ((vm.vback_porch - 1) << BACK_PORCH_SHIFT) & BACK_PORCH_MASK;
+	val |= ((vm.vfront_porch - 1) << FRONT_PORCH_SHIFT) & FRONT_PORCH_MASK;
+	writel(val, vou->timing + (is_main ? FIR_MAIN_V_TIMING :
+					     FIR_AUX_V_TIMING));
+
+	/* Set up polarities */
+	if (vm.flags & DISPLAY_FLAGS_VSYNC_LOW)
+		pol |= 1 << POL_VSYNC_SHIFT;
+	if (vm.flags & DISPLAY_FLAGS_HSYNC_LOW)
+		pol |= 1 << POL_HSYNC_SHIFT;
+
+	val = readl(vou->timing + TIMING_CTRL);
+	val &= ~(is_main ? MAIN_POL_MASK : AUX_POL_MASK);
+	val |= pol << (is_main ? MAIN_POL_SHIFT : AUX_POL_SHIFT);
+	writel(val, vou->timing + TIMING_CTRL);
+
+	/* Setup SHIFT register by following what ZTE BSP does */
+	writel(H_SHIFT_VAL, vou->timing + (is_main ? TIMING_MAIN_SHIFT :
+						     TIMING_AUX_SHIFT));
+	writel(H_PI_SHIFT_VAL, vou->timing + (is_main ? TIMING_MAIN_PI_SHIFT :
+							TIMING_AUX_PI_SHIFT));
+
+	/* Enable TIMING_CTRL */
+	val = readl(vou->timing + TIMING_TC_ENABLE);
+	val |= is_main ? MAIN_TC_EN : AUX_TC_EN;
+	writel(val, vou->timing + TIMING_TC_ENABLE);
+
+	/* Configure channel screen size */
+	val = readl(zcrtc->chnreg + CHN_CTRL1);
+	val &= ~(CHN_SCREEN_W_MASK | CHN_SCREEN_H_MASK);
+	val |= (vm.hactive << CHN_SCREEN_W_SHIFT) & CHN_SCREEN_W_MASK;
+	val |= (vm.vactive << CHN_SCREEN_H_SHIFT) & CHN_SCREEN_H_MASK;
+	writel(val, zcrtc->chnreg + CHN_CTRL1);
+
+	/* Update channel */
+	vou_chn_set_update(zcrtc);
+
+	/* Enable channel */
+	val = readl(zcrtc->chnreg + CHN_CTRL0);
+	val |= CHN_ENABLE;
+	writel(val, zcrtc->chnreg + CHN_CTRL0);
+
+	/* Enable Graphic Layer */
+	val = readl(vou->mmio + OSD_CTRL0);
+	val |= is_main ? OSD_CTRL0_GL0_EN : OSD_CTRL0_GL1_EN;
+	writel(val, vou->mmio + OSD_CTRL0);
+
+	drm_crtc_vblank_on(crtc);
+
+	/* Enable pixel clock */
+	clk_set_rate(zcrtc->pixclk, mode->clock * 1000);
+	clk_prepare_enable(zcrtc->pixclk);
+}
+
+static void zx_crtc_disable(struct drm_crtc *crtc)
+{
+	struct zx_crtc *zcrtc = to_zx_crtc(crtc);
+	struct zx_vou *vou = dev_get_drvdata(zcrtc->dev);
+	bool is_main = is_main_crtc(crtc);
+	u32 val;
+
+	clk_disable_unprepare(zcrtc->pixclk);
+
+	drm_crtc_vblank_off(crtc);
+
+	/* Disable Graphic Layer */
+	val = readl(vou->mmio + OSD_CTRL0);
+	val &= ~(is_main ? OSD_CTRL0_GL0_EN : OSD_CTRL0_GL1_EN);
+	writel(val, vou->mmio + OSD_CTRL0);
+
+	/* Disable channel */
+	val = readl(zcrtc->chnreg + CHN_CTRL0);
+	val &= ~CHN_ENABLE;
+	writel(val, zcrtc->chnreg + CHN_CTRL0);
+
+	/* Disable TIMING_CTRL */
+	val = readl(vou->timing + TIMING_TC_ENABLE);
+	val &= ~(is_main ? MAIN_TC_EN : AUX_TC_EN);
+	writel(val, vou->timing + TIMING_TC_ENABLE);
+}
+
+static void zx_crtc_atomic_begin(struct drm_crtc *crtc,
+				 struct drm_crtc_state *state)
+{
+	struct drm_pending_vblank_event *event = crtc->state->event;
+
+	if (event) {
+		crtc->state->event = NULL;
+
+		spin_lock_irq(&crtc->dev->event_lock);
+		if (drm_crtc_vblank_get(crtc) == 0)
+			drm_crtc_arm_vblank_event(crtc, event);
+		else
+			drm_crtc_send_vblank_event(crtc, event);
+		spin_unlock_irq(&crtc->dev->event_lock);
+	}
+}
+
+static const struct drm_crtc_helper_funcs zx_crtc_helper_funcs = {
+	.enable = zx_crtc_enable,
+	.disable = zx_crtc_disable,
+	.atomic_begin = zx_crtc_atomic_begin,
+};
+
+static const struct drm_crtc_funcs zx_crtc_funcs = {
+	.destroy = drm_crtc_cleanup,
+	.set_config = drm_atomic_helper_set_config,
+	.page_flip = drm_atomic_helper_page_flip,
+	.reset = drm_atomic_helper_crtc_reset,
+	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+};
+
+static struct zx_crtc *zx_crtc_init(struct drm_device *drm,
+				    enum vou_chn_type chn_type)
+{
+	struct zx_drm_private *priv = drm->dev_private;
+	struct zx_vou *vou = priv->vou;
+	struct device *dev = vou->dev;
+	struct zx_layer_data *data;
+	struct zx_crtc *zcrtc;
+	int ret;
+
+	zcrtc = devm_kzalloc(dev, sizeof(*zcrtc), GFP_KERNEL);
+	if (!zcrtc)
+		return ERR_PTR(-ENOMEM);
+
+	zcrtc->dev = dev;
+	zcrtc->chn_type = chn_type;
+
+	if (chn_type == VOU_CHN_MAIN) {
+		data = &gl_data[0];
+		zcrtc->chnreg = vou->mmio + OSD_MAIN_CHN;
+	} else {
+		data = &gl_data[1];
+		zcrtc->chnreg = vou->mmio + OSD_AUX_CHN;
+	}
+
+	zcrtc->pixclk = devm_clk_get(dev, (chn_type == VOU_CHN_MAIN) ?
+					  "main_wclk" : "aux_wclk");
+	if (IS_ERR(zcrtc->pixclk))
+		return ERR_PTR(PTR_ERR(zcrtc->pixclk));
+
+	zcrtc->primary = zx_plane_init(drm, dev, vou->mmio, data,
+				       DRM_PLANE_TYPE_PRIMARY);
+	if (IS_ERR(zcrtc->primary))
+		return ERR_PTR(PTR_ERR(zcrtc->primary));
+
+	ret = drm_crtc_init_with_planes(drm, &zcrtc->crtc, zcrtc->primary, NULL,
+					&zx_crtc_funcs, NULL);
+	if (ret)
+		return ERR_PTR(ret);
+
+	drm_crtc_helper_add(&zcrtc->crtc, &zx_crtc_helper_funcs);
+
+	return zcrtc;
+}
+
+int zx_crtc_enable_vblank(struct drm_device *drm, unsigned int pipe)
+{
+	struct zx_drm_private *priv = drm->dev_private;
+	struct zx_vou *vou = priv->vou;
+	u32 intctl;
+
+	intctl = readl(vou->timing + TIMING_INT_CTRL);
+	if (pipe == 0)
+		intctl |= TIMING_INT_MAIN_FRAME;
+	else
+		intctl |= TIMING_INT_AUX_FRAME;
+	writel(intctl, vou->timing + TIMING_INT_CTRL);
+
+	return 0;
+}
+
+void zx_crtc_disable_vblank(struct drm_device *drm, unsigned int pipe)
+{
+	struct zx_drm_private *priv = drm->dev_private;
+	struct zx_vou *vou = priv->vou;
+	u32 intctl;
+
+	intctl = readl(vou->timing + TIMING_INT_CTRL);
+	if (pipe == 0)
+		intctl &= ~TIMING_INT_MAIN_FRAME;
+	else
+		intctl &= ~TIMING_INT_AUX_FRAME;
+	writel(intctl, vou->timing + TIMING_INT_CTRL);
+}
+
+static irqreturn_t vou_irq_handler(int irq, void *dev_id)
+{
+	struct zx_vou *vou = dev_id;
+	u32 state;
+
+	/* Handle TIMING_CTRL frame interrupts */
+	state = readl(vou->timing + TIMING_INT_STATE);
+	writel(state, vou->timing + TIMING_INT_STATE);
+
+	if (state & TIMING_INT_MAIN_FRAME)
+		drm_crtc_handle_vblank(&vou->main_crtc->crtc);
+
+	if (state & TIMING_INT_AUX_FRAME)
+		drm_crtc_handle_vblank(&vou->aux_crtc->crtc);
+
+	/* Handle OSD interrupts */
+	state = readl(vou->mmio + OSD_INT_STA);
+	writel(state, vou->mmio + OSD_INT_CLRSTA);
+
+	if (state & OSD_INT_MAIN_UPT) {
+		vou_chn_set_update(vou->main_crtc);
+		zx_plane_set_update(vou->main_crtc->primary);
+	}
+
+	if (state & OSD_INT_AUX_UPT) {
+		vou_chn_set_update(vou->aux_crtc);
+		zx_plane_set_update(vou->aux_crtc->primary);
+	}
+
+	if (state & OSD_INT_ERROR)
+		dev_err(vou->dev, "OSD ERROR: 0x%08x!\n", state);
+
+	return IRQ_HANDLED;
+}
+
+static void vou_dtrc_init(struct zx_vou *vou)
+{
+	u32 val;
+
+	val = readl(vou->dtrc + DTRC_DETILE_CTRL);
+	/* Clear bit for bypass by ID */
+	val &= ~TILE2RASTESCAN_BYPASS_MODE;
+	/* Select ARIDR mode */
+	val &= ~DETILE_ARIDR_MODE_MASK;
+	val |= DETILE_ARID_IN_ARIDR;
+	writel(val, vou->dtrc + DTRC_DETILE_CTRL);
+
+	/* Bypass decompression for both frames */
+	val = readl(vou->dtrc + DTRC_F0_CTRL);
+	val |= DTRC_DECOMPRESS_BYPASS;
+	writel(val, vou->dtrc + DTRC_F0_CTRL);
+
+	val = readl(vou->dtrc + DTRC_F1_CTRL);
+	val |= DTRC_DECOMPRESS_BYPASS;
+	writel(val, vou->dtrc + DTRC_F1_CTRL);
+
+	/* Set up ARID register */
+	val = 0x0e;
+	val |= 0x0f << 8;
+	val |= 0x0e << 16;
+	val |= 0x0f << 24;
+	writel(val, vou->dtrc + DTRC_ARID);
+
+	/* Set up DEC2DDR_ARID register */
+	val = 0x0e;
+	val |= 0x0f << 8;
+	writel(val, vou->dtrc + DTRC_DEC2DDR_ARID);
+}
+
+static void vou_hw_init(struct zx_vou *vou)
+{
+	u32 val;
+
+	/* Set GL0 to main channel and GL1 to aux channel */
+	val = readl(vou->mmio + OSD_CTRL0);
+	val &= ~OSD_CTRL0_GL0_SEL;
+	val |= OSD_CTRL0_GL1_SEL;
+	writel(val, vou->mmio + OSD_CTRL0);
+
+	/* Release reset for all VOU modules */
+	writel(~0, vou->vouctl + VOU_SOFT_RST);
+
+	/* Select main clock for GL0 and aux clock for GL1 module */
+	val = readl(vou->vouctl + VOU_CLK_SEL);
+	val &= ~VOU_CLK_GL0_SEL;
+	val |= VOU_CLK_GL1_SEL;
+	writel(val, vou->vouctl + VOU_CLK_SEL);
+
+	/* Enable clock auto-gating for all VOU modules */
+	writel(~0, vou->vouctl + VOU_CLK_REQEN);
+
+	/* Enable all VOU module clocks */
+	writel(~0, vou->vouctl + VOU_CLK_EN);
+
+	/* Clear both OSD and TIMING_CTRL interrupt state */
+	writel(~0, vou->mmio + OSD_INT_CLRSTA);
+	writel(~0, vou->timing + TIMING_INT_STATE);
+
+	/* Enable OSD and TIMING_CTRL interrrupts */
+	writel(OSD_INT_ENABLE, vou->mmio + OSD_INT_MSK);
+	writel(TIMING_INT_ENABLE, vou->timing + TIMING_INT_CTRL);
+
+	/* Select GPC as input to gl/vl scaler as a sane default setting */
+	writel(0x2a, vou->otfppu + OTFPPU_RSZ_DATA_SOURCE);
+
+	/*
+	 * Needs to reset channel and layer logic per frame when frame starts
+	 * to get VOU work properly.
+	 */
+	val = readl(vou->mmio + OSD_RST_CLR);
+	val |= RST_PER_FRAME;
+	writel(val, vou->mmio + OSD_RST_CLR);
+
+	vou_dtrc_init(vou);
+}
+
+static int zx_crtc_bind(struct device *dev, struct device *master, void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct device_node *np = dev->of_node;
+	struct drm_device *drm = data;
+	struct zx_drm_private *priv = drm->dev_private;
+	struct resource res;
+	struct zx_vou *vou;
+	int irq;
+	int ret;
+
+	vou = devm_kzalloc(dev, sizeof(*vou), GFP_KERNEL);
+	if (!vou)
+		return -ENOMEM;
+
+	/*
+	 * Skip mem region request to avoid overlapping on output device
+	 * mem regions, as the regions will be requested by connector drivers.
+	 */
+	of_address_to_resource(np, 0, &res);
+	vou->mmio = devm_ioremap(dev, res.start, resource_size(&res));
+	if (!vou->mmio)
+		return -ENOMEM;
+
+	vou->timing = vou->mmio + VOU_TIMING_CTRL;
+	vou->vouctl = vou->mmio + VOU_CTRL;
+	vou->otfppu = vou->mmio + OTFPPU_CTRL;
+	vou->dtrc = vou->mmio + DTRC;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	vou->axi_clk = devm_clk_get(dev, "aclk");
+	if (IS_ERR(vou->axi_clk))
+		return PTR_ERR(vou->axi_clk);
+
+	vou->ppu_clk = devm_clk_get(dev, "ppu_wclk");
+	if (IS_ERR(vou->ppu_clk))
+		return PTR_ERR(vou->ppu_clk);
+
+	clk_prepare_enable(vou->axi_clk);
+	clk_prepare_enable(vou->ppu_clk);
+
+	vou->dev = dev;
+	priv->vou = vou;
+	dev_set_drvdata(dev, vou);
+
+	vou_hw_init(vou);
+
+	ret = devm_request_irq(dev, irq, vou_irq_handler, 0, "zx_vou", vou);
+	if (ret < 0)
+		return ret;
+
+	vou->main_crtc = zx_crtc_init(drm, VOU_CHN_MAIN);
+	if (IS_ERR(vou->main_crtc))
+		return PTR_ERR(vou->main_crtc);
+
+	vou->aux_crtc = zx_crtc_init(drm, VOU_CHN_AUX);
+	if (IS_ERR(vou->aux_crtc))
+		return PTR_ERR(vou->aux_crtc);
+
+	return 0;
+}
+
+static void zx_crtc_unbind(struct device *dev, struct device *master,
+			   void *data)
+{
+	struct zx_vou *vou = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(vou->axi_clk);
+	clk_disable_unprepare(vou->ppu_clk);
+}
+
+static const struct component_ops zx_crtc_component_ops = {
+	.bind = zx_crtc_bind,
+	.unbind = zx_crtc_unbind,
+};
+
+static int zx_crtc_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &zx_crtc_component_ops);
+}
+
+static int zx_crtc_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &zx_crtc_component_ops);
+	return 0;
+}
+
+static const struct of_device_id zx_crtc_of_match[] = {
+	{ .compatible = "zte,zx296718-vou", },
+	{ /* end */ },
+};
+MODULE_DEVICE_TABLE(of, zx_crtc_of_match);
+
+struct platform_driver zx_crtc_driver = {
+	.probe = zx_crtc_probe,
+	.remove = zx_crtc_remove,
+	.driver	= {
+		.name = "zx-crtc",
+		.of_match_table	= zx_crtc_of_match,
+	},
+};
diff --git a/drivers/gpu/drm/zte/zx_crtc.h b/drivers/gpu/drm/zte/zx_crtc.h
new file mode 100644
index 000000000000..f889208054ce
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_crtc.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2016 Linaro Ltd.
+ * Copyright 2016 ZTE Corporation.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ZX_CRTC_H__
+#define __ZX_CRTC_H__
+
+#define VOU_CRTC_MASK		0x3
+
+/* VOU output interfaces */
+enum vou_inf_id {
+	VOU_HDMI	= 0,
+	VOU_RGB_LCD	= 1,
+	VOU_TV_ENC	= 2,
+	VOU_MIPI_DSI	= 3,
+	VOU_LVDS	= 4,
+	VOU_VGA		= 5,
+};
+
+enum vou_inf_data_sel {
+	VOU_YUV444	= 0,
+	VOU_RGB_101010	= 1,
+	VOU_RGB_888	= 2,
+	VOU_RGB_666	= 3,
+};
+
+struct vou_inf {
+	struct drm_encoder *encoder;
+	enum vou_inf_id id;
+	enum vou_inf_data_sel data_sel;
+	u32 clocks_en_bits;
+	u32 clocks_sel_bits;
+};
+
+void vou_inf_enable(struct vou_inf *inf);
+void vou_inf_disable(struct vou_inf *inf);
+
+int zx_crtc_enable_vblank(struct drm_device *drm, unsigned int pipe);
+void zx_crtc_disable_vblank(struct drm_device *drm, unsigned int pipe);
+
+#endif /* __ZX_CRTC_H__ */
diff --git a/drivers/gpu/drm/zte/zx_drm_drv.c b/drivers/gpu/drm/zte/zx_drm_drv.c
new file mode 100644
index 000000000000..a45ecaa7007b
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_drm_drv.c
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2016 Linaro Ltd.
+ * Copyright 2016 ZTE Corporation.
+ *
+ * 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/module.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/list.h>
+#include <linux/of_graph.h>
+#include <linux/of_platform.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_of.h>
+
+#include "zx_drm_drv.h"
+#include "zx_crtc.h"
+
+static void zx_drm_fb_output_poll_changed(struct drm_device *drm)
+{
+	struct zx_drm_private *priv = drm->dev_private;
+
+	drm_fbdev_cma_hotplug_event(priv->fbdev);
+}
+
+static const struct drm_mode_config_funcs zx_drm_mode_config_funcs = {
+	.fb_create = drm_fb_cma_create,
+	.output_poll_changed = zx_drm_fb_output_poll_changed,
+	.atomic_check = drm_atomic_helper_check,
+	.atomic_commit = drm_atomic_helper_commit,
+};
+
+static void zx_drm_lastclose(struct drm_device *drm)
+{
+	struct zx_drm_private *priv = drm->dev_private;
+
+	drm_fbdev_cma_restore_mode(priv->fbdev);
+}
+
+static const struct file_operations zx_drm_fops = {
+	.owner = THIS_MODULE,
+	.open = drm_open,
+	.release = drm_release,
+	.unlocked_ioctl = drm_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = drm_compat_ioctl,
+#endif
+	.poll = drm_poll,
+	.read = drm_read,
+	.llseek = noop_llseek,
+	.mmap = drm_gem_cma_mmap,
+};
+
+static struct drm_driver zx_drm_driver = {
+	.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
+			   DRIVER_ATOMIC,
+	.lastclose = zx_drm_lastclose,
+	.get_vblank_counter = drm_vblank_no_hw_counter,
+	.enable_vblank = zx_crtc_enable_vblank,
+	.disable_vblank = zx_crtc_disable_vblank,
+	.gem_free_object = drm_gem_cma_free_object,
+	.gem_vm_ops = &drm_gem_cma_vm_ops,
+	.dumb_create = drm_gem_cma_dumb_create,
+	.dumb_map_offset = drm_gem_cma_dumb_map_offset,
+	.dumb_destroy = drm_gem_dumb_destroy,
+	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+	.gem_prime_export = drm_gem_prime_export,
+	.gem_prime_import = drm_gem_prime_import,
+	.gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
+	.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
+	.gem_prime_vmap = drm_gem_cma_prime_vmap,
+	.gem_prime_vunmap = drm_gem_cma_prime_vunmap,
+	.gem_prime_mmap = drm_gem_cma_prime_mmap,
+	.fops = &zx_drm_fops,
+	.name = "zx-vou",
+	.desc = "ZTE VOU Controller DRM",
+	.date = "20160811",
+	.major = 1,
+	.minor = 0,
+};
+
+static int zx_drm_bind(struct device *dev)
+{
+	struct drm_device *drm;
+	struct zx_drm_private *priv;
+	int ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	drm = drm_dev_alloc(&zx_drm_driver, dev);
+	if (!drm)
+		return -ENOMEM;
+
+	drm->dev_private = priv;
+	dev_set_drvdata(dev, drm);
+
+	drm_mode_config_init(drm);
+	drm->mode_config.min_width = 16;
+	drm->mode_config.min_height = 16;
+	drm->mode_config.max_width = 4096;
+	drm->mode_config.max_height = 4096;
+	drm->mode_config.funcs = &zx_drm_mode_config_funcs;
+
+	ret = drm_dev_register(drm, 0);
+	if (ret)
+		goto out_free;
+
+	ret = component_bind_all(dev, drm);
+	if (ret) {
+		DRM_ERROR("Failed to bind all components\n");
+		goto out_unregister;
+	}
+
+	ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
+	if (ret < 0) {
+		DRM_ERROR("failed to initialise vblank\n");
+		goto out_unbind;
+	}
+
+	/*
+	 * We will manage irq handler on our own.  In this case, irq_enabled
+	 * need to be true for using vblank core support.
+	 */
+	drm->irq_enabled = true;
+
+	drm_mode_config_reset(drm);
+	drm_kms_helper_poll_init(drm);
+
+	priv->fbdev = drm_fbdev_cma_init(drm, 32, drm->mode_config.num_crtc,
+					 drm->mode_config.num_connector);
+	if (IS_ERR(priv->fbdev)) {
+		ret = PTR_ERR(priv->fbdev);
+		priv->fbdev = NULL;
+		goto out_fini;
+	}
+
+	return 0;
+
+out_fini:
+	drm_kms_helper_poll_fini(drm);
+	drm_mode_config_cleanup(drm);
+	drm_vblank_cleanup(drm);
+out_unbind:
+	component_unbind_all(dev, drm);
+out_unregister:
+	drm_dev_unregister(drm);
+out_free:
+	dev_set_drvdata(dev, NULL);
+	drm_dev_unref(drm);
+	return ret;
+}
+
+static void zx_drm_unbind(struct device *dev)
+{
+	struct drm_device *drm = dev_get_drvdata(dev);
+	struct zx_drm_private *priv = drm->dev_private;
+
+	if (priv->fbdev) {
+		drm_fbdev_cma_fini(priv->fbdev);
+		priv->fbdev = NULL;
+	}
+	drm_kms_helper_poll_fini(drm);
+	component_unbind_all(dev, drm);
+	drm_vblank_cleanup(drm);
+	drm_mode_config_cleanup(drm);
+	drm_dev_unregister(drm);
+	drm_dev_unref(drm);
+	drm->dev_private = NULL;
+	dev_set_drvdata(dev, NULL);
+}
+
+static const struct component_master_ops zx_drm_master_ops = {
+	.bind = zx_drm_bind,
+	.unbind = zx_drm_unbind,
+};
+
+static int compare_of(struct device *dev, void *data)
+{
+	return dev->of_node == data;
+}
+
+static int zx_drm_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *parent = dev->of_node;
+	struct device_node *child;
+	struct component_match *match = NULL;
+	int ret;
+
+	ret = of_platform_populate(parent, NULL, NULL, dev);
+	if (ret)
+		return ret;
+
+	for_each_available_child_of_node(parent, child) {
+		component_match_add(dev, &match, compare_of, child);
+		of_node_put(child);
+	}
+
+	return component_master_add_with_match(dev, &zx_drm_master_ops, match);
+}
+
+static int zx_drm_remove(struct platform_device *pdev)
+{
+	component_master_del(&pdev->dev, &zx_drm_master_ops);
+	return 0;
+}
+
+static const struct of_device_id zx_drm_of_match[] = {
+	{ .compatible = "zte,zx-display-subsystem", },
+	{ /* end */ },
+};
+MODULE_DEVICE_TABLE(of, zx_drm_of_match);
+
+static struct platform_driver zx_drm_platform_driver = {
+	.probe = zx_drm_probe,
+	.remove = zx_drm_remove,
+	.driver	= {
+		.name = "zx-drm",
+		.of_match_table	= zx_drm_of_match,
+	},
+};
+
+static struct platform_driver *drivers[] = {
+	&zx_crtc_driver,
+	&zx_hdmi_driver,
+	&zx_drm_platform_driver,
+};
+
+static int zx_drm_init(void)
+{
+	return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
+}
+module_init(zx_drm_init);
+
+static void zx_drm_exit(void)
+{
+	platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
+}
+module_exit(zx_drm_exit);
+
+MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
+MODULE_DESCRIPTION("ZTE ZX VOU DRM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/zte/zx_drm_drv.h b/drivers/gpu/drm/zte/zx_drm_drv.h
new file mode 100644
index 000000000000..6aac303de6aa
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_drm_drv.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2016 Linaro Ltd.
+ * Copyright 2016 ZTE Corporation.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ZX_DRM_DRV_H__
+#define __ZX_DRM_DRV_H__
+
+struct zx_drm_private {
+	struct drm_fbdev_cma *fbdev;
+	struct zx_vou *vou;
+};
+
+extern struct platform_driver zx_crtc_driver;
+extern struct platform_driver zx_hdmi_driver;
+
+#endif /* __ZX_DRM_DRV_H__ */
diff --git a/drivers/gpu/drm/zte/zx_hdmi.c b/drivers/gpu/drm/zte/zx_hdmi.c
new file mode 100644
index 000000000000..5aaab8493b1b
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_hdmi.c
@@ -0,0 +1,540 @@
+/*
+ * Copyright 2016 Linaro Ltd.
+ * Copyright 2016 ZTE Corporation.
+ *
+ * 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 <drm/drm_of.h>
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/hdmi.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_device.h>
+#include <linux/component.h>
+
+#include "zx_crtc.h"
+
+#define FUNC_SEL			0x000b
+#define FUNC_HDMI_EN			BIT(0)
+#define CLKPWD				0x000d
+#define CLKPWD_PDIDCK			BIT(2)
+#define PWD_SRST			0x0010
+#define P2T_CTRL			0x0066
+#define P2T_DC_PKT_EN			BIT(7)
+#define L1_INTR_STAT			0x007e
+#define L1_INTR_STAT_INTR1		BIT(0)
+#define INTR1_STAT			0x008f
+#define INTR1_MASK			0x0095
+#define INTR1_MONITOR_DETECT		(BIT(5) | BIT(6))
+#define ZX_DDC_ADDR			0x00ed
+#define ZX_DDC_SEGM			0x00ee
+#define ZX_DDC_OFFSET			0x00ef
+#define ZX_DDC_DIN_CNT1			0x00f0
+#define ZX_DDC_DIN_CNT2			0x00f1
+#define ZX_DDC_CMD			0x00f3
+#define DDC_CMD_MASK			0xf
+#define DDC_CMD_CLEAR_FIFO		0x9
+#define DDC_CMD_SEQUENTIAL_READ		0x2
+#define ZX_DDC_DATA			0x00f4
+#define ZX_DDC_DOUT_CNT			0x00f5
+#define DDC_DOUT_CNT_MASK		0x1f
+#define TEST_TXCTRL			0x00f7
+#define TEST_TXCTRL_HDMI_MODE		BIT(1)
+#define HDMICTL4			0x0235
+#define TPI_HPD_RSEN			0x063b
+#define TPI_HPD_CONNECTION		(BIT(1) | BIT(2))
+#define TPI_INFO_FSEL			0x06bf
+#define FSEL_AVI			0
+#define FSEL_GBD			1
+#define FSEL_AUDIO			2
+#define FSEL_SPD			3
+#define FSEL_MPEG			4
+#define FSEL_VSIF			5
+#define TPI_INFO_B0			0x06c0
+#define TPI_INFO_EN			0x06df
+#define TPI_INFO_TRANS_EN		BIT(7)
+#define TPI_INFO_TRANS_RPT		BIT(6)
+#define TPI_DDC_MASTER_EN		0x06f8
+#define HW_DDC_MASTER			BIT(7)
+
+#define ZX_HDMI_INFOFRAME_SIZE		31
+
+struct zx_hdmi {
+	struct drm_connector connector;
+	struct drm_encoder encoder;
+	struct device *dev;
+	struct drm_device *drm;
+	void __iomem *mmio;
+	struct clk *cec_clk;
+	struct clk *osc_clk;
+	struct clk *xclk;
+	bool sink_is_hdmi;
+	bool sink_has_audio;
+	struct vou_inf *inf;
+};
+
+#define to_zx_hdmi(x)	container_of(x, struct zx_hdmi, x)
+
+static struct vou_inf vou_inf_hdmi = {
+	.id = VOU_HDMI,
+	.data_sel = VOU_YUV444,
+	.clocks_en_bits = BIT(24) | BIT(18) | BIT(6),
+	.clocks_sel_bits = BIT(13) | BIT(2),
+};
+
+static inline u8 hdmi_readb(struct zx_hdmi *hdmi, u16 offset)
+{
+	return readl_relaxed(hdmi->mmio + offset * 4);
+}
+
+static inline void hdmi_writeb(struct zx_hdmi *hdmi, u16 offset, u8 val)
+{
+	writel_relaxed(val, hdmi->mmio + offset * 4);
+}
+
+static int zx_hdmi_infoframe_trans(struct zx_hdmi *hdmi,
+				   union hdmi_infoframe *frame, u8 fsel)
+{
+	u8 buffer[ZX_HDMI_INFOFRAME_SIZE];
+	u8 val;
+	ssize_t num;
+	int i;
+
+	hdmi_writeb(hdmi, TPI_INFO_FSEL, fsel);
+
+	num = hdmi_infoframe_pack(frame, buffer, ZX_HDMI_INFOFRAME_SIZE);
+	if (num < 0)
+		return num;
+
+	for (i = 0; i < num; i++)
+		hdmi_writeb(hdmi, TPI_INFO_B0 + i, buffer[i]);
+
+	val = hdmi_readb(hdmi, TPI_INFO_EN);
+	val |= TPI_INFO_TRANS_EN | TPI_INFO_TRANS_RPT;
+	hdmi_writeb(hdmi, TPI_INFO_EN, val);
+
+	return num;
+}
+
+static int zx_hdmi_config_video_vsi(struct zx_hdmi *hdmi,
+				    struct drm_display_mode *mode)
+{
+	union hdmi_infoframe frame;
+	int ret;
+
+	ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi,
+							  mode);
+	if (ret)
+		return ret;
+
+	return zx_hdmi_infoframe_trans(hdmi, &frame, FSEL_VSIF);
+}
+
+static int zx_hdmi_config_video_avi(struct zx_hdmi *hdmi,
+				    struct drm_display_mode *mode)
+{
+	union hdmi_infoframe frame;
+	int ret;
+
+	ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode);
+	if (ret)
+		return ret;
+
+	/* We always use YUV444 for HDMI output. */
+	frame.avi.colorspace = HDMI_COLORSPACE_YUV444;
+
+	return zx_hdmi_infoframe_trans(hdmi, &frame, FSEL_AVI);
+}
+
+static void zx_hdmi_encoder_mode_set(struct drm_encoder *encoder,
+				     struct drm_display_mode *mode,
+				     struct drm_display_mode *adj_mode)
+{
+	struct zx_hdmi *hdmi = to_zx_hdmi(encoder);
+
+	if (hdmi->sink_is_hdmi) {
+		zx_hdmi_config_video_avi(hdmi, mode);
+		zx_hdmi_config_video_vsi(hdmi, mode);
+	}
+}
+
+static void zx_hdmi_encoder_enable(struct drm_encoder *encoder)
+{
+	struct zx_hdmi *hdmi = to_zx_hdmi(encoder);
+
+	vou_inf_enable(hdmi->inf);
+}
+
+static void zx_hdmi_encoder_disable(struct drm_encoder *encoder)
+{
+	struct zx_hdmi *hdmi = to_zx_hdmi(encoder);
+
+	vou_inf_disable(hdmi->inf);
+}
+
+static const struct drm_encoder_helper_funcs zx_hdmi_encoder_helper_funcs = {
+	.enable	= zx_hdmi_encoder_enable,
+	.disable = zx_hdmi_encoder_disable,
+	.mode_set = zx_hdmi_encoder_mode_set,
+};
+
+static const struct drm_encoder_funcs zx_hdmi_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+static int zx_hdmi_get_edid_block(void *data, u8 *buf, unsigned int block,
+				  size_t len)
+{
+	struct zx_hdmi *hdmi = data;
+	int retry = 0;
+	int ret = 0;
+	int i = 0;
+	u8 val;
+
+	/* Enable DDC master access */
+	val = hdmi_readb(hdmi, TPI_DDC_MASTER_EN);
+	val |= HW_DDC_MASTER;
+	hdmi_writeb(hdmi, TPI_DDC_MASTER_EN, val);
+
+	hdmi_writeb(hdmi, ZX_DDC_ADDR, 0xa0);
+	hdmi_writeb(hdmi, ZX_DDC_OFFSET, block * EDID_LENGTH);
+	/* Bits [9:8] of bytes */
+	hdmi_writeb(hdmi, ZX_DDC_DIN_CNT2, (len >> 8) & 0xff);
+	/* Bits [7:0] of bytes */
+	hdmi_writeb(hdmi, ZX_DDC_DIN_CNT1, len & 0xff);
+
+	/* Clear FIFO */
+	val = hdmi_readb(hdmi, ZX_DDC_CMD);
+	val &= ~DDC_CMD_MASK;
+	val |= DDC_CMD_CLEAR_FIFO;
+	hdmi_writeb(hdmi, ZX_DDC_CMD, val);
+
+	/* Kick off the read */
+	val = hdmi_readb(hdmi, ZX_DDC_CMD);
+	val &= ~DDC_CMD_MASK;
+	val |= DDC_CMD_SEQUENTIAL_READ;
+	hdmi_writeb(hdmi, ZX_DDC_CMD, val);
+
+	while (len > 0) {
+		int cnt, j;
+
+		/* FIFO needs some time to get ready */
+		usleep_range(500, 1000);
+
+		cnt = hdmi_readb(hdmi, ZX_DDC_DOUT_CNT) & DDC_DOUT_CNT_MASK;
+		if (cnt == 0) {
+			if (++retry > 5) {
+				dev_err(hdmi->dev, "DDC read timed out!");
+				ret = -ETIMEDOUT;
+				break;
+			}
+			continue;
+		}
+
+		for (j = 0; j < cnt; j++)
+			buf[i++] = hdmi_readb(hdmi, ZX_DDC_DATA);
+		len -= cnt;
+	}
+
+	/* Disable DDC master access */
+	val = hdmi_readb(hdmi, TPI_DDC_MASTER_EN);
+	val &= ~HW_DDC_MASTER;
+	hdmi_writeb(hdmi, TPI_DDC_MASTER_EN, val);
+
+	return ret;
+}
+
+static int zx_hdmi_connector_get_modes(struct drm_connector *connector)
+{
+	struct zx_hdmi *hdmi = to_zx_hdmi(connector);
+	struct edid *edid;
+	int ret = 0;
+
+	edid = drm_do_get_edid(connector, zx_hdmi_get_edid_block, hdmi);
+	if (edid) {
+		hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid);
+		hdmi->sink_has_audio = drm_detect_monitor_audio(edid);
+		drm_mode_connector_update_edid_property(connector, edid);
+		ret = drm_add_edid_modes(connector, edid);
+		kfree(edid);
+	}
+
+	return ret;
+}
+
+static enum drm_mode_status
+zx_hdmi_connector_mode_valid(struct drm_connector *connector,
+			     struct drm_display_mode *mode)
+{
+	return MODE_OK;
+}
+
+static struct drm_connector_helper_funcs zx_hdmi_connector_helper_funcs = {
+	.get_modes = zx_hdmi_connector_get_modes,
+	.mode_valid = zx_hdmi_connector_mode_valid,
+};
+
+static enum drm_connector_status
+zx_hdmi_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct zx_hdmi *hdmi = to_zx_hdmi(connector);
+
+	return (hdmi_readb(hdmi, TPI_HPD_RSEN) & TPI_HPD_CONNECTION) ?
+		connector_status_connected : connector_status_disconnected;
+}
+
+static void zx_hdmi_connector_destroy(struct drm_connector *connector)
+{
+	drm_connector_unregister(connector);
+	drm_connector_cleanup(connector);
+}
+
+static const struct drm_connector_funcs zx_hdmi_connector_funcs = {
+	.dpms = drm_atomic_helper_connector_dpms,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.detect = zx_hdmi_connector_detect,
+	.destroy = zx_hdmi_connector_destroy,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int zx_hdmi_register(struct drm_device *drm, struct zx_hdmi *hdmi)
+{
+	struct drm_encoder *encoder = &hdmi->encoder;
+
+	encoder->possible_crtcs = VOU_CRTC_MASK;
+
+	drm_encoder_init(drm, encoder, &zx_hdmi_encoder_funcs,
+			 DRM_MODE_ENCODER_TMDS, NULL);
+	drm_encoder_helper_add(encoder, &zx_hdmi_encoder_helper_funcs);
+
+	hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
+
+	drm_connector_init(drm, &hdmi->connector, &zx_hdmi_connector_funcs,
+			   DRM_MODE_CONNECTOR_HDMIA);
+	drm_connector_helper_add(&hdmi->connector,
+				 &zx_hdmi_connector_helper_funcs);
+
+	drm_mode_connector_attach_encoder(&hdmi->connector, encoder);
+	drm_connector_register(&hdmi->connector);
+
+	return 0;
+}
+
+static irqreturn_t zx_hdmi_irq_thread(int irq, void *dev_id)
+{
+	struct zx_hdmi *hdmi = dev_id;
+
+	drm_helper_hpd_irq_event(hdmi->connector.dev);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t zx_hdmi_irq_handler(int irq, void *dev_id)
+{
+	struct zx_hdmi *hdmi = dev_id;
+	u8 lstat;
+
+	lstat = hdmi_readb(hdmi, L1_INTR_STAT);
+
+	/* Monitor detect/HPD interrupt */
+	if (lstat & L1_INTR_STAT_INTR1) {
+		u8 stat = hdmi_readb(hdmi, INTR1_STAT);
+
+		hdmi_writeb(hdmi, INTR1_STAT, stat);
+		if (stat & INTR1_MONITOR_DETECT)
+			return IRQ_WAKE_THREAD;
+	}
+
+	return IRQ_NONE;
+}
+
+static void zx_hdmi_phy_start(struct zx_hdmi *hdmi)
+{
+	/* Copy from ZTE BSP code */
+	hdmi_writeb(hdmi, 0x222, 0x0);
+	hdmi_writeb(hdmi, 0x224, 0x4);
+	hdmi_writeb(hdmi, 0x909, 0x0);
+	hdmi_writeb(hdmi, 0x7b0, 0x90);
+	hdmi_writeb(hdmi, 0x7b1, 0x00);
+	hdmi_writeb(hdmi, 0x7b2, 0xa7);
+	hdmi_writeb(hdmi, 0x7b8, 0xaa);
+	hdmi_writeb(hdmi, 0x7b2, 0xa7);
+	hdmi_writeb(hdmi, 0x7b3, 0x0f);
+	hdmi_writeb(hdmi, 0x7b4, 0x0f);
+	hdmi_writeb(hdmi, 0x7b5, 0x55);
+	hdmi_writeb(hdmi, 0x7b7, 0x03);
+	hdmi_writeb(hdmi, 0x7b9, 0x12);
+	hdmi_writeb(hdmi, 0x7ba, 0x32);
+	hdmi_writeb(hdmi, 0x7bc, 0x68);
+	hdmi_writeb(hdmi, 0x7be, 0x40);
+	hdmi_writeb(hdmi, 0x7bf, 0x84);
+	hdmi_writeb(hdmi, 0x7c1, 0x0f);
+	hdmi_writeb(hdmi, 0x7c8, 0x02);
+	hdmi_writeb(hdmi, 0x7c9, 0x03);
+	hdmi_writeb(hdmi, 0x7ca, 0x40);
+	hdmi_writeb(hdmi, 0x7dc, 0x31);
+	hdmi_writeb(hdmi, 0x7e2, 0x04);
+	hdmi_writeb(hdmi, 0x7e0, 0x06);
+	hdmi_writeb(hdmi, 0x7cb, 0x68);
+	hdmi_writeb(hdmi, 0x7f9, 0x02);
+	hdmi_writeb(hdmi, 0x7b6, 0x02);
+	hdmi_writeb(hdmi, 0x7f3, 0x0);
+}
+
+static void zx_hdmi_hw_init(struct zx_hdmi *hdmi)
+{
+	u8 val;
+
+	/* Software reset */
+	hdmi_writeb(hdmi, PWD_SRST, 1);
+
+	/* Enable pclk */
+	val = hdmi_readb(hdmi, CLKPWD);
+	val |= CLKPWD_PDIDCK;
+	hdmi_writeb(hdmi, CLKPWD, val);
+
+	/* Enable HDMI for TX */
+	val = hdmi_readb(hdmi, FUNC_SEL);
+	val |= FUNC_HDMI_EN;
+	hdmi_writeb(hdmi, FUNC_SEL, val);
+
+	/* Enable deep color packet */
+	val = hdmi_readb(hdmi, P2T_CTRL);
+	val |= P2T_DC_PKT_EN;
+	hdmi_writeb(hdmi, P2T_CTRL, val);
+
+	/* Enable HDMI/MHL mode for output */
+	val = hdmi_readb(hdmi, TEST_TXCTRL);
+	val |= TEST_TXCTRL_HDMI_MODE;
+	hdmi_writeb(hdmi, TEST_TXCTRL, val);
+
+	/* Configure reg_qc_sel */
+	hdmi_writeb(hdmi, HDMICTL4, 0x3);
+
+	/* Enable interrupt */
+	val = hdmi_readb(hdmi, INTR1_MASK);
+	val |= INTR1_MONITOR_DETECT;
+	hdmi_writeb(hdmi, INTR1_MASK, val);
+
+	/* Clear reset for normal operation */
+	hdmi_writeb(hdmi, PWD_SRST, 0);
+
+	/* Start up phy */
+	zx_hdmi_phy_start(hdmi);
+}
+
+static int zx_hdmi_bind(struct device *dev, struct device *master, void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct drm_device *drm = data;
+	struct resource *res;
+	struct zx_hdmi *hdmi;
+	struct vou_inf *inf;
+	int irq;
+	int ret;
+
+	hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
+	if (!hdmi)
+		return -ENOMEM;
+
+	hdmi->dev = dev;
+	hdmi->drm = drm;
+
+	inf = &vou_inf_hdmi;
+	inf->encoder = &hdmi->encoder;
+	hdmi->inf = inf;
+
+	dev_set_drvdata(dev, hdmi);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	hdmi->mmio = devm_ioremap_resource(dev, res);
+	if (IS_ERR(hdmi->mmio))
+		return PTR_ERR(hdmi->mmio);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	hdmi->cec_clk = devm_clk_get(hdmi->dev, "osc_cec");
+	if (IS_ERR(hdmi->cec_clk))
+		return PTR_ERR(hdmi->cec_clk);
+
+	hdmi->osc_clk = devm_clk_get(hdmi->dev, "osc_clk");
+	if (IS_ERR(hdmi->osc_clk))
+		return PTR_ERR(hdmi->osc_clk);
+
+	hdmi->xclk = devm_clk_get(hdmi->dev, "xclk");
+	if (IS_ERR(hdmi->xclk))
+		return PTR_ERR(hdmi->xclk);
+
+	zx_hdmi_hw_init(hdmi);
+
+	clk_prepare_enable(hdmi->cec_clk);
+	clk_prepare_enable(hdmi->osc_clk);
+	clk_prepare_enable(hdmi->xclk);
+
+	ret = zx_hdmi_register(drm, hdmi);
+	if (ret)
+		return ret;
+
+	ret = devm_request_threaded_irq(dev, irq, zx_hdmi_irq_handler,
+					zx_hdmi_irq_thread, IRQF_SHARED,
+					dev_name(dev), hdmi);
+
+	return 0;
+}
+
+static void zx_hdmi_unbind(struct device *dev, struct device *master,
+			   void *data)
+{
+	struct zx_hdmi *hdmi = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(hdmi->cec_clk);
+	clk_disable_unprepare(hdmi->osc_clk);
+	clk_disable_unprepare(hdmi->xclk);
+}
+
+static const struct component_ops zx_hdmi_component_ops = {
+	.bind = zx_hdmi_bind,
+	.unbind = zx_hdmi_unbind,
+};
+
+static int zx_hdmi_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &zx_hdmi_component_ops);
+}
+
+static int zx_hdmi_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &zx_hdmi_component_ops);
+	return 0;
+}
+
+static const struct of_device_id zx_hdmi_of_match[] = {
+	{ .compatible = "zte,zx296718-hdmi", },
+	{ /* end */ },
+};
+MODULE_DEVICE_TABLE(of, zx_hdmi_of_match);
+
+struct platform_driver zx_hdmi_driver = {
+	.probe = zx_hdmi_probe,
+	.remove = zx_hdmi_remove,
+	.driver	= {
+		.name = "zx-hdmi",
+		.of_match_table	= zx_hdmi_of_match,
+	},
+};
diff --git a/drivers/gpu/drm/zte/zx_plane.c b/drivers/gpu/drm/zte/zx_plane.c
new file mode 100644
index 000000000000..7d1f3bbed210
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_plane.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright 2016 Linaro Ltd.
+ * Copyright 2016 ZTE Corporation.
+ *
+ * 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 <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_plane_helper.h>
+
+#include "zx_crtc.h"
+#include "zx_plane.h"
+
+/* GL registers */
+#define GL_CTRL0			0x00
+#define GL_UPDATE			BIT(5)
+#define GL_CTRL1			0x04
+#define GL_DATA_FMT_SHIFT		0
+#define GL_DATA_FMT_MASK		(0xf << GL_DATA_FMT_SHIFT)
+#define GL_FMT_ARGB8888			0
+#define GL_FMT_RGB888			1
+#define GL_FMT_RGB565			2
+#define GL_FMT_ARGB1555			3
+#define GL_FMT_ARGB4444			4
+#define GL_CTRL2			0x08
+#define GL_GLOBAL_ALPHA_SHIFT		8
+#define GL_GLOBAL_ALPHA_MASK		(0xff << GL_GLOBAL_ALPHA_SHIFT)
+#define GL_CTRL3			0x0c
+#define GL_SCALER_BYPASS_MODE		BIT(0)
+#define GL_STRIDE			0x18
+#define GL_ADDR				0x1c
+#define GL_SRC_SIZE			0x38
+#define GL_SRC_W_SHIFT			16
+#define GL_SRC_W_MASK			(0x3fff << GL_SRC_W_SHIFT)
+#define GL_SRC_H_SHIFT			0
+#define GL_SRC_H_MASK			(0x3fff << GL_SRC_H_SHIFT)
+#define GL_POS_START			0x9c
+#define GL_POS_END			0xa0
+#define GL_POS_X_SHIFT			16
+#define GL_POS_X_MASK			(0x1fff << GL_POS_X_SHIFT)
+#define GL_POS_Y_SHIFT			0
+#define GL_POS_Y_MASK			(0x1fff << GL_POS_Y_SHIFT)
+
+/* CSC registers */
+#define CSC_CTRL0			0x30
+#define CSC_COV_MODE_SHIFT		16
+#define CSC_COV_MODE_MASK		(0xffff << CSC_COV_MODE_SHIFT)
+#define CSC_BT601_IMAGE_RGB2YCBCR	0
+#define CSC_BT601_IMAGE_YCBCR2RGB	1
+#define CSC_BT601_VIDEO_RGB2YCBCR	2
+#define CSC_BT601_VIDEO_YCBCR2RGB	3
+#define CSC_BT709_IMAGE_RGB2YCBCR	4
+#define CSC_BT709_IMAGE_YCBCR2RGB	5
+#define CSC_BT709_VIDEO_RGB2YCBCR	6
+#define CSC_BT709_VIDEO_YCBCR2RGB	7
+#define CSC_BT2020_IMAGE_RGB2YCBCR	8
+#define CSC_BT2020_IMAGE_YCBCR2RGB	9
+#define CSC_BT2020_VIDEO_RGB2YCBCR	10
+#define CSC_BT2020_VIDEO_YCBCR2RGB	11
+#define CSC_WORK_ENABLE			BIT(0)
+
+/* RSZ registers */
+#define RSZ_SRC_CFG			0x00
+#define RSZ_DEST_CFG			0x04
+#define RSZ_ENABLE_CFG			0x14
+
+/* HBSC registers */
+#define HBSC_SATURATION			0x00
+#define HBSC_HUE			0x04
+#define HBSC_BRIGHT			0x08
+#define HBSC_CONTRAST			0x0c
+#define HBSC_THRESHOLD_COL1		0x10
+#define HBSC_THRESHOLD_COL2		0x14
+#define HBSC_THRESHOLD_COL3		0x18
+#define HBSC_CTRL0			0x28
+#define HBSC_CTRL_EN			BIT(2)
+
+struct zx_plane {
+	struct drm_plane plane;
+	void __iomem *layer;
+	void __iomem *csc;
+	void __iomem *hbsc;
+	void __iomem *rsz;
+};
+
+#define to_zx_plane(plane)	container_of(plane, struct zx_plane, plane)
+
+static const uint32_t gl_formats[] = {
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_RGB888,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_ARGB4444,
+};
+
+static int zx_gl_plane_atomic_check(struct drm_plane *plane,
+				    struct drm_plane_state *state)
+{
+	u32 src_w, src_h;
+
+	src_w = state->src_w >> 16;
+	src_h = state->src_h >> 16;
+
+	/* TODO: support scaling of the plane source */
+	if ((src_w != state->crtc_w) || (src_h != state->crtc_h))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int zx_gl_get_fmt(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XRGB8888:
+		return GL_FMT_ARGB8888;
+	case DRM_FORMAT_RGB888:
+		return GL_FMT_RGB888;
+	case DRM_FORMAT_RGB565:
+		return GL_FMT_RGB565;
+	case DRM_FORMAT_ARGB1555:
+		return GL_FMT_ARGB1555;
+	case DRM_FORMAT_ARGB4444:
+		return GL_FMT_ARGB4444;
+	default:
+		WARN_ONCE(1, "invalid pixel format %d\n", format);
+		return -EINVAL;
+	}
+}
+
+static inline void zx_gl_set_update(struct zx_plane *zplane)
+{
+	void __iomem *layer = zplane->layer;
+	u32 val;
+
+	val = readl(layer + GL_CTRL0);
+	val |= GL_UPDATE;
+	writel(val, layer + GL_CTRL0);
+}
+
+static inline void zx_gl_rsz_set_update(struct zx_plane *zplane)
+{
+	writel(1, zplane->rsz + RSZ_ENABLE_CFG);
+}
+
+void zx_plane_set_update(struct drm_plane *plane)
+{
+	struct zx_plane *zplane = to_zx_plane(plane);
+
+	zx_gl_rsz_set_update(zplane);
+	zx_gl_set_update(zplane);
+}
+
+static void zx_gl_rsz_setup(struct zx_plane *zplane, u32 src_w, u32 src_h,
+			    u32 dst_w, u32 dst_h)
+{
+	void __iomem *rsz = zplane->rsz;
+	u32 val;
+
+	val = ((src_h - 1) & 0xffff) << 16;
+	val |= (src_w - 1) & 0xffff;
+	writel(val, rsz + RSZ_SRC_CFG);
+
+	val = ((dst_h - 1) & 0xffff) << 16;
+	val |= (dst_w - 1) & 0xffff;
+	writel(val, rsz + RSZ_DEST_CFG);
+
+	zx_gl_rsz_set_update(zplane);
+}
+
+static void zx_gl_plane_atomic_update(struct drm_plane *plane,
+				      struct drm_plane_state *old_state)
+{
+	struct zx_plane *zplane = to_zx_plane(plane);
+	struct drm_framebuffer *fb = plane->state->fb;
+	struct drm_gem_cma_object *cma_obj;
+	void __iomem *layer = zplane->layer;
+	void __iomem *csc = zplane->csc;
+	void __iomem *hbsc = zplane->hbsc;
+	u32 src_x, src_y, src_w, src_h;
+	u32 dst_x, dst_y, dst_w, dst_h;
+	unsigned int depth, bpp;
+	uint32_t format;
+	dma_addr_t paddr;
+	u32 stride;
+	int fmt;
+	u32 val;
+
+	if (!fb)
+		return;
+
+	format = fb->pixel_format;
+	stride = fb->pitches[0];
+
+	src_x = plane->state->src_x >> 16;
+	src_y = plane->state->src_y >> 16;
+	src_w = plane->state->src_w >> 16;
+	src_h = plane->state->src_h >> 16;
+
+	dst_x = plane->state->crtc_x;
+	dst_y = plane->state->crtc_y;
+	dst_w = plane->state->crtc_w;
+	dst_h = plane->state->crtc_h;
+
+	drm_fb_get_bpp_depth(format, &depth, &bpp);
+
+	cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+	paddr = cma_obj->paddr + fb->offsets[0];
+	paddr += src_y * stride + src_x * bpp / 8;
+	writel(paddr, layer + GL_ADDR);
+
+	/* Set up source height/width register */
+	val = (src_w << GL_SRC_W_SHIFT) & GL_SRC_W_MASK;
+	val |= (src_h << GL_SRC_H_SHIFT) & GL_SRC_H_MASK;
+	writel(val, layer + GL_SRC_SIZE);
+
+	/* Set up start position register */
+	val = (dst_x << GL_POS_X_SHIFT) & GL_POS_X_MASK;
+	val |= (dst_y << GL_POS_Y_SHIFT) & GL_POS_Y_MASK;
+	writel(val, layer + GL_POS_START);
+
+	/* Set up end position register */
+	val = ((dst_x + dst_w) << GL_POS_X_SHIFT) & GL_POS_X_MASK;
+	val |= ((dst_y + dst_h) << GL_POS_Y_SHIFT) & GL_POS_Y_MASK;
+	writel(val, layer + GL_POS_END);
+
+	/* Set up stride register */
+	writel(stride & 0xffff, layer + GL_STRIDE);
+
+	/* Set up graphic layer data format */
+	fmt = zx_gl_get_fmt(format);
+	if (fmt >= 0) {
+		val = readl(layer + GL_CTRL1);
+		val &= ~GL_DATA_FMT_MASK;
+		val |= fmt << GL_DATA_FMT_SHIFT;
+		writel(val, layer + GL_CTRL1);
+	}
+
+	/* Initialize global alpha with a sane value */
+	val = readl(layer + GL_CTRL2);
+	val &= ~GL_GLOBAL_ALPHA_MASK;
+	val |= 0xff << GL_GLOBAL_ALPHA_SHIFT;
+	writel(val, layer + GL_CTRL2);
+
+	/* Setup CSC for the GL */
+	val = readl(csc + CSC_CTRL0);
+	val &= ~CSC_COV_MODE_MASK;
+	if (dst_h > 720)
+		val |= CSC_BT709_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT;
+	else
+		val |= CSC_BT601_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT;
+	val |= CSC_WORK_ENABLE;
+	writel(val, csc + CSC_CTRL0);
+
+	/* Always use scaler since it exists */
+	val = readl(layer + GL_CTRL3);
+	val |= GL_SCALER_BYPASS_MODE;	/* set for not bypass */
+	writel(val, layer + GL_CTRL3);
+
+	zx_gl_rsz_setup(zplane, src_w, src_h, dst_w, dst_h);
+
+	/* Enable HBSC block */
+	val = readl(hbsc + HBSC_CTRL0);
+	val |= HBSC_CTRL_EN;
+	writel(val, hbsc + HBSC_CTRL0);
+
+	zx_gl_set_update(zplane);
+}
+
+static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = {
+	.atomic_check = zx_gl_plane_atomic_check,
+	.atomic_update = zx_gl_plane_atomic_update,
+};
+
+static void zx_plane_destroy(struct drm_plane *plane)
+{
+	drm_plane_helper_disable(plane);
+	drm_plane_cleanup(plane);
+}
+
+static const struct drm_plane_funcs zx_plane_funcs = {
+	.update_plane = drm_atomic_helper_update_plane,
+	.disable_plane = drm_atomic_helper_disable_plane,
+	.destroy = zx_plane_destroy,
+	.reset = drm_atomic_helper_plane_reset,
+	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+};
+
+static void zx_plane_hbsc_init(struct zx_plane *zplane)
+{
+	void __iomem *hbsc = zplane->hbsc;
+
+	/*
+	 *  Initialize HBSC block with a sane configuration per recommedation
+	 *  from ZTE BSP code.
+	 */
+	writel(0x200, hbsc + HBSC_SATURATION);
+	writel(0x0, hbsc + HBSC_HUE);
+	writel(0x0, hbsc + HBSC_BRIGHT);
+	writel(0x200, hbsc + HBSC_CONTRAST);
+
+	writel((0x3ac << 16) | 0x40, hbsc + HBSC_THRESHOLD_COL1);
+	writel((0x3c0 << 16) | 0x40, hbsc + HBSC_THRESHOLD_COL2);
+	writel((0x3c0 << 16) | 0x40, hbsc + HBSC_THRESHOLD_COL3);
+}
+
+struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
+				void __iomem *mmio, struct zx_layer_data *data,
+				enum drm_plane_type type)
+{
+	const struct drm_plane_helper_funcs *helper;
+	struct zx_plane *zplane;
+	struct drm_plane *plane;
+	const uint32_t *formats;
+	unsigned int format_count;
+	int ret;
+
+	zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL);
+	if (!zplane)
+		return ERR_PTR(-ENOMEM);
+
+	plane = &zplane->plane;
+
+	zplane->layer = mmio + data->layer_offset;
+	zplane->hbsc = mmio + data->hbsc_offset;
+	zplane->csc = mmio + data->csc_offset;
+	zplane->rsz = mmio + data->rsz_offset;
+
+	zx_plane_hbsc_init(zplane);
+
+	switch (type) {
+	case DRM_PLANE_TYPE_PRIMARY:
+		helper = &zx_gl_plane_helper_funcs;
+		formats = gl_formats;
+		format_count = ARRAY_SIZE(gl_formats);
+		break;
+	case DRM_PLANE_TYPE_OVERLAY:
+		/* TODO: add video layer (vl) support */
+		break;
+	default:
+		return ERR_PTR(-ENODEV);
+	}
+
+	ret = drm_universal_plane_init(drm, plane, VOU_CRTC_MASK,
+				       &zx_plane_funcs, formats, format_count,
+				       type, NULL);
+	if (ret)
+		return ERR_PTR(ret);
+
+	drm_plane_helper_add(plane, helper);
+
+	return plane;
+}
diff --git a/drivers/gpu/drm/zte/zx_plane.h b/drivers/gpu/drm/zte/zx_plane.h
new file mode 100644
index 000000000000..84a4e32cfc24
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_plane.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2016 Linaro Ltd.
+ * Copyright 2016 ZTE Corporation.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ZX_PLANE_H__
+#define __ZX_PLANE_H__
+
+struct zx_layer_data {
+	u16 layer_offset;
+	u16 csc_offset;
+	u16 hbsc_offset;
+	u16 rsz_offset;
+};
+
+struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
+				void __iomem *mmio, struct zx_layer_data *data,
+				enum drm_plane_type type);
+void zx_plane_set_update(struct drm_plane *plane);
+
+#endif /* __ZX_PLANE_H__ */
-- 
1.9.1

^ permalink raw reply related

* [PATCHv9 0/6] dmaengine: rcar-dmac: add iommu support for slave transfers
From: Niklas Söderlund @ 2016-09-23  7:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160915162650.GZ13920@localhost>

Hi Vinod,

On 2016-09-15 21:56:51 +0530, Vinod Koul wrote:
> On Wed, Aug 10, 2016 at 11:07:10PM +0530, Vinod Koul wrote:
> > On Wed, Aug 10, 2016 at 01:22:13PM +0200, Niklas S?derlund wrote:
> > > Hi,
> > > 
> > > This series tries to solve the problem with DMA with device registers
> > > (MMIO registers) that are behind an IOMMU for the rcar-dmac driver. A
> > > recent patch '9575632 (dmaengine: make slave address physical)'
> > > clarifies that DMA slave address provided by clients is the physical
> > > address. This puts the task of mapping the DMA slave address from a
> > > phys_addr_t to a dma_addr_t on the DMA engine.
> > > 
> > > Without an IOMMU this is easy since the phys_addr_t and dma_addr_t are
> > > the same and no special care is needed. However if you have a IOMMU you
> > > need to map the DMA slave phys_addr_t to a dma_addr_t using something
> > > like this.
> > > 
> > > This series is based on top of v4.8-rc1. And I'm hoping to be able to collect a
> > > Ack from Russell King on patch 4/6 that adds the ARM specific part and then be
> > > able to take the whole series through the dmaengine tree. If this is not the
> > > best route I'm more then happy to do it another way.
> > > 
> > > It's tested on a Koelsch with CONFIG_IPMMU_VMSA and by enabling the
> > > ipmmu_ds node in r8a7791.dtsi. I verified operation by interacting with
> > > /dev/mmcblk1, i2c and the serial console which are devices behind the
> > > iommu.
> > 
> > As I said in last one, the dmaengine parts look fine to me. But to go thru
> > dmaengine tree I would need ACK on non dmaengine patches.
> 
> I havent heard back from this one and I am inclined to merge this one now.
> If anyone has any objects, please speak up now...

I'm just curios, do you plan to merge this series with Arnds Ack? If not 
is there anything I can do to help move the series in the right 
direction?

> 
> Also ACKs welcome...
> 

-- 
Regards,
Niklas S?derlund

^ permalink raw reply

* [PATCH V3 RFT 3/5] ARM64: dts: bcm283x: Use dtsi for USB host mode
From: Stefan Wahren @ 2016-09-23  7:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473257837.28663.80.camel@redhat.com>

Am 07.09.2016 um 16:17 schrieb Gerd Hoffmann:
>   Hi,
>
>> ARM: dts: Remove use of skeleton.dtsi from bcm283x.dtsi
>> ARM64: dts: bcm: Use a symlink to R-Pi dtsi files from arch=arm
> Picked them up.
>
>> In case of a multiplatform config with following settings the driver
>> isn't able to "detect" the role:
>>
>> CONFIG_USB=y
>> CONFIG_USB_OTG=y
>> CONFIG_USB_DWC2=y
>> CONFIG_USB_DWC2_DUAL_ROLE=y
>> CONFIG_USB_PHY=y
>> CONFIG_NOP_USB_XCEIV=y
>> CONFIG_USB_GADGET=y
>> CONFIG_USB_ZERO=y
> Configured my kernel that way so the test actually tests something ;)
>
> And ... everything looks fine.  usb ethernet works, and so does the usb
> keyboard.  /proc/device-tree/soc/usb at 7e980000/dr_mode exists and
> contains "host".
>
> Tested-by: Gerd Hoffmann <kraxel@redhat.com>
>

This patch hasn't been merged yet. Is there something wrong?

Stefan

^ permalink raw reply

* [PATCH v2 0/3] arm64: kgdb: fix single stepping
From: AKASHI Takahiro @ 2016-09-23  7:33 UTC (permalink / raw)
  To: linux-arm-kernel

Kgdb support on arm64 was merged in v3.15, but from its first appearance,
"signle step" has never worked well.

This patch fixes all the error cases I found so far.
The original patch[1] was splitted into three pieces, ones for each case.
patch#1, #2 should be applied to all the version, v3.15 and later.
pathc#3 only for v3.16 and later.

[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2014-October/295632.html

AKASHI Takahiro (3):
  arm64: kgdb: fix single stepping
  arm64: kgdb: prevent kgdb from being invoked recursively
  arm64: kgdb: disable interrupts while a software step is enabled

 arch/arm64/kernel/kgdb.c | 60 +++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 46 insertions(+), 14 deletions(-)

-- 
2.10.0

^ permalink raw reply

* [PATCH v2 1/3] arm64: kgdb: fix single stepping
From: AKASHI Takahiro @ 2016-09-23  7:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160923073327.9657-1-takahiro.akashi@linaro.org>

After entering kgdb mode, the first 'stepi' can succeed, but the following
'stepi' never executes the next instruction.

This is because a software step cannot get enabled as the software step
bit(SS) in SPSR, which is cleared by the first single stepping, will not
be set again for the following 's' commands.
Please note that this bit, as well as the software step control bit(SS)
in MDSCR, must be set before resuming the execution.
kernel_active_single_step() called by kgdb_arch_handle_exception() checks
only for the bit in MDSCR, and so kgdb_enable_single_step() will never be
called.

This patch removes kgdb_disable_single_step() from 'c' command handling
and enables/disables a single step explicitly at every entry and exit
of 's' command handling.

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Jason Wessel <jason.wessel@windriver.com>
Cc: <stable@vger.kernel.org> # 3.15-
---
 arch/arm64/kernel/kgdb.c | 13 +++----------
 1 file changed, 3 insertions(+), 10 deletions(-)

diff --git a/arch/arm64/kernel/kgdb.c b/arch/arm64/kernel/kgdb.c
index 8c57f64..afe5f90 100644
--- a/arch/arm64/kernel/kgdb.c
+++ b/arch/arm64/kernel/kgdb.c
@@ -189,14 +189,6 @@ int kgdb_arch_handle_exception(int exception_vector, int signo,
 		 * over and over again.
 		 */
 		kgdb_arch_update_addr(linux_regs, remcom_in_buffer);
-		atomic_set(&kgdb_cpu_doing_single_step, -1);
-		kgdb_single_step =  0;
-
-		/*
-		 * Received continue command, disable single step
-		 */
-		if (kernel_active_single_step())
-			kernel_disable_single_step();
 
 		err = 0;
 		break;
@@ -211,8 +203,6 @@ int kgdb_arch_handle_exception(int exception_vector, int signo,
 		 */
 		kgdb_arch_update_addr(linux_regs, remcom_in_buffer);
 		atomic_set(&kgdb_cpu_doing_single_step, raw_smp_processor_id());
-		kgdb_single_step =  1;
-
 		/*
 		 * Enable single step handling
 		 */
@@ -244,6 +234,9 @@ NOKPROBE_SYMBOL(kgdb_compiled_brk_fn);
 
 static int kgdb_step_brk_fn(struct pt_regs *regs, unsigned int esr)
 {
+	kernel_disable_single_step();
+	atomic_set(&kgdb_cpu_doing_single_step, -1);
+
 	kgdb_handle_exception(1, SIGTRAP, 0, regs);
 	return 0;
 }
-- 
2.10.0

^ permalink raw reply related

* [PATCH v2 2/3] arm64: kgdb: prevent kgdb from being invoked recursively
From: AKASHI Takahiro @ 2016-09-23  7:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160923073327.9657-1-takahiro.akashi@linaro.org>

If a breakpoint is set in an interrupt-sensitive place,
like gic_handle_irq(), a debug exception can be triggerred recursively.
We will see the following message:

    KGDB: re-enter error: breakpoint removed ffffffc000081258
    ------------[ cut here ]------------
    WARNING: CPU: 0 PID: 650 at kernel/debug/debug_core.c:435
                                        kgdb_handle_exception+0x1dc/0x1f4()
    Modules linked in:
    CPU: 0 PID: 650 Comm: sh Not tainted 3.17.0-rc2+ #177
    Call trace:
    [<ffffffc000087fac>] dump_backtrace+0x0/0x130
    [<ffffffc0000880ec>] show_stack+0x10/0x1c
    [<ffffffc0004d683c>] dump_stack+0x74/0xb8
    [<ffffffc0000ab824>] warn_slowpath_common+0x8c/0xb4
    [<ffffffc0000ab90c>] warn_slowpath_null+0x14/0x20
    [<ffffffc000121bfc>] kgdb_handle_exception+0x1d8/0x1f4
    [<ffffffc000092ffc>] kgdb_brk_fn+0x18/0x28
    [<ffffffc0000821c8>] brk_handler+0x9c/0xe8
    [<ffffffc0000811e8>] do_debug_exception+0x3c/0xac
    Exception stack(0xffffffc07e027650 to 0xffffffc07e027770)
    ...
    [<ffffffc000083cac>] el1_dbg+0x14/0x68
    [<ffffffc00012178c>] kgdb_cpu_enter+0x464/0x5c0
    [<ffffffc000121bb4>] kgdb_handle_exception+0x190/0x1f4
    [<ffffffc000092ffc>] kgdb_brk_fn+0x18/0x28
    [<ffffffc0000821c8>] brk_handler+0x9c/0xe8
    [<ffffffc0000811e8>] do_debug_exception+0x3c/0xac
    Exception stack(0xffffffc07e027ac0 to 0xffffffc07e027be0)
    ...
    [<ffffffc000083cac>] el1_dbg+0x14/0x68
    [<ffffffc00032e4b4>] __handle_sysrq+0x11c/0x190
    [<ffffffc00032e93c>] write_sysrq_trigger+0x4c/0x60
    [<ffffffc0001e7d58>] proc_reg_write+0x54/0x84
    [<ffffffc000192fa4>] vfs_write+0x98/0x1c8
    [<ffffffc0001939b0>] SyS_write+0x40/0xa0

When some interrupt occurs, a breakpoint at gic_handle_irq() invokes kgdb.
Kgdb then calls kgdb_roundup_cpus() to sync with other cpus. Current
kgdb_roundup_cpus() unmasks interrupts temporarily to use
smp_call_function(). This eventually allows another interrupt to occur and
likely results in hitting a breakpoint at gic_handle_irq() again since
a debug exception is always enabled in el1_irq.

We can avoid this issue by specifying "nokgdbroundup" in a kernel command
line, but this will also leave other cpus be in unknown state in terms of
kgdb, and may result in interfering with kgdb.

This patch re-implements kgdb_roundup_cpus() so that we won't have to
enable interrupts there by using irq_work.

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Jason Wessel <jason.wessel@windriver.com>
Cc: <stable@vger.kernel.org> # 3.15-
---
 arch/arm64/kernel/kgdb.c | 32 ++++++++++++++++++++++++++++----
 1 file changed, 28 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kernel/kgdb.c b/arch/arm64/kernel/kgdb.c
index afe5f90..59c4aec 100644
--- a/arch/arm64/kernel/kgdb.c
+++ b/arch/arm64/kernel/kgdb.c
@@ -19,10 +19,13 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/cpumask.h>
 #include <linux/irq.h>
+#include <linux/irq_work.h>
 #include <linux/kdebug.h>
 #include <linux/kgdb.h>
 #include <linux/kprobes.h>
+#include <linux/percpu.h>
 #include <asm/traps.h>
 
 struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
@@ -106,6 +109,8 @@ struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
 	{ "fpcr", 4, -1 },
 };
 
+static DEFINE_PER_CPU(struct irq_work, kgdb_irq_work);
+
 char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
 {
 	if (regno >= DBG_MAX_REG_NUM || regno < 0)
@@ -258,16 +263,27 @@ static struct step_hook kgdb_step_hook = {
 	.fn		= kgdb_step_brk_fn
 };
 
-static void kgdb_call_nmi_hook(void *ignored)
+static void kgdb_roundup_hook(struct irq_work *work)
 {
 	kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
 }
 
 void kgdb_roundup_cpus(unsigned long flags)
 {
-	local_irq_enable();
-	smp_call_function(kgdb_call_nmi_hook, NULL, 0);
-	local_irq_disable();
+	int cpu;
+	struct cpumask mask;
+	struct irq_work *work;
+
+	mask = *cpu_online_mask;
+	cpumask_clear_cpu(smp_processor_id(), &mask);
+	cpu = cpumask_first(&mask);
+	if (cpu >= nr_cpu_ids)
+		return;
+
+	for_each_cpu(cpu, &mask) {
+		work = per_cpu_ptr(&kgdb_irq_work, cpu);
+		irq_work_queue_on(work, cpu);
+	}
 }
 
 static int __kgdb_notify(struct die_args *args, unsigned long cmd)
@@ -308,6 +324,8 @@ static struct notifier_block kgdb_notifier = {
 int kgdb_arch_init(void)
 {
 	int ret = register_die_notifier(&kgdb_notifier);
+	int cpu;
+	struct irq_work *work;
 
 	if (ret != 0)
 		return ret;
@@ -315,6 +333,12 @@ int kgdb_arch_init(void)
 	register_break_hook(&kgdb_brkpt_hook);
 	register_break_hook(&kgdb_compiled_brkpt_hook);
 	register_step_hook(&kgdb_step_hook);
+
+	for_each_possible_cpu(cpu) {
+		work = per_cpu_ptr(&kgdb_irq_work, cpu);
+		init_irq_work(work, kgdb_roundup_hook);
+	}
+
 	return 0;
 }
 
-- 
2.10.0

^ permalink raw reply related

* [PATCH v2 3/3] arm64: kgdb: disable interrupts while a software step is enabled
From: AKASHI Takahiro @ 2016-09-23  7:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160923073327.9657-1-takahiro.akashi@linaro.org>

After entering kgdb mode, 'stepi' may unexpectedly breaks the execution
somewhere in el1_irq.

This happens because a debug exception is always enabled in el1_irq
due to the following commit merged in v3.16:
  commit 2a2830703a23 ("arm64: debug: avoid accessing mdscr_el1 on fault
			paths where possible")
A pending interrupt can be taken after kgdb has enabled a software step,
but before a debug exception is actually taken.

This patch enforces interrupts to be masked while single stepping.

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Jason Wessel <jason.wessel@windriver.com>
Cc: <stable@vger.kernel.org> # 3.16-
---
 arch/arm64/kernel/kgdb.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/arch/arm64/kernel/kgdb.c b/arch/arm64/kernel/kgdb.c
index 59c4aec..6732a27 100644
--- a/arch/arm64/kernel/kgdb.c
+++ b/arch/arm64/kernel/kgdb.c
@@ -26,6 +26,7 @@
 #include <linux/kgdb.h>
 #include <linux/kprobes.h>
 #include <linux/percpu.h>
+#include <asm/ptrace.h>
 #include <asm/traps.h>
 
 struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
@@ -109,6 +110,7 @@ struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
 	{ "fpcr", 4, -1 },
 };
 
+static DEFINE_PER_CPU(unsigned int, kgdb_pstate);
 static DEFINE_PER_CPU(struct irq_work, kgdb_irq_work);
 
 char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
@@ -198,6 +200,10 @@ int kgdb_arch_handle_exception(int exception_vector, int signo,
 		err = 0;
 		break;
 	case 's':
+		/* mask interrupts while single stepping */
+		__this_cpu_write(kgdb_pstate, linux_regs->pstate);
+		linux_regs->pstate |= PSR_I_BIT;
+
 		/*
 		 * Update step address value with address passed
 		 * with step packet.
@@ -239,9 +245,18 @@ NOKPROBE_SYMBOL(kgdb_compiled_brk_fn);
 
 static int kgdb_step_brk_fn(struct pt_regs *regs, unsigned int esr)
 {
+	unsigned int pstate;
+
 	kernel_disable_single_step();
 	atomic_set(&kgdb_cpu_doing_single_step, -1);
 
+	/* restore interrupt mask status */
+	pstate = __this_cpu_read(kgdb_pstate);
+	if (pstate & PSR_I_BIT)
+		regs->pstate |= PSR_I_BIT;
+	else
+		regs->pstate &= ~PSR_I_BIT;
+
 	kgdb_handle_exception(1, SIGTRAP, 0, regs);
 	return 0;
 }
-- 
2.10.0

^ permalink raw reply related

* [PATCH v2] ARM: dts: wheat: add DU support
From: Simon Horman @ 2016-09-23  7:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <3066182.ZErLCrPBIM@wasted.cogentembedded.com>

On Fri, Sep 23, 2016 at 12:06:43AM +0300, Sergei Shtylyov wrote:
> Define  the  Wheat board dependent  part of the DU device node.
> Add the device nodes for the Analog Devices ADV7513 HDMI transmitters
> connected to DU0/1.  Add the necessary subnodes to interconnect DU with
> HDMI transmitters/connectors.
> 
> Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>

Thanks, I have queued this up.

^ permalink raw reply

* [PATCH v2] arm: dts: zynq: Add MicroZed board support
From: Jagan Teki @ 2016-09-23  7:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4a586da6-8d94-bfbe-ea0c-58b6f8573e7b@xilinx.com>

On Fri, Sep 23, 2016 at 11:33 AM, Michal Simek <michal.simek@xilinx.com> wrote:
> On 22.9.2016 22:59, S?ren Brinkmann wrote:
>> On Thu, 2016-09-22 at 18:51:29 +0530, Jagan Teki wrote:
>>> From: Jagan Teki <jteki@openedev.com>
>>>
>>> Added basic dts support for MicroZed board.
>>>
>>> - UART
>>> - SDHCI
>>> - Ethernet
>>>
>>> Cc: Soren Brinkmann <soren.brinkmann@xilinx.com>
>>> Cc: Michal Simek <michal.simek@xilinx.com>
>>> Signed-off-by: Jagan Teki <jteki@openedev.com>
>>> ---
>>> Changes for v2:
>>>      - Add SDHCI
>>>      - Add Ethernet
>>>
>>>  arch/arm/boot/dts/Makefile          |  1 +
>>>  arch/arm/boot/dts/zynq-microzed.dts | 95 +++++++++++++++++++++++++++++++++++++
>>>  2 files changed, 96 insertions(+)
>>>  create mode 100644 arch/arm/boot/dts/zynq-microzed.dts
>>>
>>> diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
>>> index faacd52..4d7b858 100644
>>> --- a/arch/arm/boot/dts/Makefile
>>> +++ b/arch/arm/boot/dts/Makefile
>>> @@ -862,6 +862,7 @@ dtb-$(CONFIG_ARCH_VT8500) += \
>>>      wm8750-apc8750.dtb \
>>>      wm8850-w70v2.dtb
>>>  dtb-$(CONFIG_ARCH_ZYNQ) += \
>>> +    zynq-microzed.dtb \
>>>      zynq-parallella.dtb \
>>>      zynq-zc702.dtb \
>>>      zynq-zc706.dtb \
>>> diff --git a/arch/arm/boot/dts/zynq-microzed.dts b/arch/arm/boot/dts/zynq-microzed.dts
>>> new file mode 100644
>>> index 0000000..9e64496
>>> --- /dev/null
>>> +++ b/arch/arm/boot/dts/zynq-microzed.dts
>>> @@ -0,0 +1,95 @@
>>> +/*
>>> + * Copyright (C) 2015 Jagan Teki <jteki@openedev.com>
>
>
> Did you created only yourself without copying part of this from others?
> There is dts in u-boot which I believe you are aware of.

I sent the initial one few months back so at that time, I was created
and now I just added USB and Ethernet with the reference of zc702
board.

thanks!
-- 
Jagan.

^ permalink raw reply

* [PATCH 0/2] Add R8A7792 MSIOF support
From: Simon Horman @ 2016-09-23  7:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <19842984-5776-0740-7552-f63ce30d4bdd@cogentembedded.com>

On Fri, Sep 23, 2016 at 12:18:52AM +0300, Sergei Shtylyov wrote:
> Hello.
> 
> On 09/05/2016 11:54 PM, Sergei Shtylyov wrote:
> 
> >   Here's the set of 2 patches against Simon Horman's 'renesas.git' repo,
> >'renesas-devel-20160905-v4.8-rc5' tag. We're adding the R8A7792 MSIOF clocks
> >and device nodes. I'm not posting the board patches because the MSIOF driver
> >seems erratic ATM...
> >
> >[1/2] ARM: dts: r8a7792: add MSIOF clock
> >[2/2] ARM: dts: r8a7792: add MSIOF support
> 
>    These seem stuck for no apparent reason. Simon?

Thanks, I have queued these up.

^ permalink raw reply

* [PATCH v2] arm64: kgdb: handle read-only text / modules
From: AKASHI Takahiro @ 2016-09-23  7:41 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160921085721.GA18176@leverpostej>

On Wed, Sep 21, 2016 at 09:57:21AM +0100, Mark Rutland wrote:
> On Wed, Sep 21, 2016 at 04:19:55PM +0900, AKASHI Takahiro wrote:
> > Handle read-only cases (CONFIG_DEBUG_RODATA/CONFIG_DEBUG_SET_MODULE_RONX)
> > by using aarch64_insn_write() instead of probe_kernel_write().
> > See how this works:
> >     commit 2f896d586610 ("arm64: use fixmap for text patching")
> > 
> > Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> > Cc: Catalin Marinas <catalin.marinas@arm.com>
> > Cc: Will Deacon <will.deacon@arm.com>
> > Cc: Jason Wessel <jason.wessel@windriver.com>
> > Cc: <stable@vger.kernel.org> # 3.18-3.19: 2f896d5: arm64: use fixmap
> > Cc: <stable@vger.kernel.org> # 4.0-
> 
> For v3.18-v3.19, we also need commit f6242cac10427c54 ("arm64: Fix text
> patching logic when using fixmap"), so as to not break the
> !CONFIG_DEBUG_SET_MODULE_RONX case.

Ah, thank you.
I will post the patch as v2.1.

-Takahiro AKASHI

> With that:
> 
> Reviewed-by: Mark Rutland <mark.rutland@arm.com>
> 
> Thanks,
> Mark.
> 
> > ---
> >  arch/arm64/include/asm/debug-monitors.h |  2 --
> >  arch/arm64/kernel/kgdb.c                | 36 ++++++++++++++++++++++-----------
> >  2 files changed, 24 insertions(+), 14 deletions(-)
> > 
> > diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h
> > index 4b6b3f7..b71420a 100644
> > --- a/arch/arm64/include/asm/debug-monitors.h
> > +++ b/arch/arm64/include/asm/debug-monitors.h
> > @@ -61,8 +61,6 @@
> >  
> >  #define AARCH64_BREAK_KGDB_DYN_DBG	\
> >  	(AARCH64_BREAK_MON | (KGDB_DYN_DBG_BRK_IMM << 5))
> > -#define KGDB_DYN_BRK_INS_BYTE(x)	\
> > -	((AARCH64_BREAK_KGDB_DYN_DBG >> (8 * (x))) & 0xff)
> >  
> >  #define CACHE_FLUSH_IS_SAFE		1
> >  
> > diff --git a/arch/arm64/kernel/kgdb.c b/arch/arm64/kernel/kgdb.c
> > index 6732a27..b06a7a2 100644
> > --- a/arch/arm64/kernel/kgdb.c
> > +++ b/arch/arm64/kernel/kgdb.c
> > @@ -19,6 +19,7 @@
> >   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> >   */
> >  
> > +#include <linux/bug.h>
> >  #include <linux/cpumask.h>
> >  #include <linux/irq.h>
> >  #include <linux/irq_work.h>
> > @@ -26,6 +27,8 @@
> >  #include <linux/kgdb.h>
> >  #include <linux/kprobes.h>
> >  #include <linux/percpu.h>
> > +#include <asm/debug-monitors.h>
> > +#include <asm/insn.h>
> >  #include <asm/ptrace.h>
> >  #include <asm/traps.h>
> >  
> > @@ -370,15 +373,24 @@ void kgdb_arch_exit(void)
> >  	unregister_die_notifier(&kgdb_notifier);
> >  }
> >  
> > -/*
> > - * ARM instructions are always in LE.
> > - * Break instruction is encoded in LE format
> > - */
> > -struct kgdb_arch arch_kgdb_ops = {
> > -	.gdb_bpt_instr = {
> > -		KGDB_DYN_BRK_INS_BYTE(0),
> > -		KGDB_DYN_BRK_INS_BYTE(1),
> > -		KGDB_DYN_BRK_INS_BYTE(2),
> > -		KGDB_DYN_BRK_INS_BYTE(3),
> > -	}
> > -};
> > +struct kgdb_arch arch_kgdb_ops;
> > +
> > +int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
> > +{
> > +	int err;
> > +
> > +	BUILD_BUG_ON(AARCH64_INSN_SIZE != BREAK_INSTR_SIZE);
> > +
> > +	err = aarch64_insn_read((void *)bpt->bpt_addr, (u32 *)bpt->saved_instr);
> > +	if (err)
> > +		return err;
> > +
> > +	return aarch64_insn_write((void *)bpt->bpt_addr,
> > +			(u32)AARCH64_BREAK_KGDB_DYN_DBG);
> > +}
> > +
> > +int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
> > +{
> > +	return aarch64_insn_write((void *)bpt->bpt_addr,
> > +			*(u32 *)bpt->saved_instr);
> > +}
> > -- 
> > 2.10.0
> > 

^ permalink raw reply

* [PATCH v2.1] arm64: kgdb: handle read-only text / modules
From: AKASHI Takahiro @ 2016-09-23  7:42 UTC (permalink / raw)
  To: linux-arm-kernel

Handle read-only cases (CONFIG_DEBUG_RODATA/CONFIG_DEBUG_SET_MODULE_RONX)
by using aarch64_insn_write() instead of probe_kernel_write().
See how this works:
    commit 2f896d586610 ("arm64: use fixmap for text patching")

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Jason Wessel <jason.wessel@windriver.com>
Cc: <stable@vger.kernel.org> # 3.18-3.19: 2f896d5: arm64: use fixmap
Cc: <stable@vger.kernel.org> # 3.18-3.19: f6242ca: arm64: Fix text
Cc: <stable@vger.kernel.org> # 4.0-
---
 arch/arm64/include/asm/debug-monitors.h |  2 --
 arch/arm64/kernel/kgdb.c                | 36 ++++++++++++++++++++++-----------
 2 files changed, 24 insertions(+), 14 deletions(-)

diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h
index 4b6b3f7..b71420a 100644
--- a/arch/arm64/include/asm/debug-monitors.h
+++ b/arch/arm64/include/asm/debug-monitors.h
@@ -61,8 +61,6 @@
 
 #define AARCH64_BREAK_KGDB_DYN_DBG	\
 	(AARCH64_BREAK_MON | (KGDB_DYN_DBG_BRK_IMM << 5))
-#define KGDB_DYN_BRK_INS_BYTE(x)	\
-	((AARCH64_BREAK_KGDB_DYN_DBG >> (8 * (x))) & 0xff)
 
 #define CACHE_FLUSH_IS_SAFE		1
 
diff --git a/arch/arm64/kernel/kgdb.c b/arch/arm64/kernel/kgdb.c
index 6732a27..b06a7a2 100644
--- a/arch/arm64/kernel/kgdb.c
+++ b/arch/arm64/kernel/kgdb.c
@@ -19,6 +19,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/bug.h>
 #include <linux/cpumask.h>
 #include <linux/irq.h>
 #include <linux/irq_work.h>
@@ -26,6 +27,8 @@
 #include <linux/kgdb.h>
 #include <linux/kprobes.h>
 #include <linux/percpu.h>
+#include <asm/debug-monitors.h>
+#include <asm/insn.h>
 #include <asm/ptrace.h>
 #include <asm/traps.h>
 
@@ -370,15 +373,24 @@ void kgdb_arch_exit(void)
 	unregister_die_notifier(&kgdb_notifier);
 }
 
-/*
- * ARM instructions are always in LE.
- * Break instruction is encoded in LE format
- */
-struct kgdb_arch arch_kgdb_ops = {
-	.gdb_bpt_instr = {
-		KGDB_DYN_BRK_INS_BYTE(0),
-		KGDB_DYN_BRK_INS_BYTE(1),
-		KGDB_DYN_BRK_INS_BYTE(2),
-		KGDB_DYN_BRK_INS_BYTE(3),
-	}
-};
+struct kgdb_arch arch_kgdb_ops;
+
+int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
+{
+	int err;
+
+	BUILD_BUG_ON(AARCH64_INSN_SIZE != BREAK_INSTR_SIZE);
+
+	err = aarch64_insn_read((void *)bpt->bpt_addr, (u32 *)bpt->saved_instr);
+	if (err)
+		return err;
+
+	return aarch64_insn_write((void *)bpt->bpt_addr,
+			(u32)AARCH64_BREAK_KGDB_DYN_DBG);
+}
+
+int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
+{
+	return aarch64_insn_write((void *)bpt->bpt_addr,
+			*(u32 *)bpt->saved_instr);
+}
-- 
2.10.0

^ permalink raw reply related

* [PATCH 0/3] regulator: axp20x: Simplify various code
From: Jean-Francois Moine @ 2016-09-23  7:44 UTC (permalink / raw)
  To: linux-arm-kernel

This patch series just simplifies a bit the code of the AXP20x driver.
It does not contain any fonctional changes.
It will be used as a base for adding new AXP devices (patches to come).
It applies on linux-next.

Jean-Francois Moine (3):
  regulator: axp20x: simplify poly-phase handling
  regulator: axp20x: simplify the treatment of linked regulators
  regulator: axp20x: simplify device access

 drivers/regulator/axp20x-regulator.c | 114 ++++++++++++++++++-----------------
 1 file changed, 60 insertions(+), 54 deletions(-)

-- 
2.10.0

^ permalink raw reply

* [PATCHv2 1/3] Documentation: dt: Add TI SCI clock driver
From: Tero Kristo @ 2016-09-23  8:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160912131038.GA13103@rob-hp-laptop>

On 12/09/16 16:10, Rob Herring wrote:
> On Thu, Sep 01, 2016 at 03:40:33PM +0300, Tero Kristo wrote:
>> Add a clock implementation, TI SCI clock, that will hook to the common
>> clock framework, and allow each clock to be controlled via TI SCI
>> protocol.
>>
>> Signed-off-by: Tero Kristo <t-kristo@ti.com>
>> Tested-by: Dave Gerlach <d-gerlach@ti.com>
>> Signed-off-by: Nishanth Menon <nm@ti.com>
>> ---
>>  .../devicetree/bindings/clock/ti,sci-clk.txt       | 51 ++++++++++++++++++++++
>>  MAINTAINERS                                        |  1 +
>>  2 files changed, 52 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/clock/ti,sci-clk.txt
>>
>> diff --git a/Documentation/devicetree/bindings/clock/ti,sci-clk.txt b/Documentation/devicetree/bindings/clock/ti,sci-clk.txt
>> new file mode 100644
>> index 0000000..231cb80
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/clock/ti,sci-clk.txt
>> @@ -0,0 +1,51 @@
>> +Texas Instruments TI-SCI Clocks
>> +===============================
>> +
>> +All clocks on Texas Instruments' SoCs that contain a System Controller,
>> +are only controlled by this entity. Communication between a host processor
>> +running an OS and the System Controller happens through a protocol known
>> +as TI-SCI[1]. This clock implementation plugs into the common clock
>> +framework and makes use of the TI-SCI protocol on clock API requests.
>> +
>> +[1] Documentation/devicetree/bindings/arm/keystone/ti,sci.txt
>> +
>> +Required properties:
>> +-------------------
>> +- compatible: Must be "ti,sci-clk"
>> +- #clock-cells: Shall be 2.
>> +  In clock consumers, this cell represents the device ID and clock ID
>> +  exposed by the PM firmware. The assignments can be found in the header
>> +  files <dt-bindings/genpd/<soc>.h> (which covers the device IDs) and
>> +  <dt-bindings/clock/<soc>.h> (which covers the clock IDs), where <soc>
>> +  is the SoC involved, for example 'k2g'.
>> +- ti,sci: Phandle to the TI SCI device to use for managing the clocks
>> +
>> +Optional properties:
>> +-------------------
>> +- ti,ssc-clocks: Array of phandle clocks that shall enable spread spectrum
>> +		 clocking while enabled
>> +- ti,allow-freq-change-clocks: Array of phandle clocks that shall allow
>> +			       dynamic clock frequency changes by firmware
>> +- ti,input-term-clocks: Array of phandle clocks that shall enable input
>> +			termination
>
> These seem like a random set of features to control. What determines the
> clocks for these? If it is based on the SoC, then make your compatible
> string SoC specific and don't put this into DT.

Currently nobody seems to be using these flags, so I will just drop the 
support for these from the next rev. If anybody will need them at some 
point, I will figure out how to support these.

-Tero

^ permalink raw reply

* [PATCHv2 3/3] clk: keystone: Add sci-clk driver support
From: Tero Kristo @ 2016-09-23  8:06 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160916230101.GM7243@codeaurora.org>

On 17/09/16 02:01, Stephen Boyd wrote:
> On 09/05, Tero Kristo wrote:
>> On 03/09/16 02:32, Stephen Boyd wrote:
>>> I still don't get it. We should be registering hw pointers in
>>> probe and handing them out in the xlate function. Not register
>>> hws in the xlate function and then handing them out as well. I
>>> haven't reviewed anything else in this patch.
>>
>> Ok, let me try to explain the functionality.
>>
>> Probe time hw pointer registration is only needed for special clocks
>> that require extra flags, like adding the spread spectrum flag.
>> There is ever going to be only handful of these.
>>
>> Xlate checks out the sci_clk list, and picks up an existing hw clock
>> if it is there. If not, it will create a new one. The reason this is
>> done like this, the device IDs / clock IDs don't mean anything to
>> the driver itself, the driver just passes these forward to the
>> underlying SCI fwk. And, we don't have inherent knowledge of valid
>> device / clock IDs either, the SCI fwk returns a failure if a
>> specific clock ID is bad. The device / clock IDs are going to be
>> different between different generations of SoC also, and in addition
>> there can be holes in the ID ranges.
>
> Ok. Thanks for the explanation.
>
> I understand the desire to make this SoC agnostic and consumer/dt
> driven. Constructor pattern and all. Unfortunately the OF clk
> provider is a getter pattern; not a constructor pattern. I'm
> seriously concerned about the locking here because we're in the
> framework creating a clk and tying it into a consumer list which
> could cause all sorts of problems if we want to reenter the
> framework and register more clks. Recursion abounds and my head
> explodes! The recursive clk prepare mutex is not something anyone
> should be thrilled about keeping around.
>
> So, just don't do this. Instead, register the clks during probe
> that exist for the firmware. That list could be discoverable with
> firmware calls, or known based on different compatible strings
> from DT that have the soc name in it, or something else. Even
> scanning the entire DT tree for
>
> 	clocks = <&my_clk_node x y>
> 	
> would be better, but probably hugely inefficient and outright
> buggy with DT overlays so don't do it. If the firmware can't tell
> us what clks are there, just have a table based on compatible
> string and be done.

Ok, I will add a static mapping of valid clock IDs within the driver and 
init all of these during probe. I have a working solution for this 
already, but will post it out only once 4.9-rc1 is out.

-Tero

^ permalink raw reply

* [PATCH V3 RFT 3/5] ARM64: dts: bcm283x: Use dtsi for USB host mode
From: Eric Anholt @ 2016-09-23  8:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <aeba1434-3903-3ec4-1a94-e5c8229f4e5f@i2se.com>

Stefan Wahren <stefan.wahren@i2se.com> writes:

> Am 07.09.2016 um 16:17 schrieb Gerd Hoffmann:
>>   Hi,
>>
>>> ARM: dts: Remove use of skeleton.dtsi from bcm283x.dtsi
>>> ARM64: dts: bcm: Use a symlink to R-Pi dtsi files from arch=arm
>> Picked them up.
>>
>>> In case of a multiplatform config with following settings the driver
>>> isn't able to "detect" the role:
>>>
>>> CONFIG_USB=y
>>> CONFIG_USB_OTG=y
>>> CONFIG_USB_DWC2=y
>>> CONFIG_USB_DWC2_DUAL_ROLE=y
>>> CONFIG_USB_PHY=y
>>> CONFIG_NOP_USB_XCEIV=y
>>> CONFIG_USB_GADGET=y
>>> CONFIG_USB_ZERO=y
>> Configured my kernel that way so the test actually tests something ;)
>>
>> And ... everything looks fine.  usb ethernet works, and so does the usb
>> keyboard.  /proc/device-tree/soc/usb at 7e980000/dr_mode exists and
>> contains "host".
>>
>> Tested-by: Gerd Hoffmann <kraxel@redhat.com>
>>
>
> This patch hasn't been merged yet. Is there something wrong?

I hadn't bumped it back to todo from RFT.  Also, is this a priority
patch, since submitting merges is a pain?  Does USB break in some way
without it?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 800 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160923/c5dd2a13/attachment.sig>

^ permalink raw reply

* [PATCH v2 0/3] arm64: kgdb: fix single stepping
From: Greg KH @ 2016-09-23  8:16 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160923073327.9657-1-takahiro.akashi@linaro.org>

On Fri, Sep 23, 2016 at 04:33:24PM +0900, AKASHI Takahiro wrote:
> Kgdb support on arm64 was merged in v3.15, but from its first appearance,
> "signle step" has never worked well.
> 
> This patch fixes all the error cases I found so far.
> The original patch[1] was splitted into three pieces, ones for each case.
> patch#1, #2 should be applied to all the version, v3.15 and later.
> pathc#3 only for v3.16 and later.

As this is not a regression (i.e. it has never worked), why is this
something for stable releases?

thanks,

greg k-h

^ permalink raw reply

* [PATCH V3 RFT 3/5] ARM64: dts: bcm283x: Use dtsi for USB host mode
From: Stefan Wahren @ 2016-09-23  8:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <87zimz821m.fsf@eliezer.anholt.net>

Am 23.09.2016 um 10:15 schrieb Eric Anholt:
> Stefan Wahren <stefan.wahren@i2se.com> writes:
>
>> Am 07.09.2016 um 16:17 schrieb Gerd Hoffmann:
>>>   Hi,
>>>
>>>> ARM: dts: Remove use of skeleton.dtsi from bcm283x.dtsi
>>>> ARM64: dts: bcm: Use a symlink to R-Pi dtsi files from arch=arm
>>> Picked them up.
>>>
>>>> In case of a multiplatform config with following settings the driver
>>>> isn't able to "detect" the role:
>>>>
>>>> CONFIG_USB=y
>>>> CONFIG_USB_OTG=y
>>>> CONFIG_USB_DWC2=y
>>>> CONFIG_USB_DWC2_DUAL_ROLE=y
>>>> CONFIG_USB_PHY=y
>>>> CONFIG_NOP_USB_XCEIV=y
>>>> CONFIG_USB_GADGET=y
>>>> CONFIG_USB_ZERO=y
>>> Configured my kernel that way so the test actually tests something ;)
>>>
>>> And ... everything looks fine.  usb ethernet works, and so does the usb
>>> keyboard.  /proc/device-tree/soc/usb at 7e980000/dr_mode exists and
>>> contains "host".
>>>
>>> Tested-by: Gerd Hoffmann <kraxel@redhat.com>
>>>
>> This patch hasn't been merged yet. Is there something wrong?
> I hadn't bumped it back to todo from RFT.  Also, is this a priority
> patch, since submitting merges is a pain? 
No
> Does USB break in some way
> without it?

No. I only want know if this is still in queue and does someone care
about this patch.

Thanks
Stefan

^ permalink raw reply

* [PATCH] ARM: shmobile: Sort Kconfig selections
From: Geert Uytterhoeven @ 2016-09-23  8:28 UTC (permalink / raw)
  To: linux-arm-kernel

Sort alphabetically all symbols selected by ARCH_RENESAS

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 arch/arm/mach-shmobile/Kconfig | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index 4a48c9f5f72537cd..b5a3cbe81dd1d1f0 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -33,15 +33,15 @@ config ARCH_RMOBILE
 menuconfig ARCH_RENESAS
 	bool "Renesas ARM SoCs"
 	depends on ARCH_MULTI_V7 && MMU
+	select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
 	select ARCH_SHMOBILE
 	select ARCH_SHMOBILE_MULTI
+	select ARM_GIC
+	select GPIOLIB
 	select HAVE_ARM_SCU if SMP
 	select HAVE_ARM_TWD if SMP
-	select ARM_GIC
-	select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
 	select NO_IOPORT_MAP
 	select PINCTRL
-	select GPIOLIB
 	select ZONE_DMA if ARM_LPAE
 
 if ARCH_RENESAS
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2 0/3] arm64: kgdb: fix single stepping
From: AKASHI Takahiro @ 2016-09-23  8:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160923081618.GH18056@kroah.com>

On Fri, Sep 23, 2016 at 10:16:18AM +0200, Greg KH wrote:
> On Fri, Sep 23, 2016 at 04:33:24PM +0900, AKASHI Takahiro wrote:
> > Kgdb support on arm64 was merged in v3.15, but from its first appearance,
> > "signle step" has never worked well.
> > 
> > This patch fixes all the error cases I found so far.
> > The original patch[1] was splitted into three pieces, ones for each case.
> > patch#1, #2 should be applied to all the version, v3.15 and later.
> > pathc#3 only for v3.16 and later.
> 
> As this is not a regression (i.e. it has never worked), why is this
> something for stable releases?

Because, I think, that is a bug.
The author seems to have believed that it worked.
Please see:
  commit 44679a4f
  Author: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
  Date:   Tue Jan 28 11:20:19 2014 +0000

      arm64: KGDB: Add step debugging support

Thanks,
-Takahiro AKASHI

> thanks,
> 
> greg k-h

^ permalink raw reply

* [PATCH v2] arm: dts: zynq: Add MicroZed board support
From: Michal Simek @ 2016-09-23  8:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAD6G_RR6JSzd-QCUj3wDC30pXabNqaNR1d1jQm9bUq6z0CP=3g@mail.gmail.com>

On 23.9.2016 09:39, Jagan Teki wrote:
> On Fri, Sep 23, 2016 at 11:33 AM, Michal Simek <michal.simek@xilinx.com> wrote:
>> On 22.9.2016 22:59, S?ren Brinkmann wrote:
>>> On Thu, 2016-09-22 at 18:51:29 +0530, Jagan Teki wrote:
>>>> From: Jagan Teki <jteki@openedev.com>
>>>>
>>>> Added basic dts support for MicroZed board.
>>>>
>>>> - UART
>>>> - SDHCI
>>>> - Ethernet
>>>>
>>>> Cc: Soren Brinkmann <soren.brinkmann@xilinx.com>
>>>> Cc: Michal Simek <michal.simek@xilinx.com>
>>>> Signed-off-by: Jagan Teki <jteki@openedev.com>
>>>> ---
>>>> Changes for v2:
>>>>      - Add SDHCI
>>>>      - Add Ethernet
>>>>
>>>>  arch/arm/boot/dts/Makefile          |  1 +
>>>>  arch/arm/boot/dts/zynq-microzed.dts | 95 +++++++++++++++++++++++++++++++++++++
>>>>  2 files changed, 96 insertions(+)
>>>>  create mode 100644 arch/arm/boot/dts/zynq-microzed.dts
>>>>
>>>> diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
>>>> index faacd52..4d7b858 100644
>>>> --- a/arch/arm/boot/dts/Makefile
>>>> +++ b/arch/arm/boot/dts/Makefile
>>>> @@ -862,6 +862,7 @@ dtb-$(CONFIG_ARCH_VT8500) += \
>>>>      wm8750-apc8750.dtb \
>>>>      wm8850-w70v2.dtb
>>>>  dtb-$(CONFIG_ARCH_ZYNQ) += \
>>>> +    zynq-microzed.dtb \
>>>>      zynq-parallella.dtb \
>>>>      zynq-zc702.dtb \
>>>>      zynq-zc706.dtb \
>>>> diff --git a/arch/arm/boot/dts/zynq-microzed.dts b/arch/arm/boot/dts/zynq-microzed.dts
>>>> new file mode 100644
>>>> index 0000000..9e64496
>>>> --- /dev/null
>>>> +++ b/arch/arm/boot/dts/zynq-microzed.dts
>>>> @@ -0,0 +1,95 @@
>>>> +/*
>>>> + * Copyright (C) 2015 Jagan Teki <jteki@openedev.com>
>>
>>
>> Did you created only yourself without copying part of this from others?
>> There is dts in u-boot which I believe you are aware of.
> 
> I sent the initial one few months back so at that time, I was created
> and now I just added USB and Ethernet with the reference of zc702
> board.

Can you send me a link to that post? I didn't find it.
Anyway you should keep Xilinx copyright there.

Thanks,
Michal

^ permalink raw reply

* [PATCH v26 1/7] arm64: kdump: reserve memory for crash dump kernel
From: AKASHI Takahiro @ 2016-09-23  8:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <26b1e4d1-e4a6-a4f7-bdf8-cd97363ce1ee@suse.com>

On Thu, Sep 22, 2016 at 12:23:08PM +0200, Matthias Bruger wrote:
> 
> 
> On 09/07/2016 06:29 AM, AKASHI Takahiro wrote:
> >On the startup of primary kernel, the memory region used by crash dump
> >kernel must be specified by "crashkernel=" kernel parameter.
> >reserve_crashkernel() will allocate and reserve the region for later use.
> >
> >User space tools, like kexec-tools, will be able to find that region as
> >	- "Crash kernel" in /proc/iomem, or
> >	- "linux,crashkernel-base" and "linux,crashkernel-size" under
> >	  /sys/firmware/devicetree/base/chosen
> >
> >Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> >Signed-off-by: Mark Salter <msalter@redhat.com>
> >Signed-off-by: Pratyush Anand <panand@redhat.com>
> >Reviewed-by: James Morse <james.morse@arm.com>
> >---
> > arch/arm64/kernel/setup.c |   7 ++-
> > arch/arm64/mm/init.c      | 113 ++++++++++++++++++++++++++++++++++++++++++++++
> > 2 files changed, 119 insertions(+), 1 deletion(-)
> >
> >diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
> >index 514b4e3..38589b5 100644
> >--- a/arch/arm64/kernel/setup.c
> >+++ b/arch/arm64/kernel/setup.c
> >@@ -31,7 +31,6 @@
> > #include <linux/screen_info.h>
> > #include <linux/init.h>
> > #include <linux/kexec.h>
> >-#include <linux/crash_dump.h>
> > #include <linux/root_dev.h>
> > #include <linux/cpu.h>
> > #include <linux/interrupt.h>
> >@@ -225,6 +224,12 @@ static void __init request_standard_resources(void)
> > 		    kernel_data.end <= res->end)
> > 			request_resource(res, &kernel_data);
> > 	}
> >+
> >+#ifdef CONFIG_KEXEC_CORE
> >+	/* User space tools will find "Crash kernel" region in /proc/iomem. */
> >+	if (crashk_res.end)
> >+		insert_resource(&iomem_resource, &crashk_res);
> >+#endif
> > }
> >
> > u64 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = INVALID_HWID };
> >diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
> >index bbb7ee7..dd273ec 100644
> >--- a/arch/arm64/mm/init.c
> >+++ b/arch/arm64/mm/init.c
> >@@ -29,11 +29,13 @@
> > #include <linux/gfp.h>
> > #include <linux/memblock.h>
> > #include <linux/sort.h>
> >+#include <linux/of.h>
> > #include <linux/of_fdt.h>
> > #include <linux/dma-mapping.h>
> > #include <linux/dma-contiguous.h>
> > #include <linux/efi.h>
> > #include <linux/swiotlb.h>
> >+#include <linux/kexec.h>
> >
> > #include <asm/boot.h>
> > #include <asm/fixmap.h>
> >@@ -76,6 +78,114 @@ static int __init early_initrd(char *p)
> > early_param("initrd", early_initrd);
> > #endif
> >
> >+#ifdef CONFIG_KEXEC_CORE
> >+static unsigned long long crash_size, crash_base;
> >+static struct property crash_base_prop = {
> >+	.name = "linux,crashkernel-base",
> >+	.length = sizeof(u64),
> >+	.value = &crash_base
> >+};
> >+static struct property crash_size_prop = {
> >+	.name = "linux,crashkernel-size",
> >+	.length = sizeof(u64),
> >+	.value = &crash_size,
> >+};
> >+
> >+static int __init export_crashkernel(void)
> >+{
> >+	struct device_node *node;
> >+	int ret;
> >+
> >+	if (!crashk_res.end)
> >+		return 0;
> >+
> >+	crash_base = cpu_to_be64(crashk_res.start);
> >+	crash_size = cpu_to_be64(crashk_res.end - crashk_res.start + 1);
> >+
> 
> Shouldn't that be the same values as in reserve_crashkernel()?
> IMHO this does not need to be recalculated here.

Right. crashk_res is calculated from crash_base/size.
So I should and will remove those lines.

Thanks,
-Takahiro AKASHI

> Regards,
> Matthias
> 
> >+	/* Add /chosen/linux,crashkernel-* properties */
> >+	node = of_find_node_by_path("/chosen");
> >+	if (!node)
> >+		return -ENOENT;
> >+
> >+	/*
> >+	 * There might be existing crash kernel properties, but we can't
> >+	 * be sure what's in them, so remove them.
> >+	 */
> >+	of_remove_property(node, of_find_property(node,
> >+				"linux,crashkernel-base", NULL));
> >+	of_remove_property(node, of_find_property(node,
> >+				"linux,crashkernel-size", NULL));
> >+
> >+	ret = of_add_property(node, &crash_base_prop);
> >+	if (ret)
> >+		goto ret_err;
> >+
> >+	ret = of_add_property(node, &crash_size_prop);
> >+	if (ret)
> >+		goto ret_err;
> >+
> >+	return 0;
> >+
> >+ret_err:
> >+	pr_warn("Exporting crashkernel region to device tree failed\n");
> >+	return ret;
> >+}
> >+late_initcall(export_crashkernel);
> >+
> >+/*
> >+ * reserve_crashkernel() - reserves memory for crash kernel
> >+ *
> >+ * This function reserves memory area given in "crashkernel=" kernel command
> >+ * line parameter. The memory reserved is used by dump capture kernel when
> >+ * primary kernel is crashing.
> >+ */
> >+static void __init reserve_crashkernel(void)
> >+{
> >+	int ret;
> >+
> >+	ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
> >+				&crash_size, &crash_base);
> >+	/* no crashkernel= or invalid value specified */
> >+	if (ret || !crash_size)
> >+		return;
> >+
> >+	if (crash_base == 0) {
> >+		/* Current arm64 boot protocol requires 2MB alignment */
> >+		crash_base = memblock_find_in_range(0, ARCH_LOW_ADDRESS_LIMIT,
> >+				crash_size, SZ_2M);
> >+		if (crash_base == 0) {
> >+			pr_warn("Unable to allocate crashkernel (size:%llx)\n",
> >+				crash_size);
> >+			return;
> >+		}
> >+	} else {
> >+		/* User specifies base address explicitly. */
> >+		if (!memblock_is_region_memory(crash_base, crash_size) ||
> >+			memblock_is_region_reserved(crash_base, crash_size)) {
> >+			pr_warn("crashkernel has wrong address or size\n");
> >+			return;
> >+		}
> >+
> >+		if (!IS_ALIGNED(crash_base, SZ_2M)) {
> >+			pr_warn("crashkernel base address is not 2MB aligned\n");
> >+			return;
> >+		}
> >+	}
> >+	memblock_reserve(crash_base, crash_size);
> >+
> >+	pr_info("Reserving %lldMB of memory at %lldMB for crashkernel\n",
> >+		crash_size >> 20, crash_base >> 20);
> >+
> >+	crashk_res.start = crash_base;
> >+	crashk_res.end = crash_base + crash_size - 1;
> >+}
> >+#else
> >+static void __init reserve_crashkernel(void)
> >+{
> >+	;
> >+}
> >+#endif /* CONFIG_KEXEC_CORE */
> >+
> > /*
> >  * Return the maximum physical address for ZONE_DMA (DMA_BIT_MASK(32)). It
> >  * currently assumes that for memory starting above 4G, 32-bit devices will
> >@@ -296,6 +406,9 @@ void __init arm64_memblock_init(void)
> > 		arm64_dma_phys_limit = max_zone_dma_phys();
> > 	else
> > 		arm64_dma_phys_limit = PHYS_MASK + 1;
> >+
> >+	reserve_crashkernel();
> >+
> > 	dma_contiguous_reserve(arm64_dma_phys_limit);
> >
> > 	memblock_allow_resize();
> >

^ permalink raw reply

* [PATCH v2] arm: dts: zynq: Add MicroZed board support
From: Jagan Teki @ 2016-09-23  8:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <aa469a8b-7968-1934-1b8e-6978fd0e6922@xilinx.com>

On Fri, Sep 23, 2016 at 2:07 PM, Michal Simek <michal.simek@xilinx.com> wrote:
> On 23.9.2016 09:39, Jagan Teki wrote:
>> On Fri, Sep 23, 2016 at 11:33 AM, Michal Simek <michal.simek@xilinx.com> wrote:
>>> On 22.9.2016 22:59, S?ren Brinkmann wrote:
>>>> On Thu, 2016-09-22 at 18:51:29 +0530, Jagan Teki wrote:
>>>>> From: Jagan Teki <jteki@openedev.com>
>>>>>
>>>>> Added basic dts support for MicroZed board.
>>>>>
>>>>> - UART
>>>>> - SDHCI
>>>>> - Ethernet
>>>>>
>>>>> Cc: Soren Brinkmann <soren.brinkmann@xilinx.com>
>>>>> Cc: Michal Simek <michal.simek@xilinx.com>
>>>>> Signed-off-by: Jagan Teki <jteki@openedev.com>
>>>>> ---
>>>>> Changes for v2:
>>>>>      - Add SDHCI
>>>>>      - Add Ethernet
>>>>>
>>>>>  arch/arm/boot/dts/Makefile          |  1 +
>>>>>  arch/arm/boot/dts/zynq-microzed.dts | 95 +++++++++++++++++++++++++++++++++++++
>>>>>  2 files changed, 96 insertions(+)
>>>>>  create mode 100644 arch/arm/boot/dts/zynq-microzed.dts
>>>>>
>>>>> diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
>>>>> index faacd52..4d7b858 100644
>>>>> --- a/arch/arm/boot/dts/Makefile
>>>>> +++ b/arch/arm/boot/dts/Makefile
>>>>> @@ -862,6 +862,7 @@ dtb-$(CONFIG_ARCH_VT8500) += \
>>>>>      wm8750-apc8750.dtb \
>>>>>      wm8850-w70v2.dtb
>>>>>  dtb-$(CONFIG_ARCH_ZYNQ) += \
>>>>> +    zynq-microzed.dtb \
>>>>>      zynq-parallella.dtb \
>>>>>      zynq-zc702.dtb \
>>>>>      zynq-zc706.dtb \
>>>>> diff --git a/arch/arm/boot/dts/zynq-microzed.dts b/arch/arm/boot/dts/zynq-microzed.dts
>>>>> new file mode 100644
>>>>> index 0000000..9e64496
>>>>> --- /dev/null
>>>>> +++ b/arch/arm/boot/dts/zynq-microzed.dts
>>>>> @@ -0,0 +1,95 @@
>>>>> +/*
>>>>> + * Copyright (C) 2015 Jagan Teki <jteki@openedev.com>
>>>
>>>
>>> Did you created only yourself without copying part of this from others?
>>> There is dts in u-boot which I believe you are aware of.
>>
>> I sent the initial one few months back so at that time, I was created
>> and now I just added USB and Ethernet with the reference of zc702
>> board.
>
> Can you send me a link to that post? I didn't find it.

Here is the link [1]

> Anyway you should keep Xilinx copyright there.

OK then will append Xilinx as well.

[1] http://lkml.iu.edu/hypermail/linux/kernel/1601.1/03236.html

thanks!
-- 
Jagan.

^ permalink raw reply

* [PATCH v2 0/3] arm64: kgdb: fix single stepping
From: Greg KH @ 2016-09-23  8:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160923083257.GL30248@linaro.org>

On Fri, Sep 23, 2016 at 05:32:58PM +0900, AKASHI Takahiro wrote:
> On Fri, Sep 23, 2016 at 10:16:18AM +0200, Greg KH wrote:
> > On Fri, Sep 23, 2016 at 04:33:24PM +0900, AKASHI Takahiro wrote:
> > > Kgdb support on arm64 was merged in v3.15, but from its first appearance,
> > > "signle step" has never worked well.
> > > 
> > > This patch fixes all the error cases I found so far.
> > > The original patch[1] was splitted into three pieces, ones for each case.
> > > patch#1, #2 should be applied to all the version, v3.15 and later.
> > > pathc#3 only for v3.16 and later.
> > 
> > As this is not a regression (i.e. it has never worked), why is this
> > something for stable releases?
> 
> Because, I think, that is a bug.
> The author seems to have believed that it worked.
> Please see:
>   commit 44679a4f
>   Author: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>   Date:   Tue Jan 28 11:20:19 2014 +0000
> 
>       arm64: KGDB: Add step debugging support

Yes, but again, it didn't work, so this would be a new feature.  One
that obviously people aren't using in the stable kernels, otherwise they
would have noticed in the past 2 years about it being broken :)

Please read Documentation/stable_kernel_rules.txt for the requirements
of a stable kernel patch.  I don't think this series meets those rules.

thanks,

greg k-h

^ permalink raw reply

* [PATCH v4 1/7] pinctrl: bcm2835: add pull defines to dt bindings
From: Linus Walleij @ 2016-09-23  8:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <87zin49p9m.fsf@eliezer.anholt.net>

On Mon, Sep 19, 2016 at 12:07 PM, Eric Anholt <eric@anholt.net> wrote:
> Gerd Hoffmann <kraxel@redhat.com> writes:
>
>> Also delete (unused) private enum from driver.
>> The pull defines can be used instead if needed.
>>
>> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
>
> Acked-by: Eric Anholt <eric@anholt.net>
>
> gpio maintainers, could I pull this through my dt tree?  Or does this
> need to be split in two?

You can take it. The bcm2835 driver is not seeing any conflicting
changes in this merge window.

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ 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