1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Maxim MAX96745 GMSL2 Serializer with eDP1.4a/DP1.4 Input
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (c) 2022 Rockchip Electronics Co. Ltd.
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <drm/drm_atomic_helper.h>
9*4882a593Smuzhiyun #include <drm/drm_bridge.h>
10*4882a593Smuzhiyun #include <drm/drm_panel.h>
11*4882a593Smuzhiyun #include <drm/drm_print.h>
12*4882a593Smuzhiyun #include <drm/drm_of.h>
13*4882a593Smuzhiyun #include <drm/drm_connector.h>
14*4882a593Smuzhiyun #include <drm/drm_probe_helper.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #include <linux/irq.h>
17*4882a593Smuzhiyun #include <linux/module.h>
18*4882a593Smuzhiyun #include <linux/kernel.h>
19*4882a593Smuzhiyun #include <linux/platform_device.h>
20*4882a593Smuzhiyun #include <linux/err.h>
21*4882a593Smuzhiyun #include <linux/extcon-provider.h>
22*4882a593Smuzhiyun #include <linux/of.h>
23*4882a593Smuzhiyun #include <linux/regmap.h>
24*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
25*4882a593Smuzhiyun #include <linux/mfd/max96745.h>
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun struct max96745_bridge {
28*4882a593Smuzhiyun struct drm_bridge bridge;
29*4882a593Smuzhiyun struct drm_panel *panel;
30*4882a593Smuzhiyun enum drm_connector_status status;
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun struct device *dev;
33*4882a593Smuzhiyun struct max96745 *parent;
34*4882a593Smuzhiyun struct regmap *regmap;
35*4882a593Smuzhiyun struct {
36*4882a593Smuzhiyun struct gpio_desc *gpio;
37*4882a593Smuzhiyun int irq;
38*4882a593Smuzhiyun atomic_t triggered;
39*4882a593Smuzhiyun } lock;
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun #define to_max96745_bridge(x) container_of(x, struct max96745_bridge, x)
43*4882a593Smuzhiyun
max96745_bridge_link_locked(struct max96745_bridge * ser)44*4882a593Smuzhiyun static bool max96745_bridge_link_locked(struct max96745_bridge *ser)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun u32 val;
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun if (ser->lock.gpio)
49*4882a593Smuzhiyun return gpiod_get_value_cansleep(ser->lock.gpio);
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun if (regmap_read(ser->regmap, 0x002a, &val))
52*4882a593Smuzhiyun return false;
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun if (!FIELD_GET(LINK_LOCKED, val))
55*4882a593Smuzhiyun return false;
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun return true;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun
max96745_bridge_attach(struct drm_bridge * bridge,enum drm_bridge_attach_flags flags)60*4882a593Smuzhiyun static int max96745_bridge_attach(struct drm_bridge *bridge,
61*4882a593Smuzhiyun enum drm_bridge_attach_flags flags)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun struct max96745_bridge *ser = to_max96745_bridge(bridge);
64*4882a593Smuzhiyun int ret;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun ret = drm_of_find_panel_or_bridge(bridge->of_node, 1, -1, &ser->panel,
67*4882a593Smuzhiyun NULL);
68*4882a593Smuzhiyun if (ret < 0 && ret != -ENODEV)
69*4882a593Smuzhiyun return ret;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun if (max96745_bridge_link_locked(ser))
72*4882a593Smuzhiyun ser->status = connector_status_connected;
73*4882a593Smuzhiyun else
74*4882a593Smuzhiyun ser->status = connector_status_disconnected;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun return 0;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun
max96745_bridge_pre_enable(struct drm_bridge * bridge)79*4882a593Smuzhiyun static void max96745_bridge_pre_enable(struct drm_bridge *bridge)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun struct max96745_bridge *ser = to_max96745_bridge(bridge);
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun if (ser->panel)
84*4882a593Smuzhiyun drm_panel_prepare(ser->panel);
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun
max96745_bridge_enable(struct drm_bridge * bridge)87*4882a593Smuzhiyun static void max96745_bridge_enable(struct drm_bridge *bridge)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun struct max96745_bridge *ser = to_max96745_bridge(bridge);
90*4882a593Smuzhiyun struct max96745 *max96745 = ser->parent;
91*4882a593Smuzhiyun struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
92*4882a593Smuzhiyun u8 cxtp, tx_rate;
93*4882a593Smuzhiyun u32 reg;
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun regmap_read(ser->regmap, 0x0011, ®);
96*4882a593Smuzhiyun cxtp = FIELD_GET(CXTP_A, reg);
97*4882a593Smuzhiyun regmap_read(ser->regmap, 0x0028, ®);
98*4882a593Smuzhiyun tx_rate = FIELD_GET(TX_RATE, reg);
99*4882a593Smuzhiyun if (!cxtp && mode->clock > 95000 && tx_rate == 1) {
100*4882a593Smuzhiyun regmap_update_bits(ser->regmap, 0x0028, TX_RATE,
101*4882a593Smuzhiyun FIELD_PREP(TX_RATE, 2));
102*4882a593Smuzhiyun regmap_update_bits(ser->regmap, 0x0029, RESET_ONESHOT,
103*4882a593Smuzhiyun FIELD_PREP(RESET_ONESHOT, 1));
104*4882a593Smuzhiyun if (regmap_read_poll_timeout(ser->regmap, 0x002a, reg,
105*4882a593Smuzhiyun reg & LINK_LOCKED, 10000, 200000))
106*4882a593Smuzhiyun dev_err(ser->dev, "%s: GMSL link not locked\n", __func__);
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun if (ser->panel)
110*4882a593Smuzhiyun drm_panel_enable(ser->panel);
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun extcon_set_state_sync(max96745->extcon, EXTCON_JACK_VIDEO_OUT, true);
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun
max96745_bridge_disable(struct drm_bridge * bridge)115*4882a593Smuzhiyun static void max96745_bridge_disable(struct drm_bridge *bridge)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun struct max96745_bridge *ser = to_max96745_bridge(bridge);
118*4882a593Smuzhiyun struct max96745 *max96745 = ser->parent;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun extcon_set_state_sync(max96745->extcon, EXTCON_JACK_VIDEO_OUT, false);
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun if (ser->panel)
123*4882a593Smuzhiyun drm_panel_disable(ser->panel);
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun
max96745_bridge_post_disable(struct drm_bridge * bridge)126*4882a593Smuzhiyun static void max96745_bridge_post_disable(struct drm_bridge *bridge)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun struct max96745_bridge *ser = to_max96745_bridge(bridge);
129*4882a593Smuzhiyun u8 cxtp, tx_rate, link_locked;
130*4882a593Smuzhiyun u32 reg;
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun regmap_read(ser->regmap, 0x002a, ®);
133*4882a593Smuzhiyun link_locked = FIELD_GET(LINK_LOCKED, reg);
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun if (ser->panel)
136*4882a593Smuzhiyun drm_panel_unprepare(ser->panel);
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun regmap_read(ser->regmap, 0x0011, ®);
139*4882a593Smuzhiyun cxtp = FIELD_GET(CXTP_A, reg);
140*4882a593Smuzhiyun regmap_read(ser->regmap, 0x0028, ®);
141*4882a593Smuzhiyun tx_rate = FIELD_GET(TX_RATE, reg);
142*4882a593Smuzhiyun if (!cxtp && tx_rate == 2) {
143*4882a593Smuzhiyun regmap_update_bits(ser->regmap, 0x0028, TX_RATE,
144*4882a593Smuzhiyun FIELD_PREP(TX_RATE, 1));
145*4882a593Smuzhiyun regmap_update_bits(ser->regmap, 0x0029, RESET_ONESHOT,
146*4882a593Smuzhiyun FIELD_PREP(RESET_ONESHOT, 1));
147*4882a593Smuzhiyun if (link_locked) {
148*4882a593Smuzhiyun if (regmap_read_poll_timeout(ser->regmap, 0x002a, reg,
149*4882a593Smuzhiyun reg & LINK_LOCKED, 10000, 200000))
150*4882a593Smuzhiyun dev_err(ser->dev, "%s: GMSL link not locked\n", __func__);
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun static enum drm_connector_status
max96745_bridge_detect(struct drm_bridge * bridge)156*4882a593Smuzhiyun max96745_bridge_detect(struct drm_bridge *bridge)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun struct max96745_bridge *ser = to_max96745_bridge(bridge);
159*4882a593Smuzhiyun struct max96745 *max96745 = ser->parent;
160*4882a593Smuzhiyun enum drm_connector_status status = connector_status_connected;
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun if (!drm_kms_helper_is_poll_worker())
163*4882a593Smuzhiyun return ser->status;
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun if (!max96745_bridge_link_locked(ser)) {
166*4882a593Smuzhiyun status = connector_status_disconnected;
167*4882a593Smuzhiyun goto out;
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun if (extcon_get_state(max96745->extcon, EXTCON_JACK_VIDEO_OUT)) {
171*4882a593Smuzhiyun u32 dprx_trn_status2;
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun if (atomic_cmpxchg(&ser->lock.triggered, 1, 0)) {
174*4882a593Smuzhiyun status = connector_status_disconnected;
175*4882a593Smuzhiyun goto out;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun if (regmap_read(ser->regmap, 0x641a, &dprx_trn_status2)) {
179*4882a593Smuzhiyun status = connector_status_disconnected;
180*4882a593Smuzhiyun goto out;
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun if ((dprx_trn_status2 & DPRX_TRAIN_STATE) != DPRX_TRAIN_STATE) {
184*4882a593Smuzhiyun dev_err(ser->dev, "Training State: 0x%lx\n",
185*4882a593Smuzhiyun FIELD_GET(DPRX_TRAIN_STATE, dprx_trn_status2));
186*4882a593Smuzhiyun status = connector_status_disconnected;
187*4882a593Smuzhiyun goto out;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun } else {
190*4882a593Smuzhiyun atomic_set(&ser->lock.triggered, 0);
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun out:
194*4882a593Smuzhiyun ser->status = status;
195*4882a593Smuzhiyun return status;
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
max96745_bridge_get_modes(struct drm_bridge * bridge,struct drm_connector * connector)198*4882a593Smuzhiyun static int max96745_bridge_get_modes(struct drm_bridge *bridge,
199*4882a593Smuzhiyun struct drm_connector *connector)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun struct max96745_bridge *ser = to_max96745_bridge(bridge);
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun if (ser->panel)
204*4882a593Smuzhiyun return drm_panel_get_modes(ser->panel, connector);
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun return drm_add_modes_noedid(connector, 1920, 1080);
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun static const struct drm_bridge_funcs max96745_bridge_funcs = {
210*4882a593Smuzhiyun .attach = max96745_bridge_attach,
211*4882a593Smuzhiyun .detect = max96745_bridge_detect,
212*4882a593Smuzhiyun .get_modes = max96745_bridge_get_modes,
213*4882a593Smuzhiyun .pre_enable = max96745_bridge_pre_enable,
214*4882a593Smuzhiyun .enable = max96745_bridge_enable,
215*4882a593Smuzhiyun .disable = max96745_bridge_disable,
216*4882a593Smuzhiyun .post_disable = max96745_bridge_post_disable,
217*4882a593Smuzhiyun .atomic_get_input_bus_fmts = drm_atomic_helper_bridge_propagate_bus_fmt,
218*4882a593Smuzhiyun .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
219*4882a593Smuzhiyun .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
220*4882a593Smuzhiyun .atomic_reset = drm_atomic_helper_bridge_reset,
221*4882a593Smuzhiyun };
222*4882a593Smuzhiyun
max96745_bridge_lock_irq_handler(int irq,void * arg)223*4882a593Smuzhiyun static irqreturn_t max96745_bridge_lock_irq_handler(int irq, void *arg)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun struct max96745_bridge *ser = arg;
226*4882a593Smuzhiyun struct max96745 *max96745 = ser->parent;
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun if (extcon_get_state(max96745->extcon, EXTCON_JACK_VIDEO_OUT))
229*4882a593Smuzhiyun atomic_set(&ser->lock.triggered, 1);
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun return IRQ_HANDLED;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun
max96745_bridge_probe(struct platform_device * pdev)234*4882a593Smuzhiyun static int max96745_bridge_probe(struct platform_device *pdev)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun struct device *dev = &pdev->dev;
237*4882a593Smuzhiyun struct max96745_bridge *ser;
238*4882a593Smuzhiyun int ret;
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun ser = devm_kzalloc(dev, sizeof(*ser), GFP_KERNEL);
241*4882a593Smuzhiyun if (!ser)
242*4882a593Smuzhiyun return -ENOMEM;
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun ser->dev = dev;
245*4882a593Smuzhiyun ser->parent = dev_get_drvdata(dev->parent);
246*4882a593Smuzhiyun platform_set_drvdata(pdev, ser);
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun ser->regmap = dev_get_regmap(dev->parent, NULL);
249*4882a593Smuzhiyun if (!ser->regmap)
250*4882a593Smuzhiyun return dev_err_probe(dev, -ENODEV, "failed to get regmap\n");
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun ser->lock.gpio = devm_gpiod_get_optional(dev, "lock", GPIOD_IN);
253*4882a593Smuzhiyun if (IS_ERR(ser->lock.gpio))
254*4882a593Smuzhiyun return dev_err_probe(dev, PTR_ERR(ser->lock.gpio),
255*4882a593Smuzhiyun "failed to get lock GPIO\n");
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun if (ser->lock.gpio) {
258*4882a593Smuzhiyun ser->lock.irq = gpiod_to_irq(ser->lock.gpio);
259*4882a593Smuzhiyun if (ser->lock.irq < 0)
260*4882a593Smuzhiyun return ser->lock.irq;
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun ret = devm_request_threaded_irq(dev, ser->lock.irq, NULL,
263*4882a593Smuzhiyun max96745_bridge_lock_irq_handler,
264*4882a593Smuzhiyun IRQF_TRIGGER_RISING | IRQF_ONESHOT,
265*4882a593Smuzhiyun dev_name(dev), ser);
266*4882a593Smuzhiyun if (ret)
267*4882a593Smuzhiyun return dev_err_probe(dev, ret, "failed to request lock IRQ\n");
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun ser->bridge.funcs = &max96745_bridge_funcs;
271*4882a593Smuzhiyun ser->bridge.of_node = dev->of_node;
272*4882a593Smuzhiyun ser->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_MODES;
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun drm_bridge_add(&ser->bridge);
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun return 0;
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun
max96745_bridge_remove(struct platform_device * pdev)279*4882a593Smuzhiyun static int max96745_bridge_remove(struct platform_device *pdev)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun struct max96745_bridge *ser = platform_get_drvdata(pdev);
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun drm_bridge_remove(&ser->bridge);
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun return 0;
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun static const struct of_device_id max96745_bridge_of_match[] = {
289*4882a593Smuzhiyun { .compatible = "maxim,max96745-bridge", },
290*4882a593Smuzhiyun {}
291*4882a593Smuzhiyun };
292*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, max96745_bridge_of_match);
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun static struct platform_driver max96745_bridge_driver = {
295*4882a593Smuzhiyun .driver = {
296*4882a593Smuzhiyun .name = "max96745-bridge",
297*4882a593Smuzhiyun .of_match_table = of_match_ptr(max96745_bridge_of_match),
298*4882a593Smuzhiyun },
299*4882a593Smuzhiyun .probe = max96745_bridge_probe,
300*4882a593Smuzhiyun .remove = max96745_bridge_remove,
301*4882a593Smuzhiyun };
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun module_platform_driver(max96745_bridge_driver);
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun MODULE_AUTHOR("Wyon Bi <bivvy.bi@rock-chips.com>");
306*4882a593Smuzhiyun MODULE_DESCRIPTION("Maxim MAX96745 GMSL2 Serializer with eDP1.4a/DP1.4 Input");
307*4882a593Smuzhiyun MODULE_LICENSE("GPL");
308