dri-devel.lists.freedesktop.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] drm/panel: Pixel 3a Panel
@ 2024-02-09  0:16 Richard Acayan
  2024-02-09  0:16 ` [PATCH 1/3] dt-bindings: display: panel-simple-dsi: add s6e3fa7 ams559nk06 compat Richard Acayan
                   ` (4 more replies)
  0 siblings, 5 replies; 12+ messages in thread
From: Richard Acayan @ 2024-02-09  0:16 UTC (permalink / raw)
  To: Neil Armstrong, Jessica Zhang, Sam Ravnborg, David Airlie,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Bjorn Andersson, Konrad Dybcio, Thierry Reding,
	dri-devel, devicetree, linux-arm-msm
  Cc: Richard Acayan

This adds support for the AMS559NK06 panel with the S6E3FA7 display
controller and enables the display subsystem on the Pixel 3a.

Richard Acayan (3):
  dt-bindings: display: panel-simple-dsi: add s6e3fa7 ams559nk06 compat
  drm/panel: add samsung s6e3fa7 panel driver
  arm64: dts: qcom: sdm670-google-sargo: add panel

 .../display/panel/panel-simple-dsi.yaml       |   2 +
 .../boot/dts/qcom/sdm670-google-sargo.dts     |  64 ++++
 drivers/gpu/drm/panel/Kconfig                 |   9 +
 drivers/gpu/drm/panel/Makefile                |   1 +
 drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c | 285 ++++++++++++++++++
 5 files changed, 361 insertions(+)
 create mode 100644 drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c

-- 
2.43.0


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/3] dt-bindings: display: panel-simple-dsi: add s6e3fa7 ams559nk06 compat
  2024-02-09  0:16 [PATCH 0/3] drm/panel: Pixel 3a Panel Richard Acayan
@ 2024-02-09  0:16 ` Richard Acayan
  2024-02-09  7:37   ` Krzysztof Kozlowski
  2024-02-09  0:16 ` [PATCH 2/3] drm/panel: add samsung s6e3fa7 panel driver Richard Acayan
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 12+ messages in thread
From: Richard Acayan @ 2024-02-09  0:16 UTC (permalink / raw)
  To: Neil Armstrong, Jessica Zhang, Sam Ravnborg, David Airlie,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Bjorn Andersson, Konrad Dybcio, Thierry Reding,
	dri-devel, devicetree, linux-arm-msm
  Cc: Richard Acayan

The Samsung S6E3FA7 display controller and AMS559NK06 panel are used for
the display in Pixel 3a devices. Add the compatible for it.

Signed-off-by: Richard Acayan <mailingradian@gmail.com>
---
 .../devicetree/bindings/display/panel/panel-simple-dsi.yaml     | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml
index f9160d7bac3c..d3abd7f4ebcd 100644
--- a/Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml
+++ b/Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml
@@ -50,6 +50,8 @@ properties:
       - panasonic,vvx10f004b00
         # Panasonic 10" WUXGA TFT LCD panel
       - panasonic,vvx10f034n00
+        # Samsung s6e3fa7 1080x2220 based AMS559NK06 AMOLED panel
+      - samsung,s6e3fa7-ams559nk06
         # Samsung s6e3fc2x01 1080x2340 AMOLED panel
       - samsung,s6e3fc2x01
         # Samsung sofef00 1080x2280 AMOLED panel
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/3] drm/panel: add samsung s6e3fa7 panel driver
  2024-02-09  0:16 [PATCH 0/3] drm/panel: Pixel 3a Panel Richard Acayan
  2024-02-09  0:16 ` [PATCH 1/3] dt-bindings: display: panel-simple-dsi: add s6e3fa7 ams559nk06 compat Richard Acayan
