Most of these issues are reproduced while supporting Allwinner A64
MIPI-DSI [1] but to confirm it with other SoC this series is reworked
on A33 since the controller tested it A33 as of now.
Since we don't have proper evidence and documentation for dsi controller
in Allwinner, these changes are more likely to rely on new working BSP
codes (even the initial driver written as per this rule).
All these fixes/updates are tested in "bananapi,s070wv20-ct16" panel
on Allwinner A33, the same panel timings are available in panel-simple
in mainline tree.
Changes for v10:
- reworked previous "Fixes/updates" patches on A33
- reworked previous A64 DSI fixes on A33
- added proper detailed commit messages with logs
- tested on BPI-M2M board.
Changes for v9:
- rebase on drm-misc
- update commit messages
- add hsync_porch overflow patch
Changes for v8:
- rebase on master
- rework on commit messages
- rework video start delay
- include drq changes from previous version
Changes for v7:
- rebase on master
- collect Merlijn Wajer Tested-by credits.
Changes for v6:
- fixed all burst mode patches as per previous version comments
- rebase on master
- update proper commit message
- dropped unneeded comments
- order the patches that make review easy
Changes for v5, v4, v3, v2:
- use existing driver code construct for hblk computation
- create separate function for vblk computation
- cleanup commit messages
- update proper commit messages
- fixed checkpatch warnings/errors
- use proper return value for tcon0 probe
- add logic to get tcon0 divider values
- simplify timings code to support burst mode
- fix drq computation return values
- rebase on master
Any inputs?
Jagan.
[1] https://patchwork.freedesktop.org/series/57834/
Jagan Teki (11):
drm/sun4i: dsi: Fix TCON DRQ set bits
drm/sun4i: dsi: Update start value in video start delay
drm/sun4i: dsi: Fix video start delay computation
drm/sun4i: tcon: Compute DCLK dividers based on format, lanes
drm/sun4i: tcon: Export get tcon0 routine
drm/sun4i: dsi: Probe tcon0 during dsi_bind
drm/sun4i: dsi: Get tcon0_div at runtime
dt-bindings: sun6i-dsi: Add VCC-DSI supply property
drm/sun4i: sun6i_mipi_dsi: Add VCC-DSI regulator support
[DO NOT MERGE] drm/panel: Add Bananapi S070WV20-CT16 ICN6211 MIPI-DSI to RGB bridge
[DO NOT MERGE] ARM: dts: sun8i: bananapi-m2m: Enable Bananapi S070WV20-CT16 DSI panel
.../bindings/display/sunxi/sun6i-dsi.txt | 1 +
arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts | 40 +++
drivers/gpu/drm/panel/Kconfig | 9 +
drivers/gpu/drm/panel/Makefile | 1 +
.../panel/panel-bananapi-s070wv20-icn6211.c | 293 ++++++++++++++++++
drivers/gpu/drm/sun4i/sun4i_tcon.c | 7 +-
drivers/gpu/drm/sun4i/sun4i_tcon.h | 1 +
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 46 ++-
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h | 4 +-
9 files changed, 393 insertions(+), 9 deletions(-)
create mode 100644 drivers/gpu/drm/panel/panel-bananapi-s070wv20-icn6211.c
--
2.18.0.321.gffc6fa0e3
Allwinner MIPI DSI controllers are supplied with SoC DSI
power rails via VCC-DSI pin.
Some board still work without supplying this but give more
faith on datasheet and hardware schematics and document this
supply property in required property list.
Reviewed-by: Rob Herring <[email protected]>
Tested-by: Merlijn Wajer <[email protected]>
Signed-off-by: Jagan Teki <[email protected]>
---
Documentation/devicetree/bindings/display/sunxi/sun6i-dsi.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/display/sunxi/sun6i-dsi.txt b/Documentation/devicetree/bindings/display/sunxi/sun6i-dsi.txt
index 6a6cf5de08b0..1cc40663b7a2 100644
--- a/Documentation/devicetree/bindings/display/sunxi/sun6i-dsi.txt
+++ b/Documentation/devicetree/bindings/display/sunxi/sun6i-dsi.txt
@@ -21,6 +21,7 @@ Required properties:
- phys: phandle to the D-PHY
- phy-names: must be "dphy"
- resets: phandle to the reset controller driving the encoder
+ - vcc-dsi-supply: the VCC-DSI power supply of the DSI encoder
- ports: A ports node with endpoint definitions as defined in
Documentation/devicetree/bindings/media/video-interfaces.txt. The
--
2.18.0.321.gffc6fa0e3
Bananapi S070WV20-CT16 ICN6211 is 800x480, 4-lane MIPI-DSI to RGB bridge
panel which can be used to connect via DSI port on BPI-M64 board,
so add a driver for it.
The same panel PCB comes with parallel RBG which is supported via
panel-simple driver with "bananapi,s070wv20-ct16" compatible.
Signed-off-by: Jagan Teki <[email protected]>
---
drivers/gpu/drm/panel/Kconfig | 9 +
drivers/gpu/drm/panel/Makefile | 1 +
.../panel/panel-bananapi-s070wv20-icn6211.c | 293 ++++++++++++++++++
3 files changed, 303 insertions(+)
create mode 100644 drivers/gpu/drm/panel/panel-bananapi-s070wv20-icn6211.c
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index e36dbb4df867..d0cb2fa3e721 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -17,6 +17,15 @@ config DRM_PANEL_ARM_VERSATILE
reference designs. The panel is detected using special registers
in the Versatile family syscon registers.
+config DRM_PANEL_BANANAPI_S070WV20_ICN6211
+ tristate "Bananapi S070WV20-CT16 ICN6211 MIPI-DSI to RGB bridge panel driver"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ help
+ Say Y if you want to enable support for panels based on the
+ Bananapi S070WV20-CT16 MIPI-DSI controller.
+
config DRM_PANEL_LVDS
tristate "Generic LVDS panel driver"
depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 78e3dc376bdd..a68e990a4a73 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_DRM_PANEL_ARM_VERSATILE) += panel-arm-versatile.o
+obj-$(CONFIG_DRM_PANEL_BANANAPI_S070WV20_ICN6211) += panel-bananapi-s070wv20-icn6211.o
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
diff --git a/drivers/gpu/drm/panel/panel-bananapi-s070wv20-icn6211.c b/drivers/gpu/drm/panel/panel-bananapi-s070wv20-icn6211.c
new file mode 100644
index 000000000000..52a5b60278af
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-bananapi-s070wv20-icn6211.c
@@ -0,0 +1,293 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Amarula Solutions
+ * Author: Jagan Teki <[email protected]>
+ */
+
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+
+struct s070wv20 {
+ struct drm_panel panel;
+ struct mipi_dsi_device *dsi;
+
+ struct backlight_device *backlight;
+ struct regulator *vdd;
+ struct gpio_desc *enable_gpio;
+ struct gpio_desc *reset_gpio;
+};
+
+static inline struct s070wv20 *panel_to_s070wv20(struct drm_panel *panel)
+{
+ return container_of(panel, struct s070wv20, panel);
+}
+
+struct s070wv20_init_cmd {
+ size_t len;
+ const char *data;
+};
+
+#define S070WV20_INIT_CMD(...) { \
+ .len = sizeof((char[]){__VA_ARGS__}), \
+ .data = (char[]){__VA_ARGS__} }
+
+static const struct s070wv20_init_cmd s070wv20_init_cmds[] = {
+ S070WV20_INIT_CMD(0x7A, 0xC1),
+ S070WV20_INIT_CMD(0x20, 0x20),
+ S070WV20_INIT_CMD(0x21, 0xE0),
+ S070WV20_INIT_CMD(0x22, 0x13),
+ S070WV20_INIT_CMD(0x23, 0x28),
+ S070WV20_INIT_CMD(0x24, 0x30),
+ S070WV20_INIT_CMD(0x25, 0x28),
+ S070WV20_INIT_CMD(0x26, 0x00),
+ S070WV20_INIT_CMD(0x27, 0x0D),
+ S070WV20_INIT_CMD(0x28, 0x03),
+ S070WV20_INIT_CMD(0x29, 0x1D),
+ S070WV20_INIT_CMD(0x34, 0x80),
+ S070WV20_INIT_CMD(0x36, 0x28),
+ S070WV20_INIT_CMD(0xB5, 0xA0),
+ S070WV20_INIT_CMD(0x5C, 0xFF),
+ S070WV20_INIT_CMD(0x2A, 0x01),
+ S070WV20_INIT_CMD(0x56, 0x92),
+ S070WV20_INIT_CMD(0x6B, 0x71),
+ S070WV20_INIT_CMD(0x69, 0x2B),
+ S070WV20_INIT_CMD(0x10, 0x40),
+ S070WV20_INIT_CMD(0x11, 0x98),
+ S070WV20_INIT_CMD(0xB6, 0x20),
+ S070WV20_INIT_CMD(0x51, 0x20),
+ S070WV20_INIT_CMD(0x09, 0x10),
+};
+
+static int s070wv20_prepare(struct drm_panel *panel)
+{
+ struct s070wv20 *ctx = panel_to_s070wv20(panel);
+ struct mipi_dsi_device *dsi = ctx->dsi;
+ unsigned int i;
+ int ret;
+
+ ret = regulator_enable(ctx->vdd);
+ if (ret)
+ return ret;
+
+ msleep(50);
+
+ gpiod_set_value(ctx->reset_gpio, 1);
+ msleep(50);
+
+ gpiod_set_value(ctx->enable_gpio, 1);
+ msleep(50);
+
+ gpiod_set_value(ctx->reset_gpio, 0);
+ msleep(50);
+
+ gpiod_set_value(ctx->reset_gpio, 1);
+ msleep(20);
+
+ for (i = 0; i < ARRAY_SIZE(s070wv20_init_cmds); i++) {
+ const struct s070wv20_init_cmd *cmd = &s070wv20_init_cmds[i];
+
+ ret = mipi_dsi_generic_write(dsi, cmd->data, cmd->len);
+ if (ret < 0)
+ return ret;
+
+ msleep(10);
+ }
+
+ return 0;
+}
+
+static int s070wv20_enable(struct drm_panel *panel)
+{
+ struct s070wv20 *ctx = panel_to_s070wv20(panel);
+
+ msleep(120);
+
+ mipi_dsi_dcs_set_display_on(ctx->dsi);
+ backlight_enable(ctx->backlight);
+
+ return 0;
+}
+
+static int s070wv20_disable(struct drm_panel *panel)
+{
+ struct s070wv20 *ctx = panel_to_s070wv20(panel);
+
+ backlight_disable(ctx->backlight);
+ return mipi_dsi_dcs_set_display_on(ctx->dsi);
+}
+
+static int s070wv20_unprepare(struct drm_panel *panel)
+{
+ struct s070wv20 *ctx = panel_to_s070wv20(panel);
+ int ret;
+
+ ret = mipi_dsi_dcs_set_display_off(ctx->dsi);
+ if (ret < 0)
+ dev_err(panel->dev, "failed to set display off: %d\n", ret);
+
+ ret = mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
+ if (ret < 0)
+ dev_err(panel->dev, "failed to enter sleep mode: %d\n", ret);
+
+ msleep(100);
+
+ gpiod_set_value(ctx->reset_gpio, 0);
+
+ gpiod_set_value(ctx->reset_gpio, 1);
+
+ gpiod_set_value(ctx->enable_gpio, 0);
+
+ gpiod_set_value(ctx->reset_gpio, 0);
+
+ regulator_disable(ctx->vdd);
+
+ return 0;
+}
+
+static const struct drm_display_mode s070wv20_default_mode = {
+ .clock = 30000,
+ .vrefresh = 60,
+
+ .hdisplay = 800,
+ .hsync_start = 800 + 40,
+ .hsync_end = 800 + 40 + 48,
+ .htotal = 800 + 40 + 48 + 40,
+
+ .vdisplay = 480,
+ .vsync_start = 480 + 13,
+ .vsync_end = 480 + 13 + 3,
+ .vtotal = 480 + 13 + 3 + 29,
+
+ .width_mm = 86,
+ .height_mm = 154,
+};
+
+static int s070wv20_get_modes(struct drm_panel *panel)
+{
+ struct drm_connector *connector = panel->connector;
+ struct s070wv20 *ctx = panel_to_s070wv20(panel);
+ struct drm_display_mode *mode;
+
+ mode = drm_mode_duplicate(panel->drm, &s070wv20_default_mode);
+ if (!mode) {
+ dev_err(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n",
+ s070wv20_default_mode.hdisplay,
+ s070wv20_default_mode.vdisplay,
+ s070wv20_default_mode.vrefresh);
+ return -ENOMEM;
+ }
+
+ drm_mode_set_name(mode);
+
+ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+ drm_mode_probed_add(connector, mode);
+
+ panel->connector->display_info.width_mm = mode->width_mm;
+ panel->connector->display_info.height_mm = mode->height_mm;
+
+ return 1;
+}
+
+static const struct drm_panel_funcs s070wv20_funcs = {
+ .disable = s070wv20_disable,
+ .unprepare = s070wv20_unprepare,
+ .prepare = s070wv20_prepare,
+ .enable = s070wv20_enable,
+ .get_modes = s070wv20_get_modes,
+};
+
+static int s070wv20_dsi_probe(struct mipi_dsi_device *dsi)
+{
+ struct device_node *np;
+ struct s070wv20 *ctx;
+ int ret;
+
+ ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+ mipi_dsi_set_drvdata(dsi, ctx);
+ ctx->dsi = dsi;
+
+ drm_panel_init(&ctx->panel);
+ ctx->panel.dev = &dsi->dev;
+ ctx->panel.funcs = &s070wv20_funcs;
+
+ ctx->vdd = devm_regulator_get(&dsi->dev, "vdd");
+ if (IS_ERR(ctx->vdd)) {
+ dev_err(&dsi->dev, "Couldn't get vdd regulator\n");
+ return PTR_ERR(ctx->vdd);
+ }
+
+ ctx->enable_gpio = devm_gpiod_get(&dsi->dev, "enable", GPIOD_OUT_LOW);
+ if (IS_ERR(ctx->enable_gpio)) {
+ dev_err(&dsi->dev, "Couldn't get our enable GPIO\n");
+ return PTR_ERR(ctx->enable_gpio);
+ }
+
+ ctx->reset_gpio = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(ctx->reset_gpio)) {
+ dev_err(&dsi->dev, "Couldn't get our reset GPIO\n");
+ return PTR_ERR(ctx->reset_gpio);
+ }
+
+ np = of_parse_phandle(dsi->dev.of_node, "backlight", 0);
+ if (np) {
+ ctx->backlight = of_find_backlight_by_node(np);
+ of_node_put(np);
+
+ if (!ctx->backlight)
+ return -EPROBE_DEFER;
+ }
+
+ ret = drm_panel_add(&ctx->panel);
+ if (ret < 0)
+ return ret;
+
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->lanes = 4;
+
+ return mipi_dsi_attach(dsi);
+}
+
+static int s070wv20_dsi_remove(struct mipi_dsi_device *dsi)
+{
+ struct s070wv20 *ctx = mipi_dsi_get_drvdata(dsi);
+
+ mipi_dsi_detach(dsi);
+ drm_panel_remove(&ctx->panel);
+
+ if (ctx->backlight)
+ put_device(&ctx->backlight->dev);
+
+ return 0;
+}
+
+static const struct of_device_id s070wv20_of_match[] = {
+ { .compatible = "bananapi,s070wv20-ct16-icn6211", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, s070wv20_of_match);
+
+static struct mipi_dsi_driver s070wv20_driver = {
+ .probe = s070wv20_dsi_probe,
+ .remove = s070wv20_dsi_remove,
+ .driver = {
+ .name = "bananapi-s070wv20-ct16-icn6211",
+ .of_match_table = s070wv20_of_match,
+ },
+};
+module_mipi_dsi_driver(s070wv20_driver);
+
+MODULE_AUTHOR("Jagan Teki <[email protected]>");
+MODULE_DESCRIPTION("Bananapi S070WV20-CT16 ICN6211 MIPI-DSI to RGB");
+MODULE_LICENSE("GPL v2");
--
2.18.0.321.gffc6fa0e3
Allwinner MIPI DSI controllers are supplied with SoC
DSI power rails via VCC-DSI pin.
Add support for this supply pin by adding voltage
regulator handling code to MIPI DSI driver.
Tested-by: Merlijn Wajer <[email protected]>
Signed-off-by: Jagan Teki <[email protected]>
---
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 14 ++++++++++++++
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h | 3 +++
2 files changed, 17 insertions(+)
diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
index 5584e9c2f8bd..a5d73a283ed7 100644
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
@@ -1150,6 +1150,12 @@ static int sun6i_dsi_probe(struct platform_device *pdev)
return PTR_ERR(base);
}
+ dsi->regulator = devm_regulator_get(dev, "vcc-dsi");
+ if (IS_ERR(dsi->regulator)) {
+ dev_err(dev, "Couldn't get VCC-DSI supply\n");
+ return PTR_ERR(dsi->regulator);
+ }
+
dsi->regs = devm_regmap_init_mmio_clk(dev, "bus", base,
&sun6i_dsi_regmap_config);
if (IS_ERR(dsi->regs)) {
@@ -1223,6 +1229,13 @@ static int sun6i_dsi_remove(struct platform_device *pdev)
static int __maybe_unused sun6i_dsi_runtime_resume(struct device *dev)
{
struct sun6i_dsi *dsi = dev_get_drvdata(dev);
+ int err;
+
+ err = regulator_enable(dsi->regulator);
+ if (err) {
+ dev_err(dsi->dev, "failed to enable VCC-DSI supply: %d\n", err);
+ return err;
+ }
reset_control_deassert(dsi->reset);
clk_prepare_enable(dsi->mod_clk);
@@ -1255,6 +1268,7 @@ static int __maybe_unused sun6i_dsi_runtime_suspend(struct device *dev)
clk_disable_unprepare(dsi->mod_clk);
reset_control_assert(dsi->reset);
+ regulator_disable(dsi->regulator);
return 0;
}
diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
index 156523859d82..c76b71259d2e 100644
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
@@ -13,6 +13,8 @@
#include <drm/drm_encoder.h>
#include <drm/drm_mipi_dsi.h>
+#include <linux/regulator/consumer.h>
+
struct sun6i_dsi {
struct drm_connector connector;
struct drm_encoder encoder;
@@ -21,6 +23,7 @@ struct sun6i_dsi {
struct clk *bus_clk;
struct clk *mod_clk;
struct regmap *regs;
+ struct regulator *regulator;
struct reset_control *reset;
struct phy *dphy;
--
2.18.0.321.gffc6fa0e3
On Mon, May 20, 2019 at 02:33:16PM +0530, Jagan Teki wrote:
> Allwinner MIPI DSI controllers are supplied with SoC
> DSI power rails via VCC-DSI pin.
>
> Add support for this supply pin by adding voltage
> regulator handling code to MIPI DSI driver.
>
> Tested-by: Merlijn Wajer <[email protected]>
> Signed-off-by: Jagan Teki <[email protected]>
This creates a lot of warnings at boot time on my board this is
missing vcc-dsi-supply.
Maxime
--
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
On Thu, Jun 13, 2019 at 01:25:52PM +0530, Jagan Teki wrote:
> On Mon, Jun 3, 2019 at 7:19 PM Maxime Ripard <[email protected]> wrote:
> >
> > On Mon, May 20, 2019 at 02:33:16PM +0530, Jagan Teki wrote:
> > > Allwinner MIPI DSI controllers are supplied with SoC
> > > DSI power rails via VCC-DSI pin.
> > >
> > > Add support for this supply pin by adding voltage
> > > regulator handling code to MIPI DSI driver.
> > >
> > > Tested-by: Merlijn Wajer <[email protected]>
> > > Signed-off-by: Jagan Teki <[email protected]>
> >
> > This creates a lot of warnings at boot time on my board this is
> > missing vcc-dsi-supply.
>
> Is it about regulator_put or similar, would you provide the log.
Sure
http://code.bulix.org/whiea9-769551?raw
Maxime
--
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
On Mon, Jun 3, 2019 at 7:19 PM Maxime Ripard <[email protected]> wrote:
>
> On Mon, May 20, 2019 at 02:33:16PM +0530, Jagan Teki wrote:
> > Allwinner MIPI DSI controllers are supplied with SoC
> > DSI power rails via VCC-DSI pin.
> >
> > Add support for this supply pin by adding voltage
> > regulator handling code to MIPI DSI driver.
> >
> > Tested-by: Merlijn Wajer <[email protected]>
> > Signed-off-by: Jagan Teki <[email protected]>
>
> This creates a lot of warnings at boot time on my board this is
> missing vcc-dsi-supply.
Is it about regulator_put or similar, would you provide the log.