* [PATCH v1 0/2] Add LT9611UXC DSI to HDMI bridge support
@ 2020-08-28 12:04 ` Dmitry Baryshkov
0 siblings, 0 replies; 21+ messages in thread
From: Dmitry Baryshkov @ 2020-08-28 12:04 UTC (permalink / raw)
To: devicetree, dri-devel
Cc: linux-arm-msm, Rob Herring, Daniel Vetter, David Airlie,
Andrzej Hajda, Neil Armstrong, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Vinod Koul
Hi,
This series adds support for Lontium LT9611UXC bridge chip which takes
MIPI DSI as input and provides HDMI signal as output.
The chip can be found in Qualcomm RB5 platform [1], [2].
[1] https://www.qualcomm.com/products/qualcomm-robotics-rb5-platform
[2] https://www.thundercomm.com/app_en/product/1590131656070623
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v1 0/2] Add LT9611UXC DSI to HDMI bridge support
@ 2020-08-28 12:04 ` Dmitry Baryshkov
0 siblings, 0 replies; 21+ messages in thread
From: Dmitry Baryshkov @ 2020-08-28 12:04 UTC (permalink / raw)
To: devicetree, dri-devel
Cc: Jernej Skrabec, Neil Armstrong, David Airlie, linux-arm-msm,
Jonas Karlman, Andrzej Hajda, Vinod Koul, Rob Herring,
Laurent Pinchart
Hi,
This series adds support for Lontium LT9611UXC bridge chip which takes
MIPI DSI as input and provides HDMI signal as output.
The chip can be found in Qualcomm RB5 platform [1], [2].
[1] https://www.qualcomm.com/products/qualcomm-robotics-rb5-platform
[2] https://www.thundercomm.com/app_en/product/1590131656070623
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v1 1/2] dt-bindings: display: bridge: Add documentation for LT9611UXC
2020-08-28 12:04 ` Dmitry Baryshkov
@ 2020-08-28 12:04 ` Dmitry Baryshkov
-1 siblings, 0 replies; 21+ messages in thread
From: Dmitry Baryshkov @ 2020-08-28 12:04 UTC (permalink / raw)
To: devicetree, dri-devel
Cc: linux-arm-msm, Rob Herring, Daniel Vetter, David Airlie,
Andrzej Hajda, Neil Armstrong, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Vinod Koul
Lontium LT9611UXC is a DSI to HDMI bridge which supports 2 DSI ports
and I2S port as input and one HDMI port as output. The LT9611UXC chip is
handled by a separate driver, but the bindings used are fully compatible
with the LT9611 chip, so let's reuse the lt9611.yaml schema.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
.../devicetree/bindings/display/bridge/lontium,lt9611.yaml | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml b/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml
index d60208359234..7a1c89b995e2 100644
--- a/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml
+++ b/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml
@@ -4,18 +4,19 @@
$id: http://devicetree.org/schemas/display/bridge/lontium,lt9611.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: Lontium LT9611 2 Port MIPI to HDMI Bridge
+title: Lontium LT9611(UXC) 2 Port MIPI to HDMI Bridge
maintainers:
- Vinod Koul <vkoul@kernel.org>
description: |
- The LT9611 is a bridge device which converts DSI to HDMI
+ The LT9611 and LT9611UXC are bridge devices which convert DSI to HDMI
properties:
compatible:
enum:
- lontium,lt9611
+ - lontium,lt9611uxc
reg:
maxItems: 1
--
2.28.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v1 1/2] dt-bindings: display: bridge: Add documentation for LT9611UXC
@ 2020-08-28 12:04 ` Dmitry Baryshkov
0 siblings, 0 replies; 21+ messages in thread
From: Dmitry Baryshkov @ 2020-08-28 12:04 UTC (permalink / raw)
To: devicetree, dri-devel
Cc: Jernej Skrabec, Neil Armstrong, David Airlie, linux-arm-msm,
Jonas Karlman, Andrzej Hajda, Vinod Koul, Rob Herring,
Laurent Pinchart
Lontium LT9611UXC is a DSI to HDMI bridge which supports 2 DSI ports
and I2S port as input and one HDMI port as output. The LT9611UXC chip is
handled by a separate driver, but the bindings used are fully compatible
with the LT9611 chip, so let's reuse the lt9611.yaml schema.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
.../devicetree/bindings/display/bridge/lontium,lt9611.yaml | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml b/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml
index d60208359234..7a1c89b995e2 100644
--- a/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml
+++ b/Documentation/devicetree/bindings/display/bridge/lontium,lt9611.yaml
@@ -4,18 +4,19 @@
$id: http://devicetree.org/schemas/display/bridge/lontium,lt9611.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: Lontium LT9611 2 Port MIPI to HDMI Bridge
+title: Lontium LT9611(UXC) 2 Port MIPI to HDMI Bridge
maintainers:
- Vinod Koul <vkoul@kernel.org>
description: |
- The LT9611 is a bridge device which converts DSI to HDMI
+ The LT9611 and LT9611UXC are bridge devices which convert DSI to HDMI
properties:
compatible:
enum:
- lontium,lt9611
+ - lontium,lt9611uxc
reg:
maxItems: 1
--
2.28.0
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v1 2/2] drm: bridge: add support for lontium LT9611UXC bridge
2020-08-28 12:04 ` Dmitry Baryshkov
@ 2020-08-28 12:04 ` Dmitry Baryshkov
-1 siblings, 0 replies; 21+ messages in thread
From: Dmitry Baryshkov @ 2020-08-28 12:04 UTC (permalink / raw)
To: devicetree, dri-devel
Cc: linux-arm-msm, Rob Herring, Daniel Vetter, David Airlie,
Andrzej Hajda, Neil Armstrong, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Vinod Koul
Add support for Lontium LT9611UXC HDMI bridge. Lontium LT9611UXC is a
DSI to HDMI bridge which supports two DSI ports and I2S port as an input
and HDMI port as output. Despite name being similar to LT9611, these
devices are different enough to warrant separate driver.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
drivers/gpu/drm/bridge/Kconfig | 13 +
drivers/gpu/drm/bridge/Makefile | 1 +
drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 777 +++++++++++++++++++++
3 files changed, 791 insertions(+)
create mode 100644 drivers/gpu/drm/bridge/lontium-lt9611uxc.c
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 3e11af4e9f63..8343fb054652 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -61,6 +61,19 @@ config DRM_LONTIUM_LT9611
HDMI signals
Please say Y if you have such hardware.
+config DRM_LONTIUM_LT9611UXC
+ tristate "Lontium LT9611UXC DSI/HDMI bridge"
+ select SND_SOC_HDMI_CODEC if SND_SOC
+ depends on OF
+ select DRM_PANEL_BRIDGE
+ select DRM_KMS_HELPER
+ select REGMAP_I2C
+ help
+ Driver for Lontium LT9611UXC DSI to HDMI bridge
+ chip driver that converts dual DSI and I2S to
+ HDMI signals
+ Please say Y if you have such hardware.
+
config DRM_LVDS_CODEC
tristate "Transparent LVDS encoders and decoders support"
depends on OF
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index c589a6a7cbe1..306850a5899b 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o
obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o
obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o
obj-$(CONFIG_DRM_LONTIUM_LT9611) += lontium-lt9611.o
+obj-$(CONFIG_DRM_LONTIUM_LT9611UXC) += lontium-lt9611uxc.o
obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o
obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o
obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
new file mode 100644
index 000000000000..fc363b65590d
--- /dev/null
+++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
@@ -0,0 +1,777 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019-2020. Linaro Limited.
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include <sound/hdmi-codec.h>
+
+#include <video/display_timing.h>
+#include <video/of_display_timing.h>
+#include <video/videomode.h>
+
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_print.h>
+
+#define EDID_BLOCK_SIZE 128
+#define EDID_NUM_BLOCKS 2
+
+struct lt9611uxc {
+ struct device *dev;
+ struct drm_bridge bridge;
+
+ struct regmap *regmap;
+ /* Protects all accesses to registers by stopping the on-chip MCU */
+ struct mutex ocm_lock;
+
+ struct device_node *dsi0_node;
+ struct device_node *dsi1_node;
+ struct mipi_dsi_device *dsi0;
+ struct mipi_dsi_device *dsi1;
+ struct platform_device *audio_pdev;
+
+ struct gpio_desc *reset_gpio;
+ struct gpio_desc *enable_gpio;
+
+ bool sleep;
+
+ struct regulator_bulk_data supplies[2];
+
+ struct i2c_client *client;
+
+ bool hpd_supported;
+ struct display_timings *timings;
+ u8 edid_buf[EDID_BLOCK_SIZE * EDID_NUM_BLOCKS];
+};
+
+#define LT9611_PAGE_CONTROL 0xff
+
+static const struct regmap_range_cfg lt9611uxc_ranges[] = {
+ {
+ .name = "register_range",
+ .range_min = 0,
+ .range_max = 0xd0ff,
+ .selector_reg = LT9611_PAGE_CONTROL,
+ .selector_mask = 0xff,
+ .selector_shift = 0,
+ .window_start = 0,
+ .window_len = 0x100,
+ },
+};
+
+static const struct regmap_config lt9611uxc_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0xffff,
+ .ranges = lt9611uxc_ranges,
+ .num_ranges = ARRAY_SIZE(lt9611uxc_ranges),
+};
+
+struct lt9611uxc_mode {
+ u16 hdisplay;
+ u16 vdisplay;
+ u8 vrefresh;
+ u8 lanes;
+ u8 intfs;
+};
+
+static struct lt9611uxc_mode lt9611uxc_modes[] = {
+ { 3840, 2160, 60, 4, 2 }, /* 3840x2160 24bit 60Hz 4Lane 2ports */
+ { 3840, 2160, 30, 4, 2 }, /* 3840x2160 24bit 30Hz 4Lane 2ports */
+ { 1920, 1080, 60, 4, 1 }, /* 1080P 24bit 60Hz 4lane 1port */
+ { 1920, 1080, 30, 3, 1 }, /* 1080P 24bit 30Hz 3lane 1port */
+ { 1920, 1080, 24, 3, 1 },
+ { 1024, 768, 60, 4, 1},
+ { 800, 600, 60, 4, 1},
+ { 720, 480, 60, 4, 1 },
+ { 720, 576, 50, 2, 1 },
+ { 640, 480, 60, 2, 1 },
+};
+
+static struct lt9611uxc *bridge_to_lt9611uxc(struct drm_bridge *bridge)
+{
+ return container_of(bridge, struct lt9611uxc, bridge);
+}
+
+static void lt9611uxc_lock(struct lt9611uxc *lt9611uxc)
+{
+ mutex_lock(<9611uxc->ocm_lock);
+ regmap_write(lt9611uxc->regmap, 0x80ee, 0x01);
+}
+
+static void lt9611uxc_unlock(struct lt9611uxc *lt9611uxc)
+{
+ regmap_write(lt9611uxc->regmap, 0x80ee, 0x00);
+ msleep(50);
+ mutex_unlock(<9611uxc->ocm_lock);
+}
+
+static irqreturn_t lt9611uxc_irq_thread_handler(int irq, void *dev_id)
+{
+ struct lt9611uxc *lt9611uxc = dev_id;
+ unsigned int irq_status = 0;
+ unsigned int hpd_status = 0;
+
+ lt9611uxc_lock(lt9611uxc);
+
+ regmap_read(lt9611uxc->regmap, 0xb022, &irq_status);
+ if (irq_status) {
+ regmap_write(lt9611uxc->regmap, 0xb022, 0);
+ regmap_read(lt9611uxc->regmap, 0xb023, &hpd_status);
+ }
+
+ lt9611uxc_unlock(lt9611uxc);
+
+ if (irq_status & 0x3 && lt9611uxc->bridge.dev)
+ drm_kms_helper_hotplug_event(lt9611uxc->bridge.dev);
+
+ return IRQ_HANDLED;
+}
+
+static void lt9611uxc_reset(struct lt9611uxc *lt9611uxc)
+{
+ gpiod_set_value_cansleep(lt9611uxc->reset_gpio, 1);
+ msleep(20);
+
+ gpiod_set_value_cansleep(lt9611uxc->reset_gpio, 0);
+ msleep(20);
+
+ gpiod_set_value_cansleep(lt9611uxc->reset_gpio, 1);
+ msleep(180);
+
+ lt9611uxc->sleep = false;
+}
+
+static void lt9611uxc_assert_5v(struct lt9611uxc *lt9611uxc)
+{
+ if (!lt9611uxc->enable_gpio)
+ return;
+
+ gpiod_set_value_cansleep(lt9611uxc->enable_gpio, 1);
+ msleep(20);
+}
+
+static int lt9611uxc_regulator_init(struct lt9611uxc *lt9611uxc)
+{
+ int ret;
+
+ lt9611uxc->supplies[0].supply = "vdd";
+ lt9611uxc->supplies[1].supply = "vcc";
+
+ ret = devm_regulator_bulk_get(lt9611uxc->dev, 2, lt9611uxc->supplies);
+ if (ret < 0)
+ return ret;
+
+ return regulator_set_load(lt9611uxc->supplies[0].consumer, 200000);
+}
+
+static int lt9611uxc_regulator_enable(struct lt9611uxc *lt9611uxc)
+{
+ int ret;
+
+ ret = regulator_enable(lt9611uxc->supplies[0].consumer);
+ if (ret < 0)
+ return ret;
+
+ usleep_range(1000, 10000); /* 50000 according to dtsi */
+
+ ret = regulator_enable(lt9611uxc->supplies[1].consumer);
+ if (ret < 0) {
+ regulator_disable(lt9611uxc->supplies[0].consumer);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct lt9611uxc_mode *lt9611uxc_find_mode(const struct drm_display_mode *mode)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(lt9611uxc_modes); i++) {
+ if (lt9611uxc_modes[i].hdisplay == mode->hdisplay &&
+ lt9611uxc_modes[i].vdisplay == mode->vdisplay &&
+ lt9611uxc_modes[i].vrefresh == drm_mode_vrefresh(mode)) {
+ return <9611uxc_modes[i];
+ }
+ }
+
+ return NULL;
+}
+
+static struct mipi_dsi_device *lt9611uxc_attach_dsi(struct lt9611uxc *lt9611uxc,
+ struct device_node *dsi_node)
+{
+ const struct mipi_dsi_device_info info = { "lt9611uxc", 0, NULL };
+ struct mipi_dsi_device *dsi;
+ struct mipi_dsi_host *host;
+ int ret;
+
+ host = of_find_mipi_dsi_host_by_node(dsi_node);
+ if (!host) {
+ dev_err(lt9611uxc->dev, "failed to find dsi host\n");
+ return ERR_PTR(-EPROBE_DEFER);
+ }
+
+ dsi = mipi_dsi_device_register_full(host, &info);
+ if (IS_ERR(dsi)) {
+ dev_err(lt9611uxc->dev, "failed to create dsi device\n");
+ return dsi;
+ }
+
+ dsi->lanes = 4;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+ MIPI_DSI_MODE_VIDEO_HSE;
+
+ ret = mipi_dsi_attach(dsi);
+ if (ret < 0) {
+ dev_err(lt9611uxc->dev, "failed to attach dsi to host\n");
+ mipi_dsi_device_unregister(dsi);
+ return ERR_PTR(ret);
+ }
+
+ return dsi;
+}
+
+static void lt9611uxc_bridge_detach(struct drm_bridge *bridge)
+{
+ struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
+
+ if (lt9611uxc->dsi1) {
+ mipi_dsi_detach(lt9611uxc->dsi1);
+ mipi_dsi_device_unregister(lt9611uxc->dsi1);
+ }
+
+ mipi_dsi_detach(lt9611uxc->dsi0);
+ mipi_dsi_device_unregister(lt9611uxc->dsi0);
+}
+
+static int lt9611uxc_bridge_attach(struct drm_bridge *bridge,
+ enum drm_bridge_attach_flags flags)
+{
+ struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
+ int ret;
+
+ if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
+ dev_err(lt9611uxc->dev, "Fix bridge driver to make connector optional!");
+ return -EINVAL;
+ }
+
+ /* Attach primary DSI */
+ lt9611uxc->dsi0 = lt9611uxc_attach_dsi(lt9611uxc, lt9611uxc->dsi0_node);
+ if (IS_ERR(lt9611uxc->dsi0))
+ return PTR_ERR(lt9611uxc->dsi0);
+
+ /* Attach secondary DSI, if specified */
+ if (lt9611uxc->dsi1_node) {
+ lt9611uxc->dsi1 = lt9611uxc_attach_dsi(lt9611uxc, lt9611uxc->dsi1_node);
+ if (IS_ERR(lt9611uxc->dsi1)) {
+ ret = PTR_ERR(lt9611uxc->dsi1);
+ goto err_unregister_dsi0;
+ }
+ }
+
+ return 0;
+
+err_unregister_dsi0:
+ lt9611uxc_bridge_detach(bridge);
+ mipi_dsi_device_unregister(lt9611uxc->dsi0);
+
+ return ret;
+}
+
+static enum drm_mode_status
+lt9611uxc_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
+{
+ struct lt9611uxc_mode *lt9611uxc_mode;
+
+ lt9611uxc_mode = lt9611uxc_find_mode(mode);
+
+ return lt9611uxc_mode ? MODE_OK : MODE_BAD;
+}
+
+static void lt9611uxc_bridge_post_disable(struct drm_bridge *bridge)
+{
+ struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
+
+ lt9611uxc_lock(lt9611uxc);
+ regmap_update_bits(lt9611uxc->regmap, 0xb024, 0x1, 0x1);
+ lt9611uxc->sleep = true;
+ lt9611uxc_unlock(lt9611uxc);
+}
+
+static void lt9611uxc_video_setup(struct lt9611uxc *lt9611uxc,
+ const struct drm_display_mode *mode)
+{
+ u32 h_total, hactive, hsync_len, hfront_porch, hsync_porch;
+ u32 v_total, vactive, vsync_len, vfront_porch, vsync_porch;
+
+ h_total = mode->htotal;
+ v_total = mode->vtotal;
+
+ hactive = mode->hdisplay;
+ hsync_len = mode->hsync_end - mode->hsync_start;
+ hfront_porch = mode->hsync_start - mode->hdisplay;
+ hsync_porch = hsync_len + mode->htotal - mode->hsync_end;
+
+ vactive = mode->vdisplay;
+ vsync_len = mode->vsync_end - mode->vsync_start;
+ vfront_porch = mode->vsync_start - mode->vdisplay;
+ vsync_porch = vsync_len + mode->vtotal - mode->vsync_end;
+
+ regmap_write(lt9611uxc->regmap, 0xd00d, (u8)(v_total / 256));
+ regmap_write(lt9611uxc->regmap, 0xd00e, (u8)(v_total % 256));
+
+ regmap_write(lt9611uxc->regmap, 0xd00f, (u8)(vactive / 256));
+ regmap_write(lt9611uxc->regmap, 0xd010, (u8)(vactive % 256));
+
+ regmap_write(lt9611uxc->regmap, 0xd011, (u8)(h_total / 256));
+ regmap_write(lt9611uxc->regmap, 0xd012, (u8)(h_total % 256));
+
+ regmap_write(lt9611uxc->regmap, 0xd013, (u8)(hactive / 256));
+ regmap_write(lt9611uxc->regmap, 0xd014, (u8)(hactive % 256));
+
+ regmap_write(lt9611uxc->regmap, 0xd015, (u8)(vsync_len % 256));
+
+ regmap_update_bits(lt9611uxc->regmap, 0xd016, 0xf, (u8)(hsync_len / 256));
+ regmap_write(lt9611uxc->regmap, 0xd017, (u8)(hsync_len % 256));
+
+ regmap_update_bits(lt9611uxc->regmap, 0xd018, 0xf, (u8)(vfront_porch / 256));
+ regmap_write(lt9611uxc->regmap, 0xd019, (u8)(vfront_porch % 256));
+
+ regmap_update_bits(lt9611uxc->regmap, 0xd01a, 0xf, (u8)(hfront_porch / 256));
+ regmap_write(lt9611uxc->regmap, 0xd01b, (u8)(hfront_porch % 256));
+}
+
+static void lt9611uxc_bridge_mode_set(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ const struct drm_display_mode *adj_mode)
+{
+ struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
+
+ if (lt9611uxc->sleep)
+ lt9611uxc_reset(lt9611uxc);
+
+ lt9611uxc_lock(lt9611uxc);
+ lt9611uxc_video_setup(lt9611uxc, mode);
+ lt9611uxc_unlock(lt9611uxc);
+}
+
+static enum drm_connector_status lt9611uxc_bridge_detect(struct drm_bridge *bridge)
+{
+ struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
+ unsigned int reg_val = 0;
+ int ret;
+ int connected = 1;
+
+ if (lt9611uxc->hpd_supported) {
+ lt9611uxc_lock(lt9611uxc);
+ ret = regmap_read(lt9611uxc->regmap, 0xb023, ®_val);
+ lt9611uxc_unlock(lt9611uxc);
+
+ if (ret)
+ dev_err(lt9611uxc->dev, "failed to read hpd status: %d\n", ret);
+ else
+ connected = reg_val & BIT(1);
+ }
+
+ return connected ? connector_status_connected :
+ connector_status_disconnected;
+}
+
+static int lt9611uxc_bridge_get_modes(struct drm_bridge *bridge,
+ struct drm_connector *connector)
+{
+ struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
+ struct display_timings *timings = lt9611uxc->timings;
+ int i;
+
+ for (i = 0; i < timings->num_timings; i++) {
+ struct drm_display_mode *mode = drm_mode_create(bridge->dev);
+ struct videomode vm;
+
+ if (videomode_from_timings(timings, &vm, i))
+ break;
+
+ drm_display_mode_from_videomode(&vm, mode);
+
+ mode->type = DRM_MODE_TYPE_DRIVER;
+
+ if (timings->native_mode == i)
+ mode->type |= DRM_MODE_TYPE_PREFERRED;
+
+ drm_mode_set_name(mode);
+ drm_mode_probed_add(connector, mode);
+ }
+
+ return i;
+}
+
+static int lt9611uxc_read_edid(struct lt9611uxc *lt9611uxc)
+{
+ int ret = 0;
+ int i;
+
+ /* memset to clear old buffer, if any */
+ memset(lt9611uxc->edid_buf, 0, sizeof(lt9611uxc->edid_buf));
+
+ lt9611uxc_lock(lt9611uxc);
+
+ regmap_write(lt9611uxc->regmap, 0xb00b, 0x10);
+
+#define EDID_SEG 16
+ for (i = 0; i < 2 * EDID_BLOCK_SIZE; i += EDID_SEG) {
+ regmap_write(lt9611uxc->regmap, 0xb00a, i);
+ ret = regmap_noinc_read(lt9611uxc->regmap, 0xb0b0,
+ <9611uxc->edid_buf[i], EDID_SEG);
+ if (ret < 0)
+ break;
+ }
+
+ lt9611uxc_unlock(lt9611uxc);
+ return ret;
+}
+
+static int lt9611uxc_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
+{
+ struct lt9611uxc *lt9611uxc = data;
+ int ret;
+
+ if (len > EDID_BLOCK_SIZE)
+ return -EINVAL;
+
+ if (block >= EDID_NUM_BLOCKS)
+ return -EINVAL;
+
+ if (block == 0) {
+ ret = lt9611uxc_read_edid(lt9611uxc);
+ if (ret) {
+ dev_err(lt9611uxc->dev, "edid read failed\n");
+ return ret;
+ }
+ }
+
+ memcpy(buf, lt9611uxc->edid_buf + block * EDID_BLOCK_SIZE, len);
+ return 0;
+};
+
+struct edid *lt9611uxc_bridge_get_edid(struct drm_bridge *bridge,
+ struct drm_connector *connector)
+{
+ struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
+
+ return drm_do_get_edid(connector, lt9611uxc_get_edid_block, lt9611uxc);
+}
+
+static const struct drm_bridge_funcs lt9611uxc_bridge_funcs = {
+ .attach = lt9611uxc_bridge_attach,
+ .detach = lt9611uxc_bridge_detach,
+ .mode_valid = lt9611uxc_bridge_mode_valid,
+ .post_disable = lt9611uxc_bridge_post_disable,
+ .mode_set = lt9611uxc_bridge_mode_set,
+ .detect = lt9611uxc_bridge_detect,
+ .get_modes = lt9611uxc_bridge_get_modes,
+ .get_edid = lt9611uxc_bridge_get_edid,
+};
+
+static int lt9611uxc_parse_dt(struct device *dev,
+ struct lt9611uxc *lt9611uxc)
+{
+ lt9611uxc->timings = of_get_display_timings(dev->of_node);
+ if (!lt9611uxc->timings)
+ dev_info(dev, "no display timings provided\n");
+
+ lt9611uxc->dsi0_node = of_graph_get_remote_node(dev->of_node, 0, -1);
+ if (!lt9611uxc->dsi0_node) {
+ dev_err(lt9611uxc->dev, "failed to get remote node for primary dsi\n");
+ return -ENODEV;
+ }
+
+ lt9611uxc->dsi1_node = of_graph_get_remote_node(dev->of_node, 1, -1);
+
+ return 0;
+}
+
+static int lt9611uxc_gpio_init(struct lt9611uxc *lt9611uxc)
+{
+ struct device *dev = lt9611uxc->dev;
+
+ lt9611uxc->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(lt9611uxc->reset_gpio)) {
+ dev_err(dev, "failed to acquire reset gpio\n");
+ return PTR_ERR(lt9611uxc->reset_gpio);
+ }
+
+ lt9611uxc->enable_gpio = devm_gpiod_get_optional(dev, "enable",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(lt9611uxc->enable_gpio)) {
+ dev_err(dev, "failed to acquire enable gpio\n");
+ return PTR_ERR(lt9611uxc->enable_gpio);
+ }
+
+ return 0;
+}
+
+static int lt9611uxc_read_device_rev(struct lt9611uxc *lt9611uxc)
+{
+ unsigned int rev0, rev1, rev2;
+ int ret;
+
+ lt9611uxc_lock(lt9611uxc);
+
+ ret = regmap_read(lt9611uxc->regmap, 0x8100, &rev0);
+ ret |= regmap_read(lt9611uxc->regmap, 0x8101, &rev1);
+ ret |= regmap_read(lt9611uxc->regmap, 0x8102, &rev2);
+ if (ret)
+ dev_err(lt9611uxc->dev, "failed to read revision: %d\n", ret);
+ else
+ dev_info(lt9611uxc->dev, "LT9611 revision: 0x%02x.%02x.%02x\n", rev0, rev1, rev2);
+
+ lt9611uxc_unlock(lt9611uxc);
+
+ return ret;
+}
+
+static int lt9611uxc_read_version(struct lt9611uxc *lt9611uxc)
+{
+ unsigned int rev;
+ int ret;
+
+ lt9611uxc_lock(lt9611uxc);
+
+ ret = regmap_read(lt9611uxc->regmap, 0xb021, &rev);
+ if (ret)
+ dev_err(lt9611uxc->dev, "failed to read revision: %d\n", ret);
+ else
+ dev_info(lt9611uxc->dev, "LT9611 version: 0x%02x\n", rev);
+
+ lt9611uxc_unlock(lt9611uxc);
+
+ return ret < 0 ? ret : rev;
+}
+
+static int lt9611uxc_hdmi_hw_params(struct device *dev, void *data,
+ struct hdmi_codec_daifmt *fmt,
+ struct hdmi_codec_params *hparms)
+{
+ /*
+ * LT9611UXC will automatically detect rate and sample size, so no need
+ * to setup anything here.
+ */
+ return 0;
+}
+
+static void lt9611uxc_audio_shutdown(struct device *dev, void *data)
+{
+}
+
+static int lt9611uxc_hdmi_i2s_get_dai_id(struct snd_soc_component *component,
+ struct device_node *endpoint)
+{
+ struct of_endpoint of_ep;
+ int ret;
+
+ ret = of_graph_parse_endpoint(endpoint, &of_ep);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * HDMI sound should be located as reg = <2>
+ * Then, it is sound port 0
+ */
+ if (of_ep.port == 2)
+ return 0;
+
+ return -EINVAL;
+}
+
+static const struct hdmi_codec_ops lt9611uxc_codec_ops = {
+ .hw_params = lt9611uxc_hdmi_hw_params,
+ .audio_shutdown = lt9611uxc_audio_shutdown,
+ .get_dai_id = lt9611uxc_hdmi_i2s_get_dai_id,
+};
+
+static int lt9611uxc_audio_init(struct device *dev, struct lt9611uxc *lt9611uxc)
+{
+ struct hdmi_codec_pdata codec_data = {
+ .ops = <9611uxc_codec_ops,
+ .max_i2s_channels = 2,
+ .i2s = 1,
+ .data = lt9611uxc,
+ };
+
+ lt9611uxc->audio_pdev =
+ platform_device_register_data(dev, HDMI_CODEC_DRV_NAME,
+ PLATFORM_DEVID_AUTO,
+ &codec_data, sizeof(codec_data));
+
+ return PTR_ERR_OR_ZERO(lt9611uxc->audio_pdev);
+}
+
+static void lt9611uxc_audio_exit(struct lt9611uxc *lt9611uxc)
+{
+ if (lt9611uxc->audio_pdev) {
+ platform_device_unregister(lt9611uxc->audio_pdev);
+ lt9611uxc->audio_pdev = NULL;
+ }
+}
+
+static int lt9611uxc_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct lt9611uxc *lt9611uxc;
+ struct device *dev = &client->dev;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(dev, "device doesn't support I2C\n");
+ return -ENODEV;
+ }
+
+ lt9611uxc = devm_kzalloc(dev, sizeof(*lt9611uxc), GFP_KERNEL);
+ if (!lt9611uxc)
+ return -ENOMEM;
+
+ lt9611uxc->dev = &client->dev;
+ lt9611uxc->client = client;
+ mutex_init(<9611uxc->ocm_lock);
+
+ lt9611uxc->regmap = devm_regmap_init_i2c(client, <9611uxc_regmap_config);
+ if (IS_ERR(lt9611uxc->regmap)) {
+ dev_err(lt9611uxc->dev, "regmap i2c init failed\n");
+ return PTR_ERR(lt9611uxc->regmap);
+ }
+
+ ret = lt9611uxc_parse_dt(&client->dev, lt9611uxc);
+ if (ret) {
+ dev_err(dev, "failed to parse device tree\n");
+ return ret;
+ }
+
+ ret = lt9611uxc_gpio_init(lt9611uxc);
+ if (ret < 0)
+ goto err_of_put;
+
+ ret = lt9611uxc_regulator_init(lt9611uxc);
+ if (ret < 0)
+ goto err_of_put;
+
+ lt9611uxc_assert_5v(lt9611uxc);
+
+ ret = lt9611uxc_regulator_enable(lt9611uxc);
+ if (ret)
+ goto err_of_put;
+
+ lt9611uxc_reset(lt9611uxc);
+
+ ret = lt9611uxc_read_device_rev(lt9611uxc);
+ if (ret) {
+ dev_err(dev, "failed to read chip rev\n");
+ goto err_disable_regulators;
+ }
+
+ ret = lt9611uxc_read_version(lt9611uxc);
+ if (ret < 0) {
+ dev_err(dev, "failed to read FW version\n");
+ goto err_disable_regulators;
+ } else if (ret == 0) {
+ dev_err(dev, "FW version 0, FW update not supported\n");
+ ret = -EOPNOTSUPP;
+ goto err_disable_regulators;
+ } else if (ret < 0x40) {
+ dev_info(dev, "FW version 0x%x, HPD not supported\n", ret);
+ } else {
+ lt9611uxc->hpd_supported = true;
+ }
+
+ ret = devm_request_threaded_irq(dev, client->irq, NULL,
+ lt9611uxc_irq_thread_handler,
+ IRQF_ONESHOT, "lt9611uxc", lt9611uxc);
+ if (ret) {
+ dev_err(dev, "failed to request irq\n");
+ goto err_disable_regulators;
+ }
+
+ i2c_set_clientdata(client, lt9611uxc);
+
+ lt9611uxc->bridge.funcs = <9611uxc_bridge_funcs;
+ lt9611uxc->bridge.of_node = client->dev.of_node;
+ lt9611uxc->bridge.ops = DRM_BRIDGE_OP_DETECT;
+ if (lt9611uxc->timings)
+ lt9611uxc->bridge.ops |= DRM_BRIDGE_OP_MODES;
+ else
+ lt9611uxc->bridge.ops |= DRM_BRIDGE_OP_EDID;
+ if (lt9611uxc->hpd_supported)
+ lt9611uxc->bridge.ops |= DRM_BRIDGE_OP_HPD;
+ lt9611uxc->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
+
+ drm_bridge_add(<9611uxc->bridge);
+
+ return lt9611uxc_audio_init(dev, lt9611uxc);
+
+err_disable_regulators:
+ regulator_bulk_disable(ARRAY_SIZE(lt9611uxc->supplies), lt9611uxc->supplies);
+
+err_of_put:
+ of_node_put(lt9611uxc->dsi1_node);
+ of_node_put(lt9611uxc->dsi0_node);
+
+ return ret;
+}
+
+static int lt9611uxc_remove(struct i2c_client *client)
+{
+ struct lt9611uxc *lt9611uxc = i2c_get_clientdata(client);
+
+ disable_irq(client->irq);
+ lt9611uxc_audio_exit(lt9611uxc);
+ drm_bridge_remove(<9611uxc->bridge);
+
+ mutex_destroy(<9611uxc->ocm_lock);
+
+ regulator_bulk_disable(ARRAY_SIZE(lt9611uxc->supplies), lt9611uxc->supplies);
+
+ of_node_put(lt9611uxc->dsi1_node);
+ of_node_put(lt9611uxc->dsi0_node);
+
+ return 0;
+}
+
+static struct i2c_device_id lt9611uxc_id[] = {
+ { "lontium,lt9611uxc", 0 },
+ {}
+};
+
+static const struct of_device_id lt9611uxc_match_table[] = {
+ { .compatible = "lontium,lt9611uxc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lt9611uxc_match_table);
+
+static struct i2c_driver lt9611uxc_driver = {
+ .driver = {
+ .name = "lt9611uxc",
+ .of_match_table = lt9611uxc_match_table,
+ },
+ .probe = lt9611uxc_probe,
+ .remove = lt9611uxc_remove,
+ .id_table = lt9611uxc_id,
+};
+module_i2c_driver(lt9611uxc_driver);
+
+MODULE_LICENSE("GPL v2");
--
2.28.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v1 2/2] drm: bridge: add support for lontium LT9611UXC bridge
@ 2020-08-28 12:04 ` Dmitry Baryshkov
0 siblings, 0 replies; 21+ messages in thread
From: Dmitry Baryshkov @ 2020-08-28 12:04 UTC (permalink / raw)
To: devicetree, dri-devel
Cc: Jernej Skrabec, Neil Armstrong, David Airlie, linux-arm-msm,
Jonas Karlman, Andrzej Hajda, Vinod Koul, Rob Herring,
Laurent Pinchart
Add support for Lontium LT9611UXC HDMI bridge. Lontium LT9611UXC is a
DSI to HDMI bridge which supports two DSI ports and I2S port as an input
and HDMI port as output. Despite name being similar to LT9611, these
devices are different enough to warrant separate driver.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
drivers/gpu/drm/bridge/Kconfig | 13 +
drivers/gpu/drm/bridge/Makefile | 1 +
drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 777 +++++++++++++++++++++
3 files changed, 791 insertions(+)
create mode 100644 drivers/gpu/drm/bridge/lontium-lt9611uxc.c
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 3e11af4e9f63..8343fb054652 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -61,6 +61,19 @@ config DRM_LONTIUM_LT9611
HDMI signals
Please say Y if you have such hardware.
+config DRM_LONTIUM_LT9611UXC
+ tristate "Lontium LT9611UXC DSI/HDMI bridge"
+ select SND_SOC_HDMI_CODEC if SND_SOC
+ depends on OF
+ select DRM_PANEL_BRIDGE
+ select DRM_KMS_HELPER
+ select REGMAP_I2C
+ help
+ Driver for Lontium LT9611UXC DSI to HDMI bridge
+ chip driver that converts dual DSI and I2S to
+ HDMI signals
+ Please say Y if you have such hardware.
+
config DRM_LVDS_CODEC
tristate "Transparent LVDS encoders and decoders support"
depends on OF
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index c589a6a7cbe1..306850a5899b 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o
obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o
obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o
obj-$(CONFIG_DRM_LONTIUM_LT9611) += lontium-lt9611.o
+obj-$(CONFIG_DRM_LONTIUM_LT9611UXC) += lontium-lt9611uxc.o
obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o
obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o
obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
new file mode 100644
index 000000000000..fc363b65590d
--- /dev/null
+++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
@@ -0,0 +1,777 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019-2020. Linaro Limited.
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include <sound/hdmi-codec.h>
+
+#include <video/display_timing.h>
+#include <video/of_display_timing.h>
+#include <video/videomode.h>
+
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_print.h>
+
+#define EDID_BLOCK_SIZE 128
+#define EDID_NUM_BLOCKS 2
+
+struct lt9611uxc {
+ struct device *dev;
+ struct drm_bridge bridge;
+
+ struct regmap *regmap;
+ /* Protects all accesses to registers by stopping the on-chip MCU */
+ struct mutex ocm_lock;
+
+ struct device_node *dsi0_node;
+ struct device_node *dsi1_node;
+ struct mipi_dsi_device *dsi0;
+ struct mipi_dsi_device *dsi1;
+ struct platform_device *audio_pdev;
+
+ struct gpio_desc *reset_gpio;
+ struct gpio_desc *enable_gpio;
+
+ bool sleep;
+
+ struct regulator_bulk_data supplies[2];
+
+ struct i2c_client *client;
+
+ bool hpd_supported;
+ struct display_timings *timings;
+ u8 edid_buf[EDID_BLOCK_SIZE * EDID_NUM_BLOCKS];
+};
+
+#define LT9611_PAGE_CONTROL 0xff
+
+static const struct regmap_range_cfg lt9611uxc_ranges[] = {
+ {
+ .name = "register_range",
+ .range_min = 0,
+ .range_max = 0xd0ff,
+ .selector_reg = LT9611_PAGE_CONTROL,
+ .selector_mask = 0xff,
+ .selector_shift = 0,
+ .window_start = 0,
+ .window_len = 0x100,
+ },
+};
+
+static const struct regmap_config lt9611uxc_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0xffff,
+ .ranges = lt9611uxc_ranges,
+ .num_ranges = ARRAY_SIZE(lt9611uxc_ranges),
+};
+
+struct lt9611uxc_mode {
+ u16 hdisplay;
+ u16 vdisplay;
+ u8 vrefresh;
+ u8 lanes;
+ u8 intfs;
+};
+
+static struct lt9611uxc_mode lt9611uxc_modes[] = {
+ { 3840, 2160, 60, 4, 2 }, /* 3840x2160 24bit 60Hz 4Lane 2ports */
+ { 3840, 2160, 30, 4, 2 }, /* 3840x2160 24bit 30Hz 4Lane 2ports */
+ { 1920, 1080, 60, 4, 1 }, /* 1080P 24bit 60Hz 4lane 1port */
+ { 1920, 1080, 30, 3, 1 }, /* 1080P 24bit 30Hz 3lane 1port */
+ { 1920, 1080, 24, 3, 1 },
+ { 1024, 768, 60, 4, 1},
+ { 800, 600, 60, 4, 1},
+ { 720, 480, 60, 4, 1 },
+ { 720, 576, 50, 2, 1 },
+ { 640, 480, 60, 2, 1 },
+};
+
+static struct lt9611uxc *bridge_to_lt9611uxc(struct drm_bridge *bridge)
+{
+ return container_of(bridge, struct lt9611uxc, bridge);
+}
+
+static void lt9611uxc_lock(struct lt9611uxc *lt9611uxc)
+{
+ mutex_lock(<9611uxc->ocm_lock);
+ regmap_write(lt9611uxc->regmap, 0x80ee, 0x01);
+}
+
+static void lt9611uxc_unlock(struct lt9611uxc *lt9611uxc)
+{
+ regmap_write(lt9611uxc->regmap, 0x80ee, 0x00);
+ msleep(50);
+ mutex_unlock(<9611uxc->ocm_lock);
+}
+
+static irqreturn_t lt9611uxc_irq_thread_handler(int irq, void *dev_id)
+{
+ struct lt9611uxc *lt9611uxc = dev_id;
+ unsigned int irq_status = 0;
+ unsigned int hpd_status = 0;
+
+ lt9611uxc_lock(lt9611uxc);
+
+ regmap_read(lt9611uxc->regmap, 0xb022, &irq_status);
+ if (irq_status) {
+ regmap_write(lt9611uxc->regmap, 0xb022, 0);
+ regmap_read(lt9611uxc->regmap, 0xb023, &hpd_status);
+ }
+
+ lt9611uxc_unlock(lt9611uxc);
+
+ if (irq_status & 0x3 && lt9611uxc->bridge.dev)
+ drm_kms_helper_hotplug_event(lt9611uxc->bridge.dev);
+
+ return IRQ_HANDLED;
+}
+
+static void lt9611uxc_reset(struct lt9611uxc *lt9611uxc)
+{
+ gpiod_set_value_cansleep(lt9611uxc->reset_gpio, 1);
+ msleep(20);
+
+ gpiod_set_value_cansleep(lt9611uxc->reset_gpio, 0);
+ msleep(20);
+
+ gpiod_set_value_cansleep(lt9611uxc->reset_gpio, 1);
+ msleep(180);
+
+ lt9611uxc->sleep = false;
+}
+
+static void lt9611uxc_assert_5v(struct lt9611uxc *lt9611uxc)
+{
+ if (!lt9611uxc->enable_gpio)
+ return;
+
+ gpiod_set_value_cansleep(lt9611uxc->enable_gpio, 1);
+ msleep(20);
+}
+
+static int lt9611uxc_regulator_init(struct lt9611uxc *lt9611uxc)
+{
+ int ret;
+
+ lt9611uxc->supplies[0].supply = "vdd";
+ lt9611uxc->supplies[1].supply = "vcc";
+
+ ret = devm_regulator_bulk_get(lt9611uxc->dev, 2, lt9611uxc->supplies);
+ if (ret < 0)
+ return ret;
+
+ return regulator_set_load(lt9611uxc->supplies[0].consumer, 200000);
+}
+
+static int lt9611uxc_regulator_enable(struct lt9611uxc *lt9611uxc)
+{
+ int ret;
+
+ ret = regulator_enable(lt9611uxc->supplies[0].consumer);
+ if (ret < 0)
+ return ret;
+
+ usleep_range(1000, 10000); /* 50000 according to dtsi */
+
+ ret = regulator_enable(lt9611uxc->supplies[1].consumer);
+ if (ret < 0) {
+ regulator_disable(lt9611uxc->supplies[0].consumer);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct lt9611uxc_mode *lt9611uxc_find_mode(const struct drm_display_mode *mode)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(lt9611uxc_modes); i++) {
+ if (lt9611uxc_modes[i].hdisplay == mode->hdisplay &&
+ lt9611uxc_modes[i].vdisplay == mode->vdisplay &&
+ lt9611uxc_modes[i].vrefresh == drm_mode_vrefresh(mode)) {
+ return <9611uxc_modes[i];
+ }
+ }
+
+ return NULL;
+}
+
+static struct mipi_dsi_device *lt9611uxc_attach_dsi(struct lt9611uxc *lt9611uxc,
+ struct device_node *dsi_node)
+{
+ const struct mipi_dsi_device_info info = { "lt9611uxc", 0, NULL };
+ struct mipi_dsi_device *dsi;
+ struct mipi_dsi_host *host;
+ int ret;
+
+ host = of_find_mipi_dsi_host_by_node(dsi_node);
+ if (!host) {
+ dev_err(lt9611uxc->dev, "failed to find dsi host\n");
+ return ERR_PTR(-EPROBE_DEFER);
+ }
+
+ dsi = mipi_dsi_device_register_full(host, &info);
+ if (IS_ERR(dsi)) {
+ dev_err(lt9611uxc->dev, "failed to create dsi device\n");
+ return dsi;
+ }
+
+ dsi->lanes = 4;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+ MIPI_DSI_MODE_VIDEO_HSE;
+
+ ret = mipi_dsi_attach(dsi);
+ if (ret < 0) {
+ dev_err(lt9611uxc->dev, "failed to attach dsi to host\n");
+ mipi_dsi_device_unregister(dsi);
+ return ERR_PTR(ret);
+ }
+
+ return dsi;
+}
+
+static void lt9611uxc_bridge_detach(struct drm_bridge *bridge)
+{
+ struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
+
+ if (lt9611uxc->dsi1) {
+ mipi_dsi_detach(lt9611uxc->dsi1);
+ mipi_dsi_device_unregister(lt9611uxc->dsi1);
+ }
+
+ mipi_dsi_detach(lt9611uxc->dsi0);
+ mipi_dsi_device_unregister(lt9611uxc->dsi0);
+}
+
+static int lt9611uxc_bridge_attach(struct drm_bridge *bridge,
+ enum drm_bridge_attach_flags flags)
+{
+ struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
+ int ret;
+
+ if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
+ dev_err(lt9611uxc->dev, "Fix bridge driver to make connector optional!");
+ return -EINVAL;
+ }
+
+ /* Attach primary DSI */
+ lt9611uxc->dsi0 = lt9611uxc_attach_dsi(lt9611uxc, lt9611uxc->dsi0_node);
+ if (IS_ERR(lt9611uxc->dsi0))
+ return PTR_ERR(lt9611uxc->dsi0);
+
+ /* Attach secondary DSI, if specified */
+ if (lt9611uxc->dsi1_node) {
+ lt9611uxc->dsi1 = lt9611uxc_attach_dsi(lt9611uxc, lt9611uxc->dsi1_node);
+ if (IS_ERR(lt9611uxc->dsi1)) {
+ ret = PTR_ERR(lt9611uxc->dsi1);
+ goto err_unregister_dsi0;
+ }
+ }
+
+ return 0;
+
+err_unregister_dsi0:
+ lt9611uxc_bridge_detach(bridge);
+ mipi_dsi_device_unregister(lt9611uxc->dsi0);
+
+ return ret;
+}
+
+static enum drm_mode_status
+lt9611uxc_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
+{
+ struct lt9611uxc_mode *lt9611uxc_mode;
+
+ lt9611uxc_mode = lt9611uxc_find_mode(mode);
+
+ return lt9611uxc_mode ? MODE_OK : MODE_BAD;
+}
+
+static void lt9611uxc_bridge_post_disable(struct drm_bridge *bridge)
+{
+ struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
+
+ lt9611uxc_lock(lt9611uxc);
+ regmap_update_bits(lt9611uxc->regmap, 0xb024, 0x1, 0x1);
+ lt9611uxc->sleep = true;
+ lt9611uxc_unlock(lt9611uxc);
+}
+
+static void lt9611uxc_video_setup(struct lt9611uxc *lt9611uxc,
+ const struct drm_display_mode *mode)
+{
+ u32 h_total, hactive, hsync_len, hfront_porch, hsync_porch;
+ u32 v_total, vactive, vsync_len, vfront_porch, vsync_porch;
+
+ h_total = mode->htotal;
+ v_total = mode->vtotal;
+
+ hactive = mode->hdisplay;
+ hsync_len = mode->hsync_end - mode->hsync_start;
+ hfront_porch = mode->hsync_start - mode->hdisplay;
+ hsync_porch = hsync_len + mode->htotal - mode->hsync_end;
+
+ vactive = mode->vdisplay;
+ vsync_len = mode->vsync_end - mode->vsync_start;
+ vfront_porch = mode->vsync_start - mode->vdisplay;
+ vsync_porch = vsync_len + mode->vtotal - mode->vsync_end;
+
+ regmap_write(lt9611uxc->regmap, 0xd00d, (u8)(v_total / 256));
+ regmap_write(lt9611uxc->regmap, 0xd00e, (u8)(v_total % 256));
+
+ regmap_write(lt9611uxc->regmap, 0xd00f, (u8)(vactive / 256));
+ regmap_write(lt9611uxc->regmap, 0xd010, (u8)(vactive % 256));
+
+ regmap_write(lt9611uxc->regmap, 0xd011, (u8)(h_total / 256));
+ regmap_write(lt9611uxc->regmap, 0xd012, (u8)(h_total % 256));
+
+ regmap_write(lt9611uxc->regmap, 0xd013, (u8)(hactive / 256));
+ regmap_write(lt9611uxc->regmap, 0xd014, (u8)(hactive % 256));
+
+ regmap_write(lt9611uxc->regmap, 0xd015, (u8)(vsync_len % 256));
+
+ regmap_update_bits(lt9611uxc->regmap, 0xd016, 0xf, (u8)(hsync_len / 256));
+ regmap_write(lt9611uxc->regmap, 0xd017, (u8)(hsync_len % 256));
+
+ regmap_update_bits(lt9611uxc->regmap, 0xd018, 0xf, (u8)(vfront_porch / 256));
+ regmap_write(lt9611uxc->regmap, 0xd019, (u8)(vfront_porch % 256));
+
+ regmap_update_bits(lt9611uxc->regmap, 0xd01a, 0xf, (u8)(hfront_porch / 256));
+ regmap_write(lt9611uxc->regmap, 0xd01b, (u8)(hfront_porch % 256));
+}
+
+static void lt9611uxc_bridge_mode_set(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ const struct drm_display_mode *adj_mode)
+{
+ struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
+
+ if (lt9611uxc->sleep)
+ lt9611uxc_reset(lt9611uxc);
+
+ lt9611uxc_lock(lt9611uxc);
+ lt9611uxc_video_setup(lt9611uxc, mode);
+ lt9611uxc_unlock(lt9611uxc);
+}
+
+static enum drm_connector_status lt9611uxc_bridge_detect(struct drm_bridge *bridge)
+{
+ struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
+ unsigned int reg_val = 0;
+ int ret;
+ int connected = 1;
+
+ if (lt9611uxc->hpd_supported) {
+ lt9611uxc_lock(lt9611uxc);
+ ret = regmap_read(lt9611uxc->regmap, 0xb023, ®_val);
+ lt9611uxc_unlock(lt9611uxc);
+
+ if (ret)
+ dev_err(lt9611uxc->dev, "failed to read hpd status: %d\n", ret);
+ else
+ connected = reg_val & BIT(1);
+ }
+
+ return connected ? connector_status_connected :
+ connector_status_disconnected;
+}
+
+static int lt9611uxc_bridge_get_modes(struct drm_bridge *bridge,
+ struct drm_connector *connector)
+{
+ struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
+ struct display_timings *timings = lt9611uxc->timings;
+ int i;
+
+ for (i = 0; i < timings->num_timings; i++) {
+ struct drm_display_mode *mode = drm_mode_create(bridge->dev);
+ struct videomode vm;
+
+ if (videomode_from_timings(timings, &vm, i))
+ break;
+
+ drm_display_mode_from_videomode(&vm, mode);
+
+ mode->type = DRM_MODE_TYPE_DRIVER;
+
+ if (timings->native_mode == i)
+ mode->type |= DRM_MODE_TYPE_PREFERRED;
+
+ drm_mode_set_name(mode);
+ drm_mode_probed_add(connector, mode);
+ }
+
+ return i;
+}
+
+static int lt9611uxc_read_edid(struct lt9611uxc *lt9611uxc)
+{
+ int ret = 0;
+ int i;
+
+ /* memset to clear old buffer, if any */
+ memset(lt9611uxc->edid_buf, 0, sizeof(lt9611uxc->edid_buf));
+
+ lt9611uxc_lock(lt9611uxc);
+
+ regmap_write(lt9611uxc->regmap, 0xb00b, 0x10);
+
+#define EDID_SEG 16
+ for (i = 0; i < 2 * EDID_BLOCK_SIZE; i += EDID_SEG) {
+ regmap_write(lt9611uxc->regmap, 0xb00a, i);
+ ret = regmap_noinc_read(lt9611uxc->regmap, 0xb0b0,
+ <9611uxc->edid_buf[i], EDID_SEG);
+ if (ret < 0)
+ break;
+ }
+
+ lt9611uxc_unlock(lt9611uxc);
+ return ret;
+}
+
+static int lt9611uxc_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
+{
+ struct lt9611uxc *lt9611uxc = data;
+ int ret;
+
+ if (len > EDID_BLOCK_SIZE)
+ return -EINVAL;
+
+ if (block >= EDID_NUM_BLOCKS)
+ return -EINVAL;
+
+ if (block == 0) {
+ ret = lt9611uxc_read_edid(lt9611uxc);
+ if (ret) {
+ dev_err(lt9611uxc->dev, "edid read failed\n");
+ return ret;
+ }
+ }
+
+ memcpy(buf, lt9611uxc->edid_buf + block * EDID_BLOCK_SIZE, len);
+ return 0;
+};
+
+struct edid *lt9611uxc_bridge_get_edid(struct drm_bridge *bridge,
+ struct drm_connector *connector)
+{
+ struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
+
+ return drm_do_get_edid(connector, lt9611uxc_get_edid_block, lt9611uxc);
+}
+
+static const struct drm_bridge_funcs lt9611uxc_bridge_funcs = {
+ .attach = lt9611uxc_bridge_attach,
+ .detach = lt9611uxc_bridge_detach,
+ .mode_valid = lt9611uxc_bridge_mode_valid,
+ .post_disable = lt9611uxc_bridge_post_disable,
+ .mode_set = lt9611uxc_bridge_mode_set,
+ .detect = lt9611uxc_bridge_detect,
+ .get_modes = lt9611uxc_bridge_get_modes,
+ .get_edid = lt9611uxc_bridge_get_edid,
+};
+
+static int lt9611uxc_parse_dt(struct device *dev,
+ struct lt9611uxc *lt9611uxc)
+{
+ lt9611uxc->timings = of_get_display_timings(dev->of_node);
+ if (!lt9611uxc->timings)
+ dev_info(dev, "no display timings provided\n");
+
+ lt9611uxc->dsi0_node = of_graph_get_remote_node(dev->of_node, 0, -1);
+ if (!lt9611uxc->dsi0_node) {
+ dev_err(lt9611uxc->dev, "failed to get remote node for primary dsi\n");
+ return -ENODEV;
+ }
+
+ lt9611uxc->dsi1_node = of_graph_get_remote_node(dev->of_node, 1, -1);
+
+ return 0;
+}
+
+static int lt9611uxc_gpio_init(struct lt9611uxc *lt9611uxc)
+{
+ struct device *dev = lt9611uxc->dev;
+
+ lt9611uxc->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(lt9611uxc->reset_gpio)) {
+ dev_err(dev, "failed to acquire reset gpio\n");
+ return PTR_ERR(lt9611uxc->reset_gpio);
+ }
+
+ lt9611uxc->enable_gpio = devm_gpiod_get_optional(dev, "enable",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(lt9611uxc->enable_gpio)) {
+ dev_err(dev, "failed to acquire enable gpio\n");
+ return PTR_ERR(lt9611uxc->enable_gpio);
+ }
+
+ return 0;
+}
+
+static int lt9611uxc_read_device_rev(struct lt9611uxc *lt9611uxc)
+{
+ unsigned int rev0, rev1, rev2;
+ int ret;
+
+ lt9611uxc_lock(lt9611uxc);
+
+ ret = regmap_read(lt9611uxc->regmap, 0x8100, &rev0);
+ ret |= regmap_read(lt9611uxc->regmap, 0x8101, &rev1);
+ ret |= regmap_read(lt9611uxc->regmap, 0x8102, &rev2);
+ if (ret)
+ dev_err(lt9611uxc->dev, "failed to read revision: %d\n", ret);
+ else
+ dev_info(lt9611uxc->dev, "LT9611 revision: 0x%02x.%02x.%02x\n", rev0, rev1, rev2);
+
+ lt9611uxc_unlock(lt9611uxc);
+
+ return ret;
+}
+
+static int lt9611uxc_read_version(struct lt9611uxc *lt9611uxc)
+{
+ unsigned int rev;
+ int ret;
+
+ lt9611uxc_lock(lt9611uxc);
+
+ ret = regmap_read(lt9611uxc->regmap, 0xb021, &rev);
+ if (ret)
+ dev_err(lt9611uxc->dev, "failed to read revision: %d\n", ret);
+ else
+ dev_info(lt9611uxc->dev, "LT9611 version: 0x%02x\n", rev);
+
+ lt9611uxc_unlock(lt9611uxc);
+
+ return ret < 0 ? ret : rev;
+}
+
+static int lt9611uxc_hdmi_hw_params(struct device *dev, void *data,
+ struct hdmi_codec_daifmt *fmt,
+ struct hdmi_codec_params *hparms)
+{
+ /*
+ * LT9611UXC will automatically detect rate and sample size, so no need
+ * to setup anything here.
+ */
+ return 0;
+}
+
+static void lt9611uxc_audio_shutdown(struct device *dev, void *data)
+{
+}
+
+static int lt9611uxc_hdmi_i2s_get_dai_id(struct snd_soc_component *component,
+ struct device_node *endpoint)
+{
+ struct of_endpoint of_ep;
+ int ret;
+
+ ret = of_graph_parse_endpoint(endpoint, &of_ep);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * HDMI sound should be located as reg = <2>
+ * Then, it is sound port 0
+ */
+ if (of_ep.port == 2)
+ return 0;
+
+ return -EINVAL;
+}
+
+static const struct hdmi_codec_ops lt9611uxc_codec_ops = {
+ .hw_params = lt9611uxc_hdmi_hw_params,
+ .audio_shutdown = lt9611uxc_audio_shutdown,
+ .get_dai_id = lt9611uxc_hdmi_i2s_get_dai_id,
+};
+
+static int lt9611uxc_audio_init(struct device *dev, struct lt9611uxc *lt9611uxc)
+{
+ struct hdmi_codec_pdata codec_data = {
+ .ops = <9611uxc_codec_ops,
+ .max_i2s_channels = 2,
+ .i2s = 1,
+ .data = lt9611uxc,
+ };
+
+ lt9611uxc->audio_pdev =
+ platform_device_register_data(dev, HDMI_CODEC_DRV_NAME,
+ PLATFORM_DEVID_AUTO,
+ &codec_data, sizeof(codec_data));
+
+ return PTR_ERR_OR_ZERO(lt9611uxc->audio_pdev);
+}
+
+static void lt9611uxc_audio_exit(struct lt9611uxc *lt9611uxc)
+{
+ if (lt9611uxc->audio_pdev) {
+ platform_device_unregister(lt9611uxc->audio_pdev);
+ lt9611uxc->audio_pdev = NULL;
+ }
+}
+
+static int lt9611uxc_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct lt9611uxc *lt9611uxc;
+ struct device *dev = &client->dev;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(dev, "device doesn't support I2C\n");
+ return -ENODEV;
+ }
+
+ lt9611uxc = devm_kzalloc(dev, sizeof(*lt9611uxc), GFP_KERNEL);
+ if (!lt9611uxc)
+ return -ENOMEM;
+
+ lt9611uxc->dev = &client->dev;
+ lt9611uxc->client = client;
+ mutex_init(<9611uxc->ocm_lock);
+
+ lt9611uxc->regmap = devm_regmap_init_i2c(client, <9611uxc_regmap_config);
+ if (IS_ERR(lt9611uxc->regmap)) {
+ dev_err(lt9611uxc->dev, "regmap i2c init failed\n");
+ return PTR_ERR(lt9611uxc->regmap);
+ }
+
+ ret = lt9611uxc_parse_dt(&client->dev, lt9611uxc);
+ if (ret) {
+ dev_err(dev, "failed to parse device tree\n");
+ return ret;
+ }
+
+ ret = lt9611uxc_gpio_init(lt9611uxc);
+ if (ret < 0)
+ goto err_of_put;
+
+ ret = lt9611uxc_regulator_init(lt9611uxc);
+ if (ret < 0)
+ goto err_of_put;
+
+ lt9611uxc_assert_5v(lt9611uxc);
+
+ ret = lt9611uxc_regulator_enable(lt9611uxc);
+ if (ret)
+ goto err_of_put;
+
+ lt9611uxc_reset(lt9611uxc);
+
+ ret = lt9611uxc_read_device_rev(lt9611uxc);
+ if (ret) {
+ dev_err(dev, "failed to read chip rev\n");
+ goto err_disable_regulators;
+ }
+
+ ret = lt9611uxc_read_version(lt9611uxc);
+ if (ret < 0) {
+ dev_err(dev, "failed to read FW version\n");
+ goto err_disable_regulators;
+ } else if (ret == 0) {
+ dev_err(dev, "FW version 0, FW update not supported\n");
+ ret = -EOPNOTSUPP;
+ goto err_disable_regulators;
+ } else if (ret < 0x40) {
+ dev_info(dev, "FW version 0x%x, HPD not supported\n", ret);
+ } else {
+ lt9611uxc->hpd_supported = true;
+ }
+
+ ret = devm_request_threaded_irq(dev, client->irq, NULL,
+ lt9611uxc_irq_thread_handler,
+ IRQF_ONESHOT, "lt9611uxc", lt9611uxc);
+ if (ret) {
+ dev_err(dev, "failed to request irq\n");
+ goto err_disable_regulators;
+ }
+
+ i2c_set_clientdata(client, lt9611uxc);
+
+ lt9611uxc->bridge.funcs = <9611uxc_bridge_funcs;
+ lt9611uxc->bridge.of_node = client->dev.of_node;
+ lt9611uxc->bridge.ops = DRM_BRIDGE_OP_DETECT;
+ if (lt9611uxc->timings)
+ lt9611uxc->bridge.ops |= DRM_BRIDGE_OP_MODES;
+ else
+ lt9611uxc->bridge.ops |= DRM_BRIDGE_OP_EDID;
+ if (lt9611uxc->hpd_supported)
+ lt9611uxc->bridge.ops |= DRM_BRIDGE_OP_HPD;
+ lt9611uxc->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
+
+ drm_bridge_add(<9611uxc->bridge);
+
+ return lt9611uxc_audio_init(dev, lt9611uxc);
+
+err_disable_regulators:
+ regulator_bulk_disable(ARRAY_SIZE(lt9611uxc->supplies), lt9611uxc->supplies);
+
+err_of_put:
+ of_node_put(lt9611uxc->dsi1_node);
+ of_node_put(lt9611uxc->dsi0_node);
+
+ return ret;
+}
+
+static int lt9611uxc_remove(struct i2c_client *client)
+{
+ struct lt9611uxc *lt9611uxc = i2c_get_clientdata(client);
+
+ disable_irq(client->irq);
+ lt9611uxc_audio_exit(lt9611uxc);
+ drm_bridge_remove(<9611uxc->bridge);
+
+ mutex_destroy(<9611uxc->ocm_lock);
+
+ regulator_bulk_disable(ARRAY_SIZE(lt9611uxc->supplies), lt9611uxc->supplies);
+
+ of_node_put(lt9611uxc->dsi1_node);
+ of_node_put(lt9611uxc->dsi0_node);
+
+ return 0;
+}
+
+static struct i2c_device_id lt9611uxc_id[] = {
+ { "lontium,lt9611uxc", 0 },
+ {}
+};
+
+static const struct of_device_id lt9611uxc_match_table[] = {
+ { .compatible = "lontium,lt9611uxc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lt9611uxc_match_table);
+
+static struct i2c_driver lt9611uxc_driver = {
+ .driver = {
+ .name = "lt9611uxc",
+ .of_match_table = lt9611uxc_match_table,
+ },
+ .probe = lt9611uxc_probe,
+ .remove = lt9611uxc_remove,
+ .id_table = lt9611uxc_id,
+};
+module_i2c_driver(lt9611uxc_driver);
+
+MODULE_LICENSE("GPL v2");
--
2.28.0
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH v1 2/2] drm: bridge: add support for lontium LT9611UXC bridge
2020-08-28 12:04 ` Dmitry Baryshkov
(?)
@ 2020-08-28 13:49 ` kernel test robot
-1 siblings, 0 replies; 21+ messages in thread
From: kernel test robot @ 2020-08-28 13:49 UTC (permalink / raw)
To: Dmitry Baryshkov, devicetree, dri-devel
Cc: kbuild-all, linux-arm-msm, Rob Herring, Daniel Vetter,
David Airlie, Andrzej Hajda, Neil Armstrong, Laurent Pinchart,
Jonas Karlman
[-- Attachment #1: Type: text/plain, Size: 8162 bytes --]
Hi Dmitry,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on drm-tip/drm-tip]
[also build test WARNING on next-20200828]
[cannot apply to robh/for-next drm-intel/for-linux-next tegra-drm/drm/tegra/for-next linus/master drm-exynos/exynos-drm-next drm/drm-next v5.9-rc2]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Dmitry-Baryshkov/Add-LT9611UXC-DSI-to-HDMI-bridge-support/20200828-200735
base: git://anongit.freedesktop.org/drm/drm-tip drm-tip
config: i386-allyesconfig (attached as .config)
compiler: gcc-9 (Debian 9.3.0-15) 9.3.0
reproduce (this is a W=1 build):
# save the attached .config to linux build tree
make W=1 ARCH=i386
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All warnings (new ones prefixed by >>):
drivers/gpu/drm/bridge/lontium-lt9611uxc.c: In function 'lt9611uxc_video_setup':
>> drivers/gpu/drm/bridge/lontium-lt9611uxc.c:322:49: warning: variable 'vsync_porch' set but not used [-Wunused-but-set-variable]
322 | u32 v_total, vactive, vsync_len, vfront_porch, vsync_porch;
| ^~~~~~~~~~~
>> drivers/gpu/drm/bridge/lontium-lt9611uxc.c:321:49: warning: variable 'hsync_porch' set but not used [-Wunused-but-set-variable]
321 | u32 h_total, hactive, hsync_len, hfront_porch, hsync_porch;
| ^~~~~~~~~~~
drivers/gpu/drm/bridge/lontium-lt9611uxc.c: At top level:
>> drivers/gpu/drm/bridge/lontium-lt9611uxc.c:473:14: warning: no previous prototype for 'lt9611uxc_bridge_get_edid' [-Wmissing-prototypes]
473 | struct edid *lt9611uxc_bridge_get_edid(struct drm_bridge *bridge,
| ^~~~~~~~~~~~~~~~~~~~~~~~~
# https://github.com/0day-ci/linux/commit/f1b935d064fd8924137d420e75eb050c3d66c22b
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Dmitry-Baryshkov/Add-LT9611UXC-DSI-to-HDMI-bridge-support/20200828-200735
git checkout f1b935d064fd8924137d420e75eb050c3d66c22b
vim +/vsync_porch +322 drivers/gpu/drm/bridge/lontium-lt9611uxc.c
317
318 static void lt9611uxc_video_setup(struct lt9611uxc *lt9611uxc,
319 const struct drm_display_mode *mode)
320 {
> 321 u32 h_total, hactive, hsync_len, hfront_porch, hsync_porch;
> 322 u32 v_total, vactive, vsync_len, vfront_porch, vsync_porch;
323
324 h_total = mode->htotal;
325 v_total = mode->vtotal;
326
327 hactive = mode->hdisplay;
328 hsync_len = mode->hsync_end - mode->hsync_start;
329 hfront_porch = mode->hsync_start - mode->hdisplay;
330 hsync_porch = hsync_len + mode->htotal - mode->hsync_end;
331
332 vactive = mode->vdisplay;
333 vsync_len = mode->vsync_end - mode->vsync_start;
334 vfront_porch = mode->vsync_start - mode->vdisplay;
335 vsync_porch = vsync_len + mode->vtotal - mode->vsync_end;
336
337 regmap_write(lt9611uxc->regmap, 0xd00d, (u8)(v_total / 256));
338 regmap_write(lt9611uxc->regmap, 0xd00e, (u8)(v_total % 256));
339
340 regmap_write(lt9611uxc->regmap, 0xd00f, (u8)(vactive / 256));
341 regmap_write(lt9611uxc->regmap, 0xd010, (u8)(vactive % 256));
342
343 regmap_write(lt9611uxc->regmap, 0xd011, (u8)(h_total / 256));
344 regmap_write(lt9611uxc->regmap, 0xd012, (u8)(h_total % 256));
345
346 regmap_write(lt9611uxc->regmap, 0xd013, (u8)(hactive / 256));
347 regmap_write(lt9611uxc->regmap, 0xd014, (u8)(hactive % 256));
348
349 regmap_write(lt9611uxc->regmap, 0xd015, (u8)(vsync_len % 256));
350
351 regmap_update_bits(lt9611uxc->regmap, 0xd016, 0xf, (u8)(hsync_len / 256));
352 regmap_write(lt9611uxc->regmap, 0xd017, (u8)(hsync_len % 256));
353
354 regmap_update_bits(lt9611uxc->regmap, 0xd018, 0xf, (u8)(vfront_porch / 256));
355 regmap_write(lt9611uxc->regmap, 0xd019, (u8)(vfront_porch % 256));
356
357 regmap_update_bits(lt9611uxc->regmap, 0xd01a, 0xf, (u8)(hfront_porch / 256));
358 regmap_write(lt9611uxc->regmap, 0xd01b, (u8)(hfront_porch % 256));
359 }
360
361 static void lt9611uxc_bridge_mode_set(struct drm_bridge *bridge,
362 const struct drm_display_mode *mode,
363 const struct drm_display_mode *adj_mode)
364 {
365 struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
366
367 if (lt9611uxc->sleep)
368 lt9611uxc_reset(lt9611uxc);
369
370 lt9611uxc_lock(lt9611uxc);
371 lt9611uxc_video_setup(lt9611uxc, mode);
372 lt9611uxc_unlock(lt9611uxc);
373 }
374
375 static enum drm_connector_status lt9611uxc_bridge_detect(struct drm_bridge *bridge)
376 {
377 struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
378 unsigned int reg_val = 0;
379 int ret;
380 int connected = 1;
381
382 if (lt9611uxc->hpd_supported) {
383 lt9611uxc_lock(lt9611uxc);
384 ret = regmap_read(lt9611uxc->regmap, 0xb023, ®_val);
385 lt9611uxc_unlock(lt9611uxc);
386
387 if (ret)
388 dev_err(lt9611uxc->dev, "failed to read hpd status: %d\n", ret);
389 else
390 connected = reg_val & BIT(1);
391 }
392
393 return connected ? connector_status_connected :
394 connector_status_disconnected;
395 }
396
397 static int lt9611uxc_bridge_get_modes(struct drm_bridge *bridge,
398 struct drm_connector *connector)
399 {
400 struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
401 struct display_timings *timings = lt9611uxc->timings;
402 int i;
403
404 for (i = 0; i < timings->num_timings; i++) {
405 struct drm_display_mode *mode = drm_mode_create(bridge->dev);
406 struct videomode vm;
407
408 if (videomode_from_timings(timings, &vm, i))
409 break;
410
411 drm_display_mode_from_videomode(&vm, mode);
412
413 mode->type = DRM_MODE_TYPE_DRIVER;
414
415 if (timings->native_mode == i)
416 mode->type |= DRM_MODE_TYPE_PREFERRED;
417
418 drm_mode_set_name(mode);
419 drm_mode_probed_add(connector, mode);
420 }
421
422 return i;
423 }
424
425 static int lt9611uxc_read_edid(struct lt9611uxc *lt9611uxc)
426 {
427 int ret = 0;
428 int i;
429
430 /* memset to clear old buffer, if any */
431 memset(lt9611uxc->edid_buf, 0, sizeof(lt9611uxc->edid_buf));
432
433 lt9611uxc_lock(lt9611uxc);
434
435 regmap_write(lt9611uxc->regmap, 0xb00b, 0x10);
436
437 #define EDID_SEG 16
438 for (i = 0; i < 2 * EDID_BLOCK_SIZE; i += EDID_SEG) {
439 regmap_write(lt9611uxc->regmap, 0xb00a, i);
440 ret = regmap_noinc_read(lt9611uxc->regmap, 0xb0b0,
441 <9611uxc->edid_buf[i], EDID_SEG);
442 if (ret < 0)
443 break;
444 }
445
446 lt9611uxc_unlock(lt9611uxc);
447 return ret;
448 }
449
450 static int lt9611uxc_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
451 {
452 struct lt9611uxc *lt9611uxc = data;
453 int ret;
454
455 if (len > EDID_BLOCK_SIZE)
456 return -EINVAL;
457
458 if (block >= EDID_NUM_BLOCKS)
459 return -EINVAL;
460
461 if (block == 0) {
462 ret = lt9611uxc_read_edid(lt9611uxc);
463 if (ret) {
464 dev_err(lt9611uxc->dev, "edid read failed\n");
465 return ret;
466 }
467 }
468
469 memcpy(buf, lt9611uxc->edid_buf + block * EDID_BLOCK_SIZE, len);
470 return 0;
471 };
472
> 473 struct edid *lt9611uxc_bridge_get_edid(struct drm_bridge *bridge,
474 struct drm_connector *connector)
475 {
476 struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
477
478 return drm_do_get_edid(connector, lt9611uxc_get_edid_block, lt9611uxc);
479 }
480
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 74952 bytes --]
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v1 2/2] drm: bridge: add support for lontium LT9611UXC bridge
@ 2020-08-28 13:49 ` kernel test robot
0 siblings, 0 replies; 21+ messages in thread
From: kernel test robot @ 2020-08-28 13:49 UTC (permalink / raw)
To: Dmitry Baryshkov, devicetree, dri-devel
Cc: kbuild-all, Neil Armstrong, David Airlie, linux-arm-msm,
Jonas Karlman, Andrzej Hajda, Rob Herring, Laurent Pinchart
[-- Attachment #1: Type: text/plain, Size: 8162 bytes --]
Hi Dmitry,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on drm-tip/drm-tip]
[also build test WARNING on next-20200828]
[cannot apply to robh/for-next drm-intel/for-linux-next tegra-drm/drm/tegra/for-next linus/master drm-exynos/exynos-drm-next drm/drm-next v5.9-rc2]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Dmitry-Baryshkov/Add-LT9611UXC-DSI-to-HDMI-bridge-support/20200828-200735
base: git://anongit.freedesktop.org/drm/drm-tip drm-tip
config: i386-allyesconfig (attached as .config)
compiler: gcc-9 (Debian 9.3.0-15) 9.3.0
reproduce (this is a W=1 build):
# save the attached .config to linux build tree
make W=1 ARCH=i386
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All warnings (new ones prefixed by >>):
drivers/gpu/drm/bridge/lontium-lt9611uxc.c: In function 'lt9611uxc_video_setup':
>> drivers/gpu/drm/bridge/lontium-lt9611uxc.c:322:49: warning: variable 'vsync_porch' set but not used [-Wunused-but-set-variable]
322 | u32 v_total, vactive, vsync_len, vfront_porch, vsync_porch;
| ^~~~~~~~~~~
>> drivers/gpu/drm/bridge/lontium-lt9611uxc.c:321:49: warning: variable 'hsync_porch' set but not used [-Wunused-but-set-variable]
321 | u32 h_total, hactive, hsync_len, hfront_porch, hsync_porch;
| ^~~~~~~~~~~
drivers/gpu/drm/bridge/lontium-lt9611uxc.c: At top level:
>> drivers/gpu/drm/bridge/lontium-lt9611uxc.c:473:14: warning: no previous prototype for 'lt9611uxc_bridge_get_edid' [-Wmissing-prototypes]
473 | struct edid *lt9611uxc_bridge_get_edid(struct drm_bridge *bridge,
| ^~~~~~~~~~~~~~~~~~~~~~~~~
# https://github.com/0day-ci/linux/commit/f1b935d064fd8924137d420e75eb050c3d66c22b
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Dmitry-Baryshkov/Add-LT9611UXC-DSI-to-HDMI-bridge-support/20200828-200735
git checkout f1b935d064fd8924137d420e75eb050c3d66c22b
vim +/vsync_porch +322 drivers/gpu/drm/bridge/lontium-lt9611uxc.c
317
318 static void lt9611uxc_video_setup(struct lt9611uxc *lt9611uxc,
319 const struct drm_display_mode *mode)
320 {
> 321 u32 h_total, hactive, hsync_len, hfront_porch, hsync_porch;
> 322 u32 v_total, vactive, vsync_len, vfront_porch, vsync_porch;
323
324 h_total = mode->htotal;
325 v_total = mode->vtotal;
326
327 hactive = mode->hdisplay;
328 hsync_len = mode->hsync_end - mode->hsync_start;
329 hfront_porch = mode->hsync_start - mode->hdisplay;
330 hsync_porch = hsync_len + mode->htotal - mode->hsync_end;
331
332 vactive = mode->vdisplay;
333 vsync_len = mode->vsync_end - mode->vsync_start;
334 vfront_porch = mode->vsync_start - mode->vdisplay;
335 vsync_porch = vsync_len + mode->vtotal - mode->vsync_end;
336
337 regmap_write(lt9611uxc->regmap, 0xd00d, (u8)(v_total / 256));
338 regmap_write(lt9611uxc->regmap, 0xd00e, (u8)(v_total % 256));
339
340 regmap_write(lt9611uxc->regmap, 0xd00f, (u8)(vactive / 256));
341 regmap_write(lt9611uxc->regmap, 0xd010, (u8)(vactive % 256));
342
343 regmap_write(lt9611uxc->regmap, 0xd011, (u8)(h_total / 256));
344 regmap_write(lt9611uxc->regmap, 0xd012, (u8)(h_total % 256));
345
346 regmap_write(lt9611uxc->regmap, 0xd013, (u8)(hactive / 256));
347 regmap_write(lt9611uxc->regmap, 0xd014, (u8)(hactive % 256));
348
349 regmap_write(lt9611uxc->regmap, 0xd015, (u8)(vsync_len % 256));
350
351 regmap_update_bits(lt9611uxc->regmap, 0xd016, 0xf, (u8)(hsync_len / 256));
352 regmap_write(lt9611uxc->regmap, 0xd017, (u8)(hsync_len % 256));
353
354 regmap_update_bits(lt9611uxc->regmap, 0xd018, 0xf, (u8)(vfront_porch / 256));
355 regmap_write(lt9611uxc->regmap, 0xd019, (u8)(vfront_porch % 256));
356
357 regmap_update_bits(lt9611uxc->regmap, 0xd01a, 0xf, (u8)(hfront_porch / 256));
358 regmap_write(lt9611uxc->regmap, 0xd01b, (u8)(hfront_porch % 256));
359 }
360
361 static void lt9611uxc_bridge_mode_set(struct drm_bridge *bridge,
362 const struct drm_display_mode *mode,
363 const struct drm_display_mode *adj_mode)
364 {
365 struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
366
367 if (lt9611uxc->sleep)
368 lt9611uxc_reset(lt9611uxc);
369
370 lt9611uxc_lock(lt9611uxc);
371 lt9611uxc_video_setup(lt9611uxc, mode);
372 lt9611uxc_unlock(lt9611uxc);
373 }
374
375 static enum drm_connector_status lt9611uxc_bridge_detect(struct drm_bridge *bridge)
376 {
377 struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
378 unsigned int reg_val = 0;
379 int ret;
380 int connected = 1;
381
382 if (lt9611uxc->hpd_supported) {
383 lt9611uxc_lock(lt9611uxc);
384 ret = regmap_read(lt9611uxc->regmap, 0xb023, ®_val);
385 lt9611uxc_unlock(lt9611uxc);
386
387 if (ret)
388 dev_err(lt9611uxc->dev, "failed to read hpd status: %d\n", ret);
389 else
390 connected = reg_val & BIT(1);
391 }
392
393 return connected ? connector_status_connected :
394 connector_status_disconnected;
395 }
396
397 static int lt9611uxc_bridge_get_modes(struct drm_bridge *bridge,
398 struct drm_connector *connector)
399 {
400 struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
401 struct display_timings *timings = lt9611uxc->timings;
402 int i;
403
404 for (i = 0; i < timings->num_timings; i++) {
405 struct drm_display_mode *mode = drm_mode_create(bridge->dev);
406 struct videomode vm;
407
408 if (videomode_from_timings(timings, &vm, i))
409 break;
410
411 drm_display_mode_from_videomode(&vm, mode);
412
413 mode->type = DRM_MODE_TYPE_DRIVER;
414
415 if (timings->native_mode == i)
416 mode->type |= DRM_MODE_TYPE_PREFERRED;
417
418 drm_mode_set_name(mode);
419 drm_mode_probed_add(connector, mode);
420 }
421
422 return i;
423 }
424
425 static int lt9611uxc_read_edid(struct lt9611uxc *lt9611uxc)
426 {
427 int ret = 0;
428 int i;
429
430 /* memset to clear old buffer, if any */
431 memset(lt9611uxc->edid_buf, 0, sizeof(lt9611uxc->edid_buf));
432
433 lt9611uxc_lock(lt9611uxc);
434
435 regmap_write(lt9611uxc->regmap, 0xb00b, 0x10);
436
437 #define EDID_SEG 16
438 for (i = 0; i < 2 * EDID_BLOCK_SIZE; i += EDID_SEG) {
439 regmap_write(lt9611uxc->regmap, 0xb00a, i);
440 ret = regmap_noinc_read(lt9611uxc->regmap, 0xb0b0,
441 <9611uxc->edid_buf[i], EDID_SEG);
442 if (ret < 0)
443 break;
444 }
445
446 lt9611uxc_unlock(lt9611uxc);
447 return ret;
448 }
449
450 static int lt9611uxc_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
451 {
452 struct lt9611uxc *lt9611uxc = data;
453 int ret;
454
455 if (len > EDID_BLOCK_SIZE)
456 return -EINVAL;
457
458 if (block >= EDID_NUM_BLOCKS)
459 return -EINVAL;
460
461 if (block == 0) {
462 ret = lt9611uxc_read_edid(lt9611uxc);
463 if (ret) {
464 dev_err(lt9611uxc->dev, "edid read failed\n");
465 return ret;
466 }
467 }
468
469 memcpy(buf, lt9611uxc->edid_buf + block * EDID_BLOCK_SIZE, len);
470 return 0;
471 };
472
> 473 struct edid *lt9611uxc_bridge_get_edid(struct drm_bridge *bridge,
474 struct drm_connector *connector)
475 {
476 struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
477
478 return drm_do_get_edid(connector, lt9611uxc_get_edid_block, lt9611uxc);
479 }
480
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 74952 bytes --]
[-- Attachment #3: Type: text/plain, Size: 160 bytes --]
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v1 2/2] drm: bridge: add support for lontium LT9611UXC bridge
@ 2020-08-28 13:49 ` kernel test robot
0 siblings, 0 replies; 21+ messages in thread
From: kernel test robot @ 2020-08-28 13:49 UTC (permalink / raw)
To: kbuild-all
[-- Attachment #1: Type: text/plain, Size: 8374 bytes --]
Hi Dmitry,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on drm-tip/drm-tip]
[also build test WARNING on next-20200828]
[cannot apply to robh/for-next drm-intel/for-linux-next tegra-drm/drm/tegra/for-next linus/master drm-exynos/exynos-drm-next drm/drm-next v5.9-rc2]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Dmitry-Baryshkov/Add-LT9611UXC-DSI-to-HDMI-bridge-support/20200828-200735
base: git://anongit.freedesktop.org/drm/drm-tip drm-tip
config: i386-allyesconfig (attached as .config)
compiler: gcc-9 (Debian 9.3.0-15) 9.3.0
reproduce (this is a W=1 build):
# save the attached .config to linux build tree
make W=1 ARCH=i386
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All warnings (new ones prefixed by >>):
drivers/gpu/drm/bridge/lontium-lt9611uxc.c: In function 'lt9611uxc_video_setup':
>> drivers/gpu/drm/bridge/lontium-lt9611uxc.c:322:49: warning: variable 'vsync_porch' set but not used [-Wunused-but-set-variable]
322 | u32 v_total, vactive, vsync_len, vfront_porch, vsync_porch;
| ^~~~~~~~~~~
>> drivers/gpu/drm/bridge/lontium-lt9611uxc.c:321:49: warning: variable 'hsync_porch' set but not used [-Wunused-but-set-variable]
321 | u32 h_total, hactive, hsync_len, hfront_porch, hsync_porch;
| ^~~~~~~~~~~
drivers/gpu/drm/bridge/lontium-lt9611uxc.c: At top level:
>> drivers/gpu/drm/bridge/lontium-lt9611uxc.c:473:14: warning: no previous prototype for 'lt9611uxc_bridge_get_edid' [-Wmissing-prototypes]
473 | struct edid *lt9611uxc_bridge_get_edid(struct drm_bridge *bridge,
| ^~~~~~~~~~~~~~~~~~~~~~~~~
# https://github.com/0day-ci/linux/commit/f1b935d064fd8924137d420e75eb050c3d66c22b
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Dmitry-Baryshkov/Add-LT9611UXC-DSI-to-HDMI-bridge-support/20200828-200735
git checkout f1b935d064fd8924137d420e75eb050c3d66c22b
vim +/vsync_porch +322 drivers/gpu/drm/bridge/lontium-lt9611uxc.c
317
318 static void lt9611uxc_video_setup(struct lt9611uxc *lt9611uxc,
319 const struct drm_display_mode *mode)
320 {
> 321 u32 h_total, hactive, hsync_len, hfront_porch, hsync_porch;
> 322 u32 v_total, vactive, vsync_len, vfront_porch, vsync_porch;
323
324 h_total = mode->htotal;
325 v_total = mode->vtotal;
326
327 hactive = mode->hdisplay;
328 hsync_len = mode->hsync_end - mode->hsync_start;
329 hfront_porch = mode->hsync_start - mode->hdisplay;
330 hsync_porch = hsync_len + mode->htotal - mode->hsync_end;
331
332 vactive = mode->vdisplay;
333 vsync_len = mode->vsync_end - mode->vsync_start;
334 vfront_porch = mode->vsync_start - mode->vdisplay;
335 vsync_porch = vsync_len + mode->vtotal - mode->vsync_end;
336
337 regmap_write(lt9611uxc->regmap, 0xd00d, (u8)(v_total / 256));
338 regmap_write(lt9611uxc->regmap, 0xd00e, (u8)(v_total % 256));
339
340 regmap_write(lt9611uxc->regmap, 0xd00f, (u8)(vactive / 256));
341 regmap_write(lt9611uxc->regmap, 0xd010, (u8)(vactive % 256));
342
343 regmap_write(lt9611uxc->regmap, 0xd011, (u8)(h_total / 256));
344 regmap_write(lt9611uxc->regmap, 0xd012, (u8)(h_total % 256));
345
346 regmap_write(lt9611uxc->regmap, 0xd013, (u8)(hactive / 256));
347 regmap_write(lt9611uxc->regmap, 0xd014, (u8)(hactive % 256));
348
349 regmap_write(lt9611uxc->regmap, 0xd015, (u8)(vsync_len % 256));
350
351 regmap_update_bits(lt9611uxc->regmap, 0xd016, 0xf, (u8)(hsync_len / 256));
352 regmap_write(lt9611uxc->regmap, 0xd017, (u8)(hsync_len % 256));
353
354 regmap_update_bits(lt9611uxc->regmap, 0xd018, 0xf, (u8)(vfront_porch / 256));
355 regmap_write(lt9611uxc->regmap, 0xd019, (u8)(vfront_porch % 256));
356
357 regmap_update_bits(lt9611uxc->regmap, 0xd01a, 0xf, (u8)(hfront_porch / 256));
358 regmap_write(lt9611uxc->regmap, 0xd01b, (u8)(hfront_porch % 256));
359 }
360
361 static void lt9611uxc_bridge_mode_set(struct drm_bridge *bridge,
362 const struct drm_display_mode *mode,
363 const struct drm_display_mode *adj_mode)
364 {
365 struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
366
367 if (lt9611uxc->sleep)
368 lt9611uxc_reset(lt9611uxc);
369
370 lt9611uxc_lock(lt9611uxc);
371 lt9611uxc_video_setup(lt9611uxc, mode);
372 lt9611uxc_unlock(lt9611uxc);
373 }
374
375 static enum drm_connector_status lt9611uxc_bridge_detect(struct drm_bridge *bridge)
376 {
377 struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
378 unsigned int reg_val = 0;
379 int ret;
380 int connected = 1;
381
382 if (lt9611uxc->hpd_supported) {
383 lt9611uxc_lock(lt9611uxc);
384 ret = regmap_read(lt9611uxc->regmap, 0xb023, ®_val);
385 lt9611uxc_unlock(lt9611uxc);
386
387 if (ret)
388 dev_err(lt9611uxc->dev, "failed to read hpd status: %d\n", ret);
389 else
390 connected = reg_val & BIT(1);
391 }
392
393 return connected ? connector_status_connected :
394 connector_status_disconnected;
395 }
396
397 static int lt9611uxc_bridge_get_modes(struct drm_bridge *bridge,
398 struct drm_connector *connector)
399 {
400 struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
401 struct display_timings *timings = lt9611uxc->timings;
402 int i;
403
404 for (i = 0; i < timings->num_timings; i++) {
405 struct drm_display_mode *mode = drm_mode_create(bridge->dev);
406 struct videomode vm;
407
408 if (videomode_from_timings(timings, &vm, i))
409 break;
410
411 drm_display_mode_from_videomode(&vm, mode);
412
413 mode->type = DRM_MODE_TYPE_DRIVER;
414
415 if (timings->native_mode == i)
416 mode->type |= DRM_MODE_TYPE_PREFERRED;
417
418 drm_mode_set_name(mode);
419 drm_mode_probed_add(connector, mode);
420 }
421
422 return i;
423 }
424
425 static int lt9611uxc_read_edid(struct lt9611uxc *lt9611uxc)
426 {
427 int ret = 0;
428 int i;
429
430 /* memset to clear old buffer, if any */
431 memset(lt9611uxc->edid_buf, 0, sizeof(lt9611uxc->edid_buf));
432
433 lt9611uxc_lock(lt9611uxc);
434
435 regmap_write(lt9611uxc->regmap, 0xb00b, 0x10);
436
437 #define EDID_SEG 16
438 for (i = 0; i < 2 * EDID_BLOCK_SIZE; i += EDID_SEG) {
439 regmap_write(lt9611uxc->regmap, 0xb00a, i);
440 ret = regmap_noinc_read(lt9611uxc->regmap, 0xb0b0,
441 <9611uxc->edid_buf[i], EDID_SEG);
442 if (ret < 0)
443 break;
444 }
445
446 lt9611uxc_unlock(lt9611uxc);
447 return ret;
448 }
449
450 static int lt9611uxc_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
451 {
452 struct lt9611uxc *lt9611uxc = data;
453 int ret;
454
455 if (len > EDID_BLOCK_SIZE)
456 return -EINVAL;
457
458 if (block >= EDID_NUM_BLOCKS)
459 return -EINVAL;
460
461 if (block == 0) {
462 ret = lt9611uxc_read_edid(lt9611uxc);
463 if (ret) {
464 dev_err(lt9611uxc->dev, "edid read failed\n");
465 return ret;
466 }
467 }
468
469 memcpy(buf, lt9611uxc->edid_buf + block * EDID_BLOCK_SIZE, len);
470 return 0;
471 };
472
> 473 struct edid *lt9611uxc_bridge_get_edid(struct drm_bridge *bridge,
474 struct drm_connector *connector)
475 {
476 struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
477
478 return drm_do_get_edid(connector, lt9611uxc_get_edid_block, lt9611uxc);
479 }
480
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 74952 bytes --]
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v1 1/2] dt-bindings: display: bridge: Add documentation for LT9611UXC
2020-08-28 12:04 ` Dmitry Baryshkov
@ 2020-08-28 14:00 ` Vinod Koul
-1 siblings, 0 replies; 21+ messages in thread
From: Vinod Koul @ 2020-08-28 14:00 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: devicetree, dri-devel, linux-arm-msm, Rob Herring, Daniel Vetter,
David Airlie, Andrzej Hajda, Neil Armstrong, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec
On 28-08-20, 15:04, Dmitry Baryshkov wrote:
> Lontium LT9611UXC is a DSI to HDMI bridge which supports 2 DSI ports
> and I2S port as input and one HDMI port as output. The LT9611UXC chip is
> handled by a separate driver, but the bindings used are fully compatible
> with the LT9611 chip, so let's reuse the lt9611.yaml schema.
Acked-By: Vinod Koul <vkoul@kernel.org>
--
~Vinod
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v1 1/2] dt-bindings: display: bridge: Add documentation for LT9611UXC
@ 2020-08-28 14:00 ` Vinod Koul
0 siblings, 0 replies; 21+ messages in thread
From: Vinod Koul @ 2020-08-28 14:00 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: devicetree, Jernej Skrabec, Neil Armstrong, David Airlie,
linux-arm-msm, Jonas Karlman, dri-devel, Andrzej Hajda,
Rob Herring, Laurent Pinchart
On 28-08-20, 15:04, Dmitry Baryshkov wrote:
> Lontium LT9611UXC is a DSI to HDMI bridge which supports 2 DSI ports
> and I2S port as input and one HDMI port as output. The LT9611UXC chip is
> handled by a separate driver, but the bindings used are fully compatible
> with the LT9611 chip, so let's reuse the lt9611.yaml schema.
Acked-By: Vinod Koul <vkoul@kernel.org>
--
~Vinod
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v1 2/2] drm: bridge: add support for lontium LT9611UXC bridge
2020-08-28 12:04 ` Dmitry Baryshkov
@ 2020-08-28 14:18 ` Vinod Koul
-1 siblings, 0 replies; 21+ messages in thread
From: Vinod Koul @ 2020-08-28 14:18 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: devicetree, dri-devel, linux-arm-msm, Rob Herring, Daniel Vetter,
David Airlie, Andrzej Hajda, Neil Armstrong, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec
On 28-08-20, 15:04, Dmitry Baryshkov wrote:
> +#define EDID_BLOCK_SIZE 128
> +#define EDID_NUM_BLOCKS 2
tab or space either one, not both ;)
> +static struct mipi_dsi_device *lt9611uxc_attach_dsi(struct lt9611uxc *lt9611uxc,
> + struct device_node *dsi_node)
Please align this with open parenthesis of preceding line (checkpatch
with --strict option will check this)
> +static int lt9611uxc_bridge_attach(struct drm_bridge *bridge,
> + enum drm_bridge_attach_flags flags)
> +{
> + struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
> + int ret;
> +
> + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
> + dev_err(lt9611uxc->dev, "Fix bridge driver to make connector optional!");
Can we support both modes as I have done in lt9611, that way once the
conversion is done we can drop the init part and support conversion.
I have patch for msm driver to set DRM_BRIDGE_ATTACH_NO_CONNECTOR, you
can use that to test
> +static int lt9611uxc_hdmi_hw_params(struct device *dev, void *data,
> + struct hdmi_codec_daifmt *fmt,
> + struct hdmi_codec_params *hparms)
> +{
> + /*
> + * LT9611UXC will automatically detect rate and sample size, so no need
> + * to setup anything here.
> + */
> + return 0;
> +}
Do we need dummy function?
--
~Vinod
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v1 2/2] drm: bridge: add support for lontium LT9611UXC bridge
@ 2020-08-28 14:18 ` Vinod Koul
0 siblings, 0 replies; 21+ messages in thread
From: Vinod Koul @ 2020-08-28 14:18 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: devicetree, Jernej Skrabec, Neil Armstrong, David Airlie,
linux-arm-msm, Jonas Karlman, dri-devel, Andrzej Hajda,
Rob Herring, Laurent Pinchart
On 28-08-20, 15:04, Dmitry Baryshkov wrote:
> +#define EDID_BLOCK_SIZE 128
> +#define EDID_NUM_BLOCKS 2
tab or space either one, not both ;)
> +static struct mipi_dsi_device *lt9611uxc_attach_dsi(struct lt9611uxc *lt9611uxc,
> + struct device_node *dsi_node)
Please align this with open parenthesis of preceding line (checkpatch
with --strict option will check this)
> +static int lt9611uxc_bridge_attach(struct drm_bridge *bridge,
> + enum drm_bridge_attach_flags flags)
> +{
> + struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
> + int ret;
> +
> + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
> + dev_err(lt9611uxc->dev, "Fix bridge driver to make connector optional!");
Can we support both modes as I have done in lt9611, that way once the
conversion is done we can drop the init part and support conversion.
I have patch for msm driver to set DRM_BRIDGE_ATTACH_NO_CONNECTOR, you
can use that to test
> +static int lt9611uxc_hdmi_hw_params(struct device *dev, void *data,
> + struct hdmi_codec_daifmt *fmt,
> + struct hdmi_codec_params *hparms)
> +{
> + /*
> + * LT9611UXC will automatically detect rate and sample size, so no need
> + * to setup anything here.
> + */
> + return 0;
> +}
Do we need dummy function?
--
~Vinod
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v1 2/2] drm: bridge: add support for lontium LT9611UXC bridge
2020-08-28 14:18 ` Vinod Koul
@ 2020-08-28 14:33 ` Laurent Pinchart
-1 siblings, 0 replies; 21+ messages in thread
From: Laurent Pinchart @ 2020-08-28 14:33 UTC (permalink / raw)
To: Vinod Koul
Cc: Dmitry Baryshkov, devicetree, dri-devel, linux-arm-msm,
Rob Herring, Daniel Vetter, David Airlie, Andrzej Hajda,
Neil Armstrong, Jonas Karlman, Jernej Skrabec
On Fri, Aug 28, 2020 at 07:48:48PM +0530, Vinod Koul wrote:
> On 28-08-20, 15:04, Dmitry Baryshkov wrote:
>
> > +#define EDID_BLOCK_SIZE 128
> > +#define EDID_NUM_BLOCKS 2
>
> tab or space either one, not both ;)
>
> > +static struct mipi_dsi_device *lt9611uxc_attach_dsi(struct lt9611uxc *lt9611uxc,
> > + struct device_node *dsi_node)
>
> Please align this with open parenthesis of preceding line (checkpatch
> with --strict option will check this)
>
> > +static int lt9611uxc_bridge_attach(struct drm_bridge *bridge,
> > + enum drm_bridge_attach_flags flags)
> > +{
> > + struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
> > + int ret;
> > +
> > + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
> > + dev_err(lt9611uxc->dev, "Fix bridge driver to make connector optional!");
>
> Can we support both modes as I have done in lt9611, that way once the
> conversion is done we can drop the init part and support conversion.
I was going to mention that :-) New drivers should support the
DRM_BRIDGE_ATTACH_NO_CONNECTOR flag.
> I have patch for msm driver to set DRM_BRIDGE_ATTACH_NO_CONNECTOR, you
> can use that to test
>
> > +static int lt9611uxc_hdmi_hw_params(struct device *dev, void *data,
> > + struct hdmi_codec_daifmt *fmt,
> > + struct hdmi_codec_params *hparms)
> > +{
> > + /*
> > + * LT9611UXC will automatically detect rate and sample size, so no need
> > + * to setup anything here.
> > + */
> > + return 0;
> > +}
>
> Do we need dummy function?
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v1 2/2] drm: bridge: add support for lontium LT9611UXC bridge
@ 2020-08-28 14:33 ` Laurent Pinchart
0 siblings, 0 replies; 21+ messages in thread
From: Laurent Pinchart @ 2020-08-28 14:33 UTC (permalink / raw)
To: Vinod Koul
Cc: devicetree, Jernej Skrabec, Neil Armstrong, David Airlie,
linux-arm-msm, Jonas Karlman, dri-devel, Andrzej Hajda,
Rob Herring, Dmitry Baryshkov
On Fri, Aug 28, 2020 at 07:48:48PM +0530, Vinod Koul wrote:
> On 28-08-20, 15:04, Dmitry Baryshkov wrote:
>
> > +#define EDID_BLOCK_SIZE 128
> > +#define EDID_NUM_BLOCKS 2
>
> tab or space either one, not both ;)
>
> > +static struct mipi_dsi_device *lt9611uxc_attach_dsi(struct lt9611uxc *lt9611uxc,
> > + struct device_node *dsi_node)
>
> Please align this with open parenthesis of preceding line (checkpatch
> with --strict option will check this)
>
> > +static int lt9611uxc_bridge_attach(struct drm_bridge *bridge,
> > + enum drm_bridge_attach_flags flags)
> > +{
> > + struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
> > + int ret;
> > +
> > + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
> > + dev_err(lt9611uxc->dev, "Fix bridge driver to make connector optional!");
>
> Can we support both modes as I have done in lt9611, that way once the
> conversion is done we can drop the init part and support conversion.
I was going to mention that :-) New drivers should support the
DRM_BRIDGE_ATTACH_NO_CONNECTOR flag.
> I have patch for msm driver to set DRM_BRIDGE_ATTACH_NO_CONNECTOR, you
> can use that to test
>
> > +static int lt9611uxc_hdmi_hw_params(struct device *dev, void *data,
> > + struct hdmi_codec_daifmt *fmt,
> > + struct hdmi_codec_params *hparms)
> > +{
> > + /*
> > + * LT9611UXC will automatically detect rate and sample size, so no need
> > + * to setup anything here.
> > + */
> > + return 0;
> > +}
>
> Do we need dummy function?
--
Regards,
Laurent Pinchart
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v1 2/2] drm: bridge: add support for lontium LT9611UXC bridge
2020-08-28 14:18 ` Vinod Koul
@ 2020-08-28 15:01 ` Dmitry Baryshkov
-1 siblings, 0 replies; 21+ messages in thread
From: Dmitry Baryshkov @ 2020-08-28 15:01 UTC (permalink / raw)
To: Vinod Koul
Cc: devicetree, dri-devel, linux-arm-msm, Rob Herring, Daniel Vetter,
David Airlie, Andrzej Hajda, Neil Armstrong, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec
On 28/08/2020 17:18, Vinod Koul wrote:
> On 28-08-20, 15:04, Dmitry Baryshkov wrote:
>> +static int lt9611uxc_bridge_attach(struct drm_bridge *bridge,
>> + enum drm_bridge_attach_flags flags)
>> +{
>> + struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
>> + int ret;
>> +
>> + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
>> + dev_err(lt9611uxc->dev, "Fix bridge driver to make connector optional!");
>
> Can we support both modes as I have done in lt9611, that way once the
> conversion is done we can drop the init part and support conversion.
>
> I have patch for msm driver to set DRM_BRIDGE_ATTACH_NO_CONNECTOR, you
> can use that to test
Probably the message text is misleading. The driver as is does not work
w/o DRM_BRIDGE_ATTACH_NO_CONNECTOR. Do you plan to push that patch into
upstream tree?
>> +static int lt9611uxc_hdmi_hw_params(struct device *dev, void *data,
>> + struct hdmi_codec_daifmt *fmt,
>> + struct hdmi_codec_params *hparms)
>> +{
>> + /*
>> + * LT9611UXC will automatically detect rate and sample size, so no need
>> + * to setup anything here.
>> + */
>> + return 0;
>> +}
>
> Do we need dummy function?
Yes, this callback is mandatory (and audio_shutdown).
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v1 2/2] drm: bridge: add support for lontium LT9611UXC bridge
@ 2020-08-28 15:01 ` Dmitry Baryshkov
0 siblings, 0 replies; 21+ messages in thread
From: Dmitry Baryshkov @ 2020-08-28 15:01 UTC (permalink / raw)
To: Vinod Koul
Cc: devicetree, Jernej Skrabec, Neil Armstrong, David Airlie,
linux-arm-msm, Jonas Karlman, dri-devel, Andrzej Hajda,
Rob Herring, Laurent Pinchart
On 28/08/2020 17:18, Vinod Koul wrote:
> On 28-08-20, 15:04, Dmitry Baryshkov wrote:
>> +static int lt9611uxc_bridge_attach(struct drm_bridge *bridge,
>> + enum drm_bridge_attach_flags flags)
>> +{
>> + struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
>> + int ret;
>> +
>> + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
>> + dev_err(lt9611uxc->dev, "Fix bridge driver to make connector optional!");
>
> Can we support both modes as I have done in lt9611, that way once the
> conversion is done we can drop the init part and support conversion.
>
> I have patch for msm driver to set DRM_BRIDGE_ATTACH_NO_CONNECTOR, you
> can use that to test
Probably the message text is misleading. The driver as is does not work
w/o DRM_BRIDGE_ATTACH_NO_CONNECTOR. Do you plan to push that patch into
upstream tree?
>> +static int lt9611uxc_hdmi_hw_params(struct device *dev, void *data,
>> + struct hdmi_codec_daifmt *fmt,
>> + struct hdmi_codec_params *hparms)
>> +{
>> + /*
>> + * LT9611UXC will automatically detect rate and sample size, so no need
>> + * to setup anything here.
>> + */
>> + return 0;
>> +}
>
> Do we need dummy function?
Yes, this callback is mandatory (and audio_shutdown).
--
With best wishes
Dmitry
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v1 2/2] drm: bridge: add support for lontium LT9611UXC bridge
2020-08-28 14:33 ` Laurent Pinchart
@ 2020-08-28 15:04 ` Laurent Pinchart
-1 siblings, 0 replies; 21+ messages in thread
From: Laurent Pinchart @ 2020-08-28 15:04 UTC (permalink / raw)
To: Vinod Koul
Cc: devicetree, Jernej Skrabec, Neil Armstrong, David Airlie,
linux-arm-msm, Jonas Karlman, dri-devel, Andrzej Hajda,
Rob Herring, Dmitry Baryshkov
On Fri, Aug 28, 2020 at 05:33:00PM +0300, Laurent Pinchart wrote:
> On Fri, Aug 28, 2020 at 07:48:48PM +0530, Vinod Koul wrote:
> > On 28-08-20, 15:04, Dmitry Baryshkov wrote:
> >
> > > +#define EDID_BLOCK_SIZE 128
> > > +#define EDID_NUM_BLOCKS 2
> >
> > tab or space either one, not both ;)
> >
> > > +static struct mipi_dsi_device *lt9611uxc_attach_dsi(struct lt9611uxc *lt9611uxc,
> > > + struct device_node *dsi_node)
> >
> > Please align this with open parenthesis of preceding line (checkpatch
> > with --strict option will check this)
> >
> > > +static int lt9611uxc_bridge_attach(struct drm_bridge *bridge,
> > > + enum drm_bridge_attach_flags flags)
> > > +{
> > > + struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
> > > + int ret;
> > > +
> > > + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
> > > + dev_err(lt9611uxc->dev, "Fix bridge driver to make connector optional!");
> >
> > Can we support both modes as I have done in lt9611, that way once the
> > conversion is done we can drop the init part and support conversion.
>
> I was going to mention that :-) New drivers should support the
> DRM_BRIDGE_ATTACH_NO_CONNECTOR flag.
Please ignore this comment, I just realized that the driver supports
DRM_BRIDGE_ATTACH_NO_CONNECTOR, it's the !DRM_BRIDGE_ATTACH_NO_CONNECTOR
case that is not supported, and that's totally fine.
> > I have patch for msm driver to set DRM_BRIDGE_ATTACH_NO_CONNECTOR, you
> > can use that to test
> >
> > > +static int lt9611uxc_hdmi_hw_params(struct device *dev, void *data,
> > > + struct hdmi_codec_daifmt *fmt,
> > > + struct hdmi_codec_params *hparms)
> > > +{
> > > + /*
> > > + * LT9611UXC will automatically detect rate and sample size, so no need
> > > + * to setup anything here.
> > > + */
> > > + return 0;
> > > +}
> >
> > Do we need dummy function?
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v1 2/2] drm: bridge: add support for lontium LT9611UXC bridge
@ 2020-08-28 15:04 ` Laurent Pinchart
0 siblings, 0 replies; 21+ messages in thread
From: Laurent Pinchart @ 2020-08-28 15:04 UTC (permalink / raw)
To: Vinod Koul
Cc: devicetree, Jernej Skrabec, Jonas Karlman, David Airlie,
linux-arm-msm, Neil Armstrong, dri-devel, Andrzej Hajda,
Rob Herring, Dmitry Baryshkov
On Fri, Aug 28, 2020 at 05:33:00PM +0300, Laurent Pinchart wrote:
> On Fri, Aug 28, 2020 at 07:48:48PM +0530, Vinod Koul wrote:
> > On 28-08-20, 15:04, Dmitry Baryshkov wrote:
> >
> > > +#define EDID_BLOCK_SIZE 128
> > > +#define EDID_NUM_BLOCKS 2
> >
> > tab or space either one, not both ;)
> >
> > > +static struct mipi_dsi_device *lt9611uxc_attach_dsi(struct lt9611uxc *lt9611uxc,
> > > + struct device_node *dsi_node)
> >
> > Please align this with open parenthesis of preceding line (checkpatch
> > with --strict option will check this)
> >
> > > +static int lt9611uxc_bridge_attach(struct drm_bridge *bridge,
> > > + enum drm_bridge_attach_flags flags)
> > > +{
> > > + struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
> > > + int ret;
> > > +
> > > + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
> > > + dev_err(lt9611uxc->dev, "Fix bridge driver to make connector optional!");
> >
> > Can we support both modes as I have done in lt9611, that way once the
> > conversion is done we can drop the init part and support conversion.
>
> I was going to mention that :-) New drivers should support the
> DRM_BRIDGE_ATTACH_NO_CONNECTOR flag.
Please ignore this comment, I just realized that the driver supports
DRM_BRIDGE_ATTACH_NO_CONNECTOR, it's the !DRM_BRIDGE_ATTACH_NO_CONNECTOR
case that is not supported, and that's totally fine.
> > I have patch for msm driver to set DRM_BRIDGE_ATTACH_NO_CONNECTOR, you
> > can use that to test
> >
> > > +static int lt9611uxc_hdmi_hw_params(struct device *dev, void *data,
> > > + struct hdmi_codec_daifmt *fmt,
> > > + struct hdmi_codec_params *hparms)
> > > +{
> > > + /*
> > > + * LT9611UXC will automatically detect rate and sample size, so no need
> > > + * to setup anything here.
> > > + */
> > > + return 0;
> > > +}
> >
> > Do we need dummy function?
--
Regards,
Laurent Pinchart
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v1 2/2] drm: bridge: add support for lontium LT9611UXC bridge
2020-08-28 15:01 ` Dmitry Baryshkov
@ 2020-08-28 15:06 ` Vinod Koul
-1 siblings, 0 replies; 21+ messages in thread
From: Vinod Koul @ 2020-08-28 15:06 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: devicetree, dri-devel, linux-arm-msm, Rob Herring, Daniel Vetter,
David Airlie, Andrzej Hajda, Neil Armstrong, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec
On 28-08-20, 18:01, Dmitry Baryshkov wrote:
> On 28/08/2020 17:18, Vinod Koul wrote:
> > On 28-08-20, 15:04, Dmitry Baryshkov wrote:
> > > +static int lt9611uxc_bridge_attach(struct drm_bridge *bridge,
> > > + enum drm_bridge_attach_flags flags)
> > > +{
> > > + struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
> > > + int ret;
> > > +
> > > + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
> > > + dev_err(lt9611uxc->dev, "Fix bridge driver to make connector optional!");
> >
> > Can we support both modes as I have done in lt9611, that way once the
> > conversion is done we can drop the init part and support conversion.
> >
> > I have patch for msm driver to set DRM_BRIDGE_ATTACH_NO_CONNECTOR, you
> > can use that to test
>
> Probably the message text is misleading. The driver as is does not work w/o
> DRM_BRIDGE_ATTACH_NO_CONNECTOR. Do you plan to push that patch into upstream
> tree?
It causes regression in laptop so have removed it ;( I need to fix that
first
The patch is here though and works on rb3 and db410c.
git.linaro.org/people/vinod.koul/kernel.git drm/no_connector
--
~Vinod
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v1 2/2] drm: bridge: add support for lontium LT9611UXC bridge
@ 2020-08-28 15:06 ` Vinod Koul
0 siblings, 0 replies; 21+ messages in thread
From: Vinod Koul @ 2020-08-28 15:06 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: devicetree, Jernej Skrabec, Neil Armstrong, David Airlie,
linux-arm-msm, Jonas Karlman, dri-devel, Andrzej Hajda,
Rob Herring, Laurent Pinchart
On 28-08-20, 18:01, Dmitry Baryshkov wrote:
> On 28/08/2020 17:18, Vinod Koul wrote:
> > On 28-08-20, 15:04, Dmitry Baryshkov wrote:
> > > +static int lt9611uxc_bridge_attach(struct drm_bridge *bridge,
> > > + enum drm_bridge_attach_flags flags)
> > > +{
> > > + struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
> > > + int ret;
> > > +
> > > + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
> > > + dev_err(lt9611uxc->dev, "Fix bridge driver to make connector optional!");
> >
> > Can we support both modes as I have done in lt9611, that way once the
> > conversion is done we can drop the init part and support conversion.
> >
> > I have patch for msm driver to set DRM_BRIDGE_ATTACH_NO_CONNECTOR, you
> > can use that to test
>
> Probably the message text is misleading. The driver as is does not work w/o
> DRM_BRIDGE_ATTACH_NO_CONNECTOR. Do you plan to push that patch into upstream
> tree?
It causes regression in laptop so have removed it ;( I need to fix that
first
The patch is here though and works on rb3 and db410c.
git.linaro.org/people/vinod.koul/kernel.git drm/no_connector
--
~Vinod
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 21+ messages in thread
end of thread, other threads:[~2020-08-29 9:23 UTC | newest]
Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-28 12:04 [PATCH v1 0/2] Add LT9611UXC DSI to HDMI bridge support Dmitry Baryshkov
2020-08-28 12:04 ` Dmitry Baryshkov
2020-08-28 12:04 ` [PATCH v1 1/2] dt-bindings: display: bridge: Add documentation for LT9611UXC Dmitry Baryshkov
2020-08-28 12:04 ` Dmitry Baryshkov
2020-08-28 14:00 ` Vinod Koul
2020-08-28 14:00 ` Vinod Koul
2020-08-28 12:04 ` [PATCH v1 2/2] drm: bridge: add support for lontium LT9611UXC bridge Dmitry Baryshkov
2020-08-28 12:04 ` Dmitry Baryshkov
2020-08-28 13:49 ` kernel test robot
2020-08-28 13:49 ` kernel test robot
2020-08-28 13:49 ` kernel test robot
2020-08-28 14:18 ` Vinod Koul
2020-08-28 14:18 ` Vinod Koul
2020-08-28 14:33 ` Laurent Pinchart
2020-08-28 14:33 ` Laurent Pinchart
2020-08-28 15:04 ` Laurent Pinchart
2020-08-28 15:04 ` Laurent Pinchart
2020-08-28 15:01 ` Dmitry Baryshkov
2020-08-28 15:01 ` Dmitry Baryshkov
2020-08-28 15:06 ` Vinod Koul
2020-08-28 15:06 ` Vinod Koul
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.