152d98d47SWyon Bi // SPDX-License-Identifier: GPL-2.0+
252d98d47SWyon Bi /*
352d98d47SWyon Bi * (C) Copyright 2022 Rockchip Electronics Co., Ltd
452d98d47SWyon Bi */
552d98d47SWyon Bi
652d98d47SWyon Bi #include <common.h>
752d98d47SWyon Bi #include <dm.h>
852d98d47SWyon Bi #include <errno.h>
952d98d47SWyon Bi #include <i2c.h>
1052d98d47SWyon Bi #include <max96745.h>
1152d98d47SWyon Bi #include <video_bridge.h>
12*6cdc64f4SWyon Bi #include <linux/iopoll.h>
1352d98d47SWyon Bi
1452d98d47SWyon Bi #include "rockchip_bridge.h"
1552d98d47SWyon Bi #include "rockchip_display.h"
1652d98d47SWyon Bi #include "rockchip_panel.h"
1752d98d47SWyon Bi
max96745_bridge_link_locked(struct udevice * dev)18*6cdc64f4SWyon Bi static bool max96745_bridge_link_locked(struct udevice *dev)
1952d98d47SWyon Bi {
20*6cdc64f4SWyon Bi int ret;
2152d98d47SWyon Bi
22*6cdc64f4SWyon Bi ret = dm_i2c_reg_read(dev->parent, 0x002a);
23*6cdc64f4SWyon Bi if (ret < 0)
24*6cdc64f4SWyon Bi return false;
25*6cdc64f4SWyon Bi
26*6cdc64f4SWyon Bi if (!FIELD_GET(LINK_LOCKED, ret))
27044a54ceSWyon Bi return false;
2852d98d47SWyon Bi
29044a54ceSWyon Bi return true;
3052d98d47SWyon Bi }
3152d98d47SWyon Bi
max96745_bridge_detect(struct rockchip_bridge * bridge)32*6cdc64f4SWyon Bi static bool max96745_bridge_detect(struct rockchip_bridge *bridge)
33*6cdc64f4SWyon Bi {
34*6cdc64f4SWyon Bi return max96745_bridge_link_locked(bridge->dev);
35*6cdc64f4SWyon Bi }
36*6cdc64f4SWyon Bi
max96745_bridge_enable(struct rockchip_bridge * bridge)37*6cdc64f4SWyon Bi static void max96745_bridge_enable(struct rockchip_bridge *bridge)
38*6cdc64f4SWyon Bi {
39*6cdc64f4SWyon Bi struct udevice *dev = bridge->dev;
40*6cdc64f4SWyon Bi struct drm_display_mode *mode = &bridge->state->conn_state.mode;
41*6cdc64f4SWyon Bi u8 cxtp, tx_rate;
42*6cdc64f4SWyon Bi int ret;
43*6cdc64f4SWyon Bi
44*6cdc64f4SWyon Bi ret = dm_i2c_reg_read(dev->parent, 0x0011);
45*6cdc64f4SWyon Bi if (ret < 0)
46*6cdc64f4SWyon Bi return;
47*6cdc64f4SWyon Bi
48*6cdc64f4SWyon Bi cxtp = FIELD_GET(CXTP_A, ret);
49*6cdc64f4SWyon Bi
50*6cdc64f4SWyon Bi ret = dm_i2c_reg_read(dev->parent, 0x0028);
51*6cdc64f4SWyon Bi if (ret < 0)
52*6cdc64f4SWyon Bi return;
53*6cdc64f4SWyon Bi
54*6cdc64f4SWyon Bi tx_rate = FIELD_GET(TX_RATE, ret);
55*6cdc64f4SWyon Bi
56*6cdc64f4SWyon Bi if (!cxtp && mode->clock > 95000 && tx_rate == 1) {
57*6cdc64f4SWyon Bi ret = dm_i2c_reg_clrset(dev->parent, 0x0028, TX_RATE,
58*6cdc64f4SWyon Bi FIELD_PREP(TX_RATE, 2));
59*6cdc64f4SWyon Bi if (ret < 0)
60*6cdc64f4SWyon Bi return;
61*6cdc64f4SWyon Bi
62*6cdc64f4SWyon Bi ret = dm_i2c_reg_clrset(dev->parent, 0x0029, RESET_ONESHOT,
63*6cdc64f4SWyon Bi FIELD_PREP(RESET_ONESHOT, 1));
64*6cdc64f4SWyon Bi if (ret < 0)
65*6cdc64f4SWyon Bi return;
66*6cdc64f4SWyon Bi
67*6cdc64f4SWyon Bi if (readx_poll_timeout(max96745_bridge_link_locked, dev, ret,
68*6cdc64f4SWyon Bi ret, 200000))
69*6cdc64f4SWyon Bi dev_err(dev, "%s: GMSL link not locked\n", __func__);
70*6cdc64f4SWyon Bi }
71*6cdc64f4SWyon Bi }
72*6cdc64f4SWyon Bi
max96745_bridge_post_disable(struct rockchip_bridge * bridge)73*6cdc64f4SWyon Bi static void max96745_bridge_post_disable(struct rockchip_bridge *bridge)
74*6cdc64f4SWyon Bi {
75*6cdc64f4SWyon Bi struct udevice *dev = bridge->dev;
76*6cdc64f4SWyon Bi u8 cxtp, tx_rate;
77*6cdc64f4SWyon Bi int ret;
78*6cdc64f4SWyon Bi
79*6cdc64f4SWyon Bi ret = dm_i2c_reg_read(dev->parent, 0x0011);
80*6cdc64f4SWyon Bi if (ret < 0)
81*6cdc64f4SWyon Bi return;
82*6cdc64f4SWyon Bi
83*6cdc64f4SWyon Bi cxtp = FIELD_GET(CXTP_A, ret);
84*6cdc64f4SWyon Bi
85*6cdc64f4SWyon Bi ret = dm_i2c_reg_read(dev->parent, 0x0028);
86*6cdc64f4SWyon Bi if (ret < 0)
87*6cdc64f4SWyon Bi return;
88*6cdc64f4SWyon Bi
89*6cdc64f4SWyon Bi tx_rate = FIELD_GET(TX_RATE, ret);
90*6cdc64f4SWyon Bi
91*6cdc64f4SWyon Bi if (!cxtp && tx_rate == 2) {
92*6cdc64f4SWyon Bi ret = dm_i2c_reg_clrset(dev->parent, 0x0028, TX_RATE,
93*6cdc64f4SWyon Bi FIELD_PREP(TX_RATE, 1));
94*6cdc64f4SWyon Bi if (ret < 0)
95*6cdc64f4SWyon Bi return;
96*6cdc64f4SWyon Bi
97*6cdc64f4SWyon Bi ret = dm_i2c_reg_clrset(dev->parent, 0x0029, RESET_ONESHOT,
98*6cdc64f4SWyon Bi FIELD_PREP(RESET_ONESHOT, 1));
99*6cdc64f4SWyon Bi if (ret < 0)
100*6cdc64f4SWyon Bi return;
101*6cdc64f4SWyon Bi
102*6cdc64f4SWyon Bi if (readx_poll_timeout(max96745_bridge_link_locked, dev, ret,
103*6cdc64f4SWyon Bi ret, 200000))
104*6cdc64f4SWyon Bi dev_err(dev, "%s: GMSL link not locked\n", __func__);
105*6cdc64f4SWyon Bi }
106*6cdc64f4SWyon Bi }
107*6cdc64f4SWyon Bi
10852d98d47SWyon Bi static const struct rockchip_bridge_funcs max96745_bridge_funcs = {
109044a54ceSWyon Bi .detect = max96745_bridge_detect,
110*6cdc64f4SWyon Bi .enable = max96745_bridge_enable,
111*6cdc64f4SWyon Bi .post_disable = max96745_bridge_post_disable,
11252d98d47SWyon Bi };
11352d98d47SWyon Bi
max96745_bridge_probe(struct udevice * dev)11452d98d47SWyon Bi static int max96745_bridge_probe(struct udevice *dev)
11552d98d47SWyon Bi {
11652d98d47SWyon Bi struct rockchip_bridge *bridge;
11752d98d47SWyon Bi
11852d98d47SWyon Bi bridge = calloc(1, sizeof(*bridge));
11952d98d47SWyon Bi if (!bridge)
12052d98d47SWyon Bi return -ENOMEM;
12152d98d47SWyon Bi
12252d98d47SWyon Bi dev->driver_data = (ulong)bridge;
12352d98d47SWyon Bi bridge->dev = dev;
12452d98d47SWyon Bi bridge->funcs = &max96745_bridge_funcs;
12552d98d47SWyon Bi
12652d98d47SWyon Bi return 0;
12752d98d47SWyon Bi }
12852d98d47SWyon Bi
12952d98d47SWyon Bi static const struct udevice_id max96745_bridge_of_match[] = {
13052d98d47SWyon Bi { .compatible = "maxim,max96745-bridge", },
13152d98d47SWyon Bi { }
13252d98d47SWyon Bi };
13352d98d47SWyon Bi
13452d98d47SWyon Bi U_BOOT_DRIVER(max96745_bridge) = {
13552d98d47SWyon Bi .name = "max96745_bridge",
13652d98d47SWyon Bi .id = UCLASS_VIDEO_BRIDGE,
13752d98d47SWyon Bi .of_match = max96745_bridge_of_match,
13852d98d47SWyon Bi .probe = max96745_bridge_probe,
13952d98d47SWyon Bi };
140