u-boot.lists.denx.de archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/6] Add video drivers for endeavoru and p880/p895
@ 2023-04-20 16:17 Svyatoslav Ryhel
  2023-04-20 16:17 ` [PATCH v2 1/6] video: add lm3533 backlight driver Svyatoslav Ryhel
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Svyatoslav Ryhel @ 2023-04-20 16:17 UTC (permalink / raw)
  To: Anatolij Gustschin, Simon Glass, Svyatoslav Ryhel; +Cc: u-boot

This patchset contains mostly generic drivers used by endeavoru
and p895/p880 (which are currently in the process of merging).
Drivers do not contain any device specific parts and mostly can
be used by any device with supported hardware.

LG P880\P895 related drivers:
- lm3533 backlight driver implements only backlight part for
bank A. Unfortunately, I can not test and set up bank B since
my device does not use it.
- Solomon ssd2825 bridge is fully implemented for 3wire-9bit
mode. It uses SPI interface and is wrapped into panel DM for
wider compatibility.
- 2 DSI panels which use Renesas R61307 and R69328 controllers
are fully implemented as well.

HTC One X (endeavoru) related drivers:
- backlight driver which uses a PWM source provided by the display
controller.
- endeavoru uses panels made by 3 different vendors but the command
sequence seems to be generally the same. Endeavoru panel driver
is set to support all 3 variants of this panel.

---

Changes from v1:
- used lower-case hex for command sequences
- ssd2825 switched to dm_spi_xfer
- used log_* instead of printf
- tweaked lm3533 help description

---

Svyatoslav Ryhel (6):
  video: add lm3533 backlight driver
  video: bridge: add Solomon SSD2825 DSI/LVDS driver
  video: panel: add Renesas R61307 MIPI DSI panel driver
  video: panel: add Renesas R69328 MIPI DSI panel driver
  video: tegra: add DC based PWM backlight driver
  video: panel: add generic endeavoru panel

 drivers/video/Kconfig                       |  38 ++
 drivers/video/Makefile                      |   4 +
 drivers/video/bridge/Kconfig                |   7 +
 drivers/video/bridge/Makefile               |   1 +
 drivers/video/bridge/ssd2825.c              | 520 ++++++++++++++++++++
 drivers/video/endeavoru-panel.c             | 252 ++++++++++
 drivers/video/lm3533_backlight.c            | 134 +++++
 drivers/video/renesas-r61307.c              | 296 +++++++++++
 drivers/video/renesas-r69328.c              | 232 +++++++++
 drivers/video/tegra20/Kconfig               |   7 +
 drivers/video/tegra20/Makefile              |   1 +
 drivers/video/tegra20/tegra-pwm-backlight.c | 155 ++++++
 12 files changed, 1647 insertions(+)
 create mode 100644 drivers/video/bridge/ssd2825.c
 create mode 100644 drivers/video/endeavoru-panel.c
 create mode 100644 drivers/video/lm3533_backlight.c
 create mode 100644 drivers/video/renesas-r61307.c
 create mode 100644 drivers/video/renesas-r69328.c
 create mode 100644 drivers/video/tegra20/tegra-pwm-backlight.c

-- 
2.37.2


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

* [PATCH v2 1/6] video: add lm3533 backlight driver
  2023-04-20 16:17 [PATCH v2 0/6] Add video drivers for endeavoru and p880/p895 Svyatoslav Ryhel
@ 2023-04-20 16:17 ` Svyatoslav Ryhel
  2023-04-20 16:17 ` [PATCH v2 2/6] video: bridge: add Solomon SSD2825 DSI/LVDS driver Svyatoslav Ryhel
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Svyatoslav Ryhel @ 2023-04-20 16:17 UTC (permalink / raw)
  To: Anatolij Gustschin, Simon Glass, Svyatoslav Ryhel; +Cc: u-boot

This is basic lm3533 driver only with bank A and backlight cell
support.

Tested-by: Andreas Westman Dorcsak <hedmoo@yahoo.com> # LG P880 T30
Tested-by: Svyatoslav Ryhel <clamor95@gmail.com> # LG P895 T30
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
---
 drivers/video/Kconfig            |   9 +++
 drivers/video/Makefile           |   1 +
 drivers/video/lm3533_backlight.c | 134 +++++++++++++++++++++++++++++++
 3 files changed, 144 insertions(+)
 create mode 100644 drivers/video/lm3533_backlight.c

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 334d64c948..60048ad86a 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -606,6 +606,15 @@ config ATMEL_HLCD
 	help
 	   HLCDC supports video output to an attached LCD panel.
 
+config BACKLIGHT_LM3533
+	bool "Backlight Driver for LM3533"
+	depends on BACKLIGHT
+	select DM_I2C
+	help
+	  Say Y to enable the backlight driver for National Semiconductor / TI
+	  LM3533 Lighting Power chip. Only Bank A is supported as for now.
+	  Supported backlight level range is from 2 to 255 with step of 1.
+
 source "drivers/video/ti/Kconfig"
 
 source "drivers/video/exynos/Kconfig"
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 4d75771745..05fb063105 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_VIDEO_LOGO) += u_boot_logo.o
 
 endif
 
+obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_backlight.o
 obj-${CONFIG_EXYNOS_FB} += exynos/
 obj-${CONFIG_VIDEO_ROCKCHIP} += rockchip/
 obj-${CONFIG_VIDEO_STM32} += stm32/
diff --git a/drivers/video/lm3533_backlight.c b/drivers/video/lm3533_backlight.c
new file mode 100644
index 0000000000..00297a09b7
--- /dev/null
+++ b/drivers/video/lm3533_backlight.c
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#define LOG_CATEGORY UCLASS_PANEL_BACKLIGHT
+
+#include <backlight.h>
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <asm/gpio.h>
+
+#define LM3533_BL_MIN_BRIGHTNESS			0x02
+#define LM3533_BL_MAX_BRIGHTNESS			0xFF
+
+#define LM3533_SINK_OUTPUT_CONFIG_1			0x10
+#define LM3533_CONTROL_BANK_A_PWM			0x14
+#define LM3533_CONTROL_BANK_AB_BRIGHTNESS		0x1A
+#define LM3533_CONTROL_BANK_A_FULLSCALE_CURRENT		0x1F
+#define LM3533_CONTROL_BANK_ENABLE			0x27
+#define LM3533_OVP_FREQUENCY_PWM_POLARITY		0x2C
+#define LM3533_BRIGHTNESS_REGISTER_A			0x40
+
+struct lm3533_backlight_priv {
+	struct gpio_desc enable_gpio;
+	u32 def_bl_lvl;
+};
+
+static int lm3533_backlight_enable(struct udevice *dev)
+{
+	struct lm3533_backlight_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	dm_gpio_set_value(&priv->enable_gpio, 1);
+	mdelay(5);
+
+	/* HVLED 1 & 2 are controlled by Bank A */
+	ret = dm_i2c_reg_write(dev, LM3533_SINK_OUTPUT_CONFIG_1, 0x00);
+	if (ret)
+		return ret;
+
+	/* PWM input is disabled for CABC */
+	ret = dm_i2c_reg_write(dev, LM3533_CONTROL_BANK_A_PWM, 0x00);
+	if (ret)
+		return ret;
+
+	/* Linear & Control Bank A is configured for register Current control */
+	ret = dm_i2c_reg_write(dev, LM3533_CONTROL_BANK_AB_BRIGHTNESS, 0x02);
+	if (ret)
+		return ret;
+
+	/* Full-Scale Current (20.2mA) */
+	ret = dm_i2c_reg_write(dev, LM3533_CONTROL_BANK_A_FULLSCALE_CURRENT, 0x13);
+	if (ret)
+		return ret;
+
+	/* Control Bank A is enable */
+	ret = dm_i2c_reg_write(dev, LM3533_CONTROL_BANK_ENABLE, 0x01);
+	if (ret)
+		return ret;
+
+	ret = dm_i2c_reg_write(dev, LM3533_OVP_FREQUENCY_PWM_POLARITY, 0x0A);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int lm3533_backlight_set_brightness(struct udevice *dev, int percent)
+{
+	struct lm3533_backlight_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	if (percent == BACKLIGHT_DEFAULT)
+		percent = priv->def_bl_lvl;
+
+	if (percent < LM3533_BL_MIN_BRIGHTNESS)
+		percent = LM3533_BL_MIN_BRIGHTNESS;
+
+	if (percent > LM3533_BL_MAX_BRIGHTNESS)
+		percent = LM3533_BL_MAX_BRIGHTNESS;
+
+	/* Set brightness level */
+	ret = dm_i2c_reg_write(dev, LM3533_BRIGHTNESS_REGISTER_A,
+			       percent);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int lm3533_backlight_probe(struct udevice *dev)
+{
+	struct lm3533_backlight_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	if (device_get_uclass_id(dev->parent) != UCLASS_I2C)
+		return -EPROTONOSUPPORT;
+
+	ret = gpio_request_by_name(dev, "enable-gpios", 0,
+				   &priv->enable_gpio, GPIOD_IS_OUT);
+	if (ret) {
+		log_err("Could not decode enable-gpios (%d)\n", ret);
+		return ret;
+	}
+
+	priv->def_bl_lvl = dev_read_u32_default(dev, "default-brightness-level",
+						LM3533_BL_MAX_BRIGHTNESS);
+
+	return 0;
+}
+
+static const struct backlight_ops lm3533_backlight_ops = {
+	.enable = lm3533_backlight_enable,
+	.set_brightness = lm3533_backlight_set_brightness,
+};
+
+static const struct udevice_id lm3533_backlight_ids[] = {
+	{ .compatible = "ti,lm3533" },
+	{ }
+};
+
+U_BOOT_DRIVER(lm3533_backlight) = {
+	.name		= "lm3533_backlight",
+	.id		= UCLASS_PANEL_BACKLIGHT,
+	.of_match	= lm3533_backlight_ids,
+	.probe		= lm3533_backlight_probe,
+	.ops		= &lm3533_backlight_ops,
+	.priv_auto	= sizeof(struct lm3533_backlight_priv),
+};
-- 
2.37.2


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

* [PATCH v2 2/6] video: bridge: add Solomon SSD2825 DSI/LVDS driver
  2023-04-20 16:17 [PATCH v2 0/6] Add video drivers for endeavoru and p880/p895 Svyatoslav Ryhel
  2023-04-20 16:17 ` [PATCH v2 1/6] video: add lm3533 backlight driver Svyatoslav Ryhel
