Path: blob/master/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
26516 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_state_helper.h>21#include <drm/drm_atomic.h>22#include <drm/drm_atomic_helper.h>23#include <drm/drm_bridge.h>24#include <drm/drm_connector.h>25#include <drm/drm_edid.h>26#include <drm/drm_modes.h>2728#include <sound/hdmi-codec.h>2930#include "dw-hdmi-qp.h"3132#define DDC_CI_ADDR 0x3733#define DDC_SEGMENT_ADDR 0x303435#define HDMI14_MAX_TMDSCLK 3400000003637#define SCRAMB_POLL_DELAY_MS 30003839/*40* Unless otherwise noted, entries in this table are 100% optimization.41* Values can be obtained from dw_hdmi_qp_compute_n() but that function is42* slow so we pre-compute values we expect to see.43*44* The values for TMDS 25175, 25200, 27000, 54000, 74250 and 148500 kHz are45* the recommended N values specified in the Audio chapter of the HDMI46* specification.47*/48static const struct dw_hdmi_audio_tmds_n {49unsigned long tmds;50unsigned int n_32k;51unsigned int n_44k1;52unsigned int n_48k;53} common_tmds_n_table[] = {54{ .tmds = 25175000, .n_32k = 4576, .n_44k1 = 7007, .n_48k = 6864, },55{ .tmds = 25200000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, },56{ .tmds = 27000000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, },57{ .tmds = 28320000, .n_32k = 4096, .n_44k1 = 5586, .n_48k = 6144, },58{ .tmds = 30240000, .n_32k = 4096, .n_44k1 = 5642, .n_48k = 6144, },59{ .tmds = 31500000, .n_32k = 4096, .n_44k1 = 5600, .n_48k = 6144, },60{ .tmds = 32000000, .n_32k = 4096, .n_44k1 = 5733, .n_48k = 6144, },61{ .tmds = 33750000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, },62{ .tmds = 36000000, .n_32k = 4096, .n_44k1 = 5684, .n_48k = 6144, },63{ .tmds = 40000000, .n_32k = 4096, .n_44k1 = 5733, .n_48k = 6144, },64{ .tmds = 49500000, .n_32k = 4096, .n_44k1 = 5488, .n_48k = 6144, },65{ .tmds = 50000000, .n_32k = 4096, .n_44k1 = 5292, .n_48k = 6144, },66{ .tmds = 54000000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, },67{ .tmds = 65000000, .n_32k = 4096, .n_44k1 = 7056, .n_48k = 6144, },68{ .tmds = 68250000, .n_32k = 4096, .n_44k1 = 5376, .n_48k = 6144, },69{ .tmds = 71000000, .n_32k = 4096, .n_44k1 = 7056, .n_48k = 6144, },70{ .tmds = 72000000, .n_32k = 4096, .n_44k1 = 5635, .n_48k = 6144, },71{ .tmds = 73250000, .n_32k = 11648, .n_44k1 = 14112, .n_48k = 6144, },72{ .tmds = 74250000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, },73{ .tmds = 75000000, .n_32k = 4096, .n_44k1 = 5880, .n_48k = 6144, },74{ .tmds = 78750000, .n_32k = 4096, .n_44k1 = 5600, .n_48k = 6144, },75{ .tmds = 78800000, .n_32k = 4096, .n_44k1 = 5292, .n_48k = 6144, },76{ .tmds = 79500000, .n_32k = 4096, .n_44k1 = 4704, .n_48k = 6144, },77{ .tmds = 83500000, .n_32k = 4096, .n_44k1 = 7056, .n_48k = 6144, },78{ .tmds = 85500000, .n_32k = 4096, .n_44k1 = 5488, .n_48k = 6144, },79{ .tmds = 88750000, .n_32k = 4096, .n_44k1 = 14112, .n_48k = 6144, },80{ .tmds = 97750000, .n_32k = 4096, .n_44k1 = 14112, .n_48k = 6144, },81{ .tmds = 101000000, .n_32k = 4096, .n_44k1 = 7056, .n_48k = 6144, },82{ .tmds = 106500000, .n_32k = 4096, .n_44k1 = 4704, .n_48k = 6144, },83{ .tmds = 108000000, .n_32k = 4096, .n_44k1 = 5684, .n_48k = 6144, },84{ .tmds = 115500000, .n_32k = 4096, .n_44k1 = 5712, .n_48k = 6144, },85{ .tmds = 119000000, .n_32k = 4096, .n_44k1 = 5544, .n_48k = 6144, },86{ .tmds = 135000000, .n_32k = 4096, .n_44k1 = 5488, .n_48k = 6144, },87{ .tmds = 146250000, .n_32k = 11648, .n_44k1 = 6272, .n_48k = 6144, },88{ .tmds = 148500000, .n_32k = 4096, .n_44k1 = 6272, .n_48k = 6144, },89{ .tmds = 154000000, .n_32k = 4096, .n_44k1 = 5544, .n_48k = 6144, },90{ .tmds = 162000000, .n_32k = 4096, .n_44k1 = 5684, .n_48k = 6144, },9192/* For 297 MHz+ HDMI spec have some other rule for setting N */93{ .tmds = 297000000, .n_32k = 3073, .n_44k1 = 4704, .n_48k = 5120, },94{ .tmds = 594000000, .n_32k = 3073, .n_44k1 = 9408, .n_48k = 10240,},9596/* End of table */97{ .tmds = 0, .n_32k = 0, .n_44k1 = 0, .n_48k = 0, },98};99100/*101* These are the CTS values as recommended in the Audio chapter of the HDMI102* specification.103*/104static const struct dw_hdmi_audio_tmds_cts {105unsigned long tmds;106unsigned int cts_32k;107unsigned int cts_44k1;108unsigned int cts_48k;109} common_tmds_cts_table[] = {110{ .tmds = 25175000, .cts_32k = 28125, .cts_44k1 = 31250, .cts_48k = 28125, },111{ .tmds = 25200000, .cts_32k = 25200, .cts_44k1 = 28000, .cts_48k = 25200, },112{ .tmds = 27000000, .cts_32k = 27000, .cts_44k1 = 30000, .cts_48k = 27000, },113{ .tmds = 54000000, .cts_32k = 54000, .cts_44k1 = 60000, .cts_48k = 54000, },114{ .tmds = 74250000, .cts_32k = 74250, .cts_44k1 = 82500, .cts_48k = 74250, },115{ .tmds = 148500000, .cts_32k = 148500, .cts_44k1 = 165000, .cts_48k = 148500, },116117/* End of table */118{ .tmds = 0, .cts_32k = 0, .cts_44k1 = 0, .cts_48k = 0, },119};120121struct dw_hdmi_qp_i2c {122struct i2c_adapter adap;123124struct mutex lock; /* used to serialize data transfers */125struct completion cmp;126u8 stat;127128u8 slave_reg;129bool is_regaddr;130bool is_segment;131};132133struct dw_hdmi_qp {134struct drm_bridge bridge;135136struct device *dev;137struct dw_hdmi_qp_i2c *i2c;138139struct {140const struct dw_hdmi_qp_phy_ops *ops;141void *data;142} phy;143144struct regmap *regm;145146unsigned long tmds_char_rate;147};148149static void dw_hdmi_qp_write(struct dw_hdmi_qp *hdmi, unsigned int val,150int offset)151{152regmap_write(hdmi->regm, offset, val);153}154155static unsigned int dw_hdmi_qp_read(struct dw_hdmi_qp *hdmi, int offset)156{157unsigned int val = 0;158159regmap_read(hdmi->regm, offset, &val);160161return val;162}163164static void dw_hdmi_qp_mod(struct dw_hdmi_qp *hdmi, unsigned int data,165unsigned int mask, unsigned int reg)166{167regmap_update_bits(hdmi->regm, reg, mask, data);168}169170static struct dw_hdmi_qp *dw_hdmi_qp_from_bridge(struct drm_bridge *bridge)171{172return container_of(bridge, struct dw_hdmi_qp, bridge);173}174175static void dw_hdmi_qp_set_cts_n(struct dw_hdmi_qp *hdmi, unsigned int cts,176unsigned int n)177{178/* Set N */179dw_hdmi_qp_mod(hdmi, n, AUDPKT_ACR_N_VALUE, AUDPKT_ACR_CONTROL0);180181/* Set CTS */182if (cts)183dw_hdmi_qp_mod(hdmi, AUDPKT_ACR_CTS_OVR_EN, AUDPKT_ACR_CTS_OVR_EN_MSK,184AUDPKT_ACR_CONTROL1);185else186dw_hdmi_qp_mod(hdmi, 0, AUDPKT_ACR_CTS_OVR_EN_MSK,187AUDPKT_ACR_CONTROL1);188189dw_hdmi_qp_mod(hdmi, AUDPKT_ACR_CTS_OVR_VAL(cts), AUDPKT_ACR_CTS_OVR_VAL_MSK,190AUDPKT_ACR_CONTROL1);191}192193static int dw_hdmi_qp_match_tmds_n_table(struct dw_hdmi_qp *hdmi,194unsigned long pixel_clk,195unsigned long freq)196{197const struct dw_hdmi_audio_tmds_n *tmds_n = NULL;198int i;199200for (i = 0; common_tmds_n_table[i].tmds != 0; i++) {201if (pixel_clk == common_tmds_n_table[i].tmds) {202tmds_n = &common_tmds_n_table[i];203break;204}205}206207if (!tmds_n)208return -ENOENT;209210switch (freq) {211case 32000:212return tmds_n->n_32k;213case 44100:214case 88200:215case 176400:216return (freq / 44100) * tmds_n->n_44k1;217case 48000:218case 96000:219case 192000:220return (freq / 48000) * tmds_n->n_48k;221default:222return -ENOENT;223}224}225226static u32 dw_hdmi_qp_audio_math_diff(unsigned int freq, unsigned int n,227unsigned int pixel_clk)228{229u64 cts = mul_u32_u32(pixel_clk, n);230231return do_div(cts, 128 * freq);232}233234static unsigned int dw_hdmi_qp_compute_n(struct dw_hdmi_qp *hdmi,235unsigned long pixel_clk,236unsigned long freq)237{238unsigned int min_n = DIV_ROUND_UP((128 * freq), 1500);239unsigned int max_n = (128 * freq) / 300;240unsigned int ideal_n = (128 * freq) / 1000;241unsigned int best_n_distance = ideal_n;242unsigned int best_n = 0;243u64 best_diff = U64_MAX;244int n;245246/* If the ideal N could satisfy the audio math, then just take it */247if (dw_hdmi_qp_audio_math_diff(freq, ideal_n, pixel_clk) == 0)248return ideal_n;249250for (n = min_n; n <= max_n; n++) {251u64 diff = dw_hdmi_qp_audio_math_diff(freq, n, pixel_clk);252253if (diff < best_diff ||254(diff == best_diff && abs(n - ideal_n) < best_n_distance)) {255best_n = n;256best_diff = diff;257best_n_distance = abs(best_n - ideal_n);258}259260/*261* The best N already satisfy the audio math, and also be262* the closest value to ideal N, so just cut the loop.263*/264if (best_diff == 0 && (abs(n - ideal_n) > best_n_distance))265break;266}267268return best_n;269}270271static unsigned int dw_hdmi_qp_find_n(struct dw_hdmi_qp *hdmi, unsigned long pixel_clk,272unsigned long sample_rate)273{274int n = dw_hdmi_qp_match_tmds_n_table(hdmi, pixel_clk, sample_rate);275276if (n > 0)277return n;278279dev_warn(hdmi->dev, "Rate %lu missing; compute N dynamically\n",280pixel_clk);281282return dw_hdmi_qp_compute_n(hdmi, pixel_clk, sample_rate);283}284285static unsigned int dw_hdmi_qp_find_cts(struct dw_hdmi_qp *hdmi, unsigned long pixel_clk,286unsigned long sample_rate)287{288const struct dw_hdmi_audio_tmds_cts *tmds_cts = NULL;289int i;290291for (i = 0; common_tmds_cts_table[i].tmds != 0; i++) {292if (pixel_clk == common_tmds_cts_table[i].tmds) {293tmds_cts = &common_tmds_cts_table[i];294break;295}296}297298if (!tmds_cts)299return 0;300301switch (sample_rate) {302case 32000:303return tmds_cts->cts_32k;304case 44100:305case 88200:306case 176400:307return tmds_cts->cts_44k1;308case 48000:309case 96000:310case 192000:311return tmds_cts->cts_48k;312default:313return -ENOENT;314}315}316317static void dw_hdmi_qp_set_audio_interface(struct dw_hdmi_qp *hdmi,318struct hdmi_codec_daifmt *fmt,319struct hdmi_codec_params *hparms)320{321u32 conf0 = 0;322323/* Reset the audio data path of the AVP */324dw_hdmi_qp_write(hdmi, AVP_DATAPATH_PACKET_AUDIO_SWINIT_P, GLOBAL_SWRESET_REQUEST);325326/* Disable AUDS, ACR, AUDI */327dw_hdmi_qp_mod(hdmi, 0,328PKTSCHED_ACR_TX_EN | PKTSCHED_AUDS_TX_EN | PKTSCHED_AUDI_TX_EN,329PKTSCHED_PKT_EN);330331/* Clear the audio FIFO */332dw_hdmi_qp_write(hdmi, AUDIO_FIFO_CLR_P, AUDIO_INTERFACE_CONTROL0);333334/* Select I2S interface as the audio source */335dw_hdmi_qp_mod(hdmi, AUD_IF_I2S, AUD_IF_SEL_MSK, AUDIO_INTERFACE_CONFIG0);336337/* Enable the active i2s lanes */338switch (hparms->channels) {339case 7 ... 8:340conf0 |= I2S_LINES_EN(3);341fallthrough;342case 5 ... 6:343conf0 |= I2S_LINES_EN(2);344fallthrough;345case 3 ... 4:346conf0 |= I2S_LINES_EN(1);347fallthrough;348default:349conf0 |= I2S_LINES_EN(0);350break;351}352353dw_hdmi_qp_mod(hdmi, conf0, I2S_LINES_EN_MSK, AUDIO_INTERFACE_CONFIG0);354355/*356* Enable bpcuv generated internally for L-PCM, or received357* from stream for NLPCM/HBR.358*/359switch (fmt->bit_fmt) {360case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:361conf0 = (hparms->channels == 8) ? AUD_HBR : AUD_ASP;362conf0 |= I2S_BPCUV_RCV_EN;363break;364default:365conf0 = AUD_ASP | I2S_BPCUV_RCV_DIS;366break;367}368369dw_hdmi_qp_mod(hdmi, conf0, I2S_BPCUV_RCV_MSK | AUD_FORMAT_MSK,370AUDIO_INTERFACE_CONFIG0);371372/* Enable audio FIFO auto clear when overflow */373dw_hdmi_qp_mod(hdmi, AUD_FIFO_INIT_ON_OVF_EN, AUD_FIFO_INIT_ON_OVF_MSK,374AUDIO_INTERFACE_CONFIG0);375}376377/*378* When transmitting IEC60958 linear PCM audio, these registers allow to379* configure the channel status information of all the channel status380* bits in the IEC60958 frame. For the moment this configuration is only381* used when the I2S audio interface, General Purpose Audio (GPA),382* or AHB audio DMA (AHBAUDDMA) interface is active383* (for S/PDIF interface this information comes from the stream).384*/385static void dw_hdmi_qp_set_channel_status(struct dw_hdmi_qp *hdmi,386u8 *channel_status, bool ref2stream)387{388/*389* AUDPKT_CHSTATUS_OVR0: { RSV, RSV, CS1, CS0 }390* AUDPKT_CHSTATUS_OVR1: { CS6, CS5, CS4, CS3 }391*392* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |393* CS0: | Mode | d | c | b | a |394* CS1: | Category Code |395* CS2: | Channel Number | Source Number |396* CS3: | Clock Accuracy | Sample Freq |397* CS4: | Ori Sample Freq | Word Length |398* CS5: | | CGMS-A |399* CS6~CS23: Reserved400*401* a: use of channel status block402* b: linear PCM identification: 0 for lpcm, 1 for nlpcm403* c: copyright information404* d: additional format information405*/406407if (ref2stream)408channel_status[0] |= IEC958_AES0_NONAUDIO;409410if ((dw_hdmi_qp_read(hdmi, AUDIO_INTERFACE_CONFIG0) & GENMASK(25, 24)) == AUD_HBR) {411/* fixup cs for HBR */412channel_status[3] = (channel_status[3] & 0xf0) | IEC958_AES3_CON_FS_768000;413channel_status[4] = (channel_status[4] & 0x0f) | IEC958_AES4_CON_ORIGFS_NOTID;414}415416dw_hdmi_qp_write(hdmi, channel_status[0] | (channel_status[1] << 8),417AUDPKT_CHSTATUS_OVR0);418419regmap_bulk_write(hdmi->regm, AUDPKT_CHSTATUS_OVR1, &channel_status[3], 1);420421if (ref2stream)422dw_hdmi_qp_mod(hdmi, 0,423AUDPKT_PBIT_FORCE_EN_MASK | AUDPKT_CHSTATUS_OVR_EN_MASK,424AUDPKT_CONTROL0);425else426dw_hdmi_qp_mod(hdmi, AUDPKT_PBIT_FORCE_EN | AUDPKT_CHSTATUS_OVR_EN,427AUDPKT_PBIT_FORCE_EN_MASK | AUDPKT_CHSTATUS_OVR_EN_MASK,428AUDPKT_CONTROL0);429}430431static void dw_hdmi_qp_set_sample_rate(struct dw_hdmi_qp *hdmi, unsigned long long tmds_char_rate,432unsigned int sample_rate)433{434unsigned int n, cts;435436n = dw_hdmi_qp_find_n(hdmi, tmds_char_rate, sample_rate);437cts = dw_hdmi_qp_find_cts(hdmi, tmds_char_rate, sample_rate);438439dw_hdmi_qp_set_cts_n(hdmi, cts, n);440}441442static int dw_hdmi_qp_audio_enable(struct drm_bridge *bridge,443struct drm_connector *connector)444{445struct dw_hdmi_qp *hdmi = dw_hdmi_qp_from_bridge(bridge);446447if (hdmi->tmds_char_rate)448dw_hdmi_qp_mod(hdmi, 0, AVP_DATAPATH_PACKET_AUDIO_SWDISABLE, GLOBAL_SWDISABLE);449450return 0;451}452453static int dw_hdmi_qp_audio_prepare(struct drm_bridge *bridge,454struct drm_connector *connector,455struct hdmi_codec_daifmt *fmt,456struct hdmi_codec_params *hparms)457{458struct dw_hdmi_qp *hdmi = dw_hdmi_qp_from_bridge(bridge);459bool ref2stream = false;460461if (!hdmi->tmds_char_rate)462return -ENODEV;463464if (fmt->bit_clk_provider | fmt->frame_clk_provider) {465dev_err(hdmi->dev, "unsupported clock settings\n");466return -EINVAL;467}468469if (fmt->bit_fmt == SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE)470ref2stream = true;471472dw_hdmi_qp_set_audio_interface(hdmi, fmt, hparms);473dw_hdmi_qp_set_sample_rate(hdmi, hdmi->tmds_char_rate, hparms->sample_rate);474dw_hdmi_qp_set_channel_status(hdmi, hparms->iec.status, ref2stream);475drm_atomic_helper_connector_hdmi_update_audio_infoframe(connector, &hparms->cea);476477return 0;478}479480static void dw_hdmi_qp_audio_disable_regs(struct dw_hdmi_qp *hdmi)481{482/*483* Keep ACR, AUDI, AUDS packet always on to make SINK device484* active for better compatibility and user experience.485*486* This also fix POP sound on some SINK devices which wakeup487* from suspend to active.488*/489dw_hdmi_qp_mod(hdmi, I2S_BPCUV_RCV_DIS, I2S_BPCUV_RCV_MSK,490AUDIO_INTERFACE_CONFIG0);491dw_hdmi_qp_mod(hdmi, AUDPKT_PBIT_FORCE_EN | AUDPKT_CHSTATUS_OVR_EN,492AUDPKT_PBIT_FORCE_EN_MASK | AUDPKT_CHSTATUS_OVR_EN_MASK,493AUDPKT_CONTROL0);494495dw_hdmi_qp_mod(hdmi, AVP_DATAPATH_PACKET_AUDIO_SWDISABLE,496AVP_DATAPATH_PACKET_AUDIO_SWDISABLE, GLOBAL_SWDISABLE);497}498499static void dw_hdmi_qp_audio_disable(struct drm_bridge *bridge,500struct drm_connector *connector)501{502struct dw_hdmi_qp *hdmi = dw_hdmi_qp_from_bridge(bridge);503504drm_atomic_helper_connector_hdmi_clear_audio_infoframe(connector);505506if (hdmi->tmds_char_rate)507dw_hdmi_qp_audio_disable_regs(hdmi);508}509510static int dw_hdmi_qp_i2c_read(struct dw_hdmi_qp *hdmi,511unsigned char *buf, unsigned int length)512{513struct dw_hdmi_qp_i2c *i2c = hdmi->i2c;514int stat;515516if (!i2c->is_regaddr) {517dev_dbg(hdmi->dev, "set read register address to 0\n");518i2c->slave_reg = 0x00;519i2c->is_regaddr = true;520}521522while (length--) {523reinit_completion(&i2c->cmp);524525dw_hdmi_qp_mod(hdmi, i2c->slave_reg++ << 12, I2CM_ADDR,526I2CM_INTERFACE_CONTROL0);527528if (i2c->is_segment)529dw_hdmi_qp_mod(hdmi, I2CM_EXT_READ, I2CM_WR_MASK,530I2CM_INTERFACE_CONTROL0);531else532dw_hdmi_qp_mod(hdmi, I2CM_FM_READ, I2CM_WR_MASK,533I2CM_INTERFACE_CONTROL0);534535stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10);536if (!stat) {537dev_err(hdmi->dev, "i2c read timed out\n");538dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);539return -EAGAIN;540}541542/* Check for error condition on the bus */543if (i2c->stat & I2CM_NACK_RCVD_IRQ) {544dev_err(hdmi->dev, "i2c read error\n");545dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);546return -EIO;547}548549*buf++ = dw_hdmi_qp_read(hdmi, I2CM_INTERFACE_RDDATA_0_3) & 0xff;550dw_hdmi_qp_mod(hdmi, 0, I2CM_WR_MASK, I2CM_INTERFACE_CONTROL0);551}552553i2c->is_segment = false;554555return 0;556}557558static int dw_hdmi_qp_i2c_write(struct dw_hdmi_qp *hdmi,559unsigned char *buf, unsigned int length)560{561struct dw_hdmi_qp_i2c *i2c = hdmi->i2c;562int stat;563564if (!i2c->is_regaddr) {565/* Use the first write byte as register address */566i2c->slave_reg = buf[0];567length--;568buf++;569i2c->is_regaddr = true;570}571572while (length--) {573reinit_completion(&i2c->cmp);574575dw_hdmi_qp_write(hdmi, *buf++, I2CM_INTERFACE_WRDATA_0_3);576dw_hdmi_qp_mod(hdmi, i2c->slave_reg++ << 12, I2CM_ADDR,577I2CM_INTERFACE_CONTROL0);578dw_hdmi_qp_mod(hdmi, I2CM_FM_WRITE, I2CM_WR_MASK,579I2CM_INTERFACE_CONTROL0);580581stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10);582if (!stat) {583dev_err(hdmi->dev, "i2c write time out!\n");584dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);585return -EAGAIN;586}587588/* Check for error condition on the bus */589if (i2c->stat & I2CM_NACK_RCVD_IRQ) {590dev_err(hdmi->dev, "i2c write nack!\n");591dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);592return -EIO;593}594595dw_hdmi_qp_mod(hdmi, 0, I2CM_WR_MASK, I2CM_INTERFACE_CONTROL0);596}597598return 0;599}600601static int dw_hdmi_qp_i2c_xfer(struct i2c_adapter *adap,602struct i2c_msg *msgs, int num)603{604struct dw_hdmi_qp *hdmi = i2c_get_adapdata(adap);605struct dw_hdmi_qp_i2c *i2c = hdmi->i2c;606u8 addr = msgs[0].addr;607int i, ret = 0;608609if (addr == DDC_CI_ADDR)610/*611* The internal I2C controller does not support the multi-byte612* read and write operations needed for DDC/CI.613* FIXME: Blacklist the DDC/CI address until we filter out614* unsupported I2C operations.615*/616return -EOPNOTSUPP;617618for (i = 0; i < num; i++) {619if (msgs[i].len == 0) {620dev_err(hdmi->dev,621"unsupported transfer %d/%d, no data\n",622i + 1, num);623return -EOPNOTSUPP;624}625}626627guard(mutex)(&i2c->lock);628629/* Unmute DONE and ERROR interrupts */630dw_hdmi_qp_mod(hdmi, I2CM_NACK_RCVD_MASK_N | I2CM_OP_DONE_MASK_N,631I2CM_NACK_RCVD_MASK_N | I2CM_OP_DONE_MASK_N,632MAINUNIT_1_INT_MASK_N);633634/* Set slave device address taken from the first I2C message */635if (addr == DDC_SEGMENT_ADDR && msgs[0].len == 1)636addr = DDC_ADDR;637638dw_hdmi_qp_mod(hdmi, addr << 5, I2CM_SLVADDR, I2CM_INTERFACE_CONTROL0);639640/* Set slave device register address on transfer */641i2c->is_regaddr = false;642643/* Set segment pointer for I2C extended read mode operation */644i2c->is_segment = false;645646for (i = 0; i < num; i++) {647if (msgs[i].addr == DDC_SEGMENT_ADDR && msgs[i].len == 1) {648i2c->is_segment = true;649dw_hdmi_qp_mod(hdmi, DDC_SEGMENT_ADDR, I2CM_SEG_ADDR,650I2CM_INTERFACE_CONTROL1);651dw_hdmi_qp_mod(hdmi, *msgs[i].buf << 7, I2CM_SEG_PTR,652I2CM_INTERFACE_CONTROL1);653} else {654if (msgs[i].flags & I2C_M_RD)655ret = dw_hdmi_qp_i2c_read(hdmi, msgs[i].buf,656msgs[i].len);657else658ret = dw_hdmi_qp_i2c_write(hdmi, msgs[i].buf,659msgs[i].len);660}661if (ret < 0)662break;663}664665if (!ret)666ret = num;667668/* Mute DONE and ERROR interrupts */669dw_hdmi_qp_mod(hdmi, 0, I2CM_OP_DONE_MASK_N | I2CM_NACK_RCVD_MASK_N,670MAINUNIT_1_INT_MASK_N);671672return ret;673}674675static u32 dw_hdmi_qp_i2c_func(struct i2c_adapter *adapter)676{677return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;678}679680static const struct i2c_algorithm dw_hdmi_qp_algorithm = {681.master_xfer = dw_hdmi_qp_i2c_xfer,682.functionality = dw_hdmi_qp_i2c_func,683};684685static struct i2c_adapter *dw_hdmi_qp_i2c_adapter(struct dw_hdmi_qp *hdmi)686{687struct dw_hdmi_qp_i2c *i2c;688struct i2c_adapter *adap;689int ret;690691i2c = devm_kzalloc(hdmi->dev, sizeof(*i2c), GFP_KERNEL);692if (!i2c)693return ERR_PTR(-ENOMEM);694695mutex_init(&i2c->lock);696init_completion(&i2c->cmp);697698adap = &i2c->adap;699adap->owner = THIS_MODULE;700adap->dev.parent = hdmi->dev;701adap->algo = &dw_hdmi_qp_algorithm;702strscpy(adap->name, "DesignWare HDMI QP", sizeof(adap->name));703704i2c_set_adapdata(adap, hdmi);705706ret = devm_i2c_add_adapter(hdmi->dev, adap);707if (ret) {708dev_warn(hdmi->dev, "cannot add %s I2C adapter\n", adap->name);709devm_kfree(hdmi->dev, i2c);710return ERR_PTR(ret);711}712713hdmi->i2c = i2c;714dev_info(hdmi->dev, "registered %s I2C bus driver\n", adap->name);715716return adap;717}718719static int dw_hdmi_qp_config_avi_infoframe(struct dw_hdmi_qp *hdmi,720const u8 *buffer, size_t len)721{722u32 val, i, j;723724if (len != HDMI_INFOFRAME_SIZE(AVI)) {725dev_err(hdmi->dev, "failed to configure avi infoframe\n");726return -EINVAL;727}728729/*730* DW HDMI QP IP uses a different byte format from standard AVI info731* frames, though generally the bits are in the correct bytes.732*/733val = buffer[1] << 8 | buffer[2] << 16;734dw_hdmi_qp_write(hdmi, val, PKT_AVI_CONTENTS0);735736for (i = 0; i < 4; i++) {737for (j = 0; j < 4; j++) {738if (i * 4 + j >= 14)739break;740if (!j)741val = buffer[i * 4 + j + 3];742val |= buffer[i * 4 + j + 3] << (8 * j);743}744745dw_hdmi_qp_write(hdmi, val, PKT_AVI_CONTENTS1 + i * 4);746}747748dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_AVI_FIELDRATE, PKTSCHED_PKT_CONFIG1);749750dw_hdmi_qp_mod(hdmi, PKTSCHED_AVI_TX_EN | PKTSCHED_GCP_TX_EN,751PKTSCHED_AVI_TX_EN | PKTSCHED_GCP_TX_EN, PKTSCHED_PKT_EN);752753return 0;754}755756static int dw_hdmi_qp_config_drm_infoframe(struct dw_hdmi_qp *hdmi,757const u8 *buffer, size_t len)758{759u32 val, i;760761if (len != HDMI_INFOFRAME_SIZE(DRM)) {762dev_err(hdmi->dev, "failed to configure drm infoframe\n");763return -EINVAL;764}765766dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_TX_EN, PKTSCHED_PKT_EN);767768val = buffer[1] << 8 | buffer[2] << 16;769dw_hdmi_qp_write(hdmi, val, PKT_DRMI_CONTENTS0);770771for (i = 0; i <= buffer[2]; i++) {772if (i % 4 == 0)773val = buffer[3 + i];774val |= buffer[3 + i] << ((i % 4) * 8);775776if ((i % 4 == 3) || i == buffer[2])777dw_hdmi_qp_write(hdmi, val,778PKT_DRMI_CONTENTS1 + ((i / 4) * 4));779}780781dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_FIELDRATE, PKTSCHED_PKT_CONFIG1);782dw_hdmi_qp_mod(hdmi, PKTSCHED_DRMI_TX_EN, PKTSCHED_DRMI_TX_EN,783PKTSCHED_PKT_EN);784785return 0;786}787788/*789* Static values documented in the TRM790* Different values are only used for debug purposes791*/792#define DW_HDMI_QP_AUDIO_INFOFRAME_HB1 0x1793#define DW_HDMI_QP_AUDIO_INFOFRAME_HB2 0xa794795static int dw_hdmi_qp_config_audio_infoframe(struct dw_hdmi_qp *hdmi,796const u8 *buffer, size_t len)797{798/*799* AUDI_CONTENTS0: { RSV, HB2, HB1, RSV }800* AUDI_CONTENTS1: { PB3, PB2, PB1, PB0 }801* AUDI_CONTENTS2: { PB7, PB6, PB5, PB4 }802*803* PB0: CheckSum804* PB1: | CT3 | CT2 | CT1 | CT0 | F13 | CC2 | CC1 | CC0 |805* PB2: | F27 | F26 | F25 | SF2 | SF1 | SF0 | SS1 | SS0 |806* PB3: | F37 | F36 | F35 | F34 | F33 | F32 | F31 | F30 |807* PB4: | CA7 | CA6 | CA5 | CA4 | CA3 | CA2 | CA1 | CA0 |808* PB5: | DM_INH | LSV3 | LSV2 | LSV1 | LSV0 | F52 | F51 | F50 |809* PB6~PB10: Reserved810*811* AUDI_CONTENTS0 default value defined by HDMI specification,812* and shall only be changed for debug purposes.813*/814u32 header_bytes = (DW_HDMI_QP_AUDIO_INFOFRAME_HB1 << 8) |815(DW_HDMI_QP_AUDIO_INFOFRAME_HB2 << 16);816817regmap_bulk_write(hdmi->regm, PKT_AUDI_CONTENTS0, &header_bytes, 1);818regmap_bulk_write(hdmi->regm, PKT_AUDI_CONTENTS1, &buffer[3], 1);819regmap_bulk_write(hdmi->regm, PKT_AUDI_CONTENTS2, &buffer[4], 1);820821/* Enable ACR, AUDI, AMD */822dw_hdmi_qp_mod(hdmi,823PKTSCHED_ACR_TX_EN | PKTSCHED_AUDI_TX_EN | PKTSCHED_AMD_TX_EN,824PKTSCHED_ACR_TX_EN | PKTSCHED_AUDI_TX_EN | PKTSCHED_AMD_TX_EN,825PKTSCHED_PKT_EN);826827/* Enable AUDS */828dw_hdmi_qp_mod(hdmi, PKTSCHED_AUDS_TX_EN, PKTSCHED_AUDS_TX_EN, PKTSCHED_PKT_EN);829830return 0;831}832833static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,834struct drm_atomic_state *state)835{836struct dw_hdmi_qp *hdmi = bridge->driver_private;837struct drm_connector_state *conn_state;838struct drm_connector *connector;839unsigned int op_mode;840841connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);842if (WARN_ON(!connector))843return;844845conn_state = drm_atomic_get_new_connector_state(state, connector);846if (WARN_ON(!conn_state))847return;848849if (connector->display_info.is_hdmi) {850dev_dbg(hdmi->dev, "%s mode=HDMI rate=%llu\n",851__func__, conn_state->hdmi.tmds_char_rate);852op_mode = 0;853hdmi->tmds_char_rate = conn_state->hdmi.tmds_char_rate;854} else {855dev_dbg(hdmi->dev, "%s mode=DVI\n", __func__);856op_mode = OPMODE_DVI;857}858859hdmi->phy.ops->init(hdmi, hdmi->phy.data);860861dw_hdmi_qp_mod(hdmi, HDCP2_BYPASS, HDCP2_BYPASS, HDCP2LOGIC_CONFIG0);862dw_hdmi_qp_mod(hdmi, op_mode, OPMODE_DVI, LINK_CONFIG0);863864drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);865}866867static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,868struct drm_atomic_state *state)869{870struct dw_hdmi_qp *hdmi = bridge->driver_private;871872hdmi->tmds_char_rate = 0;873874hdmi->phy.ops->disable(hdmi, hdmi->phy.data);875}876877static enum drm_connector_status878dw_hdmi_qp_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connector)879{880struct dw_hdmi_qp *hdmi = bridge->driver_private;881882return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data);883}884885static const struct drm_edid *886dw_hdmi_qp_bridge_edid_read(struct drm_bridge *bridge,887struct drm_connector *connector)888{889struct dw_hdmi_qp *hdmi = bridge->driver_private;890const struct drm_edid *drm_edid;891892drm_edid = drm_edid_read_ddc(connector, bridge->ddc);893if (!drm_edid)894dev_dbg(hdmi->dev, "failed to get edid\n");895896return drm_edid;897}898899static enum drm_mode_status900dw_hdmi_qp_bridge_tmds_char_rate_valid(const struct drm_bridge *bridge,901const struct drm_display_mode *mode,902unsigned long long rate)903{904struct dw_hdmi_qp *hdmi = bridge->driver_private;905906if (rate > HDMI14_MAX_TMDSCLK) {907dev_dbg(hdmi->dev, "Unsupported TMDS char rate: %lld\n", rate);908return MODE_CLOCK_HIGH;909}910911return MODE_OK;912}913914static int dw_hdmi_qp_bridge_clear_infoframe(struct drm_bridge *bridge,915enum hdmi_infoframe_type type)916{917struct dw_hdmi_qp *hdmi = bridge->driver_private;918919switch (type) {920case HDMI_INFOFRAME_TYPE_AVI:921dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_AVI_TX_EN | PKTSCHED_GCP_TX_EN,922PKTSCHED_PKT_EN);923break;924925case HDMI_INFOFRAME_TYPE_DRM:926dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_TX_EN, PKTSCHED_PKT_EN);927break;928929case HDMI_INFOFRAME_TYPE_AUDIO:930dw_hdmi_qp_mod(hdmi, 0,931PKTSCHED_ACR_TX_EN |932PKTSCHED_AUDS_TX_EN |933PKTSCHED_AUDI_TX_EN,934PKTSCHED_PKT_EN);935break;936default:937dev_dbg(hdmi->dev, "Unsupported infoframe type %x\n", type);938}939940return 0;941}942943static int dw_hdmi_qp_bridge_write_infoframe(struct drm_bridge *bridge,944enum hdmi_infoframe_type type,945const u8 *buffer, size_t len)946{947struct dw_hdmi_qp *hdmi = bridge->driver_private;948949dw_hdmi_qp_bridge_clear_infoframe(bridge, type);950951switch (type) {952case HDMI_INFOFRAME_TYPE_AVI:953return dw_hdmi_qp_config_avi_infoframe(hdmi, buffer, len);954955case HDMI_INFOFRAME_TYPE_DRM:956return dw_hdmi_qp_config_drm_infoframe(hdmi, buffer, len);957958case HDMI_INFOFRAME_TYPE_AUDIO:959return dw_hdmi_qp_config_audio_infoframe(hdmi, buffer, len);960961default:962dev_dbg(hdmi->dev, "Unsupported infoframe type %x\n", type);963return 0;964}965}966967static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {968.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,969.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,970.atomic_reset = drm_atomic_helper_bridge_reset,971.atomic_enable = dw_hdmi_qp_bridge_atomic_enable,972.atomic_disable = dw_hdmi_qp_bridge_atomic_disable,973.detect = dw_hdmi_qp_bridge_detect,974.edid_read = dw_hdmi_qp_bridge_edid_read,975.hdmi_tmds_char_rate_valid = dw_hdmi_qp_bridge_tmds_char_rate_valid,976.hdmi_clear_infoframe = dw_hdmi_qp_bridge_clear_infoframe,977.hdmi_write_infoframe = dw_hdmi_qp_bridge_write_infoframe,978.hdmi_audio_startup = dw_hdmi_qp_audio_enable,979.hdmi_audio_shutdown = dw_hdmi_qp_audio_disable,980.hdmi_audio_prepare = dw_hdmi_qp_audio_prepare,981};982983static irqreturn_t dw_hdmi_qp_main_hardirq(int irq, void *dev_id)984{985struct dw_hdmi_qp *hdmi = dev_id;986struct dw_hdmi_qp_i2c *i2c = hdmi->i2c;987u32 stat;988989stat = dw_hdmi_qp_read(hdmi, MAINUNIT_1_INT_STATUS);990991i2c->stat = stat & (I2CM_OP_DONE_IRQ | I2CM_READ_REQUEST_IRQ |992I2CM_NACK_RCVD_IRQ);993994if (i2c->stat) {995dw_hdmi_qp_write(hdmi, i2c->stat, MAINUNIT_1_INT_CLEAR);996complete(&i2c->cmp);997}998999if (stat)1000return IRQ_HANDLED;10011002return IRQ_NONE;1003}10041005static const struct regmap_config dw_hdmi_qp_regmap_config = {1006.reg_bits = 32,1007.val_bits = 32,1008.reg_stride = 4,1009.max_register = EARCRX_1_INT_FORCE,1010};10111012static void dw_hdmi_qp_init_hw(struct dw_hdmi_qp *hdmi)1013{1014dw_hdmi_qp_write(hdmi, 0, MAINUNIT_0_INT_MASK_N);1015dw_hdmi_qp_write(hdmi, 0, MAINUNIT_1_INT_MASK_N);1016dw_hdmi_qp_write(hdmi, 428571429, TIMER_BASE_CONFIG0);10171018/* Software reset */1019dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);10201021dw_hdmi_qp_write(hdmi, 0x085c085c, I2CM_FM_SCL_CONFIG0);10221023dw_hdmi_qp_mod(hdmi, 0, I2CM_FM_EN, I2CM_INTERFACE_CONTROL0);10241025/* Clear DONE and ERROR interrupts */1026dw_hdmi_qp_write(hdmi, I2CM_OP_DONE_CLEAR | I2CM_NACK_RCVD_CLEAR,1027MAINUNIT_1_INT_CLEAR);10281029if (hdmi->phy.ops->setup_hpd)1030hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data);1031}10321033struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,1034struct drm_encoder *encoder,1035const struct dw_hdmi_qp_plat_data *plat_data)1036{1037struct device *dev = &pdev->dev;1038struct dw_hdmi_qp *hdmi;1039void __iomem *regs;1040int ret;10411042if (!plat_data->phy_ops || !plat_data->phy_ops->init ||1043!plat_data->phy_ops->disable || !plat_data->phy_ops->read_hpd) {1044dev_err(dev, "Missing platform PHY ops\n");1045return ERR_PTR(-ENODEV);1046}10471048hdmi = devm_drm_bridge_alloc(dev, struct dw_hdmi_qp, bridge,1049&dw_hdmi_qp_bridge_funcs);1050if (IS_ERR(hdmi))1051return ERR_CAST(hdmi);10521053hdmi->dev = dev;10541055regs = devm_platform_ioremap_resource(pdev, 0);1056if (IS_ERR(regs))1057return ERR_CAST(regs);10581059hdmi->regm = devm_regmap_init_mmio(dev, regs, &dw_hdmi_qp_regmap_config);1060if (IS_ERR(hdmi->regm)) {1061dev_err(dev, "Failed to configure regmap\n");1062return ERR_CAST(hdmi->regm);1063}10641065hdmi->phy.ops = plat_data->phy_ops;1066hdmi->phy.data = plat_data->phy_data;10671068dw_hdmi_qp_init_hw(hdmi);10691070ret = devm_request_threaded_irq(dev, plat_data->main_irq,1071dw_hdmi_qp_main_hardirq, NULL,1072IRQF_SHARED, dev_name(dev), hdmi);1073if (ret)1074return ERR_PTR(ret);10751076hdmi->bridge.driver_private = hdmi;1077hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT |1078DRM_BRIDGE_OP_EDID |1079DRM_BRIDGE_OP_HDMI |1080DRM_BRIDGE_OP_HDMI_AUDIO |1081DRM_BRIDGE_OP_HPD;1082hdmi->bridge.of_node = pdev->dev.of_node;1083hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;1084hdmi->bridge.vendor = "Synopsys";1085hdmi->bridge.product = "DW HDMI QP TX";10861087hdmi->bridge.ddc = dw_hdmi_qp_i2c_adapter(hdmi);1088if (IS_ERR(hdmi->bridge.ddc))1089return ERR_CAST(hdmi->bridge.ddc);10901091hdmi->bridge.hdmi_audio_max_i2s_playback_channels = 8;1092hdmi->bridge.hdmi_audio_dev = dev;1093hdmi->bridge.hdmi_audio_dai_port = 1;10941095ret = devm_drm_bridge_add(dev, &hdmi->bridge);1096if (ret)1097return ERR_PTR(ret);10981099ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL,1100DRM_BRIDGE_ATTACH_NO_CONNECTOR);1101if (ret)1102return ERR_PTR(ret);11031104return hdmi;1105}1106EXPORT_SYMBOL_GPL(dw_hdmi_qp_bind);11071108void dw_hdmi_qp_resume(struct device *dev, struct dw_hdmi_qp *hdmi)1109{1110dw_hdmi_qp_init_hw(hdmi);1111}1112EXPORT_SYMBOL_GPL(dw_hdmi_qp_resume);11131114MODULE_AUTHOR("Algea Cao <[email protected]>");1115MODULE_AUTHOR("Cristian Ciocaltea <[email protected]>");1116MODULE_DESCRIPTION("DW HDMI QP transmitter library");1117MODULE_LICENSE("GPL");111811191120