int find_subdev_mipi(struct decon_device *decon)
{
	struct exynos_md *md;

	if (decon->id && decon->pdata->dsi_mode == DSI_MODE_SINGLE) {
		decon_err("failed to get subdev of dsim\n");
		return -EINVAL;
	}

	md = (struct exynos_md *)module_name_to_driver_data(MDEV_MODULE_NAME);
	if (!md) {
		decon_err("failed to get mdev device(%d)\n", decon->id);
		return -ENODEV;
	}

	decon->output_sd = md->dsim_sd[decon->id];
	decon->out_type = DECON_OUT_DSI;

	if (IS_ERR_OR_NULL(decon->output_sd))
		decon_warn("couldn't find dsim%d subdev\n", decon->id);

	v4l2_subdev_call(decon->output_sd, core, ioctl, DSIM_IOC_GET_LCD_INFO, NULL);
	decon->lcd_info = (struct decon_lcd *)v4l2_get_subdev_hostdata(decon->output_sd);
	if (IS_ERR_OR_NULL(decon->lcd_info)) {
		decon_err("failed to get lcd information\n");
		return -EINVAL;
	}

	return 0;
}
int decon_ext_register_irq(struct platform_device *pdev, struct decon_device *decon)
{
	struct device *dev = decon->dev;
	struct resource *res;
	int ret = 0;
	irqreturn_t (*irq_handler)(int, void *);

	if (decon->out_type == DECON_OUT_DSI)
		irq_handler = decon_ext_dsi_irq_handler;
	else
		irq_handler = decon_ext_wb_irq_handler;

	/* Get IRQ resource and register IRQ handler. */
	/* 0: FIFO irq */
	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	ret = devm_request_irq(dev, res->start, irq_handler, 0,
			pdev->name, decon);
	if (ret) {
		decon_err("failed to install irq\n");
		return ret;
	}

	/* 1: frame irq */
	res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
	ret = devm_request_irq(dev, res->start, irq_handler, 0,
			pdev->name, decon);
	if (ret) {
		decon_err("failed to install irq\n");
		return ret;
	}

	/* 2: i80 irq */
	res = platform_get_resource(pdev, IORESOURCE_IRQ, 2);
	ret = devm_request_irq(dev, res->start, irq_handler, 0,
			pdev->name, decon);
	if (ret) {
		decon_err("failed to install irq\n");
		return ret;
	}

	/* 3: wb frame done irq */
	res = platform_get_resource(pdev, IORESOURCE_IRQ, 3);
	ret = devm_request_irq(dev, res->start, irq_handler, 0,
			pdev->name, decon);
	if (ret) {
		decon_err("failed to install irq\n");
		return ret;
	}

	/* 4: external irq for te */
	if (decon->pdata->dsi_mode == DSI_MODE_DUAL_DISPLAY) {
		ret = decon_ext_config_eint_for_te(pdev, decon);
		if (ret) {
			decon_err("failed to config external irq\n");
			return ret;
		}
	}

	return ret;
}
int decon_get_hdmi_config(struct decon_device *decon,
               struct exynos_hdmi_data *hdmi_data)
{
	struct v4l2_control ctrl;
	int ret = 0;

	ctrl.id = 0;
	ctrl.value = 0;
	decon_dbg("state : %d\n", hdmi_data->state);

