xref: /rk3399_rockchip-uboot/drivers/video/bridge/anx6345.c (revision c52351ffbe8d698997ed6d1eaedc72399a017ebb)
196b9f0a7SVasily Khoruzhick /*
296b9f0a7SVasily Khoruzhick  * Copyright (C) 2017 Vasily Khoruzhick <anarsoul@gmail.com>
396b9f0a7SVasily Khoruzhick  *
496b9f0a7SVasily Khoruzhick  * SPDX-License-Identifier:	GPL-2.0+
596b9f0a7SVasily Khoruzhick  */
696b9f0a7SVasily Khoruzhick 
796b9f0a7SVasily Khoruzhick #include <common.h>
896b9f0a7SVasily Khoruzhick #include <dm.h>
996b9f0a7SVasily Khoruzhick #include <errno.h>
1096b9f0a7SVasily Khoruzhick #include <i2c.h>
1196b9f0a7SVasily Khoruzhick #include <edid.h>
1296b9f0a7SVasily Khoruzhick #include <video_bridge.h>
1396b9f0a7SVasily Khoruzhick #include "../anx98xx-edp.h"
14*c52351ffSWyon Bi #include "../drm/rockchip_bridge.h"
1596b9f0a7SVasily Khoruzhick 
1696b9f0a7SVasily Khoruzhick #define DP_MAX_LINK_RATE		0x001
1796b9f0a7SVasily Khoruzhick #define DP_MAX_LANE_COUNT		0x002
1896b9f0a7SVasily Khoruzhick #define DP_MAX_LANE_COUNT_MASK		0x1f
1996b9f0a7SVasily Khoruzhick 
2096b9f0a7SVasily Khoruzhick DECLARE_GLOBAL_DATA_PTR;
2196b9f0a7SVasily Khoruzhick 
2296b9f0a7SVasily Khoruzhick struct anx6345_priv {
23*c52351ffSWyon Bi 	u8 chipid;
2496b9f0a7SVasily Khoruzhick 	u8 edid[EDID_SIZE];
2596b9f0a7SVasily Khoruzhick };
2696b9f0a7SVasily Khoruzhick 
anx6345_write(struct udevice * dev,unsigned int addr_off,unsigned char reg_addr,unsigned char value)2796b9f0a7SVasily Khoruzhick static int anx6345_write(struct udevice *dev, unsigned int addr_off,
2896b9f0a7SVasily Khoruzhick 			 unsigned char reg_addr, unsigned char value)
2996b9f0a7SVasily Khoruzhick {
3096b9f0a7SVasily Khoruzhick 	uint8_t buf[2];
3196b9f0a7SVasily Khoruzhick 	struct i2c_msg msg;
3296b9f0a7SVasily Khoruzhick 	int ret;
3396b9f0a7SVasily Khoruzhick 
3496b9f0a7SVasily Khoruzhick 	msg.addr = addr_off;
3596b9f0a7SVasily Khoruzhick 	msg.flags = 0;
3696b9f0a7SVasily Khoruzhick 	buf[0] = reg_addr;
3796b9f0a7SVasily Khoruzhick 	buf[1] = value;
3896b9f0a7SVasily Khoruzhick 	msg.buf = buf;
3996b9f0a7SVasily Khoruzhick 	msg.len = 2;
4096b9f0a7SVasily Khoruzhick 	ret = dm_i2c_xfer(dev, &msg, 1);
4196b9f0a7SVasily Khoruzhick 	if (ret) {
4296b9f0a7SVasily Khoruzhick 		debug("%s: write failed, reg=%#x, value=%#x, ret=%d\n",
4396b9f0a7SVasily Khoruzhick 		      __func__, reg_addr, value, ret);
4496b9f0a7SVasily Khoruzhick 		return ret;
4596b9f0a7SVasily Khoruzhick 	}
4696b9f0a7SVasily Khoruzhick 
4796b9f0a7SVasily Khoruzhick 	return 0;
4896b9f0a7SVasily Khoruzhick }
4996b9f0a7SVasily Khoruzhick 
anx6345_read(struct udevice * dev,unsigned int addr_off,unsigned char reg_addr,unsigned char * value)5096b9f0a7SVasily Khoruzhick static int anx6345_read(struct udevice *dev, unsigned int addr_off,
5196b9f0a7SVasily Khoruzhick 			unsigned char reg_addr, unsigned char *value)
5296b9f0a7SVasily Khoruzhick {
5396b9f0a7SVasily Khoruzhick 	uint8_t addr, val;
5496b9f0a7SVasily Khoruzhick 	struct i2c_msg msg[2];
5596b9f0a7SVasily Khoruzhick 	int ret;
5696b9f0a7SVasily Khoruzhick 
5796b9f0a7SVasily Khoruzhick 	msg[0].addr = addr_off;
5896b9f0a7SVasily Khoruzhick 	msg[0].flags = 0;
5996b9f0a7SVasily Khoruzhick 	addr = reg_addr;
6096b9f0a7SVasily Khoruzhick 	msg[0].buf = &addr;
6196b9f0a7SVasily Khoruzhick 	msg[0].len = 1;
6296b9f0a7SVasily Khoruzhick 	msg[1].addr = addr_off;
6396b9f0a7SVasily Khoruzhick 	msg[1].flags = I2C_M_RD;
6496b9f0a7SVasily Khoruzhick 	msg[1].buf = &val;
6596b9f0a7SVasily Khoruzhick 	msg[1].len = 1;
6696b9f0a7SVasily Khoruzhick 	ret = dm_i2c_xfer(dev, msg, 2);
6796b9f0a7SVasily Khoruzhick 	if (ret) {
6896b9f0a7SVasily Khoruzhick 		debug("%s: read failed, reg=%.2x, value=%p, ret=%d\n",
6996b9f0a7SVasily Khoruzhick 		      __func__, (int)reg_addr, value, ret);
7096b9f0a7SVasily Khoruzhick 		return ret;
7196b9f0a7SVasily Khoruzhick 	}
7296b9f0a7SVasily Khoruzhick 	*value = val;
7396b9f0a7SVasily Khoruzhick 
7496b9f0a7SVasily Khoruzhick 	return 0;
7596b9f0a7SVasily Khoruzhick }
7696b9f0a7SVasily Khoruzhick 
anx6345_write_r0(struct udevice * dev,unsigned char reg_addr,unsigned char value)7796b9f0a7SVasily Khoruzhick static int anx6345_write_r0(struct udevice *dev, unsigned char reg_addr,
7896b9f0a7SVasily Khoruzhick 			    unsigned char value)
7996b9f0a7SVasily Khoruzhick {
8096b9f0a7SVasily Khoruzhick 	struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
8196b9f0a7SVasily Khoruzhick 
8296b9f0a7SVasily Khoruzhick 	return anx6345_write(dev, chip->chip_addr, reg_addr, value);
8396b9f0a7SVasily Khoruzhick }
8496b9f0a7SVasily Khoruzhick 
anx6345_read_r0(struct udevice * dev,unsigned char reg_addr,unsigned char * value)8596b9f0a7SVasily Khoruzhick static int anx6345_read_r0(struct udevice *dev, unsigned char reg_addr,
8696b9f0a7SVasily Khoruzhick 			   unsigned char *value)
8796b9f0a7SVasily Khoruzhick {
8896b9f0a7SVasily Khoruzhick 	struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
8996b9f0a7SVasily Khoruzhick 
9096b9f0a7SVasily Khoruzhick 	return anx6345_read(dev, chip->chip_addr, reg_addr, value);
9196b9f0a7SVasily Khoruzhick }
9296b9f0a7SVasily Khoruzhick 
anx6345_write_r1(struct udevice * dev,unsigned char reg_addr,unsigned char value)9396b9f0a7SVasily Khoruzhick static int anx6345_write_r1(struct udevice *dev, unsigned char reg_addr,
9496b9f0a7SVasily Khoruzhick 			    unsigned char value)
9596b9f0a7SVasily Khoruzhick {
9696b9f0a7SVasily Khoruzhick 	struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
9796b9f0a7SVasily Khoruzhick 
9896b9f0a7SVasily Khoruzhick 	return anx6345_write(dev, chip->chip_addr + 1, reg_addr, value);
9996b9f0a7SVasily Khoruzhick }
10096b9f0a7SVasily Khoruzhick 
anx6345_read_r1(struct udevice * dev,unsigned char reg_addr,unsigned char * value)10196b9f0a7SVasily Khoruzhick static int anx6345_read_r1(struct udevice *dev, unsigned char reg_addr,
10296b9f0a7SVasily Khoruzhick 			   unsigned char *value)
10396b9f0a7SVasily Khoruzhick {
10496b9f0a7SVasily Khoruzhick 	struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
10596b9f0a7SVasily Khoruzhick 
10696b9f0a7SVasily Khoruzhick 	return anx6345_read(dev, chip->chip_addr + 1, reg_addr, value);
10796b9f0a7SVasily Khoruzhick }
10896b9f0a7SVasily Khoruzhick 
anx6345_set_backlight(struct udevice * dev,int percent)10996b9f0a7SVasily Khoruzhick static int anx6345_set_backlight(struct udevice *dev, int percent)
11096b9f0a7SVasily Khoruzhick {
11196b9f0a7SVasily Khoruzhick 	return -ENOSYS;
11296b9f0a7SVasily Khoruzhick }
11396b9f0a7SVasily Khoruzhick 
anx6345_aux_wait(struct udevice * dev)11496b9f0a7SVasily Khoruzhick static int anx6345_aux_wait(struct udevice *dev)
11596b9f0a7SVasily Khoruzhick {
11696b9f0a7SVasily Khoruzhick 	int ret = -ETIMEDOUT;
11796b9f0a7SVasily Khoruzhick 	u8 v;
11896b9f0a7SVasily Khoruzhick 	int retries = 1000;
11996b9f0a7SVasily Khoruzhick 
12096b9f0a7SVasily Khoruzhick 	do {
12196b9f0a7SVasily Khoruzhick 		anx6345_read_r0(dev, ANX9804_DP_AUX_CH_CTL_2, &v);
12296b9f0a7SVasily Khoruzhick 		if (!(v & ANX9804_AUX_EN)) {
12396b9f0a7SVasily Khoruzhick 			ret = 0;
12496b9f0a7SVasily Khoruzhick 			break;
12596b9f0a7SVasily Khoruzhick 		}
12696b9f0a7SVasily Khoruzhick 		udelay(100);
12796b9f0a7SVasily Khoruzhick 	} while (retries--);
12896b9f0a7SVasily Khoruzhick 
12996b9f0a7SVasily Khoruzhick 	if (ret) {
13096b9f0a7SVasily Khoruzhick 		debug("%s: timed out waiting for AUX_EN to clear\n", __func__);
13196b9f0a7SVasily Khoruzhick 		return ret;
13296b9f0a7SVasily Khoruzhick 	}
13396b9f0a7SVasily Khoruzhick 
13496b9f0a7SVasily Khoruzhick 	ret = -ETIMEDOUT;
13596b9f0a7SVasily Khoruzhick 	retries = 1000;
13696b9f0a7SVasily Khoruzhick 	do {
13796b9f0a7SVasily Khoruzhick 		anx6345_read_r1(dev, ANX9804_DP_INT_STA, &v);
13896b9f0a7SVasily Khoruzhick 		if (v & ANX9804_RPLY_RECEIV) {
13996b9f0a7SVasily Khoruzhick 			ret = 0;
14096b9f0a7SVasily Khoruzhick 			break;
14196b9f0a7SVasily Khoruzhick 		}
14296b9f0a7SVasily Khoruzhick 		udelay(100);
14396b9f0a7SVasily Khoruzhick 	} while (retries--);
14496b9f0a7SVasily Khoruzhick 
14596b9f0a7SVasily Khoruzhick 	if (ret) {
14696b9f0a7SVasily Khoruzhick 		debug("%s: timed out waiting to receive reply\n", __func__);
14796b9f0a7SVasily Khoruzhick 		return ret;
14896b9f0a7SVasily Khoruzhick 	}
14996b9f0a7SVasily Khoruzhick 
15096b9f0a7SVasily Khoruzhick 	/* Clear RPLY_RECEIV bit */
15196b9f0a7SVasily Khoruzhick 	anx6345_write_r1(dev, ANX9804_DP_INT_STA, v);
15296b9f0a7SVasily Khoruzhick 
15396b9f0a7SVasily Khoruzhick 	anx6345_read_r0(dev, ANX9804_AUX_CH_STA, &v);
15496b9f0a7SVasily Khoruzhick 	if ((v & ANX9804_AUX_STATUS_MASK) != 0) {
15596b9f0a7SVasily Khoruzhick 		debug("AUX status: %d\n", v & ANX9804_AUX_STATUS_MASK);
15696b9f0a7SVasily Khoruzhick 		ret = -EIO;
15796b9f0a7SVasily Khoruzhick 	}
15896b9f0a7SVasily Khoruzhick 
15996b9f0a7SVasily Khoruzhick 	return ret;
16096b9f0a7SVasily Khoruzhick }
16196b9f0a7SVasily Khoruzhick 
anx6345_aux_addr(struct udevice * dev,u32 addr)16296b9f0a7SVasily Khoruzhick static void anx6345_aux_addr(struct udevice *dev, u32 addr)
16396b9f0a7SVasily Khoruzhick {
16496b9f0a7SVasily Khoruzhick 	u8 val;
16596b9f0a7SVasily Khoruzhick 
16696b9f0a7SVasily Khoruzhick 	val = addr & 0xff;
16796b9f0a7SVasily Khoruzhick 	anx6345_write_r0(dev, ANX9804_DP_AUX_ADDR_7_0, val);
16896b9f0a7SVasily Khoruzhick 	val = (addr >> 8) & 0xff;
16996b9f0a7SVasily Khoruzhick 	anx6345_write_r0(dev, ANX9804_DP_AUX_ADDR_15_8, val);
17096b9f0a7SVasily Khoruzhick 	val = (addr >> 16) & 0x0f;
17196b9f0a7SVasily Khoruzhick 	anx6345_write_r0(dev, ANX9804_DP_AUX_ADDR_19_16, val);
17296b9f0a7SVasily Khoruzhick }
17396b9f0a7SVasily Khoruzhick 
anx6345_aux_transfer(struct udevice * dev,u8 req,u32 addr,u8 * buf,size_t len)17496b9f0a7SVasily Khoruzhick static int anx6345_aux_transfer(struct udevice *dev, u8 req,
17596b9f0a7SVasily Khoruzhick 				u32 addr, u8 *buf, size_t len)
17696b9f0a7SVasily Khoruzhick {
17796b9f0a7SVasily Khoruzhick 	int i, ret;
17896b9f0a7SVasily Khoruzhick 	u8 ctrl1 = req;
17996b9f0a7SVasily Khoruzhick 	u8 ctrl2 = ANX9804_AUX_EN;
18096b9f0a7SVasily Khoruzhick 
18196b9f0a7SVasily Khoruzhick 	if (len > 16)
18296b9f0a7SVasily Khoruzhick 		return -E2BIG;
18396b9f0a7SVasily Khoruzhick 
18496b9f0a7SVasily Khoruzhick 	if (len)
18596b9f0a7SVasily Khoruzhick 		ctrl1 |= ANX9804_AUX_LENGTH(len);
18696b9f0a7SVasily Khoruzhick 	else
18796b9f0a7SVasily Khoruzhick 		ctrl2 |= ANX9804_ADDR_ONLY;
18896b9f0a7SVasily Khoruzhick 
18996b9f0a7SVasily Khoruzhick 	if (len && !(req & ANX9804_AUX_TX_COMM_READ)) {
19096b9f0a7SVasily Khoruzhick 		for (i = 0; i < len; i++)
19196b9f0a7SVasily Khoruzhick 			anx6345_write_r0(dev, ANX9804_BUF_DATA_0 + i, buf[i]);
19296b9f0a7SVasily Khoruzhick 	}
19396b9f0a7SVasily Khoruzhick 
19496b9f0a7SVasily Khoruzhick 	anx6345_aux_addr(dev, addr);
19596b9f0a7SVasily Khoruzhick 	anx6345_write_r0(dev, ANX9804_DP_AUX_CH_CTL_1, ctrl1);
19696b9f0a7SVasily Khoruzhick 	anx6345_write_r0(dev, ANX9804_DP_AUX_CH_CTL_2, ctrl2);
19796b9f0a7SVasily Khoruzhick 	ret = anx6345_aux_wait(dev);
19896b9f0a7SVasily Khoruzhick 	if (ret) {
19996b9f0a7SVasily Khoruzhick 		debug("AUX transaction timed out\n");
20096b9f0a7SVasily Khoruzhick 		return ret;
20196b9f0a7SVasily Khoruzhick 	}
20296b9f0a7SVasily Khoruzhick 
20396b9f0a7SVasily Khoruzhick 	if (len && (req & ANX9804_AUX_TX_COMM_READ)) {
20496b9f0a7SVasily Khoruzhick 		for (i = 0; i < len; i++)
20596b9f0a7SVasily Khoruzhick 			anx6345_read_r0(dev, ANX9804_BUF_DATA_0 + i, &buf[i]);
20696b9f0a7SVasily Khoruzhick 	}
20796b9f0a7SVasily Khoruzhick 
20896b9f0a7SVasily Khoruzhick 	return 0;
20996b9f0a7SVasily Khoruzhick }
21096b9f0a7SVasily Khoruzhick 
anx6345_read_aux_i2c(struct udevice * dev,u8 chip_addr,u8 offset,size_t count,u8 * buf)21196b9f0a7SVasily Khoruzhick static int anx6345_read_aux_i2c(struct udevice *dev, u8 chip_addr,
21296b9f0a7SVasily Khoruzhick 				u8 offset, size_t count, u8 *buf)
21396b9f0a7SVasily Khoruzhick {
21496b9f0a7SVasily Khoruzhick 	int i, ret;
21596b9f0a7SVasily Khoruzhick 	size_t cur_cnt;
21696b9f0a7SVasily Khoruzhick 	u8 cur_offset;
21796b9f0a7SVasily Khoruzhick 
21896b9f0a7SVasily Khoruzhick 	for (i = 0; i < count; i += 16) {
21996b9f0a7SVasily Khoruzhick 		cur_cnt = (count - i) > 16 ? 16 : count - i;
22096b9f0a7SVasily Khoruzhick 		cur_offset = offset + i;
22196b9f0a7SVasily Khoruzhick 		ret = anx6345_aux_transfer(dev, ANX9804_AUX_TX_COMM_MOT,
22296b9f0a7SVasily Khoruzhick 					   chip_addr, &cur_offset, 1);
22396b9f0a7SVasily Khoruzhick 		if (ret) {
22496b9f0a7SVasily Khoruzhick 			debug("%s: failed to set i2c offset: %d\n",
22596b9f0a7SVasily Khoruzhick 			      __func__, ret);
22696b9f0a7SVasily Khoruzhick 			return ret;
22796b9f0a7SVasily Khoruzhick 		}
22896b9f0a7SVasily Khoruzhick 		ret = anx6345_aux_transfer(dev, ANX9804_AUX_TX_COMM_READ,
22996b9f0a7SVasily Khoruzhick 					   chip_addr, buf + i, cur_cnt);
23096b9f0a7SVasily Khoruzhick 		if (ret) {
23196b9f0a7SVasily Khoruzhick 			debug("%s: failed to read from i2c device: %d\n",
23296b9f0a7SVasily Khoruzhick 			      __func__, ret);
23396b9f0a7SVasily Khoruzhick 			return ret;
23496b9f0a7SVasily Khoruzhick 		}
23596b9f0a7SVasily Khoruzhick 	}
23696b9f0a7SVasily Khoruzhick 
23796b9f0a7SVasily Khoruzhick 	return 0;
23896b9f0a7SVasily Khoruzhick }
23996b9f0a7SVasily Khoruzhick 
anx6345_read_dpcd(struct udevice * dev,u32 reg,u8 * val)24096b9f0a7SVasily Khoruzhick static int anx6345_read_dpcd(struct udevice *dev, u32 reg, u8 *val)
24196b9f0a7SVasily Khoruzhick {
24296b9f0a7SVasily Khoruzhick 	int ret;
24396b9f0a7SVasily Khoruzhick 
24496b9f0a7SVasily Khoruzhick 	ret = anx6345_aux_transfer(dev,
24596b9f0a7SVasily Khoruzhick 				   ANX9804_AUX_TX_COMM_READ |
24696b9f0a7SVasily Khoruzhick 				   ANX9804_AUX_TX_COMM_DP_TRANSACTION,
24796b9f0a7SVasily Khoruzhick 				   reg, val, 1);
24896b9f0a7SVasily Khoruzhick 	if (ret) {
24996b9f0a7SVasily Khoruzhick 		debug("Failed to read DPCD\n");
25096b9f0a7SVasily Khoruzhick 		return ret;
25196b9f0a7SVasily Khoruzhick 	}
25296b9f0a7SVasily Khoruzhick 
25396b9f0a7SVasily Khoruzhick 	return 0;
25496b9f0a7SVasily Khoruzhick }
25596b9f0a7SVasily Khoruzhick 
anx6345_read_edid(struct udevice * dev,u8 * buf,int size)25696b9f0a7SVasily Khoruzhick static int anx6345_read_edid(struct udevice *dev, u8 *buf, int size)
25796b9f0a7SVasily Khoruzhick {
25896b9f0a7SVasily Khoruzhick 	struct anx6345_priv *priv = dev_get_priv(dev);
259*c52351ffSWyon Bi 	int ret;
260*c52351ffSWyon Bi 
261*c52351ffSWyon Bi 	ret = anx6345_read_aux_i2c(dev, 0x50, 0x0, EDID_SIZE, priv->edid);
262*c52351ffSWyon Bi 	if (ret < 0) {
263*c52351ffSWyon Bi 		dev_err(dev, "failed to get edid\n");
264*c52351ffSWyon Bi 		return ret;
265*c52351ffSWyon Bi 	}
26696b9f0a7SVasily Khoruzhick 
26796b9f0a7SVasily Khoruzhick 	if (size > EDID_SIZE)
26896b9f0a7SVasily Khoruzhick 		size = EDID_SIZE;
26996b9f0a7SVasily Khoruzhick 	memcpy(buf, priv->edid, size);
27096b9f0a7SVasily Khoruzhick 
27196b9f0a7SVasily Khoruzhick 	return size;
27296b9f0a7SVasily Khoruzhick }
27396b9f0a7SVasily Khoruzhick 
anx6345_attach(struct udevice * dev)27496b9f0a7SVasily Khoruzhick static int anx6345_attach(struct udevice *dev)
27596b9f0a7SVasily Khoruzhick {
27696b9f0a7SVasily Khoruzhick 	/* No-op */
27796b9f0a7SVasily Khoruzhick 	return 0;
27896b9f0a7SVasily Khoruzhick }
27996b9f0a7SVasily Khoruzhick 
anx6345_init(struct udevice * dev)280*c52351ffSWyon Bi static int anx6345_init(struct udevice *dev)
28196b9f0a7SVasily Khoruzhick {
28296b9f0a7SVasily Khoruzhick 	struct anx6345_priv *priv = dev_get_priv(dev);
283*c52351ffSWyon Bi 	u8 c;
284*c52351ffSWyon Bi 	int ret, i;
28596b9f0a7SVasily Khoruzhick 
28696b9f0a7SVasily Khoruzhick 	/* Deassert reset and enable power */
28796b9f0a7SVasily Khoruzhick 	ret = video_bridge_set_active(dev, true);
28896b9f0a7SVasily Khoruzhick 	if (ret)
28996b9f0a7SVasily Khoruzhick 		return ret;
29096b9f0a7SVasily Khoruzhick 
29196b9f0a7SVasily Khoruzhick 	/* Reset */
29296b9f0a7SVasily Khoruzhick 	anx6345_write_r1(dev, ANX9804_RST_CTRL_REG, 1);
29396b9f0a7SVasily Khoruzhick 	mdelay(100);
29496b9f0a7SVasily Khoruzhick 	anx6345_write_r1(dev, ANX9804_RST_CTRL_REG, 0);
29596b9f0a7SVasily Khoruzhick 
29696b9f0a7SVasily Khoruzhick 	/* Write 0 to the powerdown reg (powerup everything) */
29796b9f0a7SVasily Khoruzhick 	anx6345_write_r1(dev, ANX9804_POWERD_CTRL_REG, 0);
29896b9f0a7SVasily Khoruzhick 
299*c52351ffSWyon Bi 	ret = anx6345_read_r1(dev, ANX9804_DEV_IDH_REG, &priv->chipid);
30096b9f0a7SVasily Khoruzhick 	if (ret)
30196b9f0a7SVasily Khoruzhick 		debug("%s: read id failed: %d\n", __func__, ret);
30296b9f0a7SVasily Khoruzhick 
303*c52351ffSWyon Bi 	switch (priv->chipid) {
30496b9f0a7SVasily Khoruzhick 	case 0x63:
30596b9f0a7SVasily Khoruzhick 		debug("ANX63xx detected.\n");
30696b9f0a7SVasily Khoruzhick 		break;
30796b9f0a7SVasily Khoruzhick 	default:
308*c52351ffSWyon Bi 		debug("Error anx6345 chipid mismatch: %.2x\n", priv->chipid);
30996b9f0a7SVasily Khoruzhick 		return -ENODEV;
31096b9f0a7SVasily Khoruzhick 	}
31196b9f0a7SVasily Khoruzhick 
31296b9f0a7SVasily Khoruzhick 	for (i = 0; i < 100; i++) {
31396b9f0a7SVasily Khoruzhick 		anx6345_read_r0(dev, ANX9804_SYS_CTRL2_REG, &c);
31496b9f0a7SVasily Khoruzhick 		anx6345_write_r0(dev, ANX9804_SYS_CTRL2_REG, c);
31596b9f0a7SVasily Khoruzhick 		anx6345_read_r0(dev, ANX9804_SYS_CTRL2_REG, &c);
31696b9f0a7SVasily Khoruzhick 		if ((c & ANX9804_SYS_CTRL2_CHA_STA) == 0)
31796b9f0a7SVasily Khoruzhick 			break;
31896b9f0a7SVasily Khoruzhick 
31996b9f0a7SVasily Khoruzhick 		mdelay(5);
32096b9f0a7SVasily Khoruzhick 	}
32196b9f0a7SVasily Khoruzhick 	if (i == 100)
32296b9f0a7SVasily Khoruzhick 		debug("Error anx6345 clock is not stable\n");
32396b9f0a7SVasily Khoruzhick 
32496b9f0a7SVasily Khoruzhick 	/* Set a bunch of analog related register values */
32596b9f0a7SVasily Khoruzhick 	anx6345_write_r0(dev, ANX9804_PLL_CTRL_REG, 0x00);
32696b9f0a7SVasily Khoruzhick 	anx6345_write_r1(dev, ANX9804_ANALOG_DEBUG_REG1, 0x70);
32796b9f0a7SVasily Khoruzhick 	anx6345_write_r0(dev, ANX9804_LINK_DEBUG_REG, 0x30);
32896b9f0a7SVasily Khoruzhick 
32996b9f0a7SVasily Khoruzhick 	/* Force HPD */
33096b9f0a7SVasily Khoruzhick 	anx6345_write_r0(dev, ANX9804_SYS_CTRL3_REG,
33196b9f0a7SVasily Khoruzhick 			 ANX9804_SYS_CTRL3_F_HPD | ANX9804_SYS_CTRL3_HPD_CTRL);
33296b9f0a7SVasily Khoruzhick 
33396b9f0a7SVasily Khoruzhick 	/* Power up and configure lanes */
33496b9f0a7SVasily Khoruzhick 	anx6345_write_r0(dev, ANX9804_ANALOG_POWER_DOWN_REG, 0x00);
33596b9f0a7SVasily Khoruzhick 	anx6345_write_r0(dev, ANX9804_TRAINING_LANE0_SET_REG, 0x00);
33696b9f0a7SVasily Khoruzhick 	anx6345_write_r0(dev, ANX9804_TRAINING_LANE1_SET_REG, 0x00);
33796b9f0a7SVasily Khoruzhick 	anx6345_write_r0(dev, ANX9804_TRAINING_LANE2_SET_REG, 0x00);
33896b9f0a7SVasily Khoruzhick 	anx6345_write_r0(dev, ANX9804_TRAINING_LANE3_SET_REG, 0x00);
33996b9f0a7SVasily Khoruzhick 
34096b9f0a7SVasily Khoruzhick 	/* Reset AUX CH */
34196b9f0a7SVasily Khoruzhick 	anx6345_write_r1(dev, ANX9804_RST_CTRL2_REG,
34296b9f0a7SVasily Khoruzhick 			 ANX9804_RST_CTRL2_AUX);
34396b9f0a7SVasily Khoruzhick 	anx6345_write_r1(dev, ANX9804_RST_CTRL2_REG, 0);
34496b9f0a7SVasily Khoruzhick 
34596b9f0a7SVasily Khoruzhick 	/* Powerdown audio and some other unused bits */
34696b9f0a7SVasily Khoruzhick 	anx6345_write_r1(dev, ANX9804_POWERD_CTRL_REG, ANX9804_POWERD_AUDIO);
34796b9f0a7SVasily Khoruzhick 	anx6345_write_r0(dev, ANX9804_HDCP_CONTROL_0_REG, 0x00);
34896b9f0a7SVasily Khoruzhick 	anx6345_write_r0(dev, 0xa7, 0x00);
34996b9f0a7SVasily Khoruzhick 
350*c52351ffSWyon Bi 	return 0;
351*c52351ffSWyon Bi }
352*c52351ffSWyon Bi 
anx6345_enable(struct udevice * dev)353*c52351ffSWyon Bi static int anx6345_enable(struct udevice *dev)
354*c52351ffSWyon Bi {
355*c52351ffSWyon Bi 	u8 colordepth, lanes, data_rate, c;
356*c52351ffSWyon Bi 	int i, bpp;
357*c52351ffSWyon Bi 	struct display_timing timing;
358*c52351ffSWyon Bi 	struct anx6345_priv *priv = dev_get_priv(dev);
359*c52351ffSWyon Bi 
36096b9f0a7SVasily Khoruzhick 	if (edid_get_timing(priv->edid, EDID_SIZE, &timing, &bpp) != 0) {
36196b9f0a7SVasily Khoruzhick 		debug("Failed to parse EDID\n");
36296b9f0a7SVasily Khoruzhick 		return -EIO;
36396b9f0a7SVasily Khoruzhick 	}
36496b9f0a7SVasily Khoruzhick 	debug("%s: panel found: %dx%d, bpp %d\n", __func__,
36596b9f0a7SVasily Khoruzhick 	      timing.hactive.typ, timing.vactive.typ, bpp);
36696b9f0a7SVasily Khoruzhick 	if (bpp == 6)
36796b9f0a7SVasily Khoruzhick 		colordepth = 0x00; /* 6 bit */
36896b9f0a7SVasily Khoruzhick 	else
36996b9f0a7SVasily Khoruzhick 		colordepth = 0x10; /* 8 bit */
37096b9f0a7SVasily Khoruzhick 	anx6345_write_r1(dev, ANX9804_VID_CTRL2_REG, colordepth);
37196b9f0a7SVasily Khoruzhick 
37296b9f0a7SVasily Khoruzhick 	if (anx6345_read_dpcd(dev, DP_MAX_LINK_RATE, &data_rate)) {
37396b9f0a7SVasily Khoruzhick 		debug("%s: Failed to DP_MAX_LINK_RATE\n", __func__);
37496b9f0a7SVasily Khoruzhick 		return -EIO;
37596b9f0a7SVasily Khoruzhick 	}
37696b9f0a7SVasily Khoruzhick 	debug("%s: data_rate: %d\n", __func__, (int)data_rate);
37796b9f0a7SVasily Khoruzhick 	if (anx6345_read_dpcd(dev, DP_MAX_LANE_COUNT, &lanes)) {
37896b9f0a7SVasily Khoruzhick 		debug("%s: Failed to read DP_MAX_LANE_COUNT\n", __func__);
37996b9f0a7SVasily Khoruzhick 		return -EIO;
38096b9f0a7SVasily Khoruzhick 	}
38196b9f0a7SVasily Khoruzhick 	lanes &= DP_MAX_LANE_COUNT_MASK;
38296b9f0a7SVasily Khoruzhick 	debug("%s: lanes: %d\n", __func__, (int)lanes);
38396b9f0a7SVasily Khoruzhick 
38496b9f0a7SVasily Khoruzhick 	/* Set data-rate / lanes */
38596b9f0a7SVasily Khoruzhick 	anx6345_write_r0(dev, ANX9804_LINK_BW_SET_REG, data_rate);
38696b9f0a7SVasily Khoruzhick 	anx6345_write_r0(dev, ANX9804_LANE_COUNT_SET_REG, lanes);
38796b9f0a7SVasily Khoruzhick 
38896b9f0a7SVasily Khoruzhick 	/* Link training */
38996b9f0a7SVasily Khoruzhick 	anx6345_write_r0(dev, ANX9804_LINK_TRAINING_CTRL_REG,
39096b9f0a7SVasily Khoruzhick 			 ANX9804_LINK_TRAINING_CTRL_EN);
39196b9f0a7SVasily Khoruzhick 	mdelay(5);
39296b9f0a7SVasily Khoruzhick 	for (i = 0; i < 100; i++) {
39396b9f0a7SVasily Khoruzhick 		anx6345_read_r0(dev, ANX9804_LINK_TRAINING_CTRL_REG, &c);
394*c52351ffSWyon Bi 		if ((priv->chipid == 0x63) && (c & 0x80) == 0)
39596b9f0a7SVasily Khoruzhick 			break;
39696b9f0a7SVasily Khoruzhick 
39796b9f0a7SVasily Khoruzhick 		mdelay(5);
39896b9f0a7SVasily Khoruzhick 	}
39996b9f0a7SVasily Khoruzhick 	if (i == 100) {
40096b9f0a7SVasily Khoruzhick 		debug("Error anx6345 link training timeout\n");
40196b9f0a7SVasily Khoruzhick 		return -ENODEV;
40296b9f0a7SVasily Khoruzhick 	}
40396b9f0a7SVasily Khoruzhick 
40496b9f0a7SVasily Khoruzhick 	/* Enable */
405*c52351ffSWyon Bi 	anx6345_write_r1(dev, ANX9804_VID_CTRL1_REG, ANX9804_VID_CTRL1_VID_EN |
406*c52351ffSWyon Bi 			 ANX9804_VID_CTRL1_DDR_CTRL | ANX9804_VID_CTRL1_EDGE);
40796b9f0a7SVasily Khoruzhick 	/* Force stream valid */
40896b9f0a7SVasily Khoruzhick 	anx6345_write_r0(dev, ANX9804_SYS_CTRL3_REG,
40996b9f0a7SVasily Khoruzhick 			 ANX9804_SYS_CTRL3_F_HPD |
41096b9f0a7SVasily Khoruzhick 			 ANX9804_SYS_CTRL3_HPD_CTRL |
41196b9f0a7SVasily Khoruzhick 			 ANX9804_SYS_CTRL3_F_VALID |
41296b9f0a7SVasily Khoruzhick 			 ANX9804_SYS_CTRL3_VALID_CTRL);
41396b9f0a7SVasily Khoruzhick 
41496b9f0a7SVasily Khoruzhick 	return 0;
41596b9f0a7SVasily Khoruzhick }
41696b9f0a7SVasily Khoruzhick 
anx6345_probe(struct udevice * dev)41796b9f0a7SVasily Khoruzhick static int anx6345_probe(struct udevice *dev)
41896b9f0a7SVasily Khoruzhick {
419*c52351ffSWyon Bi 	struct rockchip_bridge *bridge =
420*c52351ffSWyon Bi 		(struct rockchip_bridge *)dev_get_driver_data(dev);
421*c52351ffSWyon Bi 
42296b9f0a7SVasily Khoruzhick 	if (device_get_uclass_id(dev->parent) != UCLASS_I2C)
42396b9f0a7SVasily Khoruzhick 		return -EPROTONOSUPPORT;
42496b9f0a7SVasily Khoruzhick 
425*c52351ffSWyon Bi 	bridge->dev = dev;
426*c52351ffSWyon Bi 
427*c52351ffSWyon Bi 	return anx6345_init(dev);
42896b9f0a7SVasily Khoruzhick }
42996b9f0a7SVasily Khoruzhick 
430*c52351ffSWyon Bi static const struct video_bridge_ops anx6345_ops = {
43196b9f0a7SVasily Khoruzhick 	.attach = anx6345_attach,
43296b9f0a7SVasily Khoruzhick 	.set_backlight = anx6345_set_backlight,
43396b9f0a7SVasily Khoruzhick 	.read_edid = anx6345_read_edid,
43496b9f0a7SVasily Khoruzhick };
43596b9f0a7SVasily Khoruzhick 
anx6345_bridge_enable(struct rockchip_bridge * bridge)436*c52351ffSWyon Bi static void anx6345_bridge_enable(struct rockchip_bridge *bridge)
437*c52351ffSWyon Bi {
438*c52351ffSWyon Bi 	anx6345_enable(bridge->dev);
439*c52351ffSWyon Bi }
440*c52351ffSWyon Bi 
441*c52351ffSWyon Bi static const struct rockchip_bridge_funcs anx6345_bridge_funcs = {
442*c52351ffSWyon Bi 	.enable = anx6345_bridge_enable,
443*c52351ffSWyon Bi };
444*c52351ffSWyon Bi 
445*c52351ffSWyon Bi static struct rockchip_bridge anx6345_driver_data = {
446*c52351ffSWyon Bi 	.funcs = &anx6345_bridge_funcs,
447*c52351ffSWyon Bi };
448*c52351ffSWyon Bi 
44996b9f0a7SVasily Khoruzhick static const struct udevice_id anx6345_ids[] = {
450*c52351ffSWyon Bi 	{
451*c52351ffSWyon Bi 		.compatible = "analogix,anx6345",
452*c52351ffSWyon Bi 		.data = (ulong)&anx6345_driver_data, },
45396b9f0a7SVasily Khoruzhick 	{ }
45496b9f0a7SVasily Khoruzhick };
45596b9f0a7SVasily Khoruzhick 
45696b9f0a7SVasily Khoruzhick U_BOOT_DRIVER(analogix_anx6345) = {
45796b9f0a7SVasily Khoruzhick 	.name	= "analogix_anx6345",
45896b9f0a7SVasily Khoruzhick 	.id	= UCLASS_VIDEO_BRIDGE,
45996b9f0a7SVasily Khoruzhick 	.of_match = anx6345_ids,
46096b9f0a7SVasily Khoruzhick 	.probe	= anx6345_probe,
46196b9f0a7SVasily Khoruzhick 	.ops	= &anx6345_ops,
46296b9f0a7SVasily Khoruzhick 	.priv_auto_alloc_size = sizeof(struct anx6345_priv),
46396b9f0a7SVasily Khoruzhick };
464