Devicetree
 help / color / mirror / Atom feed
* [PATCH 2/2] DTS: ARM: gta04: introduce legacy spi-cs-high to make display work again
From: H. Nikolaus Schaller @ 2019-07-08 14:46 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Mark Rutland, Benoît Cousson,
	Tony Lindgren
  Cc: letux-kernel, linux-spi, devicetree, linux-kernel, linux-omap,
	H. Nikolaus Schaller, stable
In-Reply-To: <cover.1562597164.git.hns@goldelico.com>

commit 6953c57ab172 "gpio: of: Handle SPI chipselect legacy bindings"

did introduce logic to centrally handle the legacy spi-cs-high property
in combination with cs-gpios. This assumes that the polarity
of the CS has to be inverted if spi-cs-high is missing, even
and especially if non-legacy GPIO_ACTIVE_HIGH is specified.

The DTS for the GTA04 was orginally introduced under the assumption
that there is no need for spi-cs-high if the gpio is defined with
proper polarity GPIO_ACTIVE_HIGH.

This was not a problem until gpiolib changed the interpretation of
GPIO_ACTIVE_HIGH and missing spi-cs-high.

The effect is that the missing spi-cs-high is now interpreted as CS being
low (despite GPIO_ACTIVE_HIGH) which turns off the SPI interface when the
panel is to be programmed by the panel driver.

Therefore, we have to add the redundant and legacy spi-cs-high property
to properly pass through the legacy handler.

Since this is nowhere documented in the bindings, we add some words of
WARNING.

Cc: stable@vger.kernel.org
Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
---
 Documentation/devicetree/bindings/spi/spi-bus.txt | 6 ++++++
 arch/arm/boot/dts/omap3-gta04.dtsi                | 1 +
 2 files changed, 7 insertions(+)

diff --git a/Documentation/devicetree/bindings/spi/spi-bus.txt b/Documentation/devicetree/bindings/spi/spi-bus.txt
index 1f6e86f787ef..982aa590058b 100644
--- a/Documentation/devicetree/bindings/spi/spi-bus.txt
+++ b/Documentation/devicetree/bindings/spi/spi-bus.txt
@@ -47,6 +47,10 @@ cs1 : native
 cs2 : &gpio1 1 0
 cs3 : &gpio1 2 0
 
+WARNING: the polarity of cs-gpios may be inverted in some cases compared
+to what is specified in the third parameter. In that case the spi-cs-high
+property must be defined for slave nodes.
+
 
 SPI slave nodes must be children of the SPI controller node.
 
@@ -69,6 +73,8 @@ All slave nodes can contain the following optional properties:
 		    phase (CPHA) mode.
 - spi-cs-high     - Empty property indicating device requires chip select
 		    active high.
+                   WARNING: this is especially required even if the cs-gpios
+		    define the gpio as GPIO_ACTIVE_HIGH
 - spi-3wire       - Empty property indicating device requires 3-wire mode.
 - spi-lsb-first   - Empty property indicating device requires LSB first mode.
 - spi-tx-bus-width - The bus width (number of data wires) that is used for MOSI.
diff --git a/arch/arm/boot/dts/omap3-gta04.dtsi b/arch/arm/boot/dts/omap3-gta04.dtsi
index 9a9a29fe88ec..47bab8e1040e 100644
--- a/arch/arm/boot/dts/omap3-gta04.dtsi
+++ b/arch/arm/boot/dts/omap3-gta04.dtsi
@@ -124,6 +124,7 @@
 			spi-max-frequency = <100000>;
 			spi-cpol;
 			spi-cpha;
+			spi-cs-high;
 
 			backlight= <&backlight>;
 			label = "lcd";
-- 
2.19.1

^ permalink raw reply related

* [PATCH v2 0/2] Add DRM ILI9341 parallel RGB panel driver
From: Josef Lusticky @ 2019-07-08 14:56 UTC (permalink / raw)
  To: sam, robh, dri-devel, devicetree; +Cc: airlied, thierry.reding, Josef Lusticky
In-Reply-To: <20190304125033.28841-1-josef@lusticky.cz>

Hi,
This is the v2 of the patch-set which adds support for
Ilitek ILI9341 parallel RGB panels.

The ILI9341 chip supports both parallel RGB input mode and SPI input mode.
This driver adds support for the parallel RGB input mode.

Changes since v1:
* Device-tree bindings in one file
* D/C GPIO pin is optional
* mipi_dbi_* functions used to initialize the display
* entry in MAINTAINERS sorted alphabetically
* Makefile, Kconfig: DRM_PANEL_ILITEK_IL9341 renamed to DRM_PANEL_ILITEK_ILI9341
* Kconfig: depend on BACKLIGHT_CLASS_DEVICE
* Kconfig: select TINYDRM_MIPI_DBI
* order of include files changed
* drm_mode_duplicate checked for failure

Thank you Rob Herring and Sam Ravnborg for comments.

Josef Lusticky (2):
  dt-bindings: panel: Add parallel RGB mode for Ilitek ILI9341 panels
  drm/panel: Add Ilitek ILI9341 parallel RGB panel driver

 .../bindings/display/ilitek,ili9341.txt       |  67 +++-
 MAINTAINERS                                   |   6 +
 drivers/gpu/drm/panel/Kconfig                 |   9 +
 drivers/gpu/drm/panel/Makefile                |   1 +
 drivers/gpu/drm/panel/panel-ilitek-ili9341.c  | 291 ++++++++++++++++++
 5 files changed, 363 insertions(+), 11 deletions(-)
 create mode 100644 drivers/gpu/drm/panel/panel-ilitek-ili9341.c

-- 
2.20.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply

* [PATCH v2 1/2] dt-bindings: panel: Add parallel RGB mode for Ilitek ILI9341 panels
From: Josef Lusticky @ 2019-07-08 14:56 UTC (permalink / raw)
  To: sam, robh, dri-devel, devicetree; +Cc: airlied, thierry.reding, Josef Lusticky
In-Reply-To: <20190708145618.26031-1-josef@lusticky.cz>

ILI9341 supports both SPI input mode and parallel RGB input mode.
This commit adds parallel RGB input mode bindings.

Signed-off-by: Josef Lusticky <josef@lusticky.cz>
---
 .../bindings/display/ilitek,ili9341.txt       | 67 ++++++++++++++++---
 1 file changed, 56 insertions(+), 11 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/ilitek,ili9341.txt b/Documentation/devicetree/bindings/display/ilitek,ili9341.txt
index 169b32e4ee4e..629f38a1d0cd 100644
--- a/Documentation/devicetree/bindings/display/ilitek,ili9341.txt
+++ b/Documentation/devicetree/bindings/display/ilitek,ili9341.txt
@@ -1,27 +1,72 @@
 Ilitek ILI9341 display panels
 
-This binding is for display panels using an Ilitek ILI9341 controller in SPI
-mode.
+This binding is for display panels using an Ilitek ILI9341 controller.
+The display panels are supported in the following graphical input modes:
+- SPI input mode
+	MIPI-DBI Type 3 Option 1 or Option 3 is used to transfer
+	commands and graphical data
+- parallel RGB input mode
+	MIPI-DBI Type 3 Option 1 or Option 3 is used for commands
+	MIPI-DPI 18-bit parallel RGB connection is used to transfer
+	graphical data
 
-Required properties:
-- compatible:	"adafruit,yx240qv29", "ilitek,ili9341"
-- dc-gpios:	D/C pin
-- reset-gpios:	Reset pin
+
+SPI input mode:
 
 The node for this driver must be a child node of a SPI controller, hence
-all mandatory properties described in ../spi/spi-bus.txt must be specified.
+all mandatory properties described in spi/spi-bus.txt must be specified.
+
+Required properties in SPI input mode:
+- compatible:   "adafruit,yx240qv29", "ilitek,ili9341"
+- backlight:    phandle of the backlight device attached to the panel
+
+Optional properties in SPI input mode:
+- rotation:     panel rotation in degrees counter clockwise (0,90,180,270)
+- dc-gpios:     GPIO spec for the D/C pin, see gpio/gpio.txt
+- reset-gpios:  GPIO spec for the reset pin, see gpio/gpio.txt
+
+
+Parallel RGB input mode:
+
+The node for this driver must be a child node of a SPI controller, hence
+all mandatory properties described in spi/spi-bus.txt must be specified.
+
+Required properties in parallel RGB input mode:
+- compatible:   "displaytech,dt024ctft", "ilitek,ili9341"
+- backlight:    phandle of the backlight device attached to the panel
+
+Optional properties in parallel RGB input mode:
+- dc-gpios:     GPIO spec for the D/C pin, see gpio/gpio.txt
+- reset-gpios:  GPIO spec for the reset pin, see gpio/gpio.txt
 
-Optional properties:
-- rotation:	panel rotation in degrees counter clockwise (0,90,180,270)
-- backlight:	phandle of the backlight device attached to the panel
+In parallel RGB input mode,
+the device node can contain one 'port' child node with one child
+'endpoint' node, according to the bindings defined in
+media/video-interfaces.txt. This node should describe panel's video bus.
 
-Example:
+
+Example in SPI input mode:
 	display@0{
 		compatible = "adafruit,yx240qv29", "ilitek,ili9341";
 		reg = <0>;
 		spi-max-frequency = <32000000>;
 		dc-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
 		reset-gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>;
+		backlight = <&backlight>;
 		rotation = <270>;
+	};
+
+Example in parallel RGB input mode:
+	panel@{
+		compatible = "displaytech,dt024ctft", "ilitek,ili9341";
+		reg = <0>;
+		spi-max-frequency = <32000000>;
+		dc-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
+		reset-gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>;
 		backlight = <&backlight>;
+		port {
+			panel_in: endpoint {
+				remote-endpoint = <&display_out>;
+			};
+		};
 	};
-- 
2.20.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related

* [PATCH v2 2/2] drm/panel: Add Ilitek ILI9341 parallel RGB panel driver
From: Josef Lusticky @ 2019-07-08 14:56 UTC (permalink / raw)
  To: sam, robh, dri-devel, devicetree; +Cc: airlied, thierry.reding, Josef Lusticky
In-Reply-To: <20190708145618.26031-1-josef@lusticky.cz>

Add driver for Ilitek ILI9341 panels in parallel RGB mode

Signed-off-by: Josef Lusticky <josef@lusticky.cz>
---
 MAINTAINERS                                  |   6 +
 drivers/gpu/drm/panel/Kconfig                |   9 +
 drivers/gpu/drm/panel/Makefile               |   1 +
 drivers/gpu/drm/panel/panel-ilitek-ili9341.c | 291 +++++++++++++++++++
 4 files changed, 307 insertions(+)
 create mode 100644 drivers/gpu/drm/panel/panel-ilitek-ili9341.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 0a76716874bd..a35bf56cc018 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5028,6 +5028,12 @@ S:	Maintained
 F:	drivers/gpu/drm/tinydrm/hx8357d.c
 F:	Documentation/devicetree/bindings/display/himax,hx8357d.txt
 
+DRM DRIVER FOR ILITEK ILI9341 PANELS
+M:	Josef Lusticky <josef@lusticky.cz>
+S:	Maintained
+F:	drivers/gpu/drm/panel/panel-ilitek-ili9341.c
+F:	Documentation/devicetree/bindings/display/panel/ilitek,ili9341.txt
+
 DRM DRIVER FOR INTEL I810 VIDEO CARDS
 S:	Orphan / Obsolete
 F:	drivers/gpu/drm/i810/
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index eaecd40cc32e..34a5b262f924 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -56,6 +56,15 @@ config DRM_PANEL_ILITEK_IL9322
 	  Say Y here if you want to enable support for Ilitek IL9322
 	  QVGA (320x240) RGB, YUV and ITU-T BT.656 panels.
 
+config DRM_PANEL_ILITEK_ILI9341
+	tristate "Ilitek ILI9341 240x320 panels"
+	depends on OF && SPI
+	depends on BACKLIGHT_CLASS_DEVICE
+	select TINYDRM_MIPI_DBI
+	help
+	  Say Y here if you want to enable support for Ilitek ILI9341
+	  QVGA (240x320) RGB panel.
+
 config DRM_PANEL_ILITEK_ILI9881C
 	tristate "Ilitek ILI9881C-based panels"
 	depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 62dae45f8f74..ba4a303c1a66 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o
 obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
 obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += panel-feiyang-fy07024di26a30d.o
 obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o
+obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o
 obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o
 obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o
 obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o
diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9341.c b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c
new file mode 100644
index 000000000000..0c700b171025
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Ilitek ILI9341 drm_panel driver
+ * 240RGBx320 dots resolution TFT LCD display
+ *
+ * This driver supports the following panel configurations:
+ * - Command interface:
+ *     - MIPI-DBI Type 3 Option 1
+ *       (9-bit SPI with Data/Command bit  - IM[3:0] = 1101)
+ *     - MIPI-DBI Type 3 Option 3
+ *       (8-bit SPI with Data/Command GPIO - IM[3:0] = 1110)
+ * - Graphical data interface:
+ *     - MIPI-DPI 18-bit parallel RGB interface
+ *
+ * Copyright (C) 2019 Josef Lusticky <josef@lusticky.cz>
+ *
+ */
+
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/spi/spi.h>
+
+#include <video/mipi_display.h>
+
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
+#include <drm/tinydrm/mipi-dbi.h>
+
+/* ILI9341 extended register set (Vendor Command Set) */
+#define ILI9341_IFMODE         0xB0 // clock polarity
+#define ILI9341_IFCTL          0xF6 // interface conrol
+#define ILI9341_PGAMCTRL       0xE0 // positive gamma control
+#define ILI9341_NGAMCTRL       0xE1 // negative gamma control
+
+#define ILI9341_MADCTL_MV      BIT(5)
+#define ILI9341_MADCTL_MX      BIT(6)
+#define ILI9341_MADCTL_MY      BIT(7)
+
+/**
+ * struct ili9341_config - the display specific configuration
+ * @width_mm: physical panel width [mm]
+ * @height_mm: physical panel height [mm]
+ */
+struct ili9341_config {
+	u32 width_mm;
+	u32 height_mm;
+};
+
+struct ili9341 {
+	struct drm_panel panel;
+	struct mipi_dbi *mipi;
+	const struct ili9341_config *conf;
+};
+
+static inline struct ili9341 *panel_to_ili9341(struct drm_panel *panel)
+{
+	return container_of(panel, struct ili9341, panel);
+}
+
+static int ili9341_deinit(struct drm_panel *panel, struct ili9341 *ili)
+{
+	mipi_dbi_command(ili->mipi, MIPI_DCS_SET_DISPLAY_OFF);
+	mipi_dbi_command(ili->mipi, MIPI_DCS_ENTER_SLEEP_MODE);
+	msleep(5);
+	return 0;
+}
+
+static int ili9341_init(struct drm_panel *panel, struct ili9341 *ili)
+{
+	/* HW / SW Reset display and wait */
+	if (ili->mipi->reset)
+		mipi_dbi_hw_reset(ili->mipi);
+
+	mipi_dbi_command(ili->mipi, MIPI_DCS_SOFT_RESET);
+	msleep(120);
+
+	/* Polarity */
+	mipi_dbi_command(ili->mipi, ILI9341_IFMODE, 0xC0);
+
+	/* Interface control */
+	mipi_dbi_command(ili->mipi, ILI9341_IFCTL, 0x09, 0x01, 0x26);
+
+	/* Pixel format */
+	mipi_dbi_command(ili->mipi, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_18BIT << 4);
+
+	/* Gamma */
+	mipi_dbi_command(ili->mipi, MIPI_DCS_SET_GAMMA_CURVE, 0x01);
+	mipi_dbi_command(ili->mipi, ILI9341_PGAMCTRL,
+		0x0f, 0x31, 0x2b, 0x0c, 0x0e, 0x08, 0x4e, 0xf1,
+		0x37, 0x07, 0x10, 0x03, 0x0e, 0x09, 0x00);
+	mipi_dbi_command(ili->mipi, ILI9341_NGAMCTRL,
+		0x00, 0x0e, 0x14, 0x03, 0x11, 0x07, 0x31, 0xc1,
+		0x48, 0x08, 0x0f, 0x0c, 0x31, 0x36, 0x0f);
+
+	/* Rotation */
+	mipi_dbi_command(ili->mipi, MIPI_DCS_SET_ADDRESS_MODE, ILI9341_MADCTL_MX);
+
+	/* Exit sleep mode */
+	mipi_dbi_command(ili->mipi, MIPI_DCS_EXIT_SLEEP_MODE);
+	msleep(120);
+
+	mipi_dbi_command(ili->mipi, MIPI_DCS_SET_DISPLAY_ON);
+
+	return 0;
+}
+
+static int ili9341_unprepare(struct drm_panel *panel)
+{
+	struct ili9341 *ili = panel_to_ili9341(panel);
+
+	return ili9341_deinit(panel, ili);
+}
+
+static int ili9341_prepare(struct drm_panel *panel)
+{
+	struct ili9341 *ili = panel_to_ili9341(panel);
+	int ret;
+
+	ret = ili9341_init(panel, ili);
+	if (ret < 0)
+		ili9341_unprepare(panel);
+	return ret;
+}
+
+static int ili9341_enable(struct drm_panel *panel)
+{
+	struct ili9341 *ili = panel_to_ili9341(panel);
+
+	return backlight_enable(ili->mipi->backlight);
+}
+
+static int ili9341_disable(struct drm_panel *panel)
+{
+	struct ili9341 *ili = panel_to_ili9341(panel);
+
+	return backlight_disable(ili->mipi->backlight);
+}
+
+static const struct drm_display_mode prgb_240x320_mode = {
+	.clock = 6350,
+
+	.hdisplay = 240,
+	.hsync_start = 240 + 10,
+	.hsync_end = 240 + 10 + 10,
+	.htotal = 240 + 10 + 10 + 20,
+
+	.vdisplay = 320,
+	.vsync_start = 320 + 4,
+	.vsync_end = 320 + 4 + 2,
+	.vtotal = 320 + 4 + 2 + 2,
+
+	.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED
+};
+
+static int ili9341_get_modes(struct drm_panel *panel)
+{
+	struct drm_connector *connector = panel->connector;
+	struct ili9341 *ili = panel_to_ili9341(panel);
+	struct drm_display_mode *mode;
+
+	mode = drm_mode_duplicate(panel->drm, &prgb_240x320_mode);
+	if (!mode) {
+		DRM_DEV_ERROR(panel->drm->dev, "bad mode or failed to add mode\n");
+		return -ENOMEM;
+	}
+
+	drm_mode_set_name(mode);
+
+	mode->width_mm = ili->conf->width_mm;
+	mode->height_mm = ili->conf->height_mm;
+
+	connector->display_info.width_mm = mode->width_mm;
+	connector->display_info.height_mm = mode->height_mm;
+	connector->display_info.bus_flags |= DRM_BUS_FLAG_DE_HIGH |
+		DRM_BUS_FLAG_PIXDATA_POSEDGE | DRM_BUS_FLAG_SYNC_NEGEDGE;
+
+	drm_mode_probed_add(connector, mode);
+
+	return 1; /* Number of modes */
+}
+
+static const struct drm_panel_funcs ili9341_drm_funcs = {
+	.disable = ili9341_disable,
+	.unprepare = ili9341_unprepare,
+	.prepare = ili9341_prepare,
+	.enable = ili9341_enable,
+	.get_modes = ili9341_get_modes,
+};
+
+static int ili9341_probe(struct spi_device *spi)
+{
+	struct device *dev = &spi->dev;
+	struct ili9341 *ili;
+	struct mipi_dbi *mipi;
+	struct gpio_desc *dc_gpio;
+	int ret;
+
+	mipi = devm_kzalloc(dev, sizeof(*mipi), GFP_KERNEL);
+	if (!mipi)
+		return -ENOMEM;
+
+	ili = devm_kzalloc(dev, sizeof(*ili), GFP_KERNEL);
+	if (!ili)
+		return -ENOMEM;
+
+	ili->mipi = mipi;
+
+	spi_set_drvdata(spi, ili);
+
+	/*
+	 * Every new incarnation of this display must have a unique
+	 * data entry for the system in this driver.
+	 */
+	ili->conf = of_device_get_match_data(dev);
+	if (!ili->conf) {
+		DRM_DEV_ERROR(dev, "missing device configuration\n");
+		return -ENODEV;
+	}
+
+	ili->mipi->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+	if (IS_ERR(ili->mipi->reset)) {
+		DRM_DEV_ERROR(dev, "failed to get gpio 'reset'\n");
+		return PTR_ERR(ili->mipi->reset);
+	}
+
+	ili->mipi->backlight = devm_of_find_backlight(dev);
+	if (IS_ERR(ili->mipi->backlight)) {
+		DRM_DEV_ERROR(dev, "failed to get backlight\n");
+		return PTR_ERR(ili->mipi->backlight);
+	}
+
+	dc_gpio = devm_gpiod_get_optional(dev, "dc", GPIOD_OUT_LOW);
+	if (IS_ERR(dc_gpio)) {
+		DRM_DEV_ERROR(dev, "failed to get gpio 'dc'\n");
+		return PTR_ERR(dc_gpio);
+	}
+
+	ret = mipi_dbi_spi_init(spi, ili->mipi, dc_gpio);
+	if (ret) {
+		DRM_DEV_ERROR(dev, "MIPI-DBI SPI setup failed\n");
+		return ret;
+	}
+
+	drm_panel_init(&ili->panel);
+	ili->panel.dev = dev;
+	ili->panel.funcs = &ili9341_drm_funcs;
+
+	return drm_panel_add(&ili->panel);
+}
+
+static int ili9341_remove(struct spi_device *spi)
+{
+	struct ili9341 *ili = spi_get_drvdata(spi);
+
+	drm_panel_remove(&ili->panel);
+
+	ili9341_disable(&ili->panel);
+	ili9341_unprepare(&ili->panel);
+
+	return 0;
+}
+
+static const struct ili9341_config dt024ctft_data = {
+	.width_mm = 37,
+	.height_mm = 49,
+};
+
+static const struct of_device_id ili9341_of_match[] = {
+	{ .compatible = "displaytech,dt024ctft", .data = &dt024ctft_data },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ili9341_of_match);
+
+static struct spi_driver ili9341_driver = {
+	.probe = ili9341_probe,
+	.remove = ili9341_remove,
+	.driver = {
+		.name = "panel-ilitek-ili9341",
+		.of_match_table = ili9341_of_match,
+	},
+};
+module_spi_driver(ili9341_driver);
+
+MODULE_AUTHOR("Josef Lusticky <josef@lusticky.cz>");
+MODULE_DESCRIPTION("ILI9341 LCD panel driver");
+MODULE_LICENSE("GPL");
-- 
2.20.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related

* Re: [PATCH 5/8] iommu/arm-smmu-v3: Add second level of context descriptor table
From: Auger Eric @ 2019-07-08 15:13 UTC (permalink / raw)
  To: Jean-Philippe Brucker, will.deacon
  Cc: joro, robh+dt, mark.rutland, robin.murphy, jacob.jun.pan, iommu,
	devicetree, linux-kernel, linux-arm-kernel
In-Reply-To: <20190610184714.6786-6-jean-philippe.brucker@arm.com>

Hi Jean,

