Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 2/3] ARM: dts: stm32: Add ADC support to stm32f429
From: Fabrice Gasnier @ 2016-12-02 13:57 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480687022-12851-1-git-send-email-fabrice.gasnier@st.com>

Add ADC support & pinctrl analog phandle (adc3_in8) to stm32f429.

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
---
 arch/arm/boot/dts/stm32f429.dtsi | 49 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
index 3dd47eb..be1d970 100644
--- a/arch/arm/boot/dts/stm32f429.dtsi
+++ b/arch/arm/boot/dts/stm32f429.dtsi
@@ -172,6 +172,49 @@
 			status = "disabled";
 		};
 
+		adc: adc at 40012000 {
+			compatible = "st,stm32f4-adc-core";
+			reg = <0x40012000 0x400>;
+			interrupts = <18>;
+			clocks = <&rcc 0 168>;
+			clock-names = "adc";
+			interrupt-controller;
+			#interrupt-cells = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+
+			adc1: adc at 0 {
+				compatible = "st,stm32f4-adc";
+				#io-channel-cells = <1>;
+				reg = <0x0>;
+				clocks = <&rcc 0 168>;
+				interrupt-parent = <&adc>;
+				interrupts = <0>;
+				status = "disabled";
+			};
+
+			adc2: adc at 100 {
+				compatible = "st,stm32f4-adc";
+				#io-channel-cells = <1>;
+				reg = <0x100>;
+				clocks = <&rcc 0 169>;
+				interrupt-parent = <&adc>;
+				interrupts = <1>;
+				status = "disabled";
+			};
+
+			adc3: adc at 200 {
+				compatible = "st,stm32f4-adc";
+				#io-channel-cells = <1>;
+				reg = <0x200>;
+				clocks = <&rcc 0 170>;
+				interrupt-parent = <&adc>;
+				interrupts = <2>;
+				status = "disabled";
+			};
+		};
+
 		syscfg: system-config at 40013800 {
 			compatible = "syscon";
 			reg = <0x40013800 0x400>;
@@ -334,6 +377,12 @@
 					slew-rate = <2>;
 				};
 			};
