1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * (C) Copyright 2022 Rockchip Electronics Co., Ltd
4 */
5
6 #include <common.h>
7 #include <dm.h>
8 #include <errno.h>
9 #include <i2c.h>
10 #include <max96745.h>
11 #include <video_bridge.h>
12 #include <linux/iopoll.h>
13
14 #include "rockchip_bridge.h"
15 #include "rockchip_display.h"
16 #include "rockchip_panel.h"
17
max96745_bridge_link_locked(struct udevice * dev)18 static bool max96745_bridge_link_locked(struct udevice *dev)
19 {
20 int ret;
21
22 ret = dm_i2c_reg_read(dev->parent, 0x002a);
23 if (ret < 0)
24 return false;
25
26 if (!FIELD_GET(LINK_LOCKED, ret))
27 return false;
28
29 return true;
30 }
31
max96745_bridge_detect(struct rockchip_bridge * bridge)32 static bool max96745_bridge_detect(struct rockchip_bridge *bridge)
33 {
34 return max96745_bridge_link_locked(bridge->dev);
35 }
36
max96745_bridge_enable(struct rockchip_bridge * bridge)37 static void max96745_bridge_enable(struct rockchip_bridge *bridge)
38 {
39 struct udevice *dev = bridge->dev;
40 struct drm_display_mode *mode = &bridge->state->conn_state.mode;
41 u8 cxtp, tx_rate;
42 int ret;
43
44 ret = dm_i2c_reg_read(dev->parent, 0x0011);
45 if (ret < 0)
46 return;
47
48 cxtp = FIELD_GET(CXTP_A, ret);
49
50 ret = dm_i2c_reg_read(dev->parent, 0x0028);
51 if (ret < 0)
52 return;
53
54 tx_rate = FIELD_GET(TX_RATE, ret);
55
56 if (!cxtp && mode->clock > 95000 && tx_rate == 1) {
57 ret = dm_i2c_reg_clrset(dev->parent, 0x0028, TX_RATE,
58 FIELD_PREP(TX_RATE, 2));
59 if (ret < 0)
60 return;
61
62 ret = dm_i2c_reg_clrset(dev->parent, 0x0029, RESET_ONESHOT,
63 FIELD_PREP(RESET_ONESHOT, 1));
64 if (ret < 0)
65 return;
66
67 if (readx_poll_timeout(max96745_bridge_link_locked, dev, ret,
68 ret, 200000))
69 dev_err(dev, "%s: GMSL link not locked\n", __func__);
70 }
71 }
72
max96745_bridge_post_disable(struct rockchip_bridge * bridge)73 static void max96745_bridge_post_disable(struct rockchip_bridge *bridge)
74 {
75 struct udevice *dev = bridge->dev;
76 u8 cxtp, tx_rate;
77 int ret;
78
79 ret = dm_i2c_reg_read(dev->parent, 0x0011);
80 if (ret < 0)
81 return;
82
83 cxtp = FIELD_GET(CXTP_A, ret);
84
85 ret = dm_i2c_reg_read(dev->parent, 0x0028);
86 if (ret < 0)
87 return;
88
89 tx_rate = FIELD_GET(TX_RATE, ret);
90
91 if (!cxtp && tx_rate == 2) {
92 ret = dm_i2c_reg_clrset(dev->parent, 0x0028, TX_RATE,
93 FIELD_PREP(TX_RATE, 1));
94 if (ret < 0)
95 return;
96
97 ret = dm_i2c_reg_clrset(dev->parent, 0x0029, RESET_ONESHOT,
98 FIELD_PREP(RESET_ONESHOT, 1));
99 if (ret < 0)
100 return;
101
102 if (readx_poll_timeout(max96745_bridge_link_locked, dev, ret,
103 ret, 200000))
104 dev_err(dev, "%s: GMSL link not locked\n", __func__);
105 }
106 }
107
108 static const struct rockchip_bridge_funcs max96745_bridge_funcs = {
109 .detect = max96745_bridge_detect,
110 .enable = max96745_bridge_enable,
111 .post_disable = max96745_bridge_post_disable,
112 };
113
max96745_bridge_probe(struct udevice * dev)114 static int max96745_bridge_probe(struct udevice *dev)
115 {
116 struct rockchip_bridge *bridge;
117
118 bridge = calloc(1, sizeof(*bridge));
119 if (!bridge)
120 return -ENOMEM;
121
122 dev->driver_data = (ulong)bridge;
123 bridge->dev = dev;
124 bridge->funcs = &max96745_bridge_funcs;
125
126 return 0;
127 }
128
129 static const struct udevice_id max96745_bridge_of_match[] = {
130 { .compatible = "maxim,max96745-bridge", },
131 { }
132 };
133
134 U_BOOT_DRIVER(max96745_bridge) = {
135 .name = "max96745_bridge",
136 .id = UCLASS_VIDEO_BRIDGE,
137 .of_match = max96745_bridge_of_match,
138 .probe = max96745_bridge_probe,
139 };
140