msm: mdss: Refactor ping pong split configurations

Refactor ping pong split programming to make it generic enough to
support the feature on multiple targets.

Change-Id: Ic2a1cad97c354997de81f06e449ab78a1864fda2
Signed-off-by: Jeykumar Sankaran <jsanka@codeaurora.org>
(cherry picked from commit 472bb7cff9aae26cac323c6cb5d01ffb1de206ab)
[veeras@codeaurora.org: Resolve merge conflict in mdss_mdp_intf_cmd.c
and mdss_mdp_intf_video.c]
Signed-off-by: Veera Sundaram Sankaran <veeras@codeaurora.org>

	../../../../tools/gator/daemon/events_xml.h
This commit is contained in:
Jeykumar Sankaran 2015-01-06 14:08:53 -08:00 committed by David Keitel
parent 1c9334a895
commit 80b557c07f
7 changed files with 337 additions and 214 deletions

View file

@ -449,6 +449,11 @@ Fudge Factors: Fudge factors are used to boost demand for
- qcom,max-pipe-width: This value specifies the maximum MDP SSPP width
the device supports. If not specified, a default value
of 2048 will be applied.
- qcom,mdss-slave-pingpong-off: Offset address for the extra TE block which needs
to be programmed when pingpong split feature is enabled.
Offset is calculated from the "mdp_phys"
register value. Mandatory when qcom,mdss-has-dst-split
is enabled.
Optional subnodes:
- mdss_fb: Child nodes representing the frame buffer virtual devices.
@ -666,6 +671,7 @@ Example:
0x00021500 0x00021700>;
qcom,mdss-cdm-off = <0x0007A200>;
qcom,mdss-ppb-off = <0x0000420>;
qcom,mdss-slave-pingpong-off = <0x00073000>
/* buffer parameters to calculate prefill bandwidth */
qcom,mdss-prefill-outstanding-buffer-bytes = <1024>;

View file

@ -314,8 +314,10 @@ struct mdss_data_type {
u32 max_target_zorder;
u8 ncursor_pipes;
u32 max_cursor_size;
u32 nppb;
struct mdss_mdp_ppb *ppb;
char __iomem *slave_pingpong_base;
struct mdss_mdp_mixer *mixer_intf;
struct mdss_mdp_mixer *mixer_wb;

View file

@ -2695,7 +2695,7 @@ static void mdss_mdp_parse_vbif_qos(struct platform_device *pdev)
static int mdss_mdp_parse_dt_misc(struct platform_device *pdev)
{
struct mdss_data_type *mdata = platform_get_drvdata(pdev);
u32 data;
u32 data, slave_pingpong_off;
const char *wfd_data;
int rc;
struct property *prop = NULL;
@ -2763,6 +2763,18 @@ static int mdss_mdp_parse_dt_misc(struct platform_device *pdev)
mdata->has_pingpong_split = of_property_read_bool(pdev->dev.of_node,
"qcom,mdss-has-dst-split");
if (mdata->has_pingpong_split) {
rc = of_property_read_u32(pdev->dev.of_node,
"qcom,mdss-slave-pingpong-off",
&slave_pingpong_off);
if (rc) {
pr_err("Error in device tree: slave pingpong offset\n");
return rc;
}
mdata->slave_pingpong_base = mdata->mdss_io.base +
slave_pingpong_off;
}
/*
* 2x factor on AB because bus driver will divide by 2
* due to 2x ports to BIMC

View file

@ -80,6 +80,9 @@
#define CURSOR_PIPE_LEFT 0
#define CURSOR_PIPE_RIGHT 1
#define MASTER_CTX 0
#define SLAVE_CTX 1
/*
* Recommendation is to have different ot depending on the fps
* and resolution, but since current SW doesn't support different
@ -300,6 +303,7 @@ struct mdss_mdp_ctl {
struct blocking_notifier_head notifier_head;
void *priv_data;
void *intf_ctx[2];
u32 wb_type;
bool prg_fet;

View file

@ -2399,6 +2399,12 @@ static void mdss_mdp_ctl_split_display_enable(int enable,
lower |= BIT(4);
else
lower |= BIT(8);
/*
* Enable SMART_PANEL_FREE_RUN if ping pong split
* is enabled.
*/
if (is_pingpong_split(main_ctl->mfd))
lower |= BIT(2);
upper = lower;
} else {
/* interface controlling sw trigger (video mode) */

View file

@ -61,6 +61,7 @@ struct mdss_mdp_cmd_ctx {
struct mdss_intf_recovery intf_recovery;
struct mdss_mdp_cmd_ctx *sync_ctx; /* for partial update */
u32 pp_timeout_report_cnt;
int pingpong_split_slave;
};
struct mdss_mdp_cmd_ctx mdss_mdp_cmd_ctx_list[MAX_SESSIONS];
@ -122,14 +123,15 @@ exit:
}
static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_ctl *ctl,
struct mdss_mdp_mixer *mixer, bool enable)
static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_mixer *mixer,
struct mdss_mdp_cmd_ctx *ctx, bool enable)
{
struct mdss_mdp_pp_tear_check *te = NULL;
struct mdss_panel_info *pinfo;
u32 vsync_clk_speed_hz, total_lines, vclks_line, cfg = 0;
char __iomem *pingpong_base;
struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
struct mdss_mdp_ctl *ctl = ctx->ctl;
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
if (IS_ERR_OR_NULL(ctl->panel_data)) {
pr_err("no panel data\n");
@ -174,9 +176,9 @@ static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_ctl *ctl,
}
pingpong_base = mixer->pingpong_base;
/* for dst split pp_num is cmd session (0 and 1) */
if (is_pingpong_split(ctl->mfd))
pingpong_base += ctx->pp_num * SPLIT_MIXER_OFFSET;
if (ctx->pingpong_split_slave)
pingpong_base = mdata->slave_pingpong_base;
mdss_mdp_pingpong_write(pingpong_base,
MDSS_MDP_REG_PP_SYNC_CONFIG_VSYNC, cfg);
@ -203,14 +205,16 @@ static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_ctl *ctl,
return 0;
}
static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_ctl *ctl, bool enable)
static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_cmd_ctx *ctx,
bool enable)
{
int rc = 0;
struct mdss_mdp_mixer *mixer;
struct mdss_mdp_ctl *ctl = ctx->ctl;
mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT);
if (mixer) {
rc = mdss_mdp_cmd_tearcheck_cfg(ctl, mixer, enable);
rc = mdss_mdp_cmd_tearcheck_cfg(mixer, ctx, enable);
if (rc)
goto err;
}
@ -218,9 +222,9 @@ static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_ctl *ctl, bool enable)
if (!(ctl->opmode & MDSS_MDP_CTL_OP_PACK_3D_ENABLE)) {
mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_RIGHT);
if (mixer)
rc = mdss_mdp_cmd_tearcheck_cfg(ctl, mixer, enable);
rc = mdss_mdp_cmd_tearcheck_cfg(mixer, ctx, enable);
}
err:
err:
return rc;
}
@ -296,7 +300,7 @@ static inline void mdss_mdp_cmd_clk_off(struct mdss_mdp_cmd_ctx *ctx)
static void mdss_mdp_cmd_readptr_done(void *arg)
{
struct mdss_mdp_ctl *ctl = arg;
struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
struct mdss_mdp_cmd_ctx *ctx = ctl->intf_ctx[MASTER_CTX];
struct mdss_mdp_vsync_handler *tmp;
ktime_t vsync_time;
@ -382,7 +386,7 @@ static void mdss_mdp_cmd_intf_recovery(void *data, int event)
static void mdss_mdp_cmd_pingpong_done(void *arg)
{
struct mdss_mdp_ctl *ctl = arg;
struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
struct mdss_mdp_cmd_ctx *ctx = ctl->intf_ctx[MASTER_CTX];
struct mdss_mdp_vsync_handler *tmp;
ktime_t vsync_time;
u32 status;
@ -463,7 +467,8 @@ static void clk_ctrl_work(struct work_struct *work)
sctl = mdss_mdp_get_split_ctl(ctl);
if (sctl) {
sctx = (struct mdss_mdp_cmd_ctx *) sctl->priv_data;
sctx =
(struct mdss_mdp_cmd_ctx *)sctl->intf_ctx[MASTER_CTX];
} else {
/* slave ctl, let master ctl do clk control */
mutex_unlock(&cmd_clk_mtx);
@ -488,7 +493,7 @@ static int mdss_mdp_cmd_add_vsync_handler(struct mdss_mdp_ctl *ctl,
unsigned long flags;
bool enable_rdptr = false;
ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
ctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[MASTER_CTX];
if (!ctx) {
pr_err("%s: invalid ctx\n", __func__);
return -ENODEV;
@ -498,7 +503,7 @@ static int mdss_mdp_cmd_add_vsync_handler(struct mdss_mdp_ctl *ctl,
ctx->rdptr_enabled);
sctl = mdss_mdp_get_split_ctl(ctl);
if (sctl)
sctx = (struct mdss_mdp_cmd_ctx *) sctl->priv_data;
sctx = (struct mdss_mdp_cmd_ctx *) sctl->intf_ctx[MASTER_CTX];
spin_lock_irqsave(&ctx->clk_lock, flags);
if (!handle->enabled) {
@ -536,7 +541,7 @@ static int mdss_mdp_cmd_remove_vsync_handler(struct mdss_mdp_ctl *ctl,
struct mdss_mdp_cmd_ctx *ctx, *sctx = NULL;
unsigned long flags;
ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
ctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[MASTER_CTX];
if (!ctx) {
pr_err("%s: invalid ctx\n", __func__);
return -ENODEV;
@ -546,7 +551,7 @@ static int mdss_mdp_cmd_remove_vsync_handler(struct mdss_mdp_ctl *ctl,
ctx->rdptr_enabled, 0x88888);
sctl = mdss_mdp_get_split_ctl(ctl);
if (sctl)
sctx = (struct mdss_mdp_cmd_ctx *) sctl->priv_data;
sctx = (struct mdss_mdp_cmd_ctx *) sctl->intf_ctx[MASTER_CTX];
spin_lock_irqsave(&ctx->clk_lock, flags);
if (handle->enabled) {
@ -593,7 +598,7 @@ static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg)
unsigned long flags;
int rc = 0;
ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
ctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[MASTER_CTX];
if (!ctx) {
pr_err("invalid ctx\n");
return -ENODEV;
@ -682,14 +687,14 @@ static void mdss_mdp_cmd_set_sync_ctx(
{
struct mdss_mdp_cmd_ctx *ctx, *sctx;
ctx = (struct mdss_mdp_cmd_ctx *)ctl->priv_data;
ctx = (struct mdss_mdp_cmd_ctx *)ctl->intf_ctx[MASTER_CTX];
if (!sctl) {
ctx->sync_ctx = NULL;
return;
}
sctx = (struct mdss_mdp_cmd_ctx *)sctl->priv_data;
sctx = (struct mdss_mdp_cmd_ctx *)sctl->intf_ctx[MASTER_CTX];
if (!sctl->roi.w && !sctl->roi.h) {
/* left only */
@ -734,14 +739,14 @@ static int mdss_mdp_cmd_panel_on(struct mdss_mdp_ctl *ctl,
struct mdss_mdp_cmd_ctx *ctx, *sctx = NULL;
int rc = 0;
ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
ctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[MASTER_CTX];
if (!ctx) {
pr_err("invalid ctx\n");
return -ENODEV;
}
if (sctl)
sctx = (struct mdss_mdp_cmd_ctx *) sctl->priv_data;
sctx = (struct mdss_mdp_cmd_ctx *) sctl->intf_ctx[MASTER_CTX];
if (!__mdss_mdp_cmd_is_panel_power_on_interactive(ctx)) {
rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_LINK_READY, NULL);
@ -779,7 +784,7 @@ static int __mdss_mdp_cmd_configure_autorefresh(struct mdss_mdp_ctl *ctl, int
pr_err("invalid ctl structure\n");
return -ENODEV;
}
ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
ctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[MASTER_CTX];
if (!ctx) {
pr_err("invalid ctx\n");
return -ENODEV;
@ -876,7 +881,7 @@ int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
struct mdss_mdp_ctl *sctl = NULL;
struct mdss_mdp_cmd_ctx *ctx, *sctx = NULL;
ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
ctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[MASTER_CTX];
if (!ctx) {
pr_err("invalid ctx\n");
return -ENODEV;
@ -900,7 +905,7 @@ int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
PERF_HW_MDP_STATE, PERF_STATUS_BUSY);
if (sctl) {
sctx = (struct mdss_mdp_cmd_ctx *) sctl->priv_data;
sctx = (struct mdss_mdp_cmd_ctx *) sctl->intf_ctx[MASTER_CTX];
mdss_mdp_ctl_perf_set_transaction_status(sctl,
PERF_HW_MDP_STATE, PERF_STATUS_BUSY);
}
@ -977,44 +982,26 @@ int mdss_mdp_cmd_restore(struct mdss_mdp_ctl *ctl)
{
pr_debug("%s: called for ctl%d\n", __func__, ctl->num);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
if (mdss_mdp_cmd_tearcheck_setup(ctl, true))
if (mdss_mdp_cmd_tearcheck_setup(ctl->intf_ctx[MASTER_CTX], true))
pr_warn("%s: tearcheck setup failed\n", __func__);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
return 0;
}
int mdss_mdp_cmd_intfs_stop(struct mdss_mdp_ctl *ctl, int session,
int panel_power_state)
int mdss_mdp_cmd_ctx_stop(struct mdss_mdp_ctl *ctl,
struct mdss_mdp_cmd_ctx *ctx, int panel_power_state)
{
struct mdss_mdp_ctl *sctl = NULL;
struct mdss_mdp_cmd_ctx *sctx = NULL;
struct mdss_mdp_cmd_ctx *ctx;
struct mdss_mdp_ctl *sctl = NULL;
unsigned long flags;
unsigned long sflags;
int need_wait = 0;
int ret = 0;
int hz;
if (session >= MAX_SESSIONS)
return 0;
if (is_pingpong_split(ctl->mfd)) {
ret = mdss_mdp_cmd_intfs_stop(ctl, (session + 1),
panel_power_state);
if (IS_ERR_VALUE(ret))
return ret;
}
sctl = mdss_mdp_get_split_ctl(ctl);
if (sctl)
sctx = (struct mdss_mdp_cmd_ctx *) sctl->priv_data;
ctx = &mdss_mdp_cmd_ctx_list[session];
if (!ctx->ref_cnt) {
pr_err("invalid ctx session: %d\n", session);
return -ENODEV;
}
sctx = (struct mdss_mdp_cmd_ctx *) sctl->intf_ctx[MASTER_CTX];
/* intf stopped, no more kickoff */
ctx->intf_stopped = 1;
@ -1057,11 +1044,11 @@ int mdss_mdp_cmd_intfs_stop(struct mdss_mdp_ctl *ctl, int session,
mdss_mdp_cmd_clk_off(ctx);
flush_work(&ctx->pp_done_work);
mdss_mdp_cmd_tearcheck_setup(ctl, false);
mdss_mdp_cmd_tearcheck_setup(ctx, false);
if (mdss_panel_is_power_on(panel_power_state)) {
pr_debug("%s: intf stopped with panel on\n", __func__);
goto end;
return 0;
}
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
@ -1071,9 +1058,39 @@ int mdss_mdp_cmd_intfs_stop(struct mdss_mdp_ctl *ctl, int session,
memset(ctx, 0, sizeof(*ctx));
end:
pr_debug("%s:-\n", __func__);
return 0;
}
int mdss_mdp_cmd_intfs_stop(struct mdss_mdp_ctl *ctl, int session,
int panel_power_state)
{
struct mdss_mdp_cmd_ctx *ctx;
if (session >= MAX_SESSIONS)
return 0;
ctx = ctl->intf_ctx[MASTER_CTX];
if (!ctx->ref_cnt) {
pr_err("invalid ctx session: %d\n", session);
return -ENODEV;
}
mdss_mdp_cmd_ctx_stop(ctl, ctx, panel_power_state);
if (is_pingpong_split(ctl->mfd)) {
session += 1;
if (session >= MAX_SESSIONS)
return 0;
ctx = ctl->intf_ctx[SLAVE_CTX];
if (!ctx->ref_cnt) {
pr_err("invalid ctx session: %d\n", session);
return -ENODEV;
}
mdss_mdp_cmd_ctx_stop(ctl, ctx, panel_power_state);
}
pr_debug("%s:-\n", __func__);
return 0;
}
@ -1084,7 +1101,7 @@ static int mdss_mdp_cmd_stop_sub(struct mdss_mdp_ctl *ctl,
struct mdss_mdp_vsync_handler *tmp, *handle;
int session;
ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
ctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[MASTER_CTX];
if (!ctx) {
pr_err("invalid ctx\n");
return -ENODEV;
@ -1102,7 +1119,7 @@ static int mdss_mdp_cmd_stop_sub(struct mdss_mdp_ctl *ctl,
int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl, int panel_power_state)
{
struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
struct mdss_mdp_cmd_ctx *ctx = ctl->intf_ctx[MASTER_CTX];
struct mdss_mdp_ctl *sctl = mdss_mdp_get_split_ctl(ctl);
bool panel_off = false;
bool turn_off_clocks = false;
@ -1215,7 +1232,8 @@ panel_events:
}
pr_debug("%s: turn off panel\n", __func__);
ctl->priv_data = NULL;
ctl->intf_ctx[MASTER_CTX] = NULL;
ctl->intf_ctx[SLAVE_CTX] = NULL;
ctl->ops.stop_fnc = NULL;
ctl->ops.display_fnc = NULL;
ctl->ops.wait_pingpong = NULL;
@ -1233,6 +1251,51 @@ end:
return ret;
}
static int mdss_mdp_cmd_ctx_setup(struct mdss_mdp_ctl *ctl,
struct mdss_mdp_cmd_ctx *ctx, int pp_num,
int pingpong_split_slave) {
int ret = 0;
ctx->ctl = ctl;
ctx->pp_num = pp_num;
ctx->pingpong_split_slave = pingpong_split_slave;
ctx->pp_timeout_report_cnt = 0;
init_waitqueue_head(&ctx->pp_waitq);
init_completion(&ctx->stop_comp);
init_completion(&ctx->readptr_done);
spin_lock_init(&ctx->clk_lock);
spin_lock_init(&ctx->koff_lock);
mutex_init(&ctx->clk_mtx);
mutex_init(&ctx->autorefresh_mtx);
INIT_WORK(&ctx->clk_work, clk_ctrl_work);
INIT_WORK(&ctx->pp_done_work, pingpong_done_work);
atomic_set(&ctx->pp_done_cnt, 0);
ctx->autorefresh_off_pending = false;
ctx->autorefresh_init = false;
INIT_LIST_HEAD(&ctx->vsync_handlers);
ctx->intf_recovery.fxn = mdss_mdp_cmd_intf_recovery;
ctx->intf_recovery.data = ctx;
ctx->intf_stopped = 0;
pr_debug("%s: ctx=%p num=%d\n", __func__, ctx, ctx->pp_num);
MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt), ctx->clk_enabled,
ctx->rdptr_enabled);
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
ctx->pp_num, mdss_mdp_cmd_readptr_done, ctl);
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
mdss_mdp_cmd_pingpong_done, ctl);
ret = mdss_mdp_cmd_tearcheck_setup(ctx, true);
if (ret)
pr_err("tearcheck setup failed\n");
return ret;
}
static int mdss_mdp_cmd_intfs_setup(struct mdss_mdp_ctl *ctl,
int session)
{
@ -1244,12 +1307,6 @@ static int mdss_mdp_cmd_intfs_setup(struct mdss_mdp_ctl *ctl,
if (session >= MAX_SESSIONS)
return 0;
if (is_pingpong_split(ctl->mfd)) {
ret = mdss_mdp_cmd_intfs_setup(ctl, (session + 1));
if (IS_ERR_VALUE(ret))
return ret;
}
sctl = mdss_mdp_get_split_ctl(ctl);
ctx = &mdss_mdp_cmd_ctx_list[session];
if (ctx->ref_cnt) {
@ -1281,51 +1338,43 @@ static int mdss_mdp_cmd_intfs_setup(struct mdss_mdp_ctl *ctl,
return -ENODEV;
}
ctl->priv_data = ctx;
if (!ctx) {
pr_err("invalid ctx\n");
ctl->intf_ctx[MASTER_CTX] = ctx;
ret = mdss_mdp_cmd_ctx_setup(ctl, ctx, session, false);
if (ret) {
pr_err("mdss_mdp_cmd_ctx_setup failed for ping ping: %d\n",
mixer->num);
ctx->ref_cnt--;
return -ENODEV;
}
ctx->ctl = ctl;
ctx->pp_num = (is_pingpong_split(ctl->mfd) ? session : mixer->num);
ctx->pp_timeout_report_cnt = 0;
init_waitqueue_head(&ctx->pp_waitq);
init_completion(&ctx->stop_comp);
init_completion(&ctx->readptr_done);
spin_lock_init(&ctx->clk_lock);
spin_lock_init(&ctx->koff_lock);
mutex_init(&ctx->clk_mtx);
mutex_init(&ctx->autorefresh_mtx);
INIT_WORK(&ctx->clk_work, clk_ctrl_work);
INIT_WORK(&ctx->pp_done_work, pingpong_done_work);
atomic_set(&ctx->pp_done_cnt, 0);
ctx->autorefresh_off_pending = false;
ctx->autorefresh_init = false;
INIT_LIST_HEAD(&ctx->vsync_handlers);
if (is_pingpong_split(ctl->mfd)) {
session += 1;
if (session >= MAX_SESSIONS)
return 0;
ctx = &mdss_mdp_cmd_ctx_list[session];
if (ctx->ref_cnt) {
if (mdss_panel_is_power_on(ctx->panel_power_state)) {
pr_debug("%s: cmd_start with panel always on\n",
__func__);
mdss_mdp_cmd_restore(ctl);
return mdss_mdp_cmd_panel_on(ctl, sctl);
} else {
pr_err("Intf %d already in use\n", session);
return -EBUSY;
}
}
ctx->ref_cnt++;
ctx->intf_recovery.fxn = mdss_mdp_cmd_intf_recovery;
ctx->intf_recovery.data = ctx;
ctl->intf_ctx[SLAVE_CTX] = ctx;
ctx->intf_stopped = 0;
pr_debug("%s: ctx=%p num=%d mixer=%d\n", __func__,
ctx, ctx->pp_num, mixer->num);
MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt), ctx->clk_enabled,
ctx->rdptr_enabled);
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
ctx->pp_num, mdss_mdp_cmd_readptr_done, ctl);
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
mdss_mdp_cmd_pingpong_done, ctl);
ret = mdss_mdp_cmd_tearcheck_setup(ctl, true);
if (ret) {
pr_err("tearcheck setup failed\n");
return ret;
ret = mdss_mdp_cmd_ctx_setup(ctl, ctx, session, true);
if (ret) {
pr_err("mdss_mdp_cmd_ctx_setup failed for slave ping pong block");
ctx->ref_cnt--;
return -EPERM;
}
}
return 0;
}
int mdss_mdp_cmd_start(struct mdss_mdp_ctl *ctl)

View file

@ -91,9 +91,9 @@ static inline u32 mdss_mdp_video_line_count(struct mdss_mdp_ctl *ctl)
{
struct mdss_mdp_video_ctx *ctx;
u32 line_cnt = 0;
if (!ctl || !ctl->priv_data)
if (!ctl || !ctl->intf_ctx[MASTER_CTX])
goto line_count_exit;
ctx = ctl->priv_data;
ctx = ctl->intf_ctx[MASTER_CTX];
line_cnt = mdp_video_read(ctx, MDSS_MDP_REG_INTF_LINE_COUNT);
line_count_exit:
return line_cnt;
@ -149,7 +149,7 @@ static void mdss_mdp_video_intf_recovery(void *data, int event)
return;
}
ctx = ctl->priv_data;
ctx = ctl->intf_ctx[MASTER_CTX];
pr_debug("%s: ctl num = %d, event = %d\n",
__func__, ctl->num, event);
@ -214,17 +214,16 @@ static void mdss_mdp_video_intf_recovery(void *data, int event)
}
static int mdss_mdp_video_timegen_setup(struct mdss_mdp_ctl *ctl,
struct intf_timing_params *p)
struct intf_timing_params *p,
struct mdss_mdp_video_ctx *ctx)
{
u32 hsync_period, vsync_period;
u32 hsync_start_x, hsync_end_x, display_v_start, display_v_end;
u32 active_h_start, active_h_end, active_v_start, active_v_end;
u32 den_polarity, hsync_polarity, vsync_polarity;
u32 display_hctl, active_hctl, hsync_ctl, polarity_ctl;
struct mdss_mdp_video_ctx *ctx;
struct mdss_data_type *mdata;
ctx = ctl->priv_data;
mdata = ctl->mdata;
hsync_period = p->hsync_pulse_width + p->h_back_porch +
p->width + p->h_front_porch;
@ -332,7 +331,7 @@ static int mdss_mdp_video_timegen_setup(struct mdss_mdp_ctl *ctl,
static inline void video_vsync_irq_enable(struct mdss_mdp_ctl *ctl, bool clear)
{
struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
struct mdss_mdp_video_ctx *ctx = ctl->intf_ctx[MASTER_CTX];
mutex_lock(&ctx->vsync_mtx);
if (atomic_inc_return(&ctx->vsync_ref) == 1)
@ -345,7 +344,7 @@ static inline void video_vsync_irq_enable(struct mdss_mdp_ctl *ctl, bool clear)
static inline void video_vsync_irq_disable(struct mdss_mdp_ctl *ctl)
{
struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
struct mdss_mdp_video_ctx *ctx = ctl->intf_ctx[MASTER_CTX];
mutex_lock(&ctx->vsync_mtx);
if (atomic_dec_return(&ctx->vsync_ref) == 0)
@ -366,7 +365,7 @@ static int mdss_mdp_video_add_vsync_handler(struct mdss_mdp_ctl *ctl,
goto exit;
}
ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
ctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[MASTER_CTX];
if (!ctx) {
pr_err("invalid ctx for ctl=%d\n", ctl->num);
ret = -ENODEV;
@ -395,7 +394,7 @@ static int mdss_mdp_video_remove_vsync_handler(struct mdss_mdp_ctl *ctl,
unsigned long flags;
bool irq_dis = false;
ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
ctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[MASTER_CTX];
if (!ctx) {
pr_err("invalid ctx for ctl=%d\n", ctl->num);
return -ENODEV;
@ -415,42 +414,12 @@ static int mdss_mdp_video_remove_vsync_handler(struct mdss_mdp_ctl *ctl,
return 0;
}
static int mdss_mdp_video_intfs_stop(struct mdss_mdp_ctl *ctl,
struct mdss_panel_data *pdata, int inum)
static int mdss_mdp_video_ctx_stop(struct mdss_mdp_ctl *ctl,
struct mdss_panel_info *pinfo, struct mdss_mdp_video_ctx *ctx)
{
struct mdss_data_type *mdata;
struct mdss_panel_info *pinfo;
struct mdss_mdp_video_ctx *ctx;
struct mdss_mdp_vsync_handler *tmp, *handle;
struct mdss_mdp_ctl *sctl;
int rc = 0;
u32 frame_rate = 0;
int ret = 0;
if (pdata == NULL)
return 0;
if (is_pingpong_split(ctl->mfd)) {
ret = mdss_mdp_video_intfs_stop(ctl, pdata->next, (inum + 1));
if (IS_ERR_VALUE(ret))
return ret;
}
mdata = ctl->mdata;
pinfo = &pdata->panel_info;
if (inum < mdata->nintf) {
ctx = ((struct mdss_mdp_video_ctx *) mdata->video_intf) + inum;
if (!ctx->ref_cnt) {
pr_err("Intf %d not in use\n", (inum + MDSS_MDP_INTF0));
return -ENODEV;
}
pr_debug("stop ctl=%d video Intf #%d base=%p", ctl->num,
ctx->intf_num, ctx->base);
} else {
pr_err("Invalid intf number: %d\n", (inum + MDSS_MDP_INTF0));
return -EINVAL;
}
mutex_lock(&ctl->offlock);
if (ctx->timegen_en) {
@ -464,8 +433,7 @@ static int mdss_mdp_video_intfs_stop(struct mdss_mdp_ctl *ctl,
mdp_video_write(ctx, MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 0);
/* wait for at least one VSYNC for proper TG OFF */
frame_rate = mdss_panel_get_framerate
(&(ctl->panel_data->panel_info));
frame_rate = mdss_panel_get_framerate(pinfo);
if (!(frame_rate >= 24 && frame_rate <= 240))
frame_rate = 24;
msleep((1000/frame_rate) + 1);
@ -487,13 +455,10 @@ static int mdss_mdp_video_intfs_stop(struct mdss_mdp_ctl *ctl,
mdss_bus_bandwidth_ctrl(false);
}
list_for_each_entry_safe(handle, tmp, &ctx->vsync_handlers, list)
mdss_mdp_video_remove_vsync_handler(ctl, handle);
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_VSYNC,
(inum + MDSS_MDP_INTF0), NULL, NULL);
ctx->intf_num, NULL, NULL);
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_UNDER_RUN,
(inum + MDSS_MDP_INTF0), NULL, NULL);
ctx->intf_num, NULL, NULL);
ctx->ref_cnt--;
end:
@ -501,6 +466,61 @@ end:
return rc;
}
static int mdss_mdp_video_intfs_stop(struct mdss_mdp_ctl *ctl,
struct mdss_panel_data *pdata, int inum)
{
struct mdss_data_type *mdata;
struct mdss_panel_info *pinfo;
struct mdss_mdp_video_ctx *ctx;
struct mdss_mdp_vsync_handler *tmp, *handle;
int ret = 0;
if (pdata == NULL)
return 0;
mdata = ctl->mdata;
pinfo = &pdata->panel_info;
ctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[MASTER_CTX];
if (!ctx->ref_cnt) {
pr_err("Intf %d not in use\n", (inum + MDSS_MDP_INTF0));
return -ENODEV;
}
pr_debug("stop ctl=%d video Intf #%d base=%p", ctl->num, ctx->intf_num,
ctx->base);
ret = mdss_mdp_video_ctx_stop(ctl, pinfo, ctx);
if (ret) {
pr_err("mdss_mdp_video_ctx_stop failed for intf: %d",
ctx->intf_num);
return -EPERM;
}
if (is_pingpong_split(ctl->mfd)) {
pinfo = &pdata->next->panel_info;
ctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[SLAVE_CTX];
if (!ctx->ref_cnt) {
pr_err("Intf %d not in use\n", (inum + MDSS_MDP_INTF0));
return -ENODEV;
}
pr_debug("stop ctl=%d video Intf #%d base=%p", ctl->num,
ctx->intf_num, ctx->base);
ret = mdss_mdp_video_ctx_stop(ctl, pinfo, ctx);
if (ret) {
pr_err("mdss_mdp_video_ctx_stop failed for intf: %d",
ctx->intf_num);
return -EPERM;
}
}
list_for_each_entry_safe(handle, tmp, &ctx->vsync_handlers, list)
mdss_mdp_video_remove_vsync_handler(ctl, handle);
return 0;
}
static int mdss_mdp_video_stop(struct mdss_mdp_ctl *ctl, int panel_power_state)
{
@ -516,7 +536,7 @@ static int mdss_mdp_video_stop(struct mdss_mdp_ctl *ctl, int panel_power_state)
MDSS_XLOG(ctl->num, ctl->vsync_cnt);
mdss_mdp_ctl_reset(ctl);
ctl->priv_data = NULL;
ctl->intf_ctx[MASTER_CTX] = NULL;
if (ctl->cdm) {
mdss_mdp_cdm_destroy(ctl->cdm);
@ -528,7 +548,7 @@ static int mdss_mdp_video_stop(struct mdss_mdp_ctl *ctl, int panel_power_state)
static void mdss_mdp_video_vsync_intr_done(void *arg)
{
struct mdss_mdp_ctl *ctl = arg;
struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
struct mdss_mdp_video_ctx *ctx = ctl->intf_ctx[MASTER_CTX];
struct mdss_mdp_vsync_handler *tmp;
ktime_t vsync_time;
@ -556,7 +576,7 @@ static void mdss_mdp_video_vsync_intr_done(void *arg)
static int mdss_mdp_video_pollwait(struct mdss_mdp_ctl *ctl)
{
struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
struct mdss_mdp_video_ctx *ctx = ctl->intf_ctx[MASTER_CTX];
u32 mask, status;
int rc;
@ -598,7 +618,7 @@ static int mdss_mdp_video_wait4comp(struct mdss_mdp_ctl *ctl, void *arg)
struct mdss_mdp_video_ctx *ctx;
int rc;
ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
ctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[MASTER_CTX];
if (!ctx) {
pr_err("invalid ctx\n");
return -ENODEV;
@ -774,7 +794,7 @@ static int mdss_mdp_video_dfps_wait4vsync(struct mdss_mdp_ctl *ctl)
int rc = 0;
struct mdss_mdp_video_ctx *ctx;
ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
ctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[MASTER_CTX];
if (!ctx) {
pr_err("invalid ctx\n");
return -ENODEV;
@ -840,9 +860,8 @@ static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl,
int rc = 0;
u32 hsync_period, vsync_period;
struct mdss_data_type *mdata;
u32 inum = ctl->intf_num - MDSS_MDP_INTF0;
ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
ctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[MASTER_CTX];
if (!ctx) {
pr_err("invalid ctx\n");
return -ENODEV;
@ -850,28 +869,15 @@ static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl,
mdata = ctl->mdata;
if (sctl) {
sctx = (struct mdss_mdp_video_ctx *) sctl->priv_data;
sctx = (struct mdss_mdp_video_ctx *) sctl->intf_ctx[MASTER_CTX];
if (!sctx) {
pr_err("invalid ctx\n");
return -ENODEV;
}
} else if (is_pingpong_split(ctl->mfd)) {
/*
* On targets when destination split is enabled, mixer swap
* is not valid. So we can safely assume that ctl->intf_num
* is INTF1. For this case, increment inum to retrieve sctx.
*/
inum += 1;
if (inum < mdata->nintf) {
sctx = ((struct mdss_mdp_video_ctx *)
mdata->video_intf) + inum;
if (!sctx) {
pr_err("invalid sctx\n");
return -ENODEV;
}
} else {
pr_err("Invalid intf number: %d\n",
(inum + MDSS_MDP_INTF0));
sctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[SLAVE_CTX];
if (!sctx) {
pr_err("invalid sctx\n");
return -ENODEV;
}
}
@ -992,7 +998,7 @@ static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg)
pr_debug("kickoff ctl=%d\n", ctl->num);
ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
ctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[MASTER_CTX];
if (!ctx) {
pr_err("invalid ctx\n");
return -ENODEV;
@ -1071,7 +1077,7 @@ int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl,
struct mdss_mdp_ctl *sctl = mdss_mdp_get_split_ctl(ctl);
off = 0;
ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
ctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[MASTER_CTX];
if (!ctx) {
pr_err("invalid ctx for ctl=%d\n", ctl->num);
return -ENODEV;
@ -1218,43 +1224,14 @@ static int mdss_mdp_video_cdm_setup(struct mdss_mdp_cdm *cdm,
setup.output_height = pinfo->yres + pinfo->lcdc.yres_pad;
return mdss_mdp_cdm_setup(cdm, &setup);
}
static int mdss_mdp_video_intfs_setup(struct mdss_mdp_ctl *ctl,
struct mdss_panel_data *pdata, int inum)
static int mdss_mdp_video_ctx_setup(struct mdss_mdp_ctl *ctl,
struct mdss_mdp_video_ctx *ctx, struct mdss_panel_info *pinfo)
{
struct mdss_data_type *mdata;
struct mdss_panel_info *pinfo;
struct mdss_mdp_video_ctx *ctx;
struct intf_timing_params itp = {0};
u32 dst_bpp;
int ret = 0;
struct mdss_data_type *mdata = ctl->mdata;
if (pdata == NULL)
return 0;
if (is_pingpong_split(ctl->mfd)) {
ret = mdss_mdp_video_intfs_setup(ctl, pdata->next, (inum + 1));
if (IS_ERR_VALUE(ret))
return ret;
}
mdata = ctl->mdata;
pinfo = &pdata->panel_info;
if (inum < mdata->nintf) {
ctx = ((struct mdss_mdp_video_ctx *) mdata->video_intf) + inum;
if (ctx->ref_cnt) {
pr_err("Intf %d already in use\n",
(inum + MDSS_MDP_INTF0));
return -EBUSY;
}
pr_debug("video Intf #%d base=%p", ctx->intf_num, ctx->base);
ctx->ref_cnt++;
} else {
pr_err("Invalid intf number: %d\n", (inum + MDSS_MDP_INTF0));
return -EINVAL;
}
ctl->priv_data = ctx;
ctx->intf_type = ctl->intf_type;
init_completion(&ctx->vsync_comp);
spin_lock_init(&ctx->vsync_lock);
@ -1295,10 +1272,10 @@ static int mdss_mdp_video_intfs_setup(struct mdss_mdp_ctl *ctl,
}
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_VSYNC,
(inum + MDSS_MDP_INTF0),
mdss_mdp_video_vsync_intr_done, ctl);
ctx->intf_num, mdss_mdp_video_vsync_intr_done,
ctl);
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_UNDER_RUN,
(inum + MDSS_MDP_INTF0),
ctx->intf_num,
mdss_mdp_video_underrun_intr_done, ctl);
dst_bpp = pinfo->fbc.enabled ? (pinfo->fbc.target_bpp) : (pinfo->bpp);
@ -1337,16 +1314,83 @@ static int mdss_mdp_video_intfs_setup(struct mdss_mdp_ctl *ctl,
itp.hsync_pulse_width >>= 1;
}
if (!ctl->panel_data->panel_info.cont_splash_enabled) {
if (mdss_mdp_video_timegen_setup(ctl, &itp)) {
if (mdss_mdp_video_timegen_setup(ctl, &itp, ctx)) {
pr_err("unable to set timing parameters intfs: %d\n",
(inum + MDSS_MDP_INTF0));
ctx->intf_num);
return -EINVAL;
}
mdss_mdp_fetch_start_config(ctx, ctl);
}
mdp_video_write(ctx, MDSS_MDP_REG_INTF_PANEL_FORMAT, ctl->dst_format);
return 0;
}
static int mdss_mdp_video_intfs_setup(struct mdss_mdp_ctl *ctl,
struct mdss_panel_data *pdata, int inum)
{
struct mdss_data_type *mdata;
struct mdss_panel_info *pinfo;
struct mdss_mdp_video_ctx *ctx;
int ret = 0;
if (pdata == NULL)
return 0;
mdata = ctl->mdata;
pinfo = &pdata->panel_info;
if (inum < mdata->nintf) {
ctx = ((struct mdss_mdp_video_ctx *) mdata->video_intf) + inum;
if (ctx->ref_cnt) {
pr_err("Intf %d already in use\n",
(inum + MDSS_MDP_INTF0));
return -EBUSY;
}
pr_debug("video Intf #%d base=%p", ctx->intf_num, ctx->base);
ctx->ref_cnt++;
} else {
pr_err("Invalid intf number: %d\n", (inum + MDSS_MDP_INTF0));
return -EINVAL;
}
ctl->intf_ctx[MASTER_CTX] = ctx;
ret = mdss_mdp_video_ctx_setup(ctl, ctx, pinfo);
if (ret) {
pr_err("Video context setup failed for interface: %d\n",
ctx->intf_num);
ctx->ref_cnt--;
return -EPERM;
}
if (is_pingpong_split(ctl->mfd)) {
if ((inum + 1) >= mdata->nintf) {
pr_err("Intf not available for ping pong split: (%d)\n",
(inum + 1 + MDSS_MDP_INTF0));
return -EINVAL;
}
ctx = ((struct mdss_mdp_video_ctx *) mdata->video_intf) +
inum + 1;
if (ctx->ref_cnt) {
pr_err("Intf %d already in use\n",
(inum + MDSS_MDP_INTF0));
return -EBUSY;
}
pr_debug("video Intf #%d base=%p", ctx->intf_num, ctx->base);
ctx->ref_cnt++;
ctl->intf_ctx[SLAVE_CTX] = ctx;
pinfo = &pdata->next->panel_info;
ret = mdss_mdp_video_ctx_setup(ctl, ctx, pinfo);
if (ret) {
pr_err("Video context setup failed for interface: %d\n",
ctx->intf_num);
ctx->ref_cnt--;
return -EPERM;
}
}
return 0;
}