	switch (hdmi_data->state) {
	case EXYNOS_HDMI_STATE_PRESET:
		ret = v4l2_subdev_call(decon->output_sd, video, g_dv_timings, &hdmi_data->timings);
		if (ret)
			decon_err("failed to get current timings\n");
		else
			ret = find_subdev_hdmi(decon);
		decon_dbg("%dx%d@%s %lldHz %s(%#x)\n", hdmi_data->timings.bt.width,
			hdmi_data->timings.bt.height,
			hdmi_data->timings.bt.interlaced ? "I" : "P",
			hdmi_data->timings.bt.pixelclock,
			hdmi_data->timings.type ? "S3D" : "2D",
			hdmi_data->timings.type);
		break;
	case EXYNOS_HDMI_STATE_ENUM_PRESET:
		ret = v4l2_subdev_call(decon->output_sd, video, enum_dv_timings, &hdmi_data->etimings);
		if (ret)
			decon_err("failed to enumerate timings\n");
		break;
	case EXYNOS_HDMI_STATE_CEC_ADDR:
		ctrl.id = V4L2_CID_TV_SOURCE_PHY_ADDR;
		ret = v4l2_subdev_call(decon->output_sd, core, g_ctrl, &ctrl);
		if (ret)
			decon_err("failed to get physical address for CEC\n");
		hdmi_data->cec_addr = ctrl.value;
		decon_dbg("get physical address for CEC: %#x\n",
					hdmi_data->cec_addr);
		break;
	case EXYNOS_HDMI_STATE_AUDIO:
		ctrl.id = V4L2_CID_TV_MAX_AUDIO_CHANNELS;
		ret = v4l2_subdev_call(decon->output_sd, core, g_ctrl, &ctrl);
		if (ret)
			decon_err("failed to get hdmi audio information\n");
		hdmi_data->audio_info = ctrl.value;
		break;
	default:
		decon_warn("unrecongnized state %u", hdmi_data->state);
		ret = -EINVAL;
		break;
	}

	return ret;
}
dma_addr_t decon_map_sec_dma_buf(struct dma_buf *dbuf, int plane)
{
        struct decon_device *decon = get_decon_drvdata(0); /* 0: decon Int ID */

        if (!dbuf || (plane >= MAX_BUF_PLANE_CNT) || (plane < 0))
                return -EINVAL;

        dma.ion_handle = NULL;
        dma.fence = NULL;

        dma.dma_buf = dbuf;
	dma.attachment = dma_buf_attach(dbuf, decon->dev);

        if (IS_ERR(dma.attachment)) {
		decon_err("dma_buf_attach() failed: %ld\n",
				PTR_ERR(dma.attachment));
		goto err_buf_map_attach;
	}

	dma.sg_table = dma_buf_map_attachment(dma.attachment,
			DMA_TO_DEVICE);

	if (IS_ERR(dma.sg_table)) {
		decon_err("dma_buf_map_attachment() failed: %ld\n",
				PTR_ERR(dma.sg_table));
		goto err_buf_map_attachment;
	}

	dma.dma_addr = ion_iovmm_map(dma.attachment, 0,
			dma.dma_buf->size, DMA_TO_DEVICE, plane);

	if (IS_ERR_VALUE(dma.dma_addr)) {
		decon_err("iovmm_map() failed: %pa\n", &dma.dma_addr);
		goto err_iovmm_map;
	}

	exynos_ion_sync_dmabuf_for_device(decon->dev, dma.dma_buf,
			dma.dma_buf->size, DMA_TO_DEVICE);

	return dma.dma_addr;

err_iovmm_map:
	dma_buf_unmap_attachment(dma.attachment, dma.sg_table,
			DMA_TO_DEVICE);
err_buf_map_attachment:
	dma_buf_detach(dma.dma_buf, dma.attachment);
err_buf_map_attach:
        return 0;
}
Example #5
0
irqreturn_t decon_t_irq_handler(int irq, void *dev_data)
{
	struct decon_device *decon = dev_data;
	u32 irq_sts_reg;

	spin_lock(&decon->slock);
	if ((decon->state == DECON_STATE_OFF) ||
		(decon->state == DECON_STATE_LPD)) {
		goto irq_end;
	}

	irq_sts_reg = decon_reg_get_interrupt_and_clear(decon->id);

	if (irq_sts_reg & INTERRUPT_FIFO_LEVEL_INT_EN) {
		DISP_SS_EVENT_LOG(DISP_EVT_UNDERRUN, &decon->sd, ktime_set(0, 0));
		decon_err("DECON_T FIFO underrun\n");
	}
	if (irq_sts_reg & INTERRUPT_FRAME_DONE_INT_EN) {
		decon_lpd_trig_reset(decon);
		DISP_SS_EVENT_LOG(DISP_EVT_DECON_FRAMEDONE, &decon->sd, ktime_set(0, 0));
		decon_dbg("%s Frame Done is occured. timeline:%d, %d\n",
				__func__, decon->timeline->value, decon->timeline_max);
	}
	if (irq_sts_reg & INTERRUPT_RESOURCE_CONFLICT_INT_EN)
		DISP_SS_EVENT_LOG(DISP_EVT_RSC_CONFLICT, &decon->sd, ktime_set(0, 0));
irq_end:
	spin_unlock(&decon->slock);
	return IRQ_HANDLED;
}
int create_link_mipi(struct decon_device *decon)
{
	int i, ret = 0;
	int n_pad = decon->n_sink_pad + decon->n_src_pad;
	int flags = 0;
	char err[80];
	struct exynos_md *md = decon->mdev;

	if (IS_ERR_OR_NULL(md->dsim_sd[decon->id])) {
		decon_err("failed to get subdev of dsim%d\n", decon->id);
		return -EINVAL;
	}

	flags = MEDIA_LNK_FL_ENABLED;
	for (i = decon->n_sink_pad; i < n_pad ; i++) {
		ret = media_entity_create_link(&decon->sd.entity, i,
				&md->dsim_sd[decon->id]->entity, 0, flags);
		if (ret) {
			snprintf(err, sizeof(err), "%s --> %s",
					decon->sd.entity.name,
					decon->output_sd->entity.name);
			return ret;
		}

		decon_info("%s[%d] --> [0]%s link is created successfully\n",
				decon->sd.entity.name, i,
				decon->output_sd->entity.name);
	}

	return ret;
}
Example #7
0
int decon_t_set_lcd_info(struct decon_device *decon)
{
	struct decon_lcd *lcd_info;

	if (decon->lcd_info != NULL)
		return 0;

	lcd_info = kzalloc(sizeof(struct decon_lcd), GFP_KERNEL);
	if (!lcd_info) {
		decon_err("could not allocate decon_lcd for wb\n");
		return -ENOMEM;
	}

	decon->lcd_info = lcd_info;
	decon->lcd_info->width = 1920;
	decon->lcd_info->height = 1080;
	decon->lcd_info->xres = 1920;
	decon->lcd_info->yres = 1080;
	decon->lcd_info->vfp = 2;
	decon->lcd_info->vbp = 20;
	decon->lcd_info->hfp = 20;
	decon->lcd_info->hbp = 20;
	decon->lcd_info->vsa = 2;
	decon->lcd_info->hsa = 20;
	decon->lcd_info->fps = 60;
	decon->pdata->out_type = DECON_OUT_WB;

	decon_info("decon_%d output size for writeback %dx%d\n", decon->id,
			decon->lcd_info->width, decon->lcd_info->height);

	return 0;
}
Example #8
0
int decon_t_register_irq(struct platform_device *pdev, struct decon_device *decon)
{
	struct device *dev = decon->dev;
	struct resource *res;
	int ret = 0;

	/* Get IRQ resource and register IRQ handler. */
	/* 0: FIFO irq */
	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	ret = devm_request_irq(dev, res->start, decon_t_irq_handler, 0,
			pdev->name, decon);
	if (ret) {
		decon_err("failed to install irq\n");
		return ret;
	}

	/* 1: VStatus irq */
	res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
	ret = devm_request_irq(dev, res->start, decon_t_irq_handler, 0,
			pdev->name, decon);
	if (ret) {
		decon_err("failed to install irq\n");
		return ret;
	}

	/* 2: FrameDone irq */
	res = platform_get_resource(pdev, IORESOURCE_IRQ, 2);
	ret = devm_request_irq(dev, res->start, decon_t_irq_handler, 0,
			pdev->name, decon);
	if (ret) {
		decon_err("failed to install irq\n");
		return ret;
	}

	/* 3: Extra Interrupts: Resource Conflict irq */
	res = platform_get_resource(pdev, IORESOURCE_IRQ, 3);
	ret = devm_request_irq(dev, res->start, decon_t_irq_handler, 0,
			pdev->name, decon);
	if (ret) {
		decon_err("failed to install irq\n");
		return ret;
	}

	return ret;
}
int decon_set_hdmi_config(struct decon_device *decon,
               struct exynos_hdmi_data *hdmi_data)
{
	struct v4l2_control ctrl;
	int ret = 0;