@ 2023-04-20 16:17 ` Svyatoslav Ryhel
  2023-04-20 16:17 ` [PATCH v2 3/6] video: panel: add Renesas R61307 MIPI DSI panel driver Svyatoslav Ryhel
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Svyatoslav Ryhel @ 2023-04-20 16:17 UTC (permalink / raw)
  To: Anatolij Gustschin, Simon Glass, Svyatoslav Ryhel; +Cc: u-boot

SSD2825 is an innovative and cost-effective MIPI Bridge Chip solution
targeting high resolution smartphones. It can convert 24bit RGB
interface into 4-lane MIPI-DSI interface to drive extremely high
resolution display modules of up to 800 x 1366, while supporting AMOLED,
a-si LCD or LTPS advanced panel technologies for smartphone applications.

Bridge is wrapped in panel uClass model for wider compatibility.

Tested-by: Andreas Westman Dorcsak <hedmoo@yahoo.com> # LG P880 T30
Tested-by: Svyatoslav Ryhel <clamor95@gmail.com> # LG P895 T30
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/video/bridge/Kconfig   |   7 +
 drivers/video/bridge/Makefile  |   1 +
 drivers/video/bridge/ssd2825.c | 520 +++++++++++++++++++++++++++++++++
 3 files changed, 528 insertions(+)
 create mode 100644 drivers/video/bridge/ssd2825.c

diff --git a/drivers/video/bridge/Kconfig b/drivers/video/bridge/Kconfig
index 765f7380b8..2311ca2d1a 100644
--- a/drivers/video/bridge/Kconfig
+++ b/drivers/video/bridge/Kconfig
@@ -33,3 +33,10 @@ config VIDEO_BRIDGE_ANALOGIX_ANX6345
 	help
 	 The Analogix ANX6345 is RGB-to-DP converter. It enables an eDP LCD
 	 panel to be connected to an parallel LCD interface.
+
+config VIDEO_BRIDGE_SOLOMON_SSD2825
+	bool "Solomon SSD2825 bridge driver"
+	depends on PANEL && DM_GPIO
+	select VIDEO_MIPI_DSI
+	help
+	  Solomon SSD2824 SPI RGB-DSI bridge driver wrapped into panel uClass.
diff --git a/drivers/video/bridge/Makefile b/drivers/video/bridge/Makefile
index 45e54ac176..22625c8bc6 100644
--- a/drivers/video/bridge/Makefile
+++ b/drivers/video/bridge/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_VIDEO_BRIDGE) += video-bridge-uclass.o
 obj-$(CONFIG_VIDEO_BRIDGE_PARADE_PS862X) += ps862x.o
 obj-$(CONFIG_VIDEO_BRIDGE_NXP_PTN3460) += ptn3460.o
 obj-$(CONFIG_VIDEO_BRIDGE_ANALOGIX_ANX6345) += anx6345.o
