summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.c66
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.h8
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_ctl.c229
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pipe.c3
4 files changed, 180 insertions, 126 deletions
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index ce6193746c98..755621a9fd71 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -74,30 +74,18 @@ u32 mdss_mdp_mixer_type_map[MDSS_MDP_MAX_LAYERMIXER] = {
MDSS_MDP_MIXER_TYPE_WRITEBACK,
};
-#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val) \
- { \
+#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val) \
+ { \
.src = MSM_BUS_MASTER_MDP_PORT0, \
.dst = MSM_BUS_SLAVE_EBI_CH0, \
.ab = (ab_val), \
.ib = (ib_val), \
}
-#define MDP_BUS_VECTOR_ENTRY_NDX(n) \
- MDP_BUS_VECTOR_ENTRY((n) * 100000000, (n) * 200000000)
-
static struct msm_bus_vectors mdp_bus_vectors[] = {
- MDP_BUS_VECTOR_ENTRY_NDX(0),
- MDP_BUS_VECTOR_ENTRY_NDX(1),
- MDP_BUS_VECTOR_ENTRY_NDX(2),
- MDP_BUS_VECTOR_ENTRY_NDX(3),
- MDP_BUS_VECTOR_ENTRY_NDX(4),
- MDP_BUS_VECTOR_ENTRY_NDX(5),
- MDP_BUS_VECTOR_ENTRY_NDX(6),
- MDP_BUS_VECTOR_ENTRY_NDX(7),
- MDP_BUS_VECTOR_ENTRY_NDX(8),
- MDP_BUS_VECTOR_ENTRY_NDX(9),
- MDP_BUS_VECTOR_ENTRY_NDX(10),
- MDP_BUS_VECTOR_ENTRY(200000000, 200000000)
+ MDP_BUS_VECTOR_ENTRY(0, 0),
+ MDP_BUS_VECTOR_ENTRY(SZ_128M, SZ_256M),
+ MDP_BUS_VECTOR_ENTRY(SZ_256M, SZ_512M),
};
static struct msm_bus_paths mdp_bus_usecases[ARRAY_SIZE(mdp_bus_vectors)];
static struct msm_bus_scale_pdata mdp_bus_scale_table = {
@@ -270,34 +258,39 @@ static void mdss_mdp_bus_scale_unregister(void)
msm_bus_scale_unregister_client(mdss_res->bus_hdl);
}
-int mdss_mdp_bus_scale_set_min_quota(u32 quota)
+int mdss_mdp_bus_scale_set_quota(u32 ab_quota, u32 ib_quota)
{
- struct msm_bus_scale_pdata *bus_pdata = &mdp_bus_scale_table;
- struct msm_bus_vectors *vect = NULL;
- int lvl;
+ static int current_bus_idx;
+ int bus_idx;
if (mdss_res->bus_hdl < 1) {
pr_err("invalid bus handle %d\n", mdss_res->bus_hdl);
return -EINVAL;
}
- for (lvl = 0; lvl < bus_pdata->num_usecases; lvl++) {
- if (bus_pdata->usecase[lvl].num_paths) {
- vect = &bus_pdata->usecase[lvl].vectors[0];
- if (vect->ab >= quota) {
- pr_debug("lvl=%d quota=%u ab=%u\n", lvl, quota,
- vect->ab);
- break;
- }
+ if ((ab_quota | ib_quota) == 0) {
+ bus_idx = 0;
+ } else {
+ int num_cases = mdp_bus_scale_table.num_usecases;
+ struct msm_bus_vectors *vect = NULL;
+
+ bus_idx = (current_bus_idx % (num_cases - 1)) + 1;
+
+ vect = mdp_bus_scale_table.usecase[current_bus_idx].vectors;
+ if ((ab_quota == vect->ab) && (ib_quota == vect->ib)) {
+ pr_debug("skip bus scaling, no change in vectors\n");
+ return 0;
}
- }
- if (lvl == bus_pdata->num_usecases) {
- pr_warn("cannot match quota=%u try with max level\n", quota);
- lvl--;
- }
+ vect = mdp_bus_scale_table.usecase[bus_idx].vectors;
+ vect->ab = ab_quota;
+ vect->ib = ib_quota;
- return msm_bus_scale_client_update_request(mdss_res->bus_hdl, lvl);
+ pr_debug("bus scale idx=%d ab=%u ib=%u\n", bus_idx,
+ vect->ab, vect->ib);
+ }
+ current_bus_idx = bus_idx;
+ return msm_bus_scale_client_update_request(mdss_res->bus_hdl, bus_idx);
}
static inline u32 mdss_mdp_irq_mask(u32 intr_type, u32 intf_num)
@@ -427,6 +420,8 @@ void mdss_mdp_set_clk_rate(unsigned long min_clk_rate)
pr_debug("mdp clk rate=%lu\n", clk_rate);
}
mutex_unlock(&mdp_clk_lock);
+ } else {
+ pr_err("mdp src clk not setup properly\n");
}
}
@@ -561,6 +556,7 @@ static int mdss_mdp_irq_clk_setup(struct platform_device *pdev)
goto error;
}
regulator_enable(mdss_res->fs);
+ mdss_res->fs_ena = true;
if (mdss_mdp_irq_clk_register(pdev, "bus_clk", MDSS_CLK_AXI) ||
mdss_mdp_irq_clk_register(pdev, "iface_clk", MDSS_CLK_AHB) ||
diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h
index cc516ce0042a..46ef280d5faa 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.h
+++ b/drivers/video/fbdev/msm/mdss_mdp.h
@@ -118,7 +118,10 @@ struct mdss_mdp_ctl {
u16 height;
u32 dst_format;
+ u32 bus_ab_quota;
+ u32 bus_ib_quota;
u32 bus_quota;
+ u32 clk_rate;
struct msm_fb_data_type *mfd;
struct mdss_mdp_mixer *mixer_left;
@@ -144,8 +147,6 @@ struct mdss_mdp_mixer {
u8 cursor_enabled;
u8 rotator_mode;
- u32 bus_quota;
-
struct mdss_mdp_ctl *ctl;
struct mdss_mdp_pipe *stage_pipe[MDSS_MDP_MAX_STAGE];
};
@@ -231,7 +232,6 @@ struct mdss_mdp_pipe {
struct mdss_mdp_format_params *src_fmt;
struct mdss_mdp_plane_sizes src_planes;
- u32 bus_quota;
u8 mixer_stage;
u8 is_fg;
u8 alpha;
@@ -273,7 +273,7 @@ void mdss_mdp_irq_disable_nosync(u32 intr_type, u32 intf_num);
int mdss_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
void (*fnc_ptr)(void *), void *arg);
-int mdss_mdp_bus_scale_set_min_quota(u32 quota);
+int mdss_mdp_bus_scale_set_quota(u32 ab_quota, u32 ib_quota);
void mdss_mdp_set_clk_rate(unsigned long min_clk_rate);
unsigned long mdss_mdp_get_clk_rate(u32 clk_idx);
int mdss_mdp_vsync_clk_enable(int enable);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
index 8b178cdf0270..fca8d087d00f 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -20,122 +20,177 @@
#include "mdss_fb.h"
#include "mdss_mdp.h"
+/* 1.10 bus fudge factor */
+#define MDSS_MDP_BUS_FUDGE_FACTOR(val) ALIGN((((val) * 11) / 10), SZ_16M)
+/* 1.25 clock fudge factor */
+#define MDSS_MDP_CLK_FUDGE_FACTOR(val) (((val) * 5) / 4)
+
enum {
- MDSS_MDP_BUS_UPDATE_SKIP,
- MDSS_MDP_BUS_UPDATE_EARLY,
- MDSS_MDP_BUS_UPDATE_LATE,
+ MDSS_MDP_PERF_UPDATE_SKIP,
+ MDSS_MDP_PERF_UPDATE_EARLY,
+ MDSS_MDP_PERF_UPDATE_LATE,
};
+#define MDSS_MDP_PERF_UPDATE_CLK BIT(0)
+#define MDSS_MDP_PERF_UPDATE_BUS BIT(1)
+#define MDSS_MDP_PERF_UPDATE_ALL -1
+
static DEFINE_MUTEX(mdss_mdp_ctl_lock);
static struct mdss_mdp_ctl mdss_mdp_ctl_list[MDSS_MDP_MAX_CTL];
static struct mdss_mdp_mixer mdss_mdp_mixer_list[MDSS_MDP_MAX_LAYERMIXER];
-static int mdss_mdp_ctl_update_clk_rate(void)
+static int mdss_mdp_ctl_perf_commit(u32 flags)
{
struct mdss_mdp_ctl *ctl;
int cnum;
- unsigned long clk_rate = MDP_CLK_DEFAULT_RATE;
+ unsigned long clk_rate = 0;
+ u32 bus_ab_quota = 0, bus_ib_quota = 0;
- mutex_lock(&mdss_mdp_ctl_lock);
- for (cnum = 0; cnum < MDSS_MDP_MAX_CTL; cnum++) {
- ctl = &mdss_mdp_ctl_list[cnum];
- if (ctl->power_on && ctl->mfd) {
- unsigned long tmp;
- pr_debug("ctl=%d pclk_rate=%u\n", ctl->num,
- ctl->mfd->panel_info.clk_rate);
- tmp = (ctl->mfd->panel_info.clk_rate * 23) / 20;
- if (tmp > clk_rate)
- clk_rate = tmp;
- }
+ if (!flags) {
+ pr_err("nothing to update\n");
+ return -EINVAL;
}
- mdss_mdp_set_clk_rate(clk_rate);
- mutex_unlock(&mdss_mdp_ctl_lock);
-
- return 0;
-}
-
-static int mdss_mdp_ctl_update_bus_scale(void)
-{
- struct mdss_mdp_ctl *ctl;
- int cnum;
- u32 bus_quota = 0;
mutex_lock(&mdss_mdp_ctl_lock);
for (cnum = 0; cnum < MDSS_MDP_MAX_CTL; cnum++) {
ctl = &mdss_mdp_ctl_list[cnum];
- if (ctl->power_on)
- bus_quota += ctl->bus_quota;
+ if (ctl->power_on) {
+ bus_ab_quota += ctl->bus_ab_quota;
+ bus_ib_quota += ctl->bus_ib_quota;
+
+ if (ctl->clk_rate > clk_rate)
+ clk_rate = ctl->clk_rate;
+ }
+ }
+ if (flags & MDSS_MDP_PERF_UPDATE_BUS) {
+ bus_ab_quota = MDSS_MDP_BUS_FUDGE_FACTOR(bus_ab_quota);
+ bus_ib_quota = MDSS_MDP_BUS_FUDGE_FACTOR(bus_ib_quota);
+ mdss_mdp_bus_scale_set_quota(bus_ab_quota, bus_ib_quota);
+ }
+ if (flags & MDSS_MDP_PERF_UPDATE_CLK) {
+ clk_rate = MDSS_MDP_CLK_FUDGE_FACTOR(clk_rate);
+ pr_debug("update clk rate = %lu\n", clk_rate);
+ mdss_mdp_set_clk_rate(clk_rate);
}
- mdss_mdp_bus_scale_set_min_quota(bus_quota);
mutex_unlock(&mdss_mdp_ctl_lock);
return 0;
}
-static void mdss_mdp_bus_update_pipe_quota(struct mdss_mdp_pipe *pipe)
-{
- u32 quota;
-
- quota = pipe->img_width * pipe->img_height * 60 * pipe->src_fmt->bpp;
- quota *= 5 / 4; /* 1.25 factor */
-
- pr_debug("pipe=%d quota old=%u new=%u\n", pipe->num,
- pipe->bus_quota, quota);
- pipe->bus_quota = quota;
-}
-
-static int mdss_mdp_bus_update_mixer_quota(struct mdss_mdp_mixer *mixer)
+static void mdss_mdp_perf_mixer_update(struct mdss_mdp_mixer *mixer,
+ u32 *bus_ab_quota, u32 *bus_ib_quota,
+ u32 *clk_rate)
{
struct mdss_mdp_pipe *pipe;
- u32 quota, stage;
-
- if (!mixer)
- return 0;
+ const int fps = 60;
+ u32 quota, rate;
+ u32 v_total, v_active;
+ int i;
+
+ *bus_ab_quota = 0;
+ *bus_ib_quota = 0;
+ *clk_rate = 0;
+
+ if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
+ struct mdss_panel_info *pinfo = &mixer->ctl->mfd->panel_info;
+ v_total = (pinfo->yres + pinfo->lcdc.v_back_porch +
+ pinfo->lcdc.v_front_porch + pinfo->lcdc.v_pulse_width);
+ v_active = pinfo->yres;
+ } else if (mixer->rotator_mode) {
+ pipe = mixer->stage_pipe[0]; /* rotator pipe */
+ v_total = pipe->flags & MDP_ROT_90 ? pipe->dst.w : pipe->dst.h;
+ v_active = v_total;
+ } else {
+ v_total = mixer->height;
+ v_active = v_total;
+ }
- quota = 0;
- for (stage = 0; stage < MDSS_MDP_MAX_STAGE; stage++) {
- pipe = mixer->stage_pipe[stage];
+ for (i = 0; i < MDSS_MDP_MAX_STAGE; i++) {
+ u32 ib_quota;
+ pipe = mixer->stage_pipe[i];
if (pipe == NULL)
continue;
- quota += pipe->bus_quota;
- }
+ quota = fps * pipe->src.w * pipe->src.h;
+ if (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420)
+ quota = (quota * 3) / 2;
+ else
+ quota *= pipe->src_fmt->bpp;
+
+ if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF)
+ quota = (quota / v_active) * v_total;
+ else
+ quota *= 2; /* bus read + write */
- pr_debug("mixer=%d quota old=%u new=%u\n", mixer->num,
- mixer->bus_quota, quota);
+ rate = pipe->dst.w;
+ if (pipe->src.h > pipe->dst.h) {
+ rate = (rate * pipe->src.h) / pipe->dst.h;
+ ib_quota = (quota / pipe->dst.h) * pipe->src.h;
+ } else {
+ ib_quota = quota;
+ }
+ rate *= v_total * fps;
+ if (mixer->rotator_mode)
+ rate /= 4; /* block mode fetch at 4 pix/clk */
- if (quota != mixer->bus_quota) {
- mixer->bus_quota = quota;
- return 1;
+ *bus_ab_quota += quota;
+ *bus_ib_quota += ib_quota;
+ if (rate > *clk_rate)
+ *clk_rate = rate;
+
+ pr_debug("mixer=%d pnum=%d clk_rate=%u bus ab=%u ib=%u\n",
+ mixer->num, pipe->num, rate, quota, ib_quota);
}
- return 0;
+ pr_debug("final mixer=%d clk_rate=%u bus ab=%u ib=%u\n", mixer->num,
+ *clk_rate, *bus_ab_quota, *bus_ib_quota);
}
-static int mdss_mdp_bus_update_ctl_quota(struct mdss_mdp_ctl *ctl)
+static int mdss_mdp_ctl_perf_update(struct mdss_mdp_ctl *ctl, u32 *flags)
{
- int ret = MDSS_MDP_BUS_UPDATE_SKIP;
+ int ret = MDSS_MDP_PERF_UPDATE_SKIP;
+ u32 clk_rate, ab_quota, ib_quota;
+ u32 max_clk_rate = 0, total_ab_quota = 0, total_ib_quota = 0;
+
+ if (ctl->mixer_left) {
+ mdss_mdp_perf_mixer_update(ctl->mixer_left, &ab_quota,
+ &ib_quota, &clk_rate);
+ total_ab_quota += ab_quota;
+ total_ib_quota += ib_quota;
+ max_clk_rate = clk_rate;
+ }
- if (mdss_mdp_bus_update_mixer_quota(ctl->mixer_left) ||
- mdss_mdp_bus_update_mixer_quota(ctl->mixer_right)) {
- u32 quota = 0;
+ if (ctl->mixer_right) {
+ mdss_mdp_perf_mixer_update(ctl->mixer_right, &ab_quota,
+ &ib_quota, &clk_rate);
+ total_ab_quota += ab_quota;
+ total_ib_quota += ib_quota;
+ if (clk_rate > max_clk_rate)
+ max_clk_rate = clk_rate;
+ }
- if (ctl->mixer_left)
- quota += ctl->mixer_left->bus_quota;
- if (ctl->mixer_right)
- quota += ctl->mixer_right->bus_quota;
+ *flags = 0;
- pr_debug("ctl=%d quota old=%u new=%u\n",
- ctl->num, ctl->bus_quota, quota);
+ if (max_clk_rate != ctl->clk_rate) {
+ if (max_clk_rate > ctl->clk_rate)
+ ret = MDSS_MDP_PERF_UPDATE_EARLY;
+ else
+ ret = MDSS_MDP_PERF_UPDATE_LATE;
+ ctl->clk_rate = max_clk_rate;
+ *flags |= MDSS_MDP_PERF_UPDATE_CLK;
+ }
- if (quota != ctl->bus_quota) {
- if (quota > ctl->bus_quota)
- ret = MDSS_MDP_BUS_UPDATE_EARLY;
+ if ((total_ab_quota != ctl->bus_ab_quota) ||
+ (total_ib_quota != ctl->bus_ib_quota)) {
+ if (ret == MDSS_MDP_PERF_UPDATE_SKIP) {
+ if (total_ib_quota > ctl->bus_ib_quota)
+ ret = MDSS_MDP_PERF_UPDATE_EARLY;
else
- ret = MDSS_MDP_BUS_UPDATE_LATE;
-
- ctl->bus_quota = quota;
+ ret = MDSS_MDP_PERF_UPDATE_LATE;
}
+ ctl->bus_ab_quota = total_ab_quota;
+ ctl->bus_ib_quota = total_ib_quota;
+ *flags |= MDSS_MDP_PERF_UPDATE_BUS;
}
return ret;
@@ -261,6 +316,7 @@ struct mdss_mdp_mixer *mdss_mdp_wb_mixer_alloc(int rotator)
mixer->ctl = ctl;
ctl->start_fnc = mdss_mdp_writeback_start;
+ ctl->power_on = true;
if (ctl->start_fnc)
ctl->start_fnc(ctl);
@@ -442,7 +498,6 @@ int mdss_mdp_ctl_on(struct msm_fb_data_type *mfd)
mutex_lock(&ctl->lock);
ctl->power_on = true;
- mdss_mdp_ctl_update_clk_rate();
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
if (ctl->start_fnc)
@@ -531,8 +586,7 @@ int mdss_mdp_ctl_off(struct msm_fb_data_type *mfd)
ctl->play_cnt = 0;
- mdss_mdp_ctl_update_bus_scale();
- mdss_mdp_ctl_update_clk_rate();
+ mdss_mdp_ctl_perf_commit(MDSS_MDP_PERF_UPDATE_ALL);
mutex_unlock(&ctl->lock);
@@ -705,7 +759,6 @@ int mdss_mdp_mixer_pipe_update(struct mdss_mdp_pipe *pipe, int params_changed)
if (params_changed) {
mixer->params_changed++;
mixer->stage_pipe[pipe->mixer_stage] = pipe;
- mdss_mdp_bus_update_pipe_quota(pipe);
}
if (pipe->type == MDSS_MDP_PIPE_TYPE_DMA)
@@ -764,14 +817,18 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg)
{
int mixer1_changed, mixer2_changed;
int ret = 0;
- int bus_update = MDSS_MDP_BUS_UPDATE_SKIP;
+ int perf_update = MDSS_MDP_PERF_UPDATE_SKIP;
+ u32 update_flags = 0;
if (!ctl) {
pr_err("display function not set\n");
return -ENODEV;
}
- pr_debug("commit ctl=%d\n", ctl->num);
+ if (!ctl->power_on)
+ return 0;
+
+ pr_debug("commit ctl=%d play_cnt=%d\n", ctl->num, ctl->play_cnt);
if (mutex_lock_interruptible(&ctl->lock))
return -EINTR;
@@ -781,7 +838,7 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg)
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
if (mixer1_changed || mixer2_changed) {
- bus_update = mdss_mdp_bus_update_ctl_quota(ctl);
+ perf_update = mdss_mdp_ctl_perf_update(ctl, &update_flags);
if (ctl->prepare_fnc)
ret = ctl->prepare_fnc(ctl, arg);
@@ -790,8 +847,8 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg)
goto done;
}
- if (bus_update == MDSS_MDP_BUS_UPDATE_EARLY)
- mdss_mdp_ctl_update_bus_scale();
+ if (perf_update == MDSS_MDP_PERF_UPDATE_EARLY)
+ mdss_mdp_ctl_perf_commit(update_flags);
if (mixer1_changed)
mdss_mdp_mixer_update(ctl->mixer_left);
@@ -813,8 +870,8 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg)
ctl->play_cnt++;
- if (bus_update == MDSS_MDP_BUS_UPDATE_LATE)
- mdss_mdp_ctl_update_bus_scale();
+ if (perf_update == MDSS_MDP_PERF_UPDATE_LATE)
+ mdss_mdp_ctl_perf_commit(update_flags);
done:
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c
index dbe2a51612bf..3a30ca15fde3 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c
@@ -630,7 +630,8 @@ int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe,
return -ENODEV;
}
- pr_debug("pnum=%x mixer=%d\n", pipe->num, pipe->mixer->num);
+ pr_debug("pnum=%x mixer=%d play_cnt=%u\n", pipe->num,
+ pipe->mixer->num, pipe->play_cnt);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);