@ 2024-02-09  0:16 ` Richard Acayan
  2024-02-09  1:34   ` Jessica Zhang
  2024-03-04 21:41   ` Caleb Connolly
  2024-02-09  0:16 ` [PATCH 3/3] arm64: dts: qcom: sdm670-google-sargo: add panel Richard Acayan
                   ` (2 subsequent siblings)
  4 siblings, 2 replies; 12+ messages in thread
From: Richard Acayan @ 2024-02-09  0:16 UTC (permalink / raw)
  To: Neil Armstrong, Jessica Zhang, Sam Ravnborg, David Airlie,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Bjorn Andersson, Konrad Dybcio, Thierry Reding,
	dri-devel, devicetree, linux-arm-msm
  Cc: Richard Acayan

The S6E3FA7 display controller is enabled in every Pixel 3a (non-XL)
variant. Add the driver for it, generated by
linux-mdss-dsi-panel-driver-generator.

There are other panels connected to the same S6E3FA7 display controller,
such as the AMS604NL01 panel, which are incompatible with this driver.
Name the device tree compatible after the panel model according to
iFixit.

Link: https://github.com/msm8916-mainline/linux-mdss-dsi-panel-driver-generator
Link: https://android.googlesource.com/kernel/msm/+/7fda1cd7b64710dafac5f34899611c6d35eb4cd2/arch/arm64/boot/dts/google/dsi-panel-s6e3fa7-1080p-cmd.dtsi
Link: https://github.com/msm8953-mainline/linux/blob/v6.6.12-r0/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c
Link: https://www.ifixit.com/Guide/Image/meta/muyjtLQTHu6MDkhK
Signed-off-by: Richard Acayan <mailingradian@gmail.com>
---
 drivers/gpu/drm/panel/Kconfig                 |   9 +
 drivers/gpu/drm/panel/Makefile                |   1 +
 drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c | 285 ++++++++++++++++++
 3 files changed, 295 insertions(+)
 create mode 100644 drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c

diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 8f3783742208..a693b03f680e 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -577,6 +577,15 @@ config DRM_PANEL_SAMSUNG_DB7430
 	  DB7430 DPI display controller used in such devices as the
 	  LMS397KF04 480x800 DPI panel.
 
+config DRM_PANEL_SAMSUNG_S6E3FA7
+	tristate "Samsung S6E3FA7 panel driver"
+	depends on OF
+	depends on DRM_MIPI_DSI
+	depends on BACKLIGHT_CLASS_DEVICE
+	help
+	  Say Y here if you want to enable support for the Samsung S6E3FA7
+	  1920x2220 panel.
+
 config DRM_PANEL_SAMSUNG_S6D16D0
 	tristate "Samsung S6D16D0 DSI video mode panel"
 	depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index d94a644d0a6c..560b62129f68 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -59,6 +59,7 @@ obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D16D0) += panel-samsung-s6d16d0.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D27A1) += panel-samsung-s6d27a1.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D7AA0) += panel-samsung-s6d7aa0.o
+obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3FA7) += panel-samsung-s6e3fa7.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0) += panel-samsung-s6e63m0.o
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c b/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c
new file mode 100644
index 000000000000..10bc8fb5f1f9
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c
@@ -0,0 +1,285 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for the Samsung S6E3FA7 panel.
+ *
+ * Copyright (c) 2022-2024, The Linux Foundation. All rights reserved.
+ * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree:
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#include <video/mipi_display.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+
+struct s6e3fa7_panel {
+	struct drm_panel panel;
+	struct mipi_dsi_device *dsi;
+	struct gpio_desc *reset_gpio;
+};
+
+static inline struct s6e3fa7_panel *to_s6e3fa7_panel(struct drm_panel *panel)
+{
+	return container_of(panel, struct s6e3fa7_panel, panel);
+}
+
+static void s6e3fa7_panel_reset(struct s6e3fa7_panel *ctx)
+{
+	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+	usleep_range(1000, 2000);
+	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+	usleep_range(10000, 11000);
+}
+
+static int s6e3fa7_panel_on(struct s6e3fa7_panel *ctx)
+{
+	struct mipi_dsi_device *dsi = ctx->dsi;
+	struct device *dev = &dsi->dev;
+	int ret;
+
+	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(120);
+
+	ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
+	if (ret < 0) {
+		dev_err(dev, "Failed to set tear on: %d\n", ret);
+		return ret;
+	}
+
+	mipi_dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a);
+	mipi_dsi_dcs_write_seq(dsi, 0xf4,
+			       0xbb, 0x23, 0x19, 0x3a, 0x9f, 0x0f, 0x09, 0xc0,
+			       0x00, 0xb4, 0x37, 0x70, 0x79, 0x69);
+	mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5);
+	mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20);
+
+	ret = mipi_dsi_dcs_set_display_on(dsi);
+	if (ret < 0) {
+		dev_err(dev, "Failed to set display on: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int s6e3fa7_panel_prepare(struct drm_panel *panel)
+{
+	struct s6e3fa7_panel *ctx = to_s6e3fa7_panel(panel);
+	struct device *dev = &ctx->dsi->dev;
+	int ret;
+
+	s6e3fa7_panel_reset(ctx);
+
+	ret = s6e3fa7_panel_on(ctx);
+	if (ret < 0) {
+		dev_err(dev, "Failed to initialize panel: %d\n", ret);
+		gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int s6e3fa7_panel_unprepare(struct drm_panel *panel)
+{
+	struct s6e3fa7_panel *ctx = to_s6e3fa7_panel(panel);
+
+	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+
+	return 0;
+}
+
+static int s6e3fa7_panel_disable(struct drm_panel *panel)
+{
+	struct s6e3fa7_panel *ctx = to_s6e3fa7_panel(panel);
+	struct mipi_dsi_device *dsi = ctx->dsi;
+	struct device *dev = &dsi->dev;
+	int ret;
+
+	ret = mipi_dsi_dcs_set_display_off(dsi);
+	if (ret < 0) {
+		dev_err(dev, "Failed to set display off: %d\n", ret);
+		return ret;
+	}
+
+	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 const struct drm_display_mode s6e3fa7_panel_mode = {
+	.clock = (1080 + 32 + 32 + 78) * (2220 + 32 + 4 + 78) * 60 / 1000,
+	.hdisplay = 1080,
+	.hsync_start = 1080 + 32,
+	.hsync_end = 1080 + 32 + 32,
+	.htotal = 1080 + 32 + 32 + 78,
+	.vdisplay = 2220,
+	.vsync_start = 2220 + 32,
+	.vsync_end = 2220 + 32 + 4,
+	.vtotal = 2220 + 32 + 4 + 78,
+	.width_mm = 62,
+	.height_mm = 127,
+};
+
+static int s6e3fa7_panel_get_modes(struct drm_panel *panel,
+				 struct drm_connector *connector)
+{
+	struct drm_display_mode *mode;
+
+	mode = drm_mode_duplicate(connector->dev, &s6e3fa7_panel_mode);
+	if (!mode)
+		return -ENOMEM;
+
+	drm_mode_set_name(mode);
+
+	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+	connector->display_info.width_mm = mode->width_mm;
+	connector->display_info.height_mm = mode->height_mm;
+	drm_mode_probed_add(connector, mode);
+
+	return 1;
+}
+
+static const struct drm_panel_funcs s6e3fa7_panel_funcs = {
+	.prepare = s6e3fa7_panel_prepare,
+	.unprepare = s6e3fa7_panel_unprepare,
+	.disable = s6e3fa7_panel_disable,
+	.get_modes = s6e3fa7_panel_get_modes,
+};
+
+static int s6e3fa7_panel_bl_update_status(struct backlight_device *bl)
+{
+	struct mipi_dsi_device *dsi = bl_get_data(bl);
+	u16 brightness = backlight_get_brightness(bl);
+	int ret;
+
+	ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int s6e3fa7_panel_bl_get_brightness(struct backlight_device *bl)
+{
+	struct mipi_dsi_device *dsi = bl_get_data(bl);
+	u16 brightness;
+	int ret;
+
+	ret = mipi_dsi_dcs_get_display_brightness_large(dsi, &brightness);
+	if (ret < 0)
+		return ret;
+
+	return brightness;
+}
+
+static const struct backlight_ops s6e3fa7_panel_bl_ops = {
+	.update_status = s6e3fa7_panel_bl_update_status,
+	.get_brightness = s6e3fa7_panel_bl_get_brightness,
+};
+
+static struct backlight_device *
+s6e3fa7_panel_create_backlight(struct mipi_dsi_device *dsi)
+{
+	struct device *dev = &dsi->dev;
+	const struct backlight_properties props = {
+		.type = BACKLIGHT_RAW,
+		.brightness = 1023,
+		.max_brightness = 1023,
+	};
+
+	return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
+					      &s6e3fa7_panel_bl_ops, &props);
+}
+
+static int s6e3fa7_panel_probe(struct mipi_dsi_device *dsi)
+{
+	struct device *dev = &dsi->dev;
+	struct s6e3fa7_panel *ctx;
+	int ret;
+
+	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	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_BURST |
+			  MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM;
+
+	drm_panel_init(&ctx->panel, dev, &s6e3fa7_panel_funcs,
+		       DRM_MODE_CONNECTOR_DSI);
+	ctx->panel.prepare_prev_first = true;
+
+	ctx->panel.backlight = s6e3fa7_panel_create_backlight(dsi);
+	if (IS_ERR(ctx->panel.backlight))
+		return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight),
+				     "Failed to create backlight\n");
+
+	drm_panel_add(&ctx->panel);
+
+	ret = mipi_dsi_attach(dsi);
+	if (ret < 0) {
+		dev_err(dev, "Failed to attach to DSI host: %d\n", ret);
+		drm_panel_remove(&ctx->panel);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void s6e3fa7_panel_remove(struct mipi_dsi_device *dsi)
+{
+	struct s6e3fa7_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 s6e3fa7_panel_of_match[] = {
+	{ .compatible = "samsung,s6e3fa7-ams559nk06" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, s6e3fa7_panel_of_match);
+
+static struct mipi_dsi_driver s6e3fa7_panel_driver = {
+	.probe = s6e3fa7_panel_probe,
+	.remove = s6e3fa7_panel_remove,
+	.driver = {
+		.name = "panel-samsung-s6e3fa7",
+		.of_match_table = s6e3fa7_panel_of_match,
+	},
+};
+module_mipi_dsi_driver(s6e3fa7_panel_driver);
+
+MODULE_AUTHOR("Richard Acayan <mailingradian@gmail.com>");
+MODULE_DESCRIPTION("DRM driver for Samsung S6E3FA7 command mode DSI panel");
+MODULE_LICENSE("GPL");
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/3] arm64: dts: qcom: sdm670-google-sargo: add panel
  2024-02-09  0:16 [PATCH 0/3] drm/panel: Pixel 3a Panel Richard Acayan
  2024-02-09  0:16 ` [PATCH 1/3] dt-bindings: display: panel-simple-dsi: add s6e3fa7 ams559nk06 compat Richard Acayan
  2024-02-09  0:16 ` [PATCH 2/3] drm/panel: add samsung s6e3fa7 panel driver Richard Acayan
@ 2024-02-09  0:16 ` Richard Acayan
  2024-02-29  8:53 ` (subset) [PATCH 0/3] drm/panel: Pixel 3a Panel Neil Armstrong
  2024-03-19  2:48 ` Bjorn Andersson
  4 siblings, 0 replies; 12+ messages in thread
From: Richard Acayan @ 2024-02-09  0:16 UTC (permalink / raw)
  To: Neil Armstrong, Jessica Zhang, Sam Ravnborg, David Airlie,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Bjorn Andersson, Konrad Dybcio, Thierry Reding,
	dri-devel, devicetree, linux-arm-msm
  Cc: Richard Acayan

Add the panel used in the Google Pixel 3a.

Signed-off-by: Richard Acayan <mailingradian@gmail.com>
---
 .../boot/dts/qcom/sdm670-google-sargo.dts     | 64 +++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/sdm670-google-sargo.dts b/arch/arm64/boot/dts/qcom/sdm670-google-sargo.dts
index 32a7bd59e1ec..176b0119fe6d 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-google-sargo.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-google-sargo.dts
@@ -441,6 +441,47 @@ rmi4-f12@12 {
 	};
 };
 
