aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/sti/sti_hdmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/sti/sti_hdmi.c')
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi.c257
1 files changed, 108 insertions, 149 deletions
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
index 376b0763c874..ce2dcba679d5 100644
--- a/drivers/gpu/drm/sti/sti_hdmi.c
+++ b/drivers/gpu/drm/sti/sti_hdmi.c
@@ -95,7 +95,6 @@
#define HDMI_CFG_HDCP_EN BIT(2)
#define HDMI_CFG_ESS_NOT_OESS BIT(3)
#define HDMI_CFG_H_SYNC_POL_NEG BIT(4)
-#define HDMI_CFG_SINK_TERM_DET_EN BIT(5)
#define HDMI_CFG_V_SYNC_POL_NEG BIT(6)
#define HDMI_CFG_422_EN BIT(8)
#define HDMI_CFG_FIFO_OVERRUN_CLR BIT(12)
@@ -159,7 +158,6 @@ struct sti_hdmi_connector {
struct drm_encoder *encoder;
struct sti_hdmi *hdmi;
struct drm_property *colorspace_property;
- struct drm_property *hdmi_mode_property;
};
#define to_sti_hdmi_connector(x) \
@@ -266,12 +264,9 @@ static void hdmi_config(struct sti_hdmi *hdmi)
/* Select encryption type and the framing mode */
conf |= HDMI_CFG_ESS_NOT_OESS;
- if (hdmi->hdmi_mode == HDMI_MODE_HDMI)
+ if (hdmi->hdmi_monitor)
conf |= HDMI_CFG_HDMI_NOT_DVI;
- /* Enable sink term detection */
- conf |= HDMI_CFG_SINK_TERM_DET_EN;
-
/* Set Hsync polarity */
if (hdmi->mode.flags & DRM_MODE_FLAG_NHSYNC) {
DRM_DEBUG_DRIVER("H Sync Negative\n");
@@ -607,9 +602,6 @@ static void hdmi_dbg_cfg(struct seq_file *s, int val)
tmp = val & HDMI_CFG_ESS_NOT_OESS;
DBGFS_PRINT_STR("HDCP mode:", tmp ? "ESS enable" : "OESS enable");
seq_puts(s, "\t\t\t\t\t");
- tmp = val & HDMI_CFG_SINK_TERM_DET_EN;
- DBGFS_PRINT_STR("Sink term detection:", tmp ? "enable" : "disable");
- seq_puts(s, "\t\t\t\t\t");
tmp = val & HDMI_CFG_H_SYNC_POL_NEG;
DBGFS_PRINT_STR("Hsync polarity:", tmp ? "inverted" : "normal");
seq_puts(s, "\t\t\t\t\t");
@@ -731,13 +723,6 @@ static struct drm_info_list hdmi_debugfs_files[] = {
{ "hdmi", hdmi_dbg_show, 0, NULL },
};
-static void hdmi_debugfs_exit(struct sti_hdmi *hdmi, struct drm_minor *minor)
-{
- drm_debugfs_remove_files(hdmi_debugfs_files,
- ARRAY_SIZE(hdmi_debugfs_files),
- minor);
-}
-
static int hdmi_debugfs_init(struct sti_hdmi *hdmi, struct drm_minor *minor)
{
unsigned int i;
@@ -788,6 +773,95 @@ static void sti_hdmi_disable(struct drm_bridge *bridge)
hdmi->enabled = false;
}
+/**
+ * sti_hdmi_audio_get_non_coherent_n() - get N parameter for non-coherent
+ * clocks. None-coherent clocks means that audio and TMDS clocks have not the
+ * same source (drifts between clocks). In this case assumption is that CTS is
+ * automatically calculated by hardware.
+ *
+ * @audio_fs: audio frame clock frequency in Hz
+ *
+ * Values computed are based on table described in HDMI specification 1.4b
+ *
+ * Returns n value.
+ */
+static int sti_hdmi_audio_get_non_coherent_n(unsigned int audio_fs)
+{
+ unsigned int n;
+
+ switch (audio_fs) {
+ case 32000:
+ n = 4096;
+ break;
+ case 44100:
+ n = 6272;
+ break;
+ case 48000:
+ n = 6144;
+ break;
+ case 88200:
+ n = 6272 * 2;
+ break;
+ case 96000:
+ n = 6144 * 2;
+ break;
+ case 176400:
+ n = 6272 * 4;
+ break;
+ case 192000:
+ n = 6144 * 4;
+ break;
+ default:
+ /* Not pre-defined, recommended value: 128 * fs / 1000 */
+ n = (audio_fs * 128) / 1000;
+ }
+
+ return n;
+}
+
+static int hdmi_audio_configure(struct sti_hdmi *hdmi)
+{
+ int audio_cfg, n;
+ struct hdmi_audio_params *params = &hdmi->audio;
+ struct hdmi_audio_infoframe *info = &params->cea;
+
+ DRM_DEBUG_DRIVER("\n");
+
+ if (!hdmi->enabled)
+ return 0;
+
+ /* update N parameter */
+ n = sti_hdmi_audio_get_non_coherent_n(params->sample_rate);
+
+ DRM_DEBUG_DRIVER("Audio rate = %d Hz, TMDS clock = %d Hz, n = %d\n",
+ params->sample_rate, hdmi->mode.clock * 1000, n);
+ hdmi_write(hdmi, n, HDMI_AUDN);
+
+ /* update HDMI registers according to configuration */
+ audio_cfg = HDMI_AUD_CFG_SPDIF_DIV_2 | HDMI_AUD_CFG_DTS_INVALID |
+ HDMI_AUD_CFG_ONE_BIT_INVALID;
+
+ switch (info->channels) {
+ case 8:
+ audio_cfg |= HDMI_AUD_CFG_CH78_VALID;
+ case 6:
+ audio_cfg |= HDMI_AUD_CFG_CH56_VALID;
+ case 4:
+ audio_cfg |= HDMI_AUD_CFG_CH34_VALID | HDMI_AUD_CFG_8CH;
+ case 2:
+ audio_cfg |= HDMI_AUD_CFG_CH12_VALID;
+ break;
+ default:
+ DRM_ERROR("ERROR: Unsupported number of channels (%d)!\n",
+ info->channels);
+ return -EINVAL;
+ }
+
+ hdmi_write(hdmi, audio_cfg, HDMI_AUDIO_CFG);
+
+ return hdmi_audio_infoframe_config(hdmi);
+}
+
static void sti_hdmi_pre_enable(struct drm_bridge *bridge)
{
struct sti_hdmi *hdmi = bridge->driver_private;
@@ -826,9 +900,12 @@ static void sti_hdmi_pre_enable(struct drm_bridge *bridge)
if (hdmi_avi_infoframe_config(hdmi))
DRM_ERROR("Unable to configure AVI infoframe\n");
- /* Program AUDIO infoframe */
- if (hdmi_audio_infoframe_config(hdmi))
- DRM_ERROR("Unable to configure AUDIO infoframe\n");
+ if (hdmi->audio.enabled) {
+ if (hdmi_audio_configure(hdmi))
+ DRM_ERROR("Unable to configure audio\n");
+ } else {
+ hdmi_audio_infoframe_config(hdmi);
+ }
/* Program VS infoframe */
if (hdmi_vendor_infoframe_config(hdmi))
@@ -892,6 +969,11 @@ static int sti_hdmi_connector_get_modes(struct drm_connector *connector)
if (!edid)
goto fail;
+ hdmi->hdmi_monitor = drm_detect_hdmi_monitor(edid);
+ DRM_DEBUG_KMS("%s : %dx%d cm\n",
+ (hdmi->hdmi_monitor ? "hdmi monitor" : "dvi monitor"),
+ edid->width_cm, edid->height_cm);
+
count = drm_add_edid_modes(connector, edid);
drm_mode_connector_update_edid_property(connector, edid);
drm_edid_to_eld(connector, edid);
@@ -975,19 +1057,6 @@ static void sti_hdmi_connector_init_property(struct drm_device *drm_dev,
}
hdmi_connector->colorspace_property = prop;
drm_object_attach_property(&connector->base, prop, hdmi->colorspace);
-
- /* hdmi_mode property */
- hdmi->hdmi_mode = DEFAULT_HDMI_MODE;
- prop = drm_property_create_enum(drm_dev, 0, "hdmi_mode",
- hdmi_mode_names,
- ARRAY_SIZE(hdmi_mode_names));
- if (!prop) {
- DRM_ERROR("fails to create colorspace property\n");
- return;
- }
- hdmi_connector->hdmi_mode_property = prop;
- drm_object_attach_property(&connector->base, prop, hdmi->hdmi_mode);
-
}
static int
@@ -1005,11 +1074,6 @@ sti_hdmi_connector_set_property(struct drm_connector *connector,
return 0;
}
- if (property == hdmi_connector->hdmi_mode_property) {
- hdmi->hdmi_mode = val;
- return 0;
- }
-
DRM_ERROR("failed to set hdmi connector property\n");
return -EINVAL;
}
@@ -1029,11 +1093,6 @@ sti_hdmi_connector_get_property(struct drm_connector *connector,
return 0;
}
- if (property == hdmi_connector->hdmi_mode_property) {
- *val = hdmi->hdmi_mode;
- return 0;
- }
-
DRM_ERROR("failed to get hdmi connector property\n");
return -EINVAL;
}
@@ -1078,97 +1137,6 @@ static struct drm_encoder *sti_hdmi_find_encoder(struct drm_device *dev)
return NULL;
}
-/**
- * sti_hdmi_audio_get_non_coherent_n() - get N parameter for non-coherent
- * clocks. None-coherent clocks means that audio and TMDS clocks have not the
- * same source (drifts between clocks). In this case assumption is that CTS is
- * automatically calculated by hardware.
- *
- * @audio_fs: audio frame clock frequency in Hz
- *
- * Values computed are based on table described in HDMI specification 1.4b
- *
- * Returns n value.
- */
-static int sti_hdmi_audio_get_non_coherent_n(unsigned int audio_fs)
-{
- unsigned int n;
-
- switch (audio_fs) {
- case 32000:
- n = 4096;
- break;
- case 44100:
- n = 6272;
- break;
- case 48000:
- n = 6144;
- break;
- case 88200:
- n = 6272 * 2;
- break;
- case 96000:
- n = 6144 * 2;
- break;
- case 176400:
- n = 6272 * 4;
- break;
- case 192000:
- n = 6144 * 4;
- break;
- default:
- /* Not pre-defined, recommended value: 128 * fs / 1000 */
- n = (audio_fs * 128) / 1000;
- }
-
- return n;
-}
-
-static int hdmi_audio_configure(struct sti_hdmi *hdmi,
- struct hdmi_audio_params *params)
-{
- int audio_cfg, n;
- struct hdmi_audio_infoframe *info = &params->cea;
-
- DRM_DEBUG_DRIVER("\n");
-
- if (!hdmi->enabled)
- return 0;
-
- /* update N parameter */
- n = sti_hdmi_audio_get_non_coherent_n(params->sample_rate);
-
- DRM_DEBUG_DRIVER("Audio rate = %d Hz, TMDS clock = %d Hz, n = %d\n",
- params->sample_rate, hdmi->mode.clock * 1000, n);
- hdmi_write(hdmi, n, HDMI_AUDN);
-
- /* update HDMI registers according to configuration */
- audio_cfg = HDMI_AUD_CFG_SPDIF_DIV_2 | HDMI_AUD_CFG_DTS_INVALID |
- HDMI_AUD_CFG_ONE_BIT_INVALID;
-
- switch (info->channels) {
- case 8:
- audio_cfg |= HDMI_AUD_CFG_CH78_VALID;
- case 6:
- audio_cfg |= HDMI_AUD_CFG_CH56_VALID;
- case 4:
- audio_cfg |= HDMI_AUD_CFG_CH34_VALID | HDMI_AUD_CFG_8CH;
- case 2:
- audio_cfg |= HDMI_AUD_CFG_CH12_VALID;
- break;
- default:
- DRM_ERROR("ERROR: Unsupported number of channels (%d)!\n",
- info->channels);
- return -EINVAL;
- }
-
- hdmi_write(hdmi, audio_cfg, HDMI_AUDIO_CFG);
-
- hdmi->audio = *params;
-
- return hdmi_audio_infoframe_config(hdmi);
-}
-
static void hdmi_audio_shutdown(struct device *dev, void *data)
{
struct sti_hdmi *hdmi = dev_get_drvdata(dev);
@@ -1192,17 +1160,9 @@ static int hdmi_audio_hw_params(struct device *dev,
{
struct sti_hdmi *hdmi = dev_get_drvdata(dev);
int ret;
- struct hdmi_audio_params audio = {
- .sample_width = params->sample_width,
- .sample_rate = params->sample_rate,
- .cea = params->cea,
- };
DRM_DEBUG_DRIVER("\n");
- if (!hdmi->enabled)
- return 0;
-
if ((daifmt->fmt != HDMI_I2S) || daifmt->bit_clk_inv ||
daifmt->frame_clk_inv || daifmt->bit_clk_master ||
daifmt->frame_clk_master) {
@@ -1213,9 +1173,13 @@ static int hdmi_audio_hw_params(struct device *dev,
return -EINVAL;
}
- audio.enabled = true;
+ hdmi->audio.sample_width = params->sample_width;
+ hdmi->audio.sample_rate = params->sample_rate;
+ hdmi->audio.cea = params->cea;
+
+ hdmi->audio.enabled = true;
- ret = hdmi_audio_configure(hdmi, &audio);
+ ret = hdmi_audio_configure(hdmi);
if (ret < 0)
return ret;
@@ -1308,9 +1272,8 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
bridge->driver_private = hdmi;
bridge->funcs = &sti_hdmi_bridge_funcs;
- drm_bridge_attach(drm_dev, bridge);
+ drm_bridge_attach(encoder, bridge, NULL);
- encoder->bridge = bridge;
connector->encoder = encoder;
drm_connector = (struct drm_connector *)connector;
@@ -1360,10 +1323,6 @@ err_sysfs:
static void sti_hdmi_unbind(struct device *dev,
struct device *master, void *data)
{
- struct sti_hdmi *hdmi = dev_get_drvdata(dev);
- struct drm_device *drm_dev = data;
-
- hdmi_debugfs_exit(hdmi, drm_dev->primary);
}
static const struct component_ops sti_hdmi_ops = {