2024-02-16 10:11:28

by Luca Weiss

[permalink] [raw]
Subject: [PATCH v3 0/4] Add display support for Fairphone 4

Introduce the bindings and panel driver for the LCD panel with the model
number 9A-3R063-1102B from DJN which is using the HX83112A driver IC. It
is used on the Fairphone 4 smartphone.

Then we can add the panel to the device dts and also enable the GPU.

Signed-off-by: Luca Weiss <[email protected]>
---
Changes in v3:
- Update compatible to djn,9a-3r063-1102b
- Add defines for manufacturer-specific DSI commands
- Pick up tags
- Link to v2: https://lore.kernel.org/r/[email protected]

Changes in v2:
- Driver:
- Drop "bool prepared" from driver (Dmitry)
- Use drm_connector_helper_get_modes_fixed (Dmitry)
- Use dev_err_probe in error path (Dmitry)
- Fix width/height variables (myself)
- Dts:
- Don't drop simple-framebuffer (Konrad)
- Drop disablement of gmu in dtsi (Konrad)
- Set zap shader path (myself)
- Pick up tags
- Link to v1: https://lore.kernel.org/r/[email protected]

---
Luca Weiss (4):
dt-bindings: display: panel: Add Himax HX83112A
drm/panel: Add driver for DJN HX83112A LCD panel
arm64: dts: qcom: sm6350: Remove "disabled" state of GMU
arm64: dts: qcom: sm7225-fairphone-fp4: Enable display and GPU

.../bindings/display/panel/himax,hx83112a.yaml | 74 ++++
arch/arm64/boot/dts/qcom/sm6350.dtsi | 4 +-
arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts | 53 +++
drivers/gpu/drm/panel/Kconfig | 10 +
drivers/gpu/drm/panel/Makefile | 1 +
drivers/gpu/drm/panel/panel-himax-hx83112a.c | 372 +++++++++++++++++++++
6 files changed, 511 insertions(+), 3 deletions(-)
---
base-commit: 91f11e5814cfbad83ee22fbcf96b0eb41302d889
change-id: 20240105-fp4-panel-50aba8536a0a

Best regards,
--
Luca Weiss <[email protected]>



2024-02-16 10:11:52

by Luca Weiss

[permalink] [raw]
Subject: [PATCH v3 3/4] arm64: dts: qcom: sm6350: Remove "disabled" state of GMU

The GMU won't probe without GPU being enabled, so we can remove the
disabled status so we don't have to explicitly enable the GMU in all the
devices that enable GPU.

Reviewed-by: Konrad Dybcio <[email protected]>
Signed-off-by: Luca Weiss <[email protected]>
---
arch/arm64/boot/dts/qcom/sm6350.dtsi | 2 --
1 file changed, 2 deletions(-)

diff --git a/arch/arm64/boot/dts/qcom/sm6350.dtsi b/arch/arm64/boot/dts/qcom/sm6350.dtsi
index 43cffe8e1247..5a05f14669be 100644
--- a/arch/arm64/boot/dts/qcom/sm6350.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm6350.dtsi
@@ -1439,8 +1439,6 @@ gmu: gmu@3d6a000 {

operating-points-v2 = <&gmu_opp_table>;

- status = "disabled";
-
gmu_opp_table: opp-table {
compatible = "operating-points-v2";


--
2.43.2


2024-02-16 10:12:12

by Luca Weiss

[permalink] [raw]
Subject: [PATCH v3 4/4] arm64: dts: qcom: sm7225-fairphone-fp4: Enable display and GPU

Add the description for the display panel found on this phone.
Unfortunately the LCDB module on PM6150L isn't yet supported upstream so
we need to use a dummy regulator-fixed in the meantime.

And with this done we can also enable the GPU and set the zap shader
firmware path.

Reviewed-by: Konrad Dybcio <[email protected]>
Signed-off-by: Luca Weiss <[email protected]>
---
arch/arm64/boot/dts/qcom/sm6350.dtsi | 2 +-
arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts | 53 +++++++++++++++++++++++
2 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/qcom/sm6350.dtsi b/arch/arm64/boot/dts/qcom/sm6350.dtsi
index 5a05f14669be..c8099b10ddc4 100644
--- a/arch/arm64/boot/dts/qcom/sm6350.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm6350.dtsi
@@ -1328,7 +1328,7 @@ gpu: gpu@3d00000 {

status = "disabled";

- zap-shader {
+ gpu_zap_shader: zap-shader {
memory-region = <&pil_gpu_mem>;
};

diff --git a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts
index ade619805519..4e61da8078d1 100644
--- a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts
+++ b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts
@@ -68,6 +68,14 @@ key-volume-up {
};
};

+ /* Dummy regulator until PM6150L has LCDB VSP/VSN support */
+ lcdb_dummy: regulator-lcdb-dummy {
+ compatible = "regulator-fixed";
+ regulator-name = "lcdb_dummy";
+ regulator-min-microvolt = <5500000>;
+ regulator-max-microvolt = <5500000>;
+ };
+
reserved-memory {
/*
* The rmtfs memory region in downstream is 'dynamically allocated'
@@ -373,6 +381,14 @@ &gpi_dma1 {
status = "okay";
};

+&gpu {
+ status = "okay";
+};
+
+&gpu_zap_shader {
+ firmware-name = "qcom/sm7225/fairphone4/a615_zap.mbn";
+};
+
&i2c0 {
clock-frequency = <400000>;
status = "okay";
@@ -404,6 +420,43 @@ &ipa {
status = "okay";
};

+&mdss {
+ status = "okay";
+};
+
+&mdss_dsi0 {
+ vdda-supply = <&vreg_l22a>;
+ status = "okay";
+
+ panel@0 {
+ compatible = "djn,9a-3r063-1102b";
+ reg = <0>;
+
+ backlight = <&pm6150l_wled>;
+ reset-gpios = <&pm6150l_gpios 9 GPIO_ACTIVE_LOW>;
+
+ vdd1-supply = <&vreg_l1e>;
+ vsn-supply = <&lcdb_dummy>;
+ vsp-supply = <&lcdb_dummy>;
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&mdss_dsi0_out>;
+ };
+ };
+ };
+};
+
+&mdss_dsi0_out {
+ data-lanes = <0 1 2 3>;
+ remote-endpoint = <&panel_in>;
+};
+
+&mdss_dsi0_phy {
+ vdds-supply = <&vreg_l18a>;
+ status = "okay";
+};
+
&mpss {
firmware-name = "qcom/sm7225/fairphone4/modem.mdt";
status = "okay";

--
2.43.2


2024-02-16 10:12:13

by Luca Weiss

[permalink] [raw]
Subject: [PATCH v3 1/4] dt-bindings: display: panel: Add Himax HX83112A

Himax HX83112A is a display driver IC used to drive LCD DSI panels.
Describe it and the DJN 9A-3R063-1102B using it.

Reviewed-by: Krzysztof Kozlowski <[email protected]>
Signed-off-by: Luca Weiss <[email protected]>
---
.../bindings/display/panel/himax,hx83112a.yaml | 74 ++++++++++++++++++++++
1 file changed, 74 insertions(+)

diff --git a/Documentation/devicetree/bindings/display/panel/himax,hx83112a.yaml b/Documentation/devicetree/bindings/display/panel/himax,hx83112a.yaml
new file mode 100644
index 000000000000..174661d13811
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/himax,hx83112a.yaml
@@ -0,0 +1,74 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/himax,hx83112a.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Himax HX83112A-based DSI display panels
+
+maintainers:
+ - Luca Weiss <[email protected]>
+
+description:
+ The Himax HX83112A is a generic DSI Panel IC used to control
+ LCD panels.
+
+allOf:
+ - $ref: panel-common.yaml#
+
+properties:
+ compatible:
+ contains:
+ const: djn,9a-3r063-1102b
+
+ vdd1-supply:
+ description: Digital voltage rail
+
+ vsn-supply:
+ description: Positive source voltage rail
+
+ vsp-supply:
+ description: Negative source voltage rail
+
+ reg: true
+ port: true
+
+required:
+ - compatible
+ - reg
+ - reset-gpios
+ - vdd1-supply
+ - vsn-supply
+ - vsp-supply
+ - port
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ dsi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ panel@0 {
+ compatible = "djn,9a-3r063-1102b";
+ reg = <0>;
+
+ backlight = <&pm6150l_wled>;
+ reset-gpios = <&pm6150l_gpios 9 GPIO_ACTIVE_LOW>;
+
+ vdd1-supply = <&vreg_l1e>;
+ vsn-supply = <&pm6150l_lcdb_ncp>;
+ vsp-supply = <&pm6150l_lcdb_ldo>;
+
+ port {
+ panel_in_0: endpoint {
+ remote-endpoint = <&dsi0_out>;
+ };
+ };
+ };
+ };
+
+...

--
2.43.2


2024-02-16 10:12:23

by Luca Weiss

[permalink] [raw]
Subject: [PATCH v3 2/4] drm/panel: Add driver for DJN HX83112A LCD panel

Add support for the 2340x1080 LCD panel (DJN 9A-3R063-1102B) bundled
with a HX83112A driver IC, as found on the Fairphone 4 smartphone.

Signed-off-by: Luca Weiss <[email protected]>
---
drivers/gpu/drm/panel/Kconfig | 10 +
drivers/gpu/drm/panel/Makefile | 1 +
drivers/gpu/drm/panel/panel-himax-hx83112a.c | 372 +++++++++++++++++++++++++++
3 files changed, 383 insertions(+)

diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 8f3783742208..7e25a4609682 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -162,6 +162,16 @@ config DRM_PANEL_FEIYANG_FY07024DI26A30D
Say Y if you want to enable support for panels based on the
Feiyang FY07024DI26A30-D MIPI-DSI interface.

+config DRM_PANEL_HIMAX_HX83112A
+ tristate "Himax HX83112A-based DSI panel"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ select DRM_KMS_HELPER
+ help
+ Say Y here if you want to enable support for Himax HX83112A-based
+ display panels, such as the one found in the Fairphone 4 smartphone.
+
config DRM_PANEL_HIMAX_HX8394
tristate "HIMAX HX8394 MIPI-DSI LCD panels"
depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index d94a644d0a6c..f3e40f24d516 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_DRM_PANEL_EBBG_FT8719) += panel-ebbg-ft8719.o
obj-$(CONFIG_DRM_PANEL_ELIDA_KD35T133) += panel-elida-kd35t133.o
obj-$(CONFIG_DRM_PANEL_FEIXIN_K101_IM2BA02) += panel-feixin-k101-im2ba02.o
obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += panel-feiyang-fy07024di26a30d.o
+obj-$(CONFIG_DRM_PANEL_HIMAX_HX83112A) += panel-himax-hx83112a.o
obj-$(CONFIG_DRM_PANEL_HIMAX_HX8394) += panel-himax-hx8394.o
obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o
obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o
diff --git a/drivers/gpu/drm/panel/panel-himax-hx83112a.c b/drivers/gpu/drm/panel/panel-himax-hx83112a.c
new file mode 100644
index 000000000000..466c27012abf
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-himax-hx83112a.c
@@ -0,0 +1,372 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree.
+ * Copyright (c) 2024 Luca Weiss <[email protected]>
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
+
+/* Manufacturer specific DSI commands */
+#define HX83112A_SETPOWER1 0xb1
+#define HX83112A_SETDISP 0xb2
+#define HX83112A_SETDRV 0xb4
+#define HX83112A_SETEXTC 0xb9
+#define HX83112A_SETBANK 0xbd
+#define HX83112A_SETPTBA 0xbf
+#define HX83112A_SETDGCLUT 0xc1
+#define HX83112A_SETTCON 0xc7
+#define HX83112A_SETCLOCK 0xcb
+#define HX83112A_SETPANEL 0xcc
+#define HX83112A_SETPOWER2 0xd2
+#define HX83112A_SETGIP0 0xd3
+#define HX83112A_SETGIP1 0xd5
+#define HX83112A_SETGIP2 0xd6
+#define HX83112A_SETGIP3 0xd8
+#define HX83112A_SETTP1 0xe7
+#define HX83112A_UNKNOWN1 0xe9
+
+struct hx83112a_panel {
+ struct drm_panel panel;
+ struct mipi_dsi_device *dsi;
+ struct regulator_bulk_data supplies[3];
+ struct gpio_desc *reset_gpio;
+};
+
+static inline struct hx83112a_panel *to_hx83112a_panel(struct drm_panel *panel)
+{
+ return container_of(panel, struct hx83112a_panel, panel);
+}
+
+static void hx83112a_reset(struct hx83112a_panel *ctx)
+{
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+ msleep(20);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ msleep(20);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+ msleep(50);
+}
+
+static int hx83112a_on(struct hx83112a_panel *ctx)
+{
+ struct mipi_dsi_device *dsi = ctx->dsi;
+ struct device *dev = &dsi->dev;
+ int ret;
+
+ dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETEXTC, 0x83, 0x11, 0x2a);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETPOWER1,
+ 0x08, 0x28, 0x28, 0x83, 0x83, 0x4c, 0x4f, 0x33);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDISP,
+ 0x00, 0x02, 0x00, 0x90, 0x24, 0x00, 0x08, 0x19,
+ 0xea, 0x11, 0x11, 0x00, 0x11, 0xa3);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDRV,
+ 0x58, 0x68, 0x58, 0x68, 0x0f, 0xef, 0x0b, 0xc0,
+ 0x0b, 0xc0, 0x0b, 0xc0, 0x00, 0xff, 0x00, 0xff,
+ 0x00, 0x00, 0x14, 0x15, 0x00, 0x29, 0x11, 0x07,
+ 0x12, 0x00, 0x29);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x02);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDRV,
+ 0x00, 0x12, 0x12, 0x11, 0x88, 0x12, 0x12, 0x00,
+ 0x53);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x03);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDGCLUT,
+ 0xff, 0xfe, 0xfb, 0xf8, 0xf4, 0xf1, 0xed, 0xe6,
+ 0xe2, 0xde, 0xdb, 0xd6, 0xd3, 0xcf, 0xca, 0xc6,
+ 0xc2, 0xbe, 0xb9, 0xb0, 0xa7, 0x9e, 0x96, 0x8d,
+ 0x84, 0x7c, 0x74, 0x6b, 0x62, 0x5a, 0x51, 0x49,
+ 0x41, 0x39, 0x31, 0x29, 0x21, 0x19, 0x12, 0x0a,
+ 0x06, 0x05, 0x02, 0x01, 0x00, 0x00, 0xc9, 0xb3,
+ 0x08, 0x0e, 0xf2, 0xe1, 0x59, 0xf4, 0x22, 0xad,
+ 0x40);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x02);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDGCLUT,
+ 0xff, 0xfe, 0xfb, 0xf8, 0xf4, 0xf1, 0xed, 0xe6,
+ 0xe2, 0xde, 0xdb, 0xd6, 0xd3, 0xcf, 0xca, 0xc6,
+ 0xc2, 0xbe, 0xb9, 0xb0, 0xa7, 0x9e, 0x96, 0x8d,
+ 0x84, 0x7c, 0x74, 0x6b, 0x62, 0x5a, 0x51, 0x49,
+ 0x41, 0x39, 0x31, 0x29, 0x21, 0x19, 0x12, 0x0a,
+ 0x06, 0x05, 0x02, 0x01, 0x00, 0x00, 0xc9, 0xb3,
+ 0x08, 0x0e, 0xf2, 0xe1, 0x59, 0xf4, 0x22, 0xad,
+ 0x40);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x01);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDGCLUT,
+ 0xff, 0xfe, 0xfb, 0xf8, 0xf4, 0xf1, 0xed, 0xe6,
+ 0xe2, 0xde, 0xdb, 0xd6, 0xd3, 0xcf, 0xca, 0xc6,
+ 0xc2, 0xbe, 0xb9, 0xb0, 0xa7, 0x9e, 0x96, 0x8d,
+ 0x84, 0x7c, 0x74, 0x6b, 0x62, 0x5a, 0x51, 0x49,
+ 0x41, 0x39, 0x31, 0x29, 0x21, 0x19, 0x12, 0x0a,
+ 0x06, 0x05, 0x02, 0x01, 0x00, 0x00, 0xc9, 0xb3,
+ 0x08, 0x0e, 0xf2, 0xe1, 0x59, 0xf4, 0x22, 0xad,
+ 0x40);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDGCLUT, 0x01);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETTCON,
+ 0x70, 0x00, 0x04, 0xe0, 0x33, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETPANEL, 0x08);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETPOWER2, 0x2b, 0x2b);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP0,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08,
+ 0x08, 0x03, 0x03, 0x22, 0x18, 0x07, 0x07, 0x07,
+ 0x07, 0x32, 0x10, 0x06, 0x00, 0x06, 0x32, 0x10,
+ 0x07, 0x00, 0x07, 0x32, 0x19, 0x31, 0x09, 0x31,
+ 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x09, 0x30, 0x00, 0x00, 0x00, 0x06, 0x0d, 0x00,
+ 0x0f);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x01);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP0,
+ 0x00, 0x00, 0x19, 0x10, 0x00, 0x0a, 0x00, 0x81);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP1,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0xc0, 0xc0, 0x18, 0x18, 0x19, 0x19, 0x18, 0x18,
+ 0x40, 0x40, 0x18, 0x18, 0x18, 0x18, 0x3f, 0x3f,
+ 0x28, 0x28, 0x24, 0x24, 0x02, 0x03, 0x02, 0x03,
+ 0x00, 0x01, 0x00, 0x01, 0x31, 0x31, 0x31, 0x31,
+ 0x30, 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP2,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x40, 0x40, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19,
+ 0x40, 0x40, 0x18, 0x18, 0x18, 0x18, 0x3f, 0x3f,
+ 0x24, 0x24, 0x28, 0x28, 0x01, 0x00, 0x01, 0x00,
+ 0x03, 0x02, 0x03, 0x02, 0x31, 0x31, 0x31, 0x31,
+ 0x30, 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP3,
+ 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xab, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xea, 0xab, 0xaa, 0xaa, 0xaa);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x01);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP3,
+ 0xaa, 0x2e, 0x28, 0x00, 0x00, 0x00, 0xaa, 0x2e,
+ 0x28, 0x00, 0x00, 0x00, 0xaa, 0xee, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xee, 0xaa, 0xaa, 0xaa, 0xaa);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x02);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP3,
+ 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xff,
+ 0xff, 0xff, 0xff, 0xff);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x03);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP3,
+ 0xaa, 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETTP1,
+ 0x0e, 0x0e, 0x1e, 0x65, 0x1c, 0x65, 0x00, 0x50,
+ 0x20, 0x20, 0x00, 0x00, 0x02, 0x02, 0x02, 0x05,
+ 0x14, 0x14, 0x32, 0xb9, 0x23, 0xb9, 0x08);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x01);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETTP1,
+ 0x02, 0x00, 0xa8, 0x01, 0xa8, 0x0d, 0xa4, 0x0e);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x02);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETTP1,
+ 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_UNKNOWN1, 0xc3);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETCLOCK, 0xd1, 0xd6);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_UNKNOWN1, 0x3f);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_UNKNOWN1, 0xc6);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_SETPTBA, 0x37);
+ mipi_dsi_dcs_write_seq(dsi, HX83112A_UNKNOWN1, 0x3f);
+
+ ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
+ if (ret < 0) {
+ dev_err(dev, "Failed to exit sleep mode: %d\n", ret);
+ return ret;
+ }
+ msleep(150);
+
+ ret = mipi_dsi_dcs_set_display_on(dsi);
+ if (ret < 0) {
+ dev_err(dev, "Failed to set display on: %d\n", ret);
+ return ret;
+ }
+ msleep(50);
+
+ return 0;
+}
+
+static int hx83112a_disable(struct drm_panel *panel)
+{
+ struct hx83112a_panel *ctx = to_hx83112a_panel(panel);
+ struct mipi_dsi_device *dsi = ctx->dsi;
+ struct device *dev = &dsi->dev;
+ int ret;
+
+ dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+ ret = mipi_dsi_dcs_set_display_off(dsi);
+ if (ret < 0) {
+ dev_err(dev, "Failed to set display off: %d\n", ret);
+ return ret;
+ }
+ msleep(20);
+
+ ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enter sleep mode: %d\n", ret);
+ return ret;
+ }
+ msleep(120);
+
+ return 0;
+}
+
+static int hx83112a_prepare(struct drm_panel *panel)
+{
+ struct hx83112a_panel *ctx = to_hx83112a_panel(panel);
+ struct device *dev = &ctx->dsi->dev;
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable regulators: %d\n", ret);
+ return ret;
+ }
+
+ hx83112a_reset(ctx);
+
+ ret = hx83112a_on(ctx);
+ if (ret < 0) {
+ dev_err(dev, "Failed to initialize panel: %d\n", ret);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int hx83112a_unprepare(struct drm_panel *panel)
+{
+ struct hx83112a_panel *ctx = to_hx83112a_panel(panel);
+
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+
+ return 0;
+}
+
+static const struct drm_display_mode hx83112a_mode = {
+ .clock = (1080 + 28 + 8 + 8) * (2340 + 27 + 5 + 5) * 60 / 1000,
+ .hdisplay = 1080,
+ .hsync_start = 1080 + 28,
+ .hsync_end = 1080 + 28 + 8,
+ .htotal = 1080 + 28 + 8 + 8,
+ .vdisplay = 2340,
+ .vsync_start = 2340 + 27,
+ .vsync_end = 2340 + 27 + 5,
+ .vtotal = 2340 + 27 + 5 + 5,
+ .width_mm = 67,
+ .height_mm = 145,
+ .type = DRM_MODE_TYPE_DRIVER,
+};
+
+static int hx83112a_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ return drm_connector_helper_get_modes_fixed(connector, &hx83112a_mode);
+}
+
+static const struct drm_panel_funcs hx83112a_panel_funcs = {
+ .prepare = hx83112a_prepare,
+ .unprepare = hx83112a_unprepare,
+ .disable = hx83112a_disable,
+ .get_modes = hx83112a_get_modes,
+};
+
+static int hx83112a_probe(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ struct hx83112a_panel *ctx;
+ int ret;
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->supplies[0].supply = "vdd1";
+ ctx->supplies[1].supply = "vsn";
+ ctx->supplies[2].supply = "vsp";
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
+ ctx->supplies);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to get regulators\n");
+
+ ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(ctx->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
+ "Failed to get reset-gpios\n");
+
+ ctx->dsi = dsi;
+ mipi_dsi_set_drvdata(dsi, ctx);
+
+ dsi->lanes = 4;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+ MIPI_DSI_MODE_VIDEO_HSE |
+ MIPI_DSI_CLOCK_NON_CONTINUOUS;
+
+ drm_panel_init(&ctx->panel, dev, &hx83112a_panel_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+ ctx->panel.prepare_prev_first = true;
+
+ ret = drm_panel_of_backlight(&ctx->panel);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get backlight\n");
+
+ drm_panel_add(&ctx->panel);
+
+ ret = mipi_dsi_attach(dsi);
+ if (ret < 0) {
+ dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
+ drm_panel_remove(&ctx->panel);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void hx83112a_remove(struct mipi_dsi_device *dsi)
+{
+ struct hx83112a_panel *ctx = mipi_dsi_get_drvdata(dsi);
+ int ret;
+
+ ret = mipi_dsi_detach(dsi);
+ if (ret < 0)
+ dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
+
+ drm_panel_remove(&ctx->panel);
+}
+
+static const struct of_device_id hx83112a_of_match[] = {
+ { .compatible = "djn,9a-3r063-1102b" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, hx83112a_of_match);
+
+static struct mipi_dsi_driver hx83112a_driver = {
+ .probe = hx83112a_probe,
+ .remove = hx83112a_remove,
+ .driver = {
+ .name = "panel-himax-hx83112a",
+ .of_match_table = hx83112a_of_match,
+ },
+};
+module_mipi_dsi_driver(hx83112a_driver);
+
+MODULE_DESCRIPTION("DRM driver for hx83112a-equipped DSI panels");
+MODULE_LICENSE("GPL");

--
2.43.2


2024-02-16 10:34:00

by Neil Armstrong

[permalink] [raw]
Subject: Re: [PATCH v3 2/4] drm/panel: Add driver for DJN HX83112A LCD panel

On 16/02/2024 11:10, Luca Weiss wrote:
> Add support for the 2340x1080 LCD panel (DJN 9A-3R063-1102B) bundled
> with a HX83112A driver IC, as found on the Fairphone 4 smartphone.
>
> Signed-off-by: Luca Weiss <[email protected]>
> ---
> drivers/gpu/drm/panel/Kconfig | 10 +
> drivers/gpu/drm/panel/Makefile | 1 +
> drivers/gpu/drm/panel/panel-himax-hx83112a.c | 372 +++++++++++++++++++++++++++
> 3 files changed, 383 insertions(+)
>
> diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
> index 8f3783742208..7e25a4609682 100644
> --- a/drivers/gpu/drm/panel/Kconfig
> +++ b/drivers/gpu/drm/panel/Kconfig
> @@ -162,6 +162,16 @@ config DRM_PANEL_FEIYANG_FY07024DI26A30D
> Say Y if you want to enable support for panels based on the
> Feiyang FY07024DI26A30-D MIPI-DSI interface.
>
> +config DRM_PANEL_HIMAX_HX83112A
> + tristate "Himax HX83112A-based DSI panel"
> + depends on OF
> + depends on DRM_MIPI_DSI
> + depends on BACKLIGHT_CLASS_DEVICE
> + select DRM_KMS_HELPER
> + help
> + Say Y here if you want to enable support for Himax HX83112A-based
> + display panels, such as the one found in the Fairphone 4 smartphone.
> +
> config DRM_PANEL_HIMAX_HX8394
> tristate "HIMAX HX8394 MIPI-DSI LCD panels"
> depends on OF
> diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
> index d94a644d0a6c..f3e40f24d516 100644
> --- a/drivers/gpu/drm/panel/Makefile
> +++ b/drivers/gpu/drm/panel/Makefile
> @@ -14,6 +14,7 @@ obj-$(CONFIG_DRM_PANEL_EBBG_FT8719) += panel-ebbg-ft8719.o
> obj-$(CONFIG_DRM_PANEL_ELIDA_KD35T133) += panel-elida-kd35t133.o
> obj-$(CONFIG_DRM_PANEL_FEIXIN_K101_IM2BA02) += panel-feixin-k101-im2ba02.o
> obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += panel-feiyang-fy07024di26a30d.o
> +obj-$(CONFIG_DRM_PANEL_HIMAX_HX83112A) += panel-himax-hx83112a.o
> obj-$(CONFIG_DRM_PANEL_HIMAX_HX8394) += panel-himax-hx8394.o
> obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o
> obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o
> diff --git a/drivers/gpu/drm/panel/panel-himax-hx83112a.c b/drivers/gpu/drm/panel/panel-himax-hx83112a.c
> new file mode 100644
> index 000000000000..466c27012abf
> --- /dev/null
> +++ b/drivers/gpu/drm/panel/panel-himax-hx83112a.c
> @@ -0,0 +1,372 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree.
> + * Copyright (c) 2024 Luca Weiss <[email protected]>
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_modes.h>
> +#include <drm/drm_panel.h>
> +#include <drm/drm_probe_helper.h>
> +
> +/* Manufacturer specific DSI commands */
> +#define HX83112A_SETPOWER1 0xb1
> +#define HX83112A_SETDISP 0xb2
> +#define HX83112A_SETDRV 0xb4
> +#define HX83112A_SETEXTC 0xb9
> +#define HX83112A_SETBANK 0xbd
> +#define HX83112A_SETPTBA 0xbf
> +#define HX83112A_SETDGCLUT 0xc1
> +#define HX83112A_SETTCON 0xc7
> +#define HX83112A_SETCLOCK 0xcb
> +#define HX83112A_SETPANEL 0xcc
> +#define HX83112A_SETPOWER2 0xd2
> +#define HX83112A_SETGIP0 0xd3
> +#define HX83112A_SETGIP1 0xd5
> +#define HX83112A_SETGIP2 0xd6
> +#define HX83112A_SETGIP3 0xd8
> +#define HX83112A_SETTP1 0xe7
> +#define HX83112A_UNKNOWN1 0xe9
> +
> +struct hx83112a_panel {
> + struct drm_panel panel;
> + struct mipi_dsi_device *dsi;
> + struct regulator_bulk_data supplies[3];
> + struct gpio_desc *reset_gpio;
> +};
> +
> +static inline struct hx83112a_panel *to_hx83112a_panel(struct drm_panel *panel)
> +{
> + return container_of(panel, struct hx83112a_panel, panel);
> +}
> +
> +static void hx83112a_reset(struct hx83112a_panel *ctx)
> +{
> + gpiod_set_value_cansleep(ctx->reset_gpio, 0);
> + msleep(20);
> + gpiod_set_value_cansleep(ctx->reset_gpio, 1);
> + msleep(20);
> + gpiod_set_value_cansleep(ctx->reset_gpio, 0);
> + msleep(50);
> +}
> +
> +static int hx83112a_on(struct hx83112a_panel *ctx)
> +{
> + struct mipi_dsi_device *dsi = ctx->dsi;
> + struct device *dev = &dsi->dev;
> + int ret;
> +
> + dsi->mode_flags |= MIPI_DSI_MODE_LPM;
> +
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETEXTC, 0x83, 0x11, 0x2a);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETPOWER1,
> + 0x08, 0x28, 0x28, 0x83, 0x83, 0x4c, 0x4f, 0x33);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDISP,
> + 0x00, 0x02, 0x00, 0x90, 0x24, 0x00, 0x08, 0x19,
> + 0xea, 0x11, 0x11, 0x00, 0x11, 0xa3);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDRV,
> + 0x58, 0x68, 0x58, 0x68, 0x0f, 0xef, 0x0b, 0xc0,
> + 0x0b, 0xc0, 0x0b, 0xc0, 0x00, 0xff, 0x00, 0xff,
> + 0x00, 0x00, 0x14, 0x15, 0x00, 0x29, 0x11, 0x07,
> + 0x12, 0x00, 0x29);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x02);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDRV,
> + 0x00, 0x12, 0x12, 0x11, 0x88, 0x12, 0x12, 0x00,
> + 0x53);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x00);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x03);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDGCLUT,
> + 0xff, 0xfe, 0xfb, 0xf8, 0xf4, 0xf1, 0xed, 0xe6,
> + 0xe2, 0xde, 0xdb, 0xd6, 0xd3, 0xcf, 0xca, 0xc6,
> + 0xc2, 0xbe, 0xb9, 0xb0, 0xa7, 0x9e, 0x96, 0x8d,
> + 0x84, 0x7c, 0x74, 0x6b, 0x62, 0x5a, 0x51, 0x49,
> + 0x41, 0x39, 0x31, 0x29, 0x21, 0x19, 0x12, 0x0a,
> + 0x06, 0x05, 0x02, 0x01, 0x00, 0x00, 0xc9, 0xb3,
> + 0x08, 0x0e, 0xf2, 0xe1, 0x59, 0xf4, 0x22, 0xad,
> + 0x40);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x02);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDGCLUT,
> + 0xff, 0xfe, 0xfb, 0xf8, 0xf4, 0xf1, 0xed, 0xe6,
> + 0xe2, 0xde, 0xdb, 0xd6, 0xd3, 0xcf, 0xca, 0xc6,
> + 0xc2, 0xbe, 0xb9, 0xb0, 0xa7, 0x9e, 0x96, 0x8d,
> + 0x84, 0x7c, 0x74, 0x6b, 0x62, 0x5a, 0x51, 0x49,
> + 0x41, 0x39, 0x31, 0x29, 0x21, 0x19, 0x12, 0x0a,
> + 0x06, 0x05, 0x02, 0x01, 0x00, 0x00, 0xc9, 0xb3,
> + 0x08, 0x0e, 0xf2, 0xe1, 0x59, 0xf4, 0x22, 0xad,
> + 0x40);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x01);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDGCLUT,
> + 0xff, 0xfe, 0xfb, 0xf8, 0xf4, 0xf1, 0xed, 0xe6,
> + 0xe2, 0xde, 0xdb, 0xd6, 0xd3, 0xcf, 0xca, 0xc6,
> + 0xc2, 0xbe, 0xb9, 0xb0, 0xa7, 0x9e, 0x96, 0x8d,
> + 0x84, 0x7c, 0x74, 0x6b, 0x62, 0x5a, 0x51, 0x49,
> + 0x41, 0x39, 0x31, 0x29, 0x21, 0x19, 0x12, 0x0a,
> + 0x06, 0x05, 0x02, 0x01, 0x00, 0x00, 0xc9, 0xb3,
> + 0x08, 0x0e, 0xf2, 0xe1, 0x59, 0xf4, 0x22, 0xad,
> + 0x40);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x00);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDGCLUT, 0x01);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETTCON,
> + 0x70, 0x00, 0x04, 0xe0, 0x33, 0x00);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETPANEL, 0x08);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETPOWER2, 0x2b, 0x2b);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP0,
> + 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08,
> + 0x08, 0x03, 0x03, 0x22, 0x18, 0x07, 0x07, 0x07,
> + 0x07, 0x32, 0x10, 0x06, 0x00, 0x06, 0x32, 0x10,
> + 0x07, 0x00, 0x07, 0x32, 0x19, 0x31, 0x09, 0x31,
> + 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x08,
> + 0x09, 0x30, 0x00, 0x00, 0x00, 0x06, 0x0d, 0x00,
> + 0x0f);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x01);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP0,
> + 0x00, 0x00, 0x19, 0x10, 0x00, 0x0a, 0x00, 0x81);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x00);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP1,
> + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
> + 0xc0, 0xc0, 0x18, 0x18, 0x19, 0x19, 0x18, 0x18,
> + 0x40, 0x40, 0x18, 0x18, 0x18, 0x18, 0x3f, 0x3f,
> + 0x28, 0x28, 0x24, 0x24, 0x02, 0x03, 0x02, 0x03,
> + 0x00, 0x01, 0x00, 0x01, 0x31, 0x31, 0x31, 0x31,
> + 0x30, 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP2,
> + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
> + 0x40, 0x40, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19,
> + 0x40, 0x40, 0x18, 0x18, 0x18, 0x18, 0x3f, 0x3f,
> + 0x24, 0x24, 0x28, 0x28, 0x01, 0x00, 0x01, 0x00,
> + 0x03, 0x02, 0x03, 0x02, 0x31, 0x31, 0x31, 0x31,
> + 0x30, 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP3,
> + 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
> + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xab, 0xaa,
> + 0xaa, 0xaa, 0xaa, 0xea, 0xab, 0xaa, 0xaa, 0xaa);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x01);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP3,
> + 0xaa, 0x2e, 0x28, 0x00, 0x00, 0x00, 0xaa, 0x2e,
> + 0x28, 0x00, 0x00, 0x00, 0xaa, 0xee, 0xaa, 0xaa,
> + 0xaa, 0xaa, 0xaa, 0xee, 0xaa, 0xaa, 0xaa, 0xaa);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x02);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP3,
> + 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xff,
> + 0xff, 0xff, 0xff, 0xff);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x03);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP3,
> + 0xaa, 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
> + 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0xff,
> + 0xff, 0xff, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x00);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETTP1,
> + 0x0e, 0x0e, 0x1e, 0x65, 0x1c, 0x65, 0x00, 0x50,
> + 0x20, 0x20, 0x00, 0x00, 0x02, 0x02, 0x02, 0x05,
> + 0x14, 0x14, 0x32, 0xb9, 0x23, 0xb9, 0x08);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x01);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETTP1,
> + 0x02, 0x00, 0xa8, 0x01, 0xa8, 0x0d, 0xa4, 0x0e);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x02);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETTP1,
> + 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
> + 0x00, 0x00, 0x00, 0x02, 0x00);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x00);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_UNKNOWN1, 0xc3);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETCLOCK, 0xd1, 0xd6);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_UNKNOWN1, 0x3f);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_UNKNOWN1, 0xc6);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_SETPTBA, 0x37);
> + mipi_dsi_dcs_write_seq(dsi, HX83112A_UNKNOWN1, 0x3f);
> +
> + ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
> + if (ret < 0) {
> + dev_err(dev, "Failed to exit sleep mode: %d\n", ret);
> + return ret;
> + }
> + msleep(150);
> +
> + ret = mipi_dsi_dcs_set_display_on(dsi);
> + if (ret < 0) {
> + dev_err(dev, "Failed to set display on: %d\n", ret);
> + return ret;
> + }
> + msleep(50);
> +
> + return 0;
> +}
> +
> +static int hx83112a_disable(struct drm_panel *panel)
> +{
> + struct hx83112a_panel *ctx = to_hx83112a_panel(panel);
> + struct mipi_dsi_device *dsi = ctx->dsi;
> + struct device *dev = &dsi->dev;
> + int ret;
> +
> + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
> +
> + ret = mipi_dsi_dcs_set_display_off(dsi);
> + if (ret < 0) {
> + dev_err(dev, "Failed to set display off: %d\n", ret);
> + return ret;
> + }
> + msleep(20);
> +
> + ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
> + if (ret < 0) {
> + dev_err(dev, "Failed to enter sleep mode: %d\n", ret);
> + return ret;
> + }
> + msleep(120);
> +
> + return 0;
> +}
> +
> +static int hx83112a_prepare(struct drm_panel *panel)
> +{
> + struct hx83112a_panel *ctx = to_hx83112a_panel(panel);
> + struct device *dev = &ctx->dsi->dev;
> + int ret;
> +
> + ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
> + if (ret < 0) {
> + dev_err(dev, "Failed to enable regulators: %d\n", ret);
> + return ret;
> + }
> +
> + hx83112a_reset(ctx);
> +
> + ret = hx83112a_on(ctx);
> + if (ret < 0) {
> + dev_err(dev, "Failed to initialize panel: %d\n", ret);
> + gpiod_set_value_cansleep(ctx->reset_gpio, 1);
> + regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int hx83112a_unprepare(struct drm_panel *panel)
> +{
> + struct hx83112a_panel *ctx = to_hx83112a_panel(panel);
> +
> + gpiod_set_value_cansleep(ctx->reset_gpio, 1);
> + regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
> +
> + return 0;
> +}
> +
> +static const struct drm_display_mode hx83112a_mode = {
> + .clock = (1080 + 28 + 8 + 8) * (2340 + 27 + 5 + 5) * 60 / 1000,
> + .hdisplay = 1080,
> + .hsync_start = 1080 + 28,
> + .hsync_end = 1080 + 28 + 8,
> + .htotal = 1080 + 28 + 8 + 8,
> + .vdisplay = 2340,
> + .vsync_start = 2340 + 27,
> + .vsync_end = 2340 + 27 + 5,
> + .vtotal = 2340 + 27 + 5 + 5,
> + .width_mm = 67,
> + .height_mm = 145,
> + .type = DRM_MODE_TYPE_DRIVER,
> +};
> +
> +static int hx83112a_get_modes(struct drm_panel *panel,
> + struct drm_connector *connector)
> +{
> + return drm_connector_helper_get_modes_fixed(connector, &hx83112a_mode);
> +}
> +
> +static const struct drm_panel_funcs hx83112a_panel_funcs = {
> + .prepare = hx83112a_prepare,
> + .unprepare = hx83112a_unprepare,
> + .disable = hx83112a_disable,
> + .get_modes = hx83112a_get_modes,
> +};
> +
> +static int hx83112a_probe(struct mipi_dsi_device *dsi)
> +{
> + struct device *dev = &dsi->dev;
> + struct hx83112a_panel *ctx;
> + int ret;
> +
> + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
> + if (!ctx)
> + return -ENOMEM;
> +
> + ctx->supplies[0].supply = "vdd1";
> + ctx->supplies[1].supply = "vsn";
> + ctx->supplies[2].supply = "vsp";
> + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
> + ctx->supplies);
> + if (ret < 0)
> + return dev_err_probe(dev, ret, "Failed to get regulators\n");
> +
> + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
> + if (IS_ERR(ctx->reset_gpio))
> + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
> + "Failed to get reset-gpios\n");
> +
> + ctx->dsi = dsi;
> + mipi_dsi_set_drvdata(dsi, ctx);
> +
> + dsi->lanes = 4;
> + dsi->format = MIPI_DSI_FMT_RGB888;
> + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
> + MIPI_DSI_MODE_VIDEO_HSE |
> + MIPI_DSI_CLOCK_NON_CONTINUOUS;
> +
> + drm_panel_init(&ctx->panel, dev, &hx83112a_panel_funcs,
> + DRM_MODE_CONNECTOR_DSI);
> + ctx->panel.prepare_prev_first = true;
> +
> + ret = drm_panel_of_backlight(&ctx->panel);
> + if (ret)
> + return dev_err_probe(dev, ret, "Failed to get backlight\n");
> +
> + drm_panel_add(&ctx->panel);
> +
> + ret = mipi_dsi_attach(dsi);
> + if (ret < 0) {
> + dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
> + drm_panel_remove(&ctx->panel);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static void hx83112a_remove(struct mipi_dsi_device *dsi)
> +{
> + struct hx83112a_panel *ctx = mipi_dsi_get_drvdata(dsi);
> + int ret;
> +
> + ret = mipi_dsi_detach(dsi);
> + if (ret < 0)
> + dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
> +
> + drm_panel_remove(&ctx->panel);
> +}
> +
> +static const struct of_device_id hx83112a_of_match[] = {
> + { .compatible = "djn,9a-3r063-1102b" },
> + { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, hx83112a_of_match);
> +
> +static struct mipi_dsi_driver hx83112a_driver = {
> + .probe = hx83112a_probe,
> + .remove = hx83112a_remove,
> + .driver = {
> + .name = "panel-himax-hx83112a",
> + .of_match_table = hx83112a_of_match,
> + },
> +};
> +module_mipi_dsi_driver(hx83112a_driver);
> +
> +MODULE_DESCRIPTION("DRM driver for hx83112a-equipped DSI panels");
> +MODULE_LICENSE("GPL");
>

LGTM

Reviewed-by: Neil Armstrong <[email protected]>

2024-02-16 11:14:58

by Neil Armstrong

[permalink] [raw]
Subject: Re: (subset) [PATCH v3 0/4] Add display support for Fairphone 4

Hi,

On Fri, 16 Feb 2024 11:10:47 +0100, Luca Weiss wrote:
> Introduce the bindings and panel driver for the LCD panel with the model
> number 9A-3R063-1102B from DJN which is using the HX83112A driver IC. It
> is used on the Fairphone 4 smartphone.
>
> Then we can add the panel to the device dts and also enable the GPU.
>
>
> [...]

Thanks, Applied to https://anongit.freedesktop.org/git/drm/drm-misc.git (drm-misc-next)

[1/4] dt-bindings: display: panel: Add Himax HX83112A
https://cgit.freedesktop.org/drm/drm-misc/commit/?id=3b59787a5170e12beb636cf1a66e481526f293cc
[2/4] drm/panel: Add driver for DJN HX83112A LCD panel
https://cgit.freedesktop.org/drm/drm-misc/commit/?id=654f26a0f43cfd35a5ebd19e008b6f065f2a1f92

--
Neil


2024-02-16 23:12:36

by Bjorn Andersson

[permalink] [raw]
Subject: Re: (subset) [PATCH v3 0/4] Add display support for Fairphone 4


On Fri, 16 Feb 2024 11:10:47 +0100, Luca Weiss wrote:
> Introduce the bindings and panel driver for the LCD panel with the model
> number 9A-3R063-1102B from DJN which is using the HX83112A driver IC. It
> is used on the Fairphone 4 smartphone.
>
> Then we can add the panel to the device dts and also enable the GPU.
>
>
> [...]

Applied, thanks!

[3/4] arm64: dts: qcom: sm6350: Remove "disabled" state of GMU
commit: 2abe4a310cc742332038aed5f9f4a15e65a0bcc1
[4/4] arm64: dts: qcom: sm7225-fairphone-fp4: Enable display and GPU
commit: 891af1aa1ea42514b9a7f42caaa1fa0c32f8e232

Best regards,
--
Bjorn Andersson <[email protected]>