+obj-$(CONFIG_VIDEO_BRIDGE_SOLOMON_SSD2825) += ssd2825.o
diff --git a/drivers/video/bridge/ssd2825.c b/drivers/video/bridge/ssd2825.c
new file mode 100644
index 0000000000..d1c6baa053
--- /dev/null
+++ b/drivers/video/bridge/ssd2825.c
@@ -0,0 +1,520 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <log.h>
+#include <misc.h>
+#include <mipi_display.h>
+#include <mipi_dsi.h>
+#include <backlight.h>
+#include <panel.h>
+#include <spi.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <asm/gpio.h>
+
+#define SSD2825_DEVICE_ID_REG			0xB0
+#define SSD2825_RGB_INTERFACE_CTRL_REG_1	0xB1
+#define SSD2825_RGB_INTERFACE_CTRL_REG_2	0xB2
+#define SSD2825_RGB_INTERFACE_CTRL_REG_3	0xB3
+#define SSD2825_RGB_INTERFACE_CTRL_REG_4	0xB4
+#define SSD2825_RGB_INTERFACE_CTRL_REG_5	0xB5
+#define SSD2825_RGB_INTERFACE_CTRL_REG_6	0xB6
+#define   SSD2825_NON_BURST			BIT(2)
+#define   SSD2825_BURST				BIT(3)
+#define   SSD2825_PCKL_HIGH			BIT(13)
+#define   SSD2825_HSYNC_HIGH			BIT(14)
+#define   SSD2825_VSYNC_HIGH			BIT(15)
+#define SSD2825_CONFIGURATION_REG		0xB7
+#define   SSD2825_CONF_REG_HS			BIT(0)
+#define   SSD2825_CONF_REG_CKE			BIT(1)
+#define   SSD2825_CONF_REG_SLP			BIT(2)
+#define   SSD2825_CONF_REG_VEN			BIT(3)
+#define   SSD2825_CONF_REG_HCLK			BIT(4)
+#define   SSD2825_CONF_REG_CSS			BIT(5)
+#define   SSD2825_CONF_REG_DCS			BIT(6)
+#define   SSD2825_CONF_REG_REN			BIT(7)
+#define   SSD2825_CONF_REG_ECD			BIT(8)
+#define   SSD2825_CONF_REG_EOT			BIT(9)
+#define   SSD2825_CONF_REG_LPE			BIT(10)
+#define SSD2825_VC_CTRL_REG			0xB8
+#define SSD2825_PLL_CTRL_REG			0xB9
+#define SSD2825_PLL_CONFIGURATION_REG		0xBA
+#define SSD2825_CLOCK_CTRL_REG			0xBB
+#define SSD2825_PACKET_SIZE_CTRL_REG_1		0xBC
+#define SSD2825_PACKET_SIZE_CTRL_REG_2		0xBD
+#define SSD2825_PACKET_SIZE_CTRL_REG_3		0xBE
+#define SSD2825_PACKET_DROP_REG			0xBF
+#define SSD2825_OPERATION_CTRL_REG		0xC0
+#define SSD2825_MAX_RETURN_SIZE_REG		0xC1
+#define SSD2825_RETURN_DATA_COUNT_REG		0xC2
+#define SSD2825_ACK_RESPONSE_REG		0xC3
+#define SSD2825_LINE_CTRL_REG			0xC4
+#define SSD2825_INTERRUPT_CTRL_REG		0xC5
+#define SSD2825_INTERRUPT_STATUS_REG		0xC6
+#define SSD2825_ERROR_STATUS_REG		0xC7
+#define SSD2825_DATA_FORMAT_REG			0xC8
+#define SSD2825_DELAY_ADJ_REG_1			0xC9
+#define SSD2825_DELAY_ADJ_REG_2			0xCA
+#define SSD2825_DELAY_ADJ_REG_3			0xCB
+#define SSD2825_DELAY_ADJ_REG_4			0xCC
+#define SSD2825_DELAY_ADJ_REG_5			0xCD
+#define SSD2825_DELAY_ADJ_REG_6			0xCE
+#define SSD2825_HS_TX_TIMER_REG_1		0xCF
+#define SSD2825_HS_TX_TIMER_REG_2		0xD0
+#define SSD2825_LP_RX_TIMER_REG_1		0xD1
+#define SSD2825_LP_RX_TIMER_REG_2		0xD2
+#define SSD2825_TE_STATUS_REG			0xD3
+#define SSD2825_SPI_READ_REG			0xD4
+#define SSD2825_PLL_LOCK_REG			0xD5
+#define SSD2825_TEST_REG			0xD6
+#define SSD2825_TE_COUNT_REG			0xD7
+#define SSD2825_ANALOG_CTRL_REG_1		0xD8
+#define SSD2825_ANALOG_CTRL_REG_2		0xD9
+#define SSD2825_ANALOG_CTRL_REG_3		0xDA
+#define SSD2825_ANALOG_CTRL_REG_4		0xDB
+#define SSD2825_INTERRUPT_OUT_CTRL_REG		0xDC
+#define SSD2825_RGB_INTERFACE_CTRL_REG_7	0xDD
+#define SSD2825_LANE_CONFIGURATION_REG		0xDE
+#define SSD2825_DELAY_ADJ_REG_7			0xDF
+#define SSD2825_INPUT_PIN_CTRL_REG_1		0xE0
+#define SSD2825_INPUT_PIN_CTRL_REG_2		0xE1
+#define SSD2825_BIDIR_PIN_CTRL_REG_1		0xE2
+#define SSD2825_BIDIR_PIN_CTRL_REG_2		0xE3
+#define SSD2825_BIDIR_PIN_CTRL_REG_3		0xE4
+#define SSD2825_BIDIR_PIN_CTRL_REG_4		0xE5
+#define SSD2825_BIDIR_PIN_CTRL_REG_5		0xE6
+#define SSD2825_BIDIR_PIN_CTRL_REG_6		0xE7
+#define SSD2825_BIDIR_PIN_CTRL_REG_7		0xE8
+#define SSD2825_CABC_BRIGHTNESS_CTRL_REG_1	0xE9
+#define SSD2825_CABC_BRIGHTNESS_CTRL_REG_2	0xEA
+#define SSD2825_CABC_BRIGHTNESS_STATUS_REG	0xEB
+#define SSD2825_READ_REG			0xFF
+#define   SSD2825_SPI_READ_REG_RESET		0xFA
+
+#define SSD2825_CMD_MASK		0x00
+#define SSD2825_DAT_MASK		0x01
+
+#define SSD2825_CMD_SEND		BIT(0)
+#define SSD2825_DAT_SEND		BIT(1)
+#define SSD2825_DSI_SEND		BIT(2)
+
+#define	SSD2828_LP_CLOCK_DIVIDER(n)	(((n) - 1) & 0x3F)
+#define SSD2825_LP_MIN_CLK		5000 /* KHz */
+#define SSD2825_REF_MIN_CLK		2000 /* KHz */
+
+struct ssd2825_bridge_priv {
+	struct mipi_dsi_host host;
+	struct mipi_dsi_device device;
+
+	struct udevice *panel;
+	struct display_timing timing;
+
+	struct gpio_desc power_gpio;
+	struct gpio_desc reset_gpio;
+
+	struct clk *tx_clk;
+
+	u32 pll_freq_kbps;	/* PLL in kbps */
+};
+
+static int ssd2825_spi_write(struct udevice *dev, int reg,
+			     const void *buf, int flags)
+{
+	u8 command[2];
+
+	if (flags & SSD2825_CMD_SEND) {
+		command[0] = SSD2825_CMD_MASK;
+		command[1] = reg;
+		dm_spi_xfer(dev, 9, &command,
+			    NULL, SPI_XFER_ONCE);
+	}
+
+	if (flags & SSD2825_DAT_SEND) {
+		u16 data = *(u16 *)buf;
+		u8 cmd1, cmd2;
+
+		/* send low byte first and then high byte */
+		cmd1 = (data & 0x00FF);
+		cmd2 = (data & 0xFF00) >> 8;
+
+		command[0] = SSD2825_DAT_MASK;
+		command[1] = cmd1;
+		dm_spi_xfer(dev, 9, &command,
+			    NULL, SPI_XFER_ONCE);
+
+		command[0] = SSD2825_DAT_MASK;
+		command[1] = cmd2;
+		dm_spi_xfer(dev, 9, &command,
+			    NULL, SPI_XFER_ONCE);
+	}
+
+	if (flags & SSD2825_DSI_SEND) {
+		u16 data = *(u16 *)buf;
+		data &= 0x00FF;
+
+		debug("%s: dsi command (0x%x)\n",
+		      __func__, data);
+
+		command[0] = SSD2825_DAT_MASK;
+		command[1] = data;
+		dm_spi_xfer(dev, 9, &command,
+			    NULL, SPI_XFER_ONCE);
+	}
+
+	return 0;
+}
+
+static int ssd2825_spi_read(struct udevice *dev, int reg,
+			    void *data, int flags)
+{
+	u8 command[2];
+
+	command[0] = SSD2825_CMD_MASK;
+	command[1] = SSD2825_SPI_READ_REG;
+	dm_spi_xfer(dev, 9, &command,
+		    NULL, SPI_XFER_ONCE);
+
+	command[0] = SSD2825_DAT_MASK;
+	command[1] = SSD2825_SPI_READ_REG_RESET;
+	dm_spi_xfer(dev, 9, &command,
+		    NULL, SPI_XFER_ONCE);
+
+	command[0] = SSD2825_DAT_MASK;
+	command[1] = 0;
+	dm_spi_xfer(dev, 9, &command,
+		    NULL, SPI_XFER_ONCE);
+
+	command[0] = SSD2825_CMD_MASK;
+	command[1] = reg;
+	dm_spi_xfer(dev, 9, &command,
+		    NULL, SPI_XFER_ONCE);
+
+	command[0] = SSD2825_CMD_MASK;
+	command[1] = SSD2825_SPI_READ_REG_RESET;
+	dm_spi_xfer(dev, 9, &command,
+		    NULL, SPI_XFER_ONCE);
+
+	dm_spi_xfer(dev, 16, NULL,
+		    (u8 *)data, SPI_XFER_ONCE);
+
+	return 0;
+}
+
+static void ssd2825_write_register(struct udevice *dev, u8 reg,
+				   u16 command)
+{
+	ssd2825_spi_write(dev, reg, &command,
+			  SSD2825_CMD_SEND |
+			  SSD2825_DAT_SEND);
+}
+
+static void ssd2825_write_dsi(struct udevice *dev, const u8 *command,
+			      int len)
+{
+	int i;
+
+	ssd2825_spi_write(dev, SSD2825_PACKET_SIZE_CTRL_REG_1, &len,
+			  SSD2825_CMD_SEND | SSD2825_DAT_SEND);
+
+	ssd2825_spi_write(dev, SSD2825_PACKET_DROP_REG, NULL,
+			  SSD2825_CMD_SEND);
+
+	for (i = 0; i < len; i++)
+		ssd2825_spi_write(dev, 0, &command[i], SSD2825_DSI_SEND);
+}
+
+static ssize_t ssd2825_bridge_transfer(struct mipi_dsi_host *host,
+				       const struct mipi_dsi_msg *msg)
+{
+	struct udevice *dev = (struct udevice *)host->dev;
+	u8 buf = *(u8 *)msg->tx_buf;
+	u16 config;
+	int ret;
+
+	ret = ssd2825_spi_read(dev, SSD2825_CONFIGURATION_REG,
+			       &config, 0);
+	if (ret)
+		return ret;
+
+	switch (msg->type) {
+	case MIPI_DSI_DCS_SHORT_WRITE:
+	case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
+	case MIPI_DSI_DCS_LONG_WRITE:
+		config |= SSD2825_CONF_REG_DCS;
+		break;
+	case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
+	case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
+	case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
+	case MIPI_DSI_GENERIC_LONG_WRITE:
+		config &= ~SSD2825_CONF_REG_DCS;
+		break;
+	default:
+		return 0;
+	}
+
+	ssd2825_write_register(dev, SSD2825_CONFIGURATION_REG, config);
+	ssd2825_write_register(dev, SSD2825_VC_CTRL_REG, 0x0000);
+	ssd2825_write_dsi(dev, msg->tx_buf, msg->tx_len);
+
+	if (buf == MIPI_DCS_SET_DISPLAY_ON) {
+		ssd2825_write_register(dev, SSD2825_CONFIGURATION_REG,
+				SSD2825_CONF_REG_HS | SSD2825_CONF_REG_VEN |
+				SSD2825_CONF_REG_DCS | SSD2825_CONF_REG_ECD |
+				SSD2825_CONF_REG_EOT);
+		ssd2825_write_register(dev, SSD2825_PLL_CTRL_REG, 0x0001);
+		ssd2825_write_register(dev, SSD2825_VC_CTRL_REG, 0x0000);
+	}
+
+	return 0;
+}
+
+static const struct mipi_dsi_host_ops ssd2825_bridge_host_ops = {
+	.transfer	= ssd2825_bridge_transfer,
+};
+
+/*
+ * PLL configuration register settings.
+ *
+ * See the "PLL Configuration Register Description" in the SSD2825 datasheet.
+ */
+static u16 construct_pll_config(struct ssd2825_bridge_priv *priv,
+				u32 desired_pll_freq_kbps, u32 reference_freq_khz)
+{
+	u32 div_factor = 1, mul_factor, fr = 0;
+
+	while (reference_freq_khz / (div_factor + 1) >= SSD2825_REF_MIN_CLK)
+		div_factor++;
+	if (div_factor > 31)
+		div_factor = 31;
+
+	mul_factor = DIV_ROUND_UP(desired_pll_freq_kbps * div_factor,
+				  reference_freq_khz);
+
+	priv->pll_freq_kbps = reference_freq_khz * mul_factor / div_factor;
+
+	if (priv->pll_freq_kbps >= 501000)
+		fr = 3;
+	else if (priv->pll_freq_kbps >= 251000)
+		fr = 2;
+	else if (priv->pll_freq_kbps >= 126000)
+		fr = 1;
+
+	return (fr << 14) | (div_factor << 8) | mul_factor;
+}
+
+static void ssd2825_setup_pll(struct udevice *dev)
+{
+	struct ssd2825_bridge_priv *priv = dev_get_priv(dev);
+	struct mipi_dsi_device *device = &priv->device;
+	struct display_timing *dt = &priv->timing;
+	u16 pll_config, lp_div;
+	u32 pclk_mult, tx_freq_khz, pd_lines;
+
+	tx_freq_khz = clk_get_rate(priv->tx_clk) / 1000;
+	pd_lines = mipi_dsi_pixel_format_to_bpp(device->format);
+	pclk_mult = pd_lines / device->lanes + 1;
+
+	pll_config = construct_pll_config(priv, pclk_mult *
+					  dt->pixelclock.typ / 1000,
+					  tx_freq_khz);
+
+	lp_div = priv->pll_freq_kbps / (SSD2825_LP_MIN_CLK * 8);
+
+	/* Disable PLL */
+	ssd2825_write_register(dev, SSD2825_PLL_CTRL_REG, 0x0000);
+	ssd2825_write_register(dev, SSD2825_LINE_CTRL_REG, 0x0001);
+
+	/* Set delays */
+	ssd2825_write_register(dev, SSD2825_DELAY_ADJ_REG_1, 0x2103);
+
+	/* Set PLL coeficients */
+	ssd2825_write_register(dev, SSD2825_PLL_CONFIGURATION_REG, pll_config);
+
+	/* Clock Control Register */
+	ssd2825_write_register(dev, SSD2825_CLOCK_CTRL_REG,
+			       SSD2828_LP_CLOCK_DIVIDER(lp_div));
+
+	/* Enable PLL */
+	ssd2825_write_register(dev, SSD2825_PLL_CTRL_REG, 0x0001);
+	ssd2825_write_register(dev, SSD2825_VC_CTRL_REG, 0x0000);
+}
+
+static int ssd2825_bridge_enable_panel(struct udevice *dev)
+{
+	struct ssd2825_bridge_priv *priv = dev_get_priv(dev);
+	struct mipi_dsi_device *device = &priv->device;
+	struct display_timing *dt = &priv->timing;
+	int ret;
+
+	ret = clk_prepare_enable(priv->tx_clk);
+	if (ret) {
+		log_err("error enabling tx_clk (%d)\n", ret);
+		return ret;
+	}
+
+	ret = dm_gpio_set_value(&priv->power_gpio, 1);
+	if (ret) {
+		log_err("error changing power-gpios (%d)\n", ret);
+		return ret;
+	}
+	mdelay(10);
+
+	ret = dm_gpio_set_value(&priv->reset_gpio, 0);
+	if (ret) {
+		log_err("error changing reset-gpios (%d)\n", ret);
+		return ret;
+	}
+	mdelay(10);
+
+	ret = dm_gpio_set_value(&priv->reset_gpio, 1);
+	if (ret) {
+		log_err("error changing reset-gpios (%d)\n", ret);
+		return ret;
+	}
+	mdelay(10);
+
+	/* Perform panel HW setup */
+	ret = panel_enable_backlight(priv->panel);
+	if (ret)
+		return ret;
+
+	/* Perform SW reset */
+	ssd2825_write_register(dev, SSD2825_OPERATION_CTRL_REG, 0x0100);
+
+	/* Set panel timings */
+	ssd2825_write_register(dev, SSD2825_RGB_INTERFACE_CTRL_REG_1,
+			       dt->vsync_len.typ << 8 | dt->hsync_len.typ);
+	ssd2825_write_register(dev, SSD2825_RGB_INTERFACE_CTRL_REG_2,
+			       (dt->vsync_len.typ + dt->vback_porch.typ) << 8 |
+			       (dt->hsync_len.typ + dt->hback_porch.typ));
+	ssd2825_write_register(dev, SSD2825_RGB_INTERFACE_CTRL_REG_3,
+			       dt->vfront_porch.typ << 8 | dt->hfront_porch.typ);
+	ssd2825_write_register(dev, SSD2825_RGB_INTERFACE_CTRL_REG_4,
+			       dt->hactive.typ);
+	ssd2825_write_register(dev, SSD2825_RGB_INTERFACE_CTRL_REG_5,
+			       dt->vactive.typ);
+	ssd2825_write_register(dev, SSD2825_RGB_INTERFACE_CTRL_REG_6,
+			       SSD2825_HSYNC_HIGH | SSD2825_VSYNC_HIGH |
+			       SSD2825_PCKL_HIGH | SSD2825_NON_BURST |
+			       (3 - device->format));
+	ssd2825_write_register(dev, SSD2825_LANE_CONFIGURATION_REG,
+			       device->lanes - 1);
+	ssd2825_write_register(dev, SSD2825_TEST_REG, 0x0004);
+
+	/* Call PLL configuration */
+	ssd2825_setup_pll(dev);
+
+	mdelay(10);
+
+	/* Initial DSI configuration register set */
+	ssd2825_write_register(dev, SSD2825_CONFIGURATION_REG,
+			       SSD2825_CONF_REG_CKE | SSD2825_CONF_REG_DCS |
+			       SSD2825_CONF_REG_ECD | SSD2825_CONF_REG_EOT);
+	ssd2825_write_register(dev, SSD2825_VC_CTRL_REG, 0x0000);
+
+	/* Set up SW panel configuration */
+	ret = panel_set_backlight(priv->panel, BACKLIGHT_DEFAULT);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int ssd2825_bridge_set_panel(struct udevice *dev, int percent)
+{
+	return 0;
+}
+
+static int ssd2825_bridge_panel_timings(struct udevice *dev,
+					struct display_timing *timing)
+{
+	struct ssd2825_bridge_priv *priv = dev_get_priv(dev);
+
+	memcpy(timing, &priv->timing, sizeof(*timing));
+
+	return 0;
+}
+
+static int ssd2825_bridge_probe(struct udevice *dev)
+{
+	struct ssd2825_bridge_priv *priv = dev_get_priv(dev);
+	struct spi_slave *slave = dev_get_parent_priv(dev);
+	struct mipi_dsi_device *device = &priv->device;
+	struct mipi_dsi_panel_plat *mipi_plat;
+	int ret;
+
+	ret = spi_claim_bus(slave);
+	if (ret) {
+		log_err("SPI bus allocation failed (%d)\n", ret);
+		return ret;
+	}
+
+	ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev,
+					   "panel", &priv->panel);
+	if (ret) {
+		log_err("cannot get panel: ret=%d\n", ret);
+		return ret;
+	}
+
+	panel_get_display_timing(priv->panel, &priv->timing);
+
+	mipi_plat = dev_get_plat(priv->panel);
+	mipi_plat->device = device;
+
+	priv->host.dev = (struct device *)dev;
+	priv->host.ops = &ssd2825_bridge_host_ops;
+
+	device->host = &priv->host;
+	device->lanes = mipi_plat->lanes;
+	device->format = mipi_plat->format;
+	device->mode_flags = mipi_plat->mode_flags;
+
+	/* get panel gpios */
+	ret = gpio_request_by_name(dev, "power-gpios", 0,
+				   &priv->power_gpio, GPIOD_IS_OUT);
+	if (ret) {
+		log_err("could not decode power-gpios (%d)\n", ret);
+		return ret;
+	}
+
+	ret = gpio_request_by_name(dev, "reset-gpios", 0,
+				   &priv->reset_gpio, GPIOD_IS_OUT);
+	if (ret) {
+		log_err("could not decode reset-gpios (%d)\n", ret);
+		return ret;
+	}
+
+	/* get clk */
+	priv->tx_clk = devm_clk_get(dev, "tx_clk");
+	if (IS_ERR(priv->tx_clk)) {
+		log_err("cannot get tx_clk: %ld\n", PTR_ERR(priv->tx_clk));
+		return PTR_ERR(priv->tx_clk);
+	}
+
+	return 0;
+}
+
+static const struct panel_ops ssd2825_bridge_ops = {
+	.enable_backlight	= ssd2825_bridge_enable_panel,
+	.set_backlight		= ssd2825_bridge_set_panel,
+	.get_display_timing	= ssd2825_bridge_panel_timings,
+};
+
+static const struct udevice_id ssd2825_bridge_ids[] = {
+	{ .compatible = "solomon,ssd2825" },
+	{ }
+};
+
+U_BOOT_DRIVER(ssd2825) = {
+	.name		= "ssd2825",
+	.id		= UCLASS_PANEL,
+	.of_match	= ssd2825_bridge_ids,
+	.ops		= &ssd2825_bridge_ops,
+	.probe		= ssd2825_bridge_probe,
+	.priv_auto	= sizeof(struct ssd2825_bridge_priv),
+};
-- 
2.37.2


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

* [PATCH v2 3/6] video: panel: add Renesas R61307 MIPI DSI panel driver
  2023-04-20 16:17 [PATCH v2 0/6] Add video drivers for endeavoru and p880/p895 Svyatoslav Ryhel
  2023-04-20 16:17 ` [PATCH v2 1/6] video: add lm3533 backlight driver Svyatoslav Ryhel
  2023-04-20 16:17 ` [PATCH v2 2/6] video: bridge: add Solomon SSD2825 DSI/LVDS driver Svyatoslav Ryhel
@ 2023-04-20 16:17 ` Svyatoslav Ryhel
  2023-04-20 16:17 ` [PATCH v2 4/6] video: panel: add Renesas R69328 " Svyatoslav Ryhel
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Svyatoslav Ryhel @ 2023-04-20 16:17 UTC (permalink / raw)
  To: Anatolij Gustschin, Simon Glass, Svyatoslav Ryhel; +Cc: u-boot

R61307 is liquid crystal driver for high-definition
amorphous silicon (a-Si) panels and is ideal for
tablets and smartphones.

Supported compatibles are:
- koe,tx13d100vm0eaa
- hitachi,tx13d100vm0eaa

Tested-by: Andreas Westman Dorcsak <hedmoo@yahoo.com> # LG P880 T30
Tested-by: Svyatoslav Ryhel <clamor95@gmail.com> # LG P895 T30
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
---
 drivers/video/Kconfig          |   9 +
 drivers/video/Makefile         |   1 +
 drivers/video/renesas-r61307.c | 296 +++++++++++++++++++++++++++++++++
 3 files changed, 306 insertions(+)
 create mode 100644 drivers/video/renesas-r61307.c

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 60048ad86a..44f21be166 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -480,6 +480,15 @@ config VIDEO_LCD_RAYDIUM_RM68200
 	Say Y here if you want to enable support for Raydium RM68200
 	720x1280 DSI video mode panel.
 
+config VIDEO_LCD_RENESAS_R61307
+	tristate "Renesas R61307 DSI video mode panel"
+	depends on PANEL && BACKLIGHT
+	select VIDEO_MIPI_DSI
+	help
+	  Say Y here if you want to enable support for KOE tx13d100vm0eaa
+	  IPS-LCD module with Renesas R69328 IC. The panel has a 1024x768
+	  resolution and uses 24 bit RGB per pixel.
+
 config VIDEO_LCD_SSD2828
 	bool "SSD2828 bridge chip"
 	---help---
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 05fb063105..9ab5de8858 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_VIDEO_LCD_ANX9804) += anx9804.o
 obj-$(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM) += hitachi_tx18d42vm_lcd.o
 obj-$(CONFIG_VIDEO_LCD_ORISETECH_OTM8009A) += orisetech_otm8009a.o
 obj-$(CONFIG_VIDEO_LCD_RAYDIUM_RM68200) += raydium-rm68200.o
+obj-$(CONFIG_VIDEO_LCD_RENESAS_R61307) += renesas-r61307.o
 obj-$(CONFIG_VIDEO_LCD_SSD2828) += ssd2828.o
 obj-$(CONFIG_VIDEO_LCD_TDO_TL070WSH30) += tdo-tl070wsh30.o
 obj-$(CONFIG_VIDEO_MCDE_SIMPLE) += mcde_simple.o
diff --git a/drivers/video/renesas-r61307.c b/drivers/video/renesas-r61307.c
new file mode 100644
index 0000000000..ddd0cfdf39
--- /dev/null
+++ b/drivers/video/renesas-r61307.c
@@ -0,0 +1,296 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Renesas R61307 panel driver
+ *
+ * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <common.h>
+#include <backlight.h>
+#include <dm.h>
+#include <panel.h>
+#include <log.h>
+#include <misc.h>
+#include <mipi_display.h>
+#include <mipi_dsi.h>
+#include <asm/gpio.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <power/regulator.h>
+
+#define R61307_MACP		0xB0 /* Manufacturer CMD Protect */
+
+#define R61307_INVERSION	0xC1
+#define R61307_GAMMA_SET_A	0xC8 /* Gamma Setting A */
+#define R61307_GAMMA_SET_B	0xC9 /* Gamma Setting B */
+#define R61307_GAMMA_SET_C	0xCA /* Gamma Setting C */
+#define R61307_CONTRAST_SET	0xCC
+
+struct renesas_r61307_priv {
+	struct udevice *vcc;
+	struct udevice *iovcc;
+
+	struct udevice *backlight;
+
+	struct gpio_desc reset_gpio;
+
+	bool dig_cont_adj;
+	bool inversion;
+	u32 gamma;
+};
+
+static const u8 macp_on[] = {
+	R61307_MACP, 0x03
+};
+
+static const u8 macp_off[] = {
+	R61307_MACP, 0x04
+};
+
+static const u8 address_mode[] = {
+	MIPI_DCS_SET_ADDRESS_MODE
+};
+
+static const u8 contrast_setting[] = {
+	R61307_CONTRAST_SET,
+	0xdc, 0xb4, 0xff
+};
+
+static const u8 column_inversion[] = {
+	R61307_INVERSION,
+	0x00, 0x50, 0x03, 0x22,
+	0x16, 0x06, 0x60, 0x11
+};
+
+static const u8 line_inversion[] = {
+	R61307_INVERSION,
+	0x00, 0x10, 0x03, 0x22,
+	0x16, 0x06, 0x60, 0x01
+};
+
+static const u8 gamma_setting[][25] = {
+	{},
+	{
+		R61307_GAMMA_SET_A,
+		0x00, 0x06, 0x0a, 0x0f,
+		0x14, 0x1f, 0x1f, 0x17,
+		0x12, 0x0c, 0x09, 0x06,
+		0x00, 0x06, 0x0a, 0x0f,
+		0x14, 0x1f, 0x1f, 0x17,
+		0x12, 0x0c, 0x09, 0x06
+	},
+	{
+		R61307_GAMMA_SET_A,
+		0x00, 0x05, 0x0b, 0x0f,
+		0x11, 0x1d, 0x20, 0x18,
+		0x18, 0x09, 0x07, 0x06,
+		0x00, 0x05, 0x0b, 0x0f,
+		0x11, 0x1d, 0x20, 0x18,
+		0x18, 0x09, 0x07, 0x06
+	},
+	{
+		R61307_GAMMA_SET_A,
+		0x0b, 0x0d, 0x10, 0x14,
+		0x13, 0x1d, 0x20, 0x18,
+		0x12, 0x09, 0x07, 0x06,
+		0x0a, 0x0c, 0x10, 0x14,
+		0x13, 0x1d, 0x20, 0x18,
+		0x12, 0x09, 0x07, 0x06
+	},
+};
+
+static struct display_timing default_timing = {
+	.pixelclock.typ		= 62000000,
+	.hactive.typ		= 768,
+	.hfront_porch.typ	= 116,
+	.hback_porch.typ	= 81,
+	.hsync_len.typ		= 5,
+	.vactive.typ		= 1024,
+	.vfront_porch.typ	= 24,
+	.vback_porch.typ	= 8,
+	.vsync_len.typ		= 2,
+};
+
+static int renesas_r61307_enable_backlight(struct udevice *dev)
+{
+	struct renesas_r61307_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = regulator_set_enable_if_allowed(priv->vcc, 1);
+	if (ret) {
+		log_err("enabling vcc-supply failed (%d)\n", ret);
+		return ret;
+	}
+	mdelay(5);
+
+	ret = regulator_set_enable_if_allowed(priv->iovcc, 1);
+	if (ret) {
+		log_err("enabling iovcc-supply failed (%d)\n", ret);
+		return ret;
+	}
+
+	ret = dm_gpio_set_value(&priv->reset_gpio, 0);
+	if (ret) {
+		log_err("changing reset-gpio failed (%d)\n", ret);
+		return ret;
+	}
+	mdelay(5);
+
+	ret = dm_gpio_set_value(&priv->reset_gpio, 1);
+	if (ret) {
+		log_err("changing reset-gpio failed (%d)\n", ret);
+		return ret;
+	}
+
+	mdelay(5);
+
+	return 0;
+}
+
+static int renesas_r61307_set_backlight(struct udevice *dev, int percent)
+{
+	struct renesas_r61307_priv *priv = dev_get_priv(dev);
+	struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
+	struct mipi_dsi_device *dsi = plat->device;
+	int ret;
+
+	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
+	if (ret < 0) {
+		log_err("failed to exit sleep mode: %d\n", ret);
+		return ret;
+	}
+
+	mdelay(80);
+
+	mipi_dsi_dcs_write_buffer(dsi, address_mode,
+				  sizeof(address_mode));
+
+	mdelay(20);
+
+	ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT << 4);
+	if (ret < 0) {
+		log_err("failed to set pixel format: %d\n", ret);
+		return ret;
+	}
+
+	/* MACP Off */
+	mipi_dsi_generic_write(dsi, macp_off, sizeof(macp_off));
+
+	if (priv->dig_cont_adj)
+		mipi_dsi_generic_write(dsi, contrast_setting,
+				       sizeof(contrast_setting));
+
+	if (priv->gamma)
+		mipi_dsi_generic_write(dsi, gamma_setting[priv->gamma],
+				       sizeof(gamma_setting[priv->gamma]));
+
+	if (priv->inversion)
+		mipi_dsi_generic_write(dsi, column_inversion,
+				       sizeof(column_inversion));
+	else
+		mipi_dsi_generic_write(dsi, line_inversion,
+				       sizeof(line_inversion));
+
+	/* MACP On */
+	mipi_dsi_generic_write(dsi, macp_on, sizeof(macp_on));
+
+	ret = mipi_dsi_dcs_set_display_on(dsi);
+	if (ret < 0) {
+		log_err("failed to set display on: %d\n", ret);
+		return ret;
+	}
+
+	mdelay(50);
+
+	ret = backlight_enable(priv->backlight);
+	if (ret)
+		return ret;
+
+	ret = backlight_set_brightness(priv->backlight, percent);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int renesas_r61307_timings(struct udevice *dev,
+				  struct display_timing *timing)
+{
+	memcpy(timing, &default_timing, sizeof(*timing));
+	return 0;
+}
+
+static int renesas_r61307_of_to_plat(struct udevice *dev)
+{
+	struct renesas_r61307_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
+					   "backlight", &priv->backlight);
+	if (ret) {
+		log_err("Cannot get backlight: ret = %d\n", ret);
+		return ret;
+	}
+
+	ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
+					   "vcc-supply", &priv->vcc);
+	if (ret) {
+		log_err("Cannot get vcc-supply: ret = %d\n", ret);
+		return ret;
+	}
+
+	ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
+					   "iovcc-supply", &priv->iovcc);
+	if (ret) {
+		log_err("Cannot get iovcc-supply: ret = %d\n", ret);
+		return ret;
+	}
+
+	ret = gpio_request_by_name(dev, "reset-gpios", 0,
+				   &priv->reset_gpio, GPIOD_IS_OUT);
+	if (ret) {
+		log_err("Could not decode reser-gpios (%d)\n", ret);
+		return ret;
+	}
+
+	priv->dig_cont_adj = dev_read_bool(dev, "renesas,contrast");
+	priv->inversion = dev_read_bool(dev, "renesas,inversion");
+	priv->gamma = dev_read_u32_default(dev, "renesas,gamma", 0);
+
+	return 0;
+}
+
+static int renesas_r61307_probe(struct udevice *dev)
+{
+	struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
+
+	/* fill characteristics of DSI data link */
+	plat->lanes = 4;
+	plat->format = MIPI_DSI_FMT_RGB888;
+	plat->mode_flags = MIPI_DSI_MODE_VIDEO;
+
+	return 0;
+}
+
+static const struct panel_ops renesas_r61307_ops = {
+	.enable_backlight	= renesas_r61307_enable_backlight,
+	.set_backlight		= renesas_r61307_set_backlight,
+	.get_display_timing	= renesas_r61307_timings,
+};
+
+static const struct udevice_id renesas_r61307_ids[] = {
+	{ .compatible = "koe,tx13d100vm0eaa" },
+	{ .compatible = "hitachi,tx13d100vm0eaa" },
+	{ }
+};
+
+U_BOOT_DRIVER(renesas_r61307) = {
+	.name		= "renesas_r61307",
+	.id		= UCLASS_PANEL,
+	.of_match	= renesas_r61307_ids,
+	.ops		= &renesas_r61307_ops,
+	.of_to_plat	= renesas_r61307_of_to_plat,
+	.probe		= renesas_r61307_probe,
+	.plat_auto	= sizeof(struct mipi_dsi_panel_plat),
+	.priv_auto	= sizeof(struct renesas_r61307_priv),
+};
-- 
2.37.2


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

* [PATCH v2 4/6] video: panel: add Renesas R69328 MIPI DSI panel driver
  2023-04-20 16:17 [PATCH v2 0/6] Add video drivers for endeavoru and p880/p895 Svyatoslav Ryhel
                   ` (2 preceding siblings ...)
  2023-04-20 16:17 ` [PATCH v2 3/6] video: panel: add Renesas R61307 MIPI DSI panel driver Svyatoslav Ryhel
