Commit 8ede2ecc authored by Kuogee Hsieh's avatar Kuogee Hsieh Committed by Rob Clark

drm/msm/dp: Add DP compliance tests on Snapdragon Chipsets

add event thread to execute events serially from event queue. Also
timeout mode is supported  which allow an event be deferred to be
executed at later time. Both link and phy compliant tests had been
done successfully.

Changes in v2:
-- Fix potential deadlock by removing redundant connect_mutex
-- Check and enable link clock during modeset
-- Drop unused code and fix function prototypes.
-- set sink power to normal operation state (D0) before DPCD read

Changes in v3:
-- push idle pattern at main link before timing generator off
-- add timeout handles for both connect and disconnect

Changes in v4:
-- add ST_SUSPEND_PENDING to handles suspend/modeset test operations
-- clear dp phy aux interrupt status when ERR_DPPHY_AUX error
-- send segment addr during edid read
-- clear bpp depth before MISC register write

Changes in v5:
-- add ST_SUSPENDED to fix crash at resume

Changes in v6:
-- at msm_dp_display_enable() do not return until resume_done to avoid
   kms commit timeout
Signed-off-by: default avatarKuogee Hsieh <khsieh@codeaurora.org>
Signed-off-by: default avatarRob Clark <robdclark@chromium.org>
parent 220b856a
......@@ -1225,6 +1225,11 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
/* wait for idle */
dpu_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE);
if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS && priv->dp) {
if (msm_dp_display_pre_disable(priv->dp, drm_enc))
DPU_ERROR_ENC(dpu_enc, "dp display push idle failed\n");
}
dpu_encoder_resource_control(drm_enc, DPU_ENC_RC_EVENT_PRE_STOP);
for (i = 0; i < dpu_enc->num_phys_encs; i++) {
......@@ -1234,6 +1239,7 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
phys->ops.disable(phys);
}
/* after phys waits for frame-done, should be no more frames pending */
if (atomic_xchg(&dpu_enc->frame_done_timeout_ms, 0)) {
DPU_ERROR("enc%d timeout pending\n", drm_enc->base.id);
......
......@@ -384,6 +384,7 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux,
PHY_AUX_CFG1);
dp_catalog_aux_reset(aux->catalog);
}
usleep_range(400, 500); /* at least 400us to next try */
goto unlock_exit;
}
......
......@@ -536,16 +536,21 @@ void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog,
* To make sure link reg writes happens before other operation,
* dp_write_link() function uses writel()
*/
dp_write_link(catalog, REG_DP_MAINLINK_CTRL,
DP_MAINLINK_FB_BOUNDARY_SEL);
dp_write_link(catalog, REG_DP_MAINLINK_CTRL,
DP_MAINLINK_FB_BOUNDARY_SEL |
DP_MAINLINK_CTRL_RESET);
dp_write_link(catalog, REG_DP_MAINLINK_CTRL,
mainlink_ctrl = dp_read_link(catalog, REG_DP_MAINLINK_CTRL);
mainlink_ctrl &= ~(DP_MAINLINK_CTRL_RESET |
DP_MAINLINK_CTRL_ENABLE);
dp_write_link(catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl);
mainlink_ctrl |= DP_MAINLINK_CTRL_RESET;
dp_write_link(catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl);
mainlink_ctrl &= ~DP_MAINLINK_CTRL_RESET;
dp_write_link(catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl);
mainlink_ctrl |= (DP_MAINLINK_CTRL_ENABLE |
DP_MAINLINK_FB_BOUNDARY_SEL);
dp_write_link(catalog, REG_DP_MAINLINK_CTRL,
DP_MAINLINK_FB_BOUNDARY_SEL |
DP_MAINLINK_CTRL_ENABLE);
dp_write_link(catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl);
} else {
mainlink_ctrl = dp_read_link(catalog, REG_DP_MAINLINK_CTRL);
mainlink_ctrl &= ~DP_MAINLINK_CTRL_ENABLE;
......@@ -644,7 +649,7 @@ int dp_catalog_ctrl_set_pattern(struct dp_catalog *dp_catalog,
bit = BIT(pattern - 1);
DRM_DEBUG_DP("hw: bit=%d train=%d\n", bit, pattern);
dp_write_link(catalog, REG_DP_STATE_CTRL, bit);
dp_catalog_ctrl_state_ctrl(dp_catalog, bit);
bit = BIT(pattern - 1) << DP_MAINLINK_READY_LINK_TRAINING_SHIFT;
......@@ -769,7 +774,7 @@ void dp_catalog_ctrl_hpd_config(struct dp_catalog *dp_catalog)
/* enable HPD interrupts */
dp_catalog_hpd_config_intr(dp_catalog,
DP_DP_HPD_PLUG_INT_MASK | DP_DP_IRQ_HPD_INT_MASK
| DP_DP_HPD_UNPLUG_INT_MASK, true);
| DP_DP_HPD_UNPLUG_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK, true);
/* Configure REFTIMER and enable it */
reftimer |= DP_DP_HPD_REFTIMER_ENABLE;
......@@ -881,15 +886,27 @@ void dp_catalog_ctrl_send_phy_pattern(struct dp_catalog *dp_catalog,
dp_write_link(catalog, REG_DP_STATE_CTRL, 0x0);
switch (pattern) {
case DP_LINK_QUAL_PATTERN_D10_2:
case DP_PHY_TEST_PATTERN_D10_2:
dp_write_link(catalog, REG_DP_STATE_CTRL,
DP_STATE_CTRL_LINK_TRAINING_PATTERN1);
return;
case DP_LINK_QUAL_PATTERN_PRBS7:
break;
case DP_PHY_TEST_PATTERN_ERROR_COUNT:
value &= ~(1 << 16);
dp_write_link(catalog, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET,
value);
value |= SCRAMBLER_RESET_COUNT_VALUE;
dp_write_link(catalog, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET,
value);
dp_write_link(catalog, REG_DP_MAINLINK_LEVELS,
DP_MAINLINK_SAFE_TO_EXIT_LEVEL_2);
dp_write_link(catalog, REG_DP_STATE_CTRL,
DP_STATE_CTRL_LINK_SYMBOL_ERR_MEASURE);
break;
case DP_PHY_TEST_PATTERN_PRBS7:
dp_write_link(catalog, REG_DP_STATE_CTRL,
DP_STATE_CTRL_LINK_PRBS7);
return;
case DP_LINK_QUAL_PATTERN_80BIT_CUSTOM:
break;
case DP_PHY_TEST_PATTERN_80BIT_CUSTOM:
dp_write_link(catalog, REG_DP_STATE_CTRL,
DP_STATE_CTRL_LINK_TEST_CUSTOM_PATTERN);
/* 00111110000011111000001111100000 */
......@@ -901,14 +918,15 @@ void dp_catalog_ctrl_send_phy_pattern(struct dp_catalog *dp_catalog,
/* 1111100000111110 */
dp_write_link(catalog, REG_DP_TEST_80BIT_CUSTOM_PATTERN_REG2,
0x0000F83E);
return;
case DP_LINK_QUAL_PATTERN_HBR2_EYE:
case DP_LINK_QUAL_PATTERN_ERROR_RATE:
value &= ~DP_HBR2_ERM_PATTERN;
if (pattern == DP_LINK_QUAL_PATTERN_HBR2_EYE)
value = DP_HBR2_ERM_PATTERN;
break;
case DP_PHY_TEST_PATTERN_CP2520:
value = dp_read_link(catalog, REG_DP_MAINLINK_CTRL);
value &= ~DP_MAINLINK_CTRL_SW_BYPASS_SCRAMBLER;
dp_write_link(catalog, REG_DP_MAINLINK_CTRL, value);
value = DP_HBR2_ERM_PATTERN;
dp_write_link(catalog, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET,
value);
value);
value |= SCRAMBLER_RESET_COUNT_VALUE;
dp_write_link(catalog, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET,
value);
......@@ -916,10 +934,19 @@ void dp_catalog_ctrl_send_phy_pattern(struct dp_catalog *dp_catalog,
DP_MAINLINK_SAFE_TO_EXIT_LEVEL_2);
dp_write_link(catalog, REG_DP_STATE_CTRL,
DP_STATE_CTRL_LINK_SYMBOL_ERR_MEASURE);
return;
value = dp_read_link(catalog, REG_DP_MAINLINK_CTRL);
value |= DP_MAINLINK_CTRL_ENABLE;
dp_write_link(catalog, REG_DP_MAINLINK_CTRL, value);
break;
case DP_PHY_TEST_PATTERN_SEL_MASK:
dp_write_link(catalog, REG_DP_MAINLINK_CTRL,
DP_MAINLINK_CTRL_ENABLE);
dp_write_link(catalog, REG_DP_STATE_CTRL,
DP_STATE_CTRL_LINK_TRAINING_PATTERN4);
break;
default:
DRM_DEBUG_DP("No valid test pattern requested:0x%x\n", pattern);
return;
break;
}
}
......
This diff is collapsed.
......@@ -21,7 +21,8 @@ struct dp_ctrl {
int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip);
void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl);
int dp_ctrl_on(struct dp_ctrl *dp_ctrl);
int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl);
int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl);
int dp_ctrl_off(struct dp_ctrl *dp_ctrl);
void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl);
void dp_ctrl_isr(struct dp_ctrl *dp_ctrl);
......
This diff is collapsed.
......@@ -13,7 +13,6 @@ struct msm_dp {
struct drm_connector *connector;
struct drm_encoder *encoder;
bool is_connected;
struct mutex connect_mutex;
u32 max_pclk_khz;
u32 max_dp_lanes;
};
......
......@@ -58,7 +58,6 @@ static int dp_connector_get_modes(struct drm_connector *connector)
if (!dp_mode)
return 0;
mutex_lock(&dp->connect_mutex);
/* pluggable case assumes EDID is read when HPD */
if (dp->is_connected) {
/*
......@@ -71,7 +70,6 @@ static int dp_connector_get_modes(struct drm_connector *connector)
if (rc <= 0) {
DRM_ERROR("failed to get DP sink modes, rc=%d\n", rc);
kfree(dp_mode);
mutex_unlock(&dp->connect_mutex);
return rc;
}
if (dp_mode->drm_mode.clock) { /* valid DP mode */
......@@ -83,7 +81,6 @@ static int dp_connector_get_modes(struct drm_connector *connector)
drm_mode.hdisplay,
drm_mode.vdisplay);
kfree(dp_mode);
mutex_unlock(&dp->connect_mutex);
return 0;
}
drm_mode_probed_add(connector, m);
......@@ -91,7 +88,6 @@ static int dp_connector_get_modes(struct drm_connector *connector)
} else {
DRM_DEBUG_DP("No sink connected\n");
}
mutex_unlock(&dp->connect_mutex);
kfree(dp_mode);
return rc;
}
......
......@@ -24,7 +24,7 @@ struct dp_hpd_private {
struct dp_usbpd dp_usbpd;
};
static int dp_hpd_connect(struct dp_usbpd *dp_usbpd, bool hpd)
int dp_hpd_connect(struct dp_usbpd *dp_usbpd, bool hpd)
{
int rc = 0;
struct dp_hpd_private *hpd_priv;
......
......@@ -75,5 +75,6 @@ struct dp_usbpd *dp_hpd_get(struct device *dev, struct dp_usbpd_cb *cb);
int dp_hpd_register(struct dp_usbpd *dp_usbpd);
void dp_hpd_unregister(struct dp_usbpd *dp_usbpd);
int dp_hpd_connect(struct dp_usbpd *dp_usbpd, bool hpd);
#endif /* _DP_HPD_H_ */
......@@ -38,7 +38,6 @@ struct dp_link_private {
struct dp_link dp_link;
struct dp_link_request request;
struct mutex test_response_mutex;
struct mutex psm_mutex;
u8 link_status[DP_LINK_STATUS_SIZE];
};
......@@ -580,17 +579,18 @@ static int dp_link_parse_phy_test_params(struct dp_link_private *link)
return rlen;
}
link->dp_link.phy_params.phy_test_pattern_sel = data;
link->dp_link.phy_params.phy_test_pattern_sel = data & 0x07;
DRM_DEBUG_DP("phy_test_pattern_sel = 0x%x\n", data);
switch (data) {
case DP_LINK_QUAL_PATTERN_DISABLE:
case DP_LINK_QUAL_PATTERN_D10_2:
case DP_LINK_QUAL_PATTERN_ERROR_RATE:
case DP_LINK_QUAL_PATTERN_PRBS7:
case DP_LINK_QUAL_PATTERN_80BIT_CUSTOM:
case DP_LINK_QUAL_PATTERN_HBR2_EYE:
case DP_PHY_TEST_PATTERN_SEL_MASK:
case DP_PHY_TEST_PATTERN_NONE:
case DP_PHY_TEST_PATTERN_D10_2:
case DP_PHY_TEST_PATTERN_ERROR_COUNT:
case DP_PHY_TEST_PATTERN_PRBS7:
case DP_PHY_TEST_PATTERN_80BIT_CUSTOM:
case DP_PHY_TEST_PATTERN_CP2520:
return 0;
default:
return -EINVAL;
......@@ -661,7 +661,6 @@ static int dp_link_parse_request(struct dp_link_private *link)
DRM_DEBUG_DP("Test:(0x%x) requested\n", data);
link->request.test_requested = data;
if (link->request.test_requested == DP_TEST_LINK_PHY_TEST_PATTERN) {
ret = dp_link_parse_phy_test_params(link);
if (ret)
......@@ -789,10 +788,8 @@ bool dp_link_send_test_response(struct dp_link *dp_link)
link = container_of(dp_link, struct dp_link_private, dp_link);
mutex_lock(&link->test_response_mutex);
ret = drm_dp_dpcd_writeb(link->aux, DP_TEST_RESPONSE,
dp_link->test_response);
mutex_unlock(&link->test_response_mutex);
return ret == 1;
}
......@@ -1028,11 +1025,9 @@ int dp_link_process_request(struct dp_link *dp_link)
link = container_of(dp_link, struct dp_link_private, dp_link);
mutex_lock(&link->test_response_mutex);
dp_link_reset_data(link);
dp_link_parse_sink_status_field(link);
mutex_unlock(&link->test_response_mutex);
if (link->request.test_requested == DP_TEST_LINK_EDID_READ) {
dp_link->sink_request |= DP_TEST_LINK_EDID_READ;
......@@ -1206,7 +1201,6 @@ struct dp_link *dp_link_get(struct device *dev, struct drm_dp_aux *aux)
link->dev = dev;
link->aux = aux;
mutex_init(&link->test_response_mutex);
mutex_init(&link->psm_mutex);
dp_link = &link->dp_link;
......
......@@ -8,8 +8,6 @@
#include <drm/drm_connector.h>
#include <drm/drm_edid.h>
#define DP_MAX_DS_PORT_COUNT 1
struct dp_panel_private {
struct device *dev;
struct dp_panel dp_panel;
......@@ -23,26 +21,32 @@ struct dp_panel_private {
static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
{
int rc = 0;
size_t rlen;
size_t len;
ssize_t rlen;
struct dp_panel_private *panel;
struct dp_link_info *link_info;
u8 *dpcd, major = 0, minor = 0, temp;
u32 dfp_count = 0, offset = DP_DPCD_REV;
u32 offset = DP_DPCD_REV;
dpcd = dp_panel->dpcd;
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
link_info = &dp_panel->link_info;
rlen = drm_dp_dpcd_read(panel->aux,
DP_TRAINING_AUX_RD_INTERVAL, &temp, 1);
if (rlen < 0) {
DRM_ERROR("err reading DP_TRAINING_AUX_RD_INTERVAL,rlen=%zd\n",
rlen);
rc = -EINVAL;
rlen = drm_dp_dpcd_read(panel->aux, offset,
dpcd, (DP_RECEIVER_CAP_SIZE + 1));
if (rlen < (DP_RECEIVER_CAP_SIZE + 1)) {
DRM_ERROR("dpcd read failed, rlen=%zd\n", rlen);
if (rlen == -ETIMEDOUT)
rc = rlen;
else
rc = -EINVAL;
goto end;
}
temp = dpcd[DP_TRAINING_AUX_RD_INTERVAL];
/* check for EXTENDED_RECEIVER_CAPABILITY_FIELD_PRESENT */
if (temp & BIT(7)) {
DRM_DEBUG_DP("using EXTENDED_RECEIVER_CAPABILITY_FIELD\n");
......@@ -61,9 +65,6 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
goto end;
}
print_hex_dump(KERN_DEBUG, "[drm-dp] SINK DPCD: ",
DUMP_PREFIX_NONE, 8, 1, dp_panel->dpcd, rlen, false);
link_info->revision = dpcd[DP_DPCD_REV];
major = (link_info->revision >> 4) & 0x0f;
minor = link_info->revision & 0x0f;
......@@ -85,14 +86,23 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
if (drm_dp_enhanced_frame_cap(dpcd))
link_info->capabilities |= DP_LINK_CAP_ENHANCED_FRAMING;
dfp_count = dpcd[DP_DOWN_STREAM_PORT_COUNT] &
DP_DOWN_STREAM_PORT_COUNT;
dp_panel->dfp_present = dpcd[DP_DOWNSTREAMPORT_PRESENT];
dp_panel->dfp_present &= DP_DWN_STRM_PORT_PRESENT;
if (dfp_count > DP_MAX_DS_PORT_COUNT) {
DRM_ERROR("DS port count %d greater that max (%d) supported\n",
dfp_count, DP_MAX_DS_PORT_COUNT);
return -EINVAL;
if (dp_panel->dfp_present && (dpcd[DP_DPCD_REV] > 0x10)) {
dp_panel->ds_port_cnt = dpcd[DP_DOWN_STREAM_PORT_COUNT];
dp_panel->ds_port_cnt &= DP_PORT_COUNT_MASK;
len = DP_DOWNSTREAM_PORTS * DP_DOWNSTREAM_CAP_SIZE;
rlen = drm_dp_dpcd_read(panel->aux,
DP_DOWNSTREAM_PORT_0, dp_panel->ds_cap_info, len);
if (rlen < len) {
DRM_ERROR("ds port status failed, rlen=%zd\n", rlen);
rc = -EINVAL;
goto end;
}
}
end:
return rc;
}
......@@ -185,6 +195,7 @@ int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
struct drm_connector *connector)
{
int rc = 0, bw_code;
int rlen, count;
struct dp_panel_private *panel;
if (!dp_panel || !connector) {
......@@ -202,11 +213,19 @@ int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
DRM_ERROR("read dpcd failed %d\n", rc);
return rc;
}
rc = drm_dp_read_desc(panel->aux, &dp_panel->desc,
drm_dp_is_branch(dp_panel->dpcd));
if (rc) {
DRM_ERROR("read sink/branch descriptor failed %d\n", rc);
return rc;
if (dp_panel->dfp_present) {
rlen = drm_dp_dpcd_read(panel->aux, DP_SINK_COUNT,
&count, 1);
if (rlen == 1) {
count = DP_GET_SINK_COUNT(count);
if (!count) {
DRM_ERROR("no downstream ports connected\n");
panel->link->sink_count = 0;
rc = -ENOTCONN;
goto end;
}
}
}
kfree(dp_panel->edid);
......@@ -216,7 +235,12 @@ int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
&panel->aux->ddc);
if (!dp_panel->edid) {
DRM_ERROR("panel edid read failed\n");
return -EINVAL;
/* fail safe edid */
mutex_lock(&connector->dev->mode_config.mutex);
if (drm_add_modes_noedid(connector, 640, 480))
drm_set_preferred_mode(connector, 640, 480);
mutex_unlock(&connector->dev->mode_config.mutex);
}
if (panel->aux_cfg_update_done) {
......@@ -231,8 +255,8 @@ int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
}
panel->aux_cfg_update_done = false;
}
return 0;
end:
return rc;
}
u32 dp_panel_get_mode_bpp(struct dp_panel *dp_panel,
......
......@@ -14,8 +14,10 @@
struct edid;
#define DP_MAX_DOWNSTREAM_PORTS 0x10
#define DPRX_EXTENDED_DPCD_FIELD 0x2200
#define DPRX_EXTENDED_DPCD_FIELD 0x2200
#define DP_DOWNSTREAM_PORTS 4
#define DP_DOWNSTREAM_CAP_SIZE 4
struct dp_display_mode {
struct drm_display_mode drm_mode;
......@@ -35,6 +37,9 @@ struct dp_panel_in {
struct dp_panel {
/* dpcd raw data */
u8 dpcd[DP_RECEIVER_CAP_SIZE + 1];
u8 ds_cap_info[DP_DOWNSTREAM_PORTS * DP_DOWNSTREAM_CAP_SIZE];
u32 ds_port_cnt;
u32 dfp_present;
struct dp_link_info link_info;
struct drm_dp_desc desc;
......
......@@ -103,11 +103,12 @@ static inline bool dp_parser_check_prefix(const char *clk_prefix,
static int dp_parser_init_clk_data(struct dp_parser *parser)
{
int num_clk, i, rc;
int core_clk_count = 0, ctrl_clk_count = 0;
int core_clk_count = 0, ctrl_clk_count = 0, stream_clk_count = 0;
const char *clk_name;
struct device *dev = &parser->pdev->dev;
struct dss_module_power *core_power = &parser->mp[DP_CORE_PM];
struct dss_module_power *ctrl_power = &parser->mp[DP_CTRL_PM];
struct dss_module_power *stream_power = &parser->mp[DP_STREAM_PM];
num_clk = of_property_count_strings(dev->of_node, "clock-names");
if (num_clk <= 0) {
......@@ -128,7 +129,7 @@ static int dp_parser_init_clk_data(struct dp_parser *parser)
ctrl_clk_count++;
if (dp_parser_check_prefix("stream", clk_name))
ctrl_clk_count++;
stream_clk_count++;
}
/* Initialize the CORE power module */
......@@ -159,6 +160,21 @@ static int dp_parser_init_clk_data(struct dp_parser *parser)
return -EINVAL;
}
/* Initialize the STREAM power module */
if (stream_clk_count == 0) {
DRM_ERROR("no stream (pixel) clocks are defined\n");
return -EINVAL;
}
stream_power->num_clk = stream_clk_count;
stream_power->clk_config = devm_kzalloc(dev,
sizeof(struct dss_clk) * stream_power->num_clk,
GFP_KERNEL);
if (!stream_power->clk_config) {
stream_power->num_clk = 0;
return -EINVAL;
}
return 0;
}
......@@ -166,15 +182,13 @@ static int dp_parser_clock(struct dp_parser *parser)
{
int rc = 0, i = 0;
int num_clk = 0;
int core_clk_index = 0, ctrl_clk_index = 0;
int core_clk_count = 0, ctrl_clk_count = 0;
int core_clk_index = 0, ctrl_clk_index = 0, stream_clk_index = 0;
int core_clk_count = 0, ctrl_clk_count = 0, stream_clk_count = 0;
const char *clk_name;
struct device *dev = &parser->pdev->dev;
struct dss_module_power *core_power = &parser->mp[DP_CORE_PM];
struct dss_module_power *ctrl_power = &parser->mp[DP_CTRL_PM];
core_power = &parser->mp[DP_CORE_PM];
ctrl_power = &parser->mp[DP_CTRL_PM];
struct dss_module_power *stream_power = &parser->mp[DP_STREAM_PM];
rc = dp_parser_init_clk_data(parser);
if (rc) {
......@@ -184,8 +198,9 @@ static int dp_parser_clock(struct dp_parser *parser)
core_clk_count = core_power->num_clk;
ctrl_clk_count = ctrl_power->num_clk;
stream_clk_count = stream_power->num_clk;
num_clk = core_clk_count + ctrl_clk_count;
num_clk = core_clk_count + ctrl_clk_count + stream_clk_count;
for (i = 0; i < num_clk; i++) {
rc = of_property_read_string_index(dev->of_node, "clock-names",
......@@ -201,14 +216,19 @@ static int dp_parser_clock(struct dp_parser *parser)
strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name));
clk->type = DSS_CLK_AHB;
core_clk_index++;
} else if ((dp_parser_check_prefix("ctrl", clk_name) ||
dp_parser_check_prefix("stream", clk_name)) &&
} else if (dp_parser_check_prefix("stream", clk_name) &&
stream_clk_index < stream_clk_count) {
struct dss_clk *clk =
&stream_power->clk_config[stream_clk_index];
strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name));
clk->type = DSS_CLK_PCLK;
stream_clk_index++;
} else if (dp_parser_check_prefix("ctrl", clk_name) &&
ctrl_clk_index < ctrl_clk_count) {
struct dss_clk *clk =
&ctrl_power->clk_config[ctrl_clk_index];
strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name));
ctrl_clk_index++;
if (dp_parser_check_prefix("ctrl_link", clk_name) ||
dp_parser_check_prefix("stream_pixel", clk_name))
clk->type = DSS_CLK_PCLK;
......
......@@ -19,6 +19,7 @@
enum dp_pm_type {
DP_CORE_PM,
DP_CTRL_PM,
DP_STREAM_PM,
DP_PHY_PM,
DP_MAX_PM
};
......@@ -33,6 +34,7 @@ static inline const char *dp_parser_pm_name(enum dp_pm_type module)
switch (module) {
case DP_CORE_PM: return "DP_CORE_PM";
case DP_CTRL_PM: return "DP_CTRL_PM";
case DP_STREAM_PM: return "DP_STREAM_PM";
case DP_PHY_PM: return "DP_PHY_PM";
default: return "???";
}
......
......@@ -95,11 +95,12 @@ static int dp_power_regulator_init(struct dp_power_private *power)
static int dp_power_clk_init(struct dp_power_private *power)
{
int rc = 0;
struct dss_module_power *core, *ctrl;
struct dss_module_power *core, *ctrl, *stream;
struct device *dev = &power->pdev->dev;
core = &power->parser->mp[DP_CORE_PM];
ctrl = &power->parser->mp[DP_CTRL_PM];
stream = &power->parser->mp[DP_STREAM_PM];
if (power->parser->pll && power->parser->pll->get_provider) {
rc = power->parser->pll->get_provider(power->parser->pll,
......@@ -126,21 +127,33 @@ static int dp_power_clk_init(struct dp_power_private *power)
return -ENODEV;
}
rc = msm_dss_get_clk(dev, stream->clk_config, stream->num_clk);
if (rc) {
DRM_ERROR("failed to get %s clk. err=%d\n",
dp_parser_pm_name(DP_CTRL_PM), rc);
msm_dss_put_clk(core->clk_config, core->num_clk);
return -ENODEV;
}
return 0;
}
static int dp_power_clk_deinit(struct dp_power_private *power)
{
struct dss_module_power *core, *ctrl;
struct dss_module_power *core, *ctrl, *stream;
core = &power->parser->mp[DP_CORE_PM];
ctrl = &power->parser->mp[DP_CTRL_PM];
stream = &power->parser->mp[DP_STREAM_PM];
if (!core || !ctrl)
if (!core || !ctrl || !stream) {
DRM_ERROR("invalid power_data\n");
return -EINVAL;
}
msm_dss_put_clk(ctrl->clk_config, ctrl->num_clk);
msm_dss_put_clk(core->clk_config, core->num_clk);
msm_dss_put_clk(stream->clk_config, stream->num_clk);
return 0;
}
......@@ -167,6 +180,20 @@ static int dp_power_clk_set_rate(struct dp_power_private *power,
return 0;
}
int dp_power_clk_status(struct dp_power *dp_power, enum dp_pm_type pm_type)
{
if (pm_type == DP_CORE_PM)
return dp_power->core_clks_on;
if (pm_type == DP_CTRL_PM)
return dp_power->link_clks_on;
if (pm_type == DP_STREAM_PM)
return dp_power->stream_clks_on;
return 0;
}
int dp_power_clk_enable(struct dp_power *dp_power,
enum dp_pm_type pm_type, bool enable)
{
......@@ -175,7 +202,8 @@ int dp_power_clk_enable(struct dp_power *dp_power,
power = container_of(dp_power, struct dp_power_private, dp_power);
if (pm_type != DP_CORE_PM && pm_type != DP_CTRL_PM) {
if (pm_type != DP_CORE_PM && pm_type != DP_CTRL_PM &&
pm_type != DP_STREAM_PM) {
DRM_ERROR("unsupported power module: %s\n",
dp_parser_pm_name(pm_type));
return -EINVAL;
......@@ -192,6 +220,11 @@ int dp_power_clk_enable(struct dp_power *dp_power,
return 0;
}
if (pm_type == DP_STREAM_PM && dp_power->stream_clks_on) {
DRM_DEBUG_DP("pixel clks already enabled\n");
return 0;
}
if ((pm_type == DP_CTRL_PM) && (!dp_power->core_clks_on)) {
DRM_DEBUG_DP("Enable core clks before link clks\n");
......@@ -215,13 +248,16 @@ int dp_power_clk_enable(struct dp_power *dp_power,
if (pm_type == DP_CORE_PM)
dp_power->core_clks_on = enable;
else if (pm_type == DP_STREAM_PM)
dp_power->stream_clks_on = enable;
else
dp_power->link_clks_on = enable;
DRM_DEBUG_DP("%s clocks for %s\n",
enable ? "enable" : "disable",
dp_parser_pm_name(pm_type));
DRM_DEBUG_DP("link_clks:%s core_clks:%s\n",
DRM_DEBUG_DP("strem_clks:%s link_clks:%s core_clks:%s\n",
dp_power->stream_clks_on ? "on" : "off",
dp_power->link_clks_on ? "on" : "off",
dp_power->core_clks_on ? "on" : "off");
......
......@@ -19,6 +19,7 @@
struct dp_power {
bool core_clks_on;
bool link_clks_on;
bool stream_clks_on;
};
/**
......@@ -43,6 +44,18 @@ int dp_power_init(struct dp_power *power, bool flip);
*/
int dp_power_deinit(struct dp_power *power);
/**
* dp_power_clk_status() - display controller clocks status
*
* @power: instance of power module
* @pm_type: type of pm, core/ctrl/phy
* return: status of power clocks
*
* This API return status of DP clocks
*/
int dp_power_clk_status(struct dp_power *dp_power, enum dp_pm_type pm_type);
/**
* dp_power_clk_enable() - enable display controller clocks
*
......
......@@ -101,6 +101,7 @@
#define REG_DP_MAINLINK_CTRL (0x00000000)
#define DP_MAINLINK_CTRL_ENABLE (0x00000001)
#define DP_MAINLINK_CTRL_RESET (0x00000002)
#define DP_MAINLINK_CTRL_SW_BYPASS_SCRAMBLER (0x00000010)
#define DP_MAINLINK_FB_BOUNDARY_SEL (0x02000000)
#define REG_DP_STATE_CTRL (0x00000004)
......
......@@ -392,6 +392,7 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
struct drm_encoder *encoder);
int msm_dp_display_enable(struct msm_dp *dp, struct drm_encoder *encoder);
int msm_dp_display_disable(struct msm_dp *dp, struct drm_encoder *encoder);
int msm_dp_display_pre_disable(struct msm_dp *dp, struct drm_encoder *encoder);
void msm_dp_display_mode_set(struct msm_dp *dp, struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment