xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/bridge/maxim-max96745.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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, &reg);
96*4882a593Smuzhiyun 	cxtp = FIELD_GET(CXTP_A, reg);
97*4882a593Smuzhiyun 	regmap_read(ser->regmap, 0x0028, &reg);
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, &reg);
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, &reg);
139*4882a593Smuzhiyun 	cxtp = FIELD_GET(CXTP_A, reg);
140*4882a593Smuzhiyun 	regmap_read(ser->regmap, 0x0028, &reg);
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