diff mbox

[U-Boot,4/5] video: Add support for the ANX9804 parallel lcd to dp bridge chip

Message ID 1439043904-31492-5-git-send-email-hdegoede@redhat.com
State Accepted
Delegated to: Hans de Goede
Headers show

Commit Message

Hans de Goede Aug. 8, 2015, 2:25 p.m. UTC
Add support for the ANX9804 bridge chip, which can take pixel data coming
from a parallel LCD interface and translate it on the flight into a DP
interface for driving eDP TFT displays. It uses I2C for configuration.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/video/Kconfig   |   8 +++
 drivers/video/Makefile  |   1 +
 drivers/video/anx9804.c | 188 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/video/anx9804.h |  25 +++++++
 4 files changed, 222 insertions(+)
 create mode 100755 drivers/video/anx9804.c
 create mode 100644 drivers/video/anx9804.h

Comments

Ian Campbell Aug. 11, 2015, 7:53 a.m. UTC | #1
On Sat, 2015-08-08 at 16:25 +0200, Hans de Goede wrote:
> Add support for the ANX9804 bridge chip, which can take pixel data coming
> from a parallel LCD interface and translate it on the flight into a DP

I think you meant "on the fly" (in the Kconfig too).

The driver itself looks pretty straight forward to me, but I'll leave
it to Anatolij to formally ack.
Hans de Goede Aug. 12, 2015, 4:04 p.m. UTC | #2
Hi,

On 08/11/2015 09:53 AM, Ian Campbell wrote:
> On Sat, 2015-08-08 at 16:25 +0200, Hans de Goede wrote:
>> Add support for the ANX9804 bridge chip, which can take pixel data coming
>> from a parallel LCD interface and translate it on the flight into a DP
>
> I think you meant "on the fly" (in the Kconfig too).

Thanks, fixed in my personal tree.

Regards,

Hans
Anatolij Gustschin Aug. 12, 2015, 10:31 p.m. UTC | #3
On Sat,  8 Aug 2015 16:25:03 +0200
Hans de Goede <hdegoede@redhat.com> wrote:

> Add support for the ANX9804 bridge chip, which can take pixel data coming
> from a parallel LCD interface and translate it on the flight into a DP
> interface for driving eDP TFT displays. It uses I2C for configuration.
> 
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>

Acked-by: Anatolij Gustschin <agust@denx.de>
diff mbox

Patch

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 9ae23e8..71cbff9 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -145,6 +145,14 @@  config FRAMEBUFFER_VESA_MODE
 	default 0x11B if FRAMEBUFFER_VESA_MODE_11B
 	default 0x117 if FRAMEBUFFER_VESA_MODE_USER
 
+config VIDEO_LCD_ANX9804
+	bool "ANX9804 bridge chip"
+	default n
+	---help---
+	Support for the ANX9804 bridge chip, which can take pixel data coming
+	from a parallel LCD interface and translate it on the flight into a DP
+	interface for driving eDP TFT displays. It uses I2C for configuration.
+
 config VIDEO_LCD_SSD2828
 	bool "SSD2828 bridge chip"
 	default n
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 2ead7f1..e414e8c 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -33,6 +33,7 @@  obj-$(CONFIG_VIDEO_COREBOOT) += coreboot_fb.o
 obj-$(CONFIG_VIDEO_CT69000) += ct69000.o videomodes.o
 obj-$(CONFIG_VIDEO_DA8XX) += da8xx-fb.o videomodes.o
 obj-$(CONFIG_VIDEO_IMX25LCDC) += imx25lcdc.o videomodes.o
+obj-$(CONFIG_VIDEO_LCD_ANX9804) += anx9804.o
 obj-$(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM) += hitachi_tx18d42vm_lcd.o
 obj-$(CONFIG_VIDEO_LCD_SSD2828) += ssd2828.o
 obj-$(CONFIG_VIDEO_MB862xx) += mb862xx.o videomodes.o
