Path: blob/master/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
51688 views
// SPDX-License-Identifier: GPL-2.0-or-later1/*2* Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd.3* Copyright (c) 2024 Collabora Ltd.4*5* Author: Algea Cao <[email protected]>6* Author: Cristian Ciocaltea <[email protected]>7*/8#include <linux/completion.h>9#include <linux/hdmi.h>10#include <linux/export.h>11#include <linux/i2c.h>12#include <linux/irq.h>13#include <linux/module.h>14#include <linux/mutex.h>15#include <linux/of.h>16#include <linux/workqueue.h>1718#include <drm/bridge/dw_hdmi_qp.h>19#include <drm/display/drm_hdmi_helper.h>20#include <drm/display/drm_hdmi_cec_helper.h>21#include <drm/display/drm_hdmi_state_helper.h>22#include <drm/drm_atomic.h>23#include <drm/drm_atomic_helper.h>24#include <drm/drm_bridge.h>25#include <drm/drm_connector.h>26#include <drm/drm_edid.h>27#include <drm/drm_modes.h>28#include <drm/drm_print.h>2930#include <media/cec.h>3132#include <sound/hdmi-codec.h>3334#include "dw-hdmi-qp.h"3536#define DDC_CI_ADDR 0x3737#define DDC_SEGMENT_ADDR 0x303839#define HDMI14_MAX_TMDSCLK 3400000004041#define SCRAMB_POLL_DELAY_MS 30004243/*44* Unless otherwise noted, entries in this table are 100% optimization.45* Values can be obtained from dw_hdmi_qp_compute_n() but that function is46* slow so we pre-compute values we expect to see.47*48* The values for TMDS 25175, 25200, 27000, 54000, 74250 and 148500 kHz are49* the recommended N values specified in the Audio chapter of the HDMI50* specification.51*/52static const struct dw_hdmi_audio_tmds_n {53unsigned long tmds;54unsigned int n_32k;55unsigned int n_44k1;56unsigned int n_48k;57} common_tmds_n_table[] = {58{ .tmds = 25175000, .n_32k = 4576, .n_44k1 = 7007, .n_48k = 6864, },59{ .tmds = 25200000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, },60{ .tmds = 27000000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, },61{ .tmds = 28320000, .n_32k = 4096, .n_44k1 = 5586, .n_48k = 6144, },62{ .tmds = 30240000, .n_32k = 4096, .n_44k1 = 5642, .n_48k = 6144, },63{ .tmds = 31500000, .n_32k = 4096, .n_44k1 = 5600, .n_48k = 6144, },64{ .tmds = 32000000, .n_32k = 4096, .n_44k1 = 5733, .n_48k = 6144, },65{ .tmds = 33750000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, },66{ .tmds = 36000000, .n_32k = 4096, .n_44k1 = 5684, .n_48k = 6144, },67{ .tmds = 40000000, .n_32k = 4096, .n_44k1 = 5733, .n_48k = 6144, },68{ .tmds = 49500000, .n_32k = 4096, .n_44k1 = 5488, .n_48k = 6144, },69{ .tmds = 50000000, .n_32k = 4096, .n_44k1 = 5292, .n_48k = 6144, },70{ .tmds = 54000000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, },71{ .tmds = 65000000, .n_32k = 4096, .n_44k1 = 7056, .n_48k = 6144, },72{ .tmds = 68250000, .n_32k = 4096, .n_44k1 = 5376, .n_48k = 6144, },73{ .tmds = 71000000, .n_32k = 4096, .n_44k1 = 7056, .n_48k = 6144, },74{ .tmds = 72000000, .n_32k = 4096, .n_44k1 = 5635, .n_48k = 6144, },75{ .tmds = 73250000, .n_32k = 11648, .n_44k1 = 14112, .n_48k = 6144, },76{ .tmds = 74250000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, },77{ .tmds = 75000000, .n_32k = 4096, .n_44k1 = 5880, .n_48k = 6144, },78{ .tmds = 78750000, .n_32k = 4096, .n_44k1 = 5600, .n_48k = 6144, },79{ .tmds = 78800000, .n_32k = 4096, .n_44k1 = 5292, .n_48k = 6144, },80{ .tmds = 79500000, .n_32k = 4096, .n_44k1 = 4704, .n_48k = 6144, },81{ .tmds = 83500000, .n_32k = 4096, .n_44k1 = 7056, .n_48k = 6144, },82{ .tmds = 85500000, .n_32k = 4096, .n_44k1 = 5488, .n_48k = 6144, },83{ .tmds = 88750000, .n_32k = 4096, .n_44k1 = 14112, .n_48k = 6144, },84{ .tmds = 97750000, .n_32k = 4096, .n_44k1 = 14112, .n_48k = 6144, },85{ .tmds = 101000000, .n_32k = 4096, .n_44k1 = 7056, .n_48k = 6144, },86{ .tmds = 106500000, .n_32k = 4096, .n_44k1 = 4704, .n_48k = 6144, },87{ .tmds = 108000000, .n_32k = 4096, .n_44k1 = 5684, .n_48k = 6144, },88{ .tmds = 115500000, .n_32k = 4096, .n_44k1 = 5712, .n_48k = 6144, },89{ .tmds = 119000000, .n_32k = 4096, .n_44k1 = 5544, .n_48k = 6144, },90{ .tmds = 135000000, .n_32k = 4096, .n_44k1 = 5488, .n_48k = 6144, },91{ .tmds = 146250000, .n_32k = 11648, .n_44k1 = 6272, .n_48k = 6144, },92{ .tmds = 148500000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, },93{ .tmds = 154000000, .n_32k = 4096, .n_44k1 = 5544, .n_48k = 6144, },94{ .tmds = 162000000, .n_32k = 4096, .n_44k1 = 5684, .n_48k = 6144, },9596/* For 297 MHz+ HDMI spec have some other rule for setting N */97{ .tmds = 297000000, .n_32k = 3073, .n_44k1 = 4704, .n_48k = 5120, },98{ .tmds = 594000000, .n_32k = 3073, .n_44k1 = 9408, .n_48k = 10240,},99100/* End of table */101{ .tmds = 0, .n_32k = 0, .n_44k1 = 0, .n_48k = 0, },102};103104/*105* These are the CTS values as recommended in the Audio chapter of the HDMI106* specification.107*/108static const struct dw_hdmi_audio_tmds_cts {109unsigned long tmds;110unsigned int cts_32k;111unsigned int cts_44k1;112unsigned int cts_48k;113} common_tmds_cts_table[] = {114{ .tmds = 25175000, .cts_32k = 28125, .cts_44k1 = 31250, .cts_48k = 28125, },115{ .tmds = 25200000, .cts_32k = 25200, .cts_44k1 = 28000, .cts_48k = 25200, },116{ .tmds = 27000000, .cts_32k = 27000, .cts_44k1 = 30000, .cts_48k = 27000, },117{ .tmds = 54000000, .cts_32k = 54000, .cts_44k1 = 60000, .cts_48k = 54000, },118{ .tmds = 74250000, .cts_32k = 74250, .cts_44k1 = 82500, .cts_48k = 74250, },119{ .tmds = 148500000, .cts_32k = 148500, .cts_44k1 = 165000, .cts_48k = 148500, },120121/* End of table */122{ .tmds = 0, .cts_32k = 0, .cts_44k1 = 0, .cts_48k = 0, },123};124125struct dw_hdmi_qp_i2c {126struct i2c_adapter adap;127128struct mutex lock; /* used to serialize data transfers */129struct completion cmp;130u8 stat;131132u8 slave_reg;133bool is_regaddr;134bool is_segment;135};136137#ifdef CONFIG_DRM_DW_HDMI_QP_CEC138struct dw_hdmi_qp_cec {139struct drm_connector *connector;140int irq;141u32 addresses;142struct cec_msg rx_msg;143u8 tx_status;144bool tx_done;145bool rx_done;146};147#endif148149struct dw_hdmi_qp {150struct drm_bridge bridge;151152struct device *dev;153struct dw_hdmi_qp_i2c *i2c;154155#ifdef CONFIG_DRM_DW_HDMI_QP_CEC156struct dw_hdmi_qp_cec *cec;157#endif158159struct {160const struct dw_hdmi_qp_phy_ops *ops;161void *data;162} phy;163164unsigned long ref_clk_rate;165struct regmap *regm;166int main_irq;167168unsigned long tmds_char_rate;169bool no_hpd;170};171172static void dw_hdmi_qp_write(struct dw_hdmi_qp *hdmi, unsigned int val,173int offset)174{175regmap_write(hdmi->regm, offset, val);176}177178static unsigned int dw_hdmi_qp_read(struct dw_hdmi_qp *hdmi, int offset)179{180unsigned int val = 0;181182regmap_read(hdmi->regm, offset, &val);183184return val;185}186187static void dw_hdmi_qp_mod(struct dw_hdmi_qp *hdmi, unsigned int data,188unsigned int mask, unsigned int reg)189{190regmap_update_bits(hdmi->regm, reg, mask, data);191}192193static struct dw_hdmi_qp *dw_hdmi_qp_from_bridge(struct drm_bridge *bridge)194{195return container_of(bridge, struct dw_hdmi_qp, bridge);196}197198static void dw_hdmi_qp_set_cts_n(struct dw_hdmi_qp *hdmi, unsigned int cts,199unsigned int n)200{201/* Set N */202dw_hdmi_qp_mod(hdmi, n, AUDPKT_ACR_N_VALUE, AUDPKT_ACR_CONTROL0);203204/* Set CTS */205if (cts)206dw_hdmi_qp_mod(hdmi, AUDPKT_ACR_CTS_OVR_EN, AUDPKT_ACR_CTS_OVR_EN_MSK,207AUDPKT_ACR_CONTROL1);208else209dw_hdmi_qp_mod(hdmi, 0, AUDPKT_ACR_CTS_OVR_EN_MSK,210AUDPKT_ACR_CONTROL1);211212dw_hdmi_qp_mod(hdmi, AUDPKT_ACR_CTS_OVR_VAL(cts), AUDPKT_ACR_CTS_OVR_VAL_MSK,213AUDPKT_ACR_CONTROL1);214}215216static int dw_hdmi_qp_match_tmds_n_table(struct dw_hdmi_qp *hdmi,217unsigned long pixel_clk,218unsigned long freq)219{220const struct dw_hdmi_audio_tmds_n *tmds_n = NULL;221int i;222223for (i = 0; common_tmds_n_table[i].tmds != 0; i++) {224if (pixel_clk == common_tmds_n_table[i].tmds) {225tmds_n = &common_tmds_n_table[i];226break;227}228}229230if (!tmds_n)231return -ENOENT;232233switch (freq) {234case 32000:235return tmds_n->n_32k;236case 44100:237case 88200:238case 176400:239return (freq / 44100) * tmds_n->n_44k1;240case 48000:241case 96000:242case 192000:243return (freq / 48000) * tmds_n->n_48k;244default:245return -ENOENT;246}247}248249static u32 dw_hdmi_qp_audio_math_diff(unsigned int freq, unsigned int n,250unsigned int pixel_clk)251{252u64 cts = mul_u32_u32(pixel_clk, n);253254return do_div(cts, 128 * freq);255}256257static unsigned int dw_hdmi_qp_compute_n(struct dw_hdmi_qp *hdmi,258unsigned long pixel_clk,259unsigned long freq)260{261unsigned int min_n = DIV_ROUND_UP((128 * freq), 1500);262unsigned int max_n = (128 * freq) / 300;263unsigned int ideal_n = (128 * freq) / 1000;264unsigned int best_n_distance = ideal_n;265unsigned int best_n = 0;266u64 best_diff = U64_MAX;267int n;268269/* If the ideal N could satisfy the audio math, then just take it */270if (dw_hdmi_qp_audio_math_diff(freq, ideal_n, pixel_clk) == 0)271return ideal_n;272273for (n = min_n; n <= max_n; n++) {274u64 diff = dw_hdmi_qp_audio_math_diff(freq, n, pixel_clk);275276if (diff < best_diff ||277(diff == best_diff && abs(n - ideal_n) < best_n_distance)) {278best_n = n;279best_diff = diff;280best_n_distance = abs(best_n - ideal_n);281}282283/*284* The best N already satisfy the audio math, and also be285* the closest value to ideal N, so just cut the loop.286*/287if (best_diff == 0 && (abs(n - ideal_n) > best_n_distance))288break;289}290291return best_n;292}293294static unsigned int dw_hdmi_qp_find_n(struct dw_hdmi_qp *hdmi, unsigned long pixel_clk,295unsigned long sample_rate)296{297int n = dw_hdmi_qp_match_tmds_n_table(hdmi, pixel_clk, sample_rate);298299if (n > 0)300return n;301302dev_warn(hdmi->dev, "Rate %lu missing; compute N dynamically\n",303pixel_clk);304305return dw_hdmi_qp_compute_n(hdmi, pixel_clk, sample_rate);306}307308static unsigned int dw_hdmi_qp_find_cts(struct dw_hdmi_qp *hdmi, unsigned long pixel_clk,309unsigned long sample_rate)310{311const struct dw_hdmi_audio_tmds_cts *tmds_cts = NULL;312int i;313314for (i = 0; common_tmds_cts_table[i].tmds != 0; i++) {315if (pixel_clk == common_tmds_cts_table[i].tmds) {316tmds_cts = &common_tmds_cts_table[i];317break;318}319}320321if (!tmds_cts)322return 0;323324switch (sample_rate) {325case 32000:326return tmds_cts->cts_32k;327case 44100:328case 88200:329case 176400:330return tmds_cts->cts_44k1;331case 48000:332case 96000:333case 192000:334return tmds_cts->cts_48k;335default:336return -ENOENT;337}338}339340static void dw_hdmi_qp_set_audio_interface(struct dw_hdmi_qp *hdmi,341struct hdmi_codec_daifmt *fmt,342struct hdmi_codec_params *hparms)343{344u32 conf0 = 0;345346/* Reset the audio data path of the AVP */347dw_hdmi_qp_write(hdmi, AVP_DATAPATH_PACKET_AUDIO_SWINIT_P, GLOBAL_SWRESET_REQUEST);348349/* Disable AUDS, ACR, AUDI */350dw_hdmi_qp_mod(hdmi, 0,351PKTSCHED_ACR_TX_EN | PKTSCHED_AUDS_TX_EN | PKTSCHED_AUDI_TX_EN,352PKTSCHED_PKT_EN);353354/* Clear the audio FIFO */355dw_hdmi_qp_write(hdmi, AUDIO_FIFO_CLR_P, AUDIO_INTERFACE_CONTROL0);356357/* Select I2S interface as the audio source */358dw_hdmi_qp_mod(hdmi, AUD_IF_I2S, AUD_IF_SEL_MSK, AUDIO_INTERFACE_CONFIG0);359360/* Enable the active i2s lanes */361switch (hparms->channels) {362case 7 ... 8:363conf0 |= I2S_LINES_EN(3);364fallthrough;365case 5 ... 6:366conf0 |= I2S_LINES_EN(2);367fallthrough;368case 3 ... 4:369conf0 |= I2S_LINES_EN(1);370fallthrough;371default:372conf0 |= I2S_LINES_EN(0);373break;374}375376dw_hdmi_qp_mod(hdmi, conf0, I2S_LINES_EN_MSK, AUDIO_INTERFACE_CONFIG0);377378/*379* Enable bpcuv generated internally for L-PCM, or received380* from stream for NLPCM/HBR.381*/382switch (fmt->bit_fmt) {383case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:384conf0 = (hparms->channels == 8) ? AUD_HBR : AUD_ASP;385conf0 |= I2S_BPCUV_RCV_EN;386break;387default:388conf0 = AUD_ASP | I2S_BPCUV_RCV_DIS;389break;390}391392dw_hdmi_qp_mod(hdmi, conf0, I2S_BPCUV_RCV_MSK | AUD_FORMAT_MSK,393AUDIO_INTERFACE_CONFIG0);394395/* Enable audio FIFO auto clear when overflow */396dw_hdmi_qp_mod(hdmi, AUD_FIFO_INIT_ON_OVF_EN, AUD_FIFO_INIT_ON_OVF_MSK,397AUDIO_INTERFACE_CONFIG0);398}399400/*401* When transmitting IEC60958 linear PCM audio, these registers allow to402* configure the channel status information of all the channel status403* bits in the IEC60958 frame. For the moment this configuration is only404* used when the I2S audio interface, General Purpose Audio (GPA),405* or AHB audio DMA (AHBAUDDMA) interface is active406* (for S/PDIF interface this information comes from the stream).407*/408static void dw_hdmi_qp_set_channel_status(struct dw_hdmi_qp *hdmi,409u8 *channel_status, bool ref2stream)410{411/*412* AUDPKT_CHSTATUS_OVR0: { RSV, RSV, CS1, CS0 }413* AUDPKT_CHSTATUS_OVR1: { CS6, CS5, CS4, CS3 }414*415* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |416* CS0: | Mode | d | c | b | a |417* CS1: | Category Code |418* CS2: | Channel Number | Source Number |419* CS3: | Clock Accuracy | Sample Freq |420* CS4: | Ori Sample Freq | Word Length |421* CS5: | | CGMS-A |422* CS6~CS23: Reserved423*424* a: use of channel status block425* b: linear PCM identification: 0 for lpcm, 1 for nlpcm426* c: copyright information427* d: additional format information428*/429430if (ref2stream)431channel_status[0] |= IEC958_AES0_NONAUDIO;432433if ((dw_hdmi_qp_read(hdmi, AUDIO_INTERFACE_CONFIG0) & GENMASK(25, 24)) == AUD_HBR) {434/* fixup cs for HBR */435channel_status[3] = (channel_status[3] & 0xf0) | IEC958_AES3_CON_FS_768000;436channel_status[4] = (channel_status[4] & 0x0f) | IEC958_AES4_CON_ORIGFS_NOTID;437}438439dw_hdmi_qp_write(hdmi, channel_status[0] | (channel_status[1] << 8),440AUDPKT_CHSTATUS_OVR0);441442regmap_bulk_write(hdmi->regm, AUDPKT_CHSTATUS_OVR1, &channel_status[3], 1);443444if (ref2stream)445dw_hdmi_qp_mod(hdmi, 0,446AUDPKT_PBIT_FORCE_EN_MASK | AUDPKT_CHSTATUS_OVR_EN_MASK,447AUDPKT_CONTROL0);448else449dw_hdmi_qp_mod(hdmi, AUDPKT_PBIT_FORCE_EN | AUDPKT_CHSTATUS_OVR_EN,450AUDPKT_PBIT_FORCE_EN_MASK | AUDPKT_CHSTATUS_OVR_EN_MASK,451AUDPKT_CONTROL0);452}453454static void dw_hdmi_qp_set_sample_rate(struct dw_hdmi_qp *hdmi, unsigned long long tmds_char_rate,455unsigned int sample_rate)456{457unsigned int n, cts;458459n = dw_hdmi_qp_find_n(hdmi, tmds_char_rate, sample_rate);460cts = dw_hdmi_qp_find_cts(hdmi, tmds_char_rate, sample_rate);461462dw_hdmi_qp_set_cts_n(hdmi, cts, n);463}464465static int dw_hdmi_qp_audio_enable(struct drm_bridge *bridge,466struct drm_connector *connector)467{468struct dw_hdmi_qp *hdmi = dw_hdmi_qp_from_bridge(bridge);469470if (hdmi->tmds_char_rate)471dw_hdmi_qp_mod(hdmi, 0, AVP_DATAPATH_PACKET_AUDIO_SWDISABLE, GLOBAL_SWDISABLE);472473return 0;474}475476static int dw_hdmi_qp_audio_prepare(struct drm_bridge *bridge,477struct drm_connector *connector,478struct hdmi_codec_daifmt *fmt,479struct hdmi_codec_params *hparms)480{481struct dw_hdmi_qp *hdmi = dw_hdmi_qp_from_bridge(bridge);482bool ref2stream = false;483484if (!hdmi->tmds_char_rate)485return -ENODEV;486487if (fmt->bit_clk_provider | fmt->frame_clk_provider) {488dev_err(hdmi->dev, "unsupported clock settings\n");489return -EINVAL;490}491492if (fmt->bit_fmt == SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE)493ref2stream = true;494495dw_hdmi_qp_set_audio_interface(hdmi, fmt, hparms);496dw_hdmi_qp_set_sample_rate(hdmi, hdmi->tmds_char_rate, hparms->sample_rate);497dw_hdmi_qp_set_channel_status(hdmi, hparms->iec.status, ref2stream);498drm_atomic_helper_connector_hdmi_update_audio_infoframe(connector, &hparms->cea);499500return 0;501}502503static void dw_hdmi_qp_audio_disable_regs(struct dw_hdmi_qp *hdmi)504{505/*506* Keep ACR, AUDI, AUDS packet always on to make SINK device507* active for better compatibility and user experience.508*509* This also fix POP sound on some SINK devices which wakeup510* from suspend to active.511*/512dw_hdmi_qp_mod(hdmi, I2S_BPCUV_RCV_DIS, I2S_BPCUV_RCV_MSK,513AUDIO_INTERFACE_CONFIG0);514dw_hdmi_qp_mod(hdmi, AUDPKT_PBIT_FORCE_EN | AUDPKT_CHSTATUS_OVR_EN,515AUDPKT_PBIT_FORCE_EN_MASK | AUDPKT_CHSTATUS_OVR_EN_MASK,516AUDPKT_CONTROL0);517518dw_hdmi_qp_mod(hdmi, AVP_DATAPATH_PACKET_AUDIO_SWDISABLE,519AVP_DATAPATH_PACKET_AUDIO_SWDISABLE, GLOBAL_SWDISABLE);520}521522static void dw_hdmi_qp_audio_disable(struct drm_bridge *bridge,523struct drm_connector *connector)524{525struct dw_hdmi_qp *hdmi = dw_hdmi_qp_from_bridge(bridge);526527drm_atomic_helper_connector_hdmi_clear_audio_infoframe(connector);528529if (hdmi->tmds_char_rate)530dw_hdmi_qp_audio_disable_regs(hdmi);531}532533static int dw_hdmi_qp_i2c_read(struct dw_hdmi_qp *hdmi,534unsigned char *buf, unsigned int length)535{536struct dw_hdmi_qp_i2c *i2c = hdmi->i2c;537int stat;538539if (!i2c->is_regaddr) {540dev_dbg(hdmi->dev, "set read register address to 0\n");541i2c->slave_reg = 0x00;542i2c->is_regaddr = true;543}544545while (length--) {546reinit_completion(&i2c->cmp);547548dw_hdmi_qp_mod(hdmi, i2c->slave_reg++ << 12, I2CM_ADDR,549I2CM_INTERFACE_CONTROL0);550551if (i2c->is_segment)552dw_hdmi_qp_mod(hdmi, I2CM_EXT_READ, I2CM_WR_MASK,553I2CM_INTERFACE_CONTROL0);554else555dw_hdmi_qp_mod(hdmi, I2CM_FM_READ, I2CM_WR_MASK,556I2CM_INTERFACE_CONTROL0);557558stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10);559if (!stat) {560if (hdmi->no_hpd)561dev_dbg_ratelimited(hdmi->dev,562"i2c read timed out\n");563else564dev_err(hdmi->dev, "i2c read timed out\n");565dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);566return -EAGAIN;567}568569/* Check for error condition on the bus */570if (i2c->stat & I2CM_NACK_RCVD_IRQ) {571if (hdmi->no_hpd)572dev_dbg_ratelimited(hdmi->dev,573"i2c read error\n");574else575dev_err(hdmi->dev, "i2c read error\n");576dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);577return -EIO;578}579580*buf++ = dw_hdmi_qp_read(hdmi, I2CM_INTERFACE_RDDATA_0_3) & 0xff;581dw_hdmi_qp_mod(hdmi, 0, I2CM_WR_MASK, I2CM_INTERFACE_CONTROL0);582}583584i2c->is_segment = false;585586return 0;587}588589static int dw_hdmi_qp_i2c_write(struct dw_hdmi_qp *hdmi,590unsigned char *buf, unsigned int length)591{592struct dw_hdmi_qp_i2c *i2c = hdmi->i2c;593int stat;594595if (!i2c->is_regaddr) {596/* Use the first write byte as register address */597i2c->slave_reg = buf[0];598length--;599buf++;600i2c->is_regaddr = true;601}602603while (length--) {604reinit_completion(&i2c->cmp);605606dw_hdmi_qp_write(hdmi, *buf++, I2CM_INTERFACE_WRDATA_0_3);607dw_hdmi_qp_mod(hdmi, i2c->slave_reg++ << 12, I2CM_ADDR,608I2CM_INTERFACE_CONTROL0);609dw_hdmi_qp_mod(hdmi, I2CM_FM_WRITE, I2CM_WR_MASK,610I2CM_INTERFACE_CONTROL0);611612stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10);613if (!stat) {614dev_err(hdmi->dev, "i2c write time out!\n");615dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);616return -EAGAIN;617}618619/* Check for error condition on the bus */620if (i2c->stat & I2CM_NACK_RCVD_IRQ) {621dev_err(hdmi->dev, "i2c write nack!\n");622dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);623return -EIO;624}625626dw_hdmi_qp_mod(hdmi, 0, I2CM_WR_MASK, I2CM_INTERFACE_CONTROL0);627}628629return 0;630}631632static int dw_hdmi_qp_i2c_xfer(struct i2c_adapter *adap,633struct i2c_msg *msgs, int num)634{635struct dw_hdmi_qp *hdmi = i2c_get_adapdata(adap);636struct dw_hdmi_qp_i2c *i2c = hdmi->i2c;637u8 addr = msgs[0].addr;638int i, ret = 0;639640if (addr == DDC_CI_ADDR)641/*642* The internal I2C controller does not support the multi-byte643* read and write operations needed for DDC/CI.644* FIXME: Blacklist the DDC/CI address until we filter out645* unsupported I2C operations.646*/647return -EOPNOTSUPP;648649for (i = 0; i < num; i++) {650if (msgs[i].len == 0) {651dev_err(hdmi->dev,652"unsupported transfer %d/%d, no data\n",653i + 1, num);654return -EOPNOTSUPP;655}656}657658guard(mutex)(&i2c->lock);659660/* Unmute DONE and ERROR interrupts */661dw_hdmi_qp_mod(hdmi, I2CM_NACK_RCVD_MASK_N | I2CM_OP_DONE_MASK_N,662I2CM_NACK_RCVD_MASK_N | I2CM_OP_DONE_MASK_N,663MAINUNIT_1_INT_MASK_N);664665/* Set slave device address taken from the first I2C message */666if (addr == DDC_SEGMENT_ADDR && msgs[0].len == 1)667addr = DDC_ADDR;668669dw_hdmi_qp_mod(hdmi, addr << 5, I2CM_SLVADDR, I2CM_INTERFACE_CONTROL0);670671/* Set slave device register address on transfer */672i2c->is_regaddr = false;673674/* Set segment pointer for I2C extended read mode operation */675i2c->is_segment = false;676677for (i = 0; i < num; i++) {678if (msgs[i].addr == DDC_SEGMENT_ADDR && msgs[i].len == 1) {679i2c->is_segment = true;680dw_hdmi_qp_mod(hdmi, DDC_SEGMENT_ADDR, I2CM_SEG_ADDR,681I2CM_INTERFACE_CONTROL1);682dw_hdmi_qp_mod(hdmi, *msgs[i].buf << 7, I2CM_SEG_PTR,683I2CM_INTERFACE_CONTROL1);684} else {685if (msgs[i].flags & I2C_M_RD)686ret = dw_hdmi_qp_i2c_read(hdmi, msgs[i].buf,687msgs[i].len);688else689ret = dw_hdmi_qp_i2c_write(hdmi, msgs[i].buf,690msgs[i].len);691}692if (ret < 0)693break;694}695696if (!ret)697ret = num;698699/* Mute DONE and ERROR interrupts */700dw_hdmi_qp_mod(hdmi, 0, I2CM_OP_DONE_MASK_N | I2CM_NACK_RCVD_MASK_N,701MAINUNIT_1_INT_MASK_N);702703return ret;704}705706static u32 dw_hdmi_qp_i2c_func(struct i2c_adapter *adapter)707{708return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;709}710711static const struct i2c_algorithm dw_hdmi_qp_algorithm = {712.master_xfer = dw_hdmi_qp_i2c_xfer,713.functionality = dw_hdmi_qp_i2c_func,714};715716static struct i2c_adapter *dw_hdmi_qp_i2c_adapter(struct dw_hdmi_qp *hdmi)717{718struct dw_hdmi_qp_i2c *i2c;719struct i2c_adapter *adap;720int ret;721722i2c = devm_kzalloc(hdmi->dev, sizeof(*i2c), GFP_KERNEL);723if (!i2c)724return ERR_PTR(-ENOMEM);725726mutex_init(&i2c->lock);727init_completion(&i2c->cmp);728729adap = &i2c->adap;730adap->owner = THIS_MODULE;731adap->dev.parent = hdmi->dev;732adap->algo = &dw_hdmi_qp_algorithm;733strscpy(adap->name, "DesignWare HDMI QP", sizeof(adap->name));734735i2c_set_adapdata(adap, hdmi);736737ret = devm_i2c_add_adapter(hdmi->dev, adap);738if (ret) {739dev_warn(hdmi->dev, "cannot add %s I2C adapter\n", adap->name);740devm_kfree(hdmi->dev, i2c);741return ERR_PTR(ret);742}743744hdmi->i2c = i2c;745dev_info(hdmi->dev, "registered %s I2C bus driver\n", adap->name);746747return adap;748}749750static int dw_hdmi_qp_config_avi_infoframe(struct dw_hdmi_qp *hdmi,751const u8 *buffer, size_t len)752{753u32 val, i, j;754755if (len != HDMI_INFOFRAME_SIZE(AVI)) {756dev_err(hdmi->dev, "failed to configure avi infoframe\n");757return -EINVAL;758}759760/*761* DW HDMI QP IP uses a different byte format from standard AVI info762* frames, though generally the bits are in the correct bytes.763*/764val = buffer[1] << 8 | buffer[2] << 16;765dw_hdmi_qp_write(hdmi, val, PKT_AVI_CONTENTS0);766767for (i = 0; i < 4; i++) {768for (j = 0; j < 4; j++) {769if (i * 4 + j >= 14)770break;771if (!j)772val = buffer[i * 4 + j + 3];773val |= buffer[i * 4 + j + 3] << (8 * j);774}775776dw_hdmi_qp_write(hdmi, val, PKT_AVI_CONTENTS1 + i * 4);777}778779dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_AVI_FIELDRATE, PKTSCHED_PKT_CONFIG1);780781dw_hdmi_qp_mod(hdmi, PKTSCHED_AVI_TX_EN | PKTSCHED_GCP_TX_EN,782PKTSCHED_AVI_TX_EN | PKTSCHED_GCP_TX_EN, PKTSCHED_PKT_EN);783784return 0;785}786787static int dw_hdmi_qp_config_drm_infoframe(struct dw_hdmi_qp *hdmi,788const u8 *buffer, size_t len)789{790u32 val, i;791792if (len != HDMI_INFOFRAME_SIZE(DRM)) {793dev_err(hdmi->dev, "failed to configure drm infoframe\n");794return -EINVAL;795}796797dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_TX_EN, PKTSCHED_PKT_EN);798799val = buffer[1] << 8 | buffer[2] << 16;800dw_hdmi_qp_write(hdmi, val, PKT_DRMI_CONTENTS0);801802for (i = 0; i <= buffer[2]; i++) {803if (i % 4 == 0)804val = buffer[3 + i];805val |= buffer[3 + i] << ((i % 4) * 8);806807if ((i % 4 == 3) || i == buffer[2])808dw_hdmi_qp_write(hdmi, val,809PKT_DRMI_CONTENTS1 + ((i / 4) * 4));810}811812dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_FIELDRATE, PKTSCHED_PKT_CONFIG1);813dw_hdmi_qp_mod(hdmi, PKTSCHED_DRMI_TX_EN, PKTSCHED_DRMI_TX_EN,814PKTSCHED_PKT_EN);815816return 0;817}818819/*820* Static values documented in the TRM821* Different values are only used for debug purposes822*/823#define DW_HDMI_QP_AUDIO_INFOFRAME_HB1 0x1824#define DW_HDMI_QP_AUDIO_INFOFRAME_HB2 0xa825826static int dw_hdmi_qp_config_audio_infoframe(struct dw_hdmi_qp *hdmi,827const u8 *buffer, size_t len)828{829/*830* AUDI_CONTENTS0: { RSV, HB2, HB1, RSV }831* AUDI_CONTENTS1: { PB3, PB2, PB1, PB0 }832* AUDI_CONTENTS2: { PB7, PB6, PB5, PB4 }833*834* PB0: CheckSum835* PB1: | CT3 | CT2 | CT1 | CT0 | F13 | CC2 | CC1 | CC0 |836* PB2: | F27 | F26 | F25 | SF2 | SF1 | SF0 | SS1 | SS0 |837* PB3: | F37 | F36 | F35 | F34 | F33 | F32 | F31 | F30 |838* PB4: | CA7 | CA6 | CA5 | CA4 | CA3 | CA2 | CA1 | CA0 |839* PB5: | DM_INH | LSV3 | LSV2 | LSV1 | LSV0 | F52 | F51 | F50 |840* PB6~PB10: Reserved841*842* AUDI_CONTENTS0 default value defined by HDMI specification,843* and shall only be changed for debug purposes.844*/845u32 header_bytes = (DW_HDMI_QP_AUDIO_INFOFRAME_HB1 << 8) |846(DW_HDMI_QP_AUDIO_INFOFRAME_HB2 << 16);847848regmap_bulk_write(hdmi->regm, PKT_AUDI_CONTENTS0, &header_bytes, 1);849regmap_bulk_write(hdmi->regm, PKT_AUDI_CONTENTS1, &buffer[3], 1);850regmap_bulk_write(hdmi->regm, PKT_AUDI_CONTENTS2, &buffer[4], 1);851852/* Enable ACR, AUDI, AMD */853dw_hdmi_qp_mod(hdmi,854PKTSCHED_ACR_TX_EN | PKTSCHED_AUDI_TX_EN | PKTSCHED_AMD_TX_EN,855PKTSCHED_ACR_TX_EN | PKTSCHED_AUDI_TX_EN | PKTSCHED_AMD_TX_EN,856PKTSCHED_PKT_EN);857858/* Enable AUDS */859dw_hdmi_qp_mod(hdmi, PKTSCHED_AUDS_TX_EN, PKTSCHED_AUDS_TX_EN, PKTSCHED_PKT_EN);860861return 0;862}863864static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,865struct drm_atomic_state *state)866{867struct dw_hdmi_qp *hdmi = bridge->driver_private;868struct drm_connector_state *conn_state;869struct drm_connector *connector;870unsigned int op_mode;871872connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);873if (WARN_ON(!connector))874return;875876conn_state = drm_atomic_get_new_connector_state(state, connector);877if (WARN_ON(!conn_state))878return;879880if (connector->display_info.is_hdmi) {881dev_dbg(hdmi->dev, "%s mode=HDMI %s rate=%llu bpc=%u\n", __func__,882drm_hdmi_connector_get_output_format_name(conn_state->hdmi.output_format),883conn_state->hdmi.tmds_char_rate, conn_state->hdmi.output_bpc);884op_mode = 0;885hdmi->tmds_char_rate = conn_state->hdmi.tmds_char_rate;886} else {887dev_dbg(hdmi->dev, "%s mode=DVI\n", __func__);888op_mode = OPMODE_DVI;889}890891hdmi->phy.ops->init(hdmi, hdmi->phy.data);892893dw_hdmi_qp_mod(hdmi, HDCP2_BYPASS, HDCP2_BYPASS, HDCP2LOGIC_CONFIG0);894dw_hdmi_qp_mod(hdmi, op_mode, OPMODE_DVI, LINK_CONFIG0);895896drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);897}898899static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,900struct drm_atomic_state *state)901{902struct dw_hdmi_qp *hdmi = bridge->driver_private;903904hdmi->tmds_char_rate = 0;905906hdmi->phy.ops->disable(hdmi, hdmi->phy.data);907}908909static enum drm_connector_status910dw_hdmi_qp_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connector)911{912struct dw_hdmi_qp *hdmi = bridge->driver_private;913const struct drm_edid *drm_edid;914915if (hdmi->no_hpd) {916drm_edid = drm_edid_read_ddc(connector, bridge->ddc);917if (drm_edid)918return connector_status_connected;919else920return connector_status_disconnected;921}922923return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data);924}925926static const struct drm_edid *927dw_hdmi_qp_bridge_edid_read(struct drm_bridge *bridge,928struct drm_connector *connector)929{930struct dw_hdmi_qp *hdmi = bridge->driver_private;931const struct drm_edid *drm_edid;932933drm_edid = drm_edid_read_ddc(connector, bridge->ddc);934if (!drm_edid)935dev_dbg(hdmi->dev, "failed to get edid\n");936937return drm_edid;938}939940static enum drm_mode_status941dw_hdmi_qp_bridge_tmds_char_rate_valid(const struct drm_bridge *bridge,942const struct drm_display_mode *mode,943unsigned long long rate)944{945struct dw_hdmi_qp *hdmi = bridge->driver_private;946947/*948* TODO: when hdmi->no_hpd is 1 we must not support modes that949* require scrambling, including every mode with a clock above950* HDMI14_MAX_TMDSCLK.951*/952if (rate > HDMI14_MAX_TMDSCLK) {953dev_dbg(hdmi->dev, "Unsupported TMDS char rate: %lld\n", rate);954return MODE_CLOCK_HIGH;955}956957return MODE_OK;958}959960static int dw_hdmi_qp_bridge_clear_avi_infoframe(struct drm_bridge *bridge)961{962struct dw_hdmi_qp *hdmi = bridge->driver_private;963964dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_AVI_TX_EN | PKTSCHED_GCP_TX_EN,965PKTSCHED_PKT_EN);966967return 0;968}969970static int dw_hdmi_qp_bridge_clear_hdmi_infoframe(struct drm_bridge *bridge)971{972/* FIXME: add support for this InfoFrame */973974drm_warn_once(bridge->encoder->dev, "HDMI VSI not supported\n");975976return 0;977}978979static int dw_hdmi_qp_bridge_clear_hdr_drm_infoframe(struct drm_bridge *bridge)980{981struct dw_hdmi_qp *hdmi = bridge->driver_private;982983dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_TX_EN, PKTSCHED_PKT_EN);984985return 0;986}987988static int dw_hdmi_qp_bridge_clear_audio_infoframe(struct drm_bridge *bridge)989{990struct dw_hdmi_qp *hdmi = bridge->driver_private;991992dw_hdmi_qp_mod(hdmi, 0,993PKTSCHED_ACR_TX_EN |994PKTSCHED_AUDS_TX_EN |995PKTSCHED_AUDI_TX_EN,996PKTSCHED_PKT_EN);997998return 0;999}10001001static int dw_hdmi_qp_bridge_write_avi_infoframe(struct drm_bridge *bridge,1002const u8 *buffer, size_t len)1003{1004struct dw_hdmi_qp *hdmi = bridge->driver_private;10051006dw_hdmi_qp_bridge_clear_avi_infoframe(bridge);10071008return dw_hdmi_qp_config_avi_infoframe(hdmi, buffer, len);1009}10101011static int dw_hdmi_qp_bridge_write_hdmi_infoframe(struct drm_bridge *bridge,1012const u8 *buffer, size_t len)1013{1014dw_hdmi_qp_bridge_clear_hdmi_infoframe(bridge);10151016/* FIXME: add support for the HDMI VSI */10171018return 0;1019}10201021static int dw_hdmi_qp_bridge_write_hdr_drm_infoframe(struct drm_bridge *bridge,1022const u8 *buffer, size_t len)1023{1024struct dw_hdmi_qp *hdmi = bridge->driver_private;10251026dw_hdmi_qp_bridge_clear_hdr_drm_infoframe(bridge);10271028return dw_hdmi_qp_config_drm_infoframe(hdmi, buffer, len);1029}10301031static int dw_hdmi_qp_bridge_write_audio_infoframe(struct drm_bridge *bridge,1032const u8 *buffer, size_t len)1033{1034struct dw_hdmi_qp *hdmi = bridge->driver_private;10351036dw_hdmi_qp_bridge_clear_audio_infoframe(bridge);10371038return dw_hdmi_qp_config_audio_infoframe(hdmi, buffer, len);1039}10401041#ifdef CONFIG_DRM_DW_HDMI_QP_CEC1042static irqreturn_t dw_hdmi_qp_cec_hardirq(int irq, void *dev_id)1043{1044struct dw_hdmi_qp *hdmi = dev_id;1045struct dw_hdmi_qp_cec *cec = hdmi->cec;1046irqreturn_t ret = IRQ_HANDLED;1047u32 stat;10481049stat = dw_hdmi_qp_read(hdmi, CEC_INT_STATUS);1050if (stat == 0)1051return IRQ_NONE;10521053dw_hdmi_qp_write(hdmi, stat, CEC_INT_CLEAR);10541055if (stat & CEC_STAT_LINE_ERR) {1056cec->tx_status = CEC_TX_STATUS_ERROR;1057cec->tx_done = true;1058ret = IRQ_WAKE_THREAD;1059} else if (stat & CEC_STAT_DONE) {1060cec->tx_status = CEC_TX_STATUS_OK;1061cec->tx_done = true;1062ret = IRQ_WAKE_THREAD;1063} else if (stat & CEC_STAT_NACK) {1064cec->tx_status = CEC_TX_STATUS_NACK;1065cec->tx_done = true;1066ret = IRQ_WAKE_THREAD;1067}10681069if (stat & CEC_STAT_EOM) {1070unsigned int len, i, val;10711072val = dw_hdmi_qp_read(hdmi, CEC_RX_COUNT_STATUS);1073len = (val & 0xf) + 1;10741075if (len > sizeof(cec->rx_msg.msg))1076len = sizeof(cec->rx_msg.msg);10771078for (i = 0; i < 4; i++) {1079val = dw_hdmi_qp_read(hdmi, CEC_RX_DATA3_0 + i * 4);1080cec->rx_msg.msg[i * 4] = val & 0xff;1081cec->rx_msg.msg[i * 4 + 1] = (val >> 8) & 0xff;1082cec->rx_msg.msg[i * 4 + 2] = (val >> 16) & 0xff;1083cec->rx_msg.msg[i * 4 + 3] = (val >> 24) & 0xff;1084}10851086dw_hdmi_qp_write(hdmi, 1, CEC_LOCK_CONTROL);10871088cec->rx_msg.len = len;1089cec->rx_done = true;10901091ret = IRQ_WAKE_THREAD;1092}10931094return ret;1095}10961097static irqreturn_t dw_hdmi_qp_cec_thread(int irq, void *dev_id)1098{1099struct dw_hdmi_qp *hdmi = dev_id;1100struct dw_hdmi_qp_cec *cec = hdmi->cec;11011102if (cec->tx_done) {1103cec->tx_done = false;1104drm_connector_hdmi_cec_transmit_attempt_done(cec->connector,1105cec->tx_status);1106}11071108if (cec->rx_done) {1109cec->rx_done = false;1110drm_connector_hdmi_cec_received_msg(cec->connector, &cec->rx_msg);1111}11121113return IRQ_HANDLED;1114}11151116static int dw_hdmi_qp_cec_init(struct drm_bridge *bridge,1117struct drm_connector *connector)1118{1119struct dw_hdmi_qp *hdmi = dw_hdmi_qp_from_bridge(bridge);1120struct dw_hdmi_qp_cec *cec = hdmi->cec;11211122cec->connector = connector;11231124dw_hdmi_qp_write(hdmi, 0, CEC_TX_COUNT);1125dw_hdmi_qp_write(hdmi, ~0, CEC_INT_CLEAR);1126dw_hdmi_qp_write(hdmi, 0, CEC_INT_MASK_N);11271128return devm_request_threaded_irq(hdmi->dev, cec->irq,1129dw_hdmi_qp_cec_hardirq,1130dw_hdmi_qp_cec_thread, IRQF_SHARED,1131dev_name(hdmi->dev), hdmi);1132}11331134static int dw_hdmi_qp_cec_log_addr(struct drm_bridge *bridge, u8 logical_addr)1135{1136struct dw_hdmi_qp *hdmi = dw_hdmi_qp_from_bridge(bridge);1137struct dw_hdmi_qp_cec *cec = hdmi->cec;11381139if (logical_addr == CEC_LOG_ADDR_INVALID)1140cec->addresses = 0;1141else1142cec->addresses |= BIT(logical_addr) | CEC_ADDR_BROADCAST;11431144dw_hdmi_qp_write(hdmi, cec->addresses, CEC_ADDR);11451146return 0;1147}11481149static int dw_hdmi_qp_cec_enable(struct drm_bridge *bridge, bool enable)1150{1151struct dw_hdmi_qp *hdmi = dw_hdmi_qp_from_bridge(bridge);1152unsigned int irqs;1153u32 swdisable;11541155if (!enable) {1156dw_hdmi_qp_write(hdmi, 0, CEC_INT_MASK_N);1157dw_hdmi_qp_write(hdmi, ~0, CEC_INT_CLEAR);11581159swdisable = dw_hdmi_qp_read(hdmi, GLOBAL_SWDISABLE);1160swdisable = swdisable | CEC_SWDISABLE;1161dw_hdmi_qp_write(hdmi, swdisable, GLOBAL_SWDISABLE);1162} else {1163swdisable = dw_hdmi_qp_read(hdmi, GLOBAL_SWDISABLE);1164swdisable = swdisable & ~CEC_SWDISABLE;1165dw_hdmi_qp_write(hdmi, swdisable, GLOBAL_SWDISABLE);11661167dw_hdmi_qp_write(hdmi, ~0, CEC_INT_CLEAR);1168dw_hdmi_qp_write(hdmi, 1, CEC_LOCK_CONTROL);11691170dw_hdmi_qp_cec_log_addr(bridge, CEC_LOG_ADDR_INVALID);11711172irqs = CEC_STAT_LINE_ERR | CEC_STAT_NACK | CEC_STAT_EOM |1173CEC_STAT_DONE;1174dw_hdmi_qp_write(hdmi, ~0, CEC_INT_CLEAR);1175dw_hdmi_qp_write(hdmi, irqs, CEC_INT_MASK_N);1176}11771178return 0;1179}11801181static int dw_hdmi_qp_cec_transmit(struct drm_bridge *bridge, u8 attempts,1182u32 signal_free_time, struct cec_msg *msg)1183{1184struct dw_hdmi_qp *hdmi = dw_hdmi_qp_from_bridge(bridge);1185unsigned int i;1186u32 val;11871188for (i = 0; i < msg->len; i++) {1189if (!(i % 4))1190val = msg->msg[i];1191if ((i % 4) == 1)1192val |= msg->msg[i] << 8;1193if ((i % 4) == 2)1194val |= msg->msg[i] << 16;1195if ((i % 4) == 3)1196val |= msg->msg[i] << 24;11971198if (i == (msg->len - 1) || (i % 4) == 3)1199dw_hdmi_qp_write(hdmi, val, CEC_TX_DATA3_0 + (i / 4) * 4);1200}12011202dw_hdmi_qp_write(hdmi, msg->len - 1, CEC_TX_COUNT);1203dw_hdmi_qp_write(hdmi, CEC_CTRL_START, CEC_TX_CONTROL);12041205return 0;1206}1207#else1208#define dw_hdmi_qp_cec_init NULL1209#define dw_hdmi_qp_cec_enable NULL1210#define dw_hdmi_qp_cec_log_addr NULL1211#define dw_hdmi_qp_cec_transmit NULL1212#endif /* CONFIG_DRM_DW_HDMI_QP_CEC */12131214static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {1215.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,1216.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,1217.atomic_reset = drm_atomic_helper_bridge_reset,1218.atomic_enable = dw_hdmi_qp_bridge_atomic_enable,1219.atomic_disable = dw_hdmi_qp_bridge_atomic_disable,1220.detect = dw_hdmi_qp_bridge_detect,1221.edid_read = dw_hdmi_qp_bridge_edid_read,1222.hdmi_tmds_char_rate_valid = dw_hdmi_qp_bridge_tmds_char_rate_valid,1223.hdmi_clear_avi_infoframe = dw_hdmi_qp_bridge_clear_avi_infoframe,1224.hdmi_write_avi_infoframe = dw_hdmi_qp_bridge_write_avi_infoframe,1225.hdmi_clear_hdmi_infoframe = dw_hdmi_qp_bridge_clear_hdmi_infoframe,1226.hdmi_write_hdmi_infoframe = dw_hdmi_qp_bridge_write_hdmi_infoframe,1227.hdmi_clear_hdr_drm_infoframe = dw_hdmi_qp_bridge_clear_hdr_drm_infoframe,1228.hdmi_write_hdr_drm_infoframe = dw_hdmi_qp_bridge_write_hdr_drm_infoframe,1229.hdmi_clear_audio_infoframe = dw_hdmi_qp_bridge_clear_audio_infoframe,1230.hdmi_write_audio_infoframe = dw_hdmi_qp_bridge_write_audio_infoframe,1231.hdmi_audio_startup = dw_hdmi_qp_audio_enable,1232.hdmi_audio_shutdown = dw_hdmi_qp_audio_disable,1233.hdmi_audio_prepare = dw_hdmi_qp_audio_prepare,1234.hdmi_cec_init = dw_hdmi_qp_cec_init,1235.hdmi_cec_enable = dw_hdmi_qp_cec_enable,1236.hdmi_cec_log_addr = dw_hdmi_qp_cec_log_addr,1237.hdmi_cec_transmit = dw_hdmi_qp_cec_transmit,1238};12391240static irqreturn_t dw_hdmi_qp_main_hardirq(int irq, void *dev_id)1241{1242struct dw_hdmi_qp *hdmi = dev_id;1243struct dw_hdmi_qp_i2c *i2c = hdmi->i2c;1244u32 stat;12451246stat = dw_hdmi_qp_read(hdmi, MAINUNIT_1_INT_STATUS);12471248i2c->stat = stat & (I2CM_OP_DONE_IRQ | I2CM_READ_REQUEST_IRQ |1249I2CM_NACK_RCVD_IRQ);12501251if (i2c->stat) {1252dw_hdmi_qp_write(hdmi, i2c->stat, MAINUNIT_1_INT_CLEAR);1253complete(&i2c->cmp);1254}12551256if (stat)1257return IRQ_HANDLED;12581259return IRQ_NONE;1260}12611262static const struct regmap_config dw_hdmi_qp_regmap_config = {1263.reg_bits = 32,1264.val_bits = 32,1265.reg_stride = 4,1266.max_register = EARCRX_1_INT_FORCE,1267};12681269static void dw_hdmi_qp_init_hw(struct dw_hdmi_qp *hdmi)1270{1271dw_hdmi_qp_write(hdmi, 0, MAINUNIT_0_INT_MASK_N);1272dw_hdmi_qp_write(hdmi, 0, MAINUNIT_1_INT_MASK_N);1273dw_hdmi_qp_write(hdmi, hdmi->ref_clk_rate, TIMER_BASE_CONFIG0);12741275/* Software reset */1276dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);1277dw_hdmi_qp_write(hdmi, 0x085c085c, I2CM_FM_SCL_CONFIG0);1278dw_hdmi_qp_mod(hdmi, 0, I2CM_FM_EN, I2CM_INTERFACE_CONTROL0);12791280/* Clear DONE and ERROR interrupts */1281dw_hdmi_qp_write(hdmi, I2CM_OP_DONE_CLEAR | I2CM_NACK_RCVD_CLEAR,1282MAINUNIT_1_INT_CLEAR);12831284if (hdmi->phy.ops->setup_hpd)1285hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data);1286}12871288struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,1289struct drm_encoder *encoder,1290const struct dw_hdmi_qp_plat_data *plat_data)1291{1292struct device *dev = &pdev->dev;1293struct dw_hdmi_qp *hdmi;1294void __iomem *regs;1295int ret;12961297if (!plat_data->phy_ops || !plat_data->phy_ops->init ||1298!plat_data->phy_ops->disable || !plat_data->phy_ops->read_hpd) {1299dev_err(dev, "Missing platform PHY ops\n");1300return ERR_PTR(-ENODEV);1301}13021303hdmi = devm_drm_bridge_alloc(dev, struct dw_hdmi_qp, bridge,1304&dw_hdmi_qp_bridge_funcs);1305if (IS_ERR(hdmi))1306return ERR_CAST(hdmi);13071308hdmi->dev = dev;13091310regs = devm_platform_ioremap_resource(pdev, 0);1311if (IS_ERR(regs))1312return ERR_CAST(regs);13131314hdmi->regm = devm_regmap_init_mmio(dev, regs, &dw_hdmi_qp_regmap_config);1315if (IS_ERR(hdmi->regm)) {1316dev_err(dev, "Failed to configure regmap\n");1317return ERR_CAST(hdmi->regm);1318}13191320hdmi->phy.ops = plat_data->phy_ops;1321hdmi->phy.data = plat_data->phy_data;13221323if (plat_data->ref_clk_rate) {1324hdmi->ref_clk_rate = plat_data->ref_clk_rate;1325} else {1326hdmi->ref_clk_rate = 428571429;1327dev_warn(dev, "Set ref_clk_rate to vendor default\n");1328}13291330dw_hdmi_qp_init_hw(hdmi);13311332hdmi->main_irq = plat_data->main_irq;1333ret = devm_request_threaded_irq(dev, plat_data->main_irq,1334dw_hdmi_qp_main_hardirq, NULL,1335IRQF_SHARED, dev_name(dev), hdmi);1336if (ret)1337return ERR_PTR(ret);13381339hdmi->no_hpd = device_property_read_bool(dev, "no-hpd");13401341hdmi->bridge.driver_private = hdmi;1342hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT |1343DRM_BRIDGE_OP_EDID |1344DRM_BRIDGE_OP_HDMI |1345DRM_BRIDGE_OP_HDMI_AUDIO |1346DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME;1347if (!hdmi->no_hpd)1348hdmi->bridge.ops |= DRM_BRIDGE_OP_HPD;1349hdmi->bridge.of_node = pdev->dev.of_node;1350hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;1351hdmi->bridge.vendor = "Synopsys";1352hdmi->bridge.product = "DW HDMI QP TX";13531354if (plat_data->supported_formats)1355hdmi->bridge.supported_formats = plat_data->supported_formats;13561357if (plat_data->max_bpc)1358hdmi->bridge.max_bpc = plat_data->max_bpc;13591360hdmi->bridge.ddc = dw_hdmi_qp_i2c_adapter(hdmi);1361if (IS_ERR(hdmi->bridge.ddc))1362return ERR_CAST(hdmi->bridge.ddc);13631364hdmi->bridge.hdmi_audio_max_i2s_playback_channels = 8;1365hdmi->bridge.hdmi_audio_dev = dev;1366hdmi->bridge.hdmi_audio_dai_port = 1;13671368#ifdef CONFIG_DRM_DW_HDMI_QP_CEC1369if (plat_data->cec_irq) {1370hdmi->bridge.ops |= DRM_BRIDGE_OP_HDMI_CEC_ADAPTER;1371hdmi->bridge.hdmi_cec_dev = dev;1372hdmi->bridge.hdmi_cec_adapter_name = dev_name(dev);13731374hdmi->cec = devm_kzalloc(hdmi->dev, sizeof(*hdmi->cec), GFP_KERNEL);1375if (!hdmi->cec)1376return ERR_PTR(-ENOMEM);13771378hdmi->cec->irq = plat_data->cec_irq;1379} else {1380dev_warn(dev, "Disabled CEC support due to missing IRQ\n");1381}1382#endif13831384ret = devm_drm_bridge_add(dev, &hdmi->bridge);1385if (ret)1386return ERR_PTR(ret);13871388ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL,1389DRM_BRIDGE_ATTACH_NO_CONNECTOR);1390if (ret)1391return ERR_PTR(ret);13921393return hdmi;1394}1395EXPORT_SYMBOL_GPL(dw_hdmi_qp_bind);13961397void dw_hdmi_qp_suspend(struct device *dev, struct dw_hdmi_qp *hdmi)1398{1399disable_irq(hdmi->main_irq);1400}1401EXPORT_SYMBOL_GPL(dw_hdmi_qp_suspend);14021403void dw_hdmi_qp_resume(struct device *dev, struct dw_hdmi_qp *hdmi)1404{1405dw_hdmi_qp_init_hw(hdmi);1406enable_irq(hdmi->main_irq);1407}1408EXPORT_SYMBOL_GPL(dw_hdmi_qp_resume);14091410MODULE_AUTHOR("Algea Cao <[email protected]>");1411MODULE_AUTHOR("Cristian Ciocaltea <[email protected]>");1412MODULE_DESCRIPTION("DW HDMI QP transmitter library");1413MODULE_LICENSE("GPL");141414151416