diff options
Diffstat (limited to 'drivers/gpu/drm/i2c')
| -rw-r--r-- | drivers/gpu/drm/i2c/tda998x_drv.c | 863 | 
1 files changed, 454 insertions, 409 deletions
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 9798d400d817..86f47e190309 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -41,12 +41,15 @@ struct tda998x_priv {  	struct i2c_client *hdmi;  	struct mutex mutex;  	u16 rev; +	u8 cec_addr;  	u8 current_page; -	int dpms; -	bool is_hdmi_sink; +	bool is_on; +	bool supports_infoframes; +	bool sink_has_audio;  	u8 vip_cntrl_0;  	u8 vip_cntrl_1;  	u8 vip_cntrl_2; +	unsigned long tmds_clock;  	struct tda998x_audio_params audio_params;  	struct platform_device *audio_pdev; @@ -105,6 +108,8 @@ struct tda998x_priv {  # define I2C_MASTER_DIS_FILT      (1 << 1)  # define I2C_MASTER_APP_STRT_LAT  (1 << 2)  #define REG_FEAT_POWERDOWN        REG(0x00, 0x0e)     /* read/write */ +# define FEAT_POWERDOWN_PREFILT   BIT(0) +# define FEAT_POWERDOWN_CSC       BIT(1)  # define FEAT_POWERDOWN_SPDIF     (1 << 3)  #define REG_INT_FLAGS_0           REG(0x00, 0x0f)     /* read/write */  #define REG_INT_FLAGS_1           REG(0x00, 0x10)     /* read/write */ @@ -370,35 +375,46 @@ struct tda998x_priv {  static void  cec_write(struct tda998x_priv *priv, u16 addr, u8 val)  { -	struct i2c_client *client = priv->cec;  	u8 buf[] = {addr, val}; +	struct i2c_msg msg = { +		.addr = priv->cec_addr, +		.len = 2, +		.buf = buf, +	};  	int ret; -	ret = i2c_master_send(client, buf, sizeof(buf)); +	ret = i2c_transfer(priv->hdmi->adapter, &msg, 1);  	if (ret < 0) -		dev_err(&client->dev, "Error %d writing to cec:0x%x\n", ret, addr); +		dev_err(&priv->hdmi->dev, "Error %d writing to cec:0x%x\n", +			ret, addr);  }  static u8  cec_read(struct tda998x_priv *priv, u8 addr)  { -	struct i2c_client *client = priv->cec;  	u8 val; +	struct i2c_msg msg[2] = { +		{ +			.addr = priv->cec_addr, +			.len = 1, +			.buf = &addr, +		}, { +			.addr = priv->cec_addr, +			.flags = I2C_M_RD, +			.len = 1, +			.buf = &val, +		}, +	};  	int ret; -	ret = i2c_master_send(client, &addr, sizeof(addr)); -	if (ret < 0) -		goto fail; - -	ret = i2c_master_recv(client, &val, sizeof(val)); -	if (ret < 0) -		goto fail; +	ret = i2c_transfer(priv->hdmi->adapter, msg, ARRAY_SIZE(msg)); +	if (ret < 0) { +		dev_err(&priv->hdmi->dev, "Error %d reading from cec:0x%x\n", +			ret, addr); +		val = 0; +	}  	return val; - -fail: -	dev_err(&client->dev, "Error %d reading from cec:0x%x\n", ret, addr); -	return 0;  }  static int @@ -579,9 +595,9 @@ tda998x_reset(struct tda998x_priv *priv)   * HPD assertion: it needs a delay of 100ms to avoid timing out while   * trying to read EDID data.   * - * However, tda998x_encoder_get_modes() may be called at any moment + * However, tda998x_connector_get_modes() may be called at any moment   * after tda998x_connector_detect() indicates that we are connected, so - * we need to delay probing modes in tda998x_encoder_get_modes() after + * we need to delay probing modes in tda998x_connector_get_modes() after   * we have seen a HPD inactive->active transition.  This code implements   * that delay.   */ @@ -630,28 +646,30 @@ static irqreturn_t tda998x_irq_thread(int irq, void *data)  	bool handled = false;  	sta = cec_read(priv, REG_CEC_INTSTATUS); -	cec = cec_read(priv, REG_CEC_RXSHPDINT); -	lvl = cec_read(priv, REG_CEC_RXSHPDLEV); -	flag0 = reg_read(priv, REG_INT_FLAGS_0); -	flag1 = reg_read(priv, REG_INT_FLAGS_1); -	flag2 = reg_read(priv, REG_INT_FLAGS_2); -	DRM_DEBUG_DRIVER( -		"tda irq sta %02x cec %02x lvl %02x f0 %02x f1 %02x f2 %02x\n", -		sta, cec, lvl, flag0, flag1, flag2); - -	if (cec & CEC_RXSHPDINT_HPD) { -		if (lvl & CEC_RXSHPDLEV_HPD) -			tda998x_edid_delay_start(priv); -		else -			schedule_work(&priv->detect_work); - -		handled = true; -	} +	if (sta & CEC_INTSTATUS_HDMI) { +		cec = cec_read(priv, REG_CEC_RXSHPDINT); +		lvl = cec_read(priv, REG_CEC_RXSHPDLEV); +		flag0 = reg_read(priv, REG_INT_FLAGS_0); +		flag1 = reg_read(priv, REG_INT_FLAGS_1); +		flag2 = reg_read(priv, REG_INT_FLAGS_2); +		DRM_DEBUG_DRIVER( +			"tda irq sta %02x cec %02x lvl %02x f0 %02x f1 %02x f2 %02x\n", +			sta, cec, lvl, flag0, flag1, flag2); + +		if (cec & CEC_RXSHPDINT_HPD) { +			if (lvl & CEC_RXSHPDLEV_HPD) +				tda998x_edid_delay_start(priv); +			else +				schedule_work(&priv->detect_work); + +			handled = true; +		} -	if ((flag2 & INT_FLAGS_2_EDID_BLK_RD) && priv->wq_edid_wait) { -		priv->wq_edid_wait = 0; -		wake_up(&priv->wq_edid); -		handled = true; +		if ((flag2 & INT_FLAGS_2_EDID_BLK_RD) && priv->wq_edid_wait) { +			priv->wq_edid_wait = 0; +			wake_up(&priv->wq_edid); +			handled = true; +		}  	}  	return IRQ_RETVAL(handled); @@ -700,6 +718,8 @@ tda998x_write_avi(struct tda998x_priv *priv, struct drm_display_mode *mode)  	tda998x_write_if(priv, DIP_IF_FLAGS_IF2, REG_IF2_HB0, &frame);  } +/* Audio support */ +  static void tda998x_audio_mute(struct tda998x_priv *priv, bool on)  {  	if (on) { @@ -713,8 +733,7 @@ static void tda998x_audio_mute(struct tda998x_priv *priv, bool on)  static int  tda998x_configure_audio(struct tda998x_priv *priv, -			struct tda998x_audio_params *params, -			unsigned mode_clock) +			struct tda998x_audio_params *params)  {  	u8 buf[6], clksel_aip, clksel_fs, cts_n, adiv;  	u32 n; @@ -771,7 +790,7 @@ tda998x_configure_audio(struct tda998x_priv *priv,  	 * assume 100MHz requires larger divider.  	 */  	adiv = AUDIO_DIV_SERCLK_8; -	if (mode_clock > 100000) +	if (priv->tmds_clock > 100000)  		adiv++;			/* AUDIO_DIV_SERCLK_16 */  	/* S/PDIF asks for a larger divider */ @@ -819,58 +838,281 @@ tda998x_configure_audio(struct tda998x_priv *priv,  	return tda998x_write_aif(priv, ¶ms->cea);  } -/* DRM encoder functions */ +static int tda998x_audio_hw_params(struct device *dev, void *data, +				   struct hdmi_codec_daifmt *daifmt, +				   struct hdmi_codec_params *params) +{ +	struct tda998x_priv *priv = dev_get_drvdata(dev); +	int i, ret; +	struct tda998x_audio_params audio = { +		.sample_width = params->sample_width, +		.sample_rate = params->sample_rate, +		.cea = params->cea, +	}; + +	memcpy(audio.status, params->iec.status, +	       min(sizeof(audio.status), sizeof(params->iec.status))); -static void tda998x_encoder_set_config(struct tda998x_priv *priv, -				       const struct tda998x_encoder_params *p) +	switch (daifmt->fmt) { +	case HDMI_I2S: +		if (daifmt->bit_clk_inv || daifmt->frame_clk_inv || +		    daifmt->bit_clk_master || daifmt->frame_clk_master) { +			dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__, +				daifmt->bit_clk_inv, daifmt->frame_clk_inv, +				daifmt->bit_clk_master, +				daifmt->frame_clk_master); +			return -EINVAL; +		} +		for (i = 0; i < ARRAY_SIZE(priv->audio_port); i++) +			if (priv->audio_port[i].format == AFMT_I2S) +				audio.config = priv->audio_port[i].config; +		audio.format = AFMT_I2S; +		break; +	case HDMI_SPDIF: +		for (i = 0; i < ARRAY_SIZE(priv->audio_port); i++) +			if (priv->audio_port[i].format == AFMT_SPDIF) +				audio.config = priv->audio_port[i].config; +		audio.format = AFMT_SPDIF; +		break; +	default: +		dev_err(dev, "%s: Invalid format %d\n", __func__, daifmt->fmt); +		return -EINVAL; +	} + +	if (audio.config == 0) { +		dev_err(dev, "%s: No audio configuration found\n", __func__); +		return -EINVAL; +	} + +	mutex_lock(&priv->audio_mutex); +	if (priv->supports_infoframes && priv->sink_has_audio) +		ret = tda998x_configure_audio(priv, &audio); +	else +		ret = 0; + +	if (ret == 0) +		priv->audio_params = audio; +	mutex_unlock(&priv->audio_mutex); + +	return ret; +} + +static void tda998x_audio_shutdown(struct device *dev, void *data)  { -	priv->vip_cntrl_0 = VIP_CNTRL_0_SWAP_A(p->swap_a) | -			    (p->mirr_a ? VIP_CNTRL_0_MIRR_A : 0) | -			    VIP_CNTRL_0_SWAP_B(p->swap_b) | -			    (p->mirr_b ? VIP_CNTRL_0_MIRR_B : 0); -	priv->vip_cntrl_1 = VIP_CNTRL_1_SWAP_C(p->swap_c) | -			    (p->mirr_c ? VIP_CNTRL_1_MIRR_C : 0) | -			    VIP_CNTRL_1_SWAP_D(p->swap_d) | -			    (p->mirr_d ? VIP_CNTRL_1_MIRR_D : 0); -	priv->vip_cntrl_2 = VIP_CNTRL_2_SWAP_E(p->swap_e) | -			    (p->mirr_e ? VIP_CNTRL_2_MIRR_E : 0) | -			    VIP_CNTRL_2_SWAP_F(p->swap_f) | -			    (p->mirr_f ? VIP_CNTRL_2_MIRR_F : 0); +	struct tda998x_priv *priv = dev_get_drvdata(dev); -	priv->audio_params = p->audio_params; +	mutex_lock(&priv->audio_mutex); + +	reg_write(priv, REG_ENA_AP, 0); + +	priv->audio_params.format = AFMT_UNUSED; + +	mutex_unlock(&priv->audio_mutex);  } -static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode) +int tda998x_audio_digital_mute(struct device *dev, void *data, bool enable)  { -	struct tda998x_priv *priv = enc_to_tda998x_priv(encoder); +	struct tda998x_priv *priv = dev_get_drvdata(dev); -	/* we only care about on or off: */ -	if (mode != DRM_MODE_DPMS_ON) -		mode = DRM_MODE_DPMS_OFF; +	mutex_lock(&priv->audio_mutex); -	if (mode == priv->dpms) -		return; +	tda998x_audio_mute(priv, enable); -	switch (mode) { -	case DRM_MODE_DPMS_ON: -		/* enable video ports, audio will be enabled later */ -		reg_write(priv, REG_ENA_VP_0, 0xff); -		reg_write(priv, REG_ENA_VP_1, 0xff); -		reg_write(priv, REG_ENA_VP_2, 0xff); -		/* set muxing after enabling ports: */ -		reg_write(priv, REG_VIP_CNTRL_0, priv->vip_cntrl_0); -		reg_write(priv, REG_VIP_CNTRL_1, priv->vip_cntrl_1); -		reg_write(priv, REG_VIP_CNTRL_2, priv->vip_cntrl_2); -		break; -	case DRM_MODE_DPMS_OFF: -		/* disable video ports */ -		reg_write(priv, REG_ENA_VP_0, 0x00); -		reg_write(priv, REG_ENA_VP_1, 0x00); -		reg_write(priv, REG_ENA_VP_2, 0x00); -		break; +	mutex_unlock(&priv->audio_mutex); +	return 0; +} + +static int tda998x_audio_get_eld(struct device *dev, void *data, +				 uint8_t *buf, size_t len) +{ +	struct tda998x_priv *priv = dev_get_drvdata(dev); + +	mutex_lock(&priv->audio_mutex); +	memcpy(buf, priv->connector.eld, +	       min(sizeof(priv->connector.eld), len)); +	mutex_unlock(&priv->audio_mutex); + +	return 0; +} + +static const struct hdmi_codec_ops audio_codec_ops = { +	.hw_params = tda998x_audio_hw_params, +	.audio_shutdown = tda998x_audio_shutdown, +	.digital_mute = tda998x_audio_digital_mute, +	.get_eld = tda998x_audio_get_eld, +}; + +static int tda998x_audio_codec_init(struct tda998x_priv *priv, +				    struct device *dev) +{ +	struct hdmi_codec_pdata codec_data = { +		.ops = &audio_codec_ops, +		.max_i2s_channels = 2, +	}; +	int i; + +	for (i = 0; i < ARRAY_SIZE(priv->audio_port); i++) { +		if (priv->audio_port[i].format == AFMT_I2S && +		    priv->audio_port[i].config != 0) +			codec_data.i2s = 1; +		if (priv->audio_port[i].format == AFMT_SPDIF && +		    priv->audio_port[i].config != 0) +			codec_data.spdif = 1;  	} -	priv->dpms = mode; +	priv->audio_pdev = platform_device_register_data( +		dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO, +		&codec_data, sizeof(codec_data)); + +	return PTR_ERR_OR_ZERO(priv->audio_pdev); +} + +/* DRM connector functions */ + +static int tda998x_connector_dpms(struct drm_connector *connector, int mode) +{ +	if (drm_core_check_feature(connector->dev, DRIVER_ATOMIC)) +		return drm_atomic_helper_connector_dpms(connector, mode); +	else +		return drm_helper_connector_dpms(connector, mode); +} + +static int tda998x_connector_fill_modes(struct drm_connector *connector, +					uint32_t maxX, uint32_t maxY) +{ +	struct tda998x_priv *priv = conn_to_tda998x_priv(connector); +	int ret; + +	mutex_lock(&priv->audio_mutex); +	ret = drm_helper_probe_single_connector_modes(connector, maxX, maxY); + +	if (connector->edid_blob_ptr) { +		struct edid *edid = (void *)connector->edid_blob_ptr->data; + +		priv->sink_has_audio = drm_detect_monitor_audio(edid); +	} else { +		priv->sink_has_audio = false; +	} +	mutex_unlock(&priv->audio_mutex); + +	return ret; +} + +static enum drm_connector_status +tda998x_connector_detect(struct drm_connector *connector, bool force) +{ +	struct tda998x_priv *priv = conn_to_tda998x_priv(connector); +	u8 val = cec_read(priv, REG_CEC_RXSHPDLEV); + +	return (val & CEC_RXSHPDLEV_HPD) ? connector_status_connected : +			connector_status_disconnected; +} + +static void tda998x_connector_destroy(struct drm_connector *connector) +{ +	drm_connector_cleanup(connector); +} + +static const struct drm_connector_funcs tda998x_connector_funcs = { +	.dpms = tda998x_connector_dpms, +	.reset = drm_atomic_helper_connector_reset, +	.fill_modes = tda998x_connector_fill_modes, +	.detect = tda998x_connector_detect, +	.destroy = tda998x_connector_destroy, +	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, +	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static int read_edid_block(void *data, u8 *buf, unsigned int blk, size_t length) +{ +	struct tda998x_priv *priv = data; +	u8 offset, segptr; +	int ret, i; + +	offset = (blk & 1) ? 128 : 0; +	segptr = blk / 2; + +	reg_write(priv, REG_DDC_ADDR, 0xa0); +	reg_write(priv, REG_DDC_OFFS, offset); +	reg_write(priv, REG_DDC_SEGM_ADDR, 0x60); +	reg_write(priv, REG_DDC_SEGM, segptr); + +	/* enable reading EDID: */ +	priv->wq_edid_wait = 1; +	reg_write(priv, REG_EDID_CTRL, 0x1); + +	/* flag must be cleared by sw: */ +	reg_write(priv, REG_EDID_CTRL, 0x0); + +	/* wait for block read to complete: */ +	if (priv->hdmi->irq) { +		i = wait_event_timeout(priv->wq_edid, +					!priv->wq_edid_wait, +					msecs_to_jiffies(100)); +		if (i < 0) { +			dev_err(&priv->hdmi->dev, "read edid wait err %d\n", i); +			return i; +		} +	} else { +		for (i = 100; i > 0; i--) { +			msleep(1); +			ret = reg_read(priv, REG_INT_FLAGS_2); +			if (ret < 0) +				return ret; +			if (ret & INT_FLAGS_2_EDID_BLK_RD) +				break; +		} +	} + +	if (i == 0) { +		dev_err(&priv->hdmi->dev, "read edid timeout\n"); +		return -ETIMEDOUT; +	} + +	ret = reg_read_range(priv, REG_EDID_DATA_0, buf, length); +	if (ret != length) { +		dev_err(&priv->hdmi->dev, "failed to read edid block %d: %d\n", +			blk, ret); +		return ret; +	} + +	return 0; +} + +static int tda998x_connector_get_modes(struct drm_connector *connector) +{ +	struct tda998x_priv *priv = conn_to_tda998x_priv(connector); +	struct edid *edid; +	int n; + +	/* +	 * If we get killed while waiting for the HPD timeout, return +	 * no modes found: we are not in a restartable path, so we +	 * can't handle signals gracefully. +	 */ +	if (tda998x_edid_delay_wait(priv)) +		return 0; + +	if (priv->rev == TDA19988) +		reg_clear(priv, REG_TX4, TX4_PD_RAM); + +	edid = drm_do_get_edid(connector, read_edid_block, priv); + +	if (priv->rev == TDA19988) +		reg_set(priv, REG_TX4, TX4_PD_RAM); + +	if (!edid) { +		dev_warn(&priv->hdmi->dev, "failed to read EDID\n"); +		return 0; +	} + +	drm_mode_connector_update_edid_property(connector, edid); +	n = drm_add_edid_modes(connector, edid); +	drm_edid_to_eld(connector, edid); + +	kfree(edid); + +	return n;  }  static int tda998x_connector_mode_valid(struct drm_connector *connector, @@ -888,6 +1130,80 @@ static int tda998x_connector_mode_valid(struct drm_connector *connector,  	return MODE_OK;  } +static struct drm_encoder * +tda998x_connector_best_encoder(struct drm_connector *connector) +{ +	struct tda998x_priv *priv = conn_to_tda998x_priv(connector); + +	return &priv->encoder; +} + +static +const struct drm_connector_helper_funcs tda998x_connector_helper_funcs = { +	.get_modes = tda998x_connector_get_modes, +	.mode_valid = tda998x_connector_mode_valid, +	.best_encoder = tda998x_connector_best_encoder, +}; + +static int tda998x_connector_init(struct tda998x_priv *priv, +				  struct drm_device *drm) +{ +	struct drm_connector *connector = &priv->connector; +	int ret; + +	connector->interlace_allowed = 1; + +	if (priv->hdmi->irq) +		connector->polled = DRM_CONNECTOR_POLL_HPD; +	else +		connector->polled = DRM_CONNECTOR_POLL_CONNECT | +			DRM_CONNECTOR_POLL_DISCONNECT; + +	drm_connector_helper_add(connector, &tda998x_connector_helper_funcs); +	ret = drm_connector_init(drm, connector, &tda998x_connector_funcs, +				 DRM_MODE_CONNECTOR_HDMIA); +	if (ret) +		return ret; + +	drm_mode_connector_attach_encoder(&priv->connector, &priv->encoder); + +	return 0; +} + +/* DRM encoder functions */ + +static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode) +{ +	struct tda998x_priv *priv = enc_to_tda998x_priv(encoder); +	bool on; + +	/* we only care about on or off: */ +	on = mode == DRM_MODE_DPMS_ON; + +	if (on == priv->is_on) +		return; + +	if (on) { +		/* enable video ports, audio will be enabled later */ +		reg_write(priv, REG_ENA_VP_0, 0xff); +		reg_write(priv, REG_ENA_VP_1, 0xff); +		reg_write(priv, REG_ENA_VP_2, 0xff); +		/* set muxing after enabling ports: */ +		reg_write(priv, REG_VIP_CNTRL_0, priv->vip_cntrl_0); +		reg_write(priv, REG_VIP_CNTRL_1, priv->vip_cntrl_1); +		reg_write(priv, REG_VIP_CNTRL_2, priv->vip_cntrl_2); + +		priv->is_on = true; +	} else { +		/* disable video ports */ +		reg_write(priv, REG_ENA_VP_0, 0x00); +		reg_write(priv, REG_ENA_VP_1, 0x00); +		reg_write(priv, REG_ENA_VP_2, 0x00); + +		priv->is_on = false; +	} +} +  static void  tda998x_encoder_mode_set(struct drm_encoder *encoder,  			 struct drm_display_mode *mode, @@ -971,6 +1287,8 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder,  			div = 3;  	} +	mutex_lock(&priv->audio_mutex); +  	/* mute the audio FIFO: */  	reg_set(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO); @@ -982,6 +1300,7 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder,  	/* no pre-filter or interpolator: */  	reg_write(priv, REG_HVF_CNTRL_0, HVF_CNTRL_0_PREFIL(0) |  			HVF_CNTRL_0_INTPOL(0)); +	reg_set(priv, REG_FEAT_POWERDOWN, FEAT_POWERDOWN_PREFILT);  	reg_write(priv, REG_VIP_CNTRL_5, VIP_CNTRL_5_SP_CNT(0));  	reg_write(priv, REG_VIP_CNTRL_4, VIP_CNTRL_4_BLANKIT(0) |  			VIP_CNTRL_4_BLC(0)); @@ -1004,6 +1323,7 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder,  	/* set color matrix bypass flag: */  	reg_write(priv, REG_MAT_CONTRL, MAT_CONTRL_MAT_BP |  				MAT_CONTRL_MAT_SC(1)); +	reg_set(priv, REG_FEAT_POWERDOWN, FEAT_POWERDOWN_CSC);  	/* set BIAS tmds value: */  	reg_write(priv, REG_ANA_GENERAL, 0x09); @@ -1064,8 +1384,22 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder,  	/* must be last register set: */  	reg_write(priv, REG_TBG_CNTRL_0, 0); -	/* Only setup the info frames if the sink is HDMI */ -	if (priv->is_hdmi_sink) { +	priv->tmds_clock = adjusted_mode->clock; + +	/* CEA-861B section 6 says that: +	 * CEA version 1 (CEA-861) has no support for infoframes. +	 * CEA version 2 (CEA-861A) supports version 1 AVI infoframes, +	 * and optional basic audio. +	 * CEA version 3 (CEA-861B) supports version 1 and 2 AVI infoframes, +	 * and optional digital audio, with audio infoframes. +	 * +	 * Since we only support generation of version 2 AVI infoframes, +	 * ignore CEA version 2 and below (iow, behave as if we're a +	 * CEA-861 source.) +	 */ +	priv->supports_infoframes = priv->connector.display_info.cea_rev >= 3; + +	if (priv->supports_infoframes) {  		/* We need to turn HDMI HDCP stuff on to get audio through */  		reg &= ~TBG_CNTRL_1_DWIN_DIS;  		reg_write(priv, REG_TBG_CNTRL_1, reg); @@ -1074,127 +1408,12 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder,  		tda998x_write_avi(priv, adjusted_mode); -		if (priv->audio_params.format != AFMT_UNUSED) { -			mutex_lock(&priv->audio_mutex); -			tda998x_configure_audio(priv, -						&priv->audio_params, -						adjusted_mode->clock); -			mutex_unlock(&priv->audio_mutex); -		} -	} -} - -static enum drm_connector_status -tda998x_connector_detect(struct drm_connector *connector, bool force) -{ -	struct tda998x_priv *priv = conn_to_tda998x_priv(connector); -	u8 val = cec_read(priv, REG_CEC_RXSHPDLEV); - -	return (val & CEC_RXSHPDLEV_HPD) ? connector_status_connected : -			connector_status_disconnected; -} - -static int read_edid_block(void *data, u8 *buf, unsigned int blk, size_t length) -{ -	struct tda998x_priv *priv = data; -	u8 offset, segptr; -	int ret, i; - -	offset = (blk & 1) ? 128 : 0; -	segptr = blk / 2; - -	reg_write(priv, REG_DDC_ADDR, 0xa0); -	reg_write(priv, REG_DDC_OFFS, offset); -	reg_write(priv, REG_DDC_SEGM_ADDR, 0x60); -	reg_write(priv, REG_DDC_SEGM, segptr); - -	/* enable reading EDID: */ -	priv->wq_edid_wait = 1; -	reg_write(priv, REG_EDID_CTRL, 0x1); - -	/* flag must be cleared by sw: */ -	reg_write(priv, REG_EDID_CTRL, 0x0); - -	/* wait for block read to complete: */ -	if (priv->hdmi->irq) { -		i = wait_event_timeout(priv->wq_edid, -					!priv->wq_edid_wait, -					msecs_to_jiffies(100)); -		if (i < 0) { -			dev_err(&priv->hdmi->dev, "read edid wait err %d\n", i); -			return i; -		} -	} else { -		for (i = 100; i > 0; i--) { -			msleep(1); -			ret = reg_read(priv, REG_INT_FLAGS_2); -			if (ret < 0) -				return ret; -			if (ret & INT_FLAGS_2_EDID_BLK_RD) -				break; -		} -	} - -	if (i == 0) { -		dev_err(&priv->hdmi->dev, "read edid timeout\n"); -		return -ETIMEDOUT; +		if (priv->audio_params.format != AFMT_UNUSED && +		    priv->sink_has_audio) +			tda998x_configure_audio(priv, &priv->audio_params);  	} -	ret = reg_read_range(priv, REG_EDID_DATA_0, buf, length); -	if (ret != length) { -		dev_err(&priv->hdmi->dev, "failed to read edid block %d: %d\n", -			blk, ret); -		return ret; -	} - -	return 0; -} - -static int tda998x_connector_get_modes(struct drm_connector *connector) -{ -	struct tda998x_priv *priv = conn_to_tda998x_priv(connector); -	struct edid *edid; -	int n; - -	/* -	 * If we get killed while waiting for the HPD timeout, return -	 * no modes found: we are not in a restartable path, so we -	 * can't handle signals gracefully. -	 */ -	if (tda998x_edid_delay_wait(priv)) -		return 0; - -	if (priv->rev == TDA19988) -		reg_clear(priv, REG_TX4, TX4_PD_RAM); - -	edid = drm_do_get_edid(connector, read_edid_block, priv); - -	if (priv->rev == TDA19988) -		reg_set(priv, REG_TX4, TX4_PD_RAM); - -	if (!edid) { -		dev_warn(&priv->hdmi->dev, "failed to read EDID\n"); -		return 0; -	} - -	drm_mode_connector_update_edid_property(connector, edid); -	n = drm_add_edid_modes(connector, edid); -	priv->is_hdmi_sink = drm_detect_hdmi_monitor(edid); -	drm_edid_to_eld(connector, edid); - -	kfree(edid); - -	return n; -} - -static void tda998x_encoder_set_polling(struct tda998x_priv *priv, -					struct drm_connector *connector) -{ -	if (priv->hdmi->irq) -		connector->polled = DRM_CONNECTOR_POLL_HPD; -	else -		connector->polled = DRM_CONNECTOR_POLL_CONNECT | -			DRM_CONNECTOR_POLL_DISCONNECT; +	mutex_unlock(&priv->audio_mutex);  }  static void tda998x_destroy(struct tda998x_priv *priv) @@ -1215,145 +1434,6 @@ static void tda998x_destroy(struct tda998x_priv *priv)  	i2c_unregister_device(priv->cec);  } -static int tda998x_audio_hw_params(struct device *dev, void *data, -				   struct hdmi_codec_daifmt *daifmt, -				   struct hdmi_codec_params *params) -{ -	struct tda998x_priv *priv = dev_get_drvdata(dev); -	int i, ret; -	struct tda998x_audio_params audio = { -		.sample_width = params->sample_width, -		.sample_rate = params->sample_rate, -		.cea = params->cea, -	}; - -	if (!priv->encoder.crtc) -		return -ENODEV; - -	memcpy(audio.status, params->iec.status, -	       min(sizeof(audio.status), sizeof(params->iec.status))); - -	switch (daifmt->fmt) { -	case HDMI_I2S: -		if (daifmt->bit_clk_inv || daifmt->frame_clk_inv || -		    daifmt->bit_clk_master || daifmt->frame_clk_master) { -			dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__, -				daifmt->bit_clk_inv, daifmt->frame_clk_inv, -				daifmt->bit_clk_master, -				daifmt->frame_clk_master); -			return -EINVAL; -		} -		for (i = 0; i < ARRAY_SIZE(priv->audio_port); i++) -			if (priv->audio_port[i].format == AFMT_I2S) -				audio.config = priv->audio_port[i].config; -		audio.format = AFMT_I2S; -		break; -	case HDMI_SPDIF: -		for (i = 0; i < ARRAY_SIZE(priv->audio_port); i++) -			if (priv->audio_port[i].format == AFMT_SPDIF) -				audio.config = priv->audio_port[i].config; -		audio.format = AFMT_SPDIF; -		break; -	default: -		dev_err(dev, "%s: Invalid format %d\n", __func__, daifmt->fmt); -		return -EINVAL; -	} - -	if (audio.config == 0) { -		dev_err(dev, "%s: No audio configutation found\n", __func__); -		return -EINVAL; -	} - -	mutex_lock(&priv->audio_mutex); -	ret = tda998x_configure_audio(priv, -				      &audio, -				      priv->encoder.crtc->hwmode.clock); - -	if (ret == 0) -		priv->audio_params = audio; -	mutex_unlock(&priv->audio_mutex); - -	return ret; -} - -static void tda998x_audio_shutdown(struct device *dev, void *data) -{ -	struct tda998x_priv *priv = dev_get_drvdata(dev); - -	mutex_lock(&priv->audio_mutex); - -	reg_write(priv, REG_ENA_AP, 0); - -	priv->audio_params.format = AFMT_UNUSED; - -	mutex_unlock(&priv->audio_mutex); -} - -int tda998x_audio_digital_mute(struct device *dev, void *data, bool enable) -{ -	struct tda998x_priv *priv = dev_get_drvdata(dev); - -	mutex_lock(&priv->audio_mutex); - -	tda998x_audio_mute(priv, enable); - -	mutex_unlock(&priv->audio_mutex); -	return 0; -} - -static int tda998x_audio_get_eld(struct device *dev, void *data, -				 uint8_t *buf, size_t len) -{ -	struct tda998x_priv *priv = dev_get_drvdata(dev); -	struct drm_mode_config *config = &priv->encoder.dev->mode_config; -	struct drm_connector *connector; -	int ret = -ENODEV; - -	mutex_lock(&config->mutex); -	list_for_each_entry(connector, &config->connector_list, head) { -		if (&priv->encoder == connector->encoder) { -			memcpy(buf, connector->eld, -			       min(sizeof(connector->eld), len)); -			ret = 0; -		} -	} -	mutex_unlock(&config->mutex); - -	return ret; -} - -static const struct hdmi_codec_ops audio_codec_ops = { -	.hw_params = tda998x_audio_hw_params, -	.audio_shutdown = tda998x_audio_shutdown, -	.digital_mute = tda998x_audio_digital_mute, -	.get_eld = tda998x_audio_get_eld, -}; - -static int tda998x_audio_codec_init(struct tda998x_priv *priv, -				    struct device *dev) -{ -	struct hdmi_codec_pdata codec_data = { -		.ops = &audio_codec_ops, -		.max_i2s_channels = 2, -	}; -	int i; - -	for (i = 0; i < ARRAY_SIZE(priv->audio_port); i++) { -		if (priv->audio_port[i].format == AFMT_I2S && -		    priv->audio_port[i].config != 0) -			codec_data.i2s = 1; -		if (priv->audio_port[i].format == AFMT_SPDIF && -		    priv->audio_port[i].config != 0) -			codec_data.spdif = 1; -	} - -	priv->audio_pdev = platform_device_register_data( -		dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO, -		&codec_data, sizeof(codec_data)); - -	return PTR_ERR_OR_ZERO(priv->audio_pdev); -} -  /* I2C driver functions */  static int tda998x_get_audio_ports(struct tda998x_priv *priv, @@ -1403,22 +1483,21 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv)  	struct device_node *np = client->dev.of_node;  	u32 video;  	int rev_lo, rev_hi, ret; -	unsigned short cec_addr; + +	mutex_init(&priv->audio_mutex); /* Protect access from audio thread */  	priv->vip_cntrl_0 = VIP_CNTRL_0_SWAP_A(2) | VIP_CNTRL_0_SWAP_B(3);  	priv->vip_cntrl_1 = VIP_CNTRL_1_SWAP_C(0) | VIP_CNTRL_1_SWAP_D(1);  	priv->vip_cntrl_2 = VIP_CNTRL_2_SWAP_E(4) | VIP_CNTRL_2_SWAP_F(5); +	/* CEC I2C address bound to TDA998x I2C addr by configuration pins */ +	priv->cec_addr = 0x34 + (client->addr & 0x03);  	priv->current_page = 0xff;  	priv->hdmi = client; -	/* CEC I2C address bound to TDA998x I2C addr by configuration pins */ -	cec_addr = 0x34 + (client->addr & 0x03); -	priv->cec = i2c_new_dummy(client->adapter, cec_addr); +	priv->cec = i2c_new_dummy(client->adapter, priv->cec_addr);  	if (!priv->cec)  		return -ENODEV; -	priv->dpms = DRM_MODE_DPMS_OFF; -  	mutex_init(&priv->mutex);	/* protect the page access */  	init_waitqueue_head(&priv->edid_delay_waitq);  	setup_timer(&priv->edid_delay_timer, tda998x_edid_delay_done, @@ -1478,7 +1557,7 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv)  	/* initialize the optional IRQ */  	if (client->irq) { -		int irqf_trigger; +		unsigned long irq_flags;  		/* init read EDID waitqueue and HDP work */  		init_waitqueue_head(&priv->wq_edid); @@ -1488,11 +1567,11 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv)  		reg_read(priv, REG_INT_FLAGS_1);  		reg_read(priv, REG_INT_FLAGS_2); -		irqf_trigger = +		irq_flags =  			irqd_get_trigger_type(irq_get_irq_data(client->irq)); +		irq_flags |= IRQF_SHARED | IRQF_ONESHOT;  		ret = request_threaded_irq(client->irq, NULL, -					   tda998x_irq_thread, -					   irqf_trigger | IRQF_ONESHOT, +					   tda998x_irq_thread, irq_flags,  					   "tda998x", priv);  		if (ret) {  			dev_err(&client->dev, @@ -1519,8 +1598,6 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv)  		priv->vip_cntrl_2 = video;  	} -	mutex_init(&priv->audio_mutex); /* Protect access from audio thread */ -  	ret = tda998x_get_audio_ports(priv, np);  	if (ret)  		goto fail; @@ -1567,45 +1644,25 @@ static const struct drm_encoder_funcs tda998x_encoder_funcs = {  	.destroy = tda998x_encoder_destroy,  }; -static struct drm_encoder * -tda998x_connector_best_encoder(struct drm_connector *connector) -{ -	struct tda998x_priv *priv = conn_to_tda998x_priv(connector); - -	return &priv->encoder; -} - -static -const struct drm_connector_helper_funcs tda998x_connector_helper_funcs = { -	.get_modes = tda998x_connector_get_modes, -	.mode_valid = tda998x_connector_mode_valid, -	.best_encoder = tda998x_connector_best_encoder, -}; - -static void tda998x_connector_destroy(struct drm_connector *connector) +static void tda998x_set_config(struct tda998x_priv *priv, +			       const struct tda998x_encoder_params *p)  { -	drm_connector_unregister(connector); -	drm_connector_cleanup(connector); -} +	priv->vip_cntrl_0 = VIP_CNTRL_0_SWAP_A(p->swap_a) | +			    (p->mirr_a ? VIP_CNTRL_0_MIRR_A : 0) | +			    VIP_CNTRL_0_SWAP_B(p->swap_b) | +			    (p->mirr_b ? VIP_CNTRL_0_MIRR_B : 0); +	priv->vip_cntrl_1 = VIP_CNTRL_1_SWAP_C(p->swap_c) | +			    (p->mirr_c ? VIP_CNTRL_1_MIRR_C : 0) | +			    VIP_CNTRL_1_SWAP_D(p->swap_d) | +			    (p->mirr_d ? VIP_CNTRL_1_MIRR_D : 0); +	priv->vip_cntrl_2 = VIP_CNTRL_2_SWAP_E(p->swap_e) | +			    (p->mirr_e ? VIP_CNTRL_2_MIRR_E : 0) | +			    VIP_CNTRL_2_SWAP_F(p->swap_f) | +			    (p->mirr_f ? VIP_CNTRL_2_MIRR_F : 0); -static int tda998x_connector_dpms(struct drm_connector *connector, int mode) -{ -	if (drm_core_check_feature(connector->dev, DRIVER_ATOMIC)) -		return drm_atomic_helper_connector_dpms(connector, mode); -	else -		return drm_helper_connector_dpms(connector, mode); +	priv->audio_params = p->audio_params;  } -static const struct drm_connector_funcs tda998x_connector_funcs = { -	.dpms = tda998x_connector_dpms, -	.reset = drm_atomic_helper_connector_reset, -	.fill_modes = drm_helper_probe_single_connector_modes, -	.detect = tda998x_connector_detect, -	.destroy = tda998x_connector_destroy, -	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, -	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; -  static int tda998x_bind(struct device *dev, struct device *master, void *data)  {  	struct tda998x_encoder_params *params = dev->platform_data; @@ -1630,7 +1687,6 @@ static int tda998x_bind(struct device *dev, struct device *master, void *data)  		crtcs = 1 << 0;  	} -	priv->connector.interlace_allowed = 1;  	priv->encoder.possible_crtcs = crtcs;  	ret = tda998x_create(client, priv); @@ -1638,9 +1694,7 @@ static int tda998x_bind(struct device *dev, struct device *master, void *data)  		return ret;  	if (!dev->of_node && params) -		tda998x_encoder_set_config(priv, params); - -	tda998x_encoder_set_polling(priv, &priv->connector); +		tda998x_set_config(priv, params);  	drm_encoder_helper_add(&priv->encoder, &tda998x_encoder_helper_funcs);  	ret = drm_encoder_init(drm, &priv->encoder, &tda998x_encoder_funcs, @@ -1648,24 +1702,12 @@ static int tda998x_bind(struct device *dev, struct device *master, void *data)  	if (ret)  		goto err_encoder; -	drm_connector_helper_add(&priv->connector, -				 &tda998x_connector_helper_funcs); -	ret = drm_connector_init(drm, &priv->connector, -				 &tda998x_connector_funcs, -				 DRM_MODE_CONNECTOR_HDMIA); +	ret = tda998x_connector_init(priv, drm);  	if (ret)  		goto err_connector; -	ret = drm_connector_register(&priv->connector); -	if (ret) -		goto err_sysfs; - -	drm_mode_connector_attach_encoder(&priv->connector, &priv->encoder); -  	return 0; -err_sysfs: -	drm_connector_cleanup(&priv->connector);  err_connector:  	drm_encoder_cleanup(&priv->encoder);  err_encoder: @@ -1678,7 +1720,6 @@ static void tda998x_unbind(struct device *dev, struct device *master,  {  	struct tda998x_priv *priv = dev_get_drvdata(dev); -	drm_connector_unregister(&priv->connector);  	drm_connector_cleanup(&priv->connector);  	drm_encoder_cleanup(&priv->encoder);  	tda998x_destroy(priv); @@ -1692,6 +1733,10 @@ static const struct component_ops tda998x_ops = {  static int  tda998x_probe(struct i2c_client *client, const struct i2c_device_id *id)  { +	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { +		dev_warn(&client->dev, "adapter does not support I2C\n"); +		return -EIO; +	}  	return component_add(&client->dev, &tda998x_ops);  }  |