@ 2023-04-20 16:17 ` Svyatoslav Ryhel
  2023-04-20 16:17 ` [PATCH v2 5/6] video: tegra: add DC based PWM backlight driver Svyatoslav Ryhel
  2023-04-20 16:17 ` [PATCH v2 6/6] video: panel: add generic endeavoru panel Svyatoslav Ryhel
  5 siblings, 0 replies; 7+ messages in thread
From: Svyatoslav Ryhel @ 2023-04-20 16:17 UTC (permalink / raw)
  To: Anatolij Gustschin, Simon Glass, Svyatoslav Ryhel; +Cc: u-boot

Driver adds support for panels with Renesas R69328 IC

Currently supported compatible is:
- jdi,dx12d100vm0eaa

Tested-by: Andreas Westman Dorcsak <hedmoo@yahoo.com> # LG P880 T30
Tested-by: Svyatoslav Ryhel <clamor95@gmail.com> # LG P895 T30
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
---
 drivers/video/Kconfig          |   9 ++
 drivers/video/Makefile         |   1 +
 drivers/video/renesas-r69328.c | 232 +++++++++++++++++++++++++++++++++
 3 files changed, 242 insertions(+)
 create mode 100644 drivers/video/renesas-r69328.c

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 44f21be166..f5e3c713e5 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -489,6 +489,15 @@ config VIDEO_LCD_RENESAS_R61307
 	  IPS-LCD module with Renesas R69328 IC. The panel has a 1024x768
 	  resolution and uses 24 bit RGB per pixel.
 
+config VIDEO_LCD_RENESAS_R69328
+	tristate "Renesas R69328 720x1280 DSI video mode panel"
+	depends on PANEL && BACKLIGHT
+	select VIDEO_MIPI_DSI
+	help
+	  Say Y here if you want to enable support for JDI dx12d100vm0eaa
+	  IPS-LCD module with Renesas R69328 IC. The panel has a 720x1280
+	  resolution and uses 24 bit RGB per pixel.
+
 config VIDEO_LCD_SSD2828
 	bool "SSD2828 bridge chip"
 	---help---
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 9ab5de8858..cddfc8fd33 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -57,6 +57,7 @@ obj-$(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM) += hitachi_tx18d42vm_lcd.o
 obj-$(CONFIG_VIDEO_LCD_ORISETECH_OTM8009A) += orisetech_otm8009a.o
 obj-$(CONFIG_VIDEO_LCD_RAYDIUM_RM68200) += raydium-rm68200.o
 obj-$(CONFIG_VIDEO_LCD_RENESAS_R61307) += renesas-r61307.o
+obj-$(CONFIG_VIDEO_LCD_RENESAS_R69328) += renesas-r69328.o
 obj-$(CONFIG_VIDEO_LCD_SSD2828) += ssd2828.o
 obj-$(CONFIG_VIDEO_LCD_TDO_TL070WSH30) += tdo-tl070wsh30.o
 obj-$(CONFIG_VIDEO_MCDE_SIMPLE) += mcde_simple.o
diff --git a/drivers/video/renesas-r69328.c b/drivers/video/renesas-r69328.c
new file mode 100644
index 0000000000..e135816d9d
--- /dev/null
+++ b/drivers/video/renesas-r69328.c
@@ -0,0 +1,232 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Renesas R69328 panel driver
+ *
+ * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <common.h>
+#include <backlight.h>
+#include <dm.h>
+#include <panel.h>
+#include <log.h>
+#include <misc.h>
+#include <mipi_display.h>
+#include <mipi_dsi.h>
+#include <asm/gpio.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <power/regulator.h>
+
+#define R69328_MACP		0xB0 /* Manufacturer Command Access Protect */
+
+#define R69328_GAMMA_SET_A	0xC8 /* Gamma Setting A */
+#define R69328_GAMMA_SET_B	0xC9 /* Gamma Setting B */
+#define R69328_GAMMA_SET_C	0xCA /* Gamma Setting C */
+
+#define R69328_POWER_SET	0xD1
+
+struct renesas_r69328_priv {
+	struct udevice *backlight;
+
+	struct gpio_desc enable_gpio;
+	struct gpio_desc reset_gpio;
+};
+
+static const u8 address_mode[] = {
+	MIPI_DCS_SET_ADDRESS_MODE
+};
+
+#define dsi_generic_write_seq(dsi, cmd, seq...) do {			\
+		static const u8 b[] = { cmd, seq };			\
+		int ret;						\
+		ret = mipi_dsi_dcs_write_buffer(dsi, b, ARRAY_SIZE(b));	\
+		if (ret < 0)						\
+			return ret;					\
+	} while (0)
+
+static struct display_timing default_timing = {
+	.pixelclock.typ		= 68000000,
+	.hactive.typ		= 720,
+	.hfront_porch.typ	= 92,
+	.hback_porch.typ	= 62,
+	.hsync_len.typ		= 4,
+	.vactive.typ		= 1280,
+	.vfront_porch.typ	= 6,
+	.vback_porch.typ	= 3,
+	.vsync_len.typ		= 1,
+};
+
+static int renesas_r69328_enable_backlight(struct udevice *dev)
+{
+	struct renesas_r69328_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = dm_gpio_set_value(&priv->enable_gpio, 1);
+	if (ret) {
+		log_err("error changing enable-gpios (%d)\n", ret);
+		return ret;
+	}
+	mdelay(5);
+
+	ret = dm_gpio_set_value(&priv->reset_gpio, 0);
+	if (ret) {
+		log_err("error changing reset-gpios (%d)\n", ret);
+		return ret;
+	}
+	mdelay(5);
+
+	ret = dm_gpio_set_value(&priv->reset_gpio, 1);
+	if (ret) {
+		log_err("error changing reset-gpios (%d)\n", ret);
+		return ret;
+	}
+
+	mdelay(5);
+
+	return 0;
+}
+
+static int renesas_r69328_set_backlight(struct udevice *dev, int percent)
+{
+	struct renesas_r69328_priv *priv = dev_get_priv(dev);
+	struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
+	struct mipi_dsi_device *dsi = plat->device;
+	int ret;
+
+	mipi_dsi_dcs_write_buffer(dsi, address_mode,
+				  sizeof(address_mode));
+
+	ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT << 4);
+	if (ret < 0) {
+		log_err("failed to set pixel format: %d\n", ret);
+		return ret;
+	}
+
+	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
+	if (ret < 0) {
+		log_err("failed to exit sleep mode: %d\n", ret);
+		return ret;
+	}
+
+	mdelay(100);
+
+	/* MACP Off */
+	dsi_generic_write_seq(dsi, R69328_MACP, 0x04);
+
+	dsi_generic_write_seq(dsi, R69328_POWER_SET, 0x14,
+			      0x1d, 0x21, 0x67, 0x11, 0x9a);
+
+	dsi_generic_write_seq(dsi, R69328_GAMMA_SET_A, 0x00,
+			      0x1a, 0x20, 0x28, 0x25, 0x24,
+			      0x26, 0x15, 0x13, 0x11, 0x18,
+			      0x1e, 0x1c, 0x00, 0x00, 0x1a,
+			      0x20, 0x28, 0x25, 0x24, 0x26,
+			      0x15, 0x13, 0x11, 0x18, 0x1e,
+			      0x1c, 0x00);
+	dsi_generic_write_seq(dsi, R69328_GAMMA_SET_B, 0x00,
+			      0x1a, 0x20, 0x28, 0x25, 0x24,
+			      0x26, 0x15, 0x13, 0x11, 0x18,
+			      0x1e, 0x1c, 0x00, 0x00, 0x1a,
+			      0x20, 0x28, 0x25, 0x24, 0x26,
+			      0x15, 0x13, 0x11, 0x18, 0x1e,
+			      0x1c, 0x00);
+	dsi_generic_write_seq(dsi, R69328_GAMMA_SET_C, 0x00,
+			      0x1a, 0x20, 0x28, 0x25, 0x24,
+			      0x26, 0x15, 0x13, 0x11, 0x18,
+			      0x1e, 0x1c, 0x00, 0x00, 0x1a,
+			      0x20, 0x28, 0x25, 0x24, 0x26,
+			      0x15, 0x13, 0x11, 0x18, 0x1e,
+			      0x1c, 0x00);
+
+	/* MACP On */
+	dsi_generic_write_seq(dsi, R69328_MACP, 0x03);
+
+	ret = mipi_dsi_dcs_set_display_on(dsi);
+	if (ret < 0) {
+		log_err("failed to set display on: %d\n", ret);
+		return ret;
+	}
+
+	mdelay(50);
+
+	ret = backlight_enable(priv->backlight);
+	if (ret)
+		return ret;
+
+	ret = backlight_set_brightness(priv->backlight, percent);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int renesas_r69328_timings(struct udevice *dev,
+				  struct display_timing *timing)
+{
+	memcpy(timing, &default_timing, sizeof(*timing));
+	return 0;
+}
+
+static int renesas_r69328_of_to_plat(struct udevice *dev)
+{
+	struct renesas_r69328_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
+					   "backlight", &priv->backlight);
+	if (ret) {
+		log_err("cannot get backlight: ret = %d\n", ret);
+		return ret;
+	}
+
+	ret = gpio_request_by_name(dev, "enable-gpios", 0,
+				   &priv->enable_gpio, GPIOD_IS_OUT);
+	if (ret) {
+		log_err("could not decode enable-gpios (%d)\n", ret);
+		return ret;
+	}
+
+	ret = gpio_request_by_name(dev, "reset-gpios", 0,
+				   &priv->reset_gpio, GPIOD_IS_OUT);
+	if (ret) {
+		log_err("could not decode reser-gpios (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int renesas_r69328_probe(struct udevice *dev)
+{
+	struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
+
+	/* fill characteristics of DSI data link */
+	plat->lanes = 4;
+	plat->format = MIPI_DSI_FMT_RGB888;
+	plat->mode_flags = MIPI_DSI_MODE_VIDEO;
+
+	return 0;
+}
+
+static const struct panel_ops renesas_r69328_ops = {
+	.enable_backlight	= renesas_r69328_enable_backlight,
+	.set_backlight		= renesas_r69328_set_backlight,
+	.get_display_timing	= renesas_r69328_timings,
+};
+
+static const struct udevice_id renesas_r69328_ids[] = {
+	{ .compatible = "jdi,dx12d100vm0eaa" },
+	{ }
+};
+
+U_BOOT_DRIVER(renesas_r69328) = {
+	.name		= "renesas_r69328",
+	.id		= UCLASS_PANEL,
+	.of_match	= renesas_r69328_ids,
+	.ops		= &renesas_r69328_ops,
+	.of_to_plat	= renesas_r69328_of_to_plat,
+	.probe		= renesas_r69328_probe,
+	.plat_auto	= sizeof(struct mipi_dsi_panel_plat),
+	.priv_auto	= sizeof(struct renesas_r69328_priv),
+};
-- 
2.37.2


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

* [PATCH v2 5/6] video: tegra: add DC based PWM backlight driver
  2023-04-20 16:17 [PATCH v2 0/6] Add video drivers for endeavoru and p880/p895 Svyatoslav Ryhel
                   ` (3 preceding siblings ...)
  2023-04-20 16:17 ` [PATCH v2 4/6] video: panel: add Renesas R69328 " Svyatoslav Ryhel
@ 2023-04-20 16:17 ` Svyatoslav Ryhel
  2023-04-20 16:17 ` [PATCH v2 6/6] video: panel: add generic endeavoru panel Svyatoslav Ryhel
  5 siblings, 0 replies; 7+ messages in thread
From: Svyatoslav Ryhel @ 2023-04-20 16:17 UTC (permalink / raw)
  To: Anatolij Gustschin, Simon Glass, Svyatoslav Ryhel; +Cc: u-boot

DC based PWM backlight is found on some T20 and T30 devices
(HTC One X). This backlight is controlled by Tegra DC and
is adjustable by the DC PM0 or PM1 signal.

Tested-by: Andreas Westman Dorcsak <hedmoo@yahoo.com> # HTC One X T30
Tested-by: Svyatoslav Ryhel <clamor95@gmail.com> # HTC One X T30
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
---
 drivers/video/tegra20/Kconfig               |   7 +
 drivers/video/tegra20/Makefile              |   1 +
 drivers/video/tegra20/tegra-pwm-backlight.c | 155 ++++++++++++++++++++
 3 files changed, 163 insertions(+)
 create mode 100644 drivers/video/tegra20/tegra-pwm-backlight.c

diff --git a/drivers/video/tegra20/Kconfig b/drivers/video/tegra20/Kconfig
index 5b1dfbfbbe..f5c4843e11 100644
--- a/drivers/video/tegra20/Kconfig
+++ b/drivers/video/tegra20/Kconfig
@@ -15,3 +15,10 @@ config VIDEO_DSI_TEGRA30
 	help
 	   T30 has native support for DSI panels. This option enables support
 	   for such panels which can be used on endeavoru and tf600t.
+
+config TEGRA_BACKLIGHT_PWM
+	bool "Enable Tegra DC PWM backlight support"
+	depends on BACKLIGHT
+	select VIDEO_TEGRA20
+	help
+	   Tegra DC dependent backlight.
diff --git a/drivers/video/tegra20/Makefile b/drivers/video/tegra20/Makefile
index e82ee96962..f0b534c579 100644
--- a/drivers/video/tegra20/Makefile
+++ b/drivers/video/tegra20/Makefile
@@ -2,3 +2,4 @@
 
 obj-$(CONFIG_VIDEO_TEGRA20) += tegra-dc.o
 obj-$(CONFIG_VIDEO_DSI_TEGRA30) += tegra-dsi.o mipi-phy.o
+obj-$(CONFIG_TEGRA_BACKLIGHT_PWM) += tegra-pwm-backlight.o
diff --git a/drivers/video/tegra20/tegra-pwm-backlight.c b/drivers/video/tegra20/tegra-pwm-backlight.c
new file mode 100644
index 0000000000..f3d7025fbb
--- /dev/null
+++ b/drivers/video/tegra20/tegra-pwm-backlight.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#define LOG_CATEGORY UCLASS_PANEL_BACKLIGHT
+
+#include <backlight.h>
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <asm/arch/display.h>
+
+#define TEGRA_DISPLAY_A_BASE		0x54200000
+#define TEGRA_DISPLAY_B_BASE		0x54240000
+
+#define TEGRA_PWM_BL_MIN_BRIGHTNESS	0x10
+#define TEGRA_PWM_BL_MAX_BRIGHTNESS	0xFF
+
+#define TEGRA_PWM_BL_PERIOD		0xFF
+#define TEGRA_PWM_BL_CLK_DIV		0x14
+#define TEGRA_PWM_BL_CLK_SELECT		0x00
+
+#define PM_PERIOD_SHIFT                 18
+#define PM_CLK_DIVIDER_SHIFT		4
+
+#define TEGRA_PWM_PM0			0
+#define TEGRA_PWM_PM1			1
+
+struct tegra_pwm_backlight_priv {
+	struct dc_ctlr *dc;		/* Display controller regmap */
+
+	u32 pwm_source;
+	u32 period;
+	u32 clk_div;
+	u32 clk_select;
+	u32 dft_brightness;
+};
+
+static int tegra_pwm_backlight_set_brightness(struct udevice *dev, int percent)
+{
+	struct tegra_pwm_backlight_priv *priv = dev_get_priv(dev);
+	struct dc_cmd_reg *cmd = &priv->dc->cmd;
+	struct dc_com_reg *com = &priv->dc->com;
+	unsigned int ctrl;
+	unsigned long out_sel;
+	unsigned long cmd_state;
+
+	if (percent == BACKLIGHT_DEFAULT)
+		percent = priv->dft_brightness;
+
+	if (percent < TEGRA_PWM_BL_MIN_BRIGHTNESS)
+		percent = TEGRA_PWM_BL_MIN_BRIGHTNESS;
+
+	if (percent > TEGRA_PWM_BL_MAX_BRIGHTNESS)
+		percent = TEGRA_PWM_BL_MAX_BRIGHTNESS;
+
+	ctrl = ((priv->period << PM_PERIOD_SHIFT) |
+		(priv->clk_div << PM_CLK_DIVIDER_SHIFT) |
+		 priv->clk_select);
+
+	/* The new value should be effected immediately */
+	cmd_state = readl(&cmd->state_access);
+	writel((cmd_state | (1 << 2)), &cmd->state_access);
+
+	switch (priv->pwm_source) {
+	case TEGRA_PWM_PM0:
+		/* Select the LM0 on PM0 */
+		out_sel = readl(&com->pin_output_sel[5]);
+		out_sel &= ~(7 << 0);
+		out_sel |= (3 << 0);
+		writel(out_sel, &com->pin_output_sel[5]);
+		writel(ctrl, &com->pm0_ctrl);
+		writel(percent, &com->pm0_duty_cycle);
+		break;
+	case TEGRA_PWM_PM1:
+		/* Select the LM1 on PM1 */
+		out_sel = readl(&com->pin_output_sel[5]);
+		out_sel &= ~(7 << 4);
+		out_sel |= (3 << 4);
+		writel(out_sel, &com->pin_output_sel[5]);
+		writel(ctrl, &com->pm1_ctrl);
+		writel(percent, &com->pm1_duty_cycle);
+		break;
+	default:
+		break;
+	}
+
+	writel(cmd_state, &cmd->state_access);
+	return 0;
+}
+
+static int tegra_pwm_backlight_enable(struct udevice *dev)
+{
+	struct tegra_pwm_backlight_priv *priv = dev_get_priv(dev);
+	return tegra_pwm_backlight_set_brightness(dev, priv->dft_brightness);
+}
+
+static int tegra_pwm_backlight_probe(struct udevice *dev)
+{
+	struct tegra_pwm_backlight_priv *priv = dev_get_priv(dev);
+
+	if (dev_read_bool(dev, "nvidia,display-b-base"))
+		priv->dc = (struct dc_ctlr *)TEGRA_DISPLAY_B_BASE;
+	else
+		priv->dc = (struct dc_ctlr *)TEGRA_DISPLAY_A_BASE;
+
+	if (!priv->dc) {
+		log_err("no display controller address\n");
+		return -EINVAL;
+	}
+
+	priv->pwm_source =
+		dev_read_u32_default(dev, "nvidia,pwm-source",
+				     TEGRA_PWM_PM0);
+	priv->period =
+		dev_read_u32_default(dev, "nvidia,period",
+				     TEGRA_PWM_BL_PERIOD);
+	priv->clk_div =
+		dev_read_u32_default(dev, "nvidia,clock-div",
+				     TEGRA_PWM_BL_CLK_DIV);
+	priv->clk_select =
+		dev_read_u32_default(dev, "nvidia,clock-select",
+				     TEGRA_PWM_BL_CLK_SELECT);
+	priv->dft_brightness =
+		dev_read_u32_default(dev, "nvidia,default-brightness",
+				     TEGRA_PWM_BL_MAX_BRIGHTNESS);
+
+	return 0;
+}
+
+static const struct backlight_ops tegra_pwm_backlight_ops = {
+	.enable = tegra_pwm_backlight_enable,
+	.set_brightness = tegra_pwm_backlight_set_brightness,
+};
+
+static const struct udevice_id tegra_pwm_backlight_ids[] = {
+	{ .compatible = "nvidia,tegra-pwm-backlight" },
+	{ }
+};
+
+U_BOOT_DRIVER(tegra_pwm_backlight) = {
+	.name		= "tegra_pwm_backlight",
+	.id		= UCLASS_PANEL_BACKLIGHT,
+	.of_match	= tegra_pwm_backlight_ids,
+	.probe		= tegra_pwm_backlight_probe,
+	.ops		= &tegra_pwm_backlight_ops,
+	.priv_auto	= sizeof(struct tegra_pwm_backlight_priv),
+};
-- 
2.37.2


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

* [PATCH v2 6/6] video: panel: add generic endeavoru panel
  2023-04-20 16:17 [PATCH v2 0/6] Add video drivers for endeavoru and p880/p895 Svyatoslav Ryhel
                   ` (4 preceding siblings ...)
  2023-04-20 16:17 ` [PATCH v2 5/6] video: tegra: add DC based PWM backlight driver Svyatoslav Ryhel
@ 2023-04-20 16:17 ` Svyatoslav Ryhel
  5 siblings, 0 replies; 7+ messages in thread
