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