On 6/10/19 8:47 PM, Jean-Philippe Brucker wrote:
> The SMMU can support up to 20 bits of SSID. Add a second level of page
> tables to accommodate this. Devices that support more than 1024 SSIDs now
> have a table of 1024 L1 entries (8kB), pointing to tables of 1024 context
> descriptors (64kB), allocated on demand.
> 
> Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
> ---
>  drivers/iommu/arm-smmu-v3.c | 136 +++++++++++++++++++++++++++++++++---
>  1 file changed, 128 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
> index d90eb604b65d..326b71793336 100644
> --- a/drivers/iommu/arm-smmu-v3.c
> +++ b/drivers/iommu/arm-smmu-v3.c
> @@ -216,6 +216,8 @@
>  
>  #define STRTAB_STE_0_S1FMT		GENMASK_ULL(5, 4)
>  #define STRTAB_STE_0_S1FMT_LINEAR	0
> +#define STRTAB_STE_0_S1FMT_4K_L2	1
As you only use 64kB L2, I guess you can remove the 4K define?
> +#define STRTAB_STE_0_S1FMT_64K_L2	2
>  #define STRTAB_STE_0_S1CTXPTR_MASK	GENMASK_ULL(51, 6)
>  #define STRTAB_STE_0_S1CDMAX		GENMASK_ULL(63, 59)
>  
> @@ -255,6 +257,18 @@
>  
>  #define STRTAB_STE_3_S2TTB_MASK		GENMASK_ULL(51, 4)
>  
> +/*
> + * Linear: when less than 1024 SSIDs are supported
> + * 2lvl: at most 1024 L1 entrie,
entries
> + *      1024 lazy entries per table.
> + */
> +#define CTXDESC_SPLIT			10
> +#define CTXDESC_NUM_L2_ENTRIES		(1 << CTXDESC_SPLIT)
> +
> +#define CTXDESC_L1_DESC_DWORD		1
> +#define CTXDESC_L1_DESC_VALID		1
> +#define CTXDESC_L1_DESC_L2PTR_MASK	GENMASK_ULL(51, 12)
> +
>  /* Context descriptor (stage-1 only) */
>  #define CTXDESC_CD_DWORDS		8
>  #define CTXDESC_CD_0_TCR_T0SZ		GENMASK_ULL(5, 0)
> @@ -530,7 +544,10 @@ struct arm_smmu_ctx_desc {
>  struct arm_smmu_s1_cfg {
>  	u8				s1fmt;
>  	u8				s1cdmax;
> -	struct arm_smmu_cd_table	table;
> +	struct arm_smmu_cd_table	*tables;
> +	size_t				num_tables;
> +	__le64				*l1ptr;
> +	dma_addr_t			l1ptr_dma;
>  
>  	/* Context descriptor 0, when substreams are disabled or s1dss = 0b10 */
>  	struct arm_smmu_ctx_desc	cd;
> @@ -1118,12 +1135,51 @@ static void arm_smmu_free_cd_leaf_table(struct arm_smmu_device *smmu,
>  {
>  	size_t size = num_entries * (CTXDESC_CD_DWORDS << 3);
>  
> +	if (!table->ptr)
> +		return;
>  	dmam_free_coherent(smmu->dev, size, table->ptr, table->ptr_dma);
>  }
>  
> -static __le64 *arm_smmu_get_cd_ptr(struct arm_smmu_s1_cfg *cfg, u32 ssid)
> +static void arm_smmu_write_cd_l1_desc(__le64 *dst,
> +				      struct arm_smmu_cd_table *table)
>  {
> -	return cfg->table.ptr + ssid * CTXDESC_CD_DWORDS;
> +	u64 val = (table->ptr_dma & CTXDESC_L1_DESC_L2PTR_MASK) |
> +		  CTXDESC_L1_DESC_VALID;
> +
> +	*dst = cpu_to_le64(val);
> +}
> +
> +static __le64 *arm_smmu_get_cd_ptr(struct arm_smmu_domain *smmu_domain,
> +				   u32 ssid)> +{
> +	unsigned int idx;
> +	struct arm_smmu_cd_table *table;
> +	struct arm_smmu_device *smmu = smmu_domain->smmu;
> +	struct arm_smmu_s1_cfg *cfg = &smmu_domain->s1_cfg;
> +
> +	if (cfg->s1fmt == STRTAB_STE_0_S1FMT_LINEAR) {
> +		table = &cfg->tables[0];
> +		idx = ssid;
> +	} else {
> +		idx = ssid >> CTXDESC_SPLIT;
> +		if (idx >= cfg->num_tables)
> +			return NULL;
> +
> +		table = &cfg->tables[idx];
> +		if (!table->ptr) {
> +			__le64 *l1ptr = cfg->l1ptr + idx * CTXDESC_L1_DESC_DWORD;
> +
> +			if (arm_smmu_alloc_cd_leaf_table(smmu, table,
> +							 CTXDESC_NUM_L2_ENTRIES))
> +				return NULL;
> +
> +			arm_smmu_write_cd_l1_desc(l1ptr, table);
> +			/* An invalid L1 entry is allowed to be cached */
> +			arm_smmu_sync_cd(smmu_domain, ssid, false);
> +		}
> +		idx = ssid & (CTXDESC_NUM_L2_ENTRIES - 1);
> +	}
> +	return table->ptr + idx * CTXDESC_CD_DWORDS;
>  }
>  
>  static u64 arm_smmu_cpu_tcr_to_cd(u64 tcr)
> @@ -1149,7 +1205,7 @@ static int arm_smmu_write_ctx_desc(struct arm_smmu_domain *smmu_domain,
>  	u64 val;
>  	bool cd_live;
>  	struct arm_smmu_device *smmu = smmu_domain->smmu;
> -	__le64 *cdptr = arm_smmu_get_cd_ptr(&smmu_domain->s1_cfg, ssid);
> +	__le64 *cdptr = arm_smmu_get_cd_ptr(smmu_domain, ssid);
>  
>  	/*
>  	 * This function handles the following cases:
> @@ -1213,20 +1269,81 @@ static int arm_smmu_write_ctx_desc(struct arm_smmu_domain *smmu_domain,
>  static int arm_smmu_alloc_cd_tables(struct arm_smmu_domain *smmu_domain,
>  				    struct arm_smmu_master *master)
>  {
> +	int ret;
> +	size_t size = 0;
> +	size_t max_contexts, num_leaf_entries;
>  	struct arm_smmu_device *smmu = smmu_domain->smmu;
>  	struct arm_smmu_s1_cfg *cfg = &smmu_domain->s1_cfg;
>  
>  	cfg->s1fmt = STRTAB_STE_0_S1FMT_LINEAR;
>  	cfg->s1cdmax = master->ssid_bits;
> -	return arm_smmu_alloc_cd_leaf_table(smmu, &cfg->table, 1 << cfg->s1cdmax);
> +
> +	max_contexts = 1 << cfg->s1cdmax;
> +	if (!(smmu->features & ARM_SMMU_FEAT_2_LVL_CDTAB) ||
> +	    max_contexts <= CTXDESC_NUM_L2_ENTRIES) {
> +		cfg->s1fmt = STRTAB_STE_0_S1FMT_LINEAR;
> +		cfg->num_tables = 1;
> +		num_leaf_entries = max_contexts;
> +	} else {
> +		cfg->s1fmt = STRTAB_STE_0_S1FMT_64K_L2;
> +		/*
> +		 * SSID[S1CDmax-1:10] indexes 1st-level table, SSID[9:0] indexes
> +		 * 2nd-level
> +		 */
> +		cfg->num_tables = max_contexts / CTXDESC_NUM_L2_ENTRIES;
> +
> +		size = cfg->num_tables * (CTXDESC_L1_DESC_DWORD << 3);
> +		cfg->l1ptr = dmam_alloc_coherent(smmu->dev, size,
> +						 &cfg->l1ptr_dma,
> +						 GFP_KERNEL | __GFP_ZERO);
> +		if (!cfg->l1ptr) {
> +			dev_warn(smmu->dev, "failed to allocate L1 context table\n");
> +			return -ENOMEM;
> +		}
> +
> +		num_leaf_entries = CTXDESC_NUM_L2_ENTRIES;
> +	}
> +
> +	cfg->tables = devm_kzalloc(smmu->dev, sizeof(struct arm_smmu_cd_table) *
> +				   cfg->num_tables, GFP_KERNEL);
> +	if (!cfg->tables)
> +		return -ENOMEM;
goto err_free_l1
> +
> +	ret = arm_smmu_alloc_cd_leaf_table(smmu, &cfg->tables[0], num_leaf_entries);
don't you want to do that only in linear case. In 2-level mode, I
understand arm_smmu_get_cd_ptr() will do the job.

> +	if (ret)
> +		goto err_free_l1;
> +
> +	if (cfg->l1ptr)
> +		arm_smmu_write_cd_l1_desc(cfg->l1ptr, &cfg->tables[0]);
that stuff could be removed as well? By the way I can see that
arm_smmu_get_cd_ptr() does a arm_smmu_sync_cd after. wouldn't it be
needed here as well?
> +
> +	return 0;
> +
> +err_free_l1:
> +	if (cfg->l1ptr)
> +		dmam_free_coherent(smmu->dev, size, cfg->l1ptr, cfg->l1ptr_dma);
> +	devm_kfree(smmu->dev, cfg->tables);
> +	return ret;
>  }
>  
>  static void arm_smmu_free_cd_tables(struct arm_smmu_domain *smmu_domain)
>  {
> +	int i;
>  	struct arm_smmu_device *smmu = smmu_domain->smmu;
>  	struct arm_smmu_s1_cfg *cfg = &smmu_domain->s1_cfg;
> +	size_t num_leaf_entries = 1 << cfg->s1cdmax;
> +	struct arm_smmu_cd_table *table = cfg->tables;
> +
> +	if (cfg->l1ptr) {
> +		size_t size = cfg->num_tables * (CTXDESC_L1_DESC_DWORD << 3);
>  
> -	arm_smmu_free_cd_leaf_table(smmu, &cfg->table, 1 << cfg->s1cdmax);
> +		dmam_free_coherent(smmu->dev, size, cfg->l1ptr,
> +				   cfg->l1ptr_dma);
> +		num_leaf_entries = CTXDESC_NUM_L2_ENTRIES;
> +	}
> +
> +	for (i = 0; i < cfg->num_tables; i++, table++)
> +		arm_smmu_free_cd_leaf_table(smmu, table, num_leaf_entries);
> +	devm_kfree(smmu->dev, cfg->tables);
>  }
>  
>  /* Stream table manipulation functions */
> @@ -1346,6 +1463,9 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid,
>  	}
>  
>  	if (s1_cfg) {
> +		dma_addr_t ptr_dma = s1_cfg->l1ptr ? s1_cfg->l1ptr_dma :
> +			             s1_cfg->tables[0].ptr_dma;
> +
>  		BUG_ON(ste_live);
>  		dst[1] = cpu_to_le64(
>  			 FIELD_PREP(STRTAB_STE_1_S1DSS, STRTAB_STE_1_S1DSS_SSID0) |
> @@ -1358,7 +1478,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid,
>  		   !(smmu->features & ARM_SMMU_FEAT_STALL_FORCE))
>  			dst[1] |= cpu_to_le64(STRTAB_STE_1_S1STALLD);
>  
> -		val |= (s1_cfg->table.ptr_dma & STRTAB_STE_0_S1CTXPTR_MASK) |
> +		val |= (ptr_dma & STRTAB_STE_0_S1CTXPTR_MASK) |
>  			FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_S1_TRANS) |
>  			FIELD_PREP(STRTAB_STE_0_S1CDMAX, s1_cfg->s1cdmax) |
>  			FIELD_PREP(STRTAB_STE_0_S1FMT, s1_cfg->s1fmt);
> @@ -1815,7 +1935,7 @@ static void arm_smmu_domain_free(struct iommu_domain *domain)
>  	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
>  		struct arm_smmu_s1_cfg *cfg = &smmu_domain->s1_cfg;
>  
> -		if (cfg->table.ptr) {
> +		if (cfg->tables) {
>  			arm_smmu_free_cd_tables(smmu_domain);
>  			arm_smmu_bitmap_free(smmu->asid_map, cfg->cd.asid);
I don't get why the arm_smmu_bitmap_free is dependent on cfg->tables.

Thanks

Eric
>  		}
> 

^ permalink raw reply

* RE: [v4 1/6] dt-bindings: media: Document bindings for DW MIPI CSI-2 Host
From: Luis de Oliveira @ 2019-07-08 15:21 UTC (permalink / raw)
  To: Sakari Ailus, Luis Oliveira
  Cc: mchehab@kernel.org, davem@davemloft.net,
	gregkh@linuxfoundation.org, Jonathan.Cameron@huawei.com,
	robh@kernel.org, nicolas.ferre@microchip.com,
	paulmck@linux.ibm.com, mark.rutland@arm.com, kishon@ti.com,
	devicetree@vger.kernel.org, linux-media@vger.kernel.org,
	linux-kernel@vger.kernel.org, Joao.Pinto@synopsys.com
In-Reply-To: <20190628141326.swgl3kg4fj5pmlqx@valkosipuli.retiisi.org.uk>

Hi Sakari,

Thank you for your feedback.
I have my comments inline.

From: Sakari Ailus <sakari.ailus@iki.fi>
Date: Fri, Jun 28, 2019 at 15:13:26

> Hi Luis,
> 
> Thank you for the patchset.
> 
> On Tue, Jun 11, 2019 at 09:20:50PM +0200, Luis Oliveira wrote:
> > From: Luis Oliveira <lolivei@synopsys.com>
> > 
> > Add bindings for Synopsys DesignWare MIPI CSI-2 host.
> > 
> > Signed-off-by: Luis Oliveira <lolivei@synopsys.com>
> > ---
> > Changelog
> > v3-v4
> > - remove "plat" from the block name @rob @laurent
> > - remove "phy-names" when single-entry @rob
> > - remove "snps,output-type" -> went to the driver config @laurent
> > 
> >  .../devicetree/bindings/media/snps,dw-csi.txt      | 41 ++++++++++++++++++++++
> >  1 file changed, 41 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/media/snps,dw-csi.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/media/snps,dw-csi.txt b/Documentation/devicetree/bindings/media/snps,dw-csi.txt
> > new file mode 100644
> > index 0000000..613b7f9
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/media/snps,dw-csi.txt
> > @@ -0,0 +1,41 @@
> > +Synopsys DesignWare CSI-2 Host controller
> > +
> > +Description
> > +-----------
> > +
> > +This HW block is used to receive image coming from an MIPI CSI-2 compatible
> > +camera.
> > +
> > +Required properties:
> > +- compatible		: shall be "snps,dw-csi"
> > +- reg			: physical base address and size of the device memory
> > +			  mapped registers;
> > +- interrupts		: DW CSI-2 Host interrupts
> > +- phys			: List of one PHY specifier (as defined in
> > +			  Documentation/devicetree/bindings/phy/phy-bindings.txt).
> > +			  This PHY is a MIPI DPHY working in RX mode.
> > +- resets		: Reference to a reset controller (optional)
> > +
> > +The per-board settings:
> > + - port sub-node describing a single endpoint connected to the camera as
> > +   described in video-interfaces.txt[1].
> 
> Which endpoint properties in video-interfaces.txt are relevant for the
> hardware? Which values may they have?
> 

Currently I'm using only two properties "data-lanes" and "bus-width", but 
I have plans to add blanking info also.
I will add more info.

> > +
> > +Example:
> > +
> > +	csi2: csi2@3000 {
> > +		compatible = "snps,dw-csi";
> > +		#address-cells = <1>;
> > +		#size-cells = <0>;
> > +		reg = < 0x03000 0x7FF>;
> 
> reg = <0x03000 0x7FF>;

Yes, I've missed that.

> 
> > +		phys = <&mipi_dphy_rx>;
> > +		resets = <&dw_rst 1>;
> > +		interrupts = <2>;
> > +
> > +		port@0 {
> > +			reg = <0>;
> 
> You can drop "@0" and the reg property.

Ok thank you.
> 
> > +			csi_ep1: endpoint {
> > +				remote-endpoint = <&camera_1>;
> > +				data-lanes = <1 2>;
> > +			};
> > +		};
> > +	};
> 
> -- 
> Kind regards,
> 
> Sakari Ailus

Best regards,
Luis

^ permalink raw reply

* Re: [PATCH 4/8] iommu/arm-smmu-v3: Add support for Substream IDs
From: Auger Eric @ 2019-07-08 15:31 UTC (permalink / raw)
  To: Jean-Philippe Brucker, will.deacon
  Cc: joro, robh+dt, mark.rutland, robin.murphy, jacob.jun.pan, iommu,
	devicetree, linux-kernel, linux-arm-kernel
In-Reply-To: <20190610184714.6786-5-jean-philippe.brucker@arm.com>

Hi Jean,

On 6/10/19 8:47 PM, Jean-Philippe Brucker wrote:
> At the moment, the SMMUv3 driver implements only one stage-1 or stage-2
> page directory per device. However SMMUv3 allows more than one address
> space for some devices, by providing multiple stage-1 page directories. In
> addition to the Stream ID (SID), that identifies a device, we can now have
> Substream IDs (SSID) identifying an address space. In PCIe, SID is called
> Requester ID (RID) and SSID is called Process Address-Space ID (PASID).
> 
> Prepare the driver for SSID support, by adding context descriptor tables
> in STEs (previously a single static context descriptor). A complete
> stage-1 walk is now performed like this by the SMMU:
> 
>       Stream tables          Ctx. tables          Page tables
>         +--------+   ,------->+-------+   ,------->+-------+
>         :        :   |        :       :   |        :       :
>         +--------+   |        +-------+   |        +-------+
>    SID->|  STE   |---'  SSID->|  CD   |---'  IOVA->|  PTE  |--> IPA
>         +--------+            +-------+            +-------+
>         :        :            :       :            :       :
>         +--------+            +-------+            +-------+
> 
> Implement a single level of context descriptor table for now, but as with
> stream and page tables, an SSID can be split to index multiple levels of
> tables.
> 
> In all stream table entries, we set S1DSS=SSID0 mode, making translations
> without an SSID use context descriptor 0. Although it would be possible by
> setting S1DSS=BYPASS, we don't currently support SSID when user selects
> iommu.passthrough.
> 
> Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
> ---
>  drivers/iommu/arm-smmu-v3.c | 238 +++++++++++++++++++++++++++++-------
>  1 file changed, 192 insertions(+), 46 deletions(-)
> 
> diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
> index 3254f473e681..d90eb604b65d 100644
> --- a/drivers/iommu/arm-smmu-v3.c
> +++ b/drivers/iommu/arm-smmu-v3.c
> @@ -219,6 +219,11 @@
>  #define STRTAB_STE_0_S1CTXPTR_MASK	GENMASK_ULL(51, 6)
>  #define STRTAB_STE_0_S1CDMAX		GENMASK_ULL(63, 59)
>  
> +#define STRTAB_STE_1_S1DSS		GENMASK_ULL(1, 0)
> +#define STRTAB_STE_1_S1DSS_TERMINATE	0x0
> +#define STRTAB_STE_1_S1DSS_BYPASS	0x1
> +#define STRTAB_STE_1_S1DSS_SSID0	0x2
> +
>  #define STRTAB_STE_1_S1C_CACHE_NC	0UL
>  #define STRTAB_STE_1_S1C_CACHE_WBRA	1UL
>  #define STRTAB_STE_1_S1C_CACHE_WT	2UL
> @@ -305,6 +310,7 @@
>  #define CMDQ_PREFETCH_1_SIZE		GENMASK_ULL(4, 0)
>  #define CMDQ_PREFETCH_1_ADDR_MASK	GENMASK_ULL(63, 12)
>  
> +#define CMDQ_CFGI_0_SSID		GENMASK_ULL(31, 12)
>  #define CMDQ_CFGI_0_SID			GENMASK_ULL(63, 32)
>  #define CMDQ_CFGI_1_LEAF		(1UL << 0)
>  #define CMDQ_CFGI_1_RANGE		GENMASK_ULL(4, 0)
> @@ -421,8 +427,11 @@ struct arm_smmu_cmdq_ent {
>  
>  		#define CMDQ_OP_CFGI_STE	0x3
>  		#define CMDQ_OP_CFGI_ALL	0x4
> +		#define CMDQ_OP_CFGI_CD		0x5
> +		#define CMDQ_OP_CFGI_CD_ALL	0x6
>  		struct {
>  			u32			sid;
> +			u32			ssid;
>  			union {
>  				bool		leaf;
>  				u8		span;
> @@ -506,16 +515,25 @@ struct arm_smmu_strtab_l1_desc {
>  	dma_addr_t			l2ptr_dma;
>  };
>  
> +struct arm_smmu_cd_table {
> +	__le64				*ptr;
> +	dma_addr_t			ptr_dma;
> +};
> +
> +struct arm_smmu_ctx_desc {
> +	u16				asid;
> +	u64				ttbr;
> +	u64				tcr;
> +	u64				mair;
> +};
> +
>  struct arm_smmu_s1_cfg {
> -	__le64				*cdptr;
> -	dma_addr_t			cdptr_dma;
> -
> -	struct arm_smmu_ctx_desc {
> -		u16	asid;
> -		u64	ttbr;
> -		u64	tcr;
> -		u64	mair;
> -	}				cd;
> +	u8				s1fmt;
> +	u8				s1cdmax;
> +	struct arm_smmu_cd_table	table;
> +
> +	/* Context descriptor 0, when substreams are disabled or s1dss = 0b10 */
> +	struct arm_smmu_ctx_desc	cd;
>  };
>  
>  struct arm_smmu_s2_cfg {
> @@ -811,10 +829,16 @@ static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent)
>  		cmd[1] |= FIELD_PREP(CMDQ_PREFETCH_1_SIZE, ent->prefetch.size);
>  		cmd[1] |= ent->prefetch.addr & CMDQ_PREFETCH_1_ADDR_MASK;
>  		break;
> +	case CMDQ_OP_CFGI_CD:
> +		cmd[0] |= FIELD_PREP(CMDQ_CFGI_0_SSID, ent->cfgi.ssid);
> +		/* Fallthrough */
>  	case CMDQ_OP_CFGI_STE:
>  		cmd[0] |= FIELD_PREP(CMDQ_CFGI_0_SID, ent->cfgi.sid);
>  		cmd[1] |= FIELD_PREP(CMDQ_CFGI_1_LEAF, ent->cfgi.leaf);
>  		break;
> +	case CMDQ_OP_CFGI_CD_ALL:
> +		cmd[0] |= FIELD_PREP(CMDQ_CFGI_0_SID, ent->cfgi.sid);
> +		break;
>  	case CMDQ_OP_CFGI_ALL:
>  		/* Cover the entire SID range */
>  		cmd[1] |= FIELD_PREP(CMDQ_CFGI_1_RANGE, 31);
> @@ -1045,6 +1069,63 @@ static int arm_smmu_cmdq_issue_sync(struct arm_smmu_device *smmu)
>  }
>  
>  /* Context descriptor manipulation functions */
> +static void arm_smmu_sync_cd(struct arm_smmu_domain *smmu_domain,
> +			     int ssid, bool leaf)
> +{
> +	size_t i;
> +	unsigned long flags;
> +	struct arm_smmu_master *master;
> +	struct arm_smmu_device *smmu = smmu_domain->smmu;
> +	struct arm_smmu_cmdq_ent cmd = {
> +		.opcode	= CMDQ_OP_CFGI_CD,
> +		.cfgi	= {
> +			.ssid	= ssid,
> +			.leaf	= leaf,
> +		},
> +	};
> +
> +	spin_lock_irqsave(&smmu_domain->devices_lock, flags);
> +	list_for_each_entry(master, &smmu_domain->devices, domain_head) {
> +		for (i = 0; i < master->num_sids; i++) {
> +			cmd.cfgi.sid = master->sids[i];
> +			arm_smmu_cmdq_issue_cmd(smmu, &cmd);
> +		}
> +	}
> +	spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
> +
> +	arm_smmu_cmdq_issue_sync(smmu);
> +}
> +
> +static int arm_smmu_alloc_cd_leaf_table(struct arm_smmu_device *smmu,
> +					struct arm_smmu_cd_table *table,
> +					size_t num_entries)
> +{
> +	size_t size = num_entries * (CTXDESC_CD_DWORDS << 3);
> +
> +	table->ptr = dmam_alloc_coherent(smmu->dev, size, &table->ptr_dma,
> +					 GFP_KERNEL | __GFP_ZERO);
> +	if (!table->ptr) {
> +		dev_warn(smmu->dev,
> +			 "failed to allocate context descriptor table\n");
> +		return -ENOMEM;
> +	}
> +	return 0;
> +}
> +
> +static void arm_smmu_free_cd_leaf_table(struct arm_smmu_device *smmu,
> +					struct arm_smmu_cd_table *table,
> +					size_t num_entries)
> +{
> +	size_t size = num_entries * (CTXDESC_CD_DWORDS << 3);
> +
> +	dmam_free_coherent(smmu->dev, size, table->ptr, table->ptr_dma);
> +}
> +
> +static __le64 *arm_smmu_get_cd_ptr(struct arm_smmu_s1_cfg *cfg, u32 ssid)
> +{
> +	return cfg->table.ptr + ssid * CTXDESC_CD_DWORDS;
> +}
> +
>  static u64 arm_smmu_cpu_tcr_to_cd(u64 tcr)
>  {
>  	u64 val = 0;
> @@ -1062,33 +1143,90 @@ static u64 arm_smmu_cpu_tcr_to_cd(u64 tcr)
>  	return val;
>  }
>  
> -static void arm_smmu_write_ctx_desc(struct arm_smmu_device *smmu,
> -				    struct arm_smmu_s1_cfg *cfg)
> +static int arm_smmu_write_ctx_desc(struct arm_smmu_domain *smmu_domain,
> +				   int ssid, struct arm_smmu_ctx_desc *cd)
>  {
>  	u64 val;
> +	bool cd_live;
> +	struct arm_smmu_device *smmu = smmu_domain->smmu;
> +	__le64 *cdptr = arm_smmu_get_cd_ptr(&smmu_domain->s1_cfg, ssid);
>  
>  	/*
> -	 * We don't need to issue any invalidation here, as we'll invalidate
> -	 * the STE when installing the new entry anyway.
> +	 * This function handles the following cases:
> +	 *
> +	 * (1) Install primary CD, for normal DMA traffic (SSID = 0).
> +	 * (2) Install a secondary CD, for SID+SSID traffic.
> +	 * (3) Update ASID of a CD. Atomically write the first 64 bits of the
> +	 *     CD, then invalidate the old entry and mappings.
Can you explain when (3) does occur?
> +	 * (4) Remove a secondary CD.
>  	 */
> -	val = arm_smmu_cpu_tcr_to_cd(cfg->cd.tcr) |
> +
> +	if (!cdptr)
> +		return -ENOMEM;
Is that relevant? arm_smmu_get_cd_ptr() does not test ssid is within the
cfg->s1cdmax range and always return smthg != NULL AFAIU.
> +
> +	val = le64_to_cpu(cdptr[0]);
> +	cd_live = !!(val & CTXDESC_CD_0_V);
> +
> +	if (!cd) { /* (4) */
> +		cdptr[0] = 0;
> +	} else if (cd_live) { /* (3) */
> +		val &= ~CTXDESC_CD_0_ASID;
> +		val |= FIELD_PREP(CTXDESC_CD_0_ASID, cd->asid);
> +
> +		cdptr[0] = cpu_to_le64(val);
> +		/*
> +		 * Until CD+TLB invalidation, both ASIDs may be used for tagging
> +		 * this substream's traffic
> +		 */
> +	} else { /* (1) and (2) */
> +		cdptr[1] = cpu_to_le64(cd->ttbr & CTXDESC_CD_1_TTB0_MASK);
> +		cdptr[2] = 0;
> +		cdptr[3] = cpu_to_le64(cd->mair);
> +
> +		/*
> +		 * STE is live, and the SMMU might fetch this CD at any
> +		 * time. Ensure that it observes the rest of the CD before we
> +		 * enable it.
> +		 */
> +		arm_smmu_sync_cd(smmu_domain, ssid, true);
> +
> +		val = arm_smmu_cpu_tcr_to_cd(cd->tcr) |
>  #ifdef __BIG_ENDIAN
> -	      CTXDESC_CD_0_ENDI |
> +			CTXDESC_CD_0_ENDI |
>  #endif
> -	      CTXDESC_CD_0_R | CTXDESC_CD_0_A | CTXDESC_CD_0_ASET |
> -	      CTXDESC_CD_0_AA64 | FIELD_PREP(CTXDESC_CD_0_ASID, cfg->cd.asid) |
> -	      CTXDESC_CD_0_V;
> +			CTXDESC_CD_0_R | CTXDESC_CD_0_A | CTXDESC_CD_0_ASET |
> +			CTXDESC_CD_0_AA64 |
> +			FIELD_PREP(CTXDESC_CD_0_ASID, cd->asid) |
> +			CTXDESC_CD_0_V;
> +
> +		/* STALL_MODEL==0b10 && CD.S==0 is ILLEGAL */
> +		if (smmu->features & ARM_SMMU_FEAT_STALL_FORCE)
> +			val |= CTXDESC_CD_0_S;
> +
> +		cdptr[0] = cpu_to_le64(val);
> +	}
>  
> -	/* STALL_MODEL==0b10 && CD.S==0 is ILLEGAL */
> -	if (smmu->features & ARM_SMMU_FEAT_STALL_FORCE)
> -		val |= CTXDESC_CD_0_S;
> +	arm_smmu_sync_cd(smmu_domain, ssid, true);
> +	return 0;
> +}
> +
> +static int arm_smmu_alloc_cd_tables(struct arm_smmu_domain *smmu_domain,
> +				    struct arm_smmu_master *master> +{
> +	struct arm_smmu_device *smmu = smmu_domain->smmu;
> +	struct arm_smmu_s1_cfg *cfg = &smmu_domain->s1_cfg;
>  
> -	cfg->cdptr[0] = cpu_to_le64(val);
> +	cfg->s1fmt = STRTAB_STE_0_S1FMT_LINEAR;
> +	cfg->s1cdmax = master->ssid_bits;
> +	return arm_smmu_alloc_cd_leaf_table(smmu, &cfg->table, 1 << cfg->s1cdmax);
> +}
>  
> -	val = cfg->cd.ttbr & CTXDESC_CD_1_TTB0_MASK;
> -	cfg->cdptr[1] = cpu_to_le64(val);
> +static void arm_smmu_free_cd_tables(struct arm_smmu_domain *smmu_domain)
> +{
> +	struct arm_smmu_device *smmu = smmu_domain->smmu;
> +	struct arm_smmu_s1_cfg *cfg = &smmu_domain->s1_cfg;
>  
> -	cfg->cdptr[3] = cpu_to_le64(cfg->cd.mair);
> +	arm_smmu_free_cd_leaf_table(smmu, &cfg->table, 1 << cfg->s1cdmax);
>  }
>  
>  /* Stream table manipulation functions */
> @@ -1210,6 +1348,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid,
>  	if (s1_cfg) {
>  		BUG_ON(ste_live);
>  		dst[1] = cpu_to_le64(
> +			 FIELD_PREP(STRTAB_STE_1_S1DSS, STRTAB_STE_1_S1DSS_SSID0) |
>  			 FIELD_PREP(STRTAB_STE_1_S1CIR, STRTAB_STE_1_S1C_CACHE_WBRA) |
>  			 FIELD_PREP(STRTAB_STE_1_S1COR, STRTAB_STE_1_S1C_CACHE_WBRA) |
>  			 FIELD_PREP(STRTAB_STE_1_S1CSH, ARM_SMMU_SH_ISH) |
> @@ -1219,8 +1358,10 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid,
>  		   !(smmu->features & ARM_SMMU_FEAT_STALL_FORCE))
>  			dst[1] |= cpu_to_le64(STRTAB_STE_1_S1STALLD);
>  
> -		val |= (s1_cfg->cdptr_dma & STRTAB_STE_0_S1CTXPTR_MASK) |
> -			FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_S1_TRANS);
> +		val |= (s1_cfg->table.ptr_dma & STRTAB_STE_0_S1CTXPTR_MASK) |
> +			FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_S1_TRANS) |
> +			FIELD_PREP(STRTAB_STE_0_S1CDMAX, s1_cfg->s1cdmax) |
> +			FIELD_PREP(STRTAB_STE_0_S1FMT, s1_cfg->s1fmt);
>  	}
>  
>  	if (s2_cfg) {
> @@ -1674,12 +1815,8 @@ static void arm_smmu_domain_free(struct iommu_domain *domain)
>  	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
>  		struct arm_smmu_s1_cfg *cfg = &smmu_domain->s1_cfg;
>  
> -		if (cfg->cdptr) {
> -			dmam_free_coherent(smmu_domain->smmu->dev,
> -					   CTXDESC_CD_DWORDS << 3,
> -					   cfg->cdptr,
> -					   cfg->cdptr_dma);
> -
> +		if (cfg->table.ptr) {
> +			arm_smmu_free_cd_tables(smmu_domain);
>  			arm_smmu_bitmap_free(smmu->asid_map, cfg->cd.asid);
>  		}
>  	} else {
> @@ -1692,6 +1829,7 @@ static void arm_smmu_domain_free(struct iommu_domain *domain)
>  }
>  
>  static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain,
> +				       struct arm_smmu_master *master,
>  				       struct io_pgtable_cfg *pgtbl_cfg)
>  {
>  	int ret;
> @@ -1703,27 +1841,29 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain,
>  	if (asid < 0)
>  		return asid;
>  
> -	cfg->cdptr = dmam_alloc_coherent(smmu->dev, CTXDESC_CD_DWORDS << 3,
> -					 &cfg->cdptr_dma,
> -					 GFP_KERNEL | __GFP_ZERO);
> -	if (!cfg->cdptr) {
> -		dev_warn(smmu->dev, "failed to allocate context descriptor\n");
> -		ret = -ENOMEM;
> +	ret = arm_smmu_alloc_cd_tables(smmu_domain, master);
> +	if (ret)
>  		goto out_free_asid;
> -	}
>  
>  	cfg->cd.asid	= (u16)asid;
>  	cfg->cd.ttbr	= pgtbl_cfg->arm_lpae_s1_cfg.ttbr[0];
>  	cfg->cd.tcr	= pgtbl_cfg->arm_lpae_s1_cfg.tcr;
>  	cfg->cd.mair	= pgtbl_cfg->arm_lpae_s1_cfg.mair[0];
> +
> +	ret = arm_smmu_write_ctx_desc(smmu_domain, 0, &smmu_domain->s1_cfg.cd);
cfg.cd
> +	if (ret)
> +		goto out_free_table;
>  	return 0;
>  
> +out_free_table:
> +	arm_smmu_free_cd_tables(smmu_domain);
>  out_free_asid:
>  	arm_smmu_bitmap_free(smmu->asid_map, asid);
>  	return ret;
>  }
>  
>  static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain,
> +				       struct arm_smmu_master *master,
>  				       struct io_pgtable_cfg *pgtbl_cfg)
>  {
>  	int vmid;
> @@ -1740,7 +1880,8 @@ static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain,
>  	return 0;
>  }
>  
> -static int arm_smmu_domain_finalise(struct iommu_domain *domain)
> +static int arm_smmu_domain_finalise(struct iommu_domain *domain,
> +				    struct arm_smmu_master *master)
>  {
>  	int ret;
>  	unsigned long ias, oas;
> @@ -1748,6 +1889,7 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain)
>  	struct io_pgtable_cfg pgtbl_cfg;
>  	struct io_pgtable_ops *pgtbl_ops;
>  	int (*finalise_stage_fn)(struct arm_smmu_domain *,
> +				 struct arm_smmu_master *,
>  				 struct io_pgtable_cfg *);
>  	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
>  	struct arm_smmu_device *smmu = smmu_domain->smmu;
> @@ -1804,7 +1946,7 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain)
>  	domain->geometry.aperture_end = (1UL << pgtbl_cfg.ias) - 1;
>  	domain->geometry.force_aperture = true;
>  
> -	ret = finalise_stage_fn(smmu_domain, &pgtbl_cfg);
> +	ret = finalise_stage_fn(smmu_domain, master, &pgtbl_cfg);
>  	if (ret < 0) {
>  		free_io_pgtable_ops(pgtbl_ops);
>  		return ret;
> @@ -1932,7 +2074,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
>  
>  	if (!smmu_domain->smmu) {
>  		smmu_domain->smmu = smmu;
> -		ret = arm_smmu_domain_finalise(domain);
> +		ret = arm_smmu_domain_finalise(domain, master);
>  		if (ret) {
>  			smmu_domain->smmu = NULL;
>  			goto out_unlock;
> @@ -1944,6 +2086,13 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
>  			dev_name(smmu->dev));
>  		ret = -ENXIO;
>  		goto out_unlock;
> +	} else if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1 &&
> +		   master->ssid_bits != smmu_domain->s1_cfg.s1cdmax) {
> +		dev_err(dev,
> +			"cannot attach to incompatible domain (%u SSID bits != %u)\n",
> +			smmu_domain->s1_cfg.s1cdmax, master->ssid_bits);
> +		ret = -EINVAL;
> +		goto out_unlock;
>  	}
>  
>  	master->domain = smmu_domain;
> @@ -1955,9 +2104,6 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
>  	if (smmu_domain->stage != ARM_SMMU_DOMAIN_BYPASS)
>  		arm_smmu_enable_ats(master);
>  
> -	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1)
> -		arm_smmu_write_ctx_desc(smmu, &smmu_domain->s1_cfg);
> -
>  	arm_smmu_install_ste_for_dev(master);
>  out_unlock:
>  	mutex_unlock(&smmu_domain->init_mutex);
> 
Thanks