From: Svyatoslav Ryhel @ 2023-04-20 16:17 UTC (permalink / raw)
  To: Anatolij Gustschin, Simon Glass, Svyatoslav Ryhel; +Cc: u-boot

Family of panels used by HTC in One X. Though were used variants
at least from 3 vendors, this driver provides generic support for
all of them.

Tested-by: Ion Agorria <ion@agorria.com> # HTC One X T30 Sony
Tested-by: Svyatoslav Ryhel <clamor95@gmail.com> # HTC One X T30 Sharp
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/video/Kconfig           |  11 ++
 drivers/video/Makefile          |   1 +
 drivers/video/endeavoru-panel.c | 252 ++++++++++++++++++++++++++++++++
 3 files changed, 264 insertions(+)
 create mode 100644 drivers/video/endeavoru-panel.c

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index f5e3c713e5..86603342a3 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -466,6 +466,17 @@ config VIDEO_BCM2835
 	  that same resolution (or as near as possible) and 32bpp depth, so
 	  that U-Boot can access it with full colour depth.
 
+config VIDEO_LCD_ENDEAVORU
+	tristate "Endeavoru 720x1280 DSI video mode panel"
+	depends on PANEL && BACKLIGHT
+	select VIDEO_MIPI_DSI
+	help
+	  Say Y here if you want to enable support for the IPS-LCD panel
+	  module for HTC One X. Driver supports a family of panels,
+	  made at least by 3 vendors (Sharp, Sony and AUO), but set up
+	  using the same DSI command sequence. The panel has a 720x1280
+	  resolution and uses 24 bit RGB per pixel.
+
 config VIDEO_LCD_ORISETECH_OTM8009A
 	bool "OTM8009A DSI LCD panel support"
 	select VIDEO_MIPI_DSI
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index cddfc8fd33..4aff7771a8 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_VIDEO_EFI) += efi.o
 obj-$(CONFIG_VIDEO_IPUV3) += imx/
 obj-$(CONFIG_VIDEO_IVYBRIDGE_IGD) += ivybridge_igd.o
 obj-$(CONFIG_VIDEO_LCD_ANX9804) += anx9804.o
