Lines Matching +full:hdmi +full:- +full:switch
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd.
6 * Author: Algea Cao <algea.cao@rock-chips.com>
10 #include <linux/hdmi.h>
28 #include <sound/hdmi-codec.h>
30 #include "dw-hdmi-qp.h"
42 * slow so we pre-compute values we expect to see.
45 * the recommended N values specified in the Audio chapter of the HDMI
92 /* For 297 MHz+ HDMI spec have some other rule for setting N */
101 * These are the CTS values as recommended in the Audio chapter of the HDMI
149 static void dw_hdmi_qp_write(struct dw_hdmi_qp *hdmi, unsigned int val, in dw_hdmi_qp_write() argument
152 regmap_write(hdmi->regm, offset, val); in dw_hdmi_qp_write()
155 static unsigned int dw_hdmi_qp_read(struct dw_hdmi_qp *hdmi, int offset) in dw_hdmi_qp_read() argument
159 regmap_read(hdmi->regm, offset, &val); in dw_hdmi_qp_read()
164 static void dw_hdmi_qp_mod(struct dw_hdmi_qp *hdmi, unsigned int data, in dw_hdmi_qp_mod() argument
167 regmap_update_bits(hdmi->regm, reg, mask, data); in dw_hdmi_qp_mod()
175 static void dw_hdmi_qp_set_cts_n(struct dw_hdmi_qp *hdmi, unsigned int cts, in dw_hdmi_qp_set_cts_n() argument
179 dw_hdmi_qp_mod(hdmi, n, AUDPKT_ACR_N_VALUE, AUDPKT_ACR_CONTROL0); in dw_hdmi_qp_set_cts_n()
183 dw_hdmi_qp_mod(hdmi, AUDPKT_ACR_CTS_OVR_EN, AUDPKT_ACR_CTS_OVR_EN_MSK, in dw_hdmi_qp_set_cts_n()
186 dw_hdmi_qp_mod(hdmi, 0, AUDPKT_ACR_CTS_OVR_EN_MSK, in dw_hdmi_qp_set_cts_n()
189 dw_hdmi_qp_mod(hdmi, AUDPKT_ACR_CTS_OVR_VAL(cts), AUDPKT_ACR_CTS_OVR_VAL_MSK, in dw_hdmi_qp_set_cts_n()
193 static int dw_hdmi_qp_match_tmds_n_table(struct dw_hdmi_qp *hdmi, in dw_hdmi_qp_match_tmds_n_table() argument
208 return -ENOENT; in dw_hdmi_qp_match_tmds_n_table()
210 switch (freq) { in dw_hdmi_qp_match_tmds_n_table()
212 return tmds_n->n_32k; in dw_hdmi_qp_match_tmds_n_table()
216 return (freq / 44100) * tmds_n->n_44k1; in dw_hdmi_qp_match_tmds_n_table()
220 return (freq / 48000) * tmds_n->n_48k; in dw_hdmi_qp_match_tmds_n_table()
222 return -ENOENT; in dw_hdmi_qp_match_tmds_n_table()
234 static unsigned int dw_hdmi_qp_compute_n(struct dw_hdmi_qp *hdmi, in dw_hdmi_qp_compute_n() argument
254 (diff == best_diff && abs(n - ideal_n) < best_n_distance)) { in dw_hdmi_qp_compute_n()
257 best_n_distance = abs(best_n - ideal_n); in dw_hdmi_qp_compute_n()
264 if (best_diff == 0 && (abs(n - ideal_n) > best_n_distance)) in dw_hdmi_qp_compute_n()
271 static unsigned int dw_hdmi_qp_find_n(struct dw_hdmi_qp *hdmi, unsigned long pixel_clk, in dw_hdmi_qp_find_n() argument
274 int n = dw_hdmi_qp_match_tmds_n_table(hdmi, pixel_clk, sample_rate); in dw_hdmi_qp_find_n()
279 dev_warn(hdmi->dev, "Rate %lu missing; compute N dynamically\n", in dw_hdmi_qp_find_n()
282 return dw_hdmi_qp_compute_n(hdmi, pixel_clk, sample_rate); in dw_hdmi_qp_find_n()
285 static unsigned int dw_hdmi_qp_find_cts(struct dw_hdmi_qp *hdmi, unsigned long pixel_clk, in dw_hdmi_qp_find_cts() argument
301 switch (sample_rate) { in dw_hdmi_qp_find_cts()
303 return tmds_cts->cts_32k; in dw_hdmi_qp_find_cts()
307 return tmds_cts->cts_44k1; in dw_hdmi_qp_find_cts()
311 return tmds_cts->cts_48k; in dw_hdmi_qp_find_cts()
313 return -ENOENT; in dw_hdmi_qp_find_cts()
317 static void dw_hdmi_qp_set_audio_interface(struct dw_hdmi_qp *hdmi, in dw_hdmi_qp_set_audio_interface() argument
324 dw_hdmi_qp_write(hdmi, AVP_DATAPATH_PACKET_AUDIO_SWINIT_P, GLOBAL_SWRESET_REQUEST); in dw_hdmi_qp_set_audio_interface()
327 dw_hdmi_qp_mod(hdmi, 0, in dw_hdmi_qp_set_audio_interface()
332 dw_hdmi_qp_write(hdmi, AUDIO_FIFO_CLR_P, AUDIO_INTERFACE_CONTROL0); in dw_hdmi_qp_set_audio_interface()
335 dw_hdmi_qp_mod(hdmi, AUD_IF_I2S, AUD_IF_SEL_MSK, AUDIO_INTERFACE_CONFIG0); in dw_hdmi_qp_set_audio_interface()
338 switch (hparms->channels) { in dw_hdmi_qp_set_audio_interface()
353 dw_hdmi_qp_mod(hdmi, conf0, I2S_LINES_EN_MSK, AUDIO_INTERFACE_CONFIG0); in dw_hdmi_qp_set_audio_interface()
356 * Enable bpcuv generated internally for L-PCM, or received in dw_hdmi_qp_set_audio_interface()
359 switch (fmt->bit_fmt) { in dw_hdmi_qp_set_audio_interface()
361 conf0 = (hparms->channels == 8) ? AUD_HBR : AUD_ASP; in dw_hdmi_qp_set_audio_interface()
369 dw_hdmi_qp_mod(hdmi, conf0, I2S_BPCUV_RCV_MSK | AUD_FORMAT_MSK, in dw_hdmi_qp_set_audio_interface()
373 dw_hdmi_qp_mod(hdmi, AUD_FIFO_INIT_ON_OVF_EN, AUD_FIFO_INIT_ON_OVF_MSK, in dw_hdmi_qp_set_audio_interface()
385 static void dw_hdmi_qp_set_channel_status(struct dw_hdmi_qp *hdmi, in dw_hdmi_qp_set_channel_status() argument
398 * CS5: | | CGMS-A | in dw_hdmi_qp_set_channel_status()
410 if ((dw_hdmi_qp_read(hdmi, AUDIO_INTERFACE_CONFIG0) & GENMASK(25, 24)) == AUD_HBR) { in dw_hdmi_qp_set_channel_status()
416 dw_hdmi_qp_write(hdmi, channel_status[0] | (channel_status[1] << 8), in dw_hdmi_qp_set_channel_status()
419 regmap_bulk_write(hdmi->regm, AUDPKT_CHSTATUS_OVR1, &channel_status[3], 1); in dw_hdmi_qp_set_channel_status()
422 dw_hdmi_qp_mod(hdmi, 0, in dw_hdmi_qp_set_channel_status()
426 dw_hdmi_qp_mod(hdmi, AUDPKT_PBIT_FORCE_EN | AUDPKT_CHSTATUS_OVR_EN, in dw_hdmi_qp_set_channel_status()
431 static void dw_hdmi_qp_set_sample_rate(struct dw_hdmi_qp *hdmi, unsigned long long tmds_char_rate, in dw_hdmi_qp_set_sample_rate() argument
436 n = dw_hdmi_qp_find_n(hdmi, tmds_char_rate, sample_rate); in dw_hdmi_qp_set_sample_rate()
437 cts = dw_hdmi_qp_find_cts(hdmi, tmds_char_rate, sample_rate); in dw_hdmi_qp_set_sample_rate()
439 dw_hdmi_qp_set_cts_n(hdmi, cts, n); in dw_hdmi_qp_set_sample_rate()
445 struct dw_hdmi_qp *hdmi = dw_hdmi_qp_from_bridge(bridge); in dw_hdmi_qp_audio_enable() local
447 if (hdmi->tmds_char_rate) in dw_hdmi_qp_audio_enable()
448 dw_hdmi_qp_mod(hdmi, 0, AVP_DATAPATH_PACKET_AUDIO_SWDISABLE, GLOBAL_SWDISABLE); in dw_hdmi_qp_audio_enable()
458 struct dw_hdmi_qp *hdmi = dw_hdmi_qp_from_bridge(bridge); in dw_hdmi_qp_audio_prepare() local
461 if (!hdmi->tmds_char_rate) in dw_hdmi_qp_audio_prepare()
462 return -ENODEV; in dw_hdmi_qp_audio_prepare()
464 if (fmt->bit_clk_provider | fmt->frame_clk_provider) { in dw_hdmi_qp_audio_prepare()
465 dev_err(hdmi->dev, "unsupported clock settings\n"); in dw_hdmi_qp_audio_prepare()
466 return -EINVAL; in dw_hdmi_qp_audio_prepare()
469 if (fmt->bit_fmt == SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE) in dw_hdmi_qp_audio_prepare()
472 dw_hdmi_qp_set_audio_interface(hdmi, fmt, hparms); in dw_hdmi_qp_audio_prepare()
473 dw_hdmi_qp_set_sample_rate(hdmi, hdmi->tmds_char_rate, hparms->sample_rate); in dw_hdmi_qp_audio_prepare()
474 dw_hdmi_qp_set_channel_status(hdmi, hparms->iec.status, ref2stream); in dw_hdmi_qp_audio_prepare()
475 drm_atomic_helper_connector_hdmi_update_audio_infoframe(connector, &hparms->cea); in dw_hdmi_qp_audio_prepare()
480 static void dw_hdmi_qp_audio_disable_regs(struct dw_hdmi_qp *hdmi) in dw_hdmi_qp_audio_disable_regs() argument
489 dw_hdmi_qp_mod(hdmi, I2S_BPCUV_RCV_DIS, I2S_BPCUV_RCV_MSK, in dw_hdmi_qp_audio_disable_regs()
491 dw_hdmi_qp_mod(hdmi, AUDPKT_PBIT_FORCE_EN | AUDPKT_CHSTATUS_OVR_EN, in dw_hdmi_qp_audio_disable_regs()
495 dw_hdmi_qp_mod(hdmi, AVP_DATAPATH_PACKET_AUDIO_SWDISABLE, in dw_hdmi_qp_audio_disable_regs()
502 struct dw_hdmi_qp *hdmi = dw_hdmi_qp_from_bridge(bridge); in dw_hdmi_qp_audio_disable() local
506 if (hdmi->tmds_char_rate) in dw_hdmi_qp_audio_disable()
507 dw_hdmi_qp_audio_disable_regs(hdmi); in dw_hdmi_qp_audio_disable()
510 static int dw_hdmi_qp_i2c_read(struct dw_hdmi_qp *hdmi, in dw_hdmi_qp_i2c_read() argument
513 struct dw_hdmi_qp_i2c *i2c = hdmi->i2c; in dw_hdmi_qp_i2c_read()
516 if (!i2c->is_regaddr) { in dw_hdmi_qp_i2c_read()
517 dev_dbg(hdmi->dev, "set read register address to 0\n"); in dw_hdmi_qp_i2c_read()
518 i2c->slave_reg = 0x00; in dw_hdmi_qp_i2c_read()
519 i2c->is_regaddr = true; in dw_hdmi_qp_i2c_read()
522 while (length--) { in dw_hdmi_qp_i2c_read()
523 reinit_completion(&i2c->cmp); in dw_hdmi_qp_i2c_read()
525 dw_hdmi_qp_mod(hdmi, i2c->slave_reg++ << 12, I2CM_ADDR, in dw_hdmi_qp_i2c_read()
528 if (i2c->is_segment) in dw_hdmi_qp_i2c_read()
529 dw_hdmi_qp_mod(hdmi, I2CM_EXT_READ, I2CM_WR_MASK, in dw_hdmi_qp_i2c_read()
532 dw_hdmi_qp_mod(hdmi, I2CM_FM_READ, I2CM_WR_MASK, in dw_hdmi_qp_i2c_read()
535 stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10); in dw_hdmi_qp_i2c_read()
537 dev_err(hdmi->dev, "i2c read timed out\n"); in dw_hdmi_qp_i2c_read()
538 dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0); in dw_hdmi_qp_i2c_read()
539 return -EAGAIN; in dw_hdmi_qp_i2c_read()
543 if (i2c->stat & I2CM_NACK_RCVD_IRQ) { in dw_hdmi_qp_i2c_read()
544 dev_err(hdmi->dev, "i2c read error\n"); in dw_hdmi_qp_i2c_read()
545 dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0); in dw_hdmi_qp_i2c_read()
546 return -EIO; in dw_hdmi_qp_i2c_read()
549 *buf++ = dw_hdmi_qp_read(hdmi, I2CM_INTERFACE_RDDATA_0_3) & 0xff; in dw_hdmi_qp_i2c_read()
550 dw_hdmi_qp_mod(hdmi, 0, I2CM_WR_MASK, I2CM_INTERFACE_CONTROL0); in dw_hdmi_qp_i2c_read()
553 i2c->is_segment = false; in dw_hdmi_qp_i2c_read()
558 static int dw_hdmi_qp_i2c_write(struct dw_hdmi_qp *hdmi, in dw_hdmi_qp_i2c_write() argument
561 struct dw_hdmi_qp_i2c *i2c = hdmi->i2c; in dw_hdmi_qp_i2c_write()
564 if (!i2c->is_regaddr) { in dw_hdmi_qp_i2c_write()
566 i2c->slave_reg = buf[0]; in dw_hdmi_qp_i2c_write()
567 length--; in dw_hdmi_qp_i2c_write()
569 i2c->is_regaddr = true; in dw_hdmi_qp_i2c_write()
572 while (length--) { in dw_hdmi_qp_i2c_write()
573 reinit_completion(&i2c->cmp); in dw_hdmi_qp_i2c_write()
575 dw_hdmi_qp_write(hdmi, *buf++, I2CM_INTERFACE_WRDATA_0_3); in dw_hdmi_qp_i2c_write()
576 dw_hdmi_qp_mod(hdmi, i2c->slave_reg++ << 12, I2CM_ADDR, in dw_hdmi_qp_i2c_write()
578 dw_hdmi_qp_mod(hdmi, I2CM_FM_WRITE, I2CM_WR_MASK, in dw_hdmi_qp_i2c_write()
581 stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10); in dw_hdmi_qp_i2c_write()
583 dev_err(hdmi->dev, "i2c write time out!\n"); in dw_hdmi_qp_i2c_write()
584 dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0); in dw_hdmi_qp_i2c_write()
585 return -EAGAIN; in dw_hdmi_qp_i2c_write()
589 if (i2c->stat & I2CM_NACK_RCVD_IRQ) { in dw_hdmi_qp_i2c_write()
590 dev_err(hdmi->dev, "i2c write nack!\n"); in dw_hdmi_qp_i2c_write()
591 dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0); in dw_hdmi_qp_i2c_write()
592 return -EIO; in dw_hdmi_qp_i2c_write()
595 dw_hdmi_qp_mod(hdmi, 0, I2CM_WR_MASK, I2CM_INTERFACE_CONTROL0); in dw_hdmi_qp_i2c_write()
604 struct dw_hdmi_qp *hdmi = i2c_get_adapdata(adap); in dw_hdmi_qp_i2c_xfer() local
605 struct dw_hdmi_qp_i2c *i2c = hdmi->i2c; in dw_hdmi_qp_i2c_xfer()
611 * The internal I2C controller does not support the multi-byte in dw_hdmi_qp_i2c_xfer()
616 return -EOPNOTSUPP; in dw_hdmi_qp_i2c_xfer()
620 dev_err(hdmi->dev, in dw_hdmi_qp_i2c_xfer()
623 return -EOPNOTSUPP; in dw_hdmi_qp_i2c_xfer()
627 guard(mutex)(&i2c->lock); in dw_hdmi_qp_i2c_xfer()
630 dw_hdmi_qp_mod(hdmi, I2CM_NACK_RCVD_MASK_N | I2CM_OP_DONE_MASK_N, in dw_hdmi_qp_i2c_xfer()
638 dw_hdmi_qp_mod(hdmi, addr << 5, I2CM_SLVADDR, I2CM_INTERFACE_CONTROL0); in dw_hdmi_qp_i2c_xfer()
641 i2c->is_regaddr = false; in dw_hdmi_qp_i2c_xfer()
644 i2c->is_segment = false; in dw_hdmi_qp_i2c_xfer()
648 i2c->is_segment = true; in dw_hdmi_qp_i2c_xfer()
649 dw_hdmi_qp_mod(hdmi, DDC_SEGMENT_ADDR, I2CM_SEG_ADDR, in dw_hdmi_qp_i2c_xfer()
651 dw_hdmi_qp_mod(hdmi, *msgs[i].buf << 7, I2CM_SEG_PTR, in dw_hdmi_qp_i2c_xfer()
655 ret = dw_hdmi_qp_i2c_read(hdmi, msgs[i].buf, in dw_hdmi_qp_i2c_xfer()
658 ret = dw_hdmi_qp_i2c_write(hdmi, msgs[i].buf, in dw_hdmi_qp_i2c_xfer()
669 dw_hdmi_qp_mod(hdmi, 0, I2CM_OP_DONE_MASK_N | I2CM_NACK_RCVD_MASK_N, in dw_hdmi_qp_i2c_xfer()
685 static struct i2c_adapter *dw_hdmi_qp_i2c_adapter(struct dw_hdmi_qp *hdmi) in dw_hdmi_qp_i2c_adapter() argument
691 i2c = devm_kzalloc(hdmi->dev, sizeof(*i2c), GFP_KERNEL); in dw_hdmi_qp_i2c_adapter()
693 return ERR_PTR(-ENOMEM); in dw_hdmi_qp_i2c_adapter()
695 mutex_init(&i2c->lock); in dw_hdmi_qp_i2c_adapter()
696 init_completion(&i2c->cmp); in dw_hdmi_qp_i2c_adapter()
698 adap = &i2c->adap; in dw_hdmi_qp_i2c_adapter()
699 adap->owner = THIS_MODULE; in dw_hdmi_qp_i2c_adapter()
700 adap->dev.parent = hdmi->dev; in dw_hdmi_qp_i2c_adapter()
701 adap->algo = &dw_hdmi_qp_algorithm; in dw_hdmi_qp_i2c_adapter()
702 strscpy(adap->name, "DesignWare HDMI QP", sizeof(adap->name)); in dw_hdmi_qp_i2c_adapter()
704 i2c_set_adapdata(adap, hdmi); in dw_hdmi_qp_i2c_adapter()
706 ret = devm_i2c_add_adapter(hdmi->dev, adap); in dw_hdmi_qp_i2c_adapter()
708 dev_warn(hdmi->dev, "cannot add %s I2C adapter\n", adap->name); in dw_hdmi_qp_i2c_adapter()
709 devm_kfree(hdmi->dev, i2c); in dw_hdmi_qp_i2c_adapter()
713 hdmi->i2c = i2c; in dw_hdmi_qp_i2c_adapter()
714 dev_info(hdmi->dev, "registered %s I2C bus driver\n", adap->name); in dw_hdmi_qp_i2c_adapter()
719 static int dw_hdmi_qp_config_avi_infoframe(struct dw_hdmi_qp *hdmi, in dw_hdmi_qp_config_avi_infoframe() argument
725 dev_err(hdmi->dev, "failed to configure avi infoframe\n"); in dw_hdmi_qp_config_avi_infoframe()
726 return -EINVAL; in dw_hdmi_qp_config_avi_infoframe()
730 * DW HDMI QP IP uses a different byte format from standard AVI info in dw_hdmi_qp_config_avi_infoframe()
734 dw_hdmi_qp_write(hdmi, val, PKT_AVI_CONTENTS0); in dw_hdmi_qp_config_avi_infoframe()
745 dw_hdmi_qp_write(hdmi, val, PKT_AVI_CONTENTS1 + i * 4); in dw_hdmi_qp_config_avi_infoframe()
748 dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_AVI_FIELDRATE, PKTSCHED_PKT_CONFIG1); in dw_hdmi_qp_config_avi_infoframe()
750 dw_hdmi_qp_mod(hdmi, PKTSCHED_AVI_TX_EN | PKTSCHED_GCP_TX_EN, in dw_hdmi_qp_config_avi_infoframe()
756 static int dw_hdmi_qp_config_drm_infoframe(struct dw_hdmi_qp *hdmi, in dw_hdmi_qp_config_drm_infoframe() argument
762 dev_err(hdmi->dev, "failed to configure drm infoframe\n"); in dw_hdmi_qp_config_drm_infoframe()
763 return -EINVAL; in dw_hdmi_qp_config_drm_infoframe()
766 dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_TX_EN, PKTSCHED_PKT_EN); in dw_hdmi_qp_config_drm_infoframe()
769 dw_hdmi_qp_write(hdmi, val, PKT_DRMI_CONTENTS0); in dw_hdmi_qp_config_drm_infoframe()
777 dw_hdmi_qp_write(hdmi, val, in dw_hdmi_qp_config_drm_infoframe()
781 dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_FIELDRATE, PKTSCHED_PKT_CONFIG1); in dw_hdmi_qp_config_drm_infoframe()
782 dw_hdmi_qp_mod(hdmi, PKTSCHED_DRMI_TX_EN, PKTSCHED_DRMI_TX_EN, in dw_hdmi_qp_config_drm_infoframe()
795 static int dw_hdmi_qp_config_audio_infoframe(struct dw_hdmi_qp *hdmi, in dw_hdmi_qp_config_audio_infoframe() argument
811 * AUDI_CONTENTS0 default value defined by HDMI specification, in dw_hdmi_qp_config_audio_infoframe()
817 regmap_bulk_write(hdmi->regm, PKT_AUDI_CONTENTS0, &header_bytes, 1); in dw_hdmi_qp_config_audio_infoframe()
818 regmap_bulk_write(hdmi->regm, PKT_AUDI_CONTENTS1, &buffer[3], 1); in dw_hdmi_qp_config_audio_infoframe()
819 regmap_bulk_write(hdmi->regm, PKT_AUDI_CONTENTS2, &buffer[4], 1); in dw_hdmi_qp_config_audio_infoframe()
822 dw_hdmi_qp_mod(hdmi, in dw_hdmi_qp_config_audio_infoframe()
828 dw_hdmi_qp_mod(hdmi, PKTSCHED_AUDS_TX_EN, PKTSCHED_AUDS_TX_EN, PKTSCHED_PKT_EN); in dw_hdmi_qp_config_audio_infoframe()
836 struct dw_hdmi_qp *hdmi = bridge->driver_private; in dw_hdmi_qp_bridge_atomic_enable() local
841 connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); in dw_hdmi_qp_bridge_atomic_enable()
849 if (connector->display_info.is_hdmi) { in dw_hdmi_qp_bridge_atomic_enable()
850 dev_dbg(hdmi->dev, "%s mode=HDMI rate=%llu\n", in dw_hdmi_qp_bridge_atomic_enable()
851 __func__, conn_state->hdmi.tmds_char_rate); in dw_hdmi_qp_bridge_atomic_enable()
853 hdmi->tmds_char_rate = conn_state->hdmi.tmds_char_rate; in dw_hdmi_qp_bridge_atomic_enable()
855 dev_dbg(hdmi->dev, "%s mode=DVI\n", __func__); in dw_hdmi_qp_bridge_atomic_enable()
859 hdmi->phy.ops->init(hdmi, hdmi->phy.data); in dw_hdmi_qp_bridge_atomic_enable()
861 dw_hdmi_qp_mod(hdmi, HDCP2_BYPASS, HDCP2_BYPASS, HDCP2LOGIC_CONFIG0); in dw_hdmi_qp_bridge_atomic_enable()
862 dw_hdmi_qp_mod(hdmi, op_mode, OPMODE_DVI, LINK_CONFIG0); in dw_hdmi_qp_bridge_atomic_enable()
870 struct dw_hdmi_qp *hdmi = bridge->driver_private; in dw_hdmi_qp_bridge_atomic_disable() local
872 hdmi->tmds_char_rate = 0; in dw_hdmi_qp_bridge_atomic_disable()
874 hdmi->phy.ops->disable(hdmi, hdmi->phy.data); in dw_hdmi_qp_bridge_atomic_disable()
880 struct dw_hdmi_qp *hdmi = bridge->driver_private; in dw_hdmi_qp_bridge_detect() local
882 return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); in dw_hdmi_qp_bridge_detect()
889 struct dw_hdmi_qp *hdmi = bridge->driver_private; in dw_hdmi_qp_bridge_edid_read() local
892 drm_edid = drm_edid_read_ddc(connector, bridge->ddc); in dw_hdmi_qp_bridge_edid_read()
894 dev_dbg(hdmi->dev, "failed to get edid\n"); in dw_hdmi_qp_bridge_edid_read()
904 struct dw_hdmi_qp *hdmi = bridge->driver_private; in dw_hdmi_qp_bridge_tmds_char_rate_valid() local
907 dev_dbg(hdmi->dev, "Unsupported TMDS char rate: %lld\n", rate); in dw_hdmi_qp_bridge_tmds_char_rate_valid()
917 struct dw_hdmi_qp *hdmi = bridge->driver_private; in dw_hdmi_qp_bridge_clear_infoframe() local
919 switch (type) { in dw_hdmi_qp_bridge_clear_infoframe()
921 dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_AVI_TX_EN | PKTSCHED_GCP_TX_EN, in dw_hdmi_qp_bridge_clear_infoframe()
926 dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_TX_EN, PKTSCHED_PKT_EN); in dw_hdmi_qp_bridge_clear_infoframe()
930 dw_hdmi_qp_mod(hdmi, 0, in dw_hdmi_qp_bridge_clear_infoframe()
937 dev_dbg(hdmi->dev, "Unsupported infoframe type %x\n", type); in dw_hdmi_qp_bridge_clear_infoframe()
947 struct dw_hdmi_qp *hdmi = bridge->driver_private; in dw_hdmi_qp_bridge_write_infoframe() local
951 switch (type) { in dw_hdmi_qp_bridge_write_infoframe()
953 return dw_hdmi_qp_config_avi_infoframe(hdmi, buffer, len); in dw_hdmi_qp_bridge_write_infoframe()
956 return dw_hdmi_qp_config_drm_infoframe(hdmi, buffer, len); in dw_hdmi_qp_bridge_write_infoframe()
959 return dw_hdmi_qp_config_audio_infoframe(hdmi, buffer, len); in dw_hdmi_qp_bridge_write_infoframe()
962 dev_dbg(hdmi->dev, "Unsupported infoframe type %x\n", type); in dw_hdmi_qp_bridge_write_infoframe()
985 struct dw_hdmi_qp *hdmi = dev_id; in dw_hdmi_qp_main_hardirq() local
986 struct dw_hdmi_qp_i2c *i2c = hdmi->i2c; in dw_hdmi_qp_main_hardirq()
989 stat = dw_hdmi_qp_read(hdmi, MAINUNIT_1_INT_STATUS); in dw_hdmi_qp_main_hardirq()
991 i2c->stat = stat & (I2CM_OP_DONE_IRQ | I2CM_READ_REQUEST_IRQ | in dw_hdmi_qp_main_hardirq()
994 if (i2c->stat) { in dw_hdmi_qp_main_hardirq()
995 dw_hdmi_qp_write(hdmi, i2c->stat, MAINUNIT_1_INT_CLEAR); in dw_hdmi_qp_main_hardirq()
996 complete(&i2c->cmp); in dw_hdmi_qp_main_hardirq()
1012 static void dw_hdmi_qp_init_hw(struct dw_hdmi_qp *hdmi) in dw_hdmi_qp_init_hw() argument
1014 dw_hdmi_qp_write(hdmi, 0, MAINUNIT_0_INT_MASK_N); in dw_hdmi_qp_init_hw()
1015 dw_hdmi_qp_write(hdmi, 0, MAINUNIT_1_INT_MASK_N); in dw_hdmi_qp_init_hw()
1016 dw_hdmi_qp_write(hdmi, 428571429, TIMER_BASE_CONFIG0); in dw_hdmi_qp_init_hw()
1019 dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0); in dw_hdmi_qp_init_hw()
1021 dw_hdmi_qp_write(hdmi, 0x085c085c, I2CM_FM_SCL_CONFIG0); in dw_hdmi_qp_init_hw()
1023 dw_hdmi_qp_mod(hdmi, 0, I2CM_FM_EN, I2CM_INTERFACE_CONTROL0); in dw_hdmi_qp_init_hw()
1026 dw_hdmi_qp_write(hdmi, I2CM_OP_DONE_CLEAR | I2CM_NACK_RCVD_CLEAR, in dw_hdmi_qp_init_hw()
1029 if (hdmi->phy.ops->setup_hpd) in dw_hdmi_qp_init_hw()
1030 hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data); in dw_hdmi_qp_init_hw()
1037 struct device *dev = &pdev->dev; in dw_hdmi_qp_bind()
1038 struct dw_hdmi_qp *hdmi; in dw_hdmi_qp_bind() local
1042 if (!plat_data->phy_ops || !plat_data->phy_ops->init || in dw_hdmi_qp_bind()
1043 !plat_data->phy_ops->disable || !plat_data->phy_ops->read_hpd) { in dw_hdmi_qp_bind()
1045 return ERR_PTR(-ENODEV); in dw_hdmi_qp_bind()
1048 hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); in dw_hdmi_qp_bind()
1049 if (!hdmi) in dw_hdmi_qp_bind()
1050 return ERR_PTR(-ENOMEM); in dw_hdmi_qp_bind()
1052 hdmi->dev = dev; in dw_hdmi_qp_bind()
1058 hdmi->regm = devm_regmap_init_mmio(dev, regs, &dw_hdmi_qp_regmap_config); in dw_hdmi_qp_bind()
1059 if (IS_ERR(hdmi->regm)) { in dw_hdmi_qp_bind()
1061 return ERR_CAST(hdmi->regm); in dw_hdmi_qp_bind()
1064 hdmi->phy.ops = plat_data->phy_ops; in dw_hdmi_qp_bind()
1065 hdmi->phy.data = plat_data->phy_data; in dw_hdmi_qp_bind()
1067 dw_hdmi_qp_init_hw(hdmi); in dw_hdmi_qp_bind()
1069 ret = devm_request_threaded_irq(dev, plat_data->main_irq, in dw_hdmi_qp_bind()
1071 IRQF_SHARED, dev_name(dev), hdmi); in dw_hdmi_qp_bind()
1075 hdmi->bridge.driver_private = hdmi; in dw_hdmi_qp_bind()
1076 hdmi->bridge.funcs = &dw_hdmi_qp_bridge_funcs; in dw_hdmi_qp_bind()
1077 hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT | in dw_hdmi_qp_bind()
1081 hdmi->bridge.of_node = pdev->dev.of_node; in dw_hdmi_qp_bind()
1082 hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA; in dw_hdmi_qp_bind()
1083 hdmi->bridge.vendor = "Synopsys"; in dw_hdmi_qp_bind()
1084 hdmi->bridge.product = "DW HDMI QP TX"; in dw_hdmi_qp_bind()
1086 hdmi->bridge.ddc = dw_hdmi_qp_i2c_adapter(hdmi); in dw_hdmi_qp_bind()
1087 if (IS_ERR(hdmi->bridge.ddc)) in dw_hdmi_qp_bind()
1088 return ERR_CAST(hdmi->bridge.ddc); in dw_hdmi_qp_bind()
1090 hdmi->bridge.hdmi_audio_max_i2s_playback_channels = 8; in dw_hdmi_qp_bind()
1091 hdmi->bridge.hdmi_audio_dev = dev; in dw_hdmi_qp_bind()
1092 hdmi->bridge.hdmi_audio_dai_port = 1; in dw_hdmi_qp_bind()
1094 ret = devm_drm_bridge_add(dev, &hdmi->bridge); in dw_hdmi_qp_bind()
1098 ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL, in dw_hdmi_qp_bind()
1103 return hdmi; in dw_hdmi_qp_bind()
1107 void dw_hdmi_qp_resume(struct device *dev, struct dw_hdmi_qp *hdmi) in dw_hdmi_qp_resume() argument
1109 dw_hdmi_qp_init_hw(hdmi); in dw_hdmi_qp_resume()
1113 MODULE_AUTHOR("Algea Cao <algea.cao@rock-chips.com>");
1115 MODULE_DESCRIPTION("DW HDMI QP transmitter library");