123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837 |
- /* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/sched.h>
- #include <linux/time.h>
- #include <linux/init.h>
- #include <linux/interrupt.h>
- #include <linux/hrtimer.h>
- #include <linux/delay.h>
- #include <mach/hardware.h>
- #include <linux/io.h>
- #include <mach/iommu_domains.h>
- #include <asm/system.h>
- #include <asm/mach-types.h>
- #include <linux/semaphore.h>
- #include <linux/spinlock.h>
- #include <linux/fb.h>
- #include "mdp.h"
- #include "msm_fb.h"
- #include "mdp4.h"
- enum {
- WB_OPEN,
- WB_START,
- WB_STOPING,
- WB_STOP
- };
- enum {
- REGISTERED,
- IN_FREE_QUEUE,
- IN_BUSY_QUEUE,
- WITH_CLIENT
- };
- #define MAX_CONTROLLER 1
- #define VSYNC_EXPIRE_TICK 0
- static struct vsycn_ctrl {
- struct device *dev;
- int inited;
- int update_ndx;
- u32 ov_koff;
- u32 ov_done;
- atomic_t suspend;
- struct mutex update_lock;
- struct completion ov_comp;
- spinlock_t spin_lock;
- struct msm_fb_data_type *mfd;
- struct mdp4_overlay_pipe *base_pipe;
- struct vsync_update vlist[2];
- struct work_struct clk_work;
- } vsync_ctrl_db[MAX_CONTROLLER];
- static void vsync_irq_enable(int intr, int term)
- {
- unsigned long flag;
- spin_lock_irqsave(&mdp_spin_lock, flag);
- /* no need to clrear other interrupts for comamnd mode */
- mdp_intr_mask |= intr;
- outp32(MDP_INTR_ENABLE, mdp_intr_mask);
- mdp_enable_irq(term);
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
- }
- static void vsync_irq_disable(int intr, int term)
- {
- unsigned long flag;
- spin_lock_irqsave(&mdp_spin_lock, flag);
- /* no need to clrear other interrupts for comamnd mode */
- mdp_intr_mask &= ~intr;
- outp32(MDP_INTR_ENABLE, mdp_intr_mask);
- mdp_disable_irq_nosync(term);
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
- }
- static int mdp4_overlay_writeback_update(struct msm_fb_data_type *mfd);
- static void mdp4_wfd_queue_wakeup(struct msm_fb_data_type *mfd,
- struct msmfb_writeback_data_list *node);
- static void mdp4_wfd_dequeue_update(struct msm_fb_data_type *mfd,
- struct msmfb_writeback_data_list **wfdnode);
- static int is_wb_operation_allowed(struct msm_fb_data_type *mfd);
- int mdp4_overlay_writeback_on(struct platform_device *pdev)
- {
- struct msm_fb_data_type *mfd;
- struct fb_info *fbi;
- uint8 *buf;
- struct mdp4_overlay_pipe *pipe;
- int bpp;
- int ret;
- uint32 data;
- struct vsycn_ctrl *vctrl;
- int cndx = 0;
- mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
- if (!mfd)
- return -ENODEV;
- if (mfd->key != MFD_KEY)
- return -EINVAL;
- vctrl = &vsync_ctrl_db[cndx];
- vctrl->mfd = mfd;
- vctrl->dev = mfd->fbi->dev;
- fbi = mfd->fbi;
- bpp = fbi->var.bits_per_pixel / 8;
- buf = (uint8 *) fbi->fix.smem_start;
- buf += fbi->var.xoffset * bpp +
- fbi->var.yoffset * fbi->fix.line_length;
- /* MDP cmd block enable */
- mdp_clk_ctrl(1);
- if (vctrl->base_pipe == NULL) {
- pipe = mdp4_overlay_pipe_alloc(OVERLAY_TYPE_BF, MDP4_MIXER2);
- if (pipe == NULL) {
- pr_info("%s: pipe_alloc failed\n", __func__);
- return -EIO;
- }
- pipe->pipe_used++;
- pipe->mixer_stage = MDP4_MIXER_STAGE_BASE;
- pipe->mixer_num = MDP4_MIXER2;
- pipe->src_format = MDP_ARGB_8888;
- mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_WRITEBACK);
- ret = mdp4_overlay_format2pipe(pipe);
- if (ret < 0)
- pr_info("%s: format2type failed\n", __func__);
- vctrl->base_pipe = pipe; /* keep it */
- } else {
- pipe = vctrl->base_pipe;
- }
- ret = panel_next_on(pdev);
- /* MDP_LAYERMIXER_WB_MUX_SEL to use mixer1 axi for mixer2 writeback */
- if (hdmi_prim_display)
- data = 0x01;
- else
- data = 0x02;
- outpdw(MDP_BASE + 0x100F4, data);
- MDP_OUTP(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x5004,
- ((0x0 & 0xFFF) << 16) | /* 12-bit B */
- (0x0 & 0xFFF)); /* 12-bit G */
- /* MSP_BORDER_COLOR */
- MDP_OUTP(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x5008,
- (0x0 & 0xFFF)); /* 12-bit R */
- mdp_clk_ctrl(0);
- return ret;
- }
- int mdp4_overlay_writeback_off(struct platform_device *pdev)
- {
- int cndx = 0;
- struct msm_fb_data_type *mfd;
- struct vsycn_ctrl *vctrl;
- struct mdp4_overlay_pipe *pipe;
- int ret = 0;
- int undx;
- struct vsync_update *vp;
- pr_debug("%s+:\n", __func__);
- mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
- vctrl = &vsync_ctrl_db[cndx];
- pipe = vctrl->base_pipe;
- if (pipe == NULL) {
- pr_err("%s: NO base pipe\n", __func__);
- return ret;
- }
- /* sanity check, free pipes besides base layer */
- mdp4_overlay_unset_mixer(pipe->mixer_num);
- mdp4_mixer_stage_down(pipe, 1);
- mdp4_overlay_pipe_free(pipe);
- vctrl->base_pipe = NULL;
- undx = vctrl->update_ndx;
- vp = &vctrl->vlist[undx];
- if (vp->update_cnt) {
- /*
- * pipe's iommu will be freed at next overlay play
- * and iommu_drop statistic will be increased by one
- */
- vp->update_cnt = 0; /* empty queue */
- }
- ret = panel_next_off(pdev);
- mdp_clk_ctrl(1);
- /* MDP_LAYERMIXER_WB_MUX_SEL to restore to default cfg*/
- outpdw(MDP_BASE + 0x100F4, 0x0);
- mdp_clk_ctrl(0);
- pr_debug("%s-:\n", __func__);
- return ret;
- }
- static int mdp4_overlay_writeback_update(struct msm_fb_data_type *mfd)
- {
- struct fb_info *fbi;
- uint8 *buf;
- unsigned int buf_offset;
- struct mdp4_overlay_pipe *pipe;
- int bpp;
- int cndx = 0;
- struct vsycn_ctrl *vctrl;
- if (mfd->key != MFD_KEY)
- return -ENODEV;
- fbi = mfd->fbi;
- vctrl = &vsync_ctrl_db[cndx];
- pipe = vctrl->base_pipe;
- if (!pipe) {
- pr_err("%s: no base layer pipe\n", __func__);
- return -EINVAL;
- }
- bpp = fbi->var.bits_per_pixel / 8;
- buf = (uint8 *) fbi->fix.smem_start;
- buf_offset = fbi->var.xoffset * bpp +
- fbi->var.yoffset * fbi->fix.line_length;
- /* MDP cmd block enable */
- mdp_clk_ctrl(1);
- pipe->src_height = fbi->var.yres;
- pipe->src_width = fbi->var.xres;
- pipe->src_h = fbi->var.yres;
- pipe->src_w = fbi->var.xres;
- pipe->dst_h = fbi->var.yres;
- pipe->dst_w = fbi->var.xres;
- pipe->srcp0_ystride = fbi->fix.line_length;
- pipe->src_y = 0;
- pipe->src_x = 0;
- pipe->dst_y = 0;
- pipe->dst_x = 0;
- mdp4_overlay_mdp_pipe_req(pipe, mfd);
- mdp4_calc_blt_mdp_bw(mfd, pipe);
- if (mfd->display_iova)
- pipe->srcp0_addr = mfd->display_iova + buf_offset;
- else
- pipe->srcp0_addr = (uint32)(buf + buf_offset);
- mdp4_mixer_stage_up(pipe, 0);
- mdp4_overlayproc_cfg(pipe);
- if (hdmi_prim_display)
- outpdw(MDP_BASE + 0x100F4, 0x01);
- else
- outpdw(MDP_BASE + 0x100F4, 0x02);
- /* MDP cmd block disable */
- mdp_clk_ctrl(0);
- wmb();
- return 0;
- }
- /*
- * mdp4_wfd_piep_queue:
- * called from thread context
- */
- void mdp4_wfd_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe)
- {
- struct vsycn_ctrl *vctrl;
- struct vsync_update *vp;
- struct mdp4_overlay_pipe *pp;
- int undx;
- if (cndx >= MAX_CONTROLLER) {
- pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
- return;
- }
- vctrl = &vsync_ctrl_db[cndx];
- if (atomic_read(&vctrl->suspend) > 0)
- return;
- mutex_lock(&vctrl->update_lock);
- undx = vctrl->update_ndx;
- vp = &vctrl->vlist[undx];
- pp = &vp->plist[pipe->pipe_ndx - 1]; /* ndx start form 1 */
- pr_debug("%s: vndx=%d pipe_ndx=%d pid=%d\n", __func__,
- undx, pipe->pipe_ndx, current->pid);
- *pp = *pipe; /* clone it */
- vp->update_cnt++;
- mutex_unlock(&vctrl->update_lock);
- mdp4_stat.overlay_play[pipe->mixer_num]++;
- }
- static void mdp4_wfd_wait4ov(int cndx);
- int mdp4_wfd_pipe_commit(struct msm_fb_data_type *mfd,
- int cndx, int wait)
- {
- int i, undx;
- int mixer = 0;
- struct vsycn_ctrl *vctrl;
- struct vsync_update *vp;
- struct mdp4_overlay_pipe *pipe;
- struct mdp4_overlay_pipe *real_pipe;
- unsigned long flags;
- int cnt = 0;
- struct msmfb_writeback_data_list *node = NULL;
- rc = is_wb_operation_allowed(mfd);
- if (rc) {
- pr_debug("%s: Unable to commit, error = %d", __func__, rc);
- return rc;
- }
- vctrl = &vsync_ctrl_db[cndx];
- mutex_lock(&vctrl->update_lock);
- undx = vctrl->update_ndx;
- vp = &vctrl->vlist[undx];
- pipe = vctrl->base_pipe;
- mixer = pipe->mixer_num;
- if (vp->update_cnt == 0) {
- mutex_unlock(&vctrl->update_lock);
- return cnt;
- }
- vctrl->update_ndx++;
- vctrl->update_ndx &= 0x01;
- vp->update_cnt = 0; /* reset */
- mutex_unlock(&vctrl->update_lock);
- mdp4_wfd_dequeue_update(mfd, &node);
- /* free previous committed iommu back to pool */
- mdp4_overlay_iommu_unmap_freelist(mixer);
- pipe = vp->plist;
- for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
- if (pipe->pipe_used) {
- cnt++;
- real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx);
- if (real_pipe && real_pipe->pipe_used) {
- /* pipe not unset */
- mdp4_overlay_vsync_commit(pipe);
- }
- /* free previous iommu to freelist
- * which will be freed at next
- * pipe_commit
- */
- mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0);
- pipe->pipe_used = 0; /* clear */
- }
- }
- mdp_clk_ctrl(1);
- mdp4_mixer_stage_commit(mixer);
- pipe = vctrl->base_pipe;
- spin_lock_irqsave(&vctrl->spin_lock, flags);
- vctrl->ov_koff++;
- INIT_COMPLETION(vctrl->ov_comp);
- vsync_irq_enable(INTR_OVERLAY2_DONE, MDP_OVERLAY2_TERM);
- pr_debug("%s: kickoff\n", __func__);
- /* kickoff overlay engine */
- mdp4_stat.kickoff_ov2++;
- outpdw(MDP_BASE + 0x00D0, 0);
- mb(); /* make sure kickoff executed */
- spin_unlock_irqrestore(&vctrl->spin_lock, flags);
- mdp4_stat.overlay_commit[pipe->mixer_num]++;
- if (wait)
- mdp4_wfd_wait4ov(cndx);
- mdp4_wfd_queue_wakeup(mfd, node);
- return cnt;
- }
- static void clk_ctrl_work(struct work_struct *work)
- {
- struct vsycn_ctrl *vctrl =
- container_of(work, typeof(*vctrl), clk_work);
- mdp_clk_ctrl(0);
- }
- void mdp4_wfd_init(int cndx)
- {
- struct vsycn_ctrl *vctrl;
- if (cndx >= MAX_CONTROLLER) {
- pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
- return;
- }
- vctrl = &vsync_ctrl_db[cndx];
- if (vctrl->inited)
- return;
- vctrl->inited = 1;
- vctrl->update_ndx = 0;
- mutex_init(&vctrl->update_lock);
- init_completion(&vctrl->ov_comp);
- spin_lock_init(&vctrl->spin_lock);
- INIT_WORK(&vctrl->clk_work, clk_ctrl_work);
- }
- static void mdp4_wfd_wait4ov(int cndx)
- {
- struct vsycn_ctrl *vctrl;
- if (cndx >= MAX_CONTROLLER) {
- pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
- return;
- }
- vctrl = &vsync_ctrl_db[cndx];
- if (atomic_read(&vctrl->suspend) > 0)
- return;
- wait_for_completion(&vctrl->ov_comp);
- }
- void mdp4_overlay2_done_wfd(struct mdp_dma_data *dma)
- {
- struct vsycn_ctrl *vctrl;
- struct mdp4_overlay_pipe *pipe;
- int cndx = 0;
- vctrl = &vsync_ctrl_db[cndx];
- pipe = vctrl->base_pipe;
- spin_lock(&vctrl->spin_lock);
- vsync_irq_disable(INTR_OVERLAY2_DONE, MDP_OVERLAY2_TERM);
- vctrl->ov_done++;
- complete(&vctrl->ov_comp);
- schedule_work(&vctrl->clk_work);
- pr_debug("%s ovdone interrupt\n", __func__);
- spin_unlock(&vctrl->spin_lock);
- }
- void mdp4_writeback_overlay(struct msm_fb_data_type *mfd)
- {
- struct vsycn_ctrl *vctrl;
- struct mdp4_overlay_pipe *pipe;
- if (mfd && !mfd->panel_power_on)
- return;
- pr_debug("%s:+ mfd=%x\n", __func__, (int)mfd);
- vctrl = &vsync_ctrl_db[0];
- pipe = vctrl->base_pipe;
- mutex_lock(&mfd->dma->ov_mutex);
- if (pipe->pipe_type == OVERLAY_TYPE_RGB)
- mdp4_wfd_pipe_queue(0, pipe);
- mdp4_overlay_mdp_perf_upd(mfd, 1);
- mdp4_wfd_pipe_commit(mfd, 0, 1);
- mdp4_overlay_mdp_perf_upd(mfd, 0);
- mutex_unlock(&mfd->dma->ov_mutex);
- }
- static int mdp4_overlay_writeback_register_buffer(
- struct msm_fb_data_type *mfd, struct msmfb_writeback_data_list *node)
- {
- if (!node) {
- pr_err("Cannot register a NULL node\n");
- return -EINVAL;
- }
- node->state = REGISTERED;
- list_add_tail(&node->registered_entry, &mfd->writeback_register_queue);
- return 0;
- }
- static struct msmfb_writeback_data_list *get_if_registered(
- struct msm_fb_data_type *mfd, struct msmfb_data *data)
- {
- struct msmfb_writeback_data_list *temp;
- bool found = false;
- int domain;
- if (!list_empty(&mfd->writeback_register_queue)) {
- list_for_each_entry(temp,
- &mfd->writeback_register_queue,
- registered_entry) {
- if (temp && temp->buf_info.iova == data->iova) {
- found = true;
- break;
- }
- }
- }
- if (!found) {
- temp = kzalloc(sizeof(struct msmfb_writeback_data_list),
- GFP_KERNEL);
- if (temp == NULL) {
- pr_err("%s: out of memory\n", __func__);
- goto register_alloc_fail;
- }
- temp->ihdl = NULL;
- if (data->iova)
- temp->addr = (void *)(data->iova + data->offset);
- else if (mfd->iclient) {
- struct ion_handle *srcp_ihdl;
- ulong len;
- srcp_ihdl = ion_import_dma_buf(mfd->iclient,
- data->memory_id);
- if (IS_ERR_OR_NULL(srcp_ihdl)) {
- pr_err("%s: ion import fd failed\n", __func__);
- goto register_ion_fail;
- }
- if (mdp_iommu_split_domain)
- domain = DISPLAY_WRITE_DOMAIN;
- else
- domain = DISPLAY_READ_DOMAIN;
- if (ion_map_iommu(mfd->iclient,
- srcp_ihdl,
- domain,
- GEN_POOL,
- SZ_4K,
- 0,
- (ulong *)&temp->addr,
- (ulong *)&len,
- 0,
- ION_IOMMU_UNMAP_DELAYED)) {
- ion_free(mfd->iclient, srcp_ihdl);
- pr_err("%s: unable to get ion mapping addr\n",
- __func__);
- goto register_ion_fail;
- }
- temp->addr += data->offset;
- temp->ihdl = srcp_ihdl;
- }
- else {
- pr_err("%s: only support ion memory\n", __func__);
- goto register_ion_fail;
- }
- memcpy(&temp->buf_info, data, sizeof(struct msmfb_data));
- if (mdp4_overlay_writeback_register_buffer(mfd, temp)) {
- pr_err("%s: error registering node\n", __func__);
- goto register_ion_fail;
- }
- }
- return temp;
- register_ion_fail:
- kfree(temp);
- register_alloc_fail:
- return NULL;
- }
- int mdp4_writeback_start(
- struct fb_info *info)
- {
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- mutex_lock(&mfd->writeback_mutex);
- mfd->writeback_state = WB_START;
- mutex_unlock(&mfd->writeback_mutex);
- wake_up(&mfd->wait_q);
- return 0;
- }
- int mdp4_writeback_queue_buffer(struct fb_info *info, struct msmfb_data *data)
- {
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- struct msmfb_writeback_data_list *node = NULL;
- int rv = 0;
- mutex_lock(&mfd->writeback_mutex);
- node = get_if_registered(mfd, data);
- if (!node || node->state == IN_BUSY_QUEUE ||
- node->state == IN_FREE_QUEUE) {
- pr_err("memory not registered or Buffer already with us\n");
- rv = -EINVAL;
- goto exit;
- }
- list_add_tail(&node->active_entry, &mfd->writeback_free_queue);
- node->state = IN_FREE_QUEUE;
- exit:
- mutex_unlock(&mfd->writeback_mutex);
- return rv;
- }
- static int is_buffer_ready(struct msm_fb_data_type *mfd)
- {
- int rc;
- mutex_lock(&mfd->writeback_mutex);
- rc = !list_empty(&mfd->writeback_busy_queue) ||
- (mfd->writeback_state == WB_STOPING);
- mutex_unlock(&mfd->writeback_mutex);
- return rc;
- }
- int mdp4_writeback_dequeue_buffer(struct fb_info *info, struct msmfb_data *data)
- {
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- struct msmfb_writeback_data_list *node = NULL;
- int rc = 0, domain;
- rc = wait_event_interruptible(mfd->wait_q, is_buffer_ready(mfd));
- if (rc) {
- pr_err("failed to get dequeued buffer\n");
- return -ENOBUFS;
- }
- mutex_lock(&mfd->writeback_mutex);
- if (mfd->writeback_state == WB_STOPING) {
- mfd->writeback_state = WB_STOP;
- mutex_unlock(&mfd->writeback_mutex);
- return -ENOBUFS;
- } else if (!list_empty(&mfd->writeback_busy_queue)) {
- node = list_first_entry(&mfd->writeback_busy_queue,
- struct msmfb_writeback_data_list, active_entry);
- }
- if (node) {
- list_del(&node->active_entry);
- node->state = WITH_CLIENT;
- memcpy(data, &node->buf_info, sizeof(struct msmfb_data));
- if (!data->iova)
- if (mfd->iclient && node->ihdl) {
- if (mdp_iommu_split_domain)
- domain = DISPLAY_WRITE_DOMAIN;
- else
- domain = DISPLAY_READ_DOMAIN;
- ion_unmap_iommu(mfd->iclient,
- node->ihdl,
- domain,
- GEN_POOL);
- ion_free(mfd->iclient,
- node->ihdl);
- }
- } else {
- pr_err("node is NULL. Somebody else dequeued?\n");
- rc = -ENOBUFS;
- }
- mutex_unlock(&mfd->writeback_mutex);
- return rc;
- }
- static bool is_writeback_inactive(struct msm_fb_data_type *mfd)
- {
- bool active;
- mutex_lock(&mfd->writeback_mutex);
- active = !mfd->writeback_active_cnt;
- mutex_unlock(&mfd->writeback_mutex);
- return active;
- }
- int mdp4_writeback_stop(struct fb_info *info)
- {
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- mutex_lock(&mfd->writeback_mutex);
- mfd->writeback_state = WB_STOPING;
- mutex_unlock(&mfd->writeback_mutex);
- /* Wait for all pending writebacks to finish */
- wait_event_interruptible(mfd->wait_q, is_writeback_inactive(mfd));
- /* Wake up dequeue thread in case of no UI update*/
- wake_up(&mfd->wait_q);
- return 0;
- }
- int mdp4_writeback_init(struct fb_info *info)
- {
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- mutex_init(&mfd->writeback_mutex);
- mutex_init(&mfd->unregister_mutex);
- INIT_LIST_HEAD(&mfd->writeback_free_queue);
- INIT_LIST_HEAD(&mfd->writeback_busy_queue);
- INIT_LIST_HEAD(&mfd->writeback_register_queue);
- mfd->writeback_state = WB_OPEN;
- init_waitqueue_head(&mfd->wait_q);
- return 0;
- }
- int mdp4_writeback_terminate(struct fb_info *info)
- {
- struct list_head *ptr, *next;
- struct msmfb_writeback_data_list *temp;
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- int rc = 0;
- mutex_lock(&mfd->unregister_mutex);
- mutex_lock(&mfd->writeback_mutex);
- if (mfd->writeback_state != WB_STOPING &&
- mfd->writeback_state != WB_STOP) {
- pr_err("%s called without stopping\n", __func__);
- rc = -EPERM;
- goto terminate_err;
- }
- if (!list_empty(&mfd->writeback_register_queue)) {
- list_for_each_safe(ptr, next,
- &mfd->writeback_register_queue) {
- temp = list_entry(ptr,
- struct msmfb_writeback_data_list,
- registered_entry);
- list_del(&temp->registered_entry);
- kfree(temp);
- }
- }
- INIT_LIST_HEAD(&mfd->writeback_register_queue);
- INIT_LIST_HEAD(&mfd->writeback_busy_queue);
- INIT_LIST_HEAD(&mfd->writeback_free_queue);
- terminate_err:
- mutex_unlock(&mfd->writeback_mutex);
- mutex_unlock(&mfd->unregister_mutex);
- return rc;
- }
- static void mdp4_wfd_dequeue_update(struct msm_fb_data_type *mfd,
- struct msmfb_writeback_data_list **wfdnode)
- {
- struct vsycn_ctrl *vctrl;
- struct mdp4_overlay_pipe *pipe;
- struct msmfb_writeback_data_list *node = NULL;
- if (mfd && !mfd->panel_power_on)
- return;
- pr_debug("%s:+ mfd=%x\n", __func__, (int)mfd);
- vctrl = &vsync_ctrl_db[0];
- pipe = vctrl->base_pipe;
- mutex_lock(&mfd->unregister_mutex);
- mutex_lock(&mfd->writeback_mutex);
- if (!list_empty(&mfd->writeback_free_queue)
- && mfd->writeback_state != WB_STOPING
- && mfd->writeback_state != WB_STOP) {
- node = list_first_entry(&mfd->writeback_free_queue,
- struct msmfb_writeback_data_list, active_entry);
- }
- if (node) {
- list_del(&(node->active_entry));
- node->state = IN_BUSY_QUEUE;
- mfd->writeback_active_cnt++;
- }
- mutex_unlock(&mfd->writeback_mutex);
- pipe->ov_blt_addr = (ulong) (node ? node->addr : NULL);
- if (!pipe->ov_blt_addr) {
- pr_err("%s: no writeback buffer 0x%x, %pK\n", __func__,
- (unsigned int)pipe->ov_blt_addr, node);
- mutex_unlock(&mfd->unregister_mutex);
- return;
- }
- mdp4_overlay_writeback_update(mfd);
- *wfdnode = node;
- mutex_unlock(&mfd->unregister_mutex);
- }
- static void mdp4_wfd_queue_wakeup(struct msm_fb_data_type *mfd,
- struct msmfb_writeback_data_list *node)
- {
- if (mfd && !mfd->panel_power_on)
- return;
- if (node == NULL)
- return;
- pr_debug("%s: mfd=%x node: %pK", __func__, (int)mfd, node);
- mutex_lock(&mfd->writeback_mutex);
- list_add_tail(&node->active_entry, &mfd->writeback_busy_queue);
- mfd->writeback_active_cnt--;
- mutex_unlock(&mfd->writeback_mutex);
- wake_up(&mfd->wait_q);
- }
- int mdp4_writeback_set_mirroring_hint(struct fb_info *info, int hint)
- {
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- if (mfd->panel.type != WRITEBACK_PANEL)
- return -ENOTSUPP;
- switch (hint) {
- case MDP_WRITEBACK_MIRROR_ON:
- case MDP_WRITEBACK_MIRROR_PAUSE:
- case MDP_WRITEBACK_MIRROR_RESUME:
- case MDP_WRITEBACK_MIRROR_OFF:
- pr_info("wfd state switched to %d\n", hint);
- switch_set_state(&mfd->writeback_sdev, hint);
- return 0;
- default:
- return -EINVAL;
- }
- }
|