+obj-$(CONFIG_VIDEO_LCD_ENDEAVORU) += endeavoru-panel.o
 obj-$(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM) += hitachi_tx18d42vm_lcd.o
 obj-$(CONFIG_VIDEO_LCD_ORISETECH_OTM8009A) += orisetech_otm8009a.o
 obj-$(CONFIG_VIDEO_LCD_RAYDIUM_RM68200) += raydium-rm68200.o
diff --git a/drivers/video/endeavoru-panel.c b/drivers/video/endeavoru-panel.c
new file mode 100644
index 0000000000..2fbfc72ca6
--- /dev/null
+++ b/drivers/video/endeavoru-panel.c
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <common.h>
+#include <backlight.h>
+#include <dm.h>
+#include <panel.h>
+#include <log.h>
+#include <misc.h>
+#include <mipi_display.h>
+#include <mipi_dsi.h>
+#include <asm/gpio.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <power/regulator.h>
+
+struct endeavoru_panel_priv {
+	struct udevice *vdd;
+	struct udevice *vddio;
+
+	struct udevice *backlight;
+
+	struct gpio_desc reset_gpio;
+};
+
+static struct display_timing default_timing = {
+	.pixelclock.typ		= 63200000,
+	.hactive.typ		= 720,
+	.hfront_porch.typ	= 55,
+	.hback_porch.typ	= 29,
+	.hsync_len.typ		= 16,
+	.vactive.typ		= 1280,
+	.vfront_porch.typ	= 2,
+	.vback_porch.typ	= 1,
+	.vsync_len.typ		= 1,
+};
+
+static void dcs_write_one(struct mipi_dsi_device *dsi, u8 cmd, u8 data)
+{
+	mipi_dsi_dcs_write(dsi, cmd, &data, 1);
+}
+
+/*
+ * This panel is not able to auto-increment all cmd addresses so for some of
+ * them, we need to send them one by one...
+ */
+#define dcs_write_seq(dsi, cmd, seq...)			\
+({							\
+	static const u8 d[] = { seq };			\
+	unsigned int i;					\
+							\
+	for (i = 0; i < ARRAY_SIZE(d) ; i++)		\
+		dcs_write_one(dsi, cmd + i, d[i]);	\
+})
+
+static int endeavoru_panel_enable_backlight(struct udevice *dev)
+{
+	struct endeavoru_panel_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = dm_gpio_set_value(&priv->reset_gpio, 1);
+	if (ret) {
+		log_err("error changing reset-gpios (%d)\n", ret);
+		return ret;
+	}
+	mdelay(5);
+
+	ret = regulator_set_enable_if_allowed(priv->vddio, 1);
+	if (ret) {
+		log_err("error enabling iovcc-supply (%d)\n", ret);
+		return ret;
+	}
+	mdelay(1);
+
+	ret = regulator_set_enable_if_allowed(priv->vdd, 1);
+	if (ret) {
+		log_err("error enabling vcc-supply (%d)\n", ret);
+		return ret;
+	}
+	mdelay(20);
+
+	ret = dm_gpio_set_value(&priv->reset_gpio, 0);
+	if (ret) {
+		log_err("error changing reset-gpios (%d)\n", ret);
+		return ret;
+	}
+	mdelay(2);
+
+	/* Reset panel */
+	ret = dm_gpio_set_value(&priv->reset_gpio, 1);
+	if (ret) {
+		log_err("error changing reset-gpios (%d)\n", ret);
+		return ret;
+	}
+	mdelay(1);
+
+	ret = dm_gpio_set_value(&priv->reset_gpio, 0);
+	if (ret) {
+		log_err("error changing reset-gpios (%d)\n", ret);
+		return ret;
+	}
+	mdelay(25);
+
+	return 0;
+}
+
+static int endeavoru_panel_set_backlight(struct udevice *dev, int percent)
+{
+	struct endeavoru_panel_priv *priv = dev_get_priv(dev);
+	struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
+	struct mipi_dsi_device *dsi = plat->device;
+	int ret;
+
+	dcs_write_one(dsi, 0xc2, 0x08);
+
+	/* color enhancement 2.2 */
+	dcs_write_one(dsi, 0xff, 0x03);
+	dcs_write_one(dsi, 0xfe, 0x08);
+	dcs_write_one(dsi, 0x18, 0x00);
+	dcs_write_one(dsi, 0x19, 0x00);
+	dcs_write_one(dsi, 0x1a, 0x00);
+	dcs_write_one(dsi, 0x25, 0x26);
+
+	dcs_write_seq(dsi, 0x00, 0x00, 0x05, 0x10, 0x17,
+		     0x22, 0x26, 0x29, 0x29, 0x26, 0x23,
+		     0x17, 0x12, 0x06, 0x02, 0x01, 0x00);
+
+	dcs_write_one(dsi, 0xfb, 0x01);
+	dcs_write_one(dsi, 0xff, 0x00);
+	dcs_write_one(dsi, 0xfe, 0x01);
+
+	mipi_dsi_dcs_exit_sleep_mode(dsi);
+
+	mdelay(105);
+
+	dcs_write_one(dsi, 0x35, 0x00);
+
+	/* PWM frequency adjust */
+	dcs_write_one(dsi, 0xff, 0x04);
+	dcs_write_one(dsi, 0x0a, 0x07);
+	dcs_write_one(dsi, 0x09, 0x20);
+	dcs_write_one(dsi, 0xff, 0x00);
+
+	dcs_write_one(dsi, 0xff, 0xee);
+	dcs_write_one(dsi, 0x12, 0x50);
+	dcs_write_one(dsi, 0x13, 0x02);
+	dcs_write_one(dsi, 0x6a, 0x60);
+	dcs_write_one(dsi, 0xfb, 0x01);
+	dcs_write_one(dsi, 0xff, 0x00);
+
+	mipi_dsi_dcs_set_display_on(dsi);
+
+	mdelay(42);
+
+	dcs_write_one(dsi, 0xba, 0x01);
+
+	dcs_write_one(dsi, 0x53, 0x24);
+	dcs_write_one(dsi, 0x55, 0x80);
+	dcs_write_one(dsi, 0x5e, 0x06);
+
+	ret = backlight_enable(priv->backlight);
+	if (ret)
+		return ret;
+
+	/* Set backlight */
+	dcs_write_one(dsi, 0x51, 0x96);
+
+	ret = backlight_set_brightness(priv->backlight, percent);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int endeavoru_panel_timings(struct udevice *dev,
+				   struct display_timing *timing)
+{
+	memcpy(timing, &default_timing, sizeof(*timing));
+	return 0;
+}
+
+static int endeavoru_panel_of_to_plat(struct udevice *dev)
+{
+	struct endeavoru_panel_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
+					   "backlight", &priv->backlight);
+	if (ret) {
+		log_err("cannot get backlight: ret = %d\n", ret);
+		return ret;
+	}
+
+	ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
+					   "vdd-supply", &priv->vdd);
+	if (ret) {
+		log_err("cannot get vdd-supply: ret = %d\n", ret);
+		return ret;
+	}
+
+	ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
+					   "vddio-supply", &priv->vddio);
+	if (ret) {
+		log_err("cannot get vddio-supply: ret = %d\n", ret);
+		return ret;
+	}
+
+	ret = gpio_request_by_name(dev, "reset-gpios", 0,
+				   &priv->reset_gpio, GPIOD_IS_OUT);
+	if (ret) {
+		log_err("could not decode reser-gpios (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int endeavoru_panel_probe(struct udevice *dev)
+{
+	struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
+
+	/* fill characteristics of DSI data link */
+	plat->lanes = 2;
+	plat->format = MIPI_DSI_FMT_RGB888;
+	plat->mode_flags = MIPI_DSI_MODE_VIDEO;
+
+	return 0;
+}
+
+static const struct panel_ops endeavoru_panel_ops = {
+	.enable_backlight	= endeavoru_panel_enable_backlight,
+	.set_backlight		= endeavoru_panel_set_backlight,
+	.get_display_timing	= endeavoru_panel_timings,
+};
+
+static const struct udevice_id endeavoru_panel_ids[] = {
+	{ .compatible = "htc,edge-panel" },
+	{ }
+};
+
+U_BOOT_DRIVER(endeavoru_panel) = {
+	.name		= "endeavoru_panel",
+	.id		= UCLASS_PANEL,
+	.of_match	= endeavoru_panel_ids,
+	.ops		= &endeavoru_panel_ops,
+	.of_to_plat	= endeavoru_panel_of_to_plat,
+	.probe		= endeavoru_panel_probe,
+	.plat_auto	= sizeof(struct mipi_dsi_panel_plat),
+	.priv_auto	= sizeof(struct endeavoru_panel_priv),
+};
-- 
2.37.2


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

end of thread, other threads:[~2023-04-20 16:19 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-04-20 16:17 [PATCH v2 0/6] Add video drivers for endeavoru and p880/p895 Svyatoslav Ryhel
2023-04-20 16:17 ` [PATCH v2 1/6] video: add lm3533 backlight driver Svyatoslav Ryhel
2023-04-20 16:17 ` [PATCH v2 2/6] video: bridge: add Solomon SSD2825 DSI/LVDS driver Svyatoslav Ryhel
2023-04-20 16:17 ` [PATCH v2 3/6] video: panel: add Renesas R61307 MIPI DSI panel driver Svyatoslav Ryhel
2023-04-20 16:17 ` [PATCH v2 4/6] video: panel: add Renesas R69328 " Svyatoslav Ryhel
2023-04-20 16:17 ` [PATCH v2 5/6] video: tegra: add DC based PWM backlight driver Svyatoslav Ryhel
2023-04-20 16:17 ` [PATCH v2 6/6] video: panel: add generic endeavoru panel Svyatoslav Ryhel

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).