	decon_dbg("state : %d\n", hdmi_data->state);

	switch (hdmi_data->state) {
	case EXYNOS_HDMI_STATE_PRESET:
		ret = v4l2_subdev_call(decon->output_sd, video, s_dv_timings, &hdmi_data->timings);
		if (ret)
			decon_err("failed to set timings newly\n");
		else
			ret = find_subdev_hdmi(decon);
		decon_dbg("%dx%d@%s %lldHz %s(%#x)\n", hdmi_data->timings.bt.width,
			hdmi_data->timings.bt.height,
			hdmi_data->timings.bt.interlaced ? "I" : "P",
			hdmi_data->timings.bt.pixelclock,
			hdmi_data->timings.type ? "S3D" : "2D",
			hdmi_data->timings.type);
		break;
	case EXYNOS_HDMI_STATE_HDCP:
		ctrl.id = V4L2_CID_TV_HDCP_ENABLE;
		ctrl.value = hdmi_data->hdcp;
		ret = v4l2_subdev_call(decon->output_sd, core, s_ctrl, &ctrl);
		if (ret)
			decon_err("failed to enable HDCP\n");
		decon_dbg("HDCP %s\n", ctrl.value ? "enabled" : "disabled");
		break;
	case EXYNOS_HDMI_STATE_AUDIO:
		ctrl.id = V4L2_CID_TV_SET_NUM_CHANNELS;
		ctrl.value = hdmi_data->audio_info;
		ret = v4l2_subdev_call(decon->output_sd, core, s_ctrl, &ctrl);
		if (ret)
			decon_err("failed to set hdmi audio information\n");
		break;
	default:
		decon_warn("unrecongnized state %u", hdmi_data->state);
		ret = -EINVAL;
		break;
	}