+
+			adc3_in8_pin: adc at 200 {
+				pins {
+					pinmux = <STM32F429_PF10_FUNC_ANALOG>;
+				};
+			};
 		};
 
 		rcc: rcc at 40023810 {
-- 
1.9.1

^ permalink raw reply related

* [PATCH 1/3] ARM: configs: stm32: enable ADC driver
From: Fabrice Gasnier @ 2016-12-02 13:57 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480687022-12851-1-git-send-email-fabrice.gasnier@st.com>

ADC driver depends on REGULATOR and IIO that are not yet selected.
Current hardware boards (like stm32f429i-eval) is using fixed
regulators.

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
---
 arch/arm/configs/stm32_defconfig | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/configs/stm32_defconfig b/arch/arm/configs/stm32_defconfig
index a60b5cb..92ccc3c 100644
--- a/arch/arm/configs/stm32_defconfig
+++ b/arch/arm/configs/stm32_defconfig
@@ -49,6 +49,8 @@ CONFIG_SERIAL_STM32=y
 CONFIG_SERIAL_STM32_CONSOLE=y
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HWMON is not set
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
 # CONFIG_USB_SUPPORT is not set
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
@@ -57,6 +59,9 @@ CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
 CONFIG_DMADEVICES=y
 CONFIG_STM32_DMA=y
+CONFIG_IIO=y
+CONFIG_STM32_ADC_CORE=y
+CONFIG_STM32_ADC=y
 # CONFIG_FILE_LOCKING is not set
 # CONFIG_DNOTIFY is not set
 # CONFIG_INOTIFY_USER is not set
-- 
1.9.1

^ permalink raw reply related

* [PATCH 0/3] Enable ADC on STM32
From: Fabrice Gasnier @ 2016-12-02 13:56 UTC (permalink / raw)
  To: linux-arm-kernel

Enable minimal configuration and device tree to support ADC on STM32,
using ADC driver: https://lwn.net/Articles/706445/

Simple test on stm32f429i-eval board, using on-board potentiometer:
- cd /sys/bus/iio/devices/iio\:device0/
- cat in_voltage8_raw

Fabrice Gasnier (3):
  ARM: configs: stm32: enable ADC driver
  ARM: dts: stm32: Add ADC support to stm32f429
  ARM: dts: stm32: enable ADC on stm32f429i-eval board

 arch/arm/boot/dts/stm32429i-eval.dts | 25 ++++++++++++++++++
 arch/arm/boot/dts/stm32f429.dtsi     | 49 ++++++++++++++++++++++++++++++++++++
 arch/arm/configs/stm32_defconfig     |  5 ++++
 3 files changed, 79 insertions(+)

-- 
1.9.1

^ permalink raw reply

* [PATCH v2 3/6] mm: hugetlb: change the return type for alloc_fresh_gigantic_page
From: Michal Hocko @ 2016-12-02 13:56 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1479107259-2011-4-git-send-email-shijie.huang@arm.com>

On Mon 14-11-16 15:07:36, Huang Shijie wrote:
> This patch changes the return type to "struct page*" for
> alloc_fresh_gigantic_page().

OK, this makes somme sense. Other hugetlb allocation function (and page
allocator in general) return struct page as well. Besides that int would
make sense if we wanted to convey an error code but 0 vs. 1 just doesn't
make any sense.

But if you are changing that then alloc_fresh_huge_page should be
changed as well.

> This patch makes preparation for later patch.
> 
> Signed-off-by: Huang Shijie <shijie.huang@arm.com>

Acked-by: Michal Hocko <mhocko@suse.com>

> ---
>  mm/hugetlb.c | 12 ++++++------
>  1 file changed, 6 insertions(+), 6 deletions(-)
> 
> diff --git a/mm/hugetlb.c b/mm/hugetlb.c
> index db0177b..6995087 100644
> --- a/mm/hugetlb.c
> +++ b/mm/hugetlb.c
> @@ -1142,7 +1142,7 @@ static struct page *alloc_fresh_gigantic_page_node(struct hstate *h,
>  	return page;
>  }
>  
> -static int alloc_fresh_gigantic_page(struct hstate *h,
> +static struct page *alloc_fresh_gigantic_page(struct hstate *h,
>  				nodemask_t *nodes_allowed, bool no_init)
>  {
>  	struct page *page = NULL;
> @@ -1151,10 +1151,10 @@ static int alloc_fresh_gigantic_page(struct hstate *h,
>  	for_each_node_mask_to_alloc(h, nr_nodes, node, nodes_allowed) {
>  		page = alloc_fresh_gigantic_page_node(h, node, no_init);
>  		if (page)
> -			return 1;
> +			return page;
>  	}
>  
> -	return 0;
> +	return NULL;
>  }
>  
>  static inline bool gigantic_page_supported(void) { return true; }
> @@ -1167,8 +1167,8 @@ static inline bool gigantic_page_supported(void) { return false; }
>  static inline void free_gigantic_page(struct page *page, unsigned int order) { }
>  static inline void destroy_compound_gigantic_page(struct page *page,
>  						unsigned int order) { }
> -static inline int alloc_fresh_gigantic_page(struct hstate *h,
> -		nodemask_t *nodes_allowed, bool no_init) { return 0; }
> +static inline struct page *alloc_fresh_gigantic_page(struct hstate *h,
> +		nodemask_t *nodes_allowed, bool no_init) { return NULL; }
>  #endif
>  
>  static void update_and_free_page(struct hstate *h, struct page *page)
> @@ -2315,7 +2315,7 @@ static unsigned long set_max_huge_pages(struct hstate *h, unsigned long count,
>  		cond_resched();
>  
>  		if (hstate_is_gigantic(h))
> -			ret = alloc_fresh_gigantic_page(h, nodes_allowed,
> +			ret = !!alloc_fresh_gigantic_page(h, nodes_allowed,
>  							false);
>  		else
>  			ret = alloc_fresh_huge_page(h, nodes_allowed);
> -- 
> 2.5.5
> 
> --
> To unsubscribe, send a message with 'unsubscribe linux-mm' in
> the body to majordomo at kvack.org.  For more info on Linux MM,
> see: http://www.linux-mm.org/ .
> Don't email: <a href=mailto:"dont@kvack.org"> email at kvack.org </a>

-- 
Michal Hocko
SUSE Labs

^ permalink raw reply

* [PATCH v2 2/6] mm: hugetlb: add a new parameter for some functions
From: Michal Hocko @ 2016-12-02 13:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1479107259-2011-3-git-send-email-shijie.huang@arm.com>

On Mon 14-11-16 15:07:35, Huang Shijie wrote:
> This patch adds a new parameter, the "no_init", for these functions:
>    alloc_fresh_gigantic_page_node()
>    alloc_fresh_gigantic_page()
> 
> The prep_new_huge_page() does some initialization for the new page.
> But sometime, we do not need it to do so, such as in the surplus case
> in later patch.
> 
> With this parameter, the prep_new_huge_page() can be called by needed:
>    If the "no_init" is false, calls the prep_new_huge_page() in
>    the alloc_fresh_gigantic_page_node();

This double negative just makes my head spin. I haven't got to later
patch to understand the motivation but if anything bool do_prep would
be much more clear. In general doing these "init if a parameter is
specified" is a bad idea. It just makes the code more convoluted and
sutble. If you need the separation then __foo vs foo with the first
doing the real work and the later some additional initialization on top
sounds like a better idea to me.

Let's see what other changes are about.

> This patch makes preparation for the later patches.
> 
> Signed-off-by: Huang Shijie <shijie.huang@arm.com>
> ---
>  mm/hugetlb.c | 15 +++++++++------
>  1 file changed, 9 insertions(+), 6 deletions(-)
> 
> diff --git a/mm/hugetlb.c b/mm/hugetlb.c
> index 496b703..db0177b 100644
> --- a/mm/hugetlb.c
> +++ b/mm/hugetlb.c
> @@ -1127,27 +1127,29 @@ static struct page *alloc_gigantic_page(int nid, unsigned int order)
>  static void prep_new_huge_page(struct hstate *h, struct page *page, int nid);
>  static void prep_compound_gigantic_page(struct page *page, unsigned int order);
>  
> -static struct page *alloc_fresh_gigantic_page_node(struct hstate *h, int nid)
> +static struct page *alloc_fresh_gigantic_page_node(struct hstate *h,
> +					int nid, bool no_init)
>  {
>  	struct page *page;
>  
>  	page = alloc_gigantic_page(nid, huge_page_order(h));
>  	if (page) {
>  		prep_compound_gigantic_page(page, huge_page_order(h));
> -		prep_new_huge_page(h, page, nid);
> +		if (!no_init)
> +			prep_new_huge_page(h, page, nid);
>  	}
>  
>  	return page;
>  }
>  
>  static int alloc_fresh_gigantic_page(struct hstate *h,
> -				nodemask_t *nodes_allowed)
> +				nodemask_t *nodes_allowed, bool no_init)
>  {
>  	struct page *page = NULL;
>  	int nr_nodes, node;
>  
>  	for_each_node_mask_to_alloc(h, nr_nodes, node, nodes_allowed) {
> -		page = alloc_fresh_gigantic_page_node(h, node);
> +		page = alloc_fresh_gigantic_page_node(h, node, no_init);
>  		if (page)
>  			return 1;
>  	}
> @@ -1166,7 +1168,7 @@ static inline void free_gigantic_page(struct page *page, unsigned int order) { }
>  static inline void destroy_compound_gigantic_page(struct page *page,
>  						unsigned int order) { }
>  static inline int alloc_fresh_gigantic_page(struct hstate *h,
> -					nodemask_t *nodes_allowed) { return 0; }
> +		nodemask_t *nodes_allowed, bool no_init) { return 0; }
>  #endif
>  
>  static void update_and_free_page(struct hstate *h, struct page *page)
> @@ -2313,7 +2315,8 @@ static unsigned long set_max_huge_pages(struct hstate *h, unsigned long count,
>  		cond_resched();
>  
>  		if (hstate_is_gigantic(h))
> -			ret = alloc_fresh_gigantic_page(h, nodes_allowed);
> +			ret = alloc_fresh_gigantic_page(h, nodes_allowed,
> +							false);
>  		else
>  			ret = alloc_fresh_huge_page(h, nodes_allowed);
>  		spin_lock(&hugetlb_lock);
> -- 
> 2.5.5
> 

-- 
Michal Hocko
SUSE Labs

^ permalink raw reply

* [RESEND PATCH v2 7/7] ARM: bcm/dt: Enable the VEC IP on all RaspberryPi boards
From: Boris Brezillon @ 2016-12-02 13:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480686493-4813-1-git-send-email-boris.brezillon@free-electrons.com>

Enable the VEC IP on all RaspberryPi boards.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 arch/arm/boot/dts/bcm2835-rpi.dtsi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi
index e9b47b2bbc33..8893240da5f6 100644
--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
@@ -84,3 +84,8 @@
 	power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
 	status = "okay";
 };
+
+&vec {
+	power-domains = <&power RPI_POWER_DOMAIN_VEC>;
+	status = "okay";
+};
-- 
2.7.4

^ permalink raw reply related

* [RESEND PATCH v2 6/7] ARM: bcm/dt: Add VEC node in bcm283x.dtsi
From: Boris Brezillon @ 2016-12-02 13:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480686493-4813-1-git-send-email-boris.brezillon@free-electrons.com>

Add the VEC (Video EnCoder) node definition in bcm283x.dtsi.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 arch/arm/boot/dts/bcm283x.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi
index 46d46d894a44..44a9c0539437 100644
--- a/arch/arm/boot/dts/bcm283x.dtsi
+++ b/arch/arm/boot/dts/bcm283x.dtsi
@@ -266,6 +266,14 @@
 			status = "disabled";
 		};
 
+		vec: vec at 7e806000 {
+			compatible = "brcm,bcm2835-vec";
+			reg = <0x7e806000 0x1000>;
+			clocks = <&clocks BCM2835_CLOCK_VEC>;
+			interrupts = <2 27>;
+			status = "disabled";
+		};
+
 		pixelvalve at 7e807000 {
 			compatible = "brcm,bcm2835-pixelvalve2";
 			reg = <0x7e807000 0x100>;
-- 
2.7.4

^ permalink raw reply related

* [RESEND PATCH v2 5/7] drm/vc4: Document VEC DT binding
From: Boris Brezillon @ 2016-12-02 13:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480686493-4813-1-git-send-email-boris.brezillon@free-electrons.com>

Document the DT binding for the VEC (Video EnCoder) IP.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt b/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt
index a5ea451e67fc..e2768703ac2b 100644
--- a/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt
+++ b/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt
@@ -43,6 +43,13 @@ Required properties for DPI:
 - port:		Port node with a single endpoint connecting to the panel
 		  device, as defined in [1]
 
+Required properties for VEC:
+- compatible:	Should be "brcm,bcm2835-vec"
+- reg:		Physical base address and length of the registers
+- clocks:	The core clock the unit runs on
+- interrupts:	The interrupt number
+		  See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt
+
 Required properties for V3D:
 - compatible:	Should be "brcm,bcm2835-v3d"
 - reg:		Physical base address and length of the V3D's registers
@@ -92,6 +99,13 @@ dpi: dpi at 7e208000 {
 	};
 };
 
+vec: vec at 7e806000 {
+	compatible = "brcm,bcm2835-vec";
+	reg = <0x7e806000 0x1000>;
+	clocks = <&clocks BCM2835_CLOCK_VEC>;
+	interrupts = <2 27>;
+};
+
 v3d: v3d at 7ec00000 {
 	compatible = "brcm,bcm2835-v3d";
 	reg = <0x7ec00000 0x1000>;
-- 
2.7.4

^ permalink raw reply related

* [RESEND PATCH v2 4/7] drm/vc4: Add support for the VEC (Video Encoder) IP
From: Boris Brezillon @ 2016-12-02 13:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480686493-4813-1-git-send-email-boris.brezillon@free-electrons.com>

The VEC IP is a TV DAC, providing support for PAL and NTSC standards.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/gpu/drm/vc4/Makefile      |   1 +
 drivers/gpu/drm/vc4/vc4_debugfs.c |   1 +
 drivers/gpu/drm/vc4/vc4_drv.c     |   1 +
 drivers/gpu/drm/vc4/vc4_drv.h     |   5 +
 drivers/gpu/drm/vc4/vc4_vec.c     | 657 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 665 insertions(+)
 create mode 100644 drivers/gpu/drm/vc4/vc4_vec.c

diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile
index fb77db755e0a..7757f69a8a77 100644
--- a/drivers/gpu/drm/vc4/Makefile
+++ b/drivers/gpu/drm/vc4/Makefile
@@ -11,6 +11,7 @@ vc4-y := \
 	vc4_kms.o \
 	vc4_gem.o \
 	vc4_hdmi.o \
+	vc4_vec.o \
 	vc4_hvs.o \
 	vc4_irq.o \
 	vc4_plane.o \
diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c
index 245115d49c46..caf817bac885 100644
--- a/drivers/gpu/drm/vc4/vc4_debugfs.c
+++ b/drivers/gpu/drm/vc4/vc4_debugfs.c
@@ -19,6 +19,7 @@ static const struct drm_info_list vc4_debugfs_list[] = {
 	{"bo_stats", vc4_bo_stats_debugfs, 0},
 	{"dpi_regs", vc4_dpi_debugfs_regs, 0},
 	{"hdmi_regs", vc4_hdmi_debugfs_regs, 0},
+	{"vec_regs", vc4_vec_debugfs_regs, 0},
 	{"hvs_regs", vc4_hvs_debugfs_regs, 0},
 	{"crtc0_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)0},
 	{"crtc1_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)1},
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index 8703f56b7947..3e6cb78f7381 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -289,6 +289,7 @@ static const struct component_master_ops vc4_drm_ops = {
 
 static struct platform_driver *const component_drivers[] = {
 	&vc4_hdmi_driver,
+	&vc4_vec_driver,
 	&vc4_dpi_driver,
 	&vc4_hvs_driver,
 	&vc4_crtc_driver,
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 946d48c33668..b3a46a51f9d0 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -17,6 +17,7 @@ struct vc4_dev {
 	struct vc4_crtc *crtc[3];
 	struct vc4_v3d *v3d;
 	struct vc4_dpi *dpi;
+	struct vc4_vec *vec;
 
 	struct drm_fbdev_cma *fbdev;
 
@@ -484,6 +485,10 @@ int vc4_queue_seqno_cb(struct drm_device *dev,
 extern struct platform_driver vc4_hdmi_driver;
 int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused);
 
+/* vc4_hdmi.c */
+extern struct platform_driver vc4_vec_driver;
+int vc4_vec_debugfs_regs(struct seq_file *m, void *unused);
+
 /* vc4_irq.c */
 irqreturn_t vc4_irq(int irq, void *arg);
 void vc4_irq_preinstall(struct drm_device *dev);
diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
new file mode 100644
index 000000000000..2d4256fcc6f2
--- /dev/null
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -0,0 +1,657 @@
+/*
+ * Copyright (C) 2016 Broadcom Limited
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * DOC: VC4 SDTV module
+ */
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_panel.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/of_graph.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+
+#include "vc4_drv.h"
+#include "vc4_regs.h"
+
+/* WSE Registers */
+#define VEC_WSE_RESET			0xc0
+
+#define VEC_WSE_CONTROL			0xc4
+#define VEC_WSE_WSS_ENABLE		BIT(7)
+
+#define VEC_WSE_WSS_DATA		0xc8
+#define VEC_WSE_VPS_DATA1		0xcc
+#define VEC_WSE_VPS_CONTROL		0xd0
+
+/* VEC Registers */
+#define VEC_REVID			0x100
+
+#define VEC_CONFIG0			0x104
+#define VEC_CONFIG0_YDEL_MASK		GENMASK(28, 26)
+#define VEC_CONFIG0_YDEL(x)		((x) << 26)
+#define VEC_CONFIG0_CDEL_MASK		GENMASK(25, 24)
+#define VEC_CONFIG0_CDEL(x)		((x) << 24)
+#define VEC_CONFIG0_PBPR_FIL		BIT(18)
+#define VEC_CONFIG0_CHROMA_GAIN_MASK	GENMASK(17, 16)
+#define VEC_CONFIG0_CHROMA_GAIN_UNITY	(0 << 16)
+#define VEC_CONFIG0_CHROMA_GAIN_1_32	(1 << 16)
+#define VEC_CONFIG0_CHROMA_GAIN_1_16	(2 << 16)
+#define VEC_CONFIG0_CHROMA_GAIN_1_8	(3 << 16)
+#define VEC_CONFIG0_CBURST_GAIN_MASK	GENMASK(14, 13)
+#define VEC_CONFIG0_CBURST_GAIN_UNITY	(0 << 13)
+#define VEC_CONFIG0_CBURST_GAIN_1_128	(1 << 13)
+#define VEC_CONFIG0_CBURST_GAIN_1_64	(2 << 13)
+#define VEC_CONFIG0_CBURST_GAIN_1_32	(3 << 13)
+#define VEC_CONFIG0_CHRBW1		BIT(11)
+#define VEC_CONFIG0_CHRBW0		BIT(10)
+#define VEC_CONFIG0_SYNCDIS		BIT(9)
+#define VEC_CONFIG0_BURDIS		BIT(8)
+#define VEC_CONFIG0_CHRDIS		BIT(7)
+#define VEC_CONFIG0_PDEN		BIT(6)
+#define VEC_CONFIG0_YCDELAY		BIT(4)
+#define VEC_CONFIG0_RAMPEN		BIT(2)
+#define VEC_CONFIG0_YCDIS		BIT(2)
+#define VEC_CONFIG0_STD_MASK		GENMASK(1, 0)
+#define VEC_CONFIG0_NTSC_STD		0
+#define VEC_CONFIG0_PAL_BDGHI_STD	1
+#define VEC_CONFIG0_PAL_N_STD		3
+
+#define VEC_SCHPH			0x108
+#define VEC_SOFT_RESET			0x10c
+#define VEC_CLMP0_START			0x144
+#define VEC_CLMP0_END			0x148
+#define VEC_FREQ3_2			0x180
+#define VEC_FREQ1_0			0x184
+
+#define VEC_CONFIG1			0x188
+#define VEC_CONFIG_VEC_RESYNC_OFF	BIT(18)
+#define VEC_CONFIG_RGB219		BIT(17)
+#define VEC_CONFIG_CBAR_EN		BIT(16)
+#define VEC_CONFIG_TC_OBB		BIT(15)
+#define VEC_CONFIG1_OUTPUT_MODE_MASK	GENMASK(12, 10)
+#define VEC_CONFIG1_C_Y_CVBS		(0 << 10)
+#define VEC_CONFIG1_CVBS_Y_C		(1 << 10)
+#define VEC_CONFIG1_PR_Y_PB		(2 << 10)
+#define VEC_CONFIG1_RGB			(4 << 10)
+#define VEC_CONFIG1_Y_C_CVBS		(5 << 10)
+#define VEC_CONFIG1_C_CVBS_Y		(6 << 10)
+#define VEC_CONFIG1_C_CVBS_CVBS		(7 << 10)
+#define VEC_CONFIG1_DIS_CHR		BIT(9)
+#define VEC_CONFIG1_DIS_LUMA		BIT(8)
+#define VEC_CONFIG1_YCBCR_IN		BIT(6)
+#define VEC_CONFIG1_DITHER_TYPE_LFSR	0
+#define VEC_CONFIG1_DITHER_TYPE_COUNTER	BIT(5)
+#define VEC_CONFIG1_DITHER_EN		BIT(4)
+#define VEC_CONFIG1_CYDELAY		BIT(3)
+#define VEC_CONFIG1_LUMADIS		BIT(2)
+#define VEC_CONFIG1_COMPDIS		BIT(1)
+#define VEC_CONFIG1_CUSTOM_FREQ		BIT(0)
+
+#define VEC_CONFIG2			0x18c
+#define VEC_CONFIG2_PROG_SCAN		BIT(15)
+#define VEC_CONFIG2_SYNC_ADJ_MASK	GENMASK(14, 12)
+#define VEC_CONFIG2_SYNC_ADJ(x)		(((x) / 2) << 12)
+#define VEC_CONFIG2_PBPR_EN		BIT(10)
+#define VEC_CONFIG2_UV_DIG_DIS		BIT(6)
+#define VEC_CONFIG2_RGB_DIG_DIS		BIT(5)
+#define VEC_CONFIG2_TMUX_MASK		GENMASK(3, 2)
+#define VEC_CONFIG2_TMUX_DRIVE0		(0 << 2)
+#define VEC_CONFIG2_TMUX_RG_COMP	(1 << 2)
+#define VEC_CONFIG2_TMUX_UV_YC		(2 << 2)
+#define VEC_CONFIG2_TMUX_SYNC_YC	(3 << 2)
+
+#define VEC_INTERRUPT_CONTROL		0x190
+#define VEC_INTERRUPT_STATUS		0x194
+#define VEC_FCW_SECAM_B			0x198
+#define VEC_SECAM_GAIN_VAL		0x19c
+
+#define VEC_CONFIG3			0x1a0
+#define VEC_CONFIG3_HORIZ_LEN_STD	(0 << 0)
+#define VEC_CONFIG3_HORIZ_LEN_MPEG1_SIF	(1 << 0)
+#define VEC_CONFIG3_SHAPE_NON_LINEAR	BIT(1)
+
+#define VEC_STATUS0			0x200
+#define VEC_MASK0			0x204
+
+#define VEC_CFG				0x208
+#define VEC_CFG_SG_MODE_MASK		GENMASK(6, 5)
+#define VEC_CFG_SG_MODE(x)		((x) << 5)
+#define VEC_CFG_SG_EN			BIT(4)
+#define VEC_CFG_VEC_EN			BIT(3)
+#define VEC_CFG_MB_EN			BIT(2)
+#define VEC_CFG_ENABLE			BIT(1)
+#define VEC_CFG_TB_EN			BIT(0)
+
+#define VEC_DAC_TEST			0x20c
+
+#define VEC_DAC_CONFIG			0x210
+#define VEC_DAC_CONFIG_LDO_BIAS_CTRL(x)	((x) << 24)
+#define VEC_DAC_CONFIG_DRIVER_CTRL(x)	((x) << 16)
+#define VEC_DAC_CONFIG_DAC_CTRL(x)	(x)
+
+#define VEC_DAC_MISC			0x214
+#define VEC_DAC_MISC_VCD_CTRL_MASK	GENMASK(31, 16)
+#define VEC_DAC_MISC_VCD_CTRL(x)	((x) << 16)
+#define VEC_DAC_MISC_VID_ACT		BIT(8)
+#define VEC_DAC_MISC_VCD_PWRDN		BIT(6)
+#define VEC_DAC_MISC_BIAS_PWRDN		BIT(5)
+#define VEC_DAC_MISC_DAC_PWRDN		BIT(2)
+#define VEC_DAC_MISC_LDO_PWRDN		BIT(1)
+#define VEC_DAC_MISC_DAC_RST_N		BIT(0)
+
+
+/* General VEC hardware state. */
+struct vc4_vec {
+	struct platform_device *pdev;
+
+	struct drm_encoder *encoder;
+	struct drm_connector *connector;
+
+	void __iomem *regs;
+
+	struct clk *clock;
+
+	const struct vc4_vec_tv_mode *tv_mode;
+};
+
+#define VEC_READ(offset) readl(vec->regs + (offset))
+#define VEC_WRITE(offset, val) writel(val, vec->regs + (offset))
+
+/* VC4 VEC encoder KMS struct */
+struct vc4_vec_encoder {
+	struct vc4_encoder base;
+	struct vc4_vec *vec;
+};
+
+static inline struct vc4_vec_encoder *
+to_vc4_vec_encoder(struct drm_encoder *encoder)
+{
+	return container_of(encoder, struct vc4_vec_encoder, base.base);
+}
+
+/* VC4 VEC connector KMS struct */
+struct vc4_vec_connector {
+	struct drm_connector base;
+	struct vc4_vec *vec;
+
+	/* Since the connector is attached to just the one encoder,
+	 * this is the reference to it so we can do the best_encoder()
+	 * hook.
+	 */
+	struct drm_encoder *encoder;
+};
+
+static inline struct vc4_vec_connector *
+to_vc4_vec_connector(struct drm_connector *connector)
+{
+	return container_of(connector, struct vc4_vec_connector, base);
+}
+
+enum vc4_vec_tv_mode_id {
+	VC4_VEC_TV_MODE_NTSC,
+	VC4_VEC_TV_MODE_NTSC_J,
+	VC4_VEC_TV_MODE_PAL,
+	VC4_VEC_TV_MODE_PAL_M,
+};
+
+struct vc4_vec_tv_mode {
+	const struct drm_display_mode *mode;
+	void (*mode_set)(struct vc4_vec *vec);
+};
+
+#define VEC_REG(reg) { reg, #reg }
+static const struct {
+	u32 reg;
+	const char *name;
+} vec_regs[] = {
+	VEC_REG(VEC_WSE_CONTROL),
+	VEC_REG(VEC_WSE_WSS_DATA),
+	VEC_REG(VEC_WSE_VPS_DATA1),
+	VEC_REG(VEC_WSE_VPS_CONTROL),
+	VEC_REG(VEC_REVID),
+	VEC_REG(VEC_CONFIG0),
+	VEC_REG(VEC_SCHPH),
+	VEC_REG(VEC_CLMP0_START),
+	VEC_REG(VEC_CLMP0_END),
+	VEC_REG(VEC_FREQ3_2),
+	VEC_REG(VEC_FREQ1_0),
+	VEC_REG(VEC_CONFIG1),
+	VEC_REG(VEC_CONFIG2),
+	VEC_REG(VEC_INTERRUPT_CONTROL),
+	VEC_REG(VEC_INTERRUPT_STATUS),
+	VEC_REG(VEC_FCW_SECAM_B),
+	VEC_REG(VEC_SECAM_GAIN_VAL),
+	VEC_REG(VEC_CONFIG3),
+	VEC_REG(VEC_STATUS0),
+	VEC_REG(VEC_MASK0),
+	VEC_REG(VEC_CFG),
+	VEC_REG(VEC_DAC_TEST),
+	VEC_REG(VEC_DAC_CONFIG),
+	VEC_REG(VEC_DAC_MISC),
+};
+
+#ifdef CONFIG_DEBUG_FS
+int vc4_vec_debugfs_regs(struct seq_file *m, void *unused)
+{
+	struct drm_info_node *node = (struct drm_info_node *)m->private;
+	struct drm_device *dev = node->minor->dev;
+	struct vc4_dev *vc4 = to_vc4_dev(dev);
+	struct vc4_vec *vec = vc4->vec;
+	int i;
+
+	if (!vec)
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(vec_regs); i++) {
+		seq_printf(m, "%s (0x%04x): 0x%08x\n",
+			   vec_regs[i].name, vec_regs[i].reg,
+			   VEC_READ(vec_regs[i].reg));
+	}
+
+	return 0;
+}
+#endif
+
+static void vc4_vec_ntsc_mode_set(struct vc4_vec *vec)
+{
+	VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN);
+	VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
+}
+
+static void vc4_vec_ntsc_j_mode_set(struct vc4_vec *vec)
+{
+	VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD);
+	VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
+}
+
+static const struct drm_display_mode ntsc_mode = {
+	DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 13500,
+		 720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0,
+		 480, 480 + 3, 480 + 3 + 3, 480 + 3 + 3 + 16, 0,
+		 DRM_MODE_FLAG_INTERLACE)
+};
+
+static void vc4_vec_pal_mode_set(struct vc4_vec *vec)
+{
+	VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD);
+	VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
+}
+
+static void vc4_vec_pal_m_mode_set(struct vc4_vec *vec)
+{
+	VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD);
+	VEC_WRITE(VEC_CONFIG1,
+		  VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ);
+	VEC_WRITE(VEC_FREQ3_2, 0x223b);
+	VEC_WRITE(VEC_FREQ1_0, 0x61d1);
+}
+
+static const struct drm_display_mode pal_mode = {
+	DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 13500,
+		 720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0,
+		 576, 576 + 2, 576 + 2 + 3, 576 + 2 + 3 + 20, 0,
+		 DRM_MODE_FLAG_INTERLACE)
+};
+
+static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
+	[VC4_VEC_TV_MODE_NTSC] = {
+		.mode = &ntsc_mode,
+		.mode_set = vc4_vec_ntsc_mode_set,
+	},
+	[VC4_VEC_TV_MODE_NTSC_J] = {
+		.mode = &ntsc_mode,
+		.mode_set = vc4_vec_ntsc_j_mode_set,
+	},
+	[VC4_VEC_TV_MODE_PAL] = {
+		.mode = &pal_mode,
+		.mode_set = vc4_vec_pal_mode_set,
+	},
+	[VC4_VEC_TV_MODE_PAL_M] = {
+		.mode = &pal_mode,
+		.mode_set = vc4_vec_pal_m_mode_set,
+	},
+};
+
+static enum drm_connector_status
+vc4_vec_connector_detect(struct drm_connector *connector, bool force)
+{
+	return connector_status_unknown;
+}
+
+static void vc4_vec_connector_destroy(struct drm_connector *connector)
+{
+	drm_connector_unregister(connector);
+	drm_connector_cleanup(connector);
+}
+
+static int vc4_vec_connector_get_modes(struct drm_connector *connector)
+{
+	struct drm_connector_state *state = connector->state;
+	struct drm_display_mode *mode;
+
+	mode = drm_mode_duplicate(connector->dev,
+				  vc4_vec_tv_modes[state->tv.mode].mode);
+	if (!mode) {
+		DRM_ERROR("Failed to create a new display mode\n");
+		return -ENOMEM;
+	}
+
+	drm_mode_probed_add(connector, mode);
+
+	return 1;
+}
+
+static const struct drm_connector_funcs vc4_vec_connector_funcs = {
+	.dpms = drm_atomic_helper_connector_dpms,
+	.detect = vc4_vec_connector_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.set_property = drm_atomic_helper_connector_set_property,
+	.destroy = vc4_vec_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 const struct drm_connector_helper_funcs vc4_vec_connector_helper_funcs = {
+	.get_modes = vc4_vec_connector_get_modes,
+};
+
+static struct drm_connector *vc4_vec_connector_init(struct drm_device *dev,
+						    struct vc4_vec *vec)
+{
+	struct drm_connector *connector = NULL;
+	struct vc4_vec_connector *vec_connector;
+
+	vec_connector = devm_kzalloc(dev->dev, sizeof(*vec_connector),
+				     GFP_KERNEL);
+	if (!vec_connector)
+		return ERR_PTR(-ENOMEM);
+
+	connector = &vec_connector->base;
+	connector->interlace_allowed = true;
+
+	vec_connector->encoder = vec->encoder;
+	vec_connector->vec = vec;
+
+	drm_connector_init(dev, connector, &vc4_vec_connector_funcs,
+			   DRM_MODE_CONNECTOR_Composite);
+	drm_connector_helper_add(connector, &vc4_vec_connector_helper_funcs);
+
+	drm_object_attach_property(&connector->base,
+				   dev->mode_config.tv_mode_property,
+				   VC4_VEC_TV_MODE_NTSC);
+	vec->tv_mode = &vc4_vec_tv_modes[VC4_VEC_TV_MODE_NTSC];
+
+	drm_mode_connector_attach_encoder(connector, vec->encoder);
+
+	return connector;
+}
+
+static const struct drm_encoder_funcs vc4_vec_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+static void vc4_vec_encoder_disable(struct drm_encoder *encoder)
+{
+	struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
+	struct vc4_vec *vec = vc4_vec_encoder->vec;
+	int ret;
+
+	VEC_WRITE(VEC_CFG, 0);
+	VEC_WRITE(VEC_DAC_MISC,
+		  VEC_DAC_MISC_VCD_PWRDN |
+		  VEC_DAC_MISC_BIAS_PWRDN |
+		  VEC_DAC_MISC_DAC_PWRDN |
+		  VEC_DAC_MISC_LDO_PWRDN);
+
+	clk_disable_unprepare(vec->clock);
+
+	ret = pm_runtime_put(&vec->pdev->dev);
+	if (ret < 0) {
+		DRM_ERROR("Failed to release power domain: %d\n", ret);
+		return;
+	}
+}
+
+static void vc4_vec_encoder_enable(struct drm_encoder *encoder)
+{
+	struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
+	struct vc4_vec *vec = vc4_vec_encoder->vec;
+	int ret;
+
+	ret = pm_runtime_get_sync(&vec->pdev->dev);
+	if (ret < 0) {
+		DRM_ERROR("Failed to retain power domain: %d\n", ret);
+		return;
+	}
+
+	/*
+	 * We need to set the clock rate each time we enable the encoder
+	 * because there's a chance we share the same parent with the HDMI
+	 * clock, and both drivers are requesting different rates.
+	 * The good news is, these 2 encoders cannot be enabled@the same
+	 * time, thus preventing incompatible rate requests.
+	 */
+	ret = clk_set_rate(vec->clock, 108000000);
+	if (ret) {
+		DRM_ERROR("Failed to set clock rate: %d\n", ret);
+		return;
+	}
+
+	ret = clk_prepare_enable(vec->clock);
+	if (ret) {
+		DRM_ERROR("Failed to turn on core clock: %d\n", ret);
+		return;
+	}
+
+	/* Reset the different blocks */
+	VEC_WRITE(VEC_WSE_RESET, 1);
+	VEC_WRITE(VEC_SOFT_RESET, 1);
+
+	/* Disable the CGSM-A and WSE blocks */
+	VEC_WRITE(VEC_WSE_CONTROL, 0);
+
+	/* Write config common to all modes. */
+
+	/*
+	 * Color subcarrier phase: phase = 360 * SCHPH / 256.
+	 * 0x28 <=> 39.375 deg.
+	 */
+	VEC_WRITE(VEC_SCHPH, 0x28);
+
+	/*
+	 * Reset to default values.
+	 */
+	VEC_WRITE(VEC_CLMP0_START, 0xac);
+	VEC_WRITE(VEC_CLMP0_END, 0xec);
+	VEC_WRITE(VEC_CONFIG2,
+		  VEC_CONFIG2_UV_DIG_DIS | VEC_CONFIG2_RGB_DIG_DIS);
+	VEC_WRITE(VEC_CONFIG3, VEC_CONFIG3_HORIZ_LEN_STD);
+	VEC_WRITE(VEC_DAC_CONFIG,
+		  VEC_DAC_CONFIG_DAC_CTRL(0xc) |
+		  VEC_DAC_CONFIG_DRIVER_CTRL(0xc) |
+		  VEC_DAC_CONFIG_LDO_BIAS_CTRL(0x46));
+
+	/* Mask all interrupts. */
+	VEC_WRITE(VEC_MASK0, 0);
+
+	vec->tv_mode->mode_set(vec);
+
+	VEC_WRITE(VEC_DAC_MISC,
+		  VEC_DAC_MISC_VID_ACT | VEC_DAC_MISC_DAC_RST_N);
+	VEC_WRITE(VEC_CFG, VEC_CFG_VEC_EN);
+}
+
+
+static bool vc4_vec_encoder_mode_fixup(struct drm_encoder *encoder,
+				       const struct drm_display_mode *mode,
+				       struct drm_display_mode *adjusted_mode)
+{
+	return true;
+}
+
+static void vc4_vec_encoder_atomic_mode_set(struct drm_encoder *encoder,
+					struct drm_crtc_state *crtc_state,
+					struct drm_connector_state *conn_state)
+{
+	struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
+	struct vc4_vec *vec = vc4_vec_encoder->vec;
+
+	vec->tv_mode = &vc4_vec_tv_modes[conn_state->tv.mode];
+}
+
+static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
+					struct drm_crtc_state *crtc_state,
+					struct drm_connector_state *conn_state)
+{
+	const struct vc4_vec_tv_mode *vec_mode;
+
+	vec_mode = &vc4_vec_tv_modes[conn_state->tv.mode];
+
+	if (conn_state->crtc &&
+	    !drm_mode_equal(vec_mode->mode, &crtc_state->adjusted_mode))
+		return -EINVAL;
+
+	return 0;
+}
+
+static const struct drm_encoder_helper_funcs vc4_vec_encoder_helper_funcs = {
+	.disable = vc4_vec_encoder_disable,
+	.enable = vc4_vec_encoder_enable,
+	.mode_fixup = vc4_vec_encoder_mode_fixup,
+	.atomic_check = vc4_vec_encoder_atomic_check,
+	.atomic_mode_set = vc4_vec_encoder_atomic_mode_set,
+};
+
+static const struct of_device_id vc4_vec_dt_match[] = {
+	{ .compatible = "brcm,bcm2835-vec", .data = NULL },
+	{ /* sentinel */ },
+};
+
+static const char * const tv_mode_names[] = {
+	[VC4_VEC_TV_MODE_NTSC] = "NTSC",
+	[VC4_VEC_TV_MODE_NTSC_J] = "NTSC-J",
+	[VC4_VEC_TV_MODE_PAL] = "PAL",
+	[VC4_VEC_TV_MODE_PAL_M] = "PAL-M",
+};
+
+static int vc4_vec_bind(struct device *dev, struct device *master, void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct drm_device *drm = dev_get_drvdata(master);
+	struct vc4_dev *vc4 = to_vc4_dev(drm);
+	struct vc4_vec *vec;
+	struct vc4_vec_encoder *vc4_vec_encoder;
+	int ret;
+
+	ret = drm_mode_create_tv_properties(drm, ARRAY_SIZE(tv_mode_names),
+					    tv_mode_names);
+	if (ret)
+		return ret;
+
+	vec = devm_kzalloc(dev, sizeof(*vec), GFP_KERNEL);
+	if (!vec)
+		return -ENOMEM;
+
+	vc4_vec_encoder = devm_kzalloc(dev, sizeof(*vc4_vec_encoder),
+				       GFP_KERNEL);
+	if (!vc4_vec_encoder)
+		return -ENOMEM;
+	vc4_vec_encoder->base.type = VC4_ENCODER_TYPE_VEC;
+	vc4_vec_encoder->vec = vec;
+	vec->encoder = &vc4_vec_encoder->base.base;
+
+	vec->pdev = pdev;
+	vec->regs = vc4_ioremap_regs(pdev, 0);
+	if (IS_ERR(vec->regs))
+		return PTR_ERR(vec->regs);
+
+	vec->clock = devm_clk_get(dev, NULL);
+	if (IS_ERR(vec->clock)) {
+		ret = PTR_ERR(vec->clock);
+		if (ret != -EPROBE_DEFER)
+			DRM_ERROR("Failed to get clock: %d\n", ret);
+		return ret;
+	}
+
+	pm_runtime_enable(dev);
+
+	drm_encoder_init(drm, vec->encoder, &vc4_vec_encoder_funcs,
+			 DRM_MODE_ENCODER_TVDAC, NULL);
+	drm_encoder_helper_add(vec->encoder, &vc4_vec_encoder_helper_funcs);
+
+	vec->connector = vc4_vec_connector_init(drm, vec);
+	if (IS_ERR(vec->connector)) {
+		ret = PTR_ERR(vec->connector);
+		goto err_destroy_encoder;
+	}
+
+	dev_set_drvdata(dev, vec);
+
+	vc4->vec = vec;
+
+	return 0;
+
+err_destroy_encoder:
+	drm_encoder_cleanup(vec->encoder);
+	pm_runtime_disable(dev);
+
+	return ret;
+}
+
+static void vc4_vec_unbind(struct device *dev, struct device *master,
+			   void *data)
+{
+	struct drm_device *drm = dev_get_drvdata(master);
+	struct vc4_dev *vc4 = to_vc4_dev(drm);
+	struct vc4_vec *vec = dev_get_drvdata(dev);
+
+	vc4_vec_connector_destroy(vec->connector);
+	drm_encoder_cleanup(vec->encoder);
+	pm_runtime_disable(dev);
+
+	vc4->vec = NULL;
+}
+
+static const struct component_ops vc4_vec_ops = {
+	.bind   = vc4_vec_bind,
+	.unbind = vc4_vec_unbind,
+};
+
+static int vc4_vec_dev_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &vc4_vec_ops);
+}
+
+static int vc4_vec_dev_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &vc4_vec_ops);
+	return 0;
+}
+
+struct platform_driver vc4_vec_driver = {
+	.probe = vc4_vec_dev_probe,
+	.remove = vc4_vec_dev_remove,
+	.driver = {
+		.name = "vc4_vec",
+		.of_match_table = vc4_vec_dt_match,
+	},
+};
-- 
2.7.4

