File Index
Files and directories
Sign in
FILE

dw_hdmi_qp-rockchip.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c C
  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/hw_bitfield.h>
 13#include <linux/mfd/syscon.h>
 14#include <linux/module.h>
 15#include <linux/platform_device.h>
 16#include <linux/phy/phy.h>
 17#include <linux/phy/phy-hdmi.h>
 18#include <linux/regmap.h>
 19#include <linux/workqueue.h>
 20
 21#include <drm/bridge/dw_hdmi_qp.h>
 22#include <drm/display/drm_hdmi_helper.h>
 23#include <drm/drm_bridge_connector.h>
 24#include <drm/drm_of.h>
 25#include <drm/drm_probe_helper.h>
 26#include <drm/drm_simple_kms_helper.h>
 27
 28#include "rockchip_drm_drv.h"
 29
 30#define RK3576_IOC_MISC_CON0		0xa400
 31#define RK3576_HDMI_HPD_INT_MSK		BIT(2)
 32#define RK3576_HDMI_HPD_INT_CLR		BIT(1)
 33
 34#define RK3576_IOC_HDMI_HPD_STATUS	0xa440
 35#define RK3576_HDMI_LEVEL_INT		BIT(3)
 36
 37#define RK3576_VO0_GRF_SOC_CON1		0x0004
 38#define RK3576_HDMI_FRL_MOD		BIT(0)
 39#define RK3576_HDMI_HDCP14_MEM_EN	BIT(15)
 40
 41#define RK3576_VO0_GRF_SOC_CON8		0x0020
 42#define RK3576_COLOR_DEPTH_MASK		GENMASK(11, 8)
 43#define RK3576_8BPC			0x0
 44#define RK3576_10BPC			0x6
 45#define RK3576_COLOR_FORMAT_MASK	GENMASK(7, 4)
 46#define RK3576_RGB			0x9
 47#define RK3576_YUV422			0x1
 48#define RK3576_YUV444			0x2
 49#define RK3576_YUV420			0x3
 50#define RK3576_CECIN_MASK		BIT(3)
 51
 52#define RK3576_VO0_GRF_SOC_CON14	0x0038
 53#define RK3576_I2S_SEL_MASK		BIT(0)
 54#define RK3576_SPDIF_SEL_MASK		BIT(1)
 55#define HDCP0_P1_GPIO_IN		BIT(2)
 56#define RK3576_SCLIN_MASK		BIT(4)
 57#define RK3576_SDAIN_MASK		BIT(5)
 58#define RK3576_HDMI_GRANT_SEL		BIT(6)
 59
 60#define RK3588_GRF_SOC_CON2		0x0308
 61#define RK3588_HDMI0_HPD_INT_MSK	BIT(13)
 62#define RK3588_HDMI0_HPD_INT_CLR	BIT(12)
 63#define RK3588_HDMI1_HPD_INT_MSK	BIT(15)
 64#define RK3588_HDMI1_HPD_INT_CLR	BIT(14)
 65#define RK3588_GRF_SOC_CON7		0x031c
 66#define RK3588_HPD_HDMI0_IO_EN_MASK	BIT(12)
 67#define RK3588_HPD_HDMI1_IO_EN_MASK	BIT(13)
 68#define RK3588_GRF_SOC_STATUS1		0x0384
 69#define RK3588_HDMI0_LEVEL_INT		BIT(16)
 70#define RK3588_HDMI1_LEVEL_INT		BIT(24)
 71#define RK3588_GRF_VO1_CON3		0x000c
 72#define RK3588_GRF_VO1_CON6		0x0018
 73#define RK3588_COLOR_DEPTH_MASK		GENMASK(7, 4)
 74#define RK3588_8BPC			0x0
 75#define RK3588_10BPC			0x6
 76#define RK3588_COLOR_FORMAT_MASK	GENMASK(3, 0)
 77#define RK3588_RGB			0x0
 78#define RK3588_YUV420			0x3
 79#define RK3588_SCLIN_MASK		BIT(9)
 80#define RK3588_SDAIN_MASK		BIT(10)
 81#define RK3588_MODE_MASK		BIT(11)
 82#define RK3588_I2S_SEL_MASK		BIT(13)
 83#define RK3588_GRF_VO1_CON9		0x0024
 84#define RK3588_HDMI0_GRANT_SEL		BIT(10)
 85#define RK3588_HDMI1_GRANT_SEL		BIT(12)
 86
 87#define HOTPLUG_DEBOUNCE_MS		150
 88#define MAX_HDMI_PORT_NUM		2
 89
 90struct rockchip_hdmi_qp {
 91	struct device *dev;
 92	struct regmap *regmap;
 93	struct regmap *vo_regmap;
 94	struct rockchip_encoder encoder;
 95	struct dw_hdmi_qp *hdmi;
 96	struct phy *phy;
 97	struct gpio_desc *frl_enable_gpio;
 98	struct delayed_work hpd_work;
 99	int port_id;
100	const struct rockchip_hdmi_qp_ctrl_ops *ctrl_ops;
101	unsigned long long tmds_char_rate;
102};
103
104struct rockchip_hdmi_qp_ctrl_ops {
105	void (*io_init)(struct rockchip_hdmi_qp *hdmi);
106	void (*enc_init)(struct rockchip_hdmi_qp *hdmi, struct rockchip_crtc_state *state);
107	irqreturn_t (*irq_callback)(int irq, void *dev_id);
108	irqreturn_t (*hardirq_callback)(int irq, void *dev_id);
109};
110
111static struct rockchip_hdmi_qp *to_rockchip_hdmi_qp(struct drm_encoder *encoder)
112{
113	struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
114
115	return container_of(rkencoder, struct rockchip_hdmi_qp, encoder);
116}
117
118static void dw_hdmi_qp_rockchip_encoder_enable(struct drm_encoder *encoder)
119{
120	struct rockchip_hdmi_qp *hdmi = to_rockchip_hdmi_qp(encoder);
121	struct drm_crtc *crtc = encoder->crtc;
122
123	/* Unconditionally switch to TMDS as FRL is not yet supported */
124	gpiod_set_value_cansleep(hdmi->frl_enable_gpio, 0);
125
126	if (!crtc || !crtc->state)
127		return;
128
129	if (hdmi->ctrl_ops->enc_init)
130		hdmi->ctrl_ops->enc_init(hdmi, to_rockchip_crtc_state(crtc->state));
131}
132
133static int
134dw_hdmi_qp_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
135					 struct drm_crtc_state *crtc_state,
136					 struct drm_connector_state *conn_state)
137{
138	struct rockchip_hdmi_qp *hdmi = to_rockchip_hdmi_qp(encoder);
139	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
140	union phy_configure_opts phy_cfg = {};
141	int ret;
142
143	if (hdmi->tmds_char_rate == conn_state->hdmi.tmds_char_rate &&
144	    s->output_bpc == conn_state->hdmi.output_bpc)
145		return 0;
146
147	phy_cfg.hdmi.tmds_char_rate = conn_state->hdmi.tmds_char_rate;
148	phy_cfg.hdmi.bpc = conn_state->hdmi.output_bpc;
149
150	ret = phy_configure(hdmi->phy, &phy_cfg);
151	if (!ret) {
152		hdmi->tmds_char_rate = conn_state->hdmi.tmds_char_rate;
153		s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
154		s->output_type = DRM_MODE_CONNECTOR_HDMIA;
155		s->output_bpc = conn_state->hdmi.output_bpc;
156	} else {
157		dev_err(hdmi->dev, "Failed to configure phy: %d\n", ret);
158	}
159
160	return ret;
161}
162
163static const struct
164drm_encoder_helper_funcs dw_hdmi_qp_rockchip_encoder_helper_funcs = {
165	.enable		= dw_hdmi_qp_rockchip_encoder_enable,
166	.atomic_check	= dw_hdmi_qp_rockchip_encoder_atomic_check,
167};
168
169static int dw_hdmi_qp_rk3588_phy_init(struct dw_hdmi_qp *dw_hdmi, void *data)
170{
171	struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
172
173	return phy_power_on(hdmi->phy);
174}
175
176static void dw_hdmi_qp_rk3588_phy_disable(struct dw_hdmi_qp *dw_hdmi,
177					  void *data)
178{
179	struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
180
181	phy_power_off(hdmi->phy);
182}
183
184static enum drm_connector_status
185dw_hdmi_qp_rk3588_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
186{
187	struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
188	u32 val;
189
190	regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &val);
191	val &= hdmi->port_id ? RK3588_HDMI1_LEVEL_INT : RK3588_HDMI0_LEVEL_INT;
192
193	return val ? connector_status_connected : connector_status_disconnected;
194}
195
196static void dw_hdmi_qp_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
197{
198	struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
199	u32 val;
200
201	if (hdmi->port_id)
202		val = (FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_CLR, 1) |
203		       FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 0));
204	else
205		val = (FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_CLR, 1) |
206		       FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 0));
207
208	regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
209}
210
211static const struct dw_hdmi_qp_phy_ops rk3588_hdmi_phy_ops = {
212	.init		= dw_hdmi_qp_rk3588_phy_init,
213	.disable	= dw_hdmi_qp_rk3588_phy_disable,
214	.read_hpd	= dw_hdmi_qp_rk3588_read_hpd,
215	.setup_hpd	= dw_hdmi_qp_rk3588_setup_hpd,
216};
217
218static enum drm_connector_status
219dw_hdmi_qp_rk3576_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
220{
221	struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
222	u32 val;
223
224	regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &val);
225
226	return val & RK3576_HDMI_LEVEL_INT ?
227		connector_status_connected : connector_status_disconnected;
228}
229
230static void dw_hdmi_qp_rk3576_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
231{
232	struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
233	u32 val;
234
235	val = (FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1) |
236	       FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0));
237
238	regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
239	regmap_write(hdmi->regmap, 0xa404, 0xffff0102);
240}
241
242static const struct dw_hdmi_qp_phy_ops rk3576_hdmi_phy_ops = {
243	.init		= dw_hdmi_qp_rk3588_phy_init,
244	.disable	= dw_hdmi_qp_rk3588_phy_disable,
245	.read_hpd	= dw_hdmi_qp_rk3576_read_hpd,
246	.setup_hpd	= dw_hdmi_qp_rk3576_setup_hpd,
247};
248
249static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work)
250{
251	struct rockchip_hdmi_qp *hdmi = container_of(work,
252						     struct rockchip_hdmi_qp,
253						     hpd_work.work);
254	struct drm_device *drm = hdmi->encoder.encoder.dev;
255	bool changed;
256
257	if (drm) {
258		changed = drm_helper_hpd_irq_event(drm);
259		if (changed)
260			dev_dbg(hdmi->dev, "connector status changed\n");
261	}
262}
263
264static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
265{
266	struct rockchip_hdmi_qp *hdmi = dev_id;
267	u32 intr_stat, val;
268
269	regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &intr_stat);
270	if (intr_stat) {
271		val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1);
272
273		regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
274		return IRQ_WAKE_THREAD;
275	}
276
277	return IRQ_NONE;
278}
279
280static irqreturn_t dw_hdmi_qp_rk3576_irq(int irq, void *dev_id)
281{
282	struct rockchip_hdmi_qp *hdmi = dev_id;
283	u32 val;
284
285	val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1);
286	regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
287	mod_delayed_work(system_wq, &hdmi->hpd_work,
288			 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
289
290	val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0);
291	regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
292
293	return IRQ_HANDLED;
294}
295
296static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id)
297{
298	struct rockchip_hdmi_qp *hdmi = dev_id;
299	u32 intr_stat, val;
300
301	regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat);
302
303	if (intr_stat) {
304		if (hdmi->port_id)
305			val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
306		else
307			val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1);
308		regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
309		return IRQ_WAKE_THREAD;
310	}
311
312	return IRQ_NONE;
313}
314
315static irqreturn_t dw_hdmi_qp_rk3588_irq(int irq, void *dev_id)
316{
317	struct rockchip_hdmi_qp *hdmi = dev_id;
318	u32 intr_stat, val;
319
320	regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat);
321	if (!intr_stat)
322		return IRQ_NONE;
323
324	if (hdmi->port_id)
325		val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_CLR, 1);
326	else
327		val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_CLR, 1);
328	regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
329
330	mod_delayed_work(system_wq, &hdmi->hpd_work,
331			 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
332
333	if (hdmi->port_id)
334		val |= FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 0);
335	else
336		val |= FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 0);
337	regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
338
339	return IRQ_HANDLED;
340}
341
342static void dw_hdmi_qp_rk3576_io_init(struct rockchip_hdmi_qp *hdmi)
343{
344	u32 val;
345
346	val = FIELD_PREP_WM16(RK3576_SCLIN_MASK, 1) |
347	      FIELD_PREP_WM16(RK3576_SDAIN_MASK, 1) |
348	      FIELD_PREP_WM16(RK3576_HDMI_GRANT_SEL, 1) |
349	      FIELD_PREP_WM16(RK3576_I2S_SEL_MASK, 1);
350
351	regmap_write(hdmi->vo_regmap, RK3576_VO0_GRF_SOC_CON14, val);
352
353	val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0);
354	regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
355}
356
357static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi)
358{
359	u32 val;
360
361	val = FIELD_PREP_WM16(RK3588_SCLIN_MASK, 1) |
362	      FIELD_PREP_WM16(RK3588_SDAIN_MASK, 1) |
363	      FIELD_PREP_WM16(RK3588_MODE_MASK, 1) |
364	      FIELD_PREP_WM16(RK3588_I2S_SEL_MASK, 1);
365	regmap_write(hdmi->vo_regmap,
366		     hdmi->port_id ? RK3588_GRF_VO1_CON6 : RK3588_GRF_VO1_CON3,
367		     val);
368
369	val = FIELD_PREP_WM16(RK3588_HPD_HDMI0_IO_EN_MASK, 1) |
370	      FIELD_PREP_WM16(RK3588_HPD_HDMI1_IO_EN_MASK, 1);
371	regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val);
372
373	if (hdmi->port_id)
374		val = FIELD_PREP_WM16(RK3588_HDMI1_GRANT_SEL, 1);
375	else
376		val = FIELD_PREP_WM16(RK3588_HDMI0_GRANT_SEL, 1);
377	regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val);
378
379	if (hdmi->port_id)
380		val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
381	else
382		val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1);
383	regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
384}
385
386static void dw_hdmi_qp_rk3576_enc_init(struct rockchip_hdmi_qp *hdmi,
387				       struct rockchip_crtc_state *state)
388{
389	u32 val;
390
391	if (state->output_bpc == 10)
392		val = FIELD_PREP_WM16(RK3576_COLOR_DEPTH_MASK, RK3576_10BPC);
393	else
394		val = FIELD_PREP_WM16(RK3576_COLOR_DEPTH_MASK, RK3576_8BPC);
395
396	regmap_write(hdmi->vo_regmap, RK3576_VO0_GRF_SOC_CON8, val);
397}
398
399static void dw_hdmi_qp_rk3588_enc_init(struct rockchip_hdmi_qp *hdmi,
400				       struct rockchip_crtc_state *state)
401{
402	u32 val;
403
404	if (state->output_bpc == 10)
405		val = FIELD_PREP_WM16(RK3588_COLOR_DEPTH_MASK, RK3588_10BPC);
406	else
407		val = FIELD_PREP_WM16(RK3588_COLOR_DEPTH_MASK, RK3588_8BPC);
408
409	regmap_write(hdmi->vo_regmap,
410		     hdmi->port_id ? RK3588_GRF_VO1_CON6 : RK3588_GRF_VO1_CON3,
411		     val);
412}
413
414static const struct rockchip_hdmi_qp_ctrl_ops rk3576_hdmi_ctrl_ops = {
415	.io_init		= dw_hdmi_qp_rk3576_io_init,
416	.enc_init		= dw_hdmi_qp_rk3576_enc_init,
417	.irq_callback		= dw_hdmi_qp_rk3576_irq,
418	.hardirq_callback	= dw_hdmi_qp_rk3576_hardirq,
419};
420
421static const struct rockchip_hdmi_qp_ctrl_ops rk3588_hdmi_ctrl_ops = {
422	.io_init		= dw_hdmi_qp_rk3588_io_init,
423	.enc_init		= dw_hdmi_qp_rk3588_enc_init,
424	.irq_callback		= dw_hdmi_qp_rk3588_irq,
425	.hardirq_callback	= dw_hdmi_qp_rk3588_hardirq,
426};
427
428struct rockchip_hdmi_qp_cfg {
429	unsigned int num_ports;
430	unsigned int port_ids[MAX_HDMI_PORT_NUM];
431	const struct rockchip_hdmi_qp_ctrl_ops *ctrl_ops;
432	const struct dw_hdmi_qp_phy_ops *phy_ops;
433};
434
435static const struct rockchip_hdmi_qp_cfg rk3576_hdmi_cfg = {
436	.num_ports = 1,
437	.port_ids = {
438		0x27da0000,
439	},
440	.ctrl_ops = &rk3576_hdmi_ctrl_ops,
441	.phy_ops = &rk3576_hdmi_phy_ops,
442};
443
444static const struct rockchip_hdmi_qp_cfg rk3588_hdmi_cfg = {
445	.num_ports = 2,
446	.port_ids = {
447		0xfde80000,
448		0xfdea0000,
449	},
450	.ctrl_ops = &rk3588_hdmi_ctrl_ops,
451	.phy_ops = &rk3588_hdmi_phy_ops,
452};
453
454static const struct of_device_id dw_hdmi_qp_rockchip_dt_ids[] = {
455	{
456		.compatible = "rockchip,rk3576-dw-hdmi-qp",
457		.data = &rk3576_hdmi_cfg
458	}, {
459		.compatible = "rockchip,rk3588-dw-hdmi-qp",
460		.data = &rk3588_hdmi_cfg
461	},
462	{},
463};
464MODULE_DEVICE_TABLE(of, dw_hdmi_qp_rockchip_dt_ids);
465
466static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
467				    void *data)
468{
469	struct platform_device *pdev = to_platform_device(dev);
470	struct dw_hdmi_qp_plat_data plat_data = {};
471	const struct rockchip_hdmi_qp_cfg *cfg;
472	struct drm_device *drm = data;
473	struct drm_connector *connector;
474	struct drm_encoder *encoder;
475	struct rockchip_hdmi_qp *hdmi;
476	struct resource *res;
477	struct clk_bulk_data *clks;
478	struct clk *ref_clk;
479	int ret, irq, i;
480
481	if (!pdev->dev.of_node)
482		return -ENODEV;
483
484	hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
485	if (!hdmi)
486		return -ENOMEM;
487
488	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
489	if (!res)
490		return -ENODEV;
491
492	cfg = of_device_get_match_data(dev);
493	if (!cfg)
494		return -ENODEV;
495
496	if (!cfg->ctrl_ops || !cfg->ctrl_ops->io_init ||
497	    !cfg->ctrl_ops->irq_callback || !cfg->ctrl_ops->hardirq_callback)
498		return dev_err_probe(dev, -ENODEV, "Missing platform ctrl ops\n");
499
500	hdmi->ctrl_ops = cfg->ctrl_ops;
501	hdmi->dev = &pdev->dev;
502	hdmi->port_id = -ENODEV;
503
504	/* Identify port ID by matching base IO address */
505	for (i = 0; i < cfg->num_ports; i++) {
506		if (res->start == cfg->port_ids[i]) {
507			hdmi->port_id = i;
508			break;
509		}
510	}
511	if (hdmi->port_id < 0)
512		return dev_err_probe(hdmi->dev, hdmi->port_id,
513				     "Failed to match HDMI port ID\n");
514
515	plat_data.phy_ops = cfg->phy_ops;
516	plat_data.phy_data = hdmi;
517	plat_data.max_bpc = 10;
518
519	encoder = &hdmi->encoder.encoder;
520	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
521
522	rockchip_drm_encoder_set_crtc_endpoint_id(&hdmi->encoder,
523						  dev->of_node, 0, 0);
524	/*
525	 * If we failed to find the CRTC(s) which this encoder is
526	 * supposed to be connected to, it's because the CRTC has
527	 * not been registered yet.  Defer probing, and hope that
528	 * the required CRTC is added later.
529	 */
530	if (encoder->possible_crtcs == 0)
531		return -EPROBE_DEFER;
532
533	hdmi->regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
534						       "rockchip,grf");
535	if (IS_ERR(hdmi->regmap))
536		return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->regmap),
537				     "Unable to get rockchip,grf\n");
538
539	hdmi->vo_regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
540							  "rockchip,vo-grf");
541	if (IS_ERR(hdmi->vo_regmap))
542		return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->vo_regmap),
543				     "Unable to get rockchip,vo-grf\n");
544
545	ret = devm_clk_bulk_get_all_enabled(hdmi->dev, &clks);
546	if (ret < 0)
547		return dev_err_probe(hdmi->dev, ret, "Failed to get clocks\n");
548
549	ref_clk = clk_get(hdmi->dev, "ref");
550	if (IS_ERR(ref_clk))
551		return dev_err_probe(hdmi->dev, PTR_ERR(ref_clk),
552				     "Failed to get ref clock\n");
553
554	plat_data.ref_clk_rate = clk_get_rate(ref_clk);
555	clk_put(ref_clk);
556
557	hdmi->frl_enable_gpio = devm_gpiod_get_optional(hdmi->dev, "frl-enable",
558							GPIOD_OUT_LOW);
559	if (IS_ERR(hdmi->frl_enable_gpio))
560		return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->frl_enable_gpio),
561				     "Failed to request FRL enable GPIO\n");
562
563	hdmi->phy = devm_of_phy_get_by_index(dev, dev->of_node, 0);
564	if (IS_ERR(hdmi->phy))
565		return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->phy),
566				     "Failed to get phy\n");
567
568	cfg->ctrl_ops->io_init(hdmi);
569
570	INIT_DELAYED_WORK(&hdmi->hpd_work, dw_hdmi_qp_rk3588_hpd_work);
571
572	plat_data.main_irq = platform_get_irq_byname(pdev, "main");
573	if (plat_data.main_irq < 0)
574		return plat_data.main_irq;
575
576	plat_data.cec_irq = platform_get_irq_byname(pdev, "cec");
577	if (plat_data.cec_irq < 0)
578		return plat_data.cec_irq;
579
580	irq = platform_get_irq_byname(pdev, "hpd");
581	if (irq < 0)
582		return irq;
583
584	ret = devm_request_threaded_irq(hdmi->dev, irq,
585					cfg->ctrl_ops->hardirq_callback,
586					cfg->ctrl_ops->irq_callback,
587					IRQF_SHARED, "dw-hdmi-qp-hpd",
588					hdmi);
589	if (ret)
590		return ret;
591
592	drm_encoder_helper_add(encoder, &dw_hdmi_qp_rockchip_encoder_helper_funcs);
593	drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
594
595	platform_set_drvdata(pdev, hdmi);
596
597	hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, &plat_data);
598	if (IS_ERR(hdmi->hdmi)) {
599		drm_encoder_cleanup(encoder);
600		return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->hdmi),
601				     "Failed to bind dw-hdmi-qp");
602	}
603
604	connector = drm_bridge_connector_init(drm, encoder);
605	if (IS_ERR(connector))
606		return dev_err_probe(hdmi->dev, PTR_ERR(connector),
607				     "Failed to init bridge connector\n");
608
609	return drm_connector_attach_encoder(connector, encoder);
610}
611
612static void dw_hdmi_qp_rockchip_unbind(struct device *dev,
613				       struct device *master,
614				       void *data)
615{
616	struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
617
618	cancel_delayed_work_sync(&hdmi->hpd_work);
619
620	drm_encoder_cleanup(&hdmi->encoder.encoder);
621}
622
623static const struct component_ops dw_hdmi_qp_rockchip_ops = {
624	.bind	= dw_hdmi_qp_rockchip_bind,
625	.unbind	= dw_hdmi_qp_rockchip_unbind,
626};
627
628static int dw_hdmi_qp_rockchip_probe(struct platform_device *pdev)
629{
630	return component_add(&pdev->dev, &dw_hdmi_qp_rockchip_ops);
631}
632
633static void dw_hdmi_qp_rockchip_remove(struct platform_device *pdev)
634{
635	component_del(&pdev->dev, &dw_hdmi_qp_rockchip_ops);
636}
637
638static int __maybe_unused dw_hdmi_qp_rockchip_suspend(struct device *dev)
639{
640	struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
641
642	dw_hdmi_qp_suspend(dev, hdmi->hdmi);
643
644	return 0;
645}
646
647static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev)
648{
649	struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
650
651	hdmi->ctrl_ops->io_init(hdmi);
652
653	dw_hdmi_qp_resume(dev, hdmi->hdmi);
654
655	if (hdmi->encoder.encoder.dev)
656		drm_helper_hpd_irq_event(hdmi->encoder.encoder.dev);
657
658	return 0;
659}
660
661static const struct dev_pm_ops dw_hdmi_qp_rockchip_pm = {
662	SET_SYSTEM_SLEEP_PM_OPS(dw_hdmi_qp_rockchip_suspend,
663				dw_hdmi_qp_rockchip_resume)
664};
665
666struct platform_driver dw_hdmi_qp_rockchip_pltfm_driver = {
667	.probe = dw_hdmi_qp_rockchip_probe,
668	.remove = dw_hdmi_qp_rockchip_remove,
669	.driver = {
670		.name = "dwhdmiqp-rockchip",
671		.pm = &dw_hdmi_qp_rockchip_pm,
672		.of_match_table = dw_hdmi_qp_rockchip_dt_ids,
673	},
674};
~/ Read-only file preview.