|
@@ -141,8 +141,12 @@ struct dw_hdmi {
|
|
u8 edid[HDMI_EDID_LEN];
|
|
u8 edid[HDMI_EDID_LEN];
|
|
bool cable_plugin;
|
|
bool cable_plugin;
|
|
|
|
|
|
- const struct dw_hdmi_phy_data *phy;
|
|
|
|
- bool phy_enabled;
|
|
|
|
|
|
+ struct {
|
|
|
|
+ const struct dw_hdmi_phy_ops *ops;
|
|
|
|
+ const char *name;
|
|
|
|
+ void *data;
|
|
|
|
+ bool enabled;
|
|
|
|
+ } phy;
|
|
|
|
|
|
struct drm_display_mode previous_mode;
|
|
struct drm_display_mode previous_mode;
|
|
|
|
|
|
@@ -831,6 +835,10 @@ static void hdmi_video_packetize(struct dw_hdmi *hdmi)
|
|
HDMI_VP_CONF);
|
|
HDMI_VP_CONF);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/* -----------------------------------------------------------------------------
|
|
|
|
+ * Synopsys PHY Handling
|
|
|
|
+ */
|
|
|
|
+
|
|
static inline void hdmi_phy_test_clear(struct dw_hdmi *hdmi,
|
|
static inline void hdmi_phy_test_clear(struct dw_hdmi *hdmi,
|
|
unsigned char bit)
|
|
unsigned char bit)
|
|
{
|
|
{
|
|
@@ -917,7 +925,7 @@ static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
|
|
|
|
|
|
static void dw_hdmi_phy_power_off(struct dw_hdmi *hdmi)
|
|
static void dw_hdmi_phy_power_off(struct dw_hdmi *hdmi)
|
|
{
|
|
{
|
|
- const struct dw_hdmi_phy_data *phy = hdmi->phy;
|
|
|
|
|
|
+ const struct dw_hdmi_phy_data *phy = hdmi->phy.data;
|
|
unsigned int i;
|
|
unsigned int i;
|
|
u16 val;
|
|
u16 val;
|
|
|
|
|
|
@@ -951,7 +959,7 @@ static void dw_hdmi_phy_power_off(struct dw_hdmi *hdmi)
|
|
|
|
|
|
static int dw_hdmi_phy_power_on(struct dw_hdmi *hdmi)
|
|
static int dw_hdmi_phy_power_on(struct dw_hdmi *hdmi)
|
|
{
|
|
{
|
|
- const struct dw_hdmi_phy_data *phy = hdmi->phy;
|
|
|
|
|
|
+ const struct dw_hdmi_phy_data *phy = hdmi->phy.data;
|
|
unsigned int i;
|
|
unsigned int i;
|
|
u8 val;
|
|
u8 val;
|
|
|
|
|
|
@@ -987,6 +995,7 @@ static int dw_hdmi_phy_power_on(struct dw_hdmi *hdmi)
|
|
|
|
|
|
static int hdmi_phy_configure(struct dw_hdmi *hdmi)
|
|
static int hdmi_phy_configure(struct dw_hdmi *hdmi)
|
|
{
|
|
{
|
|
|
|
+ const struct dw_hdmi_phy_data *phy = hdmi->phy.data;
|
|
const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
|
|
const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
|
|
const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg;
|
|
const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg;
|
|
const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr;
|
|
const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr;
|
|
@@ -1019,7 +1028,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
|
|
dw_hdmi_phy_power_off(hdmi);
|
|
dw_hdmi_phy_power_off(hdmi);
|
|
|
|
|
|
/* Leave low power consumption mode by asserting SVSRET. */
|
|
/* Leave low power consumption mode by asserting SVSRET. */
|
|
- if (hdmi->phy->has_svsret)
|
|
|
|
|
|
+ if (phy->has_svsret)
|
|
dw_hdmi_phy_enable_svsret(hdmi, 1);
|
|
dw_hdmi_phy_enable_svsret(hdmi, 1);
|
|
|
|
|
|
/* PHY reset. The reset signal is active high on Gen2 PHYs. */
|
|
/* PHY reset. The reset signal is active high on Gen2 PHYs. */
|
|
@@ -1057,7 +1066,8 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
|
|
return dw_hdmi_phy_power_on(hdmi);
|
|
return dw_hdmi_phy_power_on(hdmi);
|
|
}
|
|
}
|
|
|
|
|
|
-static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
|
|
|
|
|
|
+static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
|
|
|
|
+ struct drm_display_mode *mode)
|
|
{
|
|
{
|
|
int i, ret;
|
|
int i, ret;
|
|
|
|
|
|
@@ -1071,10 +1081,31 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
- hdmi->phy_enabled = true;
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data)
|
|
|
|
+{
|
|
|
|
+ dw_hdmi_phy_power_off(hdmi);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi,
|
|
|
|
+ void *data)
|
|
|
|
+{
|
|
|
|
+ return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
|
|
|
|
+ connector_status_connected : connector_status_disconnected;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static const struct dw_hdmi_phy_ops dw_hdmi_synopsys_phy_ops = {
|
|
|
|
+ .init = dw_hdmi_phy_init,
|
|
|
|
+ .disable = dw_hdmi_phy_disable,
|
|
|
|
+ .read_hpd = dw_hdmi_phy_read_hpd,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/* -----------------------------------------------------------------------------
|
|
|
|
+ * HDMI TX Setup
|
|
|
|
+ */
|
|
|
|
+
|
|
static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi)
|
|
static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi)
|
|
{
|
|
{
|
|
u8 de;
|
|
u8 de;
|
|
@@ -1289,16 +1320,6 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
|
|
hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
|
|
hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
|
|
}
|
|
}
|
|
|
|
|
|
-static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi)
|
|
|
|
-{
|
|
|
|
- if (!hdmi->phy_enabled)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- dw_hdmi_phy_power_off(hdmi);
|
|
|
|
-
|
|
|
|
- hdmi->phy_enabled = false;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/* HDMI Initialization Step B.4 */
|
|
/* HDMI Initialization Step B.4 */
|
|
static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
|
|
static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
|
|
{
|
|
{
|
|
@@ -1431,9 +1452,10 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
|
|
hdmi_av_composer(hdmi, mode);
|
|
hdmi_av_composer(hdmi, mode);
|
|
|
|
|
|
/* HDMI Initializateion Step B.2 */
|
|
/* HDMI Initializateion Step B.2 */
|
|
- ret = dw_hdmi_phy_init(hdmi);
|
|
|
|
|
|
+ ret = hdmi->phy.ops->init(hdmi, hdmi->phy.data, &hdmi->previous_mode);
|
|
if (ret)
|
|
if (ret)
|
|
return ret;
|
|
return ret;
|
|
|
|
+ hdmi->phy.enabled = true;
|
|
|
|
|
|
/* HDMI Initialization Step B.3 */
|
|
/* HDMI Initialization Step B.3 */
|
|
dw_hdmi_enable_video_path(hdmi);
|
|
dw_hdmi_enable_video_path(hdmi);
|
|
@@ -1548,7 +1570,11 @@ static void dw_hdmi_poweron(struct dw_hdmi *hdmi)
|
|
|
|
|
|
static void dw_hdmi_poweroff(struct dw_hdmi *hdmi)
|
|
static void dw_hdmi_poweroff(struct dw_hdmi *hdmi)
|
|
{
|
|
{
|
|
- dw_hdmi_phy_disable(hdmi);
|
|
|
|
|
|
+ if (hdmi->phy.enabled) {
|
|
|
|
+ hdmi->phy.ops->disable(hdmi, hdmi->phy.data);
|
|
|
|
+ hdmi->phy.enabled = false;
|
|
|
|
+ }
|
|
|
|
+
|
|
hdmi->bridge_is_on = false;
|
|
hdmi->bridge_is_on = false;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1611,8 +1637,7 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
|
dw_hdmi_update_phy_mask(hdmi);
|
|
dw_hdmi_update_phy_mask(hdmi);
|
|
mutex_unlock(&hdmi->mutex);
|
|
mutex_unlock(&hdmi->mutex);
|
|
|
|
|
|
- return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
|
|
|
|
- connector_status_connected : connector_status_disconnected;
|
|
|
|
|
|
+ return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data);
|
|
}
|
|
}
|
|
|
|
|
|
static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
|
|
static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
|
|
@@ -1898,19 +1923,31 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
|
|
|
|
|
|
phy_type = hdmi_readb(hdmi, HDMI_CONFIG2_ID);
|
|
phy_type = hdmi_readb(hdmi, HDMI_CONFIG2_ID);
|
|
|
|
|
|
|
|
+ if (phy_type == DW_HDMI_PHY_VENDOR_PHY) {
|
|
|
|
+ /* Vendor PHYs require support from the glue layer. */
|
|
|
|
+ if (!hdmi->plat_data->phy_ops || !hdmi->plat_data->phy_name) {
|
|
|
|
+ dev_err(hdmi->dev,
|
|
|
|
+ "Vendor HDMI PHY not supported by glue layer\n");
|
|
|
|
+ return -ENODEV;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ hdmi->phy.ops = hdmi->plat_data->phy_ops;
|
|
|
|
+ hdmi->phy.data = hdmi->plat_data->phy_data;
|
|
|
|
+ hdmi->phy.name = hdmi->plat_data->phy_name;
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Synopsys PHYs are handled internally. */
|
|
for (i = 0; i < ARRAY_SIZE(dw_hdmi_phys); ++i) {
|
|
for (i = 0; i < ARRAY_SIZE(dw_hdmi_phys); ++i) {
|
|
if (dw_hdmi_phys[i].type == phy_type) {
|
|
if (dw_hdmi_phys[i].type == phy_type) {
|
|
- hdmi->phy = &dw_hdmi_phys[i];
|
|
|
|
|
|
+ hdmi->phy.ops = &dw_hdmi_synopsys_phy_ops;
|
|
|
|
+ hdmi->phy.name = dw_hdmi_phys[i].name;
|
|
|
|
+ hdmi->phy.data = (void *)&dw_hdmi_phys[i];
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- if (phy_type == DW_HDMI_PHY_VENDOR_PHY)
|
|
|
|
- dev_err(hdmi->dev, "Unsupported vendor HDMI PHY\n");
|
|
|
|
- else
|
|
|
|
- dev_err(hdmi->dev, "Unsupported HDMI PHY type (%02x)\n",
|
|
|
|
- phy_type);
|
|
|
|
-
|
|
|
|
|
|
+ dev_err(hdmi->dev, "Unsupported HDMI PHY type (%02x)\n", phy_type);
|
|
return -ENODEV;
|
|
return -ENODEV;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2031,7 +2068,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
|
|
dev_info(dev, "Detected HDMI TX controller v%x.%03x %s HDCP (%s)\n",
|
|
dev_info(dev, "Detected HDMI TX controller v%x.%03x %s HDCP (%s)\n",
|
|
hdmi->version >> 12, hdmi->version & 0xfff,
|
|
hdmi->version >> 12, hdmi->version & 0xfff,
|
|
prod_id1 & HDMI_PRODUCT_ID1_HDCP ? "with" : "without",
|
|
prod_id1 & HDMI_PRODUCT_ID1_HDCP ? "with" : "without",
|
|
- hdmi->phy->name);
|
|
|
|
|
|
+ hdmi->phy.name);
|
|
|
|
|
|
initialize_hdmi_ih_mutes(hdmi);
|
|
initialize_hdmi_ih_mutes(hdmi);
|
|
|
|
|