diff --git a/drivers/video/anx9804.c b/drivers/video/anx9804.c
new file mode 100755
index 0000000..83d60d6
--- /dev/null
+++ b/drivers/video/anx9804.c
@@ -0,0 +1,188 @@ 
+/*
+ * (C) 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/*
+ * Support for the ANX9804 bridge chip, which can take pixel data coming
+ * from a parallel LCD interface and translate it on the flight into a DP
+ * interface for driving eDP TFT displays.
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include "anx9804.h"
+
+#define BIT(x) (1 << (x))
+
+/* Registers at i2c address 0x38 */
+
+#define ANX9804_HDCP_CONTROL_0_REG				0x01
+
+#define ANX9804_SYS_CTRL2_REG					0x81
+#define ANX9804_SYS_CTRL2_CHA_STA				0x04
+
+#define ANX9804_SYS_CTRL3_REG					0x82
+#define ANX9804_SYS_CTRL3_VALID_CTRL				BIT(0)
+#define ANX9804_SYS_CTRL3_F_VALID				BIT(1)
+#define ANX9804_SYS_CTRL3_HPD_CTRL				BIT(4)
+#define ANX9804_SYS_CTRL3_F_HPD					BIT(5)
+
+#define ANX9804_LINK_BW_SET_REG					0xa0
+#define ANX9804_LANE_COUNT_SET_REG				0xa1
+#define ANX9804_TRAINING_PTN_SET_REG				0xa2
+#define ANX9804_TRAINING_LANE0_SET_REG				0xa3
+#define ANX9804_TRAINING_LANE1_SET_REG				0xa4
+#define ANX9804_TRAINING_LANE2_SET_REG				0xa5
+#define ANX9804_TRAINING_LANE3_SET_REG				0xa6
+
+#define ANX9804_LINK_TRAINING_CTRL_REG				0xa8
+#define ANX9804_LINK_TRAINING_CTRL_EN				BIT(0)
+
+#define ANX9804_LINK_DEBUG_REG					0xb8
+#define ANX9804_PLL_CTRL_REG					0xc7	
+#define ANX9804_ANALOG_POWER_DOWN_REG				0xc8
+
+/* Registers at i2c address 0x39 */
+
+#define ANX9804_DEV_IDH_REG					0x03
+
+#define ANX9804_POWERD_CTRL_REG					0x05
+#define ANX9804_POWERD_AUDIO					BIT(4)
+
+#define ANX9804_RST_CTRL_REG					0x06
+
+#define ANX9804_RST_CTRL2_REG					0x07
+#define ANX9804_RST_CTRL2_AUX					BIT(2)
+#define ANX9804_RST_CTRL2_AC_MODE				BIT(6)
+
+#define ANX9804_VID_CTRL1_REG					0x08
+#define ANX9804_VID_CTRL1_VID_EN				BIT(7)
+#define ANX9804_VID_CTRL1_EDGE					BIT(0)
+
+#define ANX9804_VID_CTRL2_REG					0x09
+#define ANX9804_ANALOG_DEBUG_REG1				0xdc
+#define ANX9804_ANALOG_DEBUG_REG3				0xde
+#define ANX9804_PLL_FILTER_CTRL1				0xdf
+#define ANX9804_PLL_FILTER_CTRL3				0xe1
+#define ANX9804_PLL_FILTER_CTRL					0xe2
+#define ANX9804_PLL_CTRL3					0xe6
+
+/**
+ * anx9804_init() - Init anx9804 parallel lcd to edp bridge chip
+ *
+ * This function will init an anx9804 parallel lcd to dp bridge chip
+ * using the passed in parameters.
+ *
+ * @i2c_bus:	Number of the i2c bus to which the anx9804 is connected.
+ * @lanes:	Number of displayport lanes to use
+ * @data_rate:	Register value for the bandwidth reg 0x06: 1.62G, 0x0a: 2.7G
+ * @bpp:	Bits per pixel, must be 18 or 24
+ */
+void anx9804_init(unsigned int i2c_bus, u8 lanes, u8 data_rate, int bpp)
+{
+	unsigned int orig_i2c_bus = i2c_get_bus_num();
+	u8 c, colordepth;
+	int i;
+
+	i2c_set_bus_num(i2c_bus);
+
+	if (bpp == 18)
+		colordepth = 0x00; /* 6 bit */
+	else
+		colordepth = 0x10; /* 8 bit */
+
+	/* Reset */
+	i2c_reg_write(0x39, ANX9804_RST_CTRL_REG, 1);
+	mdelay(100);
+	i2c_reg_write(0x39, ANX9804_RST_CTRL_REG, 0);
+
+	/* Write 0 to the powerdown reg (powerup everything) */
+	i2c_reg_write(0x39, ANX9804_POWERD_CTRL_REG, 0);
+
+	c = i2c_reg_read(0x39, ANX9804_DEV_IDH_REG);
+	if (c != 0x98) {
+		printf("Error anx9804 chipid mismatch\n");
+		i2c_set_bus_num(orig_i2c_bus);
+		return;
+	}
+
+	for (i = 0; i < 100; i++) {
+		c = i2c_reg_read(0x38, ANX9804_SYS_CTRL2_REG);
+		i2c_reg_write(0x38, ANX9804_SYS_CTRL2_REG, c);
+		c = i2c_reg_read(0x38, ANX9804_SYS_CTRL2_REG);
+		if ((c & ANX9804_SYS_CTRL2_CHA_STA) == 0)
+			break;
+
+		mdelay(5);
+	}
+	if (i == 100)
+		printf("Error anx9804 clock is not stable\n");
+
+	i2c_reg_write(0x39, ANX9804_VID_CTRL2_REG, colordepth);
+	
+	/* Set a bunch of analog related register values */
+	i2c_reg_write(0x38, ANX9804_PLL_CTRL_REG, 0x07); 
+	i2c_reg_write(0x39, ANX9804_PLL_FILTER_CTRL3, 0x19); 
+	i2c_reg_write(0x39, ANX9804_PLL_CTRL3, 0xd9); 
+	i2c_reg_write(0x39, ANX9804_RST_CTRL2_REG, ANX9804_RST_CTRL2_AC_MODE);
+	i2c_reg_write(0x39, ANX9804_ANALOG_DEBUG_REG1, 0xf0);
+	i2c_reg_write(0x39, ANX9804_ANALOG_DEBUG_REG3, 0x99);
+	i2c_reg_write(0x39, ANX9804_PLL_FILTER_CTRL1, 0x7b);
+	i2c_reg_write(0x38, ANX9804_LINK_DEBUG_REG, 0x30);
+	i2c_reg_write(0x39, ANX9804_PLL_FILTER_CTRL, 0x06);
+
+	/* Force HPD */
+	i2c_reg_write(0x38, ANX9804_SYS_CTRL3_REG,
+		      ANX9804_SYS_CTRL3_F_HPD | ANX9804_SYS_CTRL3_HPD_CTRL);
+
+	/* Power up and configure lanes */
+	i2c_reg_write(0x38, ANX9804_ANALOG_POWER_DOWN_REG, 0x00);
+	i2c_reg_write(0x38, ANX9804_TRAINING_LANE0_SET_REG, 0x00);
+	i2c_reg_write(0x38, ANX9804_TRAINING_LANE1_SET_REG, 0x00);
+	i2c_reg_write(0x38, ANX9804_TRAINING_LANE2_SET_REG, 0x00);
+	i2c_reg_write(0x38, ANX9804_TRAINING_LANE3_SET_REG, 0x00);
+
+	/* Reset AUX CH */
+	i2c_reg_write(0x39, ANX9804_RST_CTRL2_REG,
+		      ANX9804_RST_CTRL2_AC_MODE | ANX9804_RST_CTRL2_AUX);
+	i2c_reg_write(0x39, ANX9804_RST_CTRL2_REG,
+		      ANX9804_RST_CTRL2_AC_MODE);
+
+	/* Powerdown audio and some other unused bits */
+	i2c_reg_write(0x39, ANX9804_POWERD_CTRL_REG, ANX9804_POWERD_AUDIO);
+	i2c_reg_write(0x38, ANX9804_HDCP_CONTROL_0_REG, 0x00);
+	i2c_reg_write(0x38, 0xa7, 0x00);
+
+	/* Set data-rate / lanes */
+	i2c_reg_write(0x38, ANX9804_LINK_BW_SET_REG, data_rate);
+	i2c_reg_write(0x38, ANX9804_LANE_COUNT_SET_REG, lanes);
+
+	/* Link training */	
+	i2c_reg_write(0x38, ANX9804_LINK_TRAINING_CTRL_REG,
+		      ANX9804_LINK_TRAINING_CTRL_EN);
+	mdelay(5);
+	for (i = 0; i < 100; i++) {
+		c = i2c_reg_read(0x38, ANX9804_LINK_TRAINING_CTRL_REG);
+		if ((c & 0x01) == 0)
+			break;
+
+		mdelay(5);
+	}
+	if(i == 100) {
+		printf("Error anx9804 link training timeout\n");
+		i2c_set_bus_num(orig_i2c_bus);
+		return;
+	}
+
+	/* Enable */
+	i2c_reg_write(0x39, ANX9804_VID_CTRL1_REG,
+		      ANX9804_VID_CTRL1_VID_EN | ANX9804_VID_CTRL1_EDGE);
+	/* Force stream valid */
+	i2c_reg_write(0x38, ANX9804_SYS_CTRL3_REG,
+		      ANX9804_SYS_CTRL3_F_HPD | ANX9804_SYS_CTRL3_HPD_CTRL |
+		      ANX9804_SYS_CTRL3_F_VALID | ANX9804_SYS_CTRL3_VALID_CTRL);
+
+	i2c_set_bus_num(orig_i2c_bus);
+}
diff --git a/drivers/video/anx9804.h b/drivers/video/anx9804.h
new file mode 100644
index 0000000..6c5daf9
--- /dev/null
+++ b/drivers/video/anx9804.h
@@ -0,0 +1,25 @@ 
+/*
+ * (C) 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/*
+ * Support for the ANX9804 bridge chip, which can take pixel data coming
+ * from a parallel LCD interface and translate it on the flight into a DP
+ * interface for driving eDP TFT displays.
+ */
+
+#ifndef _ANX9804_H
+#define _ANX9804_H
+
+#define ANX9804_DATA_RATE_1620M				0x06
+#define ANX9804_DATA_RATE_2700M				0x0a
+
+#ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
+void anx9804_init(unsigned int i2c_bus, u8 lanes, u8 data_rate, int bpp);
+#else
+static inline void anx9804_init(unsigned int i2c_bus, u8 lanes, u8 data_rate,
+				int bpp) {}
+#endif
+#endif