^ permalink raw reply related

* [RESEND PATCH v2 3/7] drm: Add TV connector states to drm_connector_state
From: Boris Brezillon @ 2016-12-02 13:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480686493-4813-1-git-send-email-boris.brezillon@free-electrons.com>

Some generic TV connector properties are exposed in drm_mode_config, but
they are currently handled independently in each DRM encoder driver.

Extend the drm_connector_state to store TV related states, and modify the
drm_atomic_connector_{set,get}_property() helpers to fill the connector
state accordingly.

Each driver is then responsible for checking and applying the new config
in its ->atomic_mode_{check,set}() operations.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
Changes in v2
- fix copy/paste errors
- use an enum for the subconnector field
- switch all fields to unsigned int
---
 drivers/gpu/drm/drm_atomic.c | 50 ++++++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_connector.h  | 32 ++++++++++++++++++++++++++++
 2 files changed, 82 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index e6862a744210..f93395c3c181 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -989,12 +989,38 @@ int drm_atomic_connector_set_property(struct drm_connector *connector,
 		 * now?) atomic writes to DPMS property:
 		 */
 		return -EINVAL;
+	} else if (property == config->tv_select_subconnector_property) {
+		state->tv.subconnector = val;
+	} else if (property == config->tv_left_margin_property) {
+		state->tv.margins.left = val;
+	} else if (property == config->tv_right_margin_property) {
+		state->tv.margins.right = val;
+	} else if (property == config->tv_top_margin_property) {
+		state->tv.margins.top = val;
+	} else if (property == config->tv_bottom_margin_property) {
+		state->tv.margins.bottom = val;
+	} else if (property == config->tv_mode_property) {
+		state->tv.mode = val;
+	} else if (property == config->tv_brightness_property) {
+		state->tv.brightness = val;
+	} else if (property == config->tv_contrast_property) {
+		state->tv.contrast = val;
+	} else if (property == config->tv_flicker_reduction_property) {
+		state->tv.flicker_reduction = val;
+	} else if (property == config->tv_overscan_property) {
+		state->tv.overscan = val;
+	} else if (property == config->tv_saturation_property) {
+		state->tv.saturation = val;
+	} else if (property == config->tv_hue_property) {
+		state->tv.hue = val;
 	} else if (connector->funcs->atomic_set_property) {
 		return connector->funcs->atomic_set_property(connector,
 				state, property, val);
 	} else {
 		return -EINVAL;
 	}
