xref: /linux/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c (revision 6a34dfa15d6edf7e78b8118d862d2db0889cf669)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd.
4  * Copyright (c) 2024 Collabora Ltd.
5  *
6  * Author: Algea Cao <algea.cao@rock-chips.com>
7  * Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
8  */
9 
10 #include <linux/clk.h>
11 #include <linux/gpio/consumer.h>
12 #include <linux/mfd/syscon.h>
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/phy/phy.h>
16 #include <linux/regmap.h>
17 #include <linux/workqueue.h>
18 
19 #include <drm/bridge/dw_hdmi_qp.h>
20 #include <drm/display/drm_hdmi_helper.h>
21 #include <drm/drm_bridge_connector.h>
22 #include <drm/drm_of.h>
23 #include <drm/drm_probe_helper.h>
24 #include <drm/drm_simple_kms_helper.h>
25 
26 #include "rockchip_drm_drv.h"
27 
28 #define RK3588_GRF_SOC_CON2		0x0308
29 #define RK3588_HDMI0_HPD_INT_MSK	BIT(13)
30 #define RK3588_HDMI0_HPD_INT_CLR	BIT(12)
31 #define RK3588_GRF_SOC_CON7		0x031c
32 #define RK3588_SET_HPD_PATH_MASK	GENMASK(13, 12)
33 #define RK3588_GRF_SOC_STATUS1		0x0384
34 #define RK3588_HDMI0_LEVEL_INT		BIT(16)
35 #define RK3588_GRF_VO1_CON3		0x000c
36 #define RK3588_SCLIN_MASK		BIT(9)
37 #define RK3588_SDAIN_MASK		BIT(10)
38 #define RK3588_MODE_MASK		BIT(11)
39 #define RK3588_I2S_SEL_MASK		BIT(13)
40 #define RK3588_GRF_VO1_CON9		0x0024
41 #define RK3588_HDMI0_GRANT_SEL		BIT(10)
42 
43 #define HIWORD_UPDATE(val, mask)	((val) | (mask) << 16)
44 #define HOTPLUG_DEBOUNCE_MS		150
45 
46 struct rockchip_hdmi_qp {
47 	struct device *dev;
48 	struct regmap *regmap;
49 	struct regmap *vo_regmap;
50 	struct rockchip_encoder encoder;
51 	struct clk *ref_clk;
52 	struct dw_hdmi_qp *hdmi;
53 	struct phy *phy;
54 	struct gpio_desc *enable_gpio;
55 	struct delayed_work hpd_work;
56 };
57 
58 static struct rockchip_hdmi_qp *to_rockchip_hdmi_qp(struct drm_encoder *encoder)
59 {
60 	struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
61 
62 	return container_of(rkencoder, struct rockchip_hdmi_qp, encoder);
63 }
64 
65 static void dw_hdmi_qp_rockchip_encoder_enable(struct drm_encoder *encoder)
66 {
67 	struct rockchip_hdmi_qp *hdmi = to_rockchip_hdmi_qp(encoder);
68 	struct drm_crtc *crtc = encoder->crtc;
69 	unsigned long long rate;
70 
71 	/* Unconditionally switch to TMDS as FRL is not yet supported */
72 	gpiod_set_value(hdmi->enable_gpio, 1);
73 
74 	if (crtc && crtc->state) {
75 		rate = drm_hdmi_compute_mode_clock(&crtc->state->adjusted_mode,
76 						   8, HDMI_COLORSPACE_RGB);
77 		clk_set_rate(hdmi->ref_clk, rate);
78 		/*
79 		 * FIXME: Temporary workaround to pass pixel clock rate
80 		 * to the PHY driver until phy_configure_opts_hdmi
81 		 * becomes available in the PHY API. See also the related
82 		 * comment in rk_hdptx_phy_power_on() from
83 		 * drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
84 		 */
85 		phy_set_bus_width(hdmi->phy, div_u64(rate, 100));
86 	}
87 }
88 
89 static int
90 dw_hdmi_qp_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
91 					 struct drm_crtc_state *crtc_state,
92 					 struct drm_connector_state *conn_state)
93 {
94 	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
95 
96 	s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
97 	s->output_type = DRM_MODE_CONNECTOR_HDMIA;
98 
99 	return 0;
100 }
101 
102 static const struct
103 drm_encoder_helper_funcs dw_hdmi_qp_rockchip_encoder_helper_funcs = {
104 	.enable		= dw_hdmi_qp_rockchip_encoder_enable,
105 	.atomic_check	= dw_hdmi_qp_rockchip_encoder_atomic_check,
106 };
107 
108 static int dw_hdmi_qp_rk3588_phy_init(struct dw_hdmi_qp *dw_hdmi, void *data)
109 {
110 	struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
111 
112 	return phy_power_on(hdmi->phy);
113 }
114 
115 static void dw_hdmi_qp_rk3588_phy_disable(struct dw_hdmi_qp *dw_hdmi,
116 					  void *data)
117 {
118 	struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
119 
120 	phy_power_off(hdmi->phy);
121 }
122 
123 static enum drm_connector_status
124 dw_hdmi_qp_rk3588_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
125 {
126 	struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
127 	u32 val;
128 
129 	regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &val);
130 
131 	return val & RK3588_HDMI0_LEVEL_INT ?
132 		connector_status_connected : connector_status_disconnected;
133 }
134 
135 static void dw_hdmi_qp_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
136 {
137 	struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
138 
139 	regmap_write(hdmi->regmap,
140 		     RK3588_GRF_SOC_CON2,
141 		     HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR,
142 				   RK3588_HDMI0_HPD_INT_CLR |
143 				   RK3588_HDMI0_HPD_INT_MSK));
144 }
145 
146 static const struct dw_hdmi_qp_phy_ops rk3588_hdmi_phy_ops = {
147 	.init		= dw_hdmi_qp_rk3588_phy_init,
148 	.disable	= dw_hdmi_qp_rk3588_phy_disable,
149 	.read_hpd	= dw_hdmi_qp_rk3588_read_hpd,
150 	.setup_hpd	= dw_hdmi_qp_rk3588_setup_hpd,
151 };
152 
153 static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work)
154 {
155 	struct rockchip_hdmi_qp *hdmi = container_of(work,
156 						     struct rockchip_hdmi_qp,
157 						     hpd_work.work);
158 	struct drm_device *drm = hdmi->encoder.encoder.dev;
159 	bool changed;
160 
161 	if (drm) {
162 		changed = drm_helper_hpd_irq_event(drm);
163 		if (changed)
164 			drm_dbg(hdmi, "connector status changed\n");
165 	}
166 }
167 
168 static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id)
169 {
170 	struct rockchip_hdmi_qp *hdmi = dev_id;
171 	u32 intr_stat, val;
172 
173 	regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat);
174 
175 	if (intr_stat) {
176 		val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK,
177 				    RK3588_HDMI0_HPD_INT_MSK);
178 		regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
179 		return IRQ_WAKE_THREAD;
180 	}
181 
182 	return IRQ_NONE;
183 }
184 
185 static irqreturn_t dw_hdmi_qp_rk3588_irq(int irq, void *dev_id)
186 {
187 	struct rockchip_hdmi_qp *hdmi = dev_id;
188 	u32 intr_stat, val;
189 
190 	regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat);
191 	if (!intr_stat)
192 		return IRQ_NONE;
193 
194 	val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR,
195 			    RK3588_HDMI0_HPD_INT_CLR);
196 	regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
197 
198 	mod_delayed_work(system_wq, &hdmi->hpd_work,
199 			 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
200 
201 	val |= HIWORD_UPDATE(0, RK3588_HDMI0_HPD_INT_MSK);
202 	regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
203 
204 	return IRQ_HANDLED;
205 }
206 
207 static const struct of_device_id dw_hdmi_qp_rockchip_dt_ids[] = {
208 	{ .compatible = "rockchip,rk3588-dw-hdmi-qp",
209 	  .data = &rk3588_hdmi_phy_ops },
210 	{},
211 };
212 MODULE_DEVICE_TABLE(of, dw_hdmi_qp_rockchip_dt_ids);
213 
214 static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
215 				    void *data)
216 {
217 	static const char * const clk_names[] = {
218 		"pclk", "earc", "aud", "hdp", "hclk_vo1",
219 		"ref" /* keep "ref" last */
220 	};
221 	struct platform_device *pdev = to_platform_device(dev);
222 	struct dw_hdmi_qp_plat_data plat_data;
223 	struct drm_device *drm = data;
224 	struct drm_connector *connector;
225 	struct drm_encoder *encoder;
226 	struct rockchip_hdmi_qp *hdmi;
227 	struct clk *clk;
228 	int ret, irq, i;
229 	u32 val;
230 
231 	if (!pdev->dev.of_node)
232 		return -ENODEV;
233 
234 	hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
235 	if (!hdmi)
236 		return -ENOMEM;
237 
238 	plat_data.phy_ops = of_device_get_match_data(dev);
239 	if (!plat_data.phy_ops)
240 		return -ENODEV;
241 
242 	plat_data.phy_data = hdmi;
243 	hdmi->dev = &pdev->dev;
244 
245 	encoder = &hdmi->encoder.encoder;
246 	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
247 
248 	rockchip_drm_encoder_set_crtc_endpoint_id(&hdmi->encoder,
249 						  dev->of_node, 0, 0);
250 	/*
251 	 * If we failed to find the CRTC(s) which this encoder is
252 	 * supposed to be connected to, it's because the CRTC has
253 	 * not been registered yet.  Defer probing, and hope that
254 	 * the required CRTC is added later.
255 	 */
256 	if (encoder->possible_crtcs == 0)
257 		return -EPROBE_DEFER;
258 
259 	hdmi->regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
260 						       "rockchip,grf");
261 	if (IS_ERR(hdmi->regmap)) {
262 		drm_err(hdmi, "Unable to get rockchip,grf\n");
263 		return PTR_ERR(hdmi->regmap);
264 	}
265 
266 	hdmi->vo_regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
267 							  "rockchip,vo-grf");
268 	if (IS_ERR(hdmi->vo_regmap)) {
269 		drm_err(hdmi, "Unable to get rockchip,vo-grf\n");
270 		return PTR_ERR(hdmi->vo_regmap);
271 	}
272 
273 	for (i = 0; i < ARRAY_SIZE(clk_names); i++) {
274 		clk = devm_clk_get_enabled(hdmi->dev, clk_names[i]);
275 
276 		if (IS_ERR(clk)) {
277 			ret = PTR_ERR(clk);
278 			if (ret != -EPROBE_DEFER)
279 				drm_err(hdmi, "Failed to get %s clock: %d\n",
280 					clk_names[i], ret);
281 			return ret;
282 		}
283 	}
284 	hdmi->ref_clk = clk;
285 
286 	hdmi->enable_gpio = devm_gpiod_get_optional(hdmi->dev, "enable",
287 						    GPIOD_OUT_HIGH);
288 	if (IS_ERR(hdmi->enable_gpio)) {
289 		ret = PTR_ERR(hdmi->enable_gpio);
290 		drm_err(hdmi, "Failed to request enable GPIO: %d\n", ret);
291 		return ret;
292 	}
293 
294 	hdmi->phy = devm_of_phy_get_by_index(dev, dev->of_node, 0);
295 	if (IS_ERR(hdmi->phy)) {
296 		ret = PTR_ERR(hdmi->phy);
297 		if (ret != -EPROBE_DEFER)
298 			drm_err(hdmi, "failed to get phy: %d\n", ret);
299 		return ret;
300 	}
301 
302 	val = HIWORD_UPDATE(RK3588_SCLIN_MASK, RK3588_SCLIN_MASK) |
303 	      HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) |
304 	      HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) |
305 	      HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK);
306 	regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON3, val);
307 
308 	val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK,
309 			    RK3588_SET_HPD_PATH_MASK);
310 	regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val);
311 
312 	val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL,
313 			    RK3588_HDMI0_GRANT_SEL);
314 	regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val);
315 
316 	val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK, RK3588_HDMI0_HPD_INT_MSK);
317 	regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
318 
319 	INIT_DELAYED_WORK(&hdmi->hpd_work, dw_hdmi_qp_rk3588_hpd_work);
320 
321 	plat_data.main_irq = platform_get_irq_byname(pdev, "main");
322 	if (plat_data.main_irq < 0)
323 		return plat_data.main_irq;
324 
325 	irq = platform_get_irq_byname(pdev, "hpd");
326 	if (irq < 0)
327 		return irq;
328 
329 	ret = devm_request_threaded_irq(hdmi->dev, irq,
330 					dw_hdmi_qp_rk3588_hardirq,
331 					dw_hdmi_qp_rk3588_irq,
332 					IRQF_SHARED, "dw-hdmi-qp-hpd",
333 					hdmi);
334 	if (ret)
335 		return ret;
336 
337 	drm_encoder_helper_add(encoder, &dw_hdmi_qp_rockchip_encoder_helper_funcs);
338 	drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
339 
340 	platform_set_drvdata(pdev, hdmi);
341 
342 	hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, &plat_data);
343 	if (IS_ERR(hdmi->hdmi)) {
344 		ret = PTR_ERR(hdmi->hdmi);
345 		drm_encoder_cleanup(encoder);
346 		return ret;
347 	}
348 
349 	connector = drm_bridge_connector_init(drm, encoder);
350 	if (IS_ERR(connector)) {
351 		ret = PTR_ERR(connector);
352 		drm_err(hdmi, "failed to init bridge connector: %d\n", ret);
353 		return ret;
354 	}
355 
356 	return drm_connector_attach_encoder(connector, encoder);
357 }
358 
359 static void dw_hdmi_qp_rockchip_unbind(struct device *dev,
360 				       struct device *master,
361 				       void *data)
362 {
363 	struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
364 
365 	cancel_delayed_work_sync(&hdmi->hpd_work);
366 
367 	drm_encoder_cleanup(&hdmi->encoder.encoder);
368 }
369 
370 static const struct component_ops dw_hdmi_qp_rockchip_ops = {
371 	.bind	= dw_hdmi_qp_rockchip_bind,
372 	.unbind	= dw_hdmi_qp_rockchip_unbind,
373 };
374 
375 static int dw_hdmi_qp_rockchip_probe(struct platform_device *pdev)
376 {
377 	return component_add(&pdev->dev, &dw_hdmi_qp_rockchip_ops);
378 }
379 
380 static void dw_hdmi_qp_rockchip_remove(struct platform_device *pdev)
381 {
382 	component_del(&pdev->dev, &dw_hdmi_qp_rockchip_ops);
383 }
384 
385 static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev)
386 {
387 	struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
388 	u32 val;
389 
390 	val = HIWORD_UPDATE(RK3588_SCLIN_MASK, RK3588_SCLIN_MASK) |
391 	      HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) |
392 	      HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) |
393 	      HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK);
394 	regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON3, val);
395 
396 	val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK,
397 			    RK3588_SET_HPD_PATH_MASK);
398 	regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val);
399 
400 	val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL,
401 			    RK3588_HDMI0_GRANT_SEL);
402 	regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val);
403 
404 	dw_hdmi_qp_resume(dev, hdmi->hdmi);
405 
406 	if (hdmi->encoder.encoder.dev)
407 		drm_helper_hpd_irq_event(hdmi->encoder.encoder.dev);
408 
409 	return 0;
410 }
411 
412 static const struct dev_pm_ops dw_hdmi_qp_rockchip_pm = {
413 	SET_SYSTEM_SLEEP_PM_OPS(NULL, dw_hdmi_qp_rockchip_resume)
414 };
415 
416 struct platform_driver dw_hdmi_qp_rockchip_pltfm_driver = {
417 	.probe = dw_hdmi_qp_rockchip_probe,
418 	.remove = dw_hdmi_qp_rockchip_remove,
419 	.driver = {
420 		.name = "dwhdmiqp-rockchip",
421 		.pm = &dw_hdmi_qp_rockchip_pm,
422 		.of_match_table = dw_hdmi_qp_rockchip_dt_ids,
423 	},
424 };
425