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