+
+	return 0;
 }
 EXPORT_SYMBOL(drm_atomic_connector_set_property);
 
@@ -1025,6 +1051,30 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
 		*val = (state->crtc) ? state->crtc->base.id : 0;
 	} else if (property == config->dpms_property) {
 		*val = connector->dpms;
+	} else if (property == config->tv_select_subconnector_property) {
+		*val = state->tv.subconnector;
+	} else if (property == config->tv_left_margin_property) {
+		*val = state->tv.margins.left;
+	} else if (property == config->tv_right_margin_property) {
+		*val = state->tv.margins.right;
+	} else if (property == config->tv_top_margin_property) {
+		*val = state->tv.margins.top;
+	} else if (property == config->tv_bottom_margin_property) {
+		*val = state->tv.margins.bottom;
+	} else if (property == config->tv_mode_property) {
+		*val = state->tv.mode;
+	} else if (property == config->tv_brightness_property) {
+		*val = state->tv.brightness;
+	} else if (property == config->tv_contrast_property) {
+		*val = state->tv.contrast;
+	} else if (property == config->tv_flicker_reduction_property) {
+		*val = state->tv.flicker_reduction;
+	} else if (property == config->tv_overscan_property) {
+		*val = state->tv.overscan;
+	} else if (property == config->tv_saturation_property) {
+		*val = state->tv.saturation;
+	} else if (property == config->tv_hue_property) {
+		*val = state->tv.hue;
 	} else if (connector->funcs->atomic_get_property) {
 		return connector->funcs->atomic_get_property(connector,
 				state, property, val);
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index ac9d7d8e0e43..2645e8038572 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -194,10 +194,40 @@ int drm_display_info_set_bus_formats(struct drm_display_info *info,
 				     unsigned int num_formats);
 
 /**
+ * struct drm_tv_connector_state - TV connector related states
+ * @subconnector: selected subconnector
+ * @margins: left/right/top/bottom margins
+ * @mode: TV mode
+ * @brightness: brightness in percent
+ * @contrast: contrast in percent
+ * @flicker_reduction: flicker reduction in percent
+ * @overscan: overscan in percent
+ * @saturation: saturation in percent
+ * @hue: hue in percent
+ */
+struct drm_tv_connector_state {
+	enum drm_mode_subconnector subconnector;
+	struct {
+		unsigned int left;
+		unsigned int right;
+		unsigned int top;
+		unsigned int bottom;
+	} margins;
+	unsigned int mode;
+	unsigned int brightness;
+	unsigned int contrast;
+	unsigned int flicker_reduction;
+	unsigned int overscan;
+	unsigned int saturation;
+	unsigned int hue;
+};
+
+/**
  * struct drm_connector_state - mutable connector state
  * @connector: backpointer to the connector
  * @best_encoder: can be used by helpers and drivers to select the encoder
  * @state: backpointer to global drm_atomic_state
+ * @tv: TV connector state
  */
 struct drm_connector_state {
 	struct drm_connector *connector;
@@ -213,6 +243,8 @@ struct drm_connector_state {
 	struct drm_encoder *best_encoder;
 
 	struct drm_atomic_state *state;
+
+	struct drm_tv_connector_state tv;
 };
 
 /**
-- 
2.7.4

^ permalink raw reply related

* [RESEND PATCH v2 2/7] drm: Turn DRM_MODE_SUBCONNECTOR_xx definitions into an enum
From: Boris Brezillon @ 2016-12-02 13:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480686493-4813-1-git-send-email-boris.brezillon@free-electrons.com>

List of values like the DRM_MODE_SUBCONNECTOR_xx ones are better
represented with enums.

Turn the DRM_MODE_SUBCONNECTOR_xx macros into an enum.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 include/uapi/drm/drm_mode.h | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index df0e3504c349..970bfc0d7107 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -220,14 +220,16 @@ struct drm_mode_get_encoder {
 
 /* This is for connectors with multiple signal types. */
 /* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */
-#define DRM_MODE_SUBCONNECTOR_Automatic	0
-#define DRM_MODE_SUBCONNECTOR_Unknown	0
-#define DRM_MODE_SUBCONNECTOR_DVID	3
-#define DRM_MODE_SUBCONNECTOR_DVIA	4
-#define DRM_MODE_SUBCONNECTOR_Composite	5
-#define DRM_MODE_SUBCONNECTOR_SVIDEO	6
-#define DRM_MODE_SUBCONNECTOR_Component	8
-#define DRM_MODE_SUBCONNECTOR_SCART	9
+enum drm_mode_subconnector {
+	DRM_MODE_SUBCONNECTOR_Automatic = 0,
+	DRM_MODE_SUBCONNECTOR_Unknown = 0,
+	DRM_MODE_SUBCONNECTOR_DVID = 3,
+	DRM_MODE_SUBCONNECTOR_DVIA = 4,
+	DRM_MODE_SUBCONNECTOR_Composite = 5,
+	DRM_MODE_SUBCONNECTOR_SVIDEO = 6,
+	DRM_MODE_SUBCONNECTOR_Component = 8,
+	DRM_MODE_SUBCONNECTOR_SCART = 9,
+};
 
 #define DRM_MODE_CONNECTOR_Unknown	0
 #define DRM_MODE_CONNECTOR_VGA		1
-- 
2.7.4

^ permalink raw reply related

* [RESEND PATCH v2 1/7] drm/vc4: Fix ->clock_select setting for the VEC encoder
From: Boris Brezillon @ 2016-12-02 13:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480686493-4813-1-git-send-email-boris.brezillon@free-electrons.com>

PV_CONTROL_CLK_SELECT_VEC is actually 2 and not 0. Fix the definition and
rework the vc4_set_crtc_possible_masks() to cover the full range of the
PV_CONTROL_CLK_SELECT field.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/gpu/drm/vc4/vc4_crtc.c | 38 +++++++++++++++++++++++---------------
 drivers/gpu/drm/vc4/vc4_drv.h  |  1 +
 drivers/gpu/drm/vc4/vc4_regs.h |  3 ++-
 3 files changed, 26 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index 7f08d681a74b..c317e9103f9b 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -83,8 +83,7 @@ struct vc4_crtc_data {
 	/* Which channel of the HVS this pixelvalve sources from. */
 	int hvs_channel;
 
-	enum vc4_encoder_type encoder0_type;
-	enum vc4_encoder_type encoder1_type;
+	enum vc4_encoder_type encoder_types[4];
 };
 
 #define CRTC_WRITE(offset, val) writel(val, vc4_crtc->regs + (offset))
@@ -859,20 +858,26 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
 
 static const struct vc4_crtc_data pv0_data = {
 	.hvs_channel = 0,
-	.encoder0_type = VC4_ENCODER_TYPE_DSI0,
-	.encoder1_type = VC4_ENCODER_TYPE_DPI,
+	.encoder_types = {
+		[PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI0,
+		[PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_DPI,
+	},
 };
 
 static const struct vc4_crtc_data pv1_data = {
 	.hvs_channel = 2,
-	.encoder0_type = VC4_ENCODER_TYPE_DSI1,
-	.encoder1_type = VC4_ENCODER_TYPE_SMI,
+	.encoder_types = {
+		[PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI1,
+		[PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_SMI,
+	},
 };
 
 static const struct vc4_crtc_data pv2_data = {
 	.hvs_channel = 1,
-	.encoder0_type = VC4_ENCODER_TYPE_VEC,
-	.encoder1_type = VC4_ENCODER_TYPE_HDMI,
+	.encoder_types = {
+		[PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_HDMI,
+		[PV_CONTROL_CLK_SELECT_VEC] = VC4_ENCODER_TYPE_VEC,
+	},
 };
 
 static const struct of_device_id vc4_crtc_dt_match[] = {
@@ -886,17 +891,20 @@ static void vc4_set_crtc_possible_masks(struct drm_device *drm,
 					struct drm_crtc *crtc)
 {
 	struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+	const struct vc4_crtc_data *crtc_data = vc4_crtc->data;
+	const enum vc4_encoder_type *encoder_types = crtc_data->encoder_types;
 	struct drm_encoder *encoder;
 
 	drm_for_each_encoder(encoder, drm) {
 		struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
-
-		if (vc4_encoder->type == vc4_crtc->data->encoder0_type) {
-			vc4_encoder->clock_select = 0;
-			encoder->possible_crtcs |= drm_crtc_mask(crtc);
-		} else if (vc4_encoder->type == vc4_crtc->data->encoder1_type) {
-			vc4_encoder->clock_select = 1;
-			encoder->possible_crtcs |= drm_crtc_mask(crtc);
+		int i;
+
+		for (i = 0; i < ARRAY_SIZE(crtc_data->encoder_types); i++) {
+			if (vc4_encoder->type == encoder_types[i]) {
+				vc4_encoder->clock_select = i;
+				encoder->possible_crtcs |= drm_crtc_mask(crtc);
+				break;
+			}
 		}
 	}
 }
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 7c1e4d97486f..946d48c33668 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -194,6 +194,7 @@ to_vc4_plane(struct drm_plane *plane)
 }
 
 enum vc4_encoder_type {
+	VC4_ENCODER_TYPE_NONE,
 	VC4_ENCODER_TYPE_HDMI,
 	VC4_ENCODER_TYPE_VEC,
 	VC4_ENCODER_TYPE_DSI0,
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
index 1aa44c2db556..39f6886b2410 100644
--- a/drivers/gpu/drm/vc4/vc4_regs.h
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
@@ -177,8 +177,9 @@
 # define PV_CONTROL_WAIT_HSTART			BIT(12)
 # define PV_CONTROL_PIXEL_REP_MASK		VC4_MASK(5, 4)
 # define PV_CONTROL_PIXEL_REP_SHIFT		4
-# define PV_CONTROL_CLK_SELECT_DSI_VEC		0
+# define PV_CONTROL_CLK_SELECT_DSI		0
 # define PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI	1
+# define PV_CONTROL_CLK_SELECT_VEC		2
 # define PV_CONTROL_CLK_SELECT_MASK		VC4_MASK(3, 2)
 # define PV_CONTROL_CLK_SELECT_SHIFT		2
 # define PV_CONTROL_FIFO_CLR			BIT(1)
-- 
2.7.4

^ permalink raw reply related

* [RESEND PATCH v2 0/7] drm/vc4: VEC (SDTV) output support
From: Boris Brezillon @ 2016-12-02 13:48 UTC (permalink / raw)
  To: linux-arm-kernel

Sorry for the noise, but I forgot to Cc the DT maintainers.

Here is the 2nd version of the VC4/VEC series.

We still miss the two clock patches mentioned by Eric in the first
version to make the encoder work no matter the setting applied by the
bootloader.

Regards,

Boris

Boris Brezillon (7):
  drm/vc4: Fix ->clock_select setting for the VEC encoder
  drm: Turn DRM_MODE_SUBCONNECTOR_xx definitions into an enum
  drm: Add TV connector states to drm_connector_state
  drm/vc4: Add support for the VEC (Video Encoder) IP
  drm/vc4: Document VEC DT binding
  ARM: bcm/dt: Add VEC node in bcm283x.dtsi
  ARM: bcm/dt: Enable the VEC IP on all RaspeberryPi boards

 .../devicetree/bindings/display/brcm,bcm-vc4.txt   |  14 +
 arch/arm/boot/dts/bcm2835-rpi.dtsi                 |   5 +
 arch/arm/boot/dts/bcm283x.dtsi                     |   8 +
 drivers/gpu/drm/drm_atomic.c                       |  50 ++
 drivers/gpu/drm/vc4/Makefile                       |   1 +
 drivers/gpu/drm/vc4/vc4_crtc.c                     |  38 +-
 drivers/gpu/drm/vc4/vc4_debugfs.c                  |   1 +
 drivers/gpu/drm/vc4/vc4_drv.c                      |   1 +
 drivers/gpu/drm/vc4/vc4_drv.h                      |   6 +
 drivers/gpu/drm/vc4/vc4_regs.h                     |   3 +-
 drivers/gpu/drm/vc4/vc4_vec.c                      | 657 +++++++++++++++++++++
 include/drm/drm_connector.h                        |  32 +
 include/uapi/drm/drm_mode.h                        |  18 +-
 13 files changed, 810 insertions(+), 24 deletions(-)
 create mode 100644 drivers/gpu/drm/vc4/vc4_vec.c

-- 
2.7.4

^ permalink raw reply

* XHCI controller does not detect USB key insertion
From: Neil Armstrong @ 2016-12-02 13:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <58414BC5.109@free.fr>

On 12/02/2016 11:24 AM, Mason wrote:
> On 02/12/2016 10:03, Felipe Balbi wrote:
> 
>> Mason wrote:
>>
>>> I'm trying out a SoC with a brand new USB controller, which is (supposedly)
>>> a standard XHCI controller. In theory, I would just need to build the right
>>> driver, and everything would auto-magically work, right?
>>
>> perhaps, but there might be needed initialization of other resources
>> like PHYs and stuff like that.
> 
> Let me dive into additional details...
> 
> First of all, there is a register aptly called "USB3_RESET" which
> is used to release several USB3-related blocks from reset.
> Of course, that's the first register I tweaked :-)
> 
> There are *3* address ranges with USB3-related registers.
> 
> 1) one called host_usb30_xhcl (I believe "xhcl" is a typo for "xhci")
> This is the address I passed to the Linux driver. The first register
> is CAPLENGTH_VERSION. I assume these are the standard XHCI registers.
> (Last register is XHCL_EXTENDED_CAP3_USB3 at offset 0xc008)
> 
> 2) one called host_usb30_port
> This contains "Device and Port Specific Registers".
> Is it standard?
> How is Linux supposed to know where to find it?
> Contains registers such as
> Device Transaction Status
> Device UTMI command and status for USB2
> Set ISOC Delay
> USB3 Function Notification
> Rx DMA BD Start Address for Control Endpoint
> EP Burst Size
> Tx DMA BD Start Address Control Endpoint
> EP $N IN/OUT
> Device Notification Register
> EP_Isochronous Timestamp
> 
> Are registers named LTSSM_TIMER_REGISTER{1,2,3} standard?
> they have fields such as reg_12_ms_timeout (and other numbers like 2, 6, 100, 300)
> 
> 3) one called host_usb30
> This contains lower-level stuff
> 0x2e800	CONFIG
> 0x2e804	CONTROL
> 0x2e808	TEST
> 0x2e80c	STATUS
> 0x2e810	CLK_RST_0
> 0x2e814	CLK_RST_1
> 0x2e818	PARAM_0
> 0x2e81c	PARAM_1
> 0x2e820	PARAM_2
> 0x2e880	SNPS_CR_ADD
> 0x2e884	SNPS_CR_DATA
> 0x2e8c0	RESET_CTRL
> 
> I haven't touched any of these so far.
> 
> 
>>> # lsusb -v
>>> Bus 001 Device 001: ID 1d6b:0002
>>> Bus 002 Device 001: ID 1d6b:0003
> 
> Isn't lsusb verbose supposed to print much more than that?
> 
> 
>>> I'd like to hear suggestions about what I can tweak to fix the problem.
>>
>> go to your documentation and see if you have initialized
>> everything. Which SoC is this?
> 
> (Sad face) All the documentation I have is in front of me, and nothing
> is ringing a bell. This is a Sigma Designs SoC, with a Pravega XHCI
> controller + Synopsys PHY.
> 
> The documentation I have:
> 
> Pravega_Dual_Mode_Datasheet_v10c.pdf (documents IP signals)
> Pravega_Dual_Mode_Controller_Programmers_Reference_manual_v1.pdf (documents IP registers)
> PHY databook (very low-level stuff)
> SoC register mapping (for how the SoC maps the IP signals to registers)

You should have all the necessary bits to enable and configure the Embedded Synopsys PHY !

You should have some register mapping of the PHY signals, or at least a way to write those registers.

You should have a reset, clock gate and eventually a power regulator to enable in order to have the PHY running.

> 
> So far, I'm stumped :-(
> 
> Regards.
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

^ permalink raw reply

* IMX6 - KMS/DRM video overlay question
From: Krzysztof Hałasa @ 2016-12-02 13:46 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

I'm currently able to display flawless full HD video on IMX6
HDMI using:

gst-launch-1.0 udpsrc uri=udp://XXX reuse=true caps="application/x-rtp,media=(string)video,clock-rate=(int)90000,encoding-name=(string)H264" ! rtph264depay ! h264parse ! v4l2video1dec capture-io-mode=dmabuf ! kmssink name=imx-drm sync=0

The CPU utilization is very small.

Now, I'd like to display some OSD on top of the video. Is it possible
with the current driver code?

The idea would be to have a YUV420 video plane in the background, and
an ARGB frame buffer (with transparency) in the foreground.

What I'm trying to do is (test source available on request; 720p ATM
but 1080p performance doesn't seem to be an issue):

drmSetMaster()

# Testing plane buffer
kms_bo_create(1280x720)
drmModeAddFB2(1280x720, DRM_FORMAT_[AX]RGB8888) <<< YUV420 planned
drmModeSetCrtc(crtc_id 24, fb_id 37)
kms_bo_map()
drmModeSetPlane(plane_id 25, crtc_id 24, fb_id 37, 1280x720)

# Testing dumb buffer
DRM_IOCTL_MODE_CREATE_DUMB(1280x720)
drmModeAddFB2(1280x720, handle 2, pitch 5120, DRM_FORMAT_[AX]RGB8888)
drmModeSetCrtc(crtc_id 24, fb_id 36)
DRM_IOCTL_MODE_MAP_DUMB(handle 2)
mmap(size 3686400, offset 0x10546000)

drmDropMaster()

I get either the video plane only (if created with XRGB8888) or both
planes, with video plane on top (if created with ARGB8888 - I can
control video plane transparency). Base FB XRGB/ARGB mode seems to be
ignored (it's always completely opaque).

Would it be possible to swap the planes (so they work like the other
drivers)?
The IMX6DQRM book says both planes can be combined in any order, however
I'm not yet sure how is it done in the driver.

Also, I noticed that I have to drmModeSetCrtc(video plane) first.
Otherwise (if drmModeSetCrtc(base fb) is done first) I only get the
video plane.

Comments?

TIA,
-- 
Krzysztof Halasa

Industrial Research Institute for Automation and Measurements PIAP
Al. Jerozolimskie 202, 02-486 Warsaw, Poland

^ permalink raw reply

* [PATCH v3 7/7] ARM: dts: stm32: add stm32 general purpose timer driver in DT
From: Alexandre Torgue @ 2016-12-02 13:41 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480673842-20804-8-git-send-email-benjamin.gaignard@st.com>

Hi Benjamin,

On 12/02/2016 11:17 AM, Benjamin Gaignard wrote:
> Add general purpose timers and it sub-nodes into DT for stm32f4.
> Define and enable pwm1 and pwm3 for stm32f469 discovery board
>
> version 3:
> - use "st,stm32-timer-trigger" in DT
>
> version 2:
> - use parameters to describe hardware capabilities
> - do not use references for pwm and iio timer subnodes
>
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
> ---
>  arch/arm/boot/dts/stm32f429.dtsi      | 333 +++++++++++++++++++++++++++++++++-
>  arch/arm/boot/dts/stm32f469-disco.dts |  28 +++
>  2 files changed, 360 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
> index bca491d..8c50d03 100644
> --- a/arch/arm/boot/dts/stm32f429.dtsi
> +++ b/arch/arm/boot/dts/stm32f429.dtsi
> @@ -48,7 +48,7 @@
>  #include "skeleton.dtsi"
>  #include "armv7-m.dtsi"
>  #include <dt-bindings/pinctrl/stm32f429-pinfunc.h>
> -
> +#include <dt-bindings/iio/timer/st,stm32-timer-triggers.h>
>  / {
>  	clocks {
>  		clk_hse: clk-hse {
> @@ -355,6 +355,21 @@
>  					slew-rate = <2>;
>  				};
>  			};
> +
> +			pwm1_pins: pwm at 1 {
> +				pins {
> +					pinmux = <STM32F429_PA8_FUNC_TIM1_CH1>,
> +						 <STM32F429_PB13_FUNC_TIM1_CH1N>,
> +						 <STM32F429_PB12_FUNC_TIM1_BKIN>;
> +				};
> +			};
> +
> +			pwm3_pins: pwm at 3 {
> +				pins {
> +					pinmux = <STM32F429_PB4_FUNC_TIM3_CH1>,
> +						 <STM32F429_PB5_FUNC_TIM3_CH2>;
> +				};
> +			};
>  		};
>
>  		rcc: rcc at 40023810 {
> @@ -426,6 +441,322 @@
>  			interrupts = <80>;
>  			clocks = <&rcc 0 38>;
>  		};
> +
> +		gptimer1: gptimer1 at 40010000 {

Currently, nodes are ordered following base address.

> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40010000 0x400>;
> +			clocks = <&rcc 0 160>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			pwm1 at 0 {
> +				compatible = "st,stm32-pwm";
> +				st,pwm-num-chan = <4>;
> +				st,breakinput;
> +				st,complementary;
> +				status = "disabled";
> +			};
> +
> +			timer1 at 0 {
> +				compatible = "st,stm32-timer-trigger";
> +				interrupts = <27>;
> +				st,input-triggers-names = TIM5_TRGO,
> +							  TIM2_TRGO,
> +							  TIM4_TRGO,
> +							  TIM3_TRGO;
> +				st,output-triggers-names = TIM1_TRGO,
> +							   TIM1_CH1,
> +							   TIM1_CH2,
> +							   TIM1_CH3,
> +							   TIM1_CH4;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer2: gptimer2 at 40000000 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40000000 0x400>;
> +			clocks = <&rcc 0 128>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			pwm2 at 0 {
> +				compatible = "st,stm32-pwm";
> +				st,pwm-num-chan = <4>;
> +				st,32bits-counter;
> +				status = "disabled";
> +			};
> +
> +			timer2 at 0 {
> +				compatible = "st,stm32-timer-trigger";
> +				interrupts = <28>;
> +				st,input-triggers-names = TIM1_TRGO,
> +							  TIM8_TRGO,
> +							  TIM3_TRGO,
> +							  TIM4_TRGO;
> +				st,output-triggers-names = TIM2_TRGO,
> +							   TIM2_CH1,
> +							   TIM2_CH2,
> +							   TIM2_CH3,
> +							   TIM2_CH4;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer3: gptimer3 at 40000400 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40000400 0x400>;
> +			clocks = <&rcc 0 129>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			pwm3 at 0 {
> +				compatible = "st,stm32-pwm";
> +				st,pwm-num-chan = <4>;
> +				status = "disabled";
> +			};
> +
> +			timer3 at 0 {
> +				compatible = "st,stm32-timer-trigger";
> +				interrupts = <29>;
> +				st,input-triggers-names = TIM1_TRGO,
> +							  TIM8_TRGO,
> +							  TIM5_TRGO,
> +							  TIM4_TRGO;
> +				st,output-triggers-names = TIM3_TRGO,
> +							   TIM3_CH1,
> +							   TIM3_CH2,
> +							   TIM3_CH3,
> +							   TIM3_CH4;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer4: gptimer4 at 40000800 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40000800 0x400>;
> +			clocks = <&rcc 0 130>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			pwm4 at 0 {
> +				compatible = "st,stm32-pwm";
> +				st,pwm-num-chan = <4>;
> +				status = "disabled";
> +			};
> +
> +			timer4 at 0 {
> +				compatible = "st,stm32-timer-trigger";
> +				interrupts = <30>;
> +				st,input-triggers-names = TIM1_TRGO,
> +							  TIM2_TRGO,
> +							  TIM3_TRGO,
> +							  TIM8_TRGO;
> +				st,output-triggers-names = TIM4_TRGO,
> +							   TIM4_CH1,
> +							   TIM4_CH2,
> +							   TIM4_CH3,
> +							   TIM4_CH4;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer5: gptimer5 at 40000C00 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40000C00 0x400>;
> +			clocks = <&rcc 0 131>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			pwm5 at 0 {
> +				compatible = "st,stm32-pwm";
> +				st,pwm-num-chan = <4>;
> +				st,32bits-counter;
> +				status = "disabled";
> +			};
> +
> +			timer5 at 0 {
> +				compatible = "st,stm32-timer-trigger";
> +				interrupts = <50>;
> +				st,input-triggers-names = TIM2_TRGO,
> +							  TIM3_TRGO,
> +							  TIM4_TRGO,
> +							  TIM8_TRGO;
> +				st,output-triggers-names = TIM5_TRGO,
> +							   TIM5_CH1,
> +							   TIM5_CH2,
> +							   TIM5_CH3,
> +							   TIM5_CH4;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer6: gptimer6 at 40001000 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40001000 0x400>;
> +			clocks = <&rcc 0 132>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			timer6 at 0 {
> +				compatible = "st,stm32-timer-trigger";
> +				interrupts = <54>;
> +				st,output-triggers-names = TIM6_TRGO;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer7: gptimer7 at 40001400 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40001400 0x400>;
> +			clocks = <&rcc 0 133>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			timer7 at 0 {
> +				compatible = "st,stm32-timer-trigger";
> +				interrupts = <55>;
> +				st,output-triggers-names = TIM7_TRGO;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer8: gptimer8 at 40010400 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40010400 0x400>;
> +			clocks = <&rcc 0 161>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			pwm8 at 0 {
> +				compatible = "st,stm32-pwm";
> +				st,pwm-num-chan = <4>;
> +				st,complementary;
> +				st,breakinput;
> +				status = "disabled";
> +			};
> +
> +			timer8 at 0 {
> +				compatible = "st,stm32-timer-trigger";
> +				interrupts = <46>;
> +				st,input-triggers-names = TIM1_TRGO,
> +							  TIM2_TRGO,
> +							  TIM4_TRGO,
> +							  TIM5_TRGO;
> +				st,output-triggers-names = TIM8_TRGO,
> +							   TIM8_CH1,
> +							   TIM8_CH2,
> +							   TIM8_CH3,
> +							   TIM8_CH4;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer9: gptimer9 at 40014000 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40014000 0x400>;
> +			clocks = <&rcc 0 176>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			pwm9 at 0 {
> +				compatible = "st,stm32-pwm";
> +				st,pwm-num-chan = <2>;
> +				status = "disabled";
> +			};
> +
> +			timer9 at 0 {
> +				compatible = "st,stm32-timer-trigger";
> +				interrupts = <24>;
> +				st,input-triggers-names = TIM2_TRGO,
> +							  TIM3_TRGO;
> +				st,output-triggers-names = TIM9_TRGO,
> +							   TIM9_CH1,
> +							   TIM9_CH2;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer10: gptimer10 at 40014400 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40014400 0x400>;
> +			clocks = <&rcc 0 177>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			pwm10 at 0 {
> +				compatible = "st,stm32-pwm";
> +				st,pwm-num-chan = <1>;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer11: gptimer11 at 40014800 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40014800 0x400>;
> +			clocks = <&rcc 0 178>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			pwm11 at 0 {
> +				compatible = "st,stm32-pwm";
> +				st,pwm-num-chan = <1>;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer12: gptimer12 at 40001800 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40001800 0x400>;
> +			clocks = <&rcc 0 134>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			pwm12 at 0 {
> +				compatible = "st,stm32-pwm";
> +				st,pwm-num-chan = <2>;
> +				status = "disabled";
> +			};
> +
> +			timer12 at 0 {
> +				compatible = "st,stm32-timer-trigger";
> +				interrupts = <43>;
> +				st,input-triggers-names = TIM4_TRGO,
> +							  TIM5_TRGO;
> +				st,output-triggers-names = TIM12_TRGO,
> +							   TIM12_CH1,
> +							   TIM12_CH2;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer13: gptimer13 at 40001C00 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40001C00 0x400>;
> +			clocks = <&rcc 0 135>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			pwm13 at 0 {
> +				compatible = "st,stm32-pwm";
> +				st,pwm-num-chan = <1>;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer14: gptimer14 at 40002000 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40002000 0x400>;
> +			clocks = <&rcc 0 136>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			pwm14 at 0 {
> +				compatible = "st,stm32-pwm";
> +				st,pwm-num-chan = <1>;
> +				status = "disabled";
> +			};
> +		};
>  	};
>  };
>
> diff --git a/arch/arm/boot/dts/stm32f469-disco.dts b/arch/arm/boot/dts/stm32f469-disco.dts
> index 8a163d7..df4ca7e 100644
> --- a/arch/arm/boot/dts/stm32f469-disco.dts
> +++ b/arch/arm/boot/dts/stm32f469-disco.dts
> @@ -81,3 +81,31 @@
>  &usart3 {
>  	status = "okay";
>  };
> +
> +&gptimer1 {
> +	status = "okay";
> +
> +	pwm1 at 0 {
> +		pinctrl-0	= <&pwm1_pins>;
> +		pinctrl-names	= "default";
> +		status = "okay";
> +	};
> +
> +	timer1 at 0 {
> +		status = "okay";
> +	};
> +};
> +
> +&gptimer3 {
> +	status = "okay";
> +
> +	pwm3 at 0 {
> +		pinctrl-0	= <&pwm3_pins>;
> +		pinctrl-names	= "default";
> +		status = "okay";
> +	};
> +
> +	timer3 at 0 {
> +		status = "okay";
> +	};
> +};
>

^ permalink raw reply

* [PATCH v3 7/7] ARM: dts: stm32: add stm32 general purpose timer driver in DT
From: Lee Jones @ 2016-12-02 13:22 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480673842-20804-8-git-send-email-benjamin.gaignard@st.com>

On Fri, 02 Dec 2016, Benjamin Gaignard wrote:

> Add general purpose timers and it sub-nodes into DT for stm32f4.
> Define and enable pwm1 and pwm3 for stm32f469 discovery board
> 
> version 3:
> - use "st,stm32-timer-trigger" in DT
> 
> version 2:
> - use parameters to describe hardware capabilities
> - do not use references for pwm and iio timer subnodes
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
> ---
>  arch/arm/boot/dts/stm32f429.dtsi      | 333 +++++++++++++++++++++++++++++++++-
>  arch/arm/boot/dts/stm32f469-disco.dts |  28 +++
>  2 files changed, 360 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
> index bca491d..8c50d03 100644
> --- a/arch/arm/boot/dts/stm32f429.dtsi
> +++ b/arch/arm/boot/dts/stm32f429.dtsi
> @@ -48,7 +48,7 @@
>  #include "skeleton.dtsi"
>  #include "armv7-m.dtsi"
>  #include <dt-bindings/pinctrl/stm32f429-pinfunc.h>
> -
> +#include <dt-bindings/iio/timer/st,stm32-timer-triggers.h>
>  / {
>  	clocks {
>  		clk_hse: clk-hse {
> @@ -355,6 +355,21 @@
>  					slew-rate = <2>;
>  				};
>  			};
> +
> +			pwm1_pins: pwm at 1 {
> +				pins {
> +					pinmux = <STM32F429_PA8_FUNC_TIM1_CH1>,
> +						 <STM32F429_PB13_FUNC_TIM1_CH1N>,
> +						 <STM32F429_PB12_FUNC_TIM1_BKIN>;
> +				};
> +			};
> +
> +			pwm3_pins: pwm at 3 {
> +				pins {
> +					pinmux = <STM32F429_PB4_FUNC_TIM3_CH1>,
> +						 <STM32F429_PB5_FUNC_TIM3_CH2>;
> +				};
> +			};
>  		};
>  
>  		rcc: rcc at 40023810 {
> @@ -426,6 +441,322 @@
>  			interrupts = <80>;
>  			clocks = <&rcc 0 38>;
>  		};
> +
> +		gptimer1: gptimer1 at 40010000 {

timer at xxxxxxx

Node names should be generic and not numbered.

I suggest that this isn't actually a timer either.  Is contains a
timer (and a PWM), but in it's completeness it is not a timer per
say.

> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40010000 0x400>;
> +			clocks = <&rcc 0 160>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			pwm1 at 0 {
> +				compatible = "st,stm32-pwm";
> +				st,pwm-num-chan = <4>;
> +				st,breakinput;
> +				st,complementary;
> +				status = "disabled";
> +			};
> +
> +			timer1 at 0 {
> +				compatible = "st,stm32-timer-trigger";
> +				interrupts = <27>;
> +				st,input-triggers-names = TIM5_TRGO,
> +							  TIM2_TRGO,
> +							  TIM4_TRGO,
> +							  TIM3_TRGO;

I'm still dubious with matching by strings.

I'll take a look at the C code to see what the alternatives could be.

> +				st,output-triggers-names = TIM1_TRGO,
> +							   TIM1_CH1,
> +							   TIM1_CH2,
> +							   TIM1_CH3,
> +							   TIM1_CH4;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer2: gptimer2 at 40000000 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40000000 0x400>;
> +			clocks = <&rcc 0 128>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			pwm2 at 0 {
> +				compatible = "st,stm32-pwm";
> +				st,pwm-num-chan = <4>;
> +				st,32bits-counter;
> +				status = "disabled";
> +			};
> +
> +			timer2 at 0 {
> +				compatible = "st,stm32-timer-trigger";
> +				interrupts = <28>;
> +				st,input-triggers-names = TIM1_TRGO,
> +							  TIM8_TRGO,
> +							  TIM3_TRGO,
> +							  TIM4_TRGO;
> +				st,output-triggers-names = TIM2_TRGO,
> +							   TIM2_CH1,
> +							   TIM2_CH2,
> +							   TIM2_CH3,
> +							   TIM2_CH4;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer3: gptimer3 at 40000400 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40000400 0x400>;
> +			clocks = <&rcc 0 129>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			pwm3 at 0 {
> +				compatible = "st,stm32-pwm";
> +				st,pwm-num-chan = <4>;
> +				status = "disabled";
> +			};
> +
> +			timer3 at 0 {
> +				compatible = "st,stm32-timer-trigger";
> +				interrupts = <29>;
> +				st,input-triggers-names = TIM1_TRGO,
> +							  TIM8_TRGO,
> +							  TIM5_TRGO,
> +							  TIM4_TRGO;
> +				st,output-triggers-names = TIM3_TRGO,
> +							   TIM3_CH1,
> +							   TIM3_CH2,
> +							   TIM3_CH3,
> +							   TIM3_CH4;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer4: gptimer4 at 40000800 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40000800 0x400>;
> +			clocks = <&rcc 0 130>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			pwm4 at 0 {
> +				compatible = "st,stm32-pwm";
> +				st,pwm-num-chan = <4>;
> +				status = "disabled";
> +			};
> +
> +			timer4 at 0 {
> +				compatible = "st,stm32-timer-trigger";
> +				interrupts = <30>;
> +				st,input-triggers-names = TIM1_TRGO,
> +							  TIM2_TRGO,
> +							  TIM3_TRGO,
> +							  TIM8_TRGO;
> +				st,output-triggers-names = TIM4_TRGO,
> +							   TIM4_CH1,
> +							   TIM4_CH2,
> +							   TIM4_CH3,
> +							   TIM4_CH4;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer5: gptimer5 at 40000C00 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40000C00 0x400>;
> +			clocks = <&rcc 0 131>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			pwm5 at 0 {
> +				compatible = "st,stm32-pwm";
> +				st,pwm-num-chan = <4>;
> +				st,32bits-counter;
> +				status = "disabled";
> +			};
> +
> +			timer5 at 0 {
> +				compatible = "st,stm32-timer-trigger";
> +				interrupts = <50>;
> +				st,input-triggers-names = TIM2_TRGO,
> +							  TIM3_TRGO,
> +							  TIM4_TRGO,
> +							  TIM8_TRGO;
> +				st,output-triggers-names = TIM5_TRGO,
> +							   TIM5_CH1,
> +							   TIM5_CH2,
> +							   TIM5_CH3,
> +							   TIM5_CH4;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer6: gptimer6 at 40001000 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40001000 0x400>;
> +			clocks = <&rcc 0 132>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			timer6 at 0 {
> +				compatible = "st,stm32-timer-trigger";
> +				interrupts = <54>;
> +				st,output-triggers-names = TIM6_TRGO;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer7: gptimer7 at 40001400 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40001400 0x400>;
> +			clocks = <&rcc 0 133>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			timer7 at 0 {
> +				compatible = "st,stm32-timer-trigger";
> +				interrupts = <55>;
> +				st,output-triggers-names = TIM7_TRGO;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer8: gptimer8 at 40010400 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40010400 0x400>;
> +			clocks = <&rcc 0 161>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			pwm8 at 0 {
> +				compatible = "st,stm32-pwm";
> +				st,pwm-num-chan = <4>;
> +				st,complementary;
> +				st,breakinput;
> +				status = "disabled";
> +			};
> +
> +			timer8 at 0 {
> +				compatible = "st,stm32-timer-trigger";
> +				interrupts = <46>;
> +				st,input-triggers-names = TIM1_TRGO,
> +							  TIM2_TRGO,
> +							  TIM4_TRGO,
> +							  TIM5_TRGO;
> +				st,output-triggers-names = TIM8_TRGO,
> +							   TIM8_CH1,
> +							   TIM8_CH2,
> +							   TIM8_CH3,
> +							   TIM8_CH4;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer9: gptimer9 at 40014000 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40014000 0x400>;
> +			clocks = <&rcc 0 176>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			pwm9 at 0 {
> +				compatible = "st,stm32-pwm";
> +				st,pwm-num-chan = <2>;
> +				status = "disabled";
> +			};
> +
> +			timer9 at 0 {
> +				compatible = "st,stm32-timer-trigger";
> +				interrupts = <24>;
> +				st,input-triggers-names = TIM2_TRGO,
> +							  TIM3_TRGO;
> +				st,output-triggers-names = TIM9_TRGO,
> +							   TIM9_CH1,
> +							   TIM9_CH2;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer10: gptimer10 at 40014400 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40014400 0x400>;
> +			clocks = <&rcc 0 177>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			pwm10 at 0 {
> +				compatible = "st,stm32-pwm";
> +				st,pwm-num-chan = <1>;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer11: gptimer11 at 40014800 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40014800 0x400>;
> +			clocks = <&rcc 0 178>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			pwm11 at 0 {
> +				compatible = "st,stm32-pwm";
> +				st,pwm-num-chan = <1>;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer12: gptimer12 at 40001800 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40001800 0x400>;
> +			clocks = <&rcc 0 134>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			pwm12 at 0 {
> +				compatible = "st,stm32-pwm";
> +				st,pwm-num-chan = <2>;
> +				status = "disabled";
> +			};
> +
> +			timer12 at 0 {
> +				compatible = "st,stm32-timer-trigger";
> +				interrupts = <43>;
> +				st,input-triggers-names = TIM4_TRGO,
> +							  TIM5_TRGO;
> +				st,output-triggers-names = TIM12_TRGO,
> +							   TIM12_CH1,
> +							   TIM12_CH2;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer13: gptimer13 at 40001C00 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40001C00 0x400>;
> +			clocks = <&rcc 0 135>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			pwm13 at 0 {
> +				compatible = "st,stm32-pwm";
> +				st,pwm-num-chan = <1>;
> +				status = "disabled";
> +			};
> +		};
> +
> +		gptimer14: gptimer14 at 40002000 {
> +			compatible = "st,stm32-gptimer";
> +			reg = <0x40002000 0x400>;
> +			clocks = <&rcc 0 136>;
> +			clock-names = "clk_int";
> +			status = "disabled";
> +
> +			pwm14 at 0 {
> +				compatible = "st,stm32-pwm";
> +				st,pwm-num-chan = <1>;
> +				status = "disabled";
> +			};
> +		};
>  	};
>  };
>  
> diff --git a/arch/arm/boot/dts/stm32f469-disco.dts b/arch/arm/boot/dts/stm32f469-disco.dts
> index 8a163d7..df4ca7e 100644
> --- a/arch/arm/boot/dts/stm32f469-disco.dts
> +++ b/arch/arm/boot/dts/stm32f469-disco.dts
> @@ -81,3 +81,31 @@
>  &usart3 {
>  	status = "okay";
>  };
> +
> +&gptimer1 {
> +	status = "okay";
> +
> +	pwm1 at 0 {
> +		pinctrl-0	= <&pwm1_pins>;
> +		pinctrl-names	= "default";
> +		status = "okay";
> +	};
> +
> +	timer1 at 0 {
> +		status = "okay";
> +	};
> +};

This is a much *better* format than before.

I still don't like the '&' syntax though.

> +&gptimer3 {
> +	status = "okay";
> +
> +	pwm3 at 0 {
> +		pinctrl-0	= <&pwm3_pins>;
> +		pinctrl-names	= "default";
> +		status = "okay";
> +	};
> +
> +	timer3 at 0 {
> +		status = "okay";
> +	};
> +};

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply

* [PATCH 06/12] usb: dwc3: omap: Replace the extcon API
From: Chanwoo Choi @ 2016-12-02 13:20 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <87fum6vh1p.fsf@linux.intel.com>

Hi Felipe,

2016-12-02 18:03 GMT+09:00 Felipe Balbi <balbi@kernel.org>:
>
> Hi,
>
> Chanwoo Choi <cw00.choi@samsung.com> writes:
>> Hi Felipe,
>>
>> On 2016? 11? 30? 19:36, Felipe Balbi wrote:
>>>
>>> Hi,
>>>
>>> Chanwoo Choi <cw00.choi@samsung.com> writes:
>>>> This patch uses the resource-managed extcon API for extcon_register_notifier()
>>>> and replaces the deprecated extcon API as following:
>>>> - extcon_get_cable_state_() -> extcon_get_state()
>>>>
>>>> Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
>>>
>>> Acked-by: Felipe Balbi <felipe.balbi@linux.intel.com>
>>>
>>
>> Thanks for your review.
>>
>> Each patch has no any dependency among patches.
>> So, If possible, could you pick the patch6/8/9/10/11/12 on your tree?
>
> my tree is closed for v4.10, I can pick it up for v4.11

Thanks for your pickup to 4.11.

-- 
Best Regards,
Chanwoo Choi

^ permalink raw reply

* [PATCH 3/3] ARM: da850: fix da850_set_pll0rate()
From: Bartosz Golaszewski @ 2016-12-02 13:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4b1d65f7-d9a6-6d4e-00f5-2835b728661c@ti.com>

2016-12-02 12:20 GMT+01:00 Sekhar Nori <nsekhar@ti.com>:
> On Thursday 01 December 2016 10:45 PM, Bartosz Golaszewski wrote:
>> This function is broken - its second argument is an index to the freq
>> table, not the requested clock rate in Hz. It leads to an oops when
>> called from clk_set_rate() since this argument isn't bounds checked
>> either.
>>
>> Fix it by iterating over the array of supported frequencies and
>> selecting a one that matches or returning -EINVAL for unsupported
>> rates.
>>
>> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>
> When this function was written, it was written for speed. The only user
> of setting pll0 rate is drivers/cpufreq/davinci-cpufreq.c (not sure how
> you were trying to set pll0 rate). And that driver directly passes the
> table index to the set_rate() function.
>

Hi Sekhar, thanks for the hints.

The origin of this series is the default pll0 frequency set by
upstream u-boot which caused FIFO underflows in LCDC even with the
pixel clock well below 37.5 MHz. I had already sent a patch to the
u-boot mailing list, but thought I'd try setting the clock from within
tilcdc code. This is when I stumbled upon this issue.

I'll send a v2 of this series.

Thanks,
Bartosz Golaszewski

^ permalink raw reply

* [RESEND PATCH] pinctrl: mt8173: set GPIO16 to usb iddig mode
From: Linus Walleij @ 2016-12-02 12:40 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480472491-4644-1-git-send-email-chunfeng.yun@mediatek.com>

On Wed, Nov 30, 2016 at 3:21 AM, Chunfeng Yun <chunfeng.yun@mediatek.com> wrote:

> the default mode of GPIO16 pin is gpio, when set EINT16 to
> IRQ_TYPE_LEVEL_HIGH, no interrupt is triggered, it can be
> fixed when set its default mode as usb iddig.
>
> Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>

Patch applied with Hongzhou's ACK!

Yours,
Linus Walleij

^ permalink raw reply

* [PATCH] ARM/ARM64: defconfig: drop GPIO_SYSFS on multiplatforms
From: Linus Walleij @ 2016-12-02 12:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <5151997.6RlLpvHqsO@wuerfel>

On Wed, Nov 30, 2016 at 11:04 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Thursday, November 24, 2016 3:57:52 PM CET Linus Walleij wrote:
>> The sysfs ABI to GPIO is marked obsolete and should not be
>> encouraged. Users should be encouraged to switch to using the
>> character device.
(...)
>>  arch/arm/configs/multi_v5_defconfig | 1 -
>>  arch/arm/configs/multi_v7_defconfig | 1 -
>>  arch/arm64/configs/defconfig        | 1 -
>
> Hmm, while this is a trivial change, we normally put the defconfig
> changes for arm and arm64 into two separate next/* branches.
>
> I've split the patch up accordingly and slightly modified the
> changelog text to match.

OK thanks a lot Arnd, I was a bit uncertain about that.

Yours,
Linus Walleij

^ permalink raw reply

* [resend v2: PATCH 1/2] dt-bindings: Document the hi3660 reset bindings
From: Arnd Bergmann @ 2016-12-02 12:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <e15e76e2-b32d-a4d0-eb8b-850626a3946a@linaro.org>

On Friday, December 2, 2016 8:21:33 AM CET zhangfei wrote:
> Hi, Arnd
> 
> On 2016?12?01? 20:05, Arnd Bergmann wrote:
> > On Thursday, December 1, 2016 8:48:40 AM CET Zhangfei Gao wrote:
> >> +               hisi,reset-bits = <0x20 0x8             /* 0: i2c0 */
> >> +                                  0x20 0x10            /* 1: i2c1 */
> >> +                                  0x20 0x20            /* 2: i2c2 */
> >> +                                  0x20 0x8000000>;     /* 3: i2c6 */
> >> +       };
> >> +
> >> +Specifying reset lines connected to IP modules
> >> +==============================================
> >> +example:
> >> +
> >> +        i2c0: i2c at ..... {
> >> +                ...
> >> +               resets = <&iomcu_rst 0>;
> >> +                ...
> >> +        };
> > I don't really like this approach, since now the information is
> > in two places. Why not put the data into the reset specifier
> > directly when it is used?
> Any example, still not understand.
> They are consumer and provider.

I mean in the i2c node, have

	i2c0: i2c at ..... {
		...
		resets = <&iomcu_rst 0x20 0x8>;
		...
	}

> > Also the format seems a little too close to the actual register
> > layout and could be a little more abstract, using bit numbers instead
> > of a bitmask and register numbers instead of offsets.
> We use bit numbers first.
> But in the developing process, we found several bits may be required for 
> one driver.
> And they may not be continuous as the bits may already be occupied.
> Directly using offset, we can set several bits together for simple, to 
> give more flexibility.
> So after discussion, we directly use offset.

Can you give an example for why this is needed? Is this different
from a device that has multiple reset lines?

	Arnd

^ permalink raw reply

* [PATCH RESEND 2/2] gpio: axp209: add pinctrl support
From: Linus Walleij @ 2016-12-02 12:30 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <f46c89f2-478b-93b8-5a66-12d1307d4514@free-electrons.com>

On Tue, Nov 29, 2016 at 11:13 PM, Quentin Schulz
<quentin.schulz@free-electrons.com> wrote:

> So basically:
>
>  - first patch for adding pinctrl to the existing driver
>  - second patch for moving the driver and binding from gpio to pinctrl
> subsystem
>  - third patch for both removing Kconfig entry and Makefile rule from
> gpio subsystem, and adding a Kconfig entry and a Makefile rule in
> pinctrl subsystem
>
> Is that what you want?

No.

Make the patch moving it to pinctrl first. This will be the same as
the patch augmenting Kcongfig and Makefile or it will not compile.

Then a second patch to add the pinctrl features.

Yours,
Linus Walleij

^ permalink raw reply

* [PATCH 1/2] Add crypto driver support for some MediaTek chips
From: Ryder Lee @ 2016-12-02 12:11 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161202081836.GA20128@Red>

Hello,

On Fri, 2016-12-02 at 09:18 +0100, Corentin Labbe wrote:
> Hello
> 
> I have some minor comment inline
> 
> On Fri, Dec 02, 2016 at 11:26:44AM +0800, Ryder Lee wrote:
> > This adds support for the MediaTek hardware accelerator on
> > mt7623/mt2701/mt8521p SoC.
> > 
> > This driver currently implement:
> > - SHA1 and SHA2 family(HMAC) hash alogrithms.
> > - AES block cipher in CBC/ECB mode with 128/196/256 bits keys.
> 
> I see also a PRNG but is seems not really used.

Yes, PRNG is not implemented yet, i will remove it temporarily.

> > 
> > Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
> > ---
> >  drivers/crypto/Kconfig                 |   17 +
> >  drivers/crypto/Makefile                |    1 +
> >  drivers/crypto/mediatek/Makefile       |    2 +
> >  drivers/crypto/mediatek/mtk-aes.c      |  734 +++++++++++++++++
> >  drivers/crypto/mediatek/mtk-platform.c |  575 +++++++++++++
> >  drivers/crypto/mediatek/mtk-platform.h |  230 ++++++
> >  drivers/crypto/mediatek/mtk-regs.h     |  194 +++++
> >  drivers/crypto/mediatek/mtk-sha.c      | 1384
++++++++++++++++++++++++++++++++
> >  8 files changed, 3137 insertions(+)
> >  create mode 100644 drivers/crypto/mediatek/Makefile
> >  create mode 100644 drivers/crypto/mediatek/mtk-aes.c
> >  create mode 100644 drivers/crypto/mediatek/mtk-platform.c
> >  create mode 100644 drivers/crypto/mediatek/mtk-platform.h
> >  create mode 100644 drivers/crypto/mediatek/mtk-regs.h
> >  create mode 100644 drivers/crypto/mediatek/mtk-sha.c
> > 
> > diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
> > index 4d2b81f..5d9c803 100644
> > --- a/drivers/crypto/Kconfig
> > +++ b/drivers/crypto/Kconfig
> > @@ -553,6 +553,23 @@ config CRYPTO_DEV_ROCKCHIP
> >       This driver interfaces with the hardware crypto accelerator.
> >       Supporting cbc/ecb chainmode, and aes/des/des3_ede cipher
mode.
> >  
> > +config CRYPTO_DEV_MEDIATEK
> > +   tristate "MediaTek's Cryptographic Engine driver"
> > +   depends on ARM && ARCH_MEDIATEK
> > +   select NEON
> > +   select KERNEL_MODE_NEON
> > +   select ARM_CRYPTO
> > +   select CRYPTO_AES
> > +   select CRYPTO_BLKCIPHER
> > +   select CRYPTO_SHA1_ARM_NEON
> > +   select CRYPTO_SHA256_ARM
> > +   select CRYPTO_SHA512_ARM
> > +   select CRYPTO_HMAC
> 
> Why do you select accelerated algos ?
> Adding COMPILE_TEST could be helpfull also.

Our Hardware has complex procedure on calculate HMAC, and it get a bad
performance.... So i decide to use ARM NEON instruction as fallback to
speedup it.
I will add COMPILE_TEST.

> [...]
> > +
> > +#include <linux/dma-mapping.h>
> > +#include <linux/scatterlist.h>
> > +#include <crypto/scatterwalk.h>
> > +#include <crypto/algapi.h>
> > +#include <crypto/aes.h>
> > +#include "mtk-platform.h"
> > +#include "mtk-regs.h"
> > +
> 
> Sort headers in alphabetical order
> 
> [...]
> > +
> > +   mtk_aes_unregister_algs();
> > +   mtk_aes_record_free(cryp);
> > +}
> > +EXPORT_SYMBOL(mtk_cipher_alg_release);
> 
> Why not EXPORT_SYMBOL_GPL ?
> Furthermore do you really need it to be exported ?

My mistake. I will remove it.

> [...]
> > +
> > +#include <linux/init.h>
> > +#include <linux/module.h>
> > +#include <linux/kernel.h>
> > +#include <linux/mfd/syscon.h>
> > +#include <linux/pm_runtime.h>
> > +#include <linux/clk.h>
> > +#include <linux/platform_device.h>
> > +#include "mtk-platform.h"
> > +#include "mtk-regs.h"
> > +
> 
> Sort headers in alphabetical order
> 
> [...]
> > +
> > +static void mtk_prng_reseed(struct mtk_cryp *cryp)
> > +{
> > +   /* 8 words to seed the PRNG to provide IVs */
> > +   void __iomem *base = cryp->base;
> > +   const u32 prng_key[8] = {0x48c24cfd, 0x6c07f742,
> > +                           0xaee75681, 0x0f27c239,
> > +                           0x79947198, 0xe2991275,
> > +                           0x21ac3c7c, 0xd008c4b4};
> 
> Why do you seed with thoses constant ?
> 
> [...]
> > +
> > +static int mtk_accelerator_init(struct mtk_cryp *cryp)
> > +{
> > +   int i, err;
> > +
> > +   /* Initialize advanced interrupt controller(AIC) */
> > +   for (i = 0; i < 5; i++) {
> 
> I see this 5 for interrupt away, so perhaps a define could be used
> 
> [...]
> 
> here 
> 
> > +   for (i = 0; i < 5; i++) {
> > +           cryp->irq[i] = platform_get_irq(pdev, i);
> > +           if (cryp->irq[i] < 0) {
> > +                   dev_err(cryp->dev, "no IRQ:%d resource info\n",
i);
> > +                   return -ENXIO;
> > +           }
> > +   }
> [...]

> > +#ifndef __MTK_PLATFORM_H_
> > +#define __MTK_PLATFORM_H_
> > +
> > +#include <linux/crypto.h>
> > +#include <crypto/internal/hash.h>
> > +#include <linux/interrupt.h>
> 
> Sort headers in alphabetical order
> 
> [...]
> > +#define MTK_DESC_FIRST             BIT(23)
> > +#define MTK_DESC_BUF_LEN(x)        ((x) & 0x1ffff)
> > +#define MTK_DESC_CT_LEN(x) (((x) & 0xff) << 24)
> > +
> > +#define WORD(x)                    ((x) >> 2)
> 
> dangerous and ambigous define

I will define a IRQ_NUM and modify ambiguous definition.

> [...]
> > +
> > +#include <linux/dma-mapping.h>
> > +#include <linux/scatterlist.h>
> > +#include <linux/crypto.h>
> > +#include <crypto/scatterwalk.h>
> > +#include <crypto/algapi.h>
> > +#include <crypto/sha.h>
> > +#include <crypto/internal/hash.h>
> 
> Sort headers in alphabetical order
> [...]
> Generally more function comment could be helpfull.

I will sort all header and add more function comment.
Thanks for your review.

> Regards

^ permalink raw reply

* [RFC PATCH] PCI: designware: add host_init() error handling
From: Srinivas Kandagatla @ 2016-12-02 11:51 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <f2c8ebba-e51a-5f47-2d96-c75f7e086c0e@synopsys.com>



On 02/12/16 10:32, Joao Pinto wrote:
>
> Hi Srinivas,
>
> ?s 11:51 AM de 12/1/2016, Srinivas Kandagatla escreveu:
>>  drivers/pci/host/pci-dra7xx.c           |  4 +++-
>>  drivers/pci/host/pci-exynos.c           |  4 +++-
>>  drivers/pci/host/pci-imx6.c             |  4 +++-
>>  drivers/pci/host/pci-keystone.c         |  4 +++-
>>  drivers/pci/host/pci-layerscape.c       | 12 ++++++++----
>>  drivers/pci/host/pcie-armada8k.c        |  4 +++-
>>  drivers/pci/host/pcie-designware-plat.c |  4 +++-
>>  drivers/pci/host/pcie-designware.c      |  4 +++-
>>  drivers/pci/host/pcie-designware.h      |  2 +-
>>  drivers/pci/host/pcie-qcom.c            |  6 ++++--
>>  drivers/pci/host/pcie-spear13xx.c       |  4 +++-
>>  11 files changed, 37 insertions(+), 15 deletions(-)
>>
>
> Thanks for the patch!
>
> In my opinion your idea is good but only qcom driver is able to detect failure
> in the specific host init routine, all others have a 'return 0' even if
> something not well init. I would recomend that we take this issue a bit further
> and add the error checking to all specific pci drivers in order to make them as
> robust as qcom'.
I totally agree with you, I can give this a go in next version.

Thanks,
srini

>
> Thanks,
> Joao
>

^ 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