+&mdss {
+	status = "okay";
+};
+
+&mdss_dsi0 {
+	vdda-supply = <&vreg_l1a_1p225>;
+	status = "okay";
+
+	panel@0 {
+		compatible = "samsung,s6e3fa7-ams559nk06";
+		reg = <0>;
+
+		reset-gpios = <&tlmm 75 GPIO_ACTIVE_LOW>;
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&panel_default>;
+
+		power-supply = <&vreg_l6b_3p3>;
+
+		port {
+			panel_in: endpoint {
+				remote-endpoint = <&mdss_dsi0_out>;
+			};
+		};
+	};
+};
+
+&mdss_dsi0_out {
+	remote-endpoint = <&panel_in>;
+	data-lanes = <0 1 2 3>;
+};
+
+&mdss_dsi0_phy {
+	vdds-supply = <&vreg_l1b_0p925>;
+	status = "okay";
+};
+
+&mdss_mdp {
+	status = "okay";
+};
+
 &pm660l_gpios {
 	vol_up_pin: vol-up-state {
 		pins = "gpio7";
@@ -481,6 +522,29 @@ &sdhc_1 {
 &tlmm {
 	gpio-reserved-ranges = <0 4>, <81 4>;
 
+	panel_default: panel-default-state {
+		te-pins {
+			pins = "gpio10";
+			function = "mdp_vsync";
+			drive-strength = <2>;
+			bias-pull-down;
+		};
+
+		reset-pins {
+			pins = "gpio75";
+			function = "gpio";
+			drive-strength = <8>;
+			bias-disable;
+		};
+
+		mode-pins {
+			pins = "gpio76";
+			function = "gpio";
+			drive-strength = <8>;
+			bias-disable;
+		};
+	};
+
 	touchscreen_default: ts-default-state {
 		ts-reset-pins {
 			pins = "gpio99";
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/3] drm/panel: add samsung s6e3fa7 panel driver
  2024-02-09  0:16 ` [PATCH 2/3] drm/panel: add samsung s6e3fa7 panel driver Richard Acayan
@ 2024-02-09  1:34   ` Jessica Zhang
  2024-02-09 23:17     ` Richard Acayan
  2024-03-04 21:41   ` Caleb Connolly
  1 sibling, 1 reply; 12+ messages in thread
From: Jessica Zhang @ 2024-02-09  1:34 UTC (permalink / raw)
  To: Richard Acayan, Neil Armstrong, Sam Ravnborg, David Airlie,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Bjorn Andersson, Konrad Dybcio, Thierry Reding,
	dri-devel, devicetree, linux-arm-msm



On 2/8/2024 4:16 PM, Richard Acayan wrote:
> The S6E3FA7 display controller is enabled in every Pixel 3a (non-XL)
> variant. Add the driver for it, generated by
> linux-mdss-dsi-panel-driver-generator.
> 
> There are other panels connected to the same S6E3FA7 display controller,
> such as the AMS604NL01 panel, which are incompatible with this driver.
> Name the device tree compatible after the panel model according to
> iFixit.
> 
> Link: https://github.com/msm8916-mainline/linux-mdss-dsi-panel-driver-generator
> Link: https://android.googlesource.com/kernel/msm/+/7fda1cd7b64710dafac5f34899611c6d35eb4cd2/arch/arm64/boot/dts/google/dsi-panel-s6e3fa7-1080p-cmd.dtsi
> Link: https://github.com/msm8953-mainline/linux/blob/v6.6.12-r0/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c
> Link: https://www.ifixit.com/Guide/Image/meta/muyjtLQTHu6MDkhK
> Signed-off-by: Richard Acayan <mailingradian@gmail.com>
> ---
>   drivers/gpu/drm/panel/Kconfig                 |   9 +
>   drivers/gpu/drm/panel/Makefile                |   1 +
>   drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c | 285 ++++++++++++++++++
>   3 files changed, 295 insertions(+)
>   create mode 100644 drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c
> 
> diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
> index 8f3783742208..a693b03f680e 100644
> --- a/drivers/gpu/drm/panel/Kconfig
> +++ b/drivers/gpu/drm/panel/Kconfig
> @@ -577,6 +577,15 @@ config DRM_PANEL_SAMSUNG_DB7430
>   	  DB7430 DPI display controller used in such devices as the
>   	  LMS397KF04 480x800 DPI panel.
>   
> +config DRM_PANEL_SAMSUNG_S6E3FA7
> +	tristate "Samsung S6E3FA7 panel driver"
> +	depends on OF
> +	depends on DRM_MIPI_DSI
> +	depends on BACKLIGHT_CLASS_DEVICE
> +	help
> +	  Say Y here if you want to enable support for the Samsung S6E3FA7
> +	  1920x2220 panel.
> +
>   config DRM_PANEL_SAMSUNG_S6D16D0
>   	tristate "Samsung S6D16D0 DSI video mode panel"
>   	depends on OF
> diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
> index d94a644d0a6c..560b62129f68 100644
> --- a/drivers/gpu/drm/panel/Makefile
> +++ b/drivers/gpu/drm/panel/Makefile
> @@ -59,6 +59,7 @@ obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o
>   obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D16D0) += panel-samsung-s6d16d0.o
>   obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D27A1) += panel-samsung-s6d27a1.o
>   obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D7AA0) += panel-samsung-s6d7aa0.o
> +obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3FA7) += panel-samsung-s6e3fa7.o
>   obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o
>   obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o
>   obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0) += panel-samsung-s6e63m0.o
> diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c b/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c
> new file mode 100644
> index 000000000000..10bc8fb5f1f9
> --- /dev/null
> +++ b/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c
> @@ -0,0 +1,285 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Driver for the Samsung S6E3FA7 panel.
> + *
> + * Copyright (c) 2022-2024, The Linux Foundation. All rights reserved.


Hi Richard,

Not really sure about the copyright dates -- since this is a completely 
new file to this tree, wouldn't the year be just 2024?

The rest LGTM.

Thanks,

Jessica Zhang

> + * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree:
> + * Copyright (c) 2013, The Linux Foundation. All rights reserved.
> + */ > +
> +#include <linux/backlight.h>
> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +
> +#include <video/mipi_display.h>
> +
> +#include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_modes.h>
> +#include <drm/drm_panel.h>
> +
> +struct s6e3fa7_panel {
> +	struct drm_panel panel;
> +	struct mipi_dsi_device *dsi;
> +	struct gpio_desc *reset_gpio;
> +};
> +
> +static inline struct s6e3fa7_panel *to_s6e3fa7_panel(struct drm_panel *panel)
> +{
> +	return container_of(panel, struct s6e3fa7_panel, panel);
> +}
> +
> +static void s6e3fa7_panel_reset(struct s6e3fa7_panel *ctx)
> +{
> +	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
> +	usleep_range(1000, 2000);
> +	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
> +	usleep_range(10000, 11000);
> +}
> +
> +static int s6e3fa7_panel_on(struct s6e3fa7_panel *ctx)
> +{
> +	struct mipi_dsi_device *dsi = ctx->dsi;
> +	struct device *dev = &dsi->dev;
> +	int ret;
> +
> +	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(120);
> +
> +	ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
> +	if (ret < 0) {
> +		dev_err(dev, "Failed to set tear on: %d\n", ret);
> +		return ret;
> +	}
> +
> +	mipi_dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a);
> +	mipi_dsi_dcs_write_seq(dsi, 0xf4,
> +			       0xbb, 0x23, 0x19, 0x3a, 0x9f, 0x0f, 0x09, 0xc0,
> +			       0x00, 0xb4, 0x37, 0x70, 0x79, 0x69);
> +	mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5);
> +	mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20);
> +
> +	ret = mipi_dsi_dcs_set_display_on(dsi);
> +	if (ret < 0) {
> +		dev_err(dev, "Failed to set display on: %d\n", ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int s6e3fa7_panel_prepare(struct drm_panel *panel)
> +{
> +	struct s6e3fa7_panel *ctx = to_s6e3fa7_panel(panel);
> +	struct device *dev = &ctx->dsi->dev;
> +	int ret;
> +
> +	s6e3fa7_panel_reset(ctx);
> +
> +	ret = s6e3fa7_panel_on(ctx);
> +	if (ret < 0) {
> +		dev_err(dev, "Failed to initialize panel: %d\n", ret);
> +		gpiod_set_value_cansleep(ctx->reset_gpio, 1);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int s6e3fa7_panel_unprepare(struct drm_panel *panel)
> +{
> +	struct s6e3fa7_panel *ctx = to_s6e3fa7_panel(panel);
> +
> +	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
> +
> +	return 0;
> +}
> +
> +static int s6e3fa7_panel_disable(struct drm_panel *panel)
> +{
> +	struct s6e3fa7_panel *ctx = to_s6e3fa7_panel(panel);
> +	struct mipi_dsi_device *dsi = ctx->dsi;
> +	struct device *dev = &dsi->dev;
> +	int ret;
> +
> +	ret = mipi_dsi_dcs_set_display_off(dsi);
> +	if (ret < 0) {
> +		dev_err(dev, "Failed to set display off: %d\n", ret);
> +		return ret;
> +	}
> +
> +	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 const struct drm_display_mode s6e3fa7_panel_mode = {
> +	.clock = (1080 + 32 + 32 + 78) * (2220 + 32 + 4 + 78) * 60 / 1000,
> +	.hdisplay = 1080,
> +	.hsync_start = 1080 + 32,
> +	.hsync_end = 1080 + 32 + 32,
> +	.htotal = 1080 + 32 + 32 + 78,
> +	.vdisplay = 2220,
> +	.vsync_start = 2220 + 32,
> +	.vsync_end = 2220 + 32 + 4,
> +	.vtotal = 2220 + 32 + 4 + 78,
> +	.width_mm = 62,
> +	.height_mm = 127,
> +};
> +
> +static int s6e3fa7_panel_get_modes(struct drm_panel *panel,
> +				 struct drm_connector *connector)
> +{
> +	struct drm_display_mode *mode;
> +
> +	mode = drm_mode_duplicate(connector->dev, &s6e3fa7_panel_mode);
> +	if (!mode)
> +		return -ENOMEM;
> +
> +	drm_mode_set_name(mode);
> +
> +	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
> +	connector->display_info.width_mm = mode->width_mm;
> +	connector->display_info.height_mm = mode->height_mm;
> +	drm_mode_probed_add(connector, mode);
> +
> +	return 1;
> +}
> +
> +static const struct drm_panel_funcs s6e3fa7_panel_funcs = {
> +	.prepare = s6e3fa7_panel_prepare,
> +	.unprepare = s6e3fa7_panel_unprepare,
> +	.disable = s6e3fa7_panel_disable,
> +	.get_modes = s6e3fa7_panel_get_modes,
> +};
> +
> +static int s6e3fa7_panel_bl_update_status(struct backlight_device *bl)
> +{
> +	struct mipi_dsi_device *dsi = bl_get_data(bl);
> +	u16 brightness = backlight_get_brightness(bl);
> +	int ret;
> +
> +	ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness);
> +	if (ret < 0)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int s6e3fa7_panel_bl_get_brightness(struct backlight_device *bl)
> +{
> +	struct mipi_dsi_device *dsi = bl_get_data(bl);
> +	u16 brightness;
> +	int ret;
> +
> +	ret = mipi_dsi_dcs_get_display_brightness_large(dsi, &brightness);
> +	if (ret < 0)
> +		return ret;
> +
> +	return brightness;
> +}
> +
> +static const struct backlight_ops s6e3fa7_panel_bl_ops = {
> +	.update_status = s6e3fa7_panel_bl_update_status,
> +	.get_brightness = s6e3fa7_panel_bl_get_brightness,
> +};
> +
> +static struct backlight_device *
> +s6e3fa7_panel_create_backlight(struct mipi_dsi_device *dsi)
> +{
> +	struct device *dev = &dsi->dev;
> +	const struct backlight_properties props = {
> +		.type = BACKLIGHT_RAW,
> +		.brightness = 1023,
> +		.max_brightness = 1023,
> +	};
> +
> +	return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
> +					      &s6e3fa7_panel_bl_ops, &props);
> +}
> +
> +static int s6e3fa7_panel_probe(struct mipi_dsi_device *dsi)
> +{
> +	struct device *dev = &dsi->dev;
> +	struct s6e3fa7_panel *ctx;
> +	int ret;
> +
> +	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
> +	if (!ctx)
> +		return -ENOMEM;
> +
> +	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_BURST |
> +			  MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM;
> +
> +	drm_panel_init(&ctx->panel, dev, &s6e3fa7_panel_funcs,
> +		       DRM_MODE_CONNECTOR_DSI);
> +	ctx->panel.prepare_prev_first = true;
> +
> +	ctx->panel.backlight = s6e3fa7_panel_create_backlight(dsi);
> +	if (IS_ERR(ctx->panel.backlight))
> +		return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight),
> +				     "Failed to create backlight\n");
> +
> +	drm_panel_add(&ctx->panel);
> +
> +	ret = mipi_dsi_attach(dsi);
> +	if (ret < 0) {
> +		dev_err(dev, "Failed to attach to DSI host: %d\n", ret);
> +		drm_panel_remove(&ctx->panel);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static void s6e3fa7_panel_remove(struct mipi_dsi_device *dsi)
> +{
> +	struct s6e3fa7_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 s6e3fa7_panel_of_match[] = {
> +	{ .compatible = "samsung,s6e3fa7-ams559nk06" },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, s6e3fa7_panel_of_match);
> +
> +static struct mipi_dsi_driver s6e3fa7_panel_driver = {
> +	.probe = s6e3fa7_panel_probe,
> +	.remove = s6e3fa7_panel_remove,
> +	.driver = {
> +		.name = "panel-samsung-s6e3fa7",
> +		.of_match_table = s6e3fa7_panel_of_match,
> +	},
> +};
> +module_mipi_dsi_driver(s6e3fa7_panel_driver);
> +
> +MODULE_AUTHOR("Richard Acayan <mailingradian@gmail.com>");
> +MODULE_DESCRIPTION("DRM driver for Samsung S6E3FA7 command mode DSI panel");
> +MODULE_LICENSE("GPL");
> -- 
> 2.43.0
> 
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/3] dt-bindings: display: panel-simple-dsi: add s6e3fa7 ams559nk06 compat
  2024-02-09  0:16 ` [PATCH 1/3] dt-bindings: display: panel-simple-dsi: add s6e3fa7 ams559nk06 compat Richard Acayan
@ 2024-02-09  7:37   ` Krzysztof Kozlowski
  0 siblings, 0 replies; 12+ messages in thread
From: Krzysztof Kozlowski @ 2024-02-09  7:37 UTC (permalink / raw)
  To: Richard Acayan, Neil Armstrong, Jessica Zhang, Sam Ravnborg,
	David Airlie, Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Bjorn Andersson, Konrad Dybcio, Thierry Reding,
	dri-devel, devicetree, linux-arm-msm

On 09/02/2024 01:16, Richard Acayan wrote:
> The Samsung S6E3FA7 display controller and AMS559NK06 panel are used for
> the display in Pixel 3a devices. Add the compatible for it.
> 
> Signed-off-by: Richard Acayan <mailingradian@gmail.com>
> ---

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/3] drm/panel: add samsung s6e3fa7 panel driver
  2024-02-09  1:34   ` Jessica Zhang
@ 2024-02-09 23:17     ` Richard Acayan
  2024-02-28 22:04       ` Jessica Zhang
  0 siblings, 1 reply; 12+ messages in thread
From: Richard Acayan @ 2024-02-09 23:17 UTC (permalink / raw)
  To: Jessica Zhang
  Cc: Neil Armstrong, Sam Ravnborg, David Airlie, Daniel Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
	Konrad Dybcio, Thierry Reding, dri-devel, devicetree,
	linux-arm-msm

On Thu, Feb 08, 2024 at 05:34:57PM -0800, Jessica Zhang wrote:
> On 2/8/2024 4:16 PM, Richard Acayan wrote:
>> The S6E3FA7 display controller is enabled in every Pixel 3a (non-XL)
>> variant. Add the driver for it, generated by
>> linux-mdss-dsi-panel-driver-generator.
>> 
>> There are other panels connected to the same S6E3FA7 display controller,
>> such as the AMS604NL01 panel, which are incompatible with this driver.
>> Name the device tree compatible after the panel model according to
>> iFixit.
>> 
>> Link: https://github.com/msm8916-mainline/linux-mdss-dsi-panel-driver-generator
>> Link: https://android.googlesource.com/kernel/msm/+/7fda1cd7b64710dafac5f34899611c6d35eb4cd2/arch/arm64/boot/dts/google/dsi-panel-s6e3fa7-1080p-cmd.dtsi
>> Link: https://github.com/msm8953-mainline/linux/blob/v6.6.12-r0/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c
>> Link: https://www.ifixit.com/Guide/Image/meta/muyjtLQTHu6MDkhK
>> Signed-off-by: Richard Acayan <mailingradian@gmail.com>
>> ---
>>   drivers/gpu/drm/panel/Kconfig                 |   9 +
>>   drivers/gpu/drm/panel/Makefile                |   1 +
>>   drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c | 285 ++++++++++++++++++
>>   3 files changed, 295 insertions(+)
>>   create mode 100644 drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c
>> 
>> diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
>> index 8f3783742208..a693b03f680e 100644
>> --- a/drivers/gpu/drm/panel/Kconfig
>> +++ b/drivers/gpu/drm/panel/Kconfig
>> @@ -577,6 +577,15 @@ config DRM_PANEL_SAMSUNG_DB7430
>>   	  DB7430 DPI display controller used in such devices as the
>>   	  LMS397KF04 480x800 DPI panel.
>> +config DRM_PANEL_SAMSUNG_S6E3FA7
>> +	tristate "Samsung S6E3FA7 panel driver"
>> +	depends on OF
>> +	depends on DRM_MIPI_DSI
>> +	depends on BACKLIGHT_CLASS_DEVICE
>> +	help
>> +	  Say Y here if you want to enable support for the Samsung S6E3FA7
>> +	  1920x2220 panel.
>> +
>>   config DRM_PANEL_SAMSUNG_S6D16D0
>>   	tristate "Samsung S6D16D0 DSI video mode panel"
>>   	depends on OF
>> diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
>> index d94a644d0a6c..560b62129f68 100644
>> --- a/drivers/gpu/drm/panel/Makefile
>> +++ b/drivers/gpu/drm/panel/Makefile
>> @@ -59,6 +59,7 @@ obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o
>>   obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D16D0) += panel-samsung-s6d16d0.o
>>   obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D27A1) += panel-samsung-s6d27a1.o
>>   obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D7AA0) += panel-samsung-s6d7aa0.o
>> +obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3FA7) += panel-samsung-s6e3fa7.o
>>   obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o
>>   obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o
>>   obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0) += panel-samsung-s6e63m0.o
>> diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c b/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c
>> new file mode 100644
>> index 000000000000..10bc8fb5f1f9
>> --- /dev/null
>> +++ b/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c
>> @@ -0,0 +1,285 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Driver for the Samsung S6E3FA7 panel.
>> + *
>> + * Copyright (c) 2022-2024, The Linux Foundation. All rights reserved.
>
>
> Hi Richard,
>
> Not really sure about the copyright dates -- since this is a completely new
> file to this tree, wouldn't the year be just 2024?

That would be more concise, but the original driver was generated and
added to a kernel fork [1] in 2022 and amendments have been made since then.

[1] https://gitlab.com/sdm670-mainline/linux/-/blob/sdm670-v6.2.6/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c?ref_type=tags

>
> The rest LGTM.
>
> Thanks,
>
> Jessica Zhang
>
>> + * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree:
>> + * Copyright (c) 2013, The Linux Foundation. All rights reserved.
>> + */ > +
>> +#include <linux/backlight.h>
>> +#include <linux/delay.h>
>> +#include <linux/gpio/consumer.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +
>> +#include <video/mipi_display.h>
>> +
>> +#include <drm/drm_mipi_dsi.h>
>> +#include <drm/drm_modes.h>
>> +#include <drm/drm_panel.h>
>> +
>> +struct s6e3fa7_panel {
>> +	struct drm_panel panel;
>> +	struct mipi_dsi_device *dsi;
>> +	struct gpio_desc *reset_gpio;
>> +};
>> +
>> +static inline struct s6e3fa7_panel *to_s6e3fa7_panel(struct drm_panel *panel)
>> +{
>> +	return container_of(panel, struct s6e3fa7_panel, panel);
>> +}
>> +
>> +static void s6e3fa7_panel_reset(struct s6e3fa7_panel *ctx)
>> +{
>> +	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
>> +	usleep_range(1000, 2000);
>> +	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
>> +	usleep_range(10000, 11000);
>> +}
>> +
>> +static int s6e3fa7_panel_on(struct s6e3fa7_panel *ctx)
>> +{
>> +	struct mipi_dsi_device *dsi = ctx->dsi;
>> +	struct device *dev = &dsi->dev;
>> +	int ret;
>> +
>> +	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(120);
>> +
>> +	ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
>> +	if (ret < 0) {
>> +		dev_err(dev, "Failed to set tear on: %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	mipi_dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a);
>> +	mipi_dsi_dcs_write_seq(dsi, 0xf4,
>> +			       0xbb, 0x23, 0x19, 0x3a, 0x9f, 0x0f, 0x09, 0xc0,
>> +			       0x00, 0xb4, 0x37, 0x70, 0x79, 0x69);
>> +	mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5);
>> +	mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20);
>> +
>> +	ret = mipi_dsi_dcs_set_display_on(dsi);
>> +	if (ret < 0) {
>> +		dev_err(dev, "Failed to set display on: %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int s6e3fa7_panel_prepare(struct drm_panel *panel)
>> +{
>> +	struct s6e3fa7_panel *ctx = to_s6e3fa7_panel(panel);
>> +	struct device *dev = &ctx->dsi->dev;
>> +	int ret;
>> +
>> +	s6e3fa7_panel_reset(ctx);
>> +
>> +	ret = s6e3fa7_panel_on(ctx);
>> +	if (ret < 0) {
>> +		dev_err(dev, "Failed to initialize panel: %d\n", ret);
>> +		gpiod_set_value_cansleep(ctx->reset_gpio, 1);
>> +		return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int s6e3fa7_panel_unprepare(struct drm_panel *panel)
>> +{
>> +	struct s6e3fa7_panel *ctx = to_s6e3fa7_panel(panel);
>> +
>> +	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
>> +
>> +	return 0;
>> +}
>> +
>> +static int s6e3fa7_panel_disable(struct drm_panel *panel)
>> +{
>> +	struct s6e3fa7_panel *ctx = to_s6e3fa7_panel(panel);
>> +	struct mipi_dsi_device *dsi = ctx->dsi;
>> +	struct device *dev = &dsi->dev;
>> +	int ret;
>> +
>> +	ret = mipi_dsi_dcs_set_display_off(dsi);
>> +	if (ret < 0) {
>> +		dev_err(dev, "Failed to set display off: %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	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 const struct drm_display_mode s6e3fa7_panel_mode = {
>> +	.clock = (1080 + 32 + 32 + 78) * (2220 + 32 + 4 + 78) * 60 / 1000,
>> +	.hdisplay = 1080,
>> +	.hsync_start = 1080 + 32,
>> +	.hsync_end = 1080 + 32 + 32,
>> +	.htotal = 1080 + 32 + 32 + 78,
>> +	.vdisplay = 2220,
>> +	.vsync_start = 2220 + 32,
>> +	.vsync_end = 2220 + 32 + 4,
>> +	.vtotal = 2220 + 32 + 4 + 78,
>> +	.width_mm = 62,
>> +	.height_mm = 127,
>> +};
>> +
>> +static int s6e3fa7_panel_get_modes(struct drm_panel *panel,
>> +				 struct drm_connector *connector)
>> +{
>> +	struct drm_display_mode *mode;
>> +
>> +	mode = drm_mode_duplicate(connector->dev, &s6e3fa7_panel_mode);
>> +	if (!mode)
>> +		return -ENOMEM;
>> +
>> +	drm_mode_set_name(mode);
>> +
>> +	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
>> +	connector->display_info.width_mm = mode->width_mm;
>> +	connector->display_info.height_mm = mode->height_mm;
>> +	drm_mode_probed_add(connector, mode);
>> +
>> +	return 1;
>> +}
>> +
>> +static const struct drm_panel_funcs s6e3fa7_panel_funcs = {
>> +	.prepare = s6e3fa7_panel_prepare,
>> +	.unprepare = s6e3fa7_panel_unprepare,
>> +	.disable = s6e3fa7_panel_disable,
>> +	.get_modes = s6e3fa7_panel_get_modes,
>> +};
>> +
>> +static int s6e3fa7_panel_bl_update_status(struct backlight_device *bl)
>> +{
>> +	struct mipi_dsi_device *dsi = bl_get_data(bl);
>> +	u16 brightness = backlight_get_brightness(bl);
>> +	int ret;
>> +
>> +	ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	return 0;
>> +}
>> +
>> +static int s6e3fa7_panel_bl_get_brightness(struct backlight_device *bl)
>> +{
>> +	struct mipi_dsi_device *dsi = bl_get_data(bl);
>> +	u16 brightness;
>> +	int ret;
>> +
>> +	ret = mipi_dsi_dcs_get_display_brightness_large(dsi, &brightness);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	return brightness;
>> +}
>> +
>> +static const struct backlight_ops s6e3fa7_panel_bl_ops = {
>> +	.update_status = s6e3fa7_panel_bl_update_status,
>> +	.get_brightness = s6e3fa7_panel_bl_get_brightness,
>> +};
>> +
>> +static struct backlight_device *
>> +s6e3fa7_panel_create_backlight(struct mipi_dsi_device *dsi)
>> +{
>> +	struct device *dev = &dsi->dev;
>> +	const struct backlight_properties props = {
>> +		.type = BACKLIGHT_RAW,
>> +		.brightness = 1023,
>> +		.max_brightness = 1023,
>> +	};
>> +
>> +	return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
>> +					      &s6e3fa7_panel_bl_ops, &props);
>> +}
>> +
>> +static int s6e3fa7_panel_probe(struct mipi_dsi_device *dsi)
>> +{
>> +	struct device *dev = &dsi->dev;
>> +	struct s6e3fa7_panel *ctx;
>> +	int ret;
>> +
>> +	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
>> +	if (!ctx)
>> +		return -ENOMEM;
>> +
>> +	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_BURST |
>> +			  MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM;
>> +
>> +	drm_panel_init(&ctx->panel, dev, &s6e3fa7_panel_funcs,
>> +		       DRM_MODE_CONNECTOR_DSI);
>> +	ctx->panel.prepare_prev_first = true;
>> +
>> +	ctx->panel.backlight = s6e3fa7_panel_create_backlight(dsi);
>> +	if (IS_ERR(ctx->panel.backlight))
>> +		return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight),
>> +				     "Failed to create backlight\n");
>> +
>> +	drm_panel_add(&ctx->panel);
>> +
>> +	ret = mipi_dsi_attach(dsi);
>> +	if (ret < 0) {
>> +		dev_err(dev, "Failed to attach to DSI host: %d\n", ret);
>> +		drm_panel_remove(&ctx->panel);
>> +		return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static void s6e3fa7_panel_remove(struct mipi_dsi_device *dsi)
>> +{
>> +	struct s6e3fa7_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 s6e3fa7_panel_of_match[] = {
>> +	{ .compatible = "samsung,s6e3fa7-ams559nk06" },
>> +	{ /* sentinel */ }
>> +};
>> +MODULE_DEVICE_TABLE(of, s6e3fa7_panel_of_match);
>> +
>> +static struct mipi_dsi_driver s6e3fa7_panel_driver = {
>> +	.probe = s6e3fa7_panel_probe,
>> +	.remove = s6e3fa7_panel_remove,
>> +	.driver = {
>> +		.name = "panel-samsung-s6e3fa7",
>> +		.of_match_table = s6e3fa7_panel_of_match,
>> +	},
>> +};
>> +module_mipi_dsi_driver(s6e3fa7_panel_driver);
>> +
>> +MODULE_AUTHOR("Richard Acayan <mailingradian@gmail.com>");
>> +MODULE_DESCRIPTION("DRM driver for Samsung S6E3FA7 command mode DSI panel");
>> +MODULE_LICENSE("GPL");
>> -- 
>> 2.43.0
>> 
>> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/3] drm/panel: add samsung s6e3fa7 panel driver
  2024-02-09 23:17     ` Richard Acayan
@ 2024-02-28 22:04       ` Jessica Zhang
  0 siblings, 0 replies; 12+ messages in thread
From: Jessica Zhang @ 2024-02-28 22:04 UTC (permalink / raw)
  To: Richard Acayan
  Cc: Neil Armstrong, Sam Ravnborg, David Airlie, Daniel Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
	Konrad Dybcio, Thierry Reding, dri-devel, devicetree,
	linux-arm-msm



On 2/9/2024 3:17 PM, Richard Acayan wrote:
> On Thu, Feb 08, 2024 at 05:34:57PM -0800, Jessica Zhang wrote:
>> On 2/8/2024 4:16 PM, Richard Acayan wrote:
>>> The S6E3FA7 display controller is enabled in every Pixel 3a (non-XL)
>>> variant. Add the driver for it, generated by
>>> linux-mdss-dsi-panel-driver-generator.
>>>
>>> There are other panels connected to the same S6E3FA7 display controller,
>>> such as the AMS604NL01 panel, which are incompatible with this driver.
>>> Name the device tree compatible after the panel model according to
>>> iFixit.
>>>
>>> Link: https://github.com/msm8916-mainline/linux-mdss-dsi-panel-driver-generator
>>> Link: https://android.googlesource.com/kernel/msm/+/7fda1cd7b64710dafac5f34899611c6d35eb4cd2/arch/arm64/boot/dts/google/dsi-panel-s6e3fa7-1080p-cmd.dtsi
>>> Link: https://github.com/msm8953-mainline/linux/blob/v6.6.12-r0/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c
>>> Link: https://www.ifixit.com/Guide/Image/meta/muyjtLQTHu6MDkhK
>>> Signed-off-by: Richard Acayan <mailingradian@gmail.com>
>>> ---
>>>    drivers/gpu/drm/panel/Kconfig                 |   9 +
>>>    drivers/gpu/drm/panel/Makefile                |   1 +
>>>    drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c | 285 ++++++++++++++++++
>>>    3 files changed, 295 insertions(+)
>>>    create mode 100644 drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c
>>>
>>> diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
>>> index 8f3783742208..a693b03f680e 100644
>>> --- a/drivers/gpu/drm/panel/Kconfig
>>> +++ b/drivers/gpu/drm/panel/Kconfig
>>> @@ -577,6 +577,15 @@ config DRM_PANEL_SAMSUNG_DB7430
>>>    	  DB7430 DPI display controller used in such devices as the
>>>    	  LMS397KF04 480x800 DPI panel.
>>> +config DRM_PANEL_SAMSUNG_S6E3FA7
>>> +	tristate "Samsung S6E3FA7 panel driver"
>>> +	depends on OF
>>> +	depends on DRM_MIPI_DSI
>>> +	depends on BACKLIGHT_CLASS_DEVICE
>>> +	help
>>> +	  Say Y here if you want to enable support for the Samsung S6E3FA7
>>> +	  1920x2220 panel.
>>> +
>>>    config DRM_PANEL_SAMSUNG_S6D16D0
>>>    	tristate "Samsung S6D16D0 DSI video mode panel"
>>>    	depends on OF
>>> diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
>>> index d94a644d0a6c..560b62129f68 100644
>>> --- a/drivers/gpu/drm/panel/Makefile
>>> +++ b/drivers/gpu/drm/panel/Makefile
>>> @@ -59,6 +59,7 @@ obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o
>>>    obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D16D0) += panel-samsung-s6d16d0.o
>>>    obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D27A1) += panel-samsung-s6d27a1.o
>>>    obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D7AA0) += panel-samsung-s6d7aa0.o
>>> +obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3FA7) += panel-samsung-s6e3fa7.o
>>>    obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o
>>>    obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o
>>>    obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0) += panel-samsung-s6e63m0.o
>>> diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c b/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c
>>> new file mode 100644
>>> index 000000000000..10bc8fb5f1f9
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c
>>> @@ -0,0 +1,285 @@
>>> +// SPDX-License-Identifier: GPL-2.0-only
>>> +/*
>>> + * Driver for the Samsung S6E3FA7 panel.
>>> + *
>>> + * Copyright (c) 2022-2024, The Linux Foundation. All rights reserved.
>>
>>
>> Hi Richard,
>>
>> Not really sure about the copyright dates -- since this is a completely new
>> file to this tree, wouldn't the year be just 2024?
> 
> That would be more concise, but the original driver was generated and
> added to a kernel fork [1] in 2022 and amendments have been made since then.

Ah, got it. Sounds good.

In that case

Reviewed-by: Jessica Zhang <quic_jesszhan@quicinc.com>

Thanks,

Jessica Zhang

> 
> [1] https://gitlab.com/sdm670-mainline/linux/-/blob/sdm670-v6.2.6/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c?ref_type=tags
> 
>>
>> The rest LGTM.
>>
>> Thanks,
>>
>> Jessica Zhang
>>
>>> + * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree:
>>> + * Copyright (c) 2013, The Linux Foundation. All rights reserved.
>>> + */ > +
>>> +#include <linux/backlight.h>
>>> +#include <linux/delay.h>
>>> +#include <linux/gpio/consumer.h>
>>> +#include <linux/module.h>
>>> +#include <linux/of.h>
>>> +
>>> +#include <video/mipi_display.h>
>>> +
>>> +#include <drm/drm_mipi_dsi.h>
>>> +#include <drm/drm_modes.h>
>>> +#include <drm/drm_panel.h>
>>> +
>>> +struct s6e3fa7_panel {
>>> +	struct drm_panel panel;
>>> +	struct mipi_dsi_device *dsi;
>>> +	struct gpio_desc *reset_gpio;
>>> +};
>>> +
>>> +static inline struct s6e3fa7_panel *to_s6e3fa7_panel(struct drm_panel *panel)
>>> +{
>>> +	return container_of(panel, struct s6e3fa7_panel, panel);
>>> +}
>>> +
>>> +static void s6e3fa7_panel_reset(struct s6e3fa7_panel *ctx)
>>> +{
>>> +	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
>>> +	usleep_range(1000, 2000);
>>> +	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
>>> +	usleep_range(10000, 11000);
>>> +}
>>> +
>>> +static int s6e3fa7_panel_on(struct s6e3fa7_panel *ctx)
>>> +{
>>> +	struct mipi_dsi_device *dsi = ctx->dsi;
>>> +	struct device *dev = &dsi->dev;
>>> +	int ret;
>>> +
>>> +	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(120);
>>> +
>>> +	ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
>>> +	if (ret < 0) {
>>> +		dev_err(dev, "Failed to set tear on: %d\n", ret);
>>> +		return ret;
>>> +	}
>>> +
>>> +	mipi_dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a);
>>> +	mipi_dsi_dcs_write_seq(dsi, 0xf4,
>>> +			       0xbb, 0x23, 0x19, 0x3a, 0x9f, 0x0f, 0x09, 0xc0,
>>> +			       0x00, 0xb4, 0x37, 0x70, 0x79, 0x69);
>>> +	mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5);
>>> +	mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20);
>>> +
>>> +	ret = mipi_dsi_dcs_set_display_on(dsi);
>>> +	if (ret < 0) {
>>> +		dev_err(dev, "Failed to set display on: %d\n", ret);
>>> +		return ret;
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int s6e3fa7_panel_prepare(struct drm_panel *panel)
>>> +{
>>> +	struct s6e3fa7_panel *ctx = to_s6e3fa7_panel(panel);
>>> +	struct device *dev = &ctx->dsi->dev;
>>> +	int ret;
>>> +
>>> +	s6e3fa7_panel_reset(ctx);
>>> +
>>> +	ret = s6e3fa7_panel_on(ctx);
>>> +	if (ret < 0) {
>>> +		dev_err(dev, "Failed to initialize panel: %d\n", ret);
>>> +		gpiod_set_value_cansleep(ctx->reset_gpio, 1);
>>> +		return ret;
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int s6e3fa7_panel_unprepare(struct drm_panel *panel)
>>> +{
>>> +	struct s6e3fa7_panel *ctx = to_s6e3fa7_panel(panel);
>>> +
>>> +	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int s6e3fa7_panel_disable(struct drm_panel *panel)
>>> +{
>>> +	struct s6e3fa7_panel *ctx = to_s6e3fa7_panel(panel);
>>> +	struct mipi_dsi_device *dsi = ctx->dsi;
>>> +	struct device *dev = &dsi->dev;
>>> +	int ret;
>>> +
>>> +	ret = mipi_dsi_dcs_set_display_off(dsi);
>>> +	if (ret < 0) {
>>> +		dev_err(dev, "Failed to set display off: %d\n", ret);
>>> +		return ret;
>>> +	}
>>> +
>>> +	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 const struct drm_display_mode s6e3fa7_panel_mode = {
>>> +	.clock = (1080 + 32 + 32 + 78) * (2220 + 32 + 4 + 78) * 60 / 1000,
>>> +	.hdisplay = 1080,
>>> +	.hsync_start = 1080 + 32,
>>> +	.hsync_end = 1080 + 32 + 32,
>>> +	.htotal = 1080 + 32 + 32 + 78,
>>> +	.vdisplay = 2220,
>>> +	.vsync_start = 2220 + 32,
>>> +	.vsync_end = 2220 + 32 + 4,
>>> +	.vtotal = 2220 + 32 + 4 + 78,
>>> +	.width_mm = 62,
>>> +	.height_mm = 127,
>>> +};
>>> +
>>> +static int s6e3fa7_panel_get_modes(struct drm_panel *panel,
>>> +				 struct drm_connector *connector)
>>> +{
>>> +	struct drm_display_mode *mode;
>>> +
>>> +	mode = drm_mode_duplicate(connector->dev, &s6e3fa7_panel_mode);
>>> +	if (!mode)
>>> +		return -ENOMEM;
>>> +
>>> +	drm_mode_set_name(mode);
>>> +
>>> +	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
>>> +	connector->display_info.width_mm = mode->width_mm;
>>> +	connector->display_info.height_mm = mode->height_mm;
>>> +	drm_mode_probed_add(connector, mode);
>>> +
>>> +	return 1;
>>> +}
>>> +
>>> +static const struct drm_panel_funcs s6e3fa7_panel_funcs = {
>>> +	.prepare = s6e3fa7_panel_prepare,
>>> +	.unprepare = s6e3fa7_panel_unprepare,
>>> +	.disable = s6e3fa7_panel_disable,
>>> +	.get_modes = s6e3fa7_panel_get_modes,
>>> +};
>>> +
>>> +static int s6e3fa7_panel_bl_update_status(struct backlight_device *bl)
>>> +{
>>> +	struct mipi_dsi_device *dsi = bl_get_data(bl);
>>> +	u16 brightness = backlight_get_brightness(bl);
>>> +	int ret;
>>> +
>>> +	ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness);
>>> +	if (ret < 0)
>>> +		return ret;
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int s6e3fa7_panel_bl_get_brightness(struct backlight_device *bl)
>>> +{
>>> +	struct mipi_dsi_device *dsi = bl_get_data(bl);
>>> +	u16 brightness;
>>> +	int ret;
>>> +
>>> +	ret = mipi_dsi_dcs_get_display_brightness_large(dsi, &brightness);
>>> +	if (ret < 0)
>>> +		return ret;
>>> +
>>> +	return brightness;
>>> +}
>>> +
>>> +static const struct backlight_ops s6e3fa7_panel_bl_ops = {
>>> +	.update_status = s6e3fa7_panel_bl_update_status,
>>> +	.get_brightness = s6e3fa7_panel_bl_get_brightness,
>>> +};
>>> +
>>> +static struct backlight_device *
>>> +s6e3fa7_panel_create_backlight(struct mipi_dsi_device *dsi)
>>> +{
>>> +	struct device *dev = &dsi->dev;
>>> +	const struct backlight_properties props = {
>>> +		.type = BACKLIGHT_RAW,
>>> +		.brightness = 1023,
>>> +		.max_brightness = 1023,
>>> +	};
>>> +
>>> +	return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
>>> +					      &s6e3fa7_panel_bl_ops, &props);
>>> +}
>>> +
>>> +static int s6e3fa7_panel_probe(struct mipi_dsi_device *dsi)
>>> +{
>>> +	struct device *dev = &dsi->dev;
>>> +	struct s6e3fa7_panel *ctx;
>>> +	int ret;
>>> +
>>> +	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
>>> +	if (!ctx)
>>> +		return -ENOMEM;
>>> +
>>> +	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_BURST |
>>> +			  MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM;
>>> +
>>> +	drm_panel_init(&ctx->panel, dev, &s6e3fa7_panel_funcs,
>>> +		       DRM_MODE_CONNECTOR_DSI);
>>> +	ctx->panel.prepare_prev_first = true;
>>> +
>>> +	ctx->panel.backlight = s6e3fa7_panel_create_backlight(dsi);
>>> +	if (IS_ERR(ctx->panel.backlight))
>>> +		return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight),
>>> +				     "Failed to create backlight\n");
>>> +
>>> +	drm_panel_add(&ctx->panel);
>>> +
>>> +	ret = mipi_dsi_attach(dsi);
>>> +	if (ret < 0) {
>>> +		dev_err(dev, "Failed to attach to DSI host: %d\n", ret);
>>> +		drm_panel_remove(&ctx->panel);
>>> +		return ret;
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static void s6e3fa7_panel_remove(struct mipi_dsi_device *dsi)
>>> +{
>>> +	struct s6e3fa7_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 s6e3fa7_panel_of_match[] = {
>>> +	{ .compatible = "samsung,s6e3fa7-ams559nk06" },
>>> +	{ /* sentinel */ }
>>> +};
>>> +MODULE_DEVICE_TABLE(of, s6e3fa7_panel_of_match);
>>> +
>>> +static struct mipi_dsi_driver s6e3fa7_panel_driver = {
>>> +	.probe = s6e3fa7_panel_probe,
>>> +	.remove = s6e3fa7_panel_remove,
>>> +	.driver = {
>>> +		.name = "panel-samsung-s6e3fa7",
>>> +		.of_match_table = s6e3fa7_panel_of_match,
>>> +	},
>>> +};
>>> +module_mipi_dsi_driver(s6e3fa7_panel_driver);
>>> +
>>> +MODULE_AUTHOR("Richard Acayan <mailingradian@gmail.com>");
>>> +MODULE_DESCRIPTION("DRM driver for Samsung S6E3FA7 command mode DSI panel");
>>> +MODULE_LICENSE("GPL");
>>> -- 
>>> 2.43.0
>>>
>>>
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: (subset) [PATCH 0/3] drm/panel: Pixel 3a Panel
  2024-02-09  0:16 [PATCH 0/3] drm/panel: Pixel 3a Panel Richard Acayan
                   ` (2 preceding siblings ...)
  2024-02-09  0:16 ` [PATCH 3/3] arm64: dts: qcom: sdm670-google-sargo: add panel Richard Acayan
@ 2024-02-29  8:53 ` Neil Armstrong
  2024-03-19  2:48 ` Bjorn Andersson
  4 siblings, 0 replies; 12+ messages in thread
From: Neil Armstrong @ 2024-02-29  8:53 UTC (permalink / raw)
  To: Jessica Zhang, Sam Ravnborg, David Airlie, Daniel Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
	Konrad Dybcio, Thierry Reding, dri-devel, devicetree,
	linux-arm-msm, Richard Acayan

Hi,

On Thu, 08 Feb 2024 19:16:41 -0500, Richard Acayan wrote:
> This adds support for the AMS559NK06 panel with the S6E3FA7 display
> controller and enables the display subsystem on the Pixel 3a.
> 
> Richard Acayan (3):
>   dt-bindings: display: panel-simple-dsi: add s6e3fa7 ams559nk06 compat
>   drm/panel: add samsung s6e3fa7 panel driver
>   arm64: dts: qcom: sdm670-google-sargo: add panel
> 
> [...]

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

[1/3] dt-bindings: display: panel-simple-dsi: add s6e3fa7 ams559nk06 compat
      https://cgit.freedesktop.org/drm/drm-misc/commit/?id=2689b33b88641a3b9a8cc411a0c8094cbed7e871
[2/3] drm/panel: add samsung s6e3fa7 panel driver
      https://cgit.freedesktop.org/drm/drm-misc/commit/?id=bf0390e2c95bf630b22dddc7cde5f83762b658e5

-- 
Neil


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/3] drm/panel: add samsung s6e3fa7 panel driver
  2024-02-09  0:16 ` [PATCH 2/3] drm/panel: add samsung s6e3fa7 panel driver Richard Acayan
  2024-02-09  1:34   ` Jessica Zhang
@ 2024-03-04 21:41   ` Caleb Connolly
  2024-03-04 21:43     ` Caleb Connolly
  1 sibling, 1 reply; 12+ messages in thread
From: Caleb Connolly @ 2024-03-04 21:41 UTC (permalink / raw)
  To: Richard Acayan, Neil Armstrong, Jessica Zhang, Sam Ravnborg,
	David Airlie, Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Bjorn Andersson, Konrad Dybcio, Thierry Reding,
	dri-devel, devicetree, linux-arm-msm



On 09/02/2024 00:16, Richard Acayan wrote:
> The S6E3FA7 display controller is enabled in every Pixel 3a (non-XL)
> variant. Add the driver for it, generated by
> linux-mdss-dsi-panel-driver-generator.
> 
> There are other panels connected to the same S6E3FA7 display controller,
> such as the AMS604NL01 panel, which are incompatible with this driver.
> Name the device tree compatible after the panel model according to
> iFixit.
> 
> Link: https://github.com/msm8916-mainline/linux-mdss-dsi-panel-driver-generator
> Link: https://android.googlesource.com/kernel/msm/+/7fda1cd7b64710dafac5f34899611c6d35eb4cd2/arch/arm64/boot/dts/google/dsi-panel-s6e3fa7-1080p-cmd.dtsi
> Link: https://github.com/msm8953-mainline/linux/blob/v6.6.12-r0/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c
> Link: https://www.ifixit.com/Guide/Image/meta/muyjtLQTHu6MDkhK
> Signed-off-by: Richard Acayan <mailingradian@gmail.com>
> ---
>  drivers/gpu/drm/panel/Kconfig                 |   9 +
>  drivers/gpu/drm/panel/Makefile                |   1 +
>  drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c | 285 ++++++++++++++++++
>  3 files changed, 295 insertions(+)
>  create mode 100644 drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c
> 

> diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c b/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c
> new file mode 100644
> index 000000000000..10bc8fb5f1f9
> --- /dev/null
> +++ b/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c
> @@ -0,0 +1,285 @@

[snip]
> +
> +static int s6e3fa7_panel_probe(struct mipi_dsi_device *dsi)
> +{
> +	struct device *dev = &dsi->dev;
> +	struct s6e3fa7_panel *ctx;
> +	int ret;
> +
> +	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
> +	if (!ctx)
> +		return -ENOMEM;
> +
> +	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_BURST |
This flag is only used for video mode panels, you can drop it.

With that,

Reviewed-by: Caleb Connolly <caleb.connolly@linaro.org>
> +			  MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM;
> +
> +	drm_panel_init(&ctx->panel, dev, &s6e3fa7_panel_funcs,
> +		       DRM_MODE_CONNECTOR_DSI);
> +	ctx->panel.prepare_prev_first = true;
> +
> +	ctx->panel.backlight = s6e3fa7_panel_create_backlight(dsi);
> +	if (IS_ERR(ctx->panel.backlight))
> +		return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight),
> +				     "Failed to create backlight\n");
> +
> +	drm_panel_add(&ctx->panel);
> +
> +	ret = mipi_dsi_attach(dsi);
> +	if (ret < 0) {
> +		dev_err(dev, "Failed to attach to DSI host: %d\n", ret);
> +		drm_panel_remove(&ctx->panel);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static void s6e3fa7_panel_remove(struct mipi_dsi_device *dsi)
> +{
> +	struct s6e3fa7_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 s6e3fa7_panel_of_match[] = {
> +	{ .compatible = "samsung,s6e3fa7-ams559nk06" },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, s6e3fa7_panel_of_match);
> +
> +static struct mipi_dsi_driver s6e3fa7_panel_driver = {
> +	.probe = s6e3fa7_panel_probe,
> +	.remove = s6e3fa7_panel_remove,
> +	.driver = {
> +		.name = "panel-samsung-s6e3fa7",
> +		.of_match_table = s6e3fa7_panel_of_match,
> +	},
> +};
> +module_mipi_dsi_driver(s6e3fa7_panel_driver);
> +
> +MODULE_AUTHOR("Richard Acayan <mailingradian@gmail.com>");
> +MODULE_DESCRIPTION("DRM driver for Samsung S6E3FA7 command mode DSI panel");
> +MODULE_LICENSE("GPL");

-- 
// Caleb (they/them)

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/3] drm/panel: add samsung s6e3fa7 panel driver
  2024-03-04 21:41   ` Caleb Connolly
@ 2024-03-04 21:43     ` Caleb Connolly
  0 siblings, 0 replies; 12+ messages in thread
From: Caleb Connolly @ 2024-03-04 21:43 UTC (permalink / raw)
  To: Richard Acayan, Neil Armstrong, Jessica Zhang, Sam Ravnborg,
	David Airlie, Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Bjorn Andersson, Konrad Dybcio, Thierry Reding,
	dri-devel, devicetree, linux-arm-msm



On 04/03/2024 21:41, Caleb Connolly wrote:
> 
> 
> On 09/02/2024 00:16, Richard Acayan wrote:
>> The S6E3FA7 display controller is enabled in every Pixel 3a (non-XL)
>> variant. Add the driver for it, generated by
>> linux-mdss-dsi-panel-driver-generator.
>>
>> There are other panels connected to the same S6E3FA7 display controller,
>> such as the AMS604NL01 panel, which are incompatible with this driver.
>> Name the device tree compatible after the panel model according to
>> iFixit.
>>
>> Link: https://github.com/msm8916-mainline/linux-mdss-dsi-panel-driver-generator
>> Link: https://android.googlesource.com/kernel/msm/+/7fda1cd7b64710dafac5f34899611c6d35eb4cd2/arch/arm64/boot/dts/google/dsi-panel-s6e3fa7-1080p-cmd.dtsi
>> Link: https://github.com/msm8953-mainline/linux/blob/v6.6.12-r0/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c
>> Link: https://www.ifixit.com/Guide/Image/meta/muyjtLQTHu6MDkhK
>> Signed-off-by: Richard Acayan <mailingradian@gmail.com>
>> ---
>>  drivers/gpu/drm/panel/Kconfig                 |   9 +
>>  drivers/gpu/drm/panel/Makefile                |   1 +
>>  drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c | 285 ++++++++++++++++++
>>  3 files changed, 295 insertions(+)
>>  create mode 100644 drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c
>>
> 
>> diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c b/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c
>> new file mode 100644
>> index 000000000000..10bc8fb5f1f9
>> --- /dev/null
>> +++ b/drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c
>> @@ -0,0 +1,285 @@
> 
> [snip]
>> +
>> +static int s6e3fa7_panel_probe(struct mipi_dsi_device *dsi)
>> +{
>> +	struct device *dev = &dsi->dev;
>> +	struct s6e3fa7_panel *ctx;
>> +	int ret;
>> +
>> +	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
>> +	if (!ctx)
>> +		return -ENOMEM;
>> +
>> +	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_BURST |
> This flag is only used for video mode panels, you can drop it.

Nevermind, I should really check the dates before hitting reply :/
> 
> With that,
> 
> Reviewed-by: Caleb Connolly <caleb.connolly@linaro.org>
>> +			  MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM;
>> +
>> +	drm_panel_init(&ctx->panel, dev, &s6e3fa7_panel_funcs,
>> +		       DRM_MODE_CONNECTOR_DSI);
>> +	ctx->panel.prepare_prev_first = true;
>> +
>> +	ctx->panel.backlight = s6e3fa7_panel_create_backlight(dsi);
>> +	if (IS_ERR(ctx->panel.backlight))
>> +		return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight),
>> +				     "Failed to create backlight\n");
>> +
>> +	drm_panel_add(&ctx->panel);
>> +
>> +	ret = mipi_dsi_attach(dsi);
>> +	if (ret < 0) {
>> +		dev_err(dev, "Failed to attach to DSI host: %d\n", ret);
>> +		drm_panel_remove(&ctx->panel);
>> +		return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static void s6e3fa7_panel_remove(struct mipi_dsi_device *dsi)
>> +{
>> +	struct s6e3fa7_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 s6e3fa7_panel_of_match[] = {
>> +	{ .compatible = "samsung,s6e3fa7-ams559nk06" },
>> +	{ /* sentinel */ }
>> +};
>> +MODULE_DEVICE_TABLE(of, s6e3fa7_panel_of_match);
>> +
>> +static struct mipi_dsi_driver s6e3fa7_panel_driver = {
>> +	.probe = s6e3fa7_panel_probe,
>> +	.remove = s6e3fa7_panel_remove,
>> +	.driver = {
>> +		.name = "panel-samsung-s6e3fa7",
>> +		.of_match_table = s6e3fa7_panel_of_match,
>> +	},
>> +};
>> +module_mipi_dsi_driver(s6e3fa7_panel_driver);
>> +
>> +MODULE_AUTHOR("Richard Acayan <mailingradian@gmail.com>");
>> +MODULE_DESCRIPTION("DRM driver for Samsung S6E3FA7 command mode DSI panel");
>> +MODULE_LICENSE("GPL");
> 

-- 
// Caleb (they/them)

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: (subset) [PATCH 0/3] drm/panel: Pixel 3a Panel
  2024-02-09  0:16 [PATCH 0/3] drm/panel: Pixel 3a Panel Richard Acayan
                   ` (3 preceding siblings ...)
  2024-02-29  8:53 ` (subset) [PATCH 0/3] drm/panel: Pixel 3a Panel Neil Armstrong
@ 2024-03-19  2:48 ` Bjorn Andersson
  4 siblings, 0 replies; 12+ messages in thread
From: Bjorn Andersson @ 2024-03-19  2:48 UTC (permalink / raw)
  To: Neil Armstrong, Jessica Zhang, Sam Ravnborg, David Airlie,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Konrad Dybcio, Thierry Reding, dri-devel,
	devicetree, linux-arm-msm, Richard Acayan


On Thu, 08 Feb 2024 19:16:41 -0500, Richard Acayan wrote:
> This adds support for the AMS559NK06 panel with the S6E3FA7 display
> controller and enables the display subsystem on the Pixel 3a.
> 
> Richard Acayan (3):
>   dt-bindings: display: panel-simple-dsi: add s6e3fa7 ams559nk06 compat
>   drm/panel: add samsung s6e3fa7 panel driver
>   arm64: dts: qcom: sdm670-google-sargo: add panel
> 
> [...]

Applied, thanks!

[3/3] arm64: dts: qcom: sdm670-google-sargo: add panel
      commit: 232490b925272d54dd91847a183bdbc2deec904b

Best regards,
-- 
Bjorn Andersson <andersson@kernel.org>

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2024-03-19  2:49 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-02-09  0:16 [PATCH 0/3] drm/panel: Pixel 3a Panel Richard Acayan
2024-02-09  0:16 ` [PATCH 1/3] dt-bindings: display: panel-simple-dsi: add s6e3fa7 ams559nk06 compat Richard Acayan
2024-02-09  7:37   ` Krzysztof Kozlowski
2024-02-09  0:16 ` [PATCH 2/3] drm/panel: add samsung s6e3fa7 panel driver Richard Acayan
2024-02-09  1:34   ` Jessica Zhang
2024-02-09 23:17     ` Richard Acayan
2024-02-28 22:04       ` Jessica Zhang
2024-03-04 21:41   ` Caleb Connolly
2024-03-04 21:43     ` Caleb Connolly
2024-02-09  0:16 ` [PATCH 3/3] arm64: dts: qcom: sdm670-google-sargo: add panel Richard Acayan
2024-02-29  8:53 ` (subset) [PATCH 0/3] drm/panel: Pixel 3a Panel Neil Armstrong
2024-03-19  2:48 ` Bjorn Andersson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).