	return ret;
}
int decon_ext_get_clocks(struct decon_device *decon)
{
	decon->res.pclk = clk_get(decon->dev, "pclk_decon1");
	if (IS_ERR_OR_NULL(decon->res.pclk)) {
		decon_err("failed to get pclk_decon1\n");
		return -ENODEV;
	}

	decon->res.aclk = clk_get(decon->dev, "aclk_decon1");
	if (IS_ERR_OR_NULL(decon->res.aclk)) {
		decon_err("failed to get aclk_decon1\n");
		return -ENODEV;
	}

	decon->res.eclk = clk_get(decon->dev, "decon1_eclk");
	if (IS_ERR_OR_NULL(decon->res.eclk)) {
		decon_err("failed to get decon1_eclk\n");
		return -ENODEV;
	}

	decon->res.vclk = clk_get(decon->dev, "decon1_vclk");
	if (IS_ERR_OR_NULL(decon->res.vclk)) {
		decon_err("failed to get decon1_vclk\n");
		return -ENODEV;
	}

	decon->res.dsd = clk_get(decon->dev, "sclk_dsd");
	if (IS_ERR_OR_NULL(decon->res.dsd)) {
		decon_err("failed to get sclk_dsd\n");
		return -ENODEV;
	}

	decon->res.lh_disp1 = clk_get(decon->dev, "aclk_lh_disp1");
	if (IS_ERR_OR_NULL(decon->res.lh_disp1)) {
		decon_err("failed to get aclk_lh_disp1\n");
		return -ENODEV;
	}

	decon->res.aclk_disp = clk_get(decon->dev, "aclk_disp");
	if (IS_ERR_OR_NULL(decon->res.aclk_disp)) {
		decon_err("failed to get aclk_disp\n");
		return -ENODEV;
	}

	decon->res.pclk_disp = clk_get(decon->dev, "pclk_disp");
	if (IS_ERR_OR_NULL(decon->res.pclk_disp)) {
		decon_err("failed to get pclk_disp\n");
		return -ENODEV;
	}

	return 0;
}
Example #11
0
int decon_t_get_clocks(struct decon_device *decon)
{
	decon->res.pclk = clk_get(decon->dev, "decon_pclk");
	if (IS_ERR_OR_NULL(decon->res.pclk)) {
		decon_err("failed to get decon_pclk\n");
		return -ENODEV;
	}

	decon->res.eclk = clk_get(decon->dev, "eclk_user");
	if (IS_ERR_OR_NULL(decon->res.eclk)) {
		decon_err("failed to get eclk_user\n");
		return -ENODEV;
	}

	decon->res.eclk_leaf = clk_get(decon->dev, "eclk_leaf");
	if (IS_ERR_OR_NULL(decon->res.eclk_leaf)) {
		decon_err("failed to get eclk_leaf\n");
		return -ENODEV;
	}

	return 0;
}
int decon_clk_set_parent(struct device *dev, const char *child, const char *parent)
{
	struct clk *p;
	struct clk *c;

	p = clk_get(dev, parent);
	if (IS_ERR_OR_NULL(p)) {
		decon_err("%s: couldn't get clock : %s\n", __func__, parent);
		return -ENODEV;
	}

	c = clk_get(dev, child);
	if (IS_ERR_OR_NULL(c)) {
		decon_err("%s: couldn't get clock : %s\n", __func__, child);
		return -ENODEV;
	}

	clk_set_parent(c, p);
	clk_put(p);
	clk_put(c);

	return 0;
}
int decon_clk_set_rate(struct device *dev, const char *conid, unsigned int rate)
{
	struct clk *target;

	target = clk_get(dev, conid);
	if (IS_ERR_OR_NULL(target)) {
		decon_err("%s: couldn't get clock : %s\n", __func__, conid);
		return -ENODEV;
	}

	clk_set_rate(target, rate);
	clk_put(target);

	return 0;
}
/* wait until shadow update is finished */
int decon_reg_wait_for_update_timeout(unsigned long timeout)
{
	unsigned long delay_time = 100;
	unsigned long cnt = timeout / delay_time;

	while ((decon_read(DECON_UPDATE) & DECON_UPDATE_STANDALONE_F) && cnt--)
		udelay(delay_time);

	if (!cnt) {
		decon_err("timeout of updating decon registers\n");
		return -EBUSY;
	}

	return 0;
}
int find_subdev_hdmi(struct decon_device *decon)
{
	struct v4l2_subdev *output_sd;

	output_sd = (struct v4l2_subdev *)module_name_to_driver_data("s5p-hdmi");
	if (!output_sd) {
		decon_err("failed to get hdmi device\n");
		return -ENODEV;
	}

	decon->output_sd = output_sd;
	decon->out_type = DECON_OUT_HDMI;
	decon_info("%s entity get successfully\n", output_sd->name);

	return 0;
}
unsigned long decon_clk_get_rate(struct device *dev, const char *clkid)
{
	struct clk *target;
	unsigned long rate;

	target = clk_get(dev, clkid);
	if (IS_ERR_OR_NULL(target)) {
		decon_err("%s: couldn't get clock : %s\n", __func__, clkid);
		return -ENODEV;
	}

	rate = clk_get_rate(target);
	clk_put(target);

	return rate;
}
/******************* CAL raw functions implementation *************************/
int decon_reg_reset(void)
{
	int tries;

	decon_write(VIDCON0, VIDCON0_SWRESET);
	for (tries = 2000; tries; --tries) {
		if (~decon_read(VIDCON0) & VIDCON0_SWRESET)
			break;
		udelay(10);
	}

	if (!tries) {
		decon_err("failed to reset Decon\n");
		return -EBUSY;
	}

	return 0;
}
int decon_int_get_clocks(struct decon_device *decon)
{
	decon->res.pclk = clk_get(decon->dev, "pclk_decon0");
	if (IS_ERR_OR_NULL(decon->res.pclk)) {
		decon_err("failed to get pclk_decon0\n");
		return -ENODEV;
	}

	decon->res.aclk = clk_get(decon->dev, "aclk_decon0");
	if (IS_ERR_OR_NULL(decon->res.aclk)) {
		decon_err("failed to get aclk_decon0\n");
		return -ENODEV;
	}

	decon->res.eclk = clk_get(decon->dev, "decon0_eclk");
	if (IS_ERR_OR_NULL(decon->res.eclk)) {
		decon_err("failed to get decon0_eclk\n");
		return -ENODEV;
	}

	decon->res.vclk = clk_get(decon->dev, "decon0_vclk");
	if (IS_ERR_OR_NULL(decon->res.vclk)) {
		decon_err("failed to get decon0_vclk\n");
		return -ENODEV;
	}

	decon->res.aclk_disp = clk_get(decon->dev, "aclk_disp");
	if (IS_ERR_OR_NULL(decon->res.aclk_disp)) {
		decon_err("failed to get aclk_disp\n");
		return -ENODEV;
	}

	decon->res.mif_pll = clk_get(decon->dev, "mif_pll");
	if (IS_ERR_OR_NULL(decon->res.mif_pll)) {
		decon_err("failed to get mif_pll\n");
		return -ENODEV;
	}

	decon->res.aclk_disp_200 = clk_get(decon->dev, "aclk_disp_200");
	if (IS_ERR_OR_NULL(decon->res.aclk_disp_200)) {
		decon_err("failed to get aclk_disp_200\n");
		return -ENODEV;
	}

	return 0;
}
int decon_ext_config_eint_for_te(struct platform_device *pdev, struct decon_device *decon)
{
	struct device *dev = decon->dev;
	int gpio;
	int ret = 0;

	/* Get IRQ resource and register IRQ handler. */
	gpio = of_get_gpio(dev->of_node, 0);
	if (gpio < 0) {
		decon_err("failed to get proper gpio number\n");
		return -EINVAL;
	}

	gpio = gpio_to_irq(gpio);
	ret = devm_request_irq(dev, gpio, decon_ext_isr_for_eint,
			  IRQF_TRIGGER_RISING, pdev->name, decon);

	return ret;
}
int decon_reg_wait_stop_status_timeout(unsigned long timeout)
{
	unsigned long delay_time = 10;
	unsigned long cnt = timeout / delay_time;
	u32 status;

	do {
		status = decon_reg_get_stop_status();
		cnt--;
		udelay(delay_time);
	} while (status && cnt);

	if (!cnt) {
		decon_err("wait timeout decon stop status(%u)\n", status);
		return -EBUSY;
	}

	return 0;
}
irqreturn_t decon_ext_dsi_irq_handler(int irq, void *dev_data)
{
	struct decon_device *decon = dev_data;
	ktime_t timestamp = ktime_get();
	u32 irq_sts_reg;
	u32 wb_irq_sts_reg;

	spin_lock(&decon->slock);

	irq_sts_reg = decon_read(decon->id, VIDINTCON1);
	wb_irq_sts_reg = decon_read(decon->id, VIDINTCON3);
	if (irq_sts_reg & VIDINTCON1_INT_FRAME) {
		/* VSYNC interrupt, accept it */
		decon_write_mask(decon->id, VIDINTCON1, ~0, VIDINTCON1_INT_FRAME);
		decon->vsync_info.timestamp = timestamp;
		wake_up_interruptible_all(&decon->vsync_info.wait);
	}
	if (irq_sts_reg & VIDINTCON1_INT_FIFO) {
		decon_err("DECON-ext FIFO underrun\n");
		decon_write_mask(decon->id, VIDINTCON1, ~0, VIDINTCON1_INT_FIFO);
	}
	if (irq_sts_reg & VIDINTCON1_INT_I80) {
		decon_write_mask(decon->id, VIDINTCON1, ~0, VIDINTCON1_INT_I80);
		wake_up_interruptible_all(&decon->wait_frmdone);
	}
#if 0 
	if (wb_irq_sts_reg & VIDINTCON3_WB_FRAME_DONE) {
		decon_dbg("write-back frame done\n");
		DISP_SS_EVENT_LOG(DISP_EVT_WB_FRAME_DONE, &decon->sd, ktime_set(0, 0));
		decon_write_mask(decon->id, VIDINTCON3, ~0, VIDINTCON3_WB_FRAME_DONE);
		atomic_set(&decon->wb_done, STATE_DONE);
		wake_up_interruptible_all(&decon->wait_frmdone);
		decon_reg_per_frame_off(decon->id);
		decon_reg_update_standalone(decon->id);
		decon_reg_wb_swtrigger(decon->id);
		decon_reg_wait_stop_status_timeout(decon->id, 20 * 1000);
	}
#endif
	spin_unlock(&decon->slock);
	return IRQ_HANDLED;
}
void decon_ext_set_clocks(struct decon_device *decon)
{
	struct device *dev = decon->dev;

	if (decon->out_type == DECON_OUT_HDMI) {
		decon_clk_set_parent(dev, "m_decon1_eclk", "um_decon1_eclk");
		decon_clk_set_rate(dev, "d_decon1_eclk", 200 * MHZ);
		decon_clk_set_parent(dev, "m_decon1_vclk", "hdmi_pixel");
	} else if (decon->out_type == DECON_OUT_WB) {
		decon_clk_set_parent(dev, "m_decon1_eclk", "um_decon1_eclk");
		decon_clk_set_rate(dev, "d_decon1_eclk", 200 * MHZ);
		decon_clk_set_parent(dev, "um_decon1_vclk", "disp_pll");
		decon_clk_set_rate(dev, "d_decon1_vclk", 134 * MHZ);
		decon_clk_set_parent(dev, "m_decon1_vclk", "d_decon1_vclk");
	} else if (decon->out_type == DECON_OUT_DSI) {
		/* NOTE: It depends on LCD resolution. default is FHD */

		/* ECLK(100Mhz) : using BUS0 PLL  */
		decon_clk_set_parent(dev, "mout_sclk_decon_ext_eclk", "mout_bus0_pll_top0");
		decon_clk_set_rate(dev, "dout_sclk_decon_ext_eclk", 100 * MHZ);
		decon_clk_set_parent(dev, "m_decon1_eclk", "um_decon1_eclk");
		decon_clk_set_rate(dev, "d_decon1_eclk", 100 * MHZ);

		/* VCLK(142Mhz) : using DISP PLL */
		/* decon-int already configures DISP PLL as 142Mhz */
		decon_clk_set_parent(dev, "um_decon1_vclk", "disp_pll");
		if (decon->lcd_info->mic_enabled)
			decon_clk_set_rate(dev, "d_decon1_vclk", 72 * MHZ);
		else
			decon_clk_set_rate(dev, "d_decon1_vclk", 143 * MHZ);
		decon_clk_set_parent(dev, "m_decon1_vclk", "d_decon1_vclk");
	} else {
		decon_err("%s: failed to find output device of decon%d\n",
			__func__, decon->id);
 	}
}
/* timeout : usec */
int decon_reg_wait_linecnt_is_zero_timeout(unsigned long timeout)
{
	unsigned long delay_time = 10;
	unsigned long cnt = timeout / delay_time;
	u32 linecnt, vstatus;

	do {
		linecnt = decon_reg_get_linecnt();
		if (!linecnt) {
			vstatus = decon_reg_get_vstatus();
			if ((vstatus != VIDCON1_VSTATUS_BACKPORCH) && (vstatus != VIDCON1_VSTATUS_ACTIVE))
				break;
		}
		cnt--;
		udelay(delay_time);
	} while (cnt);

	if (!cnt) {
		decon_err("wait timeout linecount is zero(%u)\n", linecnt);
		return -EBUSY;
	}

	return 0;
}
int decon_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
	struct decon_win *win = info->par;
	struct decon_device *decon = win->decon;
	int x, y;
	unsigned long long hz;

	var->xres_virtual = max(var->xres_virtual, var->xres);
	var->yres_virtual = max(var->yres_virtual, var->yres);

	if (!decon_validate_x_alignment(decon, 0, var->xres,
			var->bits_per_pixel))
		return -EINVAL;

	/* always ensure these are zero, for drop through cases below */
	var->transp.offset = 0;
	var->transp.length = 0;

	switch (var->bits_per_pixel) {
	case 1:
	case 2:
	case 4:
	case 8:
		var->red.offset		= 4;
		var->green.offset	= 2;
		var->blue.offset	= 0;
		var->red.length		= 5;
		var->green.length	= 3;
		var->blue.length	= 2;
		var->transp.offset	= 7;
		var->transp.length	= 1;
		break;

	case 19:
		/* 666 with one bit alpha/transparency */
		var->transp.offset	= 18;
		var->transp.length	= 1;
	case 18:
		var->bits_per_pixel	= 32;

		/* 666 format */
		var->red.offset		= 12;
		var->green.offset	= 6;
		var->blue.offset	= 0;
		var->red.length		= 6;
		var->green.length	= 6;
		var->blue.length	= 6;
		break;

	case 16:
		/* 16 bpp, 565 format */
		var->red.offset		= 11;
		var->green.offset	= 5;
		var->blue.offset	= 0;
		var->red.length		= 5;
		var->green.length	= 6;
		var->blue.length	= 5;
		break;

	case 32:
	case 28:
	case 25:
		var->transp.length	= var->bits_per_pixel - 24;
		var->transp.offset	= 24;
		/* drop through */
	case 24:
		/* our 24bpp is unpacked, so 32bpp */
		var->bits_per_pixel	= 32;
		var->red.offset		= 16;
		var->red.length		= 8;
		var->green.offset	= 8;
		var->green.length	= 8;
		var->blue.offset	= 0;
		var->blue.length	= 8;
		break;

	default:
		decon_err("invalid bpp %d\n", var->bits_per_pixel);
		return -EINVAL;
	}

	if (decon->pdata->psr_mode == DECON_MIPI_COMMAND_MODE) {
		x = var->xres;
		y = var->yres;
	} else {
		x = var->xres + var->left_margin + var->right_margin + var->hsync_len;
		y = var->yres + var->upper_margin + var->lower_margin + var->vsync_len;
	}
	hz = 1000000000000ULL;		/* 1e12 picoseconds per second */

	hz += (x * y) / 2;
	do_div(hz, x * y);		/* divide by x * y with rounding */

	hz += var->pixclock / 2;
	do_div(hz, var->pixclock);	/* divide by pixclock with rounding */

	win->fps = hz;
	decon_dbg("xres:%d, yres:%d, v_xres:%d, v_yres:%d, bpp:%d, %lldhz\n",
			var->xres, var->yres, var->xres_virtual,
			var->yres_virtual, var->bits_per_pixel, hz);

	return 0;
}