Eric

^ permalink raw reply

* Re: [PATCH RFC 1/7] pinctrl: sh-pfc: add new flags into struct sh_pfc_pin_config
From: Sergei Shtylyov @ 2019-07-08 15:51 UTC (permalink / raw)
  To: Yoshihiro Shimoda, linus.walleij, geert+renesas, thierry.reding,
	robh+dt, mark.rutland
  Cc: linux-gpio, linux-pwm, devicetree, linux-renesas-soc
In-Reply-To: <1562576868-8124-2-git-send-email-yoshihiro.shimoda.uh@renesas.com>

On 08.07.2019 12:07, Yoshihiro Shimoda wrote:

> To clean/modify the code up later, this patch just adds new flags
> "mux_set" and "gpio_enabled" into the struct sh_pfc_pin_config.
> 
> Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
> ---
>   drivers/pinctrl/sh-pfc/pinctrl.c | 14 +++++++++++++-
>   1 file changed, 13 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/pinctrl/sh-pfc/pinctrl.c b/drivers/pinctrl/sh-pfc/pinctrl.c
> index 2824be4..157b257 100644
> --- a/drivers/pinctrl/sh-pfc/pinctrl.c
> +++ b/drivers/pinctrl/sh-pfc/pinctrl.c
> @@ -27,6 +27,8 @@
>   
>   struct sh_pfc_pin_config {
>   	u32 type;
> +	bool mux_set;
> +	bool gpio_enabled;
>   };
>   
>   struct sh_pfc_pinctrl {
> @@ -364,7 +366,15 @@ static int sh_pfc_func_set_mux(struct pinctrl_dev *pctldev, unsigned selector,
>   	for (i = 0; i < grp->nr_pins; ++i) {
>   		ret = sh_pfc_config_mux(pfc, grp->mux[i], PINMUX_TYPE_FUNCTION);
>   		if (ret < 0)
> -			break;
> +			goto done;
> +	}
> +
> +	/* All group pins are configurated, mark the pins as mux_set */

    Configured.

> +	for (i = 0; i < grp->nr_pins; ++i) {
> +		int idx = sh_pfc_get_pin_index(pfc, grp->pins[i]);
> +		struct sh_pfc_pin_config *cfg = &pmx->configs[idx];
> +
> +		cfg->mux_set = true;
>   	}
>   
>   done:
[...]

MBR, Sergei

^ permalink raw reply

* Re: [PATCH v5 0/7] drm/panel: simple: Add mode support to devicetree
From: Doug Anderson @ 2019-07-08 15:58 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: Sam Ravnborg, Thierry Reding, Sean Paul, Mark Rutland, devicetree,
	Dmitry Torokhov, Rob Herring, David Airlie, Viresh Kumar,
	Brian Norris, dri-devel, LKML, open list:ARM/Rockchip SoC...,
	Boris Brezillon, Klaus Goger, Laurent Pinchart,
	Enric Balletbò
In-Reply-To: <2169143.hEFa8b2HQR@diego>

Hi Sam,

On Sat, Jun 29, 2019 at 7:09 AM Heiko Stübner <heiko@sntech.de> wrote:
>
> Hi Sam,
>
> Am Freitag, 28. Juni 2019, 19:13:42 CEST schrieb Sam Ravnborg:
> > Hi Doug.
> >
> > > Sam: Oh!  I hadn't noticed that you've been added as a panel
> > > maintainer in commit ef0db94f94a0 ("MAINTAINERS: Add Sam as reviewer
> > > for drm/panel").  Does that mean you are able to provide some advice
> > > for how to land this series?
> > Reviewer only, not maintainer....
> >
> > It is on my TODO list for the weekend to go through the patch set in
> > details and provide feedback. I have read them before, but I miss to do
> > a more detailed read through.
> >
> > But I cannot apply this unless Thierry or one of the DRM maintainers
> > ack it.
> > We simply need someone with a better general knowledge of DRM to ack it
> > than I have.
>
> So Thierry was able to look at the patches yesterday it seems and has Acked
> all the relevant ones. As a drm-misc-contributor I could also apply them
> myself, but now don't want to preempt any additional comments you might
> have ;-) . So I guess my question would be if you still want to do a review
> or if I should apply them.

Hopefully you saw, but I responded to all of your review feedback.  In
the end, I thought it'd be OK to land the series as-is and I can fix
up nits in a follow-up series, though I'm waiting for your responses
to a couple questions first.

It would be ideal if you could confirm that you're OK with this plan
even if you don't have time to respond in detail to my emails yet.  I
think Heiko can land them all through the appropriate channels since
the patches have all the proper Acks.

Thanks!

-Doug

^ permalink raw reply

* Re: [PATCH 1/6] dt-bindings: irqchip: Add PRUSS interrupt controller bindings
From: Suman Anna @ 2019-07-08 15:59 UTC (permalink / raw)
  To: Andrew F. Davis, Marc Zyngier, Rob Herring, Thomas Gleixner,
	Jason Cooper
  Cc: Tony Lindgren, Roger Quadros, Lokesh Vutla, Grygorii Strashko,
	Sekhar Nori, David Lechner, Murali Karicheri, devicetree,
	linux-omap, linux-arm-kernel, linux-kernel
In-Reply-To: <b67e8ce6-a291-ce4c-9972-b7fc7cd08bb4@ti.com>

Hi Andrew,

On 7/8/19 9:34 AM, Andrew F. Davis wrote:
> On 7/7/19 11:52 PM, Suman Anna wrote:
>> The Programmable Real-Time Unit Subsystem (PRUSS) contains an interrupt
>> controller (INTC) that can handle various system input events and post
>> interrupts back to the device-level initiators. The INTC can support
>> upto 64 input events on most SoCs with individual control configuration
>> and hardware prioritization. These events are mapped onto 10 interrupt
>> lines through two levels of many-to-one mapping support. Different
>> interrupt lines are routed to the individual PRU cores or to the
>> host CPU or to other PRUSS instances.
>>
>> The K3 AM65x and J721E SoCs have the next generation of the PRU-ICSS IP,
>> commonly called ICSSG. The ICSSG interrupt controller on K3 SoCs provide
>> a higher number of host interrupts (20 vs 10) and can handle an increased
>> number of input events (160 vs 64) from various SoC interrupt sources.
>>
>> Add the bindings document for these interrupt controllers on all the
>> applicable SoCs. It covers the OMAP architecture SoCs - AM33xx, AM437x
>> and AM57xx; the Keystone 2 architecture based 66AK2G SoC; the Davinci
>> architecture based OMAPL138 SoCs, and the K3 architecture based AM65x
>> and J721E SoCs.
>>
>> Signed-off-by: Suman Anna <s-anna@ti.com>
>> Signed-off-by: Andrew F. Davis <afd@ti.com>
>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>> ---
>> Prior version: https://patchwork.kernel.org/patch/10795771/
>>
>>  .../interrupt-controller/ti,pruss-intc.txt    | 92 +++++++++++++++++++
>>  1 file changed, 92 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc.txt
>>
>> diff --git a/Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc.txt
>> new file mode 100644
>> index 000000000000..020073c07a92
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc.txt
>> @@ -0,0 +1,92 @@
>> +PRU ICSS INTC on TI SoCs
>> +========================
>> +
>> +Each PRUSS has a single interrupt controller instance that is common to both
>> +the PRU cores. Most interrupt controllers can route 64 input events which are
>> +then mapped to 10 possible output interrupts through two levels of mapping.
>> +The input events can be triggered by either the PRUs and/or various other
>> +PRUSS internal and external peripherals. The first 2 output interrupts are
>> +fed exclusively to the internal PRU cores, with the remaining 8 (2 through 9)
>> +connected to external interrupt controllers including the MPU and/or other
>> +PRUSS instances, DSPs or devices.
>> +
>> +The K3 family of SoCs can handle 160 input events that can be mapped to 20
>> +different possible output interrupts. The additional output interrupts (10
>> +through 19) are connected to new sub-modules within the ICSSG instances.
>> +
>> +This interrupt-controller node should be defined as a child node of the
>> +corresponding PRUSS node. The node should be named "interrupt-controller".
>> +Please see the overall PRUSS bindings document for additional details
>> +including a complete example,
>> +    Documentation/devicetree/bindings/soc/ti/ti,pruss.txt
>> +
>> +Required Properties:
>> +--------------------
>> +- compatible           : should be one of the following,
>> +                             "ti,pruss-intc" for OMAP-L13x/AM18x/DA850 SoCs,
>> +                                                 AM335x family of SoCs,
>> +                                                 AM437x family of SoCs,
>> +                                                 AM57xx family of SoCs
>> +                                                 66AK2G family of SoCs
>> +                             "ti,icssg-intc" for K3 AM65x & J721E family of SoCs
>> +- reg                  : base address and size for the PRUSS INTC sub-module
>> +- interrupts           : all the interrupts generated towards the main host
>> +                         processor in the SoC. The format depends on the
>> +                         interrupt specifier for the particular SoC's ARM GIC
>> +                         parent interrupt controller. A shared interrupt can
>> +                         be skipped if the desired destination and usage is by
>> +                         a different processor/device.
>> +- interrupt-names      : should use one of the following names for each valid
>> +                         interrupt connected to ARM GIC, the name should match
>> +                         the corresponding host interrupt number,
>> +                             "host0", "host1", "host2", "host3", "host4",
>> +                             "host5", "host6" or "host7"
>> +- interrupt-controller : mark this node as an interrupt controller
>> +- #interrupt-cells     : should be 1. Client users shall use the PRU System
>> +                         event number (the interrupt source that the client
>> +                         is interested in) as the value of the interrupts
>> +                         property in their node
>> +
>> +Optional Properties:
>> +--------------------
>> +The following properties are _required_ only for some SoCs. If none of the below
>> +properties are defined, it implies that all the host interrupts 2 through 9 are
>> +connected exclusively to the ARM GIC.
>> +
>> +- ti,irqs-reserved     : an array of 8-bit elements of host interrupts between
>> +                         0 and 7 (corresponding to PRUSS INTC output interrupts
>> +                         2 through 9) that are not connected to the ARM GIC.
> 
> The reason for 0-7 mapping to 2-9 is not instantly clear to someone
> reading this. If you respin this could you note that reason is
> interrupts 0 and 1 are always routed back into the PRUSS. 

Yeah, this is always going to be somewhat confusing since the driver has
to deal with all hosts from channel-mapping perspective, but only the 8
interrupts at most that reach MPU for handling interrupts. TRM has

Anyway, I have already mentioned the first 2 interrupt routing in the
first paragraph above.

Thinking more
> on that, the same is true for interrupt 7 ("host5") on AM437x/66AK2G yet
> we don't skip that in the naming.. now that we have the reserved IRQ
> mechanism above, why not leave the one-to-one interrupt to name mapping,
> but always have at least the first two marked as reserved for all the
> current devices:
> 
> ti,irqs-reserved = /bits/ 8 <0 1>;
> 
> Then any "hostx" listed as reserved need not be present in the host
> interrupts property array. To me that would solve the "managing
> interrupts not targeting the Linux running core" problem and keep the
> names consistent, e.g.:

I had actually used the interrupt-names always starting from "host2"
through "host9" (names from PRU perspective) previously, and I have
changed this to start indexing from 0 in this series to address an
internal review comment from Grygorii and to align with TRM. All the
TRMs (except for AM572x) actually use the names/signals "host_intr0",
"host_intr1".."host_intr7" etc for the interrupts going towards MPU.
Maybe I should actually rename the interrupt-names to be host_intrX
instead of hostX to avoid confusion and be exactly aligned with the TRM
names. I will file a bug against AM57xx TRM to align the names with all
other SoC TRMs.

I am using "output interrupt lines" to imply names w.r.t PRU vs "host
interrupt" to imply ARM GIC names.

regards
Suman

> 
> /* AM437x PRU-ICSS */
> pruss_intc: interrupt-controller@20000 {
> 	compatible = "ti,pruss-intc";
> 	reg = <0x20000 0x2000>;
> 	interrupts = <                       20       21       22
> 	                   23       24                25       26>;
> 	interrupt-names =                   "host2", "host3", "host4",
> 	                  "host5", "host6",          "host8", "host9";
> 	interrupt-controller;
> 	#interrupt-cells = <1>;
> 	ti,irqs-reserved = /bits/ 8 <0 1 7>;
> };
> 
> Instantly clear which are missing and which "hostx" maps to which host
> interrupt number.
> 
> Andrew
> 
>> +                           Eg: AM437x and 66AK2G SoCs do not have "host5"
>> +                               interrupt connected to MPU
>> +- ti,irqs-shared       : an array of 8-bit elements of host interrupts between
>> +                         0 and 7 (corresponding to PRUSS INTC output interrupts
>> +                         2 through 9) that are also connected to other devices
>> +                         or processors in the SoC.
>> +                           Eg: AM65x and J721E SoCs have "host5", "host6" and
>> +                               "host7" interrupts connected to MPU, and other
>> +                               ICSSG instances
>> +
>> +
>> +Example:
>> +--------
>> +
>> +1.	/* AM33xx PRU-ICSS */
>> +	pruss: pruss@0 {
>> +		compatible = "ti,am3356-pruss";
>> +		reg = <0x0 0x80000>;
>> +		#address-cells = <1>;
>> +		#size-cells = <1>;
>> +		...
>> +
>> +		pruss_intc: interrupt-controller@20000 {
>> +			compatible = "ti,pruss-intc";
>> +			reg = <0x20000 0x2000>;
>> +			interrupts = <20 21 22 23 24 25 26 27>;
>> +			interrupt-names = "host0", "host1", "host2",
>> +					  "host3", "host4", "host5",
>> +					  "host6", "host7";
>> +			interrupt-controller;
>> +			#interrupt-cells = <1>;
>> +			ti,irqs-shared = /bits/ 8 <0 6 7>;
>> +		};
>> +	};
>>

^ permalink raw reply

* [PATCH v2 0/2] Add Sharp panel option for Lenovo Miix 630
From: Jeffrey Hugo @ 2019-07-08 16:56 UTC (permalink / raw)
  To: robh+dt, mark.rutland, thierry.reding, sam, airlied, daniel
  Cc: bjorn.andersson, dri-devel, devicetree, linux-arm-msm,
	linux-kernel, Jeffrey Hugo

The Lenovo Miix 630 laptop can be found with one of two panels - a BOE
or Sharp option.  This likely provides options during manufacturing.

These panels connect via eDP, however they sit behind a DSI to eDP
bridge on the laptop, so they can easily be handled by the existing
simple panel code.

This series adds support for the Sharp option.

v2:
-removed no-hpd from dt example
-added .bus_format and .bus_flags fields based on reviews
-added .flags after Bjorn pointed me to something I missed
-added Sam's reviewed-by tags

Jeffrey Hugo (2):
  dt-bindings: panel: Add Sharp LD-D5116Z01B
  drm/panel: simple: Add support for Sharp LD-D5116Z01B panel

 .../display/panel/sharp,ld-d5116z01b.txt      | 26 +++++++++++++++++
 drivers/gpu/drm/panel/panel-simple.c          | 29 +++++++++++++++++++
 2 files changed, 55 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/sharp,ld-d5116z01b.txt

-- 
2.17.1

^ permalink raw reply

* [PATCH v2 1/2] dt-bindings: panel: Add Sharp LD-D5116Z01B
From: Jeffrey Hugo @ 2019-07-08 16:57 UTC (permalink / raw)
  To: robh+dt, mark.rutland, thierry.reding, sam, airlied, daniel
  Cc: bjorn.andersson, dri-devel, devicetree, linux-arm-msm,
	linux-kernel, Jeffrey Hugo
In-Reply-To: <20190708165647.46224-1-jeffrey.l.hugo@gmail.com>

The Sharp LD-D5116Z01B is a 12.3" eDP panel with a 1920X1280 resolution.

Signed-off-by: Jeffrey Hugo <jeffrey.l.hugo@gmail.com>
Reviewed-by: Sam Ravnborg <sam@ravnborg.org>
---
 .../display/panel/sharp,ld-d5116z01b.txt      | 26 +++++++++++++++++++
 1 file changed, 26 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/sharp,ld-d5116z01b.txt

diff --git a/Documentation/devicetree/bindings/display/panel/sharp,ld-d5116z01b.txt b/Documentation/devicetree/bindings/display/panel/sharp,ld-d5116z01b.txt
new file mode 100644
index 000000000000..fd9cf39bde77
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/sharp,ld-d5116z01b.txt
@@ -0,0 +1,26 @@
+Sharp LD-D5116Z01B 12.3" WUXGA+ eDP panel
+
+Required properties:
+- compatible: should be "sharp,ld-d5116z01b"
+- power-supply: regulator to provide the VCC supply voltage (3.3 volts)
+
+This binding is compatible with the simple-panel binding.
+
+The device node can contain one 'port' child node with one child
+'endpoint' node, according to the bindings defined in [1]. This
+node should describe panel's video bus.
+
+[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Example:
+
+	panel: panel {
+		compatible = "sharp,ld-d5116z01b";
+		power-supply = <&vlcd_3v3>;
+
+		port {
+			panel_ep: endpoint {
+				remote-endpoint = <&bridge_out_ep>;
+			};
+		};
+	};
-- 
2.17.1

^ permalink raw reply related

* [PATCH v2 2/2] drm/panel: simple: Add support for Sharp LD-D5116Z01B panel
From: Jeffrey Hugo @ 2019-07-08 16:58 UTC (permalink / raw)
  To: thierry.reding, sam, airlied, daniel
  Cc: robh+dt, mark.rutland, bjorn.andersson, dri-devel, devicetree,
	linux-arm-msm, linux-kernel, Jeffrey Hugo
In-Reply-To: <20190708165647.46224-1-jeffrey.l.hugo@gmail.com>

The Sharp LD-D5116Z01B is a 12.3" eDP panel with a 1920X1280 resolution.

Signed-off-by: Jeffrey Hugo <jeffrey.l.hugo@gmail.com>
Reviewed-by: Sam Ravnborg <sam@ravnborg.org>
---
 drivers/gpu/drm/panel/panel-simple.c | 29 ++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index 5a93c4edf1e4..a8808b13c370 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -2354,6 +2354,32 @@ static const struct panel_desc samsung_ltn140at29_301 = {
 	},
 };
 
+static const struct drm_display_mode sharp_ld_d5116z01b_mode = {
+	.clock = 168480,
+	.hdisplay = 1920,
+	.hsync_start = 1920 + 48,
+	.hsync_end = 1920 + 48 + 32,
+	.htotal = 1920 + 48 + 32 + 80,
+	.vdisplay = 1280,
+	.vsync_start = 1280 + 3,
+	.vsync_end = 1280 + 3 + 10,
+	.vtotal = 1280 + 3 + 10 + 57,
+	.vrefresh = 60,
+	.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
+};
+
+static const struct panel_desc sharp_ld_d5116z01b = {
+	.modes = &sharp_ld_d5116z01b_mode,
+	.num_modes = 1,
+	.bpc = 8,
+	.size = {
+		.width = 260,
+		.height = 120,
+	},
+	.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+	.bus_flags = DRM_BUS_FLAG_DATA_MSB_TO_LSB,
+};
+
 static const struct drm_display_mode sharp_lq035q7db03_mode = {
 	.clock = 5500,
 	.hdisplay = 240,
@@ -3002,6 +3028,9 @@ static const struct of_device_id platform_of_match[] = {
 	}, {
 		.compatible = "samsung,ltn140at29-301",
 		.data = &samsung_ltn140at29_301,
+	}, {
+		.compatible = "sharp,ld-d5116z01b",
+		.data = &sharp_ld_d5116z01b,
 	}, {
 		.compatible = "sharp,lq035q7db03",
 		.data = &sharp_lq035q7db03,
-- 
2.17.1

^ permalink raw reply related

* Re: [PATCH v2 1/1] ARM: dts: colibri: introduce dts with UHS-I support enabled
From: Marcel Ziswiler @ 2019-07-08 17:09 UTC (permalink / raw)
  To: m.felsch@pengutronix.de, Igor Opaniuk
  Cc: stefan@agner.ch, linux-imx@nxp.com, kernel@pengutronix.de,
	festevam@gmail.com, mark.rutland@arm.com,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	shawnguo@kernel.org, linux-arm-kernel@lists.infradead.org,
	s.hauer@pengutronix.de, robh+dt@kernel.org
In-Reply-To: <20190702125134.4m5fvdcpuqlrg6ek@pengutronix.de>

Hi Marco

On Tue, 2019-07-02 at 14:51 +0200, Marco Felsch wrote:
> Hi Igor,
> 
> On 19-07-02 09:42, Igor Opaniuk wrote:
> > Hi Marco,
> > 
> > On Tue, Jul 2, 2019 at 10:27 AM Marco Felsch <
> > m.felsch@pengutronix.de> wrote:
> > > Hi Igor,
> > > 
> > > On 19-05-14 17:38, Igor Opaniuk wrote:
> > > > Introduce DTS for Colibri iMX6S/DL V1.1x re-design, where UHS-I 
> > > > support was
> > > > added. Provide proper configuration for VGEN3, which allows
> > > > that rail to
> > > > be automatically switched to 1.8 volts for proper UHS-I
> > > > operation mode.
> > > > 
> > > > Signed-off-by: Igor Opaniuk <igor.opaniuk@toradex.com>
> > > > ---
> > > > 
> > > > v2:
> > > > - rework hierarchy of dts files, and a separate dtsi for
> > > > Colibri
> > > >   iMX6S/DL V1.1x re-design, where UHS-I was added
> > > > - add comments about vgen3 power rail
> > > > - fix other minor issues, addressing Marcel's comments.
> > > > 
> > > >  arch/arm/boot/dts/Makefile                    |   1 +
> > > >  .../boot/dts/imx6dl-colibri-v1.1-eval-v3.dts  | 220 +++++
> > > >  arch/arm/boot/dts/imx6qdl-colibri-v1.1.dtsi   | 852
> > > > ++++++++++++++++++
> > > >  3 files changed, 1073 insertions(+)
> > > >  create mode 100644 arch/arm/boot/dts/imx6dl-colibri-v1.1-eval-
> > > > v3.dts
> > > >  create mode 100644 arch/arm/boot/dts/imx6qdl-colibri-v1.1.dtsi
> > > > 
> > > > diff --git a/arch/arm/boot/dts/Makefile
> > > > b/arch/arm/boot/dts/Makefile
> > > > index dab2914fa293..dc4ea05c8e2a 100644
> > > > --- a/arch/arm/boot/dts/Makefile
> > > > +++ b/arch/arm/boot/dts/Makefile
> > > > @@ -401,6 +401,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
> > > >       imx6dl-aristainetos2_4.dtb \
> > > >       imx6dl-aristainetos2_7.dtb \
> > > >       imx6dl-colibri-eval-v3.dtb \
> > > > +     imx6dl-colibri-v1.1-eval-v3.dtb \
> > > 
> > > I don't know the style convention but xxx-v1.1-eval-v3.dtb seems
> > > weird
> > > to me.

Absolutely nothing weird about it at all. See e.g. other mainline
device trees of us:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm/boot/dts/imx6q-apalis-ixora-v1.1.dts

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm/boot/dts/tegra124-apalis-v1.2-eval.dts

etc.

> > This was done intentionally. The first version (v1.1) is for SoM,
> > the
> > second one (v3)
> > is for a carrier board. There is an explanation below.
> 
> I mean the point between the v1.1 maybe this should be v11 or v1_1.

No, not at all. That's really how hardware gets version-controlled e.g.
see:

https://developer.toradex.com/products/colibri-imx6#revision-history

What's wrong with that dot?

> > > >       imx6dl-cubox-i.dtb \
> > > >       imx6dl-cubox-i-emmc-som-v15.dtb \
> > > >       imx6dl-cubox-i-som-v15.dtb \
> > > > diff --git a/arch/arm/boot/dts/imx6dl-colibri-v1.1-eval-v3.dts
> > > > b/arch/arm/boot/dts/imx6dl-colibri-v1.1-eval-v3.dts
> > > > new file mode 100644
> > > > index 000000000000..8ed7a528e7c7
> > > > --- /dev/null
> > > > +++ b/arch/arm/boot/dts/imx6dl-colibri-v1.1-eval-v3.dts
> > > > @@ -0,0 +1,220 @@
> > > > +// SPDX-License-Identifier: GPL-2.0+ OR X11
> > > > +/*
> > > > + * Copyright 2019 Toradex AG
> > > > + */
> > > > +
> > > > +/dts-v1/;
> > > > +
> > > > +#include <dt-bindings/input/input.h>
> > > > +#include <dt-bindings/interrupt-controller/irq.h>
> > > > +#include "imx6dl.dtsi"
> > > > +#include "imx6qdl-colibri-v1.1.dtsi"
> > > 
> > > Same here..
> > > 
> > > Why you don't use the exsiting "imx6qdl-colibri.dtsi"? The
> > > "imx6qdl-colibri-v1.1.dtsi" would be a lot of boilerplate code.
> > > Instead
> > > you can use the existing one and apply your changes. I don't know
> > > why
> > > the vgen3 node isn't available currently but you can add them
> > > without
> > > worries. Just drop the boot-default-on property within the the
> > > dtsi. Why
> > > do you need this at all?
> > > 
> > > I checked the v1.1 and the v1 DTS to and this is exactly the same
> > > code.
> > > So you can avoid even more code and improve maintainability.
> > > 
> > > I would do something like this:
> > 
> > This was done already for v1, and there was a discussion about that
> > [1].
> > The problem is that it brakes the earlier defined hierarchy of
> > device tree
> > sources [2].
> 
> Can you provide me the link please?

You mean this one?

https://developer.toradex.com/device-tree-customization

> > Currently we have 3 levels:
> > 1. SoC level: imx6qdl.dtsi(all iMX6 SoCs) and imx6dl.dtsi (iMX6DL/S
> > SoCs),
> > that contain CPU/GPU configuration, all common peripherals
> > configuration.
> > 2. SoM level: imx6qdl-colibri.dtsi common configuration (pinmuxes,
> > UART),
> > common on module peripherals
> > 3. Carrier board level: imx6dl-colibri-v1.1-eval-v3.dts specific
> > carrier board
> > configuration (where eval-v3 is the name and the version of a
> > carrier board)
> 
> I know that kind of hierarchy ;)

Sure.

> > The UHS-I feature was not present on V1.0x Colibri iMX6 modules
> > but got only added later as part of the V1.1x re-design. For this
> > purposes I added
> > imx6qdl-colibri-v1.1.dtsi for this particular re-designed version.
> 
> The vgen3 regulator node can be available in the imx6qdl-colibri.dtsi 
> even
> if it isn't used on the v1.0. The comment should highlight that.
> 
> > Another issue is that a proper pinctrl and power configuration
> > should
> > be provided for usdhc1 to support UHS-I feature, which is done in
> > Carier
> > board-level, this is why a separate DTS file (specifically for
> > Colibri iMX6 v1.1 SoM) was introduced.
> 
> The last dts node will override/expand the underlying nodes. The
> 'no-1-8-v' should be moved to the v1.0 dts or you need to add
> '/delete-property/ no-1-8-v' to your v1.1 dts. All other properties
> will
> exapand the node.

While that is true such constructs just confuse most of our customers.
We really like to keep it as simple as possible.

> > I understand your objection here, but unfortunately I have to
> > follow
> > this hierarchy.
> 
> Pleas check my above comments. Your patche duplicates a lot of code
> which is common.

While true this is much easier to understand and for our customers to
further customise.

> > As a trade-off some common parts can be moved to SoM-level common
> > dtsi file,
> > something like imx6qdl-colibri-common.dtsi, and then introduce two
> > dtsi files
> > for 1.0 and 1.1 versions of this SoM(imx6qdl-colibri-v1.0.dtsi and
> > imx6qdl-colibri-v1.1.dtsi
> > accordingly).

Yes, but that even introduces one more level while most customers do
not even understand the basic SoC, SoM, carrier board levels.

> Please check my above comments.
> 
> Regards,
>   Marco

Cheers

Marcel

> > > 8<-------------------------------------------------
> > > // SPDX-License-Identifier: GPL-2.0+ OR X11
> > > /*
> > >  * Copyright 2019 Toradex AG
> > >  */
> > > 
> > > #inculde "imx6dl-colibri-eval-v3.dts"
> > > 
> > > / {
> > >         model = "Toradex Colibri iMX6DL/S V1.1 on Colibri
> > > Evaluation Board V3";
> > > };
> > > 
> > > &iomuxc {
> > >         pinctrl_usdhc1_100mhz: usdhc1grp100mhz {
> > >                 fsl,pins = <
> > >                         MX6QDL_PAD_SD1_CMD__SD1_CMD    0x170b1
> > >                         MX6QDL_PAD_SD1_CLK__SD1_CLK    0x100b1
> > >                         MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x170b1
> > >                         MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x170b1
> > >                         MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x170b1
> > >                         MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x170b1
> > >                 >;
> > >         };
> > > 
> > >         pinctrl_usdhc1_200mhz: usdhc1grp200mhz {
> > >                 fsl,pins = <
> > >                         MX6QDL_PAD_SD1_CMD__SD1_CMD    0x170f1
> > >                         MX6QDL_PAD_SD1_CLK__SD1_CLK    0x100f1
> > >                         MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x170f1
> > >                         MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x170f1
> > >                         MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x170f1
> > >                         MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x170f1
> > >                 >;
> > >         };
> > > };
> > > 
> > > /* Colibri MMC */
> > > &usdhc1 {
> > >         pinctrl-names = "default", "state_100mhz",
> > > "state_200mhz";
> > >         pinctrl-0 = <&pinctrl_usdhc1 &pinctrl_mmc_cd>;
> > >         pinctrl-1 = <&pinctrl_usdhc1_100mhz &pinctrl_mmc_cd>;
> > >         pinctrl-2 = <&pinctrl_usdhc1_200mhz &pinctrl_mmc_cd>;
> > >         vmmc-supply = <&reg_module_3v3>;
> > >         vqmmc-supply = <&vgen3_reg>;
> > >         bus-width = <4>;
> > >         cd-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>; /* MMCD */
> > >         disable-wp;
> > >         enable-sdio-wakeup;
> > >         keep-power-in-suspend;
> > >         sd-uhs-sdr12;
> > >         sd-uhs-sdr25;
> > >         sd-uhs-sdr50;
> > >         sd-uhs-sdr104;
> > >         status = "disabled";
> > > };
> > > 8<-------------------------------------------------
> > > 
> > > The vgen3_reg update should be done on the imx6qdl-colibri.dtsi.
> > > 
> > > I hope this will help you.
> > > 
> > > Regards,
> > >   Marco
> > > 
> > > > +
> > > > +/ {
> > > > +     model = "Toradex Colibri iMX6DL/S V1.1 on Colibri
> > > > Evaluation Board V3";
> > > > +     compatible = "toradex,colibri_imx6dl-eval-v3",
> > > > "toradex,colibri_imx6dl",
> > > > +                  "fsl,imx6dl";
> > > > +
> > > > +     /* Will be filled by the bootloader */
> > > > +     memory@10000000 {
> > > > +             device_type = "memory";
> > > > +             reg = <0x10000000 0>;
> > > > +     };
> > > > +
> > > > +     aliases {
> > > > +             i2c0 = &i2c2;
> > > > +             i2c1 = &i2c3;
> > > > +     };
> > > > +
> > > > +     aliases {
> > > > +             rtc0 = &rtc_i2c;
> > > > +             rtc1 = &snvs_rtc;
> > > > +     };
> > > > +
> > > > +     chosen {
> > > > +             stdout-path = "serial0:115200n8";
> > > > +     };
> > > > +
> > > > +     /* Fixed crystal dedicated to mcp251x */
> > > > +     clk16m: clock-16m {
> > > > +             compatible = "fixed-clock";
> > > > +             #clock-cells = <0>;
> > > > +             clock-frequency = <16000000>;
> > > > +             clock-output-names = "clk16m";
> > > > +     };
> > > > +
> > > > +     gpio-keys {
> > > > +             compatible = "gpio-keys";
> > > > +             pinctrl-names = "default";
> > > > +             pinctrl-0 = <&pinctrl_gpio_keys>;
> > > > +
> > > > +             wakeup {
> > > > +                     label = "Wake-Up";
> > > > +                     gpios = <&gpio2 22 GPIO_ACTIVE_HIGH>; /*
> > > > SODIMM 45 */
> > > > +                     linux,code = <KEY_WAKEUP>;
> > > > +                     debounce-interval = <10>;
> > > > +                     wakeup-source;
> > > > +             };
> > > > +     };
> > > > +
> > > > +     lcd_display: disp0 {
> > > > +             compatible = "fsl,imx-parallel-display";
> > > > +             #address-cells = <1>;
> > > > +             #size-cells = <0>;
> > > > +             interface-pix-fmt = "bgr666";
> > > > +             pinctrl-names = "default";
> > > > +             pinctrl-0 = <&pinctrl_ipu1_lcdif>;
> > > > +             status = "okay";
> > > > +
> > > > +             port@0 {
> > > > +                     reg = <0>;
> > > > +
> > > > +                     lcd_display_in: endpoint {
> > > > +                             remote-endpoint =
> > > > <&ipu1_di0_disp0>;
> > > > +                     };
> > > > +             };
> > > > +
> > > > +             port@1 {
> > > > +                     reg = <1>;
> > > > +
> > > > +                     lcd_display_out: endpoint {
> > > > +                             remote-endpoint =
> > > > <&lcd_panel_in>;
> > > > +                     };
> > > > +             };
> > > > +     };
> > > > +
> > > > +     panel: panel {
> > > > +             /*
> > > > +              * edt,et057090dhu: EDT 5.7" LCD TFT
> > > > +              * edt,et070080dh6: EDT 7.0" LCD TFT
> > > > +              */
> > > > +             compatible = "edt,et057090dhu";
> > > > +             backlight = <&backlight>;
> > > > +
> > > > +             port {
> > > > +                     lcd_panel_in: endpoint {
> > > > +                             remote-endpoint =
> > > > <&lcd_display_out>;
> > > > +                     };
> > > > +             };
> > > > +     };
> > > > +};
> > > > +
> > > > +&backlight {
> > > > +     brightness-levels = <0 127 191 223 239 247 251 255>;
> > > > +     default-brightness-level = <1>;
> > > > +     status = "okay";
> > > > +};
> > > > +
> > > > +/* Colibri SSP */
> > > > +&ecspi4 {
> > > > +     status = "okay";
> > > > +
> > > > +     mcp251x0: mcp251x@0 {
> > > > +             compatible = "microchip,mcp2515";
> > > > +             reg = <0>;
> > > > +             clocks = <&clk16m>;
> > > > +             interrupt-parent = <&gpio3>;
> > > > +             interrupts = <27 0x2>;
> > > > +             spi-max-frequency = <10000000>;
> > > > +             status = "okay";
> > > > +     };
> > > > +};
> > > > +
> > > > +&hdmi {
> > > > +     status = "okay";
> > > > +};
> > > > +
> > > > +/*
> > > > + * Colibri I2C: I2C3_SDA/SCL on SODIMM 194/196 (e.g. RTC on
> > > > carrier board)
> > > > + */
> > > > +&i2c3 {
> > > > +     status = "okay";
> > > > +
> > > > +     /* M41T0M6 real time clock on carrier board */
> > > > +     rtc_i2c: rtc@68 {
> > > > +             compatible = "st,m41t0";
> > > > +             reg = <0x68>;
> > > > +     };
> > > > +};
> > > > +
> > > > +&ipu1_di0_disp0 {
> > > > +     remote-endpoint = <&lcd_display_in>;
> > > > +};
> > > > +
> > > > +&pwm1 {
> > > > +     status = "okay";
> > > > +};
> > > > +
> > > > +&pwm2 {
> > > > +     status = "okay";
> > > > +};
> > > > +
> > > > +&pwm3 {
> > > > +     status = "okay";
> > > > +};
> > > > +
> > > > +&pwm4 {
> > > > +     status = "okay";
> > > > +};
> > > > +
> > > > +&reg_usb_host_vbus {
> > > > +     status = "okay";
> > > > +};
> > > > +
> > > > +&uart1 {
> > > > +     status = "okay";
> > > > +};
> > > > +
> > > > +&uart2 {
> > > > +     status = "okay";
> > > > +};
> > > > +
> > > > +&uart3 {
> > > > +     status = "okay";
> > > > +};
> > > > +
> > > > +&usbh1 {
> > > > +     vbus-supply = <&reg_usb_host_vbus>;
> > > > +     status = "okay";
> > > > +};
> > > > +
> > > > +&usbotg {
> > > > +     status = "okay";
> > > > +};
> > > > +
> > > > +/* Colibri MMC */
> > > > +&usdhc1 {
> > > > +     status = "okay";
> > > > +};
> > > > +
> > > > +&weim {
> > > > +     status = "okay";
> > > > +
> > > > +     /* weim memory map: 32MB on CS0, CS1, CS2 and CS3 */
> > > > +     ranges = <0 0 0x08000000 0x02000000
> > > > +               1 0 0x0a000000 0x02000000
> > > > +               2 0 0x0c000000 0x02000000
> > > > +               3 0 0x0e000000 0x02000000>;
> > > > +
> > > > +     /* SRAM on Colibri nEXT_CS0 */
> > > > +     sram@0,0 {
> > > > +             compatible = "cypress,cy7c1019dv33-10zsxi, mtd-
> > > > ram";
> > > > +             reg = <0 0 0x00010000>;
> > > > +             #address-cells = <1>;
> > > > +             #size-cells = <1>;
> > > > +             bank-width = <2>;
> > > > +             fsl,weim-cs-timing = <0x00010081 0x00000000
> > > > 0x04000000
> > > > +                                   0x00000000 0x04000040
> > > > 0x00000000>;
> > > > +     };
> > > > +
> > > > +     /* SRAM on Colibri nEXT_CS1 */
> > > > +     sram@1,0 {
> > > > +             compatible = "cypress,cy7c1019dv33-10zsxi, mtd-
> > > > ram";
> > > > +             reg = <1 0 0x00010000>;
> > > > +             #address-cells = <1>;
> > > > +             #size-cells = <1>;
> > > > +             bank-width = <2>;
> > > > +             fsl,weim-cs-timing = <0x00010081 0x00000000
> > > > 0x04000000
> > > > +                                   0x00000000 0x04000040
> > > > 0x00000000>;
> > > > +     };
> > > > +};
> > > > diff --git a/arch/arm/boot/dts/imx6qdl-colibri-v1.1.dtsi
> > > > b/arch/arm/boot/dts/imx6qdl-colibri-v1.1.dtsi
> > > > new file mode 100644
> > > > index 000000000000..e40819f05c81
> > > > --- /dev/null
> > > > +++ b/arch/arm/boot/dts/imx6qdl-colibri-v1.1.dtsi
> > > > @@ -0,0 +1,852 @@
> > > > +// SPDX-License-Identifier: GPL-2.0+ OR X11
> > > > +/*
> > > > + * Copyright 2019 Toradex AG
> > > > + */
> > > > +#include <dt-bindings/gpio/gpio.h>
> > > > +
> > > > +/ {
> > > > +     model = "Toradex Colibri iMX6DL/S V1.1 Module";
> > > > +     compatible = "toradex,colibri_imx6dl", "fsl,imx6dl";
> > > > +
> > > > +     backlight: backlight {
> > > > +             compatible = "pwm-backlight";
> > > > +             pinctrl-names = "default";
> > > > +             pinctrl-0 = <&pinctrl_gpio_bl_on>;
> > > > +             pwms = <&pwm3 0 5000000>;
> > > > +             enable-gpios = <&gpio3 26 GPIO_ACTIVE_HIGH>; /*
> > > > Colibri BL_ON */
> > > > +             status = "disabled";
> > > > +     };
> > > > +
> > > > +     reg_module_3v3: regulator-module-3v3 {
> > > > +             compatible = "regulator-fixed";
> > > > +             regulator-name = "+V3.3";
> > > > +             regulator-min-microvolt = <3300000>;
> > > > +             regulator-max-microvolt = <3300000>;
> > > > +             regulator-always-on;
> > > > +     };
> > > > +
> > > > +     reg_module_3v3_audio: regulator-module-3v3-audio {
> > > > +             compatible = "regulator-fixed";
> > > > +             regulator-name = "+V3.3_AUDIO";
> > > > +             regulator-min-microvolt = <3300000>;
> > > > +             regulator-max-microvolt = <3300000>;
> > > > +             regulator-always-on;
> > > > +     };
> > > > +
> > > > +     reg_usb_host_vbus: regulator-usb-host-vbus {
> > > > +             compatible = "regulator-fixed";
> > > > +             pinctrl-names = "default";
> > > > +             pinctrl-0 = <&pinctrl_regulator_usbh_pwr>;
> > > > +             regulator-name = "usb_host_vbus";
> > > > +             regulator-min-microvolt = <5000000>;
> > > > +             regulator-max-microvolt = <5000000>;
> > > > +             gpio = <&gpio3 31 GPIO_ACTIVE_HIGH>; /* USBH_PEN
> > > > */
> > > > +             status = "disabled";
> > > > +     };
> > > > +
> > > > +     sound {
> > > > +             compatible = "fsl,imx-audio-sgtl5000";
> > > > +             model = "imx6dl-colibri-sgtl5000";
> > > > +             ssi-controller = <&ssi1>;
> > > > +             audio-codec = <&codec>;
> > > > +             audio-routing =
> > > > +                     "Headphone Jack", "HP_OUT",
> > > > +                     "LINE_IN", "Line In Jack",
> > > > +                     "MIC_IN", "Mic Jack",
> > > > +                     "Mic Jack", "Mic Bias";
> > > > +             mux-int-port = <1>;
> > > > +             mux-ext-port = <5>;
> > > > +     };
> > > > +
> > > > +     /* Optional S/PDIF in on SODIMM 88 and out on SODIMM 90,
> > > > 137 or 168 */
> > > > +     sound_spdif: sound-spdif {
> > > > +             compatible = "fsl,imx-audio-spdif";
> > > > +             model = "imx-spdif";
> > > > +             spdif-controller = <&spdif>;
> > > > +             spdif-in;
> > > > +             spdif-out;
> > > > +             status = "disabled";
> > > > +     };
> > > > +};
> > > > +
> > > > +&audmux {
> > > > +     pinctrl-names = "default";
> > > > +     pinctrl-0 = <&pinctrl_audmux &pinctrl_mic_gnd>;
> > > > +     status = "okay";
> > > > +};
> > > > +
> > > > +/* Optional on SODIMM 55/63 */
> > > > +&can1 {
> > > > +     pinctrl-names = "default";
> > > > +     pinctrl-0 = <&pinctrl_flexcan1>;
> > > > +     status = "disabled";
> > > > +};
> > > > +
> > > > +/* Optional on SODIMM 178/188 */
> > > > +&can2 {
> > > > +     pinctrl-names = "default";
> > > > +     pinctrl-0 = <&pinctrl_flexcan2>;
> > > > +     status = "disabled";
> > > > +};
> > > > +
> > > > +/* Colibri SSP */
> > > > +&ecspi4 {
> > > > +     cs-gpios = <&gpio5 2 GPIO_ACTIVE_HIGH>;
> > > > +     pinctrl-names = "default";
> > > > +     pinctrl-0 = <&pinctrl_ecspi4>;
> > > > +     status = "disabled";
> > > > +};
> > > > +
> > > > +&fec {
> > > > +     pinctrl-names = "default";
> > > > +     pinctrl-0 = <&pinctrl_enet>;
> > > > +     phy-mode = "rmii";
> > > > +     status = "okay";
> > > > +};
> > > > +
> > > > +&hdmi {
> > > > +     pinctrl-names = "default";
> > > > +     pinctrl-0 = <&pinctrl_hdmi_ddc>;
> > > > +     status = "disabled";
> > > > +};
> > > > +
> > > > +/*
> > > > + * PWR_I2C: power I2C to audio codec, PMIC, temperature sensor
> > > > and
> > > > + * touch screen controller
> > > > + */
> > > > +&i2c2 {
> > > > +     clock-frequency = <100000>;
> > > > +     pinctrl-names = "default";
> > > > +     pinctrl-0 = <&pinctrl_i2c2>;
> > > > +     status = "okay";
> > > > +
> > > > +     pmic: pfuze100@8 {
> > > > +             compatible = "fsl,pfuze100";
> > > > +             reg = <0x08>;
> > > > +
> > > > +             regulators {
> > > > +                     sw1a_reg: sw1ab {
> > > > +                             regulator-min-microvolt =
> > > > <300000>;
> > > > +                             regulator-max-microvolt =
> > > > <1875000>;
> > > > +                             regulator-boot-on;
> > > > +                             regulator-always-on;
> > > > +                             regulator-ramp-delay = <6250>;
> > > > +                     };
> > > > +
> > > > +                     sw1c_reg: sw1c {
> > > > +                             regulator-min-microvolt =
> > > > <300000>;
> > > > +                             regulator-max-microvolt =
> > > > <1875000>;
> > > > +                             regulator-boot-on;
> > > > +                             regulator-always-on;
> > > > +                             regulator-ramp-delay = <6250>;
> > > > +                     };
> > > > +
> > > > +                     sw3a_reg: sw3a {
> > > > +                             regulator-min-microvolt =
> > > > <400000>;
> > > > +                             regulator-max-microvolt =
> > > > <1975000>;
> > > > +                             regulator-boot-on;
> > > > +                             regulator-always-on;
> > > > +                     };
> > > > +
> > > > +                     swbst_reg: swbst {
> > > > +                             regulator-min-microvolt =
> > > > <5000000>;
> > > > +                             regulator-max-microvolt =
> > > > <5150000>;
> > > > +                             regulator-boot-on;
> > > > +                             regulator-always-on;
> > > > +                     };
> > > > +
> > > > +                     snvs_reg: vsnvs {
> > > > +                             regulator-min-microvolt =
> > > > <1000000>;
> > > > +                             regulator-max-microvolt =
> > > > <3000000>;
> > > > +                             regulator-boot-on;
> > > > +                             regulator-always-on;
> > > > +                     };
> > > > +
> > > > +                     vref_reg: vrefddr {
> > > > +                             regulator-boot-on;
> > > > +                             regulator-always-on;
> > > > +                     };
> > > > +
> > > > +                     /* vgen1: unused */
> > > > +
> > > > +                     vgen2_reg: vgen2 {
> > > > +                             regulator-min-microvolt =
> > > > <800000>;
> > > > +                             regulator-max-microvolt =
> > > > <1550000>;
> > > > +                             regulator-boot-on;
> > > > +                             regulator-always-on;
> > > > +                     };
> > > > +
> > > > +                     /*
> > > > +                      * +V3.3_1.8_SD1 coming off VGEN3 and
> > > > supplying
> > > > +                      * the i.MX 6 NVCC_SD1.
> > > > +                      */
> > > > +                     vgen3_reg: vgen3 {
> > > > +                             regulator-min-microvolt =
> > > > <1800000>;
> > > > +                             regulator-max-microvolt =
> > > > <3300000>;
> > > > +                             regulator-boot-on;
> > > > +                     };
> > > > +
> > > > +                     vgen4_reg: vgen4 {
> > > > +                             regulator-min-microvolt =
> > > > <1800000>;
> > > > +                             regulator-max-microvolt =
> > > > <1800000>;
> > > > +                             regulator-boot-on;
> > > > +                             regulator-always-on;
> > > > +                     };
> > > > +
> > > > +                     vgen5_reg: vgen5 {
> > > > +                             regulator-min-microvolt =
> > > > <1800000>;
> > > > +                             regulator-max-microvolt =
> > > > <3300000>;
> > > > +                             regulator-boot-on;
> > > > +                             regulator-always-on;
> > > > +                     };
> > > > +
> > > > +                     vgen6_reg: vgen6 {
> > > > +                             regulator-min-microvolt =
> > > > <1800000>;
> > > > +                             regulator-max-microvolt =
> > > > <3300000>;
> > > > +                             regulator-boot-on;
> > > > +                             regulator-always-on;
> > > > +                     };
> > > > +             };
> > > > +     };
> > > > +
> > > > +     codec: sgtl5000@a {
> > > > +             compatible = "fsl,sgtl5000";
> > > > +             reg = <0x0a>;
> > > > +             clocks = <&clks IMX6QDL_CLK_CKO>;
> > > > +             VDDA-supply = <&reg_module_3v3_audio>;
> > > > +             VDDIO-supply = <&reg_module_3v3>;
> > > > +             VDDD-supply = <&vgen4_reg>;
> > > > +             lrclk-strength = <3>;
> > > > +     };
> > > > +
> > > > +     /* STMPE811 touch screen controller */
> > > > +     stmpe811@41 {
> > > > +             compatible = "st,stmpe811";
> > > > +             pinctrl-names = "default";
> > > > +             pinctrl-0 = <&pinctrl_touch_int>;
> > > > +             reg = <0x41>;
> > > > +             interrupts = <20 IRQ_TYPE_LEVEL_LOW>;
> > > > +             interrupt-parent = <&gpio6>;
> > > > +             interrupt-controller;
> > > > +             id = <0>;
> > > > +             blocks = <0x5>;
> > > > +             irq-trigger = <0x1>;
> > > > +             /* 3.25 MHz ADC clock speed */
> > > > +             st,adc-freq = <1>;
> > > > +             /* 12-bit ADC */
> > > > +             st,mod-12b = <1>;
> > > > +             /* internal ADC reference */
> > > > +             st,ref-sel = <0>;
> > > > +             /* ADC conversion time: 80 clocks */
> > > > +             st,sample-time = <4>;
> > > > +
> > > > +             stmpe_touchscreen {
> > > > +                     compatible = "st,stmpe-ts";
> > > > +                     /* 8 sample average control */
> > > > +                     st,ave-ctrl = <3>;
> > > > +                     /* 7 length fractional part in z */
> > > > +                     st,fraction-z = <7>;
> > > > +                     /*
> > > > +                      * 50 mA typical 80 mA max touchscreen
> > > > drivers
> > > > +                      * current limit value
> > > > +                      */
> > > > +                     st,i-drive = <1>;
> > > > +                     /* 1 ms panel driver settling time */
> > > > +                     st,settling = <3>;
> > > > +                     /* 5 ms touch detect interrupt delay */
> > > > +                     st,touch-det-delay = <5>;
> > > > +             };
> > > > +
> > > > +             stmpe_adc {
> > > > +                     compatible = "st,stmpe-adc";
> > > > +                     /* forbid to use ADC channels 3-0 (touch)
> > > > */
> > > > +                     st,norequest-mask = <0x0F>;
> > > > +             };
> > > > +     };
> > > > +};
> > > > +
> > > > +/*
> > > > + * I2C3_SDA/SCL on SODIMM 194/196 (e.g. RTC on carrier board)
> > > > + */
> > > > +&i2c3 {
> > > > +     clock-frequency = <100000>;
> > > > +     pinctrl-names = "default", "recovery";
> > > > +     pinctrl-0 = <&pinctrl_i2c3>;
> > > > +     pinctrl-1 = <&pinctrl_i2c3_recovery>;
> > > > +     scl-gpios = <&gpio1 3 (GPIO_ACTIVE_HIGH |
> > > > GPIO_OPEN_DRAIN)>;
> > > > +     sda-gpios = <&gpio1 6 (GPIO_ACTIVE_HIGH |
> > > > GPIO_OPEN_DRAIN)>;
> > > > +     status = "disabled";
> > > > +};
> > > > +
> > > > +/* Colibri PWM<B> */
> > > > +&pwm1 {
> > > > +     pinctrl-names = "default";
> > > > +     pinctrl-0 = <&pinctrl_pwm1>;
> > > > +     status = "disabled";
> > > > +};
> > > > +
> > > > +/* Colibri PWM<D> */
> > > > +&pwm2 {
> > > > +     pinctrl-names = "default";
> > > > +     pinctrl-0 = <&pinctrl_pwm2>;
> > > > +     status = "disabled";
> > > > +};
> > > > +
> > > > +/* Colibri PWM<A> */
> > > > +&pwm3 {
> > > > +     pinctrl-names = "default";
> > > > +     pinctrl-0 = <&pinctrl_pwm3>;
> > > > +     status = "disabled";
> > > > +};
> > > > +
> > > > +/* Colibri PWM<C> */
> > > > +&pwm4 {
> > > > +     pinctrl-names = "default";
> > > > +     pinctrl-0 = <&pinctrl_pwm4>;
> > > > +     status = "disabled";
> > > > +};
> > > > +
> > > > +/* Optional S/PDIF out on SODIMM 137 */
> > > > +&spdif {
> > > > +     pinctrl-names = "default";
> > > > +     pinctrl-0 = <&pinctrl_spdif>;
> > > > +     status = "disabled";
> > > > +};
> > > > +
> > > > +&ssi1 {
> > > > +     status = "okay";
> > > > +};
> > > > +
> > > > +/* Colibri UART_A */
> > > > +&uart1 {
> > > > +     pinctrl-names = "default";
> > > > +     pinctrl-0 = <&pinctrl_uart1_dte &pinctrl_uart1_ctrl>;
> > > > +     fsl,dte-mode;
> > > > +     uart-has-rtscts;
> > > > +     status = "disabled";
> > > > +};
> > > > +
> > > > +/* Colibri UART_B */
> > > > +&uart2 {
> > > > +     pinctrl-names = "default";
> > > > +     pinctrl-0 = <&pinctrl_uart2_dte>;
> > > > +     fsl,dte-mode;
> > > > +     uart-has-rtscts;
> > > > +     status = "disabled";
> > > > +};
> > > > +
> > > > +/* Colibri UART_C */
> > > > +&uart3 {
> > > > +     pinctrl-names = "default";
> > > > +     pinctrl-0 = <&pinctrl_uart3_dte>;
> > > > +     fsl,dte-mode;
> > > > +     status = "disabled";
> > > > +};
> > > > +
> > > > +&usbotg {
> > > > +     pinctrl-names = "default";
> > > > +     disable-over-current;
> > > > +     dr_mode = "peripheral";
> > > > +     status = "disabled";
> > > > +};
> > > > +
> > > > +/* Colibri MMC */
> > > > +&usdhc1 {
> > > > +     pinctrl-names = "default", "state_100mhz",
> > > > "state_200mhz";
> > > > +     pinctrl-0 = <&pinctrl_usdhc1 &pinctrl_mmc_cd>;
> > > > +     pinctrl-1 = <&pinctrl_usdhc1_100mhz &pinctrl_mmc_cd>;
> > > > +     pinctrl-2 = <&pinctrl_usdhc1_200mhz &pinctrl_mmc_cd>;
> > > > +     vmmc-supply = <&reg_module_3v3>;
> > > > +     vqmmc-supply = <&vgen3_reg>;
> > > > +     bus-width = <4>;
> > > > +     cd-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>; /* MMCD */
> > > > +     disable-wp;
> > > > +     enable-sdio-wakeup;
> > > > +     keep-power-in-suspend;
> > > > +     sd-uhs-sdr12;
> > > > +     sd-uhs-sdr25;
> > > > +     sd-uhs-sdr50;
> > > > +     sd-uhs-sdr104;
> > > > +     status = "disabled";
> > > > +};
> > > > +
> > > > +/* eMMC */
> > > > +&usdhc3 {
> > > > +     pinctrl-names = "default";
> > > > +     pinctrl-0 = <&pinctrl_usdhc3>;
> > > > +     vqmmc-supply = <&reg_module_3v3>;
> > > > +     bus-width = <8>;
> > > > +     no-1-8-v;
> > > > +     non-removable;
> > > > +     status = "okay";
> > > > +};
> > > > +
> > > > +&weim {
> > > > +     pinctrl-names = "default";
> > > > +     pinctrl-0 = <&pinctrl_weim_sram  &pinctrl_weim_cs0
> > > > +                  &pinctrl_weim_cs1   &pinctrl_weim_cs2
> > > > +                  &pinctrl_weim_rdnwr &pinctrl_weim_npwe>;
> > > > +     #address-cells = <2>;
> > > > +     #size-cells = <1>;
> > > > +     status = "disabled";
> > > > +};
> > > > +
> > > > +&iomuxc {
> > > > +     pinctrl_audmux: audmuxgrp {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_KEY_COL0__AUD5_TXC   0x130b0
> > > > +                     MX6QDL_PAD_KEY_ROW0__AUD5_TXD   0x130b0
> > > > +                     MX6QDL_PAD_KEY_COL1__AUD5_TXFS  0x130b0
> > > > +                     MX6QDL_PAD_KEY_ROW1__AUD5_RXD   0x130b0
> > > > +                     /* SGTL5000 sys_mclk */
> > > > +                     MX6QDL_PAD_GPIO_0__CCM_CLKO1    0x000b0
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_cam_mclk: cammclkgrp {
> > > > +             fsl,pins = <
> > > > +                     /* Parallel Camera CAM sys_mclk */
> > > > +                     MX6QDL_PAD_NANDF_CS2__CCM_CLKO2 0x00b0
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_ecspi4: ecspi4grp {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_EIM_D22__ECSPI4_MISO 0x100b1
> > > > +                     MX6QDL_PAD_EIM_D28__ECSPI4_MOSI 0x100b1
> > > > +                     MX6QDL_PAD_EIM_D21__ECSPI4_SCLK 0x100b1
> > > > +                     /* SPI CS */
> > > > +                     MX6QDL_PAD_EIM_A25__GPIO5_IO02  0x000b1
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_enet: enetgrp {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_ENET_MDC__ENET_MDC           0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_ENET_MDIO__ENET_MDIO         0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_ENET_RXD0__ENET_RX_DATA0     0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_ENET_RXD1__ENET_RX_DATA1     0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_ENET_RX_ER__ENET_RX_ER       0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN       0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_ENET_TXD0__ENET_TX_DATA0     0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_ENET_TXD1__ENET_TX_DATA1     0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_ENET_CRS_DV__ENET_RX_EN      0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_GPIO_16__ENET_REF_CLK     ((1<
> > > > <30) | 0x1b0b0)
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_flexcan1: flexcan1grp {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_GPIO_7__FLEXCAN1_TX          0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_GPIO_8__FLEXCAN1_RX          0
> > > > x1b0b0
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_flexcan2: flexcan2grp {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_KEY_COL4__FLEXCAN2_TX        0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_KEY_ROW4__FLEXCAN2_RX        0
> > > > x1b0b0
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_gpio_bl_on: gpioblon {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_EIM_D26__GPIO3_IO26          0
> > > > x1b0b0
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_gpio_keys: gpiokeys {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_EIM_A16__GPIO2_IO22          0
> > > > x130b0
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_hdmi_ddc: hdmiddcgrp {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_KEY_COL3__HDMI_TX_DDC_SCL
> > > > 0x4001b8b1
> > > > +                     MX6QDL_PAD_KEY_ROW3__HDMI_TX_DDC_SDA
> > > > 0x4001b8b1
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_i2c2: i2c2grp {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1
> > > > +                     MX6QDL_PAD_EIM_D16__I2C2_SDA 0x4001b8b1
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_i2c3: i2c3grp {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1
> > > > +                     MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_i2c3_recovery: i2c3recoverygrp {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_GPIO_3__GPIO1_IO03 0x4001b8b1
> > > > +                     MX6QDL_PAD_GPIO_6__GPIO1_IO06 0x4001b8b1
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_ipu1_csi0: ipu1csi0grp { /* Parallel Camera */
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_EIM_A17__IPU1_CSI1_DATA12    0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_A18__IPU1_CSI1_DATA13    0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_A19__IPU1_CSI1_DATA14    0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_A20__IPU1_CSI1_DATA15    0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_A21__IPU1_CSI1_DATA16    0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_A22__IPU1_CSI1_DATA17    0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_A23__IPU1_CSI1_DATA18    0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_A24__IPU1_CSI1_DATA19    0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_D17__IPU1_CSI1_PIXCLK    0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_EB3__IPU1_CSI1_HSYNC     0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_D29__IPU1_CSI1_VSYNC     0
> > > > xb0b1
> > > > +                     /* Disable PWM pins on camera interface
> > > > */
> > > > +                     MX6QDL_PAD_SD4_DAT1__GPIO2_IO09         0
> > > > x40
> > > > +                     MX6QDL_PAD_GPIO_1__GPIO1_IO01           0
> > > > x40
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_ipu1_lcdif: ipu1lcdifgrp {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CL
> > > > K      0xa1
> > > > +                     MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15     
> > > >        0xa1
> > > > +                     MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02      
> > > >        0xa1
> > > > +                     MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03      
> > > >        0xa1
> > > > +                     MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 
> > > >        0xa1
> > > > +                     MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 
> > > >        0xa1
> > > > +                     MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 
> > > >        0xa1
> > > > +                     MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 
> > > >        0xa1
> > > > +                     MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 
> > > >        0xa1
> > > > +                     MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 
> > > >        0xa1
> > > > +                     MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 
> > > >        0xa1
> > > > +                     MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 
> > > >        0xa1
> > > > +                     MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 
> > > >        0xa1
> > > > +                     MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 
> > > >        0xa1
> > > > +                     MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10
> > > >        0xa1
> > > > +                     MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11
> > > >        0xa1
> > > > +                     MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12
> > > >        0xa1
> > > > +                     MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13
> > > >        0xa1
> > > > +                     MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14
> > > >        0xa1
> > > > +                     MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15
> > > >        0xa1
> > > > +                     MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16
> > > >        0xa1
> > > > +                     MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17
> > > >        0xa1
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_mic_gnd: gpiomicgnd {
> > > > +             fsl,pins = <
> > > > +                     /* Controls Mic GND, PU or '1' pull Mic
> > > > GND to GND */
> > > > +                     MX6QDL_PAD_RGMII_TD1__GPIO6_IO21 0x1b0b0
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_mmc_cd: gpiommccd {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_NANDF_D5__GPIO2_IO05 0x1b0b1
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_pwm1: pwm1grp {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_GPIO_9__PWM1_OUT     0x1b0b1
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_pwm2: pwm2grp {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_GPIO_1__PWM2_OUT     0x1b0b1
> > > > +                     MX6QDL_PAD_EIM_A21__GPIO2_IO17  0x00040
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_pwm3: pwm3grp {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_SD4_DAT1__PWM3_OUT   0x1b0b1
> > > > +                     MX6QDL_PAD_EIM_A22__GPIO2_IO16  0x00040
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_pwm4: pwm4grp {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_SD4_DAT2__PWM4_OUT   0x1b0b1
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_regulator_usbh_pwr: gpioregusbhpwrgrp {
> > > > +             fsl,pins = <
> > > > +                     /* USBH_EN */
> > > > +                     MX6QDL_PAD_EIM_D31__GPIO3_IO31  0x0f058
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_spdif: spdifgrp {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x1b0b0
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_touch_int: gpiotouchintgrp {
> > > > +             fsl,pins = <
> > > > +                     /* STMPE811 interrupt */
> > > > +                     MX6QDL_PAD_RGMII_TD0__GPIO6_IO20 0x1b0b0
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_uart1_dce: uart1dcegrp {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA
> > > > 0x1b0b1
> > > > +                     MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA
> > > > 0x1b0b1
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     /* DTE mode */
> > > > +     pinctrl_uart1_dte: uart1dtegrp {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_CSI0_DAT10__UART1_RX_DATA
> > > > 0x1b0b1
> > > > +                     MX6QDL_PAD_CSI0_DAT11__UART1_TX_DATA
> > > > 0x1b0b1
> > > > +                     MX6QDL_PAD_EIM_D19__UART1_RTS_B 0x1b0b1
> > > > +                     MX6QDL_PAD_EIM_D20__UART1_CTS_B 0x1b0b1
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     /* Additional DTR, DSR, DCD */
> > > > +     pinctrl_uart1_ctrl: uart1ctrlgrp {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_EIM_D23__UART1_DCD_B 0x1b0b0
> > > > +                     MX6QDL_PAD_EIM_D24__UART1_DTR_B 0x1b0b0
> > > > +                     MX6QDL_PAD_EIM_D25__UART1_DSR_B 0x1b0b0
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_uart2_dte: uart2dtegrp {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_SD4_DAT4__UART2_TX_DATA      0
> > > > x1b0b1
> > > > +                     MX6QDL_PAD_SD4_DAT7__UART2_RX_DATA      0
> > > > x1b0b1
> > > > +                     MX6QDL_PAD_SD4_DAT6__UART2_RTS_B        0
> > > > x1b0b1
> > > > +                     MX6QDL_PAD_SD4_DAT5__UART2_CTS_B        0
> > > > x1b0b1
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_uart3_dte: uart3dtegrp {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_SD4_CLK__UART3_TX_DATA       0
> > > > x1b0b1
> > > > +                     MX6QDL_PAD_SD4_CMD__UART3_RX_DATA       0
> > > > x1b0b1
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_usbc_det: usbcdetgrp {
> > > > +             fsl,pins = <
> > > > +                     /* USBC_DET */
> > > > +                     MX6QDL_PAD_GPIO_17__GPIO7_IO12          0
> > > > x1b0b0
> > > > +                     /* USBC_DET_EN */
> > > > +                     MX6QDL_PAD_RGMII_TX_CTL__GPIO6_IO26     0
> > > > x0f058
> > > > +                     /* USBC_DET_OVERWRITE */
> > > > +                     MX6QDL_PAD_RGMII_RXC__GPIO6_IO30        0
> > > > x0f058
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_usdhc1: usdhc1grp {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_SD1_CMD__SD1_CMD     0x17071
> > > > +                     MX6QDL_PAD_SD1_CLK__SD1_CLK     0x10071
> > > > +                     MX6QDL_PAD_SD1_DAT0__SD1_DATA0  0x17071
> > > > +                     MX6QDL_PAD_SD1_DAT1__SD1_DATA1  0x17071
> > > > +                     MX6QDL_PAD_SD1_DAT2__SD1_DATA2  0x17071
> > > > +                     MX6QDL_PAD_SD1_DAT3__SD1_DATA3  0x17071
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_usdhc1_100mhz: usdhc1grp100mhz {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_SD1_CMD__SD1_CMD    0x170b1
> > > > +                     MX6QDL_PAD_SD1_CLK__SD1_CLK    0x100b1
> > > > +                     MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x170b1
> > > > +                     MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x170b1
> > > > +                     MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x170b1
> > > > +                     MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x170b1
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_usdhc1_200mhz: usdhc1grp200mhz {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_SD1_CMD__SD1_CMD    0x170f1
> > > > +                     MX6QDL_PAD_SD1_CLK__SD1_CLK    0x100f1
> > > > +                     MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x170f1
> > > > +                     MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x170f1
> > > > +                     MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x170f1
> > > > +                     MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x170f1
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_usdhc3: usdhc3grp {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_SD3_CMD__SD3_CMD     0x17059
> > > > +                     MX6QDL_PAD_SD3_CLK__SD3_CLK     0x10059
> > > > +                     MX6QDL_PAD_SD3_DAT0__SD3_DATA0  0x17059
> > > > +                     MX6QDL_PAD_SD3_DAT1__SD3_DATA1  0x17059
> > > > +                     MX6QDL_PAD_SD3_DAT2__SD3_DATA2  0x17059
> > > > +                     MX6QDL_PAD_SD3_DAT3__SD3_DATA3  0x17059
> > > > +                     MX6QDL_PAD_SD3_DAT4__SD3_DATA4  0x17059
> > > > +                     MX6QDL_PAD_SD3_DAT5__SD3_DATA5  0x17059
> > > > +                     MX6QDL_PAD_SD3_DAT6__SD3_DATA6  0x17059
> > > > +                     MX6QDL_PAD_SD3_DAT7__SD3_DATA7  0x17059
> > > > +                     /* eMMC reset */
> > > > +                     MX6QDL_PAD_SD3_RST__SD3_RESET   0x17059
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_weim_cs0: weimcs0grp {
> > > > +             fsl,pins = <
> > > > +                     /* nEXT_CS0 */
> > > > +                     MX6QDL_PAD_EIM_CS0__EIM_CS0_B   0xb0b1
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_weim_cs1: weimcs1grp {
> > > > +             fsl,pins = <
> > > > +                     /* nEXT_CS1 */
> > > > +                     MX6QDL_PAD_EIM_CS1__EIM_CS1_B   0xb0b1
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_weim_cs2: weimcs2grp {
> > > > +             fsl,pins = <
> > > > +                     /* nEXT_CS2 */
> > > > +                     MX6QDL_PAD_SD2_DAT1__EIM_CS2_B  0xb0b1
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_weim_sram: weimsramgrp {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_EIM_OE__EIM_OE_B             0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_RW__EIM_RW               0
> > > > xb0b1
> > > > +                     /* Data */
> > > > +                     MX6QDL_PAD_CSI0_DATA_EN__EIM_DATA00     0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_CSI0_VSYNC__EIM_DATA01       0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_CSI0_DAT4__EIM_DATA02        0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_CSI0_DAT5__EIM_DATA03        0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_CSI0_DAT6__EIM_DATA04        0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_CSI0_DAT7__EIM_DATA05        0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_CSI0_DAT8__EIM_DATA06        0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_CSI0_DAT9__EIM_DATA07        0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_CSI0_DAT12__EIM_DATA08       0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_CSI0_DAT13__EIM_DATA09       0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_CSI0_DAT14__EIM_DATA10       0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_CSI0_DAT15__EIM_DATA11       0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_CSI0_DAT16__EIM_DATA12       0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_CSI0_DAT17__EIM_DATA13       0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_CSI0_DAT18__EIM_DATA14       0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_CSI0_DAT19__EIM_DATA15       0
> > > > x1b0b0
> > > > +                     /* Address */
> > > > +                     MX6QDL_PAD_EIM_DA15__EIM_AD15           0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_DA14__EIM_AD14           0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_DA13__EIM_AD13           0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_DA12__EIM_AD12           0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_DA11__EIM_AD11           0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_DA10__EIM_AD10           0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_DA9__EIM_AD09            0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_DA8__EIM_AD08            0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_DA7__EIM_AD07            0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_DA6__EIM_AD06            0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_DA5__EIM_AD05            0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_DA4__EIM_AD04            0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_DA3__EIM_AD03            0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_DA2__EIM_AD02            0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_DA1__EIM_AD01            0
> > > > xb0b1
> > > > +                     MX6QDL_PAD_EIM_DA0__EIM_AD00            0
> > > > xb0b1
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_weim_rdnwr: weimrdnwr {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_SD2_CLK__GPIO1_IO10          0
> > > > x0040
> > > > +                     MX6QDL_PAD_RGMII_TD3__GPIO6_IO23        0
> > > > x130b0
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     pinctrl_weim_npwe: weimnpwe {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_SD2_DAT3__GPIO1_IO12         0
> > > > x0040
> > > > +                     MX6QDL_PAD_RGMII_TD2__GPIO6_IO22        0
> > > > x130b0
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     /* ADDRESS[16:18] [25] used as GPIO */
> > > > +     pinctrl_weim_gpio_1: weimgpio-1 {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_KEY_ROW4__GPIO4_IO15         0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_KEY_ROW2__GPIO4_IO11         0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_KEY_COL2__GPIO4_IO10         0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_DISP0_DAT23__GPIO5_IO17      0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_DISP0_DAT22__GPIO5_IO16      0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_DISP0_DAT21__GPIO5_IO15      0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_DISP0_DAT20__GPIO5_IO14      0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_DISP0_DAT19__GPIO5_IO13      0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_DISP0_DAT18__GPIO5_IO12      0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_NANDF_D1__GPIO2_IO01         0
> > > > x1b0b0
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     /* ADDRESS[19:24] used as GPIO */
> > > > +     pinctrl_weim_gpio_2: weimgpio-2 {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_KEY_ROW2__GPIO4_IO11         0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_KEY_COL2__GPIO4_IO10         0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_DISP0_DAT23__GPIO5_IO17      0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_DISP0_DAT22__GPIO5_IO16      0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_DISP0_DAT21__GPIO5_IO15      0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_DISP0_DAT20__GPIO5_IO14      0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_DISP0_DAT19__GPIO5_IO13      0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_DISP0_DAT18__GPIO5_IO12      0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_NANDF_D1__GPIO2_IO01         0
> > > > x1b0b0
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     /* DATA[16:31] used as GPIO */
> > > > +     pinctrl_weim_gpio_3: weimgpio-3 {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_EIM_LBA__GPIO2_IO27          0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_EIM_BCLK__GPIO6_IO31         0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_NANDF_CS3__GPIO6_IO16        0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_NANDF_CS1__GPIO6_IO14        0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_NANDF_RB0__GPIO6_IO10        0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_NANDF_ALE__GPIO6_IO08        0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_NANDF_WP_B__GPIO6_IO09       0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_NANDF_CS0__GPIO6_IO11        0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_NANDF_CLE__GPIO6_IO07        0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_GPIO_19__GPIO4_IO05          0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_CSI0_MCLK__GPIO5_IO19        0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_CSI0_PIXCLK__GPIO5_IO18      0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_GPIO_4__GPIO1_IO04           0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_GPIO_5__GPIO1_IO05           0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_GPIO_2__GPIO1_IO02           0
> > > > x1b0b0
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     /* DQM[0:3] used as GPIO */
> > > > +     pinctrl_weim_gpio_4: weimgpio-4 {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_EIM_EB0__GPIO2_IO28          0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_EIM_EB1__GPIO2_IO29          0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_SD2_DAT2__GPIO1_IO13         0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_NANDF_D0__GPIO2_IO00         0
> > > > x1b0b0
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     /* RDY used as GPIO */
> > > > +     pinctrl_weim_gpio_5: weimgpio-5 {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_EIM_WAIT__GPIO5_IO00         0
> > > > x1b0b0
> > > > +             >;
> > > > +     };
> > > > +
> > > > +     /* ADDRESS[16] DATA[30] used as GPIO */
> > > > +     pinctrl_weim_gpio_6: weimgpio-6 {
> > > > +             fsl,pins = <
> > > > +                     MX6QDL_PAD_KEY_ROW4__GPIO4_IO15         0
> > > > x1b0b0
> > > > +                     MX6QDL_PAD_KEY_COL4__GPIO4_IO14         0
> > > > x1b0b0
> > > > +             >;
> > > > +     };
> > > > +};
> > > > --
> > > > 2.17.1
> > > > 
> > > > 
> > > > 
> > > 
> > > --
> > > Pengutronix
> > > e.K.                           |                             |
> > > Industrial Linux Solutions                 | 
> > > http://www.pengutronix.de/  |
> > > Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-
> > > 206917-0    |
> > > Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-
> > > 206917-5555 |
> > 
> > Thanks for looking into this!
> > 
> > [1] https://patchwork.kernel.org/patch/10885309/
> > [2] https://developer.toradex.com/device-tree-customization
> > 
> > -- 
> > Best regards - Freundliche Grüsse - Meilleures salutations
> > 
> > Senior Development Engineer,
> > Igor Opaniuk
> > 
> > Toradex AG
> > Altsagenstrasse 5 | 6048 Horw/Luzern | Switzerland | T: +41 41 500
> > 48
> > 00 (main line)
> > _______________________________________________
> > linux-arm-kernel mailing list
> > linux-arm-kernel@lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH RFC v1 0/2] Amlogic 32-bit Meson SDHC MMC controller driver
From: Martin Blumenstingl @ 2019-07-08 17:33 UTC (permalink / raw)
  To: linux-amlogic, devicetree, linux-mmc, robh+dt, ulf.hansson,
	jianxin.pan
  Cc: linux-kernel, linux-arm-kernel, mark.rutland, Martin Blumenstingl

Hello,

this is RFC v1 of the attempt to upstream the driver for the "SDHC" MMC
controller found on Meson6, Meson8, Meson8b and Meson8m2 SoCs.

The public S805 (Meson8b) datasheet has some documentation starting on
page 74: [0]

The goal of this RFC v1 is to:
- find out how to set up the MMC clock correctly with Jianxin's help (see
  the description of patch #2 with questions)
- get feedback from the MMC maintainers to see which bits need changing


[0] https://dn.odroid.com/S805/Datasheet/S805_Datasheet%20V0.8%2020150126.pdf


Martin Blumenstingl (2):
  dt-bindings: mmc: Document the Amlogic Meson SDHC MMC host controller
  mmc: host: meson-mx-sdhc: new driver for the Amlogic Meson SDHC host

 .../bindings/mmc/amlogic,meson-mx-sdhc.txt    |   34 +
 drivers/mmc/host/Kconfig                      |   14 +
 drivers/mmc/host/Makefile                     |    1 +
 drivers/mmc/host/meson-mx-sdhc.c              | 1161 +++++++++++++++++
 4 files changed, 1210 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdhc.txt
 create mode 100644 drivers/mmc/host/meson-mx-sdhc.c

-- 
2.22.0

^ permalink raw reply

* [PATCH RFC v1 1/2] dt-bindings: mmc: Document the Amlogic Meson SDHC MMC host controller
From: Martin Blumenstingl @ 2019-07-08 17:33 UTC (permalink / raw)
  To: linux-amlogic, devicetree, linux-mmc, robh+dt, ulf.hansson,
	jianxin.pan
  Cc: linux-kernel, linux-arm-kernel, mark.rutland, Martin Blumenstingl
In-Reply-To: <20190708173330.13217-1-martin.blumenstingl@googlemail.com>

This documents the devicetree bindings for the SDHC MMC host controller
found in Meson6, Meson8, Meson8b and Meson8m2 SoCs. It can use a
bus-width of 1/4/8-bit and it supports eMMC spec 4.4x/4.5x including
HS200 mode (up to 100MHz clock).

Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
 .../bindings/mmc/amlogic,meson-mx-sdhc.txt    | 34 +++++++++++++++++++
 1 file changed, 34 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdhc.txt

diff --git a/Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdhc.txt b/Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdhc.txt
new file mode 100644
index 000000000000..afe14210030c
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdhc.txt
@@ -0,0 +1,34 @@
+* Amlogic Meson6, Meson8, Meson8b and Meson8m2 SDHC controller
+
+The SDHC MMC host controller on Amlogic SoCs provides an eMMC and MMC
+card interface with 1/4/8-bit bus width.
+It supports eMMC spec 4.4x/4.5x including HS200 (up to 100MHz clock).
+
+This file documents the properties in addition to those available in
+the MMC core bindings, documented by mmc.txt.
+
+Required properties:
+ - compatible : must be one of
+	- "amlogic,meson8-sdhc"
+	- "amlogic,meson8b-sdhc"
+	- "amlogic,meson8m2-sdhc"
+	preceded by the generic "amlogic,meson-mx-sdhc"
+ - reg : register base address and size
+ - interrupts : SDHC controller interrupt
+ - clocks : phandle to clock providers
+ - clock-names : "pclk", "clkin0", "clkin1", "clkin2" and "clkin3"
+		 ("pclk" is the module gate clock, and clkin are
+		  the inputs to the internal clock mux)
+
+Examples:
+	mmc@8e00 {
+		compatible = "amlogic,meson8-sdhc", "amlogic,meson-mx-sdhc";
+		reg = <0x8e00 0x42>;
+		interrupts = <GIC_SPI 78 IRQ_TYPE_EDGE_RISING>;
+		clocks = <&clkc CLKID_SDHC>,
+			<&clkc CLKID_XTAL>,
+			<&clkc CLKID_FCLK_DIV4>,
+			<&clkc CLKID_FCLK_DIV3>,
+			<&clkc CLKID_FCLK_DIV5>;
+		clock-names = "pclk", "clkin0", "clkin1", "clkin2", "clkin3";
+	};
-- 
2.22.0

^ permalink raw reply related

* [PATCH RFC v1 2/2] mmc: host: meson-mx-sdhc: new driver for the Amlogic Meson SDHC host
From: Martin Blumenstingl @ 2019-07-08 17:33 UTC (permalink / raw)
  To: linux-amlogic, devicetree, linux-mmc, robh+dt, ulf.hansson,
	jianxin.pan
  Cc: linux-kernel, linux-arm-kernel, mark.rutland, Martin Blumenstingl
In-Reply-To: <20190708173330.13217-1-martin.blumenstingl@googlemail.com>

WiP - only partially working - see performance numbers.

Odroid-C1 eMMC (HS-200):
Amlogic's vendor driver @ Linux 3.10:
  7781351936 bytes (7.8 GB) copied, 134.714 s, 57.8 MB/s
This driver:
  7781351936 bytes (7.8 GB, 7.2 GiB) copied, 189.02 s, 41.2 MB/s

EC-100 eMMC (HS MMC):
Amlogic's vendor driver @ Linux 3.10:
  15762194432 bytes (16 GB) copied, 422.967 s, 37.3 MB/s
This driver:
  15762194432 bytes (16 GB, 15 GiB) copied, 9232.65 s, 1.7 MB/s

1) Amlogic's vendor driver does some magic with the divider:
      clk_div = input_rate / clk_ios - !(input_rate%clk_ios);
      if (!(clk_div & 0x01)) // if even number, turn it to an odd one
         clk_div++;
   It's not clear to me whether what the reason behind this is, what is
   supposed to be achieved with this?

2) The hardcoded RX clock phases are taken from the vendor driver. It
   seems that these are only valid when fclk_div3 is used as input
   clock (however, there are four more inputs). It's not clear to me how
   to calculate the RX clock phases in set_ios based on the input clock
   and the ios rate.

3) The hardware supports a timeout IRQ but the max_busy_timeout is not
   documented anywhere.

Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
 drivers/mmc/host/Kconfig         |   14 +
 drivers/mmc/host/Makefile        |    1 +
 drivers/mmc/host/meson-mx-sdhc.c | 1161 ++++++++++++++++++++++++++++++
 3 files changed, 1176 insertions(+)
 create mode 100644 drivers/mmc/host/meson-mx-sdhc.c

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 931770f17087..9dbcf8147f72 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -380,6 +380,20 @@ config MMC_MESON_GX
 
 	  If you have a controller with this interface, say Y here.
 
+config MMC_MESON_MX_SDHC
+	tristate "Amlogic Meson SDHC Host Controller support"
+	depends on (ARM && ARCH_MESON) || COMPILE_TEST
+	depends on COMMON_CLK
+	depends on OF
+	help
+	  This selects support for the SDHC Host Controller on
+	  Amlogic Meson6, Meson8, Meson8b and Meson8m2 SoCs.
+	  The controller supports the SD/SDIO Spec 3.x and eMMC Spec 4.5x
+	  with 1, 4, and 8 bit bus widths.
+
+	  If you have a controller with this interface, say Y or M here.
+	  If unsure, say N.
+
 config MMC_MESON_MX_SDIO
 	tristate "Amlogic Meson6/Meson8/Meson8b SD/MMC Host Controller support"
 	depends on ARCH_MESON || COMPILE_TEST
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 73578718f119..b561d4dd38cd 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_MMC_VUB300)	+= vub300.o
 obj-$(CONFIG_MMC_USHC)		+= ushc.o
 obj-$(CONFIG_MMC_WMT)		+= wmt-sdmmc.o
 obj-$(CONFIG_MMC_MESON_GX)	+= meson-gx-mmc.o
+obj-$(CONFIG_MMC_MESON_MX_SDHC)	+= meson-mx-sdhc.o
 obj-$(CONFIG_MMC_MESON_MX_SDIO)	+= meson-mx-sdio.o
 obj-$(CONFIG_MMC_MOXART)	+= moxart-mmc.o
 obj-$(CONFIG_MMC_SUNXI)		+= sunxi-mmc.o
diff --git a/drivers/mmc/host/meson-mx-sdhc.c b/drivers/mmc/host/meson-mx-sdhc.c
new file mode 100644
index 000000000000..a37639ff8962
--- /dev/null
+++ b/drivers/mmc/host/meson-mx-sdhc.c
@@ -0,0 +1,1161 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Amlogic Meson6/Meson8/Meson8b/Meson8m2 SDHC MMC host controller driver.
+ *
+ * Copyright (C) 2019 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/slot-gpio.h>
+
+#define MESON_SDHC_ARGU						0x00
+
+#define MESON_SDHC_SEND						0x04
+	#define MESON_SDHC_SEND_CMD_INDEX			GENMASK(5, 0)
+	#define MESON_SDHC_SEND_CMD_HAS_RESP			BIT(6)
+	#define MESON_SDHC_SEND_CMD_HAS_DATA			BIT(7)
+	#define MESON_SDHC_SEND_RESP_LEN			BIT(8)
+	#define MESON_SDHC_SEND_RESP_NO_CRC			BIT(9)
+	#define MESON_SDHC_SEND_DATA_DIR			BIT(10)
+	#define MESON_SDHC_SEND_DATA_STOP			BIT(11)
+	#define MESON_SDHC_SEND_R1B				BIT(12)
+	#define MESON_SDHC_SEND_TOTAL_PACK			GENMASK(31, 16)
+
+#define MESON_SDHC_CTRL						0x08
+	#define MESON_SDHC_CTRL_DAT_TYPE			GENMASK(1, 0)
+	#define MESON_SDHC_CTRL_DDR_MODE			BIT(2)
+	#define MESON_SDHC_CTRL_TX_CRC_NOCHECK			BIT(3)
+	#define MESON_SDHC_CTRL_PACK_LEN			GENMASK(12, 4)
+	#define MESON_SDHC_CTRL_RX_TIMEOUT			GENMASK(19, 13)
+	#define MESON_SDHC_CTRL_RX_PERIOD			GENMASK(23, 20)
+	#define MESON_SDHC_CTRL_RX_ENDIAN			GENMASK(26, 24)
+	#define MESON_SDHC_CTRL_SDIO_IRQ_MODE			BIT(27)
+	#define MESON_SDHC_CTRL_DAT0_IRQ_SEL			BIT(28)
+	#define MESON_SDHC_CTRL_TX_ENDIAN			GENMASK(31, 29)
+
+#define MESON_SDHC_STAT						0x0c
+	#define MESON_SDHC_STAT_CMD_BUSY			BIT(0)
+	#define MESON_SDHC_STAT_DAT3_0				GENMASK(4, 1)
+	#define MESON_SDHC_STAT_CMD				BIT(5)
+	#define MESON_SDHC_STAT_RXFIFO_CNT			GENMASK(12, 6)
+	#define MESON_SDHC_STAT_TXFIFO_CNT			GENMASK(19, 13)
+	#define MESON_SDHC_STAT_DAT7_4				GENMASK(23, 20)
+
+#define MESON_SDHC_CLKC						0x10
+	#define MESON_SDHC_CLKC_CLK_DIV				GENMASK(11, 0)
+	#define MESON_SDHC_CLKC_TX_CLK_ON			BIT(12)
+	#define MESON_SDHC_CLKC_RX_CLK_ON			BIT(13)
+	#define MESON_SDHC_CLKC_SD_CLK_ON			BIT(14)
+	#define MESON_SDHC_CLKC_MOD_CLK_ON			BIT(15)
+	#define MESON_SDHC_CLKC_CLK_SRC_SEL			GENMASK(18, 16)
+	#define MESON_SDHC_CLKC_CLK_JIC				BIT(24)
+	#define MESON_SDHC_CLKC_MEM_PWR_OFF			GENMASK(26, 25)
+
+#define MESON_SDHC_ADDR						0x14
+
+#define MESON_SDHC_PDMA						0x18
+	#define MESON_SDHC_PDMA_DMA_MODE			BIT(0)
+	#define MESON_SDHC_PDMA_PIO_RDRESP			GENMASK(3, 1)
+	#define MESON_SDHC_PDMA_DMA_URGENT			BIT(4)
+	#define MESON_SDHC_PDMA_WR_BURST			GENMASK(9, 5)
+	#define MESON_SDHC_PDMA_RD_BURST			GENMASK(14, 10)
+	#define MESON_SDHC_PDMA_RXFIFO_TH			GENMASK(21, 15)
+	#define MESON_SDHC_PDMA_TXFIFO_TH			GENMASK(28, 22)
+	#define MESON_SDHC_PDMA_RXFIFO_MANUAL_FLUSH		GENMASK(30, 29)
+	#define MESON_SDHC_PDMA_TXFIFO_FILL			BIT(31)
+
+#define MESON_SDHC_MISC						0x1c
+	#define MESON_SDHC_MISC_WCRC_ERR_PATT			GENMASK(6, 4)
+	#define MESON_SDHC_MISC_WCRC_OK_PATT			GENMASK(9, 7)
+	#define MESON_SDHC_MISC_BURST_NUM			GENMASK(21, 16)
+	#define MESON_SDHC_MISC_THREAD_ID			GENMASK(27, 22)
+	#define MESON_SDHC_MISC_MANUAL_STOP			BIT(28)
+	#define MESON_SDHC_MISC_TXSTART_THRES			GENMASK(31, 29)
+
+#define MESON_SDHC_DATA						0x20
+
+#define MESON_SDHC_ICTL						0x24
+	#define MESON_SDHC_ICTL_RESP_OK				BIT(0)
+	#define MESON_SDHC_ICTL_RESP_TIMEOUT			BIT(1)
+	#define MESON_SDHC_ICTL_RESP_ERR_CRC			BIT(2)
+	#define MESON_SDHC_ICTL_RESP_OK_NOCLEAR			BIT(3)
+	#define MESON_SDHC_ICTL_DATA_1PACK_OK			BIT(4)
+	#define MESON_SDHC_ICTL_DATA_TIMEOUT			BIT(5)
+	#define MESON_SDHC_ICTL_DATA_ERR_CRC			BIT(6)
+	#define MESON_SDHC_ICTL_DATA_XFER_OK			BIT(7)
+	#define MESON_SDHC_ICTL_RX_HIGHER			BIT(8)
+	#define MESON_SDHC_ICTL_RX_LOWER			BIT(9)
+	#define MESON_SDHC_ICTL_DAT1_IRQ			BIT(10)
+	#define MESON_SDHC_ICTL_DMA_DONE			BIT(11)
+	#define MESON_SDHC_ICTL_RXFIFO_FULL			BIT(12)
+	#define MESON_SDHC_ICTL_TXFIFO_EMPTY			BIT(13)
+	#define MESON_SDHC_ICTL_ADDI_DAT1_IRQ			BIT(14)
+	#define MESON_SDHC_ICTL_ALL_IRQS			GENMASK(14, 0)
+	#define MESON_SDHC_ICTL_DAT1_IRQ_DELAY			GENMASK(17, 16)
+
+#define MESON_SDHC_ISTA						0x28
+	#define MESON_SDHC_ISTA_RESP_OK				BIT(0)
+	#define MESON_SDHC_ISTA_RESP_TIMEOUT			BIT(1)
+	#define MESON_SDHC_ISTA_RESP_ERR_CRC			BIT(2)
+	#define MESON_SDHC_ISTA_RESP_OK_NOCLEAR			BIT(3)
+	#define MESON_SDHC_ISTA_DATA_1PACK_OK			BIT(4)
+	#define MESON_SDHC_ISTA_DATA_TIMEOUT			BIT(5)
+	#define MESON_SDHC_ISTA_DATA_ERR_CRC			BIT(6)
+	#define MESON_SDHC_ISTA_DATA_XFER_OK			BIT(7)
+	#define MESON_SDHC_ISTA_RX_HIGHER			BIT(8)
+	#define MESON_SDHC_ISTA_RX_LOWER			BIT(9)
+	#define MESON_SDHC_ISTA_DAT1_IRQ			BIT(10)
+	#define MESON_SDHC_ISTA_DMA_DONE			BIT(11)
+	#define MESON_SDHC_ISTA_RXFIFO_FULL			BIT(12)
+	#define MESON_SDHC_ISTA_TXFIFO_EMPTY			BIT(13)
+	#define MESON_SDHC_ISTA_ADDI_DAT1_IRQ			BIT(14)
+	#define MESON_SDHC_ISTA_ALL_IRQS			GENMASK(14, 0)
+
+#define MESON_SDHC_SRST						0x2c
+	#define MESON_SDHC_SRST_MAIN_CTRL			BIT(0)
+	#define MESON_SDHC_SRST_RXFIFO				BIT(1)
+	#define MESON_SDHC_SRST_TXFIFO				BIT(2)
+	#define MESON_SDHC_SRST_DPHY_RX				BIT(3)
+	#define MESON_SDHC_SRST_DPHY_TX				BIT(4)
+	#define MESON_SDHC_SRST_DMA_IF				BIT(5)
+
+#define MESON_SDHC_ESTA						0x30
+	#define MESON_SDHC_ESTA_11_13				GENMASK(13, 11)
+
+#define MESON_SDHC_ENHC						0x34
+	#define MESON_SDHC_ENHC_MESON8M2_WRRSP_MODE		BIT(0)
+	#define MESON_SDHC_ENHC_MESON8M2_CHK_WRRSP		BIT(1)
+	#define MESON_SDHC_ENHC_MESON8M2_CHK_DMA		BIT(2)
+	#define MESON_SDHC_ENHC_MESON8M2_DEBUG			GENMASK(5, 3)
+	#define MESON_SDHC_ENHC_MESON6_RX_TIMEOUT		GENMASK(7, 0)
+	#define MESON_SDHC_ENHC_MESON6_DMA_RD_RESP		BIT(16)
+	#define MESON_SDHC_ENHC_MESON6_DMA_WR_RESP		BIT(17)
+	#define MESON_SDHC_ENHC_SDIO_IRQ_PERIOD			GENMASK(15, 8)
+	#define MESON_SDHC_ENHC_RXFIFO_TH			GENMASK(24, 18)
+	#define MESON_SDHC_ENHC_TXFIFO_TH			GENMASK(31, 25)
+
+#define MESON_SDHC_CLK2						0x38
+	#define MESON_SDHC_CLK2_RX_CLK_PHASE			GENMASK(11, 0)
+	#define MESON_SDHC_CLK2_SD_CLK_PHASE			GENMASK(23, 12)
+
+#define MESON_SDHC_PARENT_CLKS					4
+#define MESON_SDHC_BOUNCE_REQ_SIZE				(512 * 1024)
+#define MESON_SDHC_MAX_BLK_SIZE					512
+#define MESON_SDHC_NUM_TUNING_TRIES				10
+
+struct meson_mx_sdhc_data {
+	void (*init_hw)(struct mmc_host *mmc);
+	void (*set_pdma)(struct mmc_host *mmc);
+	void (*wait_before_send)(struct mmc_host *mmc);
+	bool hardware_flush_all_cmds;
+};
+
+struct meson_mx_sdhc_host {
+	struct mmc_host			*mmc;
+
+	struct mmc_request		*mrq;
+	struct mmc_command		*cmd;
+	int				error;
+
+	void __iomem			*base;
+
+	struct clk_divider		clkc_clk_div;
+	struct clk_gate			clkc_tx_clk_on;
+	struct clk_gate			clkc_rx_clk_on;
+	struct clk_gate			clkc_sd_clk_on;
+	struct clk_gate			clkc_mod_clk_on;
+	struct clk_mux			clkc_clk_src_sel;
+
+	struct clk_bulk_data		parent_clks[MESON_SDHC_PARENT_CLKS];
+	struct clk			*pclk;
+
+	struct clk			*tx_clk;
+	struct clk			*rx_clk;
+	struct clk			*sd_clk;
+	struct clk			*mod_clk;
+	bool				clocks_enabled;
+
+	const struct meson_mx_sdhc_data	*platform;
+};
+
+static void meson_mx_sdhc_mask_bits(struct mmc_host *mmc, u8 reg, u32 mask,
+				    u32 val)
+{
+	struct meson_mx_sdhc_host *host = mmc_priv(mmc);
+	u32 regval;
+
+	regval = readl(host->base + reg);
+	regval &= ~mask;
+	regval |= (val & mask);
+
+	writel(regval, host->base + reg);
+}
+
+static struct mmc_command *meson_mx_sdhc_get_next_cmd(struct mmc_command *cmd)
+{
+	if (cmd->opcode == MMC_SET_BLOCK_COUNT && !cmd->error)
+		return cmd->mrq->cmd;
+	else if (mmc_op_multi(cmd->opcode) &&
+		 (!cmd->mrq->sbc || cmd->error || cmd->data->error))
+		return cmd->mrq->stop;
+	else
+		return NULL;
+}
+
+static void meson_mx_sdhc_hw_reset(struct mmc_host *mmc)
+{
+	struct meson_mx_sdhc_host *host = mmc_priv(mmc);
+
+	writel(MESON_SDHC_SRST_MAIN_CTRL |  MESON_SDHC_SRST_RXFIFO |
+	       MESON_SDHC_SRST_TXFIFO | MESON_SDHC_SRST_DPHY_RX |
+	       MESON_SDHC_SRST_DPHY_TX | MESON_SDHC_SRST_DMA_IF,
+	       host->base + MESON_SDHC_SRST);
+	udelay(5);
+
+	writel(0, host->base + MESON_SDHC_SRST);
+	udelay(10, 100);
+}
+
+static void meson_mx_sdhc_wait_cmd_ready(struct mmc_host *mmc)
+{
+	struct meson_mx_sdhc_host *host = mmc_priv(mmc);
+	u32 stat, esta;
+	int ret;
+
+	ret = readl_poll_timeout(host->base + MESON_SDHC_STAT, stat,
+				 !(stat & MESON_SDHC_STAT_CMD_BUSY), 1, 10000);
+	if (ret) {
+		dev_warn(mmc_dev(mmc),
+			 "Failed to poll for CMD_BUSY while processing CMD%d\n",
+			 host->cmd->opcode);
+		meson_mx_sdhc_hw_reset(mmc);
+	}
+
+	ret = readl_poll_timeout(host->base + MESON_SDHC_ESTA, esta,
+				 !(esta & MESON_SDHC_ESTA_11_13), 1, 10000);
+	if (ret) {
+		dev_warn(mmc_dev(mmc),
+			 "Failed to poll for ESTA[13:11] while processing CMD%d\n",
+			 host->cmd->opcode);
+		meson_mx_sdhc_hw_reset(mmc);
+	}
+}
+
+static void meson_mx_sdhc_start_cmd(struct mmc_host *mmc,
+				    struct mmc_command *cmd)
+{
+	struct meson_mx_sdhc_host *host = mmc_priv(mmc);
+	u32 ictl, send;
+	int pack_len;
+
+	host->cmd = cmd;
+
+	ictl = MESON_SDHC_ICTL_DATA_TIMEOUT | MESON_SDHC_ICTL_DATA_ERR_CRC |
+	       MESON_SDHC_ICTL_RXFIFO_FULL | MESON_SDHC_ICTL_TXFIFO_EMPTY |
+	       MESON_SDHC_ICTL_RESP_TIMEOUT | MESON_SDHC_ICTL_RESP_ERR_CRC;
+
+	send = FIELD_PREP(MESON_SDHC_SEND_CMD_INDEX, cmd->opcode);
+
+	if (cmd->data) {
+		send |= MESON_SDHC_SEND_CMD_HAS_DATA;
+		send |= FIELD_PREP(MESON_SDHC_SEND_TOTAL_PACK,
+				   cmd->data->blocks - 1);
+
+		if (cmd->data->blksz < MESON_SDHC_MAX_BLK_SIZE)
+			pack_len = cmd->data->blksz;
+		else
+			pack_len = 0;
+
+		if (cmd->data->flags & MMC_DATA_WRITE)
+			send |= MESON_SDHC_SEND_DATA_DIR;
+
+		/*
+		 * If command with no data, just wait response done
+		 * interrupt(int[0]), and if command with data transfer, just
+		 * wait dma done interrupt(int[11]), don't need care about
+		 * dat0 busy or not.
+		 */
+		if (host->platform->hardware_flush_all_cmds ||
+		    cmd->data->flags & MMC_DATA_WRITE)
+			/* hardware flush: */
+			ictl |= MESON_SDHC_ICTL_DMA_DONE;
+		else
+			/* software flush: */
+			ictl |= MESON_SDHC_ICTL_DATA_XFER_OK;
+
+		meson_mx_sdhc_mask_bits(mmc, MESON_SDHC_MISC,
+					MESON_SDHC_MISC_MANUAL_STOP,
+					MESON_SDHC_MISC_MANUAL_STOP);
+	} else {
+		ictl |= MESON_SDHC_ICTL_RESP_OK;
+
+		pack_len = 0;
+	}
+
+	if (cmd->opcode == MMC_STOP_TRANSMISSION)
+		send |= MESON_SDHC_SEND_DATA_STOP;
+
+	if (cmd->flags & MMC_RSP_PRESENT)
+		send |= MESON_SDHC_SEND_CMD_HAS_RESP;
+
+	if (cmd->flags & MMC_RSP_136) {
+		send |= MESON_SDHC_SEND_RESP_LEN;
+		send |= MESON_SDHC_SEND_RESP_NO_CRC;
+	}
+
+	if (!(cmd->flags & MMC_RSP_CRC))
+		send |= MESON_SDHC_SEND_RESP_NO_CRC;
+
+	if (cmd->flags & MMC_RSP_BUSY)
+		send |= MESON_SDHC_SEND_R1B;
+
+	/* enable the new IRQs and mask all pending ones */
+	writel(ictl, host->base + MESON_SDHC_ICTL);
+	writel(MESON_SDHC_ISTA_ALL_IRQS, host->base + MESON_SDHC_ISTA);
+
+	writel(cmd->arg, host->base + MESON_SDHC_ARGU);
+
+	meson_mx_sdhc_mask_bits(mmc, MESON_SDHC_CTRL, MESON_SDHC_CTRL_PACK_LEN,
+				FIELD_PREP(MESON_SDHC_CTRL_PACK_LEN, pack_len));
+
+	if (cmd->data)
+		writel(sg_dma_address(cmd->data->sg),
+		       host->base + MESON_SDHC_ADDR);
+
+	meson_mx_sdhc_wait_cmd_ready(mmc);
+
+	if (cmd->data)
+		host->platform->set_pdma(mmc);
+
+	if (host->platform->wait_before_send)
+		host->platform->wait_before_send(mmc);
+
+	writel(send, host->base + MESON_SDHC_SEND);
+}
+
+static void meson_mx_sdhc_disable_clks(struct mmc_host *mmc)
+{
+	struct meson_mx_sdhc_host *host = mmc_priv(mmc);
+
+	if (!host->clocks_enabled)
+		return;
+
+	clk_disable_unprepare(host->tx_clk);
+	clk_disable_unprepare(host->rx_clk);
+	clk_disable_unprepare(host->sd_clk);
+
+	clk_disable_unprepare(host->mod_clk);
+
+	host->clocks_enabled = false;
+}
+
+static int meson_mx_sdhc_enable_clks(struct mmc_host *mmc)
+{
+	struct meson_mx_sdhc_host *host = mmc_priv(mmc);
+	struct clk *clocks[] = {
+		host->mod_clk,
+		host->sd_clk,
+		host->tx_clk,
+		host->rx_clk,
+	};
+	int i, ret;
+
+	if (host->clocks_enabled)
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(clocks); i++) {
+		ret = clk_prepare_enable(clocks[i]);
+		if (ret) {
+			dev_err(mmc_dev(mmc), "Failed to enable clock %s\n",
+				__clk_get_name(clocks[i]));
+			goto err;
+		}
+	}
+
+	host->clocks_enabled = true;
+
+	return 0;
+
+err:
+	while (--i >= 0)
+		clk_disable_unprepare(clocks[i]);
+
+	return ret;
+}
+
+static int meson_mx_sdhc_set_clk(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct meson_mx_sdhc_host *host = mmc_priv(mmc);
+	u32 rx_clk_phase, val;
+	int ret;
+
+	meson_mx_sdhc_disable_clks(mmc);
+
+	if (ios->clock) {
+		ret = clk_set_rate(host->sd_clk, ios->clock);
+		if (ret) {
+			dev_warn(mmc_dev(mmc),
+				 "Failed to set MMC clock to %uHz: %d\n",
+				 ios->clock, host->error);
+			return ret;
+		}
+
+		ret = meson_mx_sdhc_enable_clks(mmc);
+		if (ret)
+			return ret;
+
+		mmc->actual_clock = clk_get_rate(host->sd_clk);
+
+		if (mmc->actual_clock > 100000000) {
+			rx_clk_phase = 1;
+		} else if (mmc->actual_clock > 45000000) {
+			if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330)
+				rx_clk_phase = 15;
+			else
+				rx_clk_phase = 11;
+		} else if (mmc->actual_clock >= 25000000) {
+			rx_clk_phase = 15;
+		} else if (mmc->actual_clock > 5000000) {
+			rx_clk_phase = 23;
+		} else if (mmc->actual_clock > 1000000) {
+			rx_clk_phase = 55;
+		} else {
+			rx_clk_phase = 1061;
+		}
+
+		val = FIELD_PREP(MESON_SDHC_CLK2_RX_CLK_PHASE, rx_clk_phase);
+		meson_mx_sdhc_mask_bits(mmc, MESON_SDHC_CLK2,
+					MESON_SDHC_CLK2_RX_CLK_PHASE, val);
+	} else {
+		mmc->actual_clock = 0;
+	}
+
+	return 0;
+}
+
+static void meson_mx_sdhc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct meson_mx_sdhc_host *host = mmc_priv(mmc);
+	unsigned short vdd = ios->vdd;
+	u32 dat_type;
+
+	switch (ios->power_mode) {
+	case MMC_POWER_OFF:
+		vdd = 0;
+		/* fall through */
+
+	case MMC_POWER_UP:
+		if (!IS_ERR(mmc->supply.vmmc)) {
+			host->error = mmc_regulator_set_ocr(mmc,
+							    mmc->supply.vmmc,
+							    vdd);
+			if (host->error)
+				return;
+		}
+
+		break;
+
+	case MMC_POWER_ON:
+		break;
+	}
+
+	host->error = meson_mx_sdhc_set_clk(mmc, ios);
+	if (host->error)
+		return;
+
+	switch (ios->bus_width) {
+	case MMC_BUS_WIDTH_1:
+		dat_type = FIELD_PREP(MESON_SDHC_CTRL_DAT_TYPE, 0);
+		break;
+
+	case MMC_BUS_WIDTH_4:
+		dat_type = FIELD_PREP(MESON_SDHC_CTRL_DAT_TYPE, 1);
+		break;
+
+	case MMC_BUS_WIDTH_8:
+		dat_type = FIELD_PREP(MESON_SDHC_CTRL_DAT_TYPE, 2);
+		break;
+
+	default:
+		dev_err(mmc_dev(mmc), "unsupported bus width: %d\n",
+			ios->bus_width);
+		host->error = -EINVAL;
+		return;
+	}
+
+	meson_mx_sdhc_mask_bits(mmc, MESON_SDHC_CTRL, MESON_SDHC_CTRL_DAT_TYPE,
+				dat_type);
+}
+
+static int meson_mx_sdhc_map_dma(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct mmc_data *data = mrq->data;
+	int dma_len;
+
+	if (!data)
+		return 0;
+
+	dma_len = dma_map_sg(mmc_dev(mmc), data->sg, data->sg_len,
+			     mmc_get_dma_dir(data));
+	if (dma_len <= 0) {
+		dev_err(mmc_dev(mmc), "dma_map_sg failed\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void meson_mx_sdhc_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct meson_mx_sdhc_host *host = mmc_priv(mmc);
+	struct mmc_command *cmd = mrq->cmd;
+
+	if (!host->error)
+		host->error = meson_mx_sdhc_map_dma(mmc, mrq);
+
+	if (host->error) {
+		cmd->error = host->error;
+		mmc_request_done(mmc, mrq);
+		return;
+	}
+
+	host->mrq = mrq;
+
+	if (mrq->sbc)
+		meson_mx_sdhc_start_cmd(mmc, mrq->sbc);
+	else
+		meson_mx_sdhc_start_cmd(mmc, mrq->cmd);
+}
+
+static int meson_mx_sdhc_card_busy(struct mmc_host *mmc)
+{
+	struct meson_mx_sdhc_host *host = mmc_priv(mmc);
+	u32 stat = readl(host->base + MESON_SDHC_STAT);
+
+	return FIELD_GET(MESON_SDHC_STAT_DAT3_0, stat) == 0;
+}
+
+static bool meson_mx_sdhc_tuning_point_matches(struct mmc_host *mmc,
+					       u32 opcode)
+{
+	unsigned int i, num_matches = 0;
+	int ret;
+
+	for (i = 0; i < MESON_SDHC_NUM_TUNING_TRIES; i++) {
+		ret = mmc_send_tuning(mmc, opcode, NULL);
+		if (!ret)
+			num_matches++;
+	}
+
+	return num_matches == MESON_SDHC_NUM_TUNING_TRIES;
+}
+
+static int meson_mx_sdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+	struct meson_mx_sdhc_host *host = mmc_priv(mmc);
+	int div, start, len, best_start, best_len;
+	int curr_phase, old_phase, new_phase;
+	u32 val;
+
+	len = 0;
+	start = 0;
+	best_len = 0;
+
+	old_phase = clk_get_phase(host->rx_clk);
+
+	div = FIELD_GET(MESON_SDHC_CLKC_CLK_DIV,
+			readl(host->base + MESON_SDHC_CLKC));
+
+	for (curr_phase = 0; curr_phase <= div; curr_phase++) {
+		val = FIELD_PREP(MESON_SDHC_CLK2_RX_CLK_PHASE, curr_phase);
+		meson_mx_sdhc_mask_bits(mmc, MESON_SDHC_CLK2,
+					MESON_SDHC_CLK2_RX_CLK_PHASE, val);
+
+		if (meson_mx_sdhc_tuning_point_matches(mmc, opcode)) {
+			if (!len) {
+				start = curr_phase;
+
+				dev_dbg(mmc_dev(mmc),
+					"New RX phase window starts at %u\n",
+					start);
+			}
+
+			len++;
+		} else {
+			if (len > best_len) {
+				best_start = start;
+				best_len = len;
+
+				dev_dbg(mmc_dev(mmc),
+					"New best RX phase window: %u - %u\n",
+					best_start, best_start + best_len);
+			}
+
+			/* reset the current window */
+			len = 0;
+		}
+	}
+
+	if (len > best_len)
+		/* the last window is the best (or possibly only) window */
+		new_phase = start + (len / 2);
+	else if (best_len)
+		/* there was a better window than the last */
+		new_phase = best_start + (best_len / 2);
+	else
+		/* no window was found at all, reset to the original phase */
+		new_phase = old_phase;
+
+	val = FIELD_PREP(MESON_SDHC_CLK2_RX_CLK_PHASE, new_phase);
+	meson_mx_sdhc_mask_bits(mmc, MESON_SDHC_CLK2,
+				MESON_SDHC_CLK2_RX_CLK_PHASE, val);
+
+	if (!len && !best_len)
+		return -EIO;
+
+	dev_dbg(mmc_dev(mmc), "Tuned RX clock phase to %u deg\n", new_phase);
+
+	return 0;
+}
+
+static const struct mmc_host_ops meson_mx_sdhc_ops = {
+	.hw_reset			= meson_mx_sdhc_hw_reset,
+	.request			= meson_mx_sdhc_request,
+	.set_ios			= meson_mx_sdhc_set_ios,
+	.card_busy			= meson_mx_sdhc_card_busy,
+	.execute_tuning			= meson_mx_sdhc_execute_tuning,
+	.get_cd				= mmc_gpio_get_cd,
+	.get_ro				= mmc_gpio_get_ro,
+};
+
+static void meson_mx_sdhc_request_done(struct meson_mx_sdhc_host *host)
+{
+	struct mmc_request *mrq = host->mrq;
+	struct mmc_host *mmc = host->mmc;
+
+	/* disable interrupts and mask all pending ones */
+	meson_mx_sdhc_mask_bits(mmc, MESON_SDHC_ICTL,
+				MESON_SDHC_ICTL_ALL_IRQS, 0);
+	meson_mx_sdhc_mask_bits(mmc, MESON_SDHC_ISTA, MESON_SDHC_ISTA_ALL_IRQS,
+				MESON_SDHC_ISTA_ALL_IRQS);
+
+	host->mrq = NULL;
+	host->cmd = NULL;
+
+	mmc_request_done(mmc, mrq);
+}
+
+static u32 meson_mx_sdhc_read_response(struct meson_mx_sdhc_host *host, u8 idx)
+{
+	meson_mx_sdhc_mask_bits(host->mmc, MESON_SDHC_PDMA,
+				MESON_SDHC_PDMA_DMA_MODE, 0);
+
+	meson_mx_sdhc_mask_bits(host->mmc, MESON_SDHC_PDMA,
+				MESON_SDHC_PDMA_PIO_RDRESP,
+				FIELD_PREP(MESON_SDHC_PDMA_PIO_RDRESP, idx));
+
+	return readl(host->base + MESON_SDHC_ARGU);
+}
+
+static irqreturn_t meson_mx_sdhc_irq(int irq, void *data)
+{
+	struct meson_mx_sdhc_host *host = data;
+	struct mmc_command *cmd = host->cmd;
+	u32 ictl, ista;
+
+	ictl = readl(host->base + MESON_SDHC_ICTL);
+	ista = readl(host->base + MESON_SDHC_ISTA);
+
+	if (!(ictl & ista))
+		return IRQ_NONE;
+
+	if (ista & MESON_SDHC_ISTA_RXFIFO_FULL ||
+	    ista & MESON_SDHC_ISTA_TXFIFO_EMPTY)
+		cmd->error = -EIO;
+	else if (ista & MESON_SDHC_ISTA_RESP_ERR_CRC)
+		cmd->error = -EILSEQ;
+	else if (ista & MESON_SDHC_ISTA_RESP_TIMEOUT)
+		cmd->error = -ETIMEDOUT;
+
+	if (cmd->data) {
+		if (ista & MESON_SDHC_ISTA_DATA_ERR_CRC)
+			cmd->data->error = -EILSEQ;
+		else if (ista & MESON_SDHC_ISTA_DATA_TIMEOUT)
+			cmd->data->error = -ETIMEDOUT;
+	}
+
+	if (cmd->error || (cmd->data && cmd->data->error))
+		dev_dbg(mmc_dev(host->mmc), "CMD%d error, ISTA: 0x%08x\n",
+			cmd->opcode, ista);
+
+	return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t meson_mx_sdhc_irq_thread(int irq, void *irq_data)
+{
+	struct meson_mx_sdhc_host *host = irq_data;
+	struct mmc_command *cmd, *next_cmd;
+	u32 pdma;
+
+	cmd = host->cmd;
+	if (WARN_ON(!cmd))
+		return IRQ_HANDLED;
+
+	if (cmd->data && !cmd->data->error) {
+		if (!host->platform->hardware_flush_all_cmds &&
+		    cmd->flags & MMC_DATA_READ) {
+			pdma = readl(host->base + MESON_SDHC_PDMA);
+			pdma |= FIELD_PREP(MESON_SDHC_PDMA_RXFIFO_MANUAL_FLUSH,
+					   2);
+			writel(pdma, host->base);
+		}
+
+		dma_unmap_sg(mmc_dev(host->mmc), cmd->data->sg,
+			     cmd->data->sg_len, mmc_get_dma_dir(cmd->data));
+
+		cmd->data->bytes_xfered = cmd->data->blksz * cmd->data->blocks;
+	}
+
+	meson_mx_sdhc_wait_cmd_ready(host->mmc);
+
+	if (cmd->flags & MMC_RSP_136) {
+		cmd->resp[0] = meson_mx_sdhc_read_response(host, 4);
+		cmd->resp[1] = meson_mx_sdhc_read_response(host, 3);
+		cmd->resp[2] = meson_mx_sdhc_read_response(host, 2);
+		cmd->resp[3] = meson_mx_sdhc_read_response(host, 1);
+	} else {
+		cmd->resp[0] = meson_mx_sdhc_read_response(host, 0);
+	}
+
+	if (cmd->error == -EIO || cmd->error == -ETIMEDOUT)
+		meson_mx_sdhc_hw_reset(host->mmc);
+
+	next_cmd = meson_mx_sdhc_get_next_cmd(cmd);
+	if (next_cmd)
+		meson_mx_sdhc_start_cmd(host->mmc, next_cmd);
+	else
+		meson_mx_sdhc_request_done(host);
+
+	return IRQ_HANDLED;
+}
+
+static struct clk *meson_mx_sdhc_register_clk(struct device *dev,
+					      struct clk_hw *hw,
+					      const char *name,
+					      int num_parents,
+					      struct clk **parents,
+					      unsigned long flags,
+					      const struct clk_ops *ops)
+{
+	const char *parent_names[MESON_SDHC_PARENT_CLKS];
+	struct clk_init_data init;
+	int i;
+
+	for (i = 0; i < num_parents; i++)
+		parent_names[i] = __clk_get_name(parents[i]);
+
+	init.name = devm_kasprintf(dev, GFP_KERNEL, "%s#%s", dev_name(dev),
+				   name);
+	if (!init.name)
+		return ERR_PTR(-ENOMEM);
+
+	init.num_parents = num_parents;
+	init.parent_names = parent_names;
+	init.flags = CLK_SET_RATE_PARENT | flags;
+	init.ops = ops;
+
+	hw->init = &init;
+
+	return devm_clk_register(dev, hw);
+}
+
+static int meson_mx_sdhc_register_clks(struct meson_mx_sdhc_host *host)
+{
+	struct clk *mux_parents[MESON_SDHC_PARENT_CLKS];
+	struct clk *mux_clk, *div_clk;
+	int i;
+
+	for (i = 0; i < MESON_SDHC_PARENT_CLKS; i++)
+		mux_parents[i] = host->parent_clks[i].clk;
+
+	host->clkc_clk_src_sel.reg = host->base + MESON_SDHC_CLKC;
+	host->clkc_clk_src_sel.shift = __ffs(MESON_SDHC_CLKC_CLK_SRC_SEL);
+	host->clkc_clk_src_sel.mask = MESON_SDHC_CLKC_CLK_SRC_SEL >>
+				      host->clkc_clk_src_sel.shift;
+	mux_clk = meson_mx_sdhc_register_clk(mmc_dev(host->mmc),
+					     &host->clkc_clk_src_sel.hw,
+					     "clk_src_sel",
+					     MESON_SDHC_PARENT_CLKS,
+					     mux_parents,
+					     CLK_SET_RATE_NO_REPARENT,
+					     &clk_mux_ops);
+	if (IS_ERR(mux_clk))
+		return PTR_ERR(mux_clk);
+
+	host->clkc_clk_div.reg = host->base + MESON_SDHC_CLKC;
+	host->clkc_clk_div.shift = __ffs(MESON_SDHC_CLKC_CLK_DIV);
+	host->clkc_clk_div.width = fls(MESON_SDHC_CLKC_CLK_DIV) -
+				   host->clkc_clk_div.shift;
+	div_clk = meson_mx_sdhc_register_clk(mmc_dev(host->mmc),
+					     &host->clkc_clk_div.hw,
+					     "clk_div", 1, &mux_clk,
+					     CLK_SET_RATE_PARENT,
+					     &clk_divider_ops);
+	if (IS_ERR(div_clk))
+		return PTR_ERR(div_clk);
+
+	host->clkc_mod_clk_on.reg = host->base + MESON_SDHC_CLKC;
+	host->clkc_mod_clk_on.bit_idx = __ffs(MESON_SDHC_CLKC_MOD_CLK_ON);
+	host->mod_clk = meson_mx_sdhc_register_clk(mmc_dev(host->mmc),
+						   &host->clkc_mod_clk_on.hw,
+						   "mod_clk_on", 1, &div_clk,
+						   0, &clk_gate_ops);
+	if (IS_ERR(host->mod_clk))
+		return PTR_ERR(host->mod_clk);
+
+	host->clkc_tx_clk_on.reg = host->base + MESON_SDHC_CLKC;
+	host->clkc_tx_clk_on.bit_idx = __ffs(MESON_SDHC_CLKC_TX_CLK_ON);
+	host->tx_clk = meson_mx_sdhc_register_clk(mmc_dev(host->mmc),
+						  &host->clkc_tx_clk_on.hw,
+						  "tx_clk_on", 1, &div_clk,
+						  CLK_SET_RATE_GATE |
+						  CLK_SET_RATE_PARENT,
+						  &clk_gate_ops);
+	if (IS_ERR(host->tx_clk))
+		return PTR_ERR(host->tx_clk);
+
+	host->clkc_rx_clk_on.reg = host->base + MESON_SDHC_CLKC;
+	host->clkc_rx_clk_on.bit_idx = __ffs(MESON_SDHC_CLKC_RX_CLK_ON);
+	host->rx_clk = meson_mx_sdhc_register_clk(mmc_dev(host->mmc),
+						  &host->clkc_rx_clk_on.hw,
+						  "rx_clk_on", 1, &div_clk,
+						  CLK_SET_RATE_GATE |
+						  CLK_SET_RATE_PARENT,
+						  &clk_gate_ops);
+	if (IS_ERR(host->rx_clk))
+		return PTR_ERR(host->rx_clk);
+
+	host->clkc_sd_clk_on.reg = host->base + MESON_SDHC_CLKC;
+	host->clkc_sd_clk_on.bit_idx = __ffs(MESON_SDHC_CLKC_SD_CLK_ON);
+	host->sd_clk = meson_mx_sdhc_register_clk(mmc_dev(host->mmc),
+						  &host->clkc_sd_clk_on.hw,
+						  "sd_clk_on", 1, &div_clk,
+						  CLK_SET_RATE_GATE |
+						  CLK_SET_RATE_PARENT,
+						  &clk_gate_ops);
+
+	if (IS_ERR(host->sd_clk))
+		return PTR_ERR(host->sd_clk);
+
+	/*
+	 * currently only fclk_div3 is supported as input clock as other
+	 * input clocks are resulting in timeouts (potentially due to the
+	 * phase setup in .set_ios).
+	 */
+	return clk_set_parent(mux_clk, host->parent_clks[2].clk);
+}
+
+static void meson_mx_sdhc_init_hw_meson8(struct mmc_host *mmc)
+{
+	struct meson_mx_sdhc_host *host = mmc_priv(mmc);
+	u32 val;
+
+	val = FIELD_PREP(MESON_SDHC_MISC_TXSTART_THRES, 7) |
+	      FIELD_PREP(MESON_SDHC_MISC_WCRC_ERR_PATT, 5) |
+	      FIELD_PREP(MESON_SDHC_MISC_WCRC_OK_PATT, 2);
+	writel(val, host->base + MESON_SDHC_MISC);
+
+	val = FIELD_PREP(MESON_SDHC_ENHC_RXFIFO_TH, 63) |
+	      MESON_SDHC_ENHC_MESON6_DMA_WR_RESP |
+	      FIELD_PREP(MESON_SDHC_ENHC_MESON6_RX_TIMEOUT, 255) |
+	      FIELD_PREP(MESON_SDHC_ENHC_SDIO_IRQ_PERIOD, 12);
+	writel(val, host->base + MESON_SDHC_ENHC);
+};
+
+static void meson_mx_sdhc_set_pdma_meson8(struct mmc_host *mmc)
+{
+	struct meson_mx_sdhc_host *host = mmc_priv(mmc);
+	u32 pdma;
+
+	pdma = readl(host->base + MESON_SDHC_PDMA);
+
+	pdma |= MESON_SDHC_PDMA_DMA_MODE;
+
+	if (host->cmd->flags & MMC_DATA_WRITE) {
+		pdma &= ~MESON_SDHC_PDMA_RD_BURST;
+		pdma |= FIELD_PREP(MESON_SDHC_PDMA_RD_BURST, 31);
+
+		pdma |= MESON_SDHC_PDMA_TXFIFO_FILL;
+	} else {
+		pdma &= ~MESON_SDHC_PDMA_RXFIFO_MANUAL_FLUSH;
+		pdma |= FIELD_PREP(MESON_SDHC_PDMA_RXFIFO_MANUAL_FLUSH, 1);
+	}
+
+	writel(pdma, host->base + MESON_SDHC_PDMA);
+
+	if (host->cmd->flags & MMC_DATA_WRITE) {
+		pdma &= ~MESON_SDHC_PDMA_RD_BURST;
+		pdma |= FIELD_PREP(MESON_SDHC_PDMA_RD_BURST, 15);
+
+		writel(pdma, host->base + MESON_SDHC_PDMA);
+	}
+}
+
+static void meson_mx_sdhc_wait_before_send_meson8(struct mmc_host *mmc)
+{
+	struct meson_mx_sdhc_host *host = mmc_priv(mmc);
+	u32 val;
+	int ret;
+
+	ret = readl_poll_timeout(host->base + MESON_SDHC_ESTA, val, val == 0,
+				 1, 200);
+	if (ret)
+		dev_warn(mmc_dev(mmc),
+			 "Failed to wait for ESTA to clear: 0x%08x\n", val);
+
+	if (host->cmd->data && host->cmd->flags & MMC_DATA_WRITE) {
+		ret = readl_poll_timeout(host->base + MESON_SDHC_STAT, val,
+					 val & MESON_SDHC_STAT_TXFIFO_CNT,
+					 1, 200);
+		if (ret)
+			dev_warn(mmc_dev(mmc),
+				 "Failed to wait for TX FIFO to fill\n");
+	}
+}
+
+static void meson_mx_sdhc_init_hw_meson8m2(struct mmc_host *mmc)
+{
+	struct meson_mx_sdhc_host *host = mmc_priv(mmc);
+	u32 val;
+
+	val = FIELD_PREP(MESON_SDHC_MISC_TXSTART_THRES, 6) |
+	      FIELD_PREP(MESON_SDHC_MISC_WCRC_ERR_PATT, 5) |
+	      FIELD_PREP(MESON_SDHC_MISC_WCRC_OK_PATT, 2);
+	writel(val, host->base + MESON_SDHC_MISC);
+
+	val = FIELD_PREP(MESON_SDHC_ENHC_RXFIFO_TH, 64) |
+	      FIELD_PREP(MESON_SDHC_ENHC_MESON8M2_DEBUG, 1) |
+	      MESON_SDHC_ENHC_MESON8M2_WRRSP_MODE |
+	      FIELD_PREP(MESON_SDHC_ENHC_SDIO_IRQ_PERIOD, 12),
+	writel(val, host->base + MESON_SDHC_ENHC);
+}
+
+static void meson_mx_sdhc_set_pdma_meson8m2(struct mmc_host *mmc)
+{
+	meson_mx_sdhc_mask_bits(mmc, MESON_SDHC_PDMA,
+				MESON_SDHC_PDMA_DMA_MODE,
+				MESON_SDHC_PDMA_DMA_MODE);
+}
+
+static void meson_mx_sdhc_init_hw(struct mmc_host *mmc)
+{
+	struct meson_mx_sdhc_host *host = mmc_priv(mmc);
+	u32 val;
+
+	meson_mx_sdhc_hw_reset(mmc);
+
+	val = FIELD_PREP(MESON_SDHC_CTRL_RX_PERIOD, 0xf) |
+	      FIELD_PREP(MESON_SDHC_CTRL_RX_TIMEOUT, 0x7f) |
+	      FIELD_PREP(MESON_SDHC_CTRL_RX_ENDIAN, 0x7) |
+	      FIELD_PREP(MESON_SDHC_CTRL_TX_ENDIAN, 0x7);
+	writel(val, host->base + MESON_SDHC_CTRL);
+
+	/*
+	 * start with a valid divider and enable the memory (un-setting
+	 * MESON_SDHC_CLKC_MEM_PWR_OFF).
+	 */
+	val = MESON_SDHC_CLKC_CLK_DIV;
+	writel(val, host->base + MESON_SDHC_CLKC);
+
+	val = FIELD_PREP(MESON_SDHC_CLK2_SD_CLK_PHASE, 1);
+	writel(val, host->base + MESON_SDHC_CLK2);
+
+	val = MESON_SDHC_PDMA_DMA_URGENT |
+	      FIELD_PREP(MESON_SDHC_PDMA_WR_BURST, 7) |
+	      FIELD_PREP(MESON_SDHC_PDMA_TXFIFO_TH, 49) |
+	      FIELD_PREP(MESON_SDHC_PDMA_RD_BURST, 15) |
+	      FIELD_PREP(MESON_SDHC_PDMA_RXFIFO_TH, 7);
+	writel(val, host->base + MESON_SDHC_PDMA);
+
+	/* some initialization bits depend on the SoC: */
+	host->platform->init_hw(mmc);
+
+	/* disable and mask all interrupts: */
+	writel(0, host->base + MESON_SDHC_ICTL);
+	writel(MESON_SDHC_ISTA_ALL_IRQS, host->base + MESON_SDHC_ISTA);
+}
+
+static int meson_mx_sdhc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct meson_mx_sdhc_host *host;
+	struct mmc_host *mmc;
+	struct resource *res;
+	int ret, irq;
+
+	mmc = mmc_alloc_host(sizeof(*host), dev);
+	if (!mmc)
+		return -ENOMEM;
+
+	ret = devm_add_action_or_reset(dev, (void(*)(void *))mmc_free_host,
+				       mmc);
+	if (ret) {
+		dev_err(dev, "Failed to register mmc_free_host action\n");
+		return ret;
+	}
+
+	host = mmc_priv(mmc);
+	host->mmc = mmc;
+
+	platform_set_drvdata(pdev, host);
+
+	host->platform = device_get_match_data(dev);
+	if (!host->platform)
+		return -EINVAL;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	host->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(host->base))
+		return PTR_ERR(host->base);
+
+	host->pclk = devm_clk_get(dev, "pclk");
+	if (IS_ERR(host->pclk))
+		return PTR_ERR(host->pclk);
+
+	host->parent_clks[0].id = "clkin0";
+	host->parent_clks[1].id = "clkin1";
+	host->parent_clks[2].id = "clkin2";
+	host->parent_clks[3].id = "clkin3";
+	ret = devm_clk_bulk_get(dev, MESON_SDHC_PARENT_CLKS,
+				host->parent_clks);
+	if (ret)
+		return ret;
+
+	/* accessing any register requires the module clock to be enabled: */
+	ret = clk_prepare_enable(host->pclk);
+	if (ret) {
+		dev_err(dev, "Failed to enable 'pclk' clock\n");
+		return ret;
+	}
+
+	ret = devm_add_action_or_reset(dev,
+				       (void(*)(void *))clk_disable_unprepare,
+				       host->pclk);
+	if (ret) {
+		dev_err(dev,
+			"Failed to register clk_disable_unprepare action\n");
+		return ret;
+	}
+
+	meson_mx_sdhc_init_hw(mmc);
+
+	ret = meson_mx_sdhc_register_clks(host);
+	if (ret)
+		return ret;
+
+	/* Get regulators and the supported OCR mask */
+	ret = mmc_regulator_get_supply(mmc);
+	if (ret)
+		return ret;
+
+	mmc->max_req_size = MESON_SDHC_BOUNCE_REQ_SIZE;
+	mmc->max_seg_size = mmc->max_req_size;
+	mmc->max_blk_count = FIELD_GET(MESON_SDHC_SEND_TOTAL_PACK, ~0);
+	mmc->max_blk_size = MESON_SDHC_MAX_BLK_SIZE;
+	mmc->max_busy_timeout = 0; // TODO: actual value?
+	mmc->f_min = clk_round_rate(host->sd_clk, 1);
+	mmc->f_max = clk_round_rate(host->sd_clk, ~0UL);
+	mmc->max_current_180 = 300;
+	mmc->max_current_330 = 300;
+	mmc->caps |= MMC_CAP_ERASE | MMC_CAP_CMD23 | MMC_CAP_HW_RESET;
+	mmc->ops = &meson_mx_sdhc_ops;
+
+	ret = mmc_of_parse(mmc);
+	if (ret)
+		return ret;
+
+	irq = platform_get_irq(pdev, 0);
+	ret = devm_request_threaded_irq(dev, irq, meson_mx_sdhc_irq,
+					meson_mx_sdhc_irq_thread, IRQF_ONESHOT,
+					NULL, host);
+	if (ret)
+		return ret;
+
+	ret = mmc_add_host(mmc);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int meson_mx_sdhc_remove(struct platform_device *pdev)
+{
+	struct meson_mx_sdhc_host *host = platform_get_drvdata(pdev);
+
+	mmc_remove_host(host->mmc);
+
+	meson_mx_sdhc_disable_clks(host->mmc);
+
+	return 0;
+}
+
+static const struct meson_mx_sdhc_data meson_mx_sdhc_data_meson8 = {
+	.init_hw			= meson_mx_sdhc_init_hw_meson8,
+	.set_pdma			= meson_mx_sdhc_set_pdma_meson8,
+	.wait_before_send		= meson_mx_sdhc_wait_before_send_meson8,
+	.hardware_flush_all_cmds	= false,
+};
+
+static const struct meson_mx_sdhc_data meson_mx_sdhc_data_meson8m2 = {
+	.init_hw			= meson_mx_sdhc_init_hw_meson8m2,
+	.set_pdma			= meson_mx_sdhc_set_pdma_meson8m2,
+	.hardware_flush_all_cmds	= true,
+};
+
+static const struct of_device_id meson_mx_sdhc_of_match[] = {
+	{
+		.compatible = "amlogic,meson8-sdhc",
+		.data = &meson_mx_sdhc_data_meson8
+	},
+	{
+		.compatible = "amlogic,meson8b-sdhc",
+		.data = &meson_mx_sdhc_data_meson8
+	},
+	{
+		.compatible = "amlogic,meson8m2-sdhc",
+		.data = &meson_mx_sdhc_data_meson8m2
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, meson_mx_sdhc_of_match);
+
+static struct platform_driver meson_mx_sdhc_driver = {
+	.probe   = meson_mx_sdhc_probe,
+	.remove  = meson_mx_sdhc_remove,
+	.driver  = {
+		.name = "meson-mx-sdhc",
+		.of_match_table = of_match_ptr(meson_mx_sdhc_of_match),
+	},
+};
+
+module_platform_driver(meson_mx_sdhc_driver);
+
+MODULE_DESCRIPTION("Meson6, Meson8, Meson8b and Meson8m2 SDHC Host Driver");
+MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
+MODULE_LICENSE("GPL v2");
-- 
2.22.0

^ permalink raw reply related

* Re: [PATCH RFC v1 2/2] mmc: host: meson-mx-sdhc: new driver for the Amlogic Meson SDHC host
From: Martin Blumenstingl @ 2019-07-08 17:40 UTC (permalink / raw)
  To: jianxin.pan
  Cc: linux-kernel, linux-arm-kernel, mark.rutland, robh+dt,
	ulf.hansson, linux-mmc, devicetree, linux-amlogic
In-Reply-To: <20190708173330.13217-3-martin.blumenstingl@googlemail.com>

Hello Jianxin,

I thought I'd put my questions inline again so it's easier to follow me.
I hope you can help clarify some of the questions I have.

On Mon, Jul 8, 2019 at 7:33 PM Martin Blumenstingl
<martin.blumenstingl@googlemail.com> wrote:
>
> WiP - only partially working - see performance numbers.
>
> Odroid-C1 eMMC (HS-200):
> Amlogic's vendor driver @ Linux 3.10:
>   7781351936 bytes (7.8 GB) copied, 134.714 s, 57.8 MB/s
> This driver:
>   7781351936 bytes (7.8 GB, 7.2 GiB) copied, 189.02 s, 41.2 MB/s
>
> EC-100 eMMC (HS MMC):
> Amlogic's vendor driver @ Linux 3.10:
>   15762194432 bytes (16 GB) copied, 422.967 s, 37.3 MB/s
> This driver:
>   15762194432 bytes (16 GB, 15 GiB) copied, 9232.65 s, 1.7 MB/s
my EC-100 board uses high-speed MMC (no HS-200) mode only and it's
really bad there
on Odroid-C1 the MMC the performance is at ~70% of the 3.10 kernel driver

my thinking is that phase tuning "fixes" the performance on Odroid-C1
(EC-100 doesn't use tuning because it's not using HS-200 mode).
I could be wrong here though. Please let me know if you have any suggestions


[...]
> +               if (mmc->actual_clock > 100000000) {
> +                       rx_clk_phase = 1;
> +               } else if (mmc->actual_clock > 45000000) {
> +                       if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330)
> +                               rx_clk_phase = 15;
> +                       else
> +                               rx_clk_phase = 11;
> +               } else if (mmc->actual_clock >= 25000000) {
> +                       rx_clk_phase = 15;
> +               } else if (mmc->actual_clock > 5000000) {
> +                       rx_clk_phase = 23;
> +               } else if (mmc->actual_clock > 1000000) {
> +                       rx_clk_phase = 55;
> +               } else {
> +                       rx_clk_phase = 1061;
> +               }
this MMC clock frequency to RX clock phase mapping only seems to work
for FCLK_DIV3
how do I calculate this dynamically?

[...]
> +static int meson_mx_sdhc_register_clks(struct meson_mx_sdhc_host *host)
> +{
> +       struct clk *mux_parents[MESON_SDHC_PARENT_CLKS];
> +       struct clk *mux_clk, *div_clk;
> +       int i;
> +
> +       for (i = 0; i < MESON_SDHC_PARENT_CLKS; i++)
> +               mux_parents[i] = host->parent_clks[i].clk;
> +
> +       host->clkc_clk_src_sel.reg = host->base + MESON_SDHC_CLKC;
> +       host->clkc_clk_src_sel.shift = __ffs(MESON_SDHC_CLKC_CLK_SRC_SEL);
> +       host->clkc_clk_src_sel.mask = MESON_SDHC_CLKC_CLK_SRC_SEL >>
> +                                     host->clkc_clk_src_sel.shift;
> +       mux_clk = meson_mx_sdhc_register_clk(mmc_dev(host->mmc),
> +                                            &host->clkc_clk_src_sel.hw,
> +                                            "clk_src_sel",
> +                                            MESON_SDHC_PARENT_CLKS,
> +                                            mux_parents,
> +                                            CLK_SET_RATE_NO_REPARENT,
> +                                            &clk_mux_ops);
> +       if (IS_ERR(mux_clk))
> +               return PTR_ERR(mux_clk);
> +
> +       host->clkc_clk_div.reg = host->base + MESON_SDHC_CLKC;
> +       host->clkc_clk_div.shift = __ffs(MESON_SDHC_CLKC_CLK_DIV);
> +       host->clkc_clk_div.width = fls(MESON_SDHC_CLKC_CLK_DIV) -
> +                                  host->clkc_clk_div.shift;
are there any constraints for the divider?
the driver from the Amlogic kernel sources does this, but I'm not sure
what this is trying to achieve (and why):
       clk_div = input_rate / clk_ios - !(input_rate%clk_ios);
       if (!(clk_div & 0x01)) // if even number, turn it to an odd one
          clk_div++;

[...]
> +       mmc->max_busy_timeout = 0; // TODO: actual value?
do you know the actual busy timeout of this IP block?


Thank you for your time!
Regards
Martin

^ permalink raw reply

* Re: [PATCH v5 2/7] drm/panel: simple: Add ability to override typical timing
From: Sam Ravnborg @ 2019-07-08 17:50 UTC (permalink / raw)
  To: Doug Anderson
  Cc: devicetree, David Airlie, Jeffy Chen, LKML, Rob Herring,
	open list:ARM/Rockchip SoC..., Thierry Reding, Sean Paul,
	dri-devel, Boris Brezillon, Enric Balletbò,
	Stéphane Marchesin, Ezequiel Garcia, Matthias Kaehlcke,
	Laurent Pinchart
In-Reply-To: <CAD=FV=V_wTD1xpkXRe-z2HsZ8QXKq7jmq8CsfhMnFxi-5XDJjw@mail.gmail.com>

Hi Dough.

On Mon, Jul 01, 2019 at 09:39:24AM -0700, Doug Anderson wrote:
> Hi,
> 
> On Sun, Jun 30, 2019 at 1:22 PM Sam Ravnborg <sam@ravnborg.org> wrote:
> >
> > > @@ -91,6 +92,8 @@ struct panel_simple {
> > >       struct i2c_adapter *ddc;
> > >
> > >       struct gpio_desc *enable_gpio;
> > > +
> > > +     struct drm_display_mode override_mode;
> > I fail to see where this poiter is assigned.
> 
> In panel_simple_parse_override_mode().  Specifically:
> 
> drm_display_mode_from_videomode(&vm, &panel->override_mode);

The above code-snippet is only called in the panel has specified display
timings using display_timings - it is not called when display_mode is
used.
So override_mode is only assigned in some cases and not all cases.
This needs to be fixed so we do not reference override_mode unless
it is set.

> 
> 
> > @@ -152,6 +162,44 @@ static int panel_simple_get_fixed_modes(struct panel_simple *panel)
> > >               num++;
> > >       }
> > >
> > > +     return num;
> > > +}
> > > +
> > > +static int panel_simple_get_non_edid_modes(struct panel_simple *panel)
> > > +{
> > > +     struct drm_connector *connector = panel->base.connector;
> > > +     struct drm_device *drm = panel->base.drm;
> > > +     struct drm_display_mode *mode;
> > > +     bool has_override = panel->override_mode.type;
> > This looks suspicious.
> > panel->override_mode.type is an unsigned int that may have a number of
> > bits set.
> > So the above code implicitly convert a .type != 0 to a true.
> > This can be expressed in a much more reader friendly way.
> 
> You would suggest that I add a boolean field to a structure to
> indicate whether an override mode is present?
A simple  bool has_override = panel->override_mode.type != 0;
would do the trick here.
Then there is no hidden conversion from int to a bool.

But as override_mode can be NULL something more needs to be done.

	Sam
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply

* Re: [PATCH v5 2/7] drm/panel: simple: Add ability to override typical timing
From: Sam Ravnborg @ 2019-07-08 17:56 UTC (permalink / raw)
  To: Doug Anderson
  Cc: devicetree, David Airlie, Jeffy Chen, LKML, Rob Herring,
	open list:ARM/Rockchip SoC..., Thierry Reding, Sean Paul,
	dri-devel, Boris Brezillon, Enric Balletbò,
	Stéphane Marchesin, Ezequiel Garcia, Matthias Kaehlcke,
	Laurent Pinchart
In-Reply-To: <CAD=FV=WH4kmhQA0kbKcAUx=oOeqTZiQOFCXYpVWwq+mG7Y7ofA@mail.gmail.com>

On Mon, Jul 01, 2019 at 09:39:06AM -0700, Doug Anderson wrote:
> Hi,
> 
> On Sun, Jun 30, 2019 at 1:55 PM Sam Ravnborg <sam@ravnborg.org> wrote:
> >
> > Hi Douglas.
> >
> > > > +
> > > > +   /* Only add timings if override was not there or failed to validate */
> > > > +   if (num == 0 && panel->desc->num_timings)
> > > > +           num = panel_simple_get_timings_modes(panel);
> > > > +
> > > > +   /*
> > > > +    * Only add fixed modes if timings/override added no mode.
> > >
> > > This part I fail to understand.
> > > If we have a panel where we in panel-simple have specified the timings,
> > > and done so using display_timing so with proper {min, typ, max} then it
> > > should be perfectly legal to specify a more precise variant in the DT
> > > file.
> > > Or what did I miss here?
> >
> > Got it now.
> > If display_mode is used for timings this is what you call "fixed mode".
> > Hmm, if I got confused someone else may also be confused by this naming.
> 
> The name "fixed mode" comes from the old code, though I guess in the
> old code it used to refer to a mode that came from either the
> display_timing or the display_mode.
> 
> How about if I call it "panel_simple_get_from_fixed_display_mode"?
> ...or if you have another suggestion feel free to chime in.
What we really want to distingush here is the use of display_mode
and display_timings (if I got the names right).
That display_mode specify a fixed timing and display_timing specify
a valid range is something in the semantics of the two types.
So naming that refer to display_mode versus display_timing will make the
code simpler to understand. and then a nice comment that when
display_mode
is used one looses the possibility to use override_mode.
That would be fine to have in the struct in the driver.

> NOTE: Since this feedback is minor and this patch has been outstanding
> for a while (and is blocking other work), I am assuming that the best
> path forward is for Heiko to land this patch with Thierry's Ack and
> I'll send a follow-up.  Please yell if you disagree.
Let's give the patches a spin more as we have passed the possibility for
the current merge window.

I am on vacation at the moment and thus slow in responses, but will be back
at the home office next week and will be more responsive again.

	Sam - who is enjoying the alps in Austria

^ permalink raw reply

* Re: [PATCH 1/2] dt-bindings: backlight: fix vendor prefix for ArcticSand arcxcnn driver bindings
From: Dan Murphy @ 2019-07-08 18:02 UTC (permalink / raw)
  To: Brian Dodge, pavel
  Cc: devicetree, daniel.thompson, jingoohan1, dri-devel, robh+dt,
	jacek.anaszewski, pbacon, lee.jones, linux-leds
In-Reply-To: <1561940895-15837-2-git-send-email-bdodge09@gmail.com>

Brian

On 6/30/19 7:28 PM, Brian Dodge wrote:
> The vendor-prefixes.txt file properly refers to ArcticSand
> as arctic but the driver bindings improperly abbreviated the
> prefix to arc. This was a mistake in the original patch. This
> patch adds "arctic" and retains "arc" (deprecated) bindings
>
> Signed-off-by: Brian Dodge <bdodge09@gmail.com>
> ---
>   .../bindings/leds/backlight/arcxcnn_bl.txt         | 31 +++++++++++++++-------
>   1 file changed, 21 insertions(+), 10 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/leds/backlight/arcxcnn_bl.txt b/Documentation/devicetree/bindings/leds/backlight/arcxcnn_bl.txt
> index 230abde..4d98394 100644
> --- a/Documentation/devicetree/bindings/leds/backlight/arcxcnn_bl.txt
> +++ b/Documentation/devicetree/bindings/leds/backlight/arcxcnn_bl.txt
> @@ -1,8 +1,13 @@
> -Binding for ArcticSand arc2c0608 LED driver
> +Binding for ArcticSand arc family LED drivers
>   
>   Required properties:
> -- compatible:		should be "arc,arc2c0608"
> -- reg:			slave address
> +- compatible: one of
> +	"arctic,arc1c0608"
> +	"arctic,arc2c0608"
> +	"arctic,arc3c0845"
> +	"arc,arc2c0608" (deprecated)
> +
> +- reg:		slave address
>   
>   Optional properties:
>   - default-brightness:	brightness value on boot, value from: 0-4095
> @@ -11,19 +16,25 @@ Optional properties:
>   - led-sources:		List of enabled channels from 0 to 5.
>   			See Documentation/devicetree/bindings/leds/common.txt
>   
> -- arc,led-config-0:	setting for register ILED_CONFIG_0
> -- arc,led-config-1:	setting for register ILED_CONFIG_1
> -- arc,dim-freq:		PWM mode frequence setting (bits [3:0] used)
> -- arc,comp-config:	setting for register CONFIG_COMP
> -- arc,filter-config:	setting for register FILTER_CONFIG
> -- arc,trim-config:	setting for register IMAXTUNE
> +- arctic,led-config-0:	setting for register ILED_CONFIG_0
> +- arctic,led-config-1:	setting for register ILED_CONFIG_1
> +- arctic,dim-freq:	PWM mode frequence setting (bits [3:0] used)
> +- arctic,comp-config:	setting for register CONFIG_COMP
> +- arctic,filter-config:	setting for register FILTER_CONFIG
> +- arctic,trim-config:	setting for register IMAXTUNE
> +- arc,led-config-0:	setting for register ILED_CONFIG_0 (deprecated)
> +- arc,led-config-1:	setting for register ILED_CONFIG_1 (deprecated)
> +- arc,dim-freq:		PWM mode frequence setting (bits [3:0] used) (deprecated)
> +- arc,comp-config:	setting for register CONFIG_COMP (deprecated)
> +- arc,filter-config:	setting for register FILTER_CONFIG (deprecated)
> +- arc,trim-config:	setting for register IMAXTUNE (deprecated)
>   
>   Note: Optional properties not specified will default to values in IC EPROM
>   
>   Example:
>   
>   arc2c0608@30 {
> -	compatible = "arc,arc2c0608";
> +	compatible = "arctic,arc2c0608";
>   	reg = <0x30>;
>   	default-brightness = <500>;
>   	label = "lcd-backlight";


Reviewed-by: Dan Murphy <dmurphy@ti.com>

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply

* Re: [PATCH 2/2] backlight: arcxcnn: add "arctic" vendor prefix
From: Dan Murphy @ 2019-07-08 18:05 UTC (permalink / raw)
  To: Brian Dodge, pavel
  Cc: devicetree, daniel.thompson, jingoohan1, dri-devel, robh+dt,
	jacek.anaszewski, pbacon, lee.jones, linux-leds
In-Reply-To: <1561940895-15837-3-git-send-email-bdodge09@gmail.com>

Brian

On 6/30/19 7:28 PM, Brian Dodge wrote:
> The original patch adding this driver and DT bindings improperly
> used "arc" as the vendor-prefix. This adds "arctic" which is the
> proper prefix and retains "arc" to allow existing users of the
> "arc" prefix to update to new kernels. There is at least one
> (Samsung Chromebook Plus)
>
> Signed-off-by: Brian Dodge <bdodge09@gmail.com>
> Acked-by: Daniel Thompson <daniel.thompson@linaro.org>
> ---
>   drivers/video/backlight/arcxcnn_bl.c | 41 +++++++++++++++++++++++++++---------
>   1 file changed, 31 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/video/backlight/arcxcnn_bl.c b/drivers/video/backlight/arcxcnn_bl.c
> index 7b1c0a0..a419554 100644
> --- a/drivers/video/backlight/arcxcnn_bl.c
> +++ b/drivers/video/backlight/arcxcnn_bl.c
> @@ -1,9 +1,9 @@
>   // SPDX-License-Identifier: GPL-2.0-only
>   /*
> - * Backlight driver for ArcticSand ARC_X_C_0N_0N Devices
> + * Backlight driver for pSemi (formerly ArcticSand) ARC_X_C_0N_0N Devices
>    *
> - * Copyright 2016 ArcticSand, Inc.
> - * Author : Brian Dodge <bdodge@arcticsand.com>

I know you are the original author from ArcticSand but did pSemi 
actually own the copyright in 2016?

I don't think this is a big issue just wondering if we should retain the 
ArcticSand copyright as well.

Probably a question for your legal department.

Otherwise

Reviewed-by: Dan Murphy <dmurphy@ti.com>

> + * Copyright 2016-2019  pSemi, Inc.
> + * Author : Brian Dodge <bdodge@psemi.com>
>    */
>   
>   #include <linux/backlight.h>
> @@ -191,27 +191,46 @@ static void arcxcnn_parse_dt(struct arcxcnn *lp)
>   	if (ret == 0)
>   		lp->pdata->initial_brightness = prog_val;
>   
> -	ret = of_property_read_u32(node, "arc,led-config-0", &prog_val);
> +	ret = of_property_read_u32(node, "arctic,led-config-0", &prog_val);
> +	if (ret)
> +		ret = of_property_read_u32(node, "arc,led-config-0", &prog_val);
> +
>   	if (ret == 0)
>   		lp->pdata->led_config_0 = (u8)prog_val;
>   
> -	ret = of_property_read_u32(node, "arc,led-config-1", &prog_val);
> +	ret = of_property_read_u32(node, "arctic,led-config-1", &prog_val);
> +	if (ret)
> +		ret = of_property_read_u32(node, "arc,led-config-1", &prog_val);
> +
>   	if (ret == 0)
>   		lp->pdata->led_config_1 = (u8)prog_val;
>   
> -	ret = of_property_read_u32(node, "arc,dim-freq", &prog_val);
> +	ret = of_property_read_u32(node, "arctic,dim-freq", &prog_val);
> +	if (ret)
> +		ret = of_property_read_u32(node, "arc,dim-freq", &prog_val);
> +
>   	if (ret == 0)
>   		lp->pdata->dim_freq = (u8)prog_val;
>   
> -	ret = of_property_read_u32(node, "arc,comp-config", &prog_val);
> +	ret = of_property_read_u32(node, "arctic,comp-config", &prog_val);
> +	if (ret)
> +		ret = of_property_read_u32(node, "arc,comp-config", &prog_val);
> +
>   	if (ret == 0)
>   		lp->pdata->comp_config = (u8)prog_val;
>   
> -	ret = of_property_read_u32(node, "arc,filter-config", &prog_val);
> +	ret = of_property_read_u32(node, "arctic,filter-config", &prog_val);
> +	if (ret)
> +		ret = of_property_read_u32(node,
> +				"arc,filter-config", &prog_val);
> +
>   	if (ret == 0)
>   		lp->pdata->filter_config = (u8)prog_val;
>   
> -	ret = of_property_read_u32(node, "arc,trim-config", &prog_val);
> +	ret = of_property_read_u32(node, "arctic,trim-config", &prog_val);
> +	if (ret)
> +		ret = of_property_read_u32(node, "arc,trim-config", &prog_val);
> +
>   	if (ret == 0)
>   		lp->pdata->trim_config = (u8)prog_val;
>   
> @@ -381,6 +400,8 @@ static int arcxcnn_remove(struct i2c_client *cl)
>   }
>   
>   static const struct of_device_id arcxcnn_dt_ids[] = {
> +	{ .compatible = "arctic,arc2c0608" },
> +	/* here to remain compatible with an older binding, do not use */
>   	{ .compatible = "arc,arc2c0608" },
>   	{ }
>   };
> @@ -404,5 +425,5 @@ static struct i2c_driver arcxcnn_driver = {
>   module_i2c_driver(arcxcnn_driver);
>   
>   MODULE_LICENSE("GPL v2");
> -MODULE_AUTHOR("Brian Dodge <bdodge@arcticsand.com>");
> +MODULE_AUTHOR("Brian Dodge <bdodge@psemi.com>");
>   MODULE_DESCRIPTION("ARCXCNN Backlight driver");
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply

* Re: [PATCH v6 01/18] kunit: test: add KUnit test runner core
From: Brendan Higgins @ 2019-07-08 18:08 UTC (permalink / raw)
  To: Luis Chamberlain
  Cc: Frank Rowand, Greg KH, Josh Poimboeuf, Kees Cook, Kieran Bingham,
	Peter Zijlstra, Rob Herring, Stephen Boyd, shuah,
	Theodore Ts'o, Masahiro Yamada, devicetree, dri-devel,
	kunit-dev, open list:DOCUMENTATION, linux-fsdevel, linux-kbuild,
	Linux Kernel Mailing List,
	"open list:KERNEL SELFTEST FRAMEWORK" <linux-ks>
In-Reply-To: <20190705201505.GA19023@42.do-not-panic.com>

On Fri, Jul 5, 2019 at 1:15 PM Luis Chamberlain <mcgrof@kernel.org> wrote:
>
> On Wed, Jul 03, 2019 at 05:35:58PM -0700, Brendan Higgins wrote:
> > Add core facilities for defining unit tests; this provides a common way
> > to define test cases, functions that execute code which is under test
> > and determine whether the code under test behaves as expected; this also
> > provides a way to group together related test cases in test suites (here
> > we call them test_modules).
> >
> > Just define test cases and how to execute them for now; setting
> > expectations on code will be defined later.
> >
> > Signed-off-by: Brendan Higgins <brendanhiggins@google.com>
> > Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > Reviewed-by: Logan Gunthorpe <logang@deltatee.com>
>
> Reviewed-by: Luis Chamberlain <mcgrof@kernel.org>
>
> But a nitpick below, I think that can be fixed later with a follow up
> patch.
>
> > +/**
> > + * struct kunit - represents a running instance of a test.
> > + * @priv: for user to store arbitrary data. Commonly used to pass data created
> > + * in the init function (see &struct kunit_suite).
> > + *
> > + * Used to store information about the current context under which the test is
> > + * running. Most of this data is private and should only be accessed indirectly
> > + * via public functions; the one exception is @priv which can be used by the
> > + * test writer to store arbitrary data.
> > + *
> > + * A brief note on locking:
> > + *
> > + * First off, we need to lock because in certain cases a user may want to use an
> > + * expectation in a thread other than the thread that the test case is running
> > + * in.
>
> This as a prefix to the struct without a lock seems odd. It would be
> clearer I think if you'd explain here what locking mechanism we decided
> to use and why it suffices today.

Whoops, sorry this should have been in the next patch. Will fix.

> > +/**
> > + * suite_test() - used to register a &struct kunit_suite with KUnit.
>
> You mean kunit_test_suite()?

Yep, sorry about that. Will fix.

> > + * @suite: a statically allocated &struct kunit_suite.
> > + *
> > + * Registers @suite with the test framework. See &struct kunit_suite for more
> > + * information.
> > + *
> > + * NOTE: Currently KUnit tests are all run as late_initcalls; this means that
> > + * they cannot test anything where tests must run at a different init phase. One
> > + * significant restriction resulting from this is that KUnit cannot reliably
> > + * test anything that is initialize in the late_init phase.
>                             initialize prior to the late init phase.
>
>
> That is, this is useless to test things running early.

Yeah, I can add that phrasing in.

> > + *
> > + * TODO(brendanhiggins@google.com): Don't run all KUnit tests as late_initcalls.
> > + * I have some future work planned to dispatch all KUnit tests from the same
> > + * place, and at the very least to do so after everything else is definitely
> > + * initialized.
>
> TODOs are odd to be adding to documentation, this is just not common
> place practice. The NOTE should suffice for you.

Because it is a kernel doc? Would you usually make a separate
non-kernel doc comment for a TODO? I guess that makes sense.

Thanks!

^ permalink raw reply

* Re: [PATCH v6 01/18] kunit: test: add KUnit test runner core
From: Brendan Higgins @ 2019-07-08 18:12 UTC (permalink / raw)
  To: Luis Chamberlain
  Cc: Petr Mladek, open list:DOCUMENTATION, Peter Zijlstra,
	Amir Goldstein, dri-devel, Sasha Levin, Masahiro Yamada,
	Michael Ellerman, open list:KERNEL SELFTEST FRAMEWORK, shuah,
	linux-nvdimm, Frank Rowand, Knut Omang, Kieran Bingham, wfg,
	Joel Stanley, David Rientjes, Jeff Dike, Dan Carpenter,
	devicetree, linux-kbuild,
	"Bird, Timothy" <Tim.Bird>
In-Reply-To: <20190705202051.GB19023@42.do-not-panic.com>

On Fri, Jul 5, 2019 at 1:20 PM Luis Chamberlain <mcgrof@kernel.org> wrote:
>
> On Wed, Jul 03, 2019 at 05:35:58PM -0700, Brendan Higgins wrote:
> > +struct kunit {
> > +     void *priv;
> > +
> > +     /* private: internal use only. */
> > +     const char *name; /* Read only after initialization! */
> > +     bool success; /* Read only after test_case finishes! */
> > +};
>
> No lock attribute above.
>
> > +void kunit_init_test(struct kunit *test, const char *name)
> > +{
> > +     spin_lock_init(&test->lock);
> > +     test->name = name;
> > +     test->success = true;
> > +}
>
> And yet here you initialize a spin lock... This won't compile. Seems
> you forgot to remove this line. So I guess a re-spin is better.

Oh crap, sorry about that. You can't compile these patches until the
kbuild patch. I will fix this and make sure I didn't make any similar
mistakes on these early patches.

Thanks!
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply

* Здравствуйте! Вас интересуют клиентские базы данных?
From: devicetree @ 2019-07-08 13:54 UTC (permalink / raw)
  To: RvzBdevicetree

Здравствуйте! Вас интересуют клиентские базы данных?

^ 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