video: rockchip: lcdc: add support dmc

Register dmc notify after than dmc driver.

Change-Id: I11c7daee1b4882da87d209854f0bda980c14551b
Signed-off-by: Huang Jiachai <hjc@rock-chips.com>
Signed-off-by: Jianqun Xu <jay.xu@rock-chips.com>
This commit is contained in:
Huang Jiachai
2016-08-05 16:50:16 +08:00
committed by Huang, Tao
parent b403b6bc55
commit 3018fa691e
4 changed files with 131 additions and 1 deletions

View File

@@ -27,6 +27,7 @@
#include <linux/slab.h>
#include <linux/suspend.h>
#include <soc/rockchip/rkfb_dmc.h>
#include <soc/rockchip/rockchip_sip.h>
struct dram_timing {
@@ -508,6 +509,9 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
data->dev = dev;
platform_set_drvdata(pdev, data);
if (vop_register_dmc())
dev_err(dev, "fail to register notify to vop.\n");
return 0;
}

View File

@@ -27,6 +27,8 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/devfreq.h>
#include <linux/devfreq-event.h>
#include <linux/rockchip-iovmm.h>
#include <asm/div64.h>
#include <linux/uaccess.h>
@@ -34,6 +36,7 @@
#include <linux/rockchip/grf.h>
#include <linux/rockchip/common.h>
#include <dt-bindings/clock/rk_system_status.h>
#include <soc/rockchip/rkfb_dmc.h>
#include "rk322x_lcdc.h"
@@ -2176,16 +2179,45 @@ static void vop_layer_enable(struct vop_device *vop_dev,
/* if no layer used,disable lcdc */
if (vop_dev->prop == EXTEND) {
if (!vop_dev->atv_layer_cnt && !open) {
if (!wait_event_timeout(vop_dev->wait_dmc_queue,
!vop_dev->dmc_in_process, HZ / 5))
dev_warn(vop_dev->dev,
"Timeout waiting for dmc when vop disable\n");
vop_dev->vop_switch_status = 1;
vop_early_suspend(&vop_dev->driver);
dev_info(vop_dev->dev,
"no layer is used,go to standby!\n");
vop_dev->standby = 1;
vop_dev->vop_switch_status = 0;
wake_up(&vop_dev->wait_vop_switch_queue);
/*
* if clsoe enxtend vop need to enable dmc again.
*/
if (vop_dev->devfreq) {
if (vop_dev->devfreq_event_dev)
devfreq_event_enable_edev(vop_dev->devfreq_event_dev);
devfreq_resume_device(vop_dev->devfreq);
}
} else if (open) {
vop_early_resume(&vop_dev->driver);
vop_dev->vop_switch_status = 0;
wake_up(&vop_dev->wait_vop_switch_queue);
/* if enable two vop, need to disable dmc */
if (vop_dev->devfreq) {
if (vop_dev->devfreq_event_dev)
devfreq_event_disable_edev(vop_dev->devfreq_event_dev);
devfreq_suspend_device(vop_dev->devfreq);
}
dev_info(vop_dev->dev, "wake up from standby!\n");
}
} else if (vop_dev->prop == PRMRY) {
if ((open) && (!vop_dev->atv_layer_cnt)) {
vop_dev->vop_switch_status = 0;
wake_up(&vop_dev->wait_vop_switch_queue);
}
}
}
static int vop_enable_irq(struct rk_lcdc_driver *dev_drv)
@@ -2207,6 +2239,31 @@ static int vop_enable_irq(struct rk_lcdc_driver *dev_drv)
return 0;
}
static int dmc_notify(struct notifier_block *nb, unsigned long event,
void *data)
{
struct vop_device *vop = container_of(nb, struct vop_device, dmc_nb);
if (event == DEVFREQ_PRECHANGE) {
/*
* check if vop in enable or disable process,
* if yes, wait until it finish, use 200ms as
* timeout.
*/
if (!wait_event_timeout(vop->wait_vop_switch_queue,
!vop->vop_switch_status, HZ / 5))
dev_warn(vop->dev,
"Timeout waiting for vop swtich status\n");
vop->dmc_in_process = 1;
} else if (event == DEVFREQ_POSTCHANGE) {
vop->dmc_in_process = 0;
wake_up(&vop->wait_dmc_queue);
}
return NOTIFY_OK;
}
static int vop_open(struct rk_lcdc_driver *dev_drv, int win_id,
bool open)
{
@@ -2216,6 +2273,11 @@ static int vop_open(struct rk_lcdc_driver *dev_drv, int win_id,
/* enable clk,when first layer open */
if ((open) && (!vop_dev->atv_layer_cnt)) {
/* rockchip_set_system_status(sys_status); */
if (!wait_event_timeout(vop_dev->wait_dmc_queue,
!vop_dev->dmc_in_process, HZ / 5))
dev_warn(vop_dev->dev,
"Timeout waiting for dmc when vop enable\n");
vop_dev->vop_switch_status = 1;
vop_pre_init(dev_drv);
vop_clk_enable(vop_dev);
vop_enable_irq(dev_drv);
@@ -4890,6 +4952,46 @@ static int vop_parse_dt(struct vop_device *vop_dev)
return 0;
}
static struct platform_device *rk322x_pdev;
int vop_register_dmc(void)
{
struct platform_device *pdev = rk322x_pdev;
struct vop_device *vop_dev;
struct device *dev = &pdev->dev;
struct devfreq *devfreq;
struct devfreq_event_dev *event_dev;
if (!pdev)
return -ENODEV;
vop_dev = platform_get_drvdata(pdev);;
if (!vop_dev)
return -ENODEV;
dev = &pdev->dev;
devfreq = devfreq_get_devfreq_by_phandle(dev, 0);
if (IS_ERR(devfreq)) {
dev_err(vop_dev->dev, "fail to get devfreq for dmc\n");
return -ENODEV;
}
vop_dev->devfreq = devfreq;
vop_dev->dmc_nb.notifier_call = dmc_notify;
devfreq_register_notifier(vop_dev->devfreq, &vop_dev->dmc_nb,
DEVFREQ_TRANSITION_NOTIFIER);
event_dev = devfreq_event_get_edev_by_phandle(vop_dev->devfreq->dev.parent,
0);
if (IS_ERR(event_dev)) {
dev_err(vop_dev->dev, "fail to get edev for dmc\n");
return -ENODEV;
}
vop_dev->devfreq_event_dev = event_dev;
return 0;
}
static int vop_probe(struct platform_device *pdev)
{
struct vop_device *vop_dev = NULL;
@@ -4998,6 +5100,11 @@ static int vop_probe(struct platform_device *pdev)
vop_dev->data->win[3].property.feature &= ~SUPPORT_HW_EXIST;
}
init_waitqueue_head(&vop_dev->wait_vop_switch_queue);
vop_dev->vop_switch_status = 0;
init_waitqueue_head(&vop_dev->wait_dmc_queue);
vop_dev->dmc_in_process = 0;
ret = rk_fb_register(dev_drv, vop_dev->data->win, vop_dev->id);
if (ret < 0) {
dev_err(dev, "register fb for lcdc%d failed!\n", vop_dev->id);
@@ -5007,6 +5114,8 @@ static int vop_probe(struct platform_device *pdev)
dev_info(dev, "lcdc%d probe ok, iommu %s\n",
vop_dev->id, dev_drv->iommu_enabled ? "enabled" : "disabled");
rk322x_pdev = pdev;
return 0;
}

View File

@@ -1432,6 +1432,13 @@ struct vop_device {
/* lock vop irq reg */
spinlock_t irq_lock;
struct devfreq *devfreq;
struct devfreq_event_dev *devfreq_event_dev;
struct notifier_block dmc_nb;
int dmc_in_process;
int vop_switch_status;
wait_queue_head_t wait_dmc_queue;
wait_queue_head_t wait_vop_switch_queue;
};
static inline void vop_writel(struct vop_device *vop_dev, u32 offset, u32 v)

View File

@@ -0,0 +1,10 @@
/*
* Rockchip devfb driver will probe earlier than devfreq, so it needs to register
* dmc_notify after than rk3399 dmc driver.
*/
#if defined(CONFIG_LCDC_RK322X)
int vop_register_dmc(void);
#else
static inline int vop_register_dmc(void) { return 0;};
#endif