int hisi_pwm_on(struct platform_device *pdev)
{
	int ret = 0;
	struct clk *clk_tmp = NULL;

	BUG_ON(pdev == NULL);

	clk_tmp = g_dss_pwm_clk;
	if (clk_tmp) {
		ret = clk_prepare(clk_tmp);
		if (ret) {
			HISI_FB_ERR("dss_pwm_clk clk_prepare failed, error=%d!\n", ret);
			return -EINVAL;
		}

		ret = clk_enable(clk_tmp);
		if (ret) {
			HISI_FB_ERR("dss_pwm_clk clk_enable failed, error=%d!\n", ret);
			return -EINVAL;
		}
	}

	ret = pinctrl_cmds_tx(pdev, pwm_pinctrl_normal_cmds,
		ARRAY_SIZE(pwm_pinctrl_normal_cmds));

	return ret;
}
static ssize_t vsync_timestamp_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	ssize_t ret = 0;
	struct fb_info *fbi = NULL;
	struct hisi_fb_data_type *hisifd = NULL;

	if (NULL == dev) {
		HISI_FB_ERR("NULL Pointer.\n");
		return 0;
	}

	fbi = dev_get_drvdata(dev);
	if (NULL == fbi) {
		HISI_FB_ERR("NULL Pointer.\n");
		return 0;
	}

	hisifd = (struct hisi_fb_data_type *)fbi->par;
	if (NULL == hisifd) {
		HISI_FB_ERR("NULL Pointer.\n");
		return 0;
	}

	if (NULL == buf) {
		HISI_FB_ERR("NULL Pointer.\n");
		return 0;
	}

	ret = snprintf(buf, PAGE_SIZE, "%llu \n",
		ktime_to_ns(hisifd->vsync_ctrl.vsync_timestamp));
	buf[strlen(buf) + 1] = '\0';

	return ret;
}
int resource_cmds_tx(struct platform_device *pdev,
	struct resource_desc *cmds, int cnt)
{
	int ret = 0;
	struct resource *res = NULL;
	struct resource_desc *cm = NULL;
	int i = 0;

	BUG_ON(pdev == NULL);
	cm = cmds;

	for (i = 0; i < cnt; i++) {
		if ((cm == NULL) || (cm->name == NULL)) {
			HISI_FB_ERR("cm or cm->name is null! index=%d\n", i);
			ret = -1;
			goto error;
		}

		res = platform_get_resource_byname(pdev, cm->flag, cm->name);
		if (!res) {
			HISI_FB_ERR("failed to get %s resource!\n", cm->name);
			ret = -1;
			goto error;
		}

		*(cm->value) = res->start;

		cm++;
	}

	return 0;

error:
	return cnt;
}
void hisifb_backlight_register(struct platform_device *pdev)
{
	struct hisi_fb_data_type *hisifd = NULL;
#ifdef CONFIG_FB_BACKLIGHT
	struct backlight_device *pbd = NULL;
	struct fb_info *fbi = NULL;
	char name[16] = {0};
	struct backlight_properties props;
#endif

	BUG_ON(pdev == NULL);
	hisifd = platform_get_drvdata(pdev);
	BUG_ON(hisifd == NULL);

	hisifd->backlight.bl_updated = 0;
	hisifd->backlight.bl_level_old = 0;
	hisifd->backlight.frame_updated = 0;
	sema_init(&hisifd->backlight.bl_sem, 1);
#ifdef CONFIG_HISI_FB_BACKLIGHT_DELAY
	INIT_DELAYED_WORK(&hisifd->backlight.bl_worker, hisifb_bl_workqueue_handler);
#endif

	if (lcd_backlight_registered)
		return;

	is_recovery_mode = (int)get_boot_into_recovery_flag();

#ifdef CONFIG_FB_BACKLIGHT
	fbi = hisifd->fbi;

	snprintf(name, sizeof(name), "hisifb%d_bl", hisifd->index);
	props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
	props.brightness = FB_BACKLIGHT_LEVELS - 1;
	pbd = backlight_device_register(name, fbi->dev, hisifd,
		&hisi_fb_bl_ops, &props);
	if (IS_ERR(pbd)) {
		fbi->bl_dev = NULL;
		HISI_FB_ERR("backlight_device_register failed!\n");
	}

	fbi->bl_dev = pbd;
	fb_bl_default_curve(fbi, 0,
		hisifd->panel_info.bl_min, hisifd->panel_info.bl_max);
#else
	/* android supports only one lcd-backlight/lcd for now */
	if (led_classdev_register(&pdev->dev, &backlight_led)) {
		HISI_FB_ERR("led_classdev_register failed!\n");
		return;
	}
#endif

	INIT_WORK(&(hisifd->backlight.sbl_work), hisifb_sbl_work);
	hisifd->backlight.sbl_queue = create_singlethread_workqueue(K3_DSS_SBL_WORKQUEUE);
	if (!hisifd->backlight.sbl_queue) {
		HISI_FB_ERR("failed to create sbl_queue!\n");
		return ;
	}

	lcd_backlight_registered = 1;
}
static int hisi_pwm_probe(struct platform_device *pdev)
{
	struct device_node *np = NULL;
	int ret = 0;

	HISI_FB_DEBUG("+.\n");

	BUG_ON(pdev == NULL);

	np = of_find_compatible_node(NULL, NULL, DTS_COMP_PWM_NAME);
	if (!np) {
		HISI_FB_ERR("NOT FOUND device node %s!\n", DTS_COMP_PWM_NAME);
		ret = -ENXIO;
		goto err_return;
	}

	/* get pwm reg base */
	hisifd_pwm_base = of_iomap(np, 0);

#if !defined(CONFIG_ARCH_HI3630FPGA) && !defined(CONFIG_HISI_3635_FPGA) \
	&& !defined(CONFIG_HISI_3650_FPGA)
	/* pwm pinctrl init */
	ret = pinctrl_cmds_tx(pdev, pwm_pinctrl_init_cmds,
		ARRAY_SIZE(pwm_pinctrl_init_cmds));
	if (ret != 0) {
		HISI_FB_ERR("Init pwm pinctrl failed! ret=%d.\n", ret);
		goto err_return;
	}

	/* get blpwm clk resource */
	g_dss_pwm_clk = of_clk_get(np, 0);
	if (IS_ERR(g_dss_pwm_clk)) {
		HISI_FB_ERR("%s clock not found: %d!\n",
			np->name, (int)PTR_ERR(g_dss_pwm_clk));
		ret = -ENXIO;
		goto err_return;
	}

	ret = clk_set_rate(g_dss_pwm_clk, DEFAULT_PWM_CLK_RATE);
	if (ret != 0) {
		HISI_FB_ERR("dss_pwm_clk clk_set_rate(%lu) failed, error=%d!\n",
			DEFAULT_PWM_CLK_RATE, ret);
		ret = -EINVAL;
		goto err_return;
	}

	HISI_FB_INFO("dss_pwm_clk:[%lu]->[%lu].\n",
		DEFAULT_PWM_CLK_RATE, clk_get_rate(g_dss_pwm_clk));
#endif

	hisi_fb_device_set_status0(DTS_PWM_READY);

	HISI_FB_DEBUG("-.\n");

	return 0;

err_return:
	return ret;
}
int set_dss_clk_rate(struct hisi_fb_data_type *hisifd)
{
	int ret = 0;

	BUG_ON(hisifd == NULL);

	if (hisifd->dss_pri_clk && (hisifd->dss_clk_rate.dss_pri_clk_rate > 0)) {
		if (hisifd->dss_clk_rate.dss_pri_clk_rate > DSS_PRI_CLK_RATE_MAX)
			hisifd->dss_clk_rate.dss_pri_clk_rate = DSS_PRI_CLK_RATE_MAX;

		ret = clk_set_rate(hisifd->dss_pri_clk, hisifd->dss_clk_rate.dss_pri_clk_rate);
		if (ret < 0) {
			HISI_FB_ERR("fb%d dss_pri_clk clk_set_rate(%llu) failed, error=%d!\n",
				hisifd->index, hisifd->dss_clk_rate.dss_pri_clk_rate, ret);
			return -EINVAL;
		}

		//HISI_FB_INFO("dss_pri_clk:[%llu]->[%llu].\n",
		//	hisifd->dss_clk_rate.dss_pri_clk_rate, clk_get_rate(hisifd->dss_pri_clk));
	}

	if (hisifd->dss_aux_clk && (hisifd->dss_clk_rate.dss_aux_clk_rate > 0)) {
		if (hisifd->dss_clk_rate.dss_aux_clk_rate > DSS_AUX_CLK_RATE_MAX)
			hisifd->dss_clk_rate.dss_aux_clk_rate = DSS_AUX_CLK_RATE_MAX;

		ret = clk_set_rate(hisifd->dss_aux_clk, hisifd->dss_clk_rate.dss_aux_clk_rate);
		if (ret < 0) {
			HISI_FB_ERR("fb%d dss_aux_clk_rate clk_set_rate(%llu) failed, error=%d!\n",
				hisifd->index, hisifd->dss_clk_rate.dss_aux_clk_rate, ret);
			return -EINVAL;
		}

		//HISI_FB_INFO("dss_aux_clk:[%lu]->[%lu].\n",
		//	hisifd->dss_clk_rate.dss_aux_clk_rate, clk_get_rate(hisifd->dss_aux_clk));
	}

	if (hisifd->dss_pclk_clk && (hisifd->dss_clk_rate.dss_pclk_clk_rate > 0)) {
		if (hisifd->dss_clk_rate.dss_pclk_clk_rate > DSS_PCLK_CLK_RATE_MAX)
			hisifd->dss_clk_rate.dss_pclk_clk_rate = DSS_PCLK_CLK_RATE_MAX;

		ret = clk_set_rate(hisifd->dss_pclk_clk, hisifd->dss_clk_rate.dss_pclk_clk_rate);
		if (ret < 0) {
			HISI_FB_ERR("fb%d dss_pclk_clk clk_set_rate(%llu) failed, error=%d!\n",
				hisifd->index, hisifd->dss_clk_rate.dss_pclk_clk_rate, ret);
			return -EINVAL;
		}

		//HISI_FB_INFO("dss_pclk_clk:[%llu]->[%llu].\n",
		//	hisifd->dss_clk_rate.dss_pclk_clk_rate, clk_get_rate(hisifd->dss_pclk_clk));
	}

	return ret;
}
int mipi_dsi_read_compare(struct mipi_dsi_read_compare_data *data, char __iomem *dsi_base)
{
	u32 *read_value = data->read_value;
	u32 *expected_value = data->expected_value;
	u32 *read_mask = data->read_mask;
	char **reg_name = data->reg_name;
	int log_on = data->log_on;
	struct dsi_cmd_desc *cmds = data->cmds;
	int cnt = data->cnt;

	int cnt_not_match = 0;
	int read_ret = 0;
	int i;

	read_ret = mipi_dsi_cmds_rx(read_value, cmds, cnt, dsi_base);

	if(read_ret){
		HISI_FB_ERR("Read error number: %d\n", read_ret);
		return cnt;
	}
	for(i=0; i<cnt; i++) {
		if (log_on) {
			HISI_FB_INFO("Read reg %s: 0x%X, value = 0x%X\n", reg_name[i], cmds[i].payload[0], read_value[i]);
		}
		if(expected_value[i] != (read_value[i] & read_mask[i])){
			cnt_not_match++;
		}
	}

	return cnt_not_match;
}
int hisi_pwm_set_backlight(struct hisi_fb_data_type *hisifd)
{
	char __iomem *pwm_base = NULL;
	uint32_t bl_max = 0;
	uint32_t bl_level = 0;

	BUG_ON(hisifd == NULL);

	pwm_base = hisifd_pwm_base;
	BUG_ON(pwm_base == NULL);

	bl_level = hisifd->bl_level;
	bl_max = hisifd->panel_info.bl_max;
	if (bl_level > hisifd->panel_info.bl_max) {
		bl_level = hisifd->panel_info.bl_max;
	}

	if (bl_max < 1) {
		HISI_FB_ERR("bl_max=%d is invalid!\n", bl_max);
		return -EINVAL;
	}

	bl_level = (bl_level * PWM_OUT_PRECISION) / bl_max;

	outp32(pwm_base + PWM_LOCK_OFFSET, 0x1acce551);
	outp32(pwm_base + PWM_CTL_OFFSET, 0x0);
	outp32(pwm_base + PWM_CFG_OFFSET, 0x2);
	outp32(pwm_base + PWM_PR0_OFFSET, 0x1);
	outp32(pwm_base + PWM_PR1_OFFSET, 0x2);
	outp32(pwm_base + PWM_CTL_OFFSET, 0x1);
	outp32(pwm_base + PWM_C0_MR_OFFSET, (PWM_OUT_PRECISION - 1));
	outp32(pwm_base + PWM_C0_MR0_OFFSET, bl_level);

	return 0;
}
static int rgb2mipi_cmd_add(struct spi_device *spi_dev, struct dsi_cmd_desc *cm)
{
    int len = 0;

    BUG_ON(spi_dev == NULL);
    BUG_ON(cm == NULL);

    switch (cm->dtype) {
    case DTYPE_GEN_WRITE:
    case DTYPE_GEN_WRITE1:
    case DTYPE_GEN_WRITE2:

    case DTYPE_DCS_WRITE:
    case DTYPE_DCS_WRITE1:
        len = rgb2mipi_swrite(spi_dev, cm);
        break;
    case DTYPE_GEN_LWRITE:
    case DTYPE_DCS_LWRITE:
        len = rgb2mipi_lwrite(spi_dev, cm);
        break;
    default:
        HISI_FB_ERR("dtype=%x NOT supported!\n", cm->dtype);
        break;
    }

    return len;
}
static void hisifb_vsync_ctrl_workqueue_handler(struct work_struct *work)
{
	struct hisi_fb_data_type *hisifd = NULL;
	struct hisifb_vsync *vsync_ctrl = NULL;
	struct hisi_fb_panel_data *pdata = NULL;
	unsigned long flags = 0;

	vsync_ctrl = container_of(work, typeof(*vsync_ctrl), vsync_ctrl_work);
	BUG_ON(vsync_ctrl == NULL);
	hisifd = vsync_ctrl->hisifd;
	BUG_ON(hisifd == NULL);
	pdata = dev_get_platdata(&hisifd->pdev->dev);
	BUG_ON(pdata == NULL);

	down(&(hisifd->blank_sem));

	if (!hisifd->panel_power_on) {
		HISI_FB_DEBUG("fb%d, panel is power off!", hisifd->index);
		up(&(hisifd->blank_sem));
		return;
	}

	mutex_lock(&(vsync_ctrl->vsync_lock));
	if (vsync_ctrl->vsync_ctrl_disabled_set &&
		(vsync_ctrl->vsync_ctrl_expire_count == 0) &&
		vsync_ctrl->vsync_ctrl_enabled &&
		!vsync_ctrl->vsync_enabled) {
		HISI_FB_DEBUG("fb%d, dss clk off!\n", hisifd->index);

		spin_lock_irqsave(&(vsync_ctrl->spin_lock), flags);
		if (pdata->vsync_ctrl) {
			pdata->vsync_ctrl(hisifd->pdev, 0);
		} else {
			HISI_FB_ERR("fb%d, vsync_ctrl not supported!\n", hisifd->index);
		}
		vsync_ctrl->vsync_ctrl_enabled = 0;
		vsync_ctrl->vsync_ctrl_disabled_set = 0;
		spin_unlock_irqrestore(&(vsync_ctrl->spin_lock), flags);

		if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_MIPI_ULPS) {
			mipi_dsi_ulps_cfg(hisifd, 0);
		}

		if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_CLK_OFF) {
			dpe_clk_disable(hisifd);
			mipi_dsi_clk_disable(hisifd);
		}

		if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_VCC_OFF) {
			dpe_regulator_disable(hisifd);
		}
	}
	mutex_unlock(&(vsync_ctrl->vsync_lock));

	if (vsync_ctrl->vsync_report_fnc) {
		vsync_ctrl->vsync_report_fnc(1);
	}

	up(&(hisifd->blank_sem));
}
int hisi_lcd_backlight_off(struct platform_device *pdev)
{
	struct hisi_fb_data_type *hisifd = NULL;
	int ret = 0;

	BUG_ON(pdev == NULL);
	hisifd = platform_get_drvdata(pdev);
	BUG_ON(hisifd == NULL);

	HISI_FB_INFO("fb%d, +!\n", hisifd->index);

	if (hisifd->panel_info.bl_set_type & BL_SET_BY_PWM) {
		ret = hisi_pwm_off(pdev);
		#ifdef CONFIG_BACKLIGHT_10000
		        ret = hisi_blpwm_off(pdev);
		#endif
	} else if (hisifd->panel_info.bl_set_type & BL_SET_BY_BLPWM) {
		ret = hisi_blpwm_off(pdev);
	} else if (hisifd->panel_info.bl_set_type & BL_SET_BY_MIPI) {
		;
	} else {
		HISI_FB_ERR("No such bl_set_type(%d)!\n", hisifd->panel_info.bl_set_type);
	}

	HISI_FB_INFO("fb%d, -!\n", hisifd->index);

	return ret;
}
void init_ifbc(struct hisi_fb_data_type *hisifd)
{
	char __iomem *ifbc_base = NULL;

	BUG_ON(hisifd == NULL);

	if (hisifd->index == PRIMARY_PANEL_IDX) {
		ifbc_base = hisifd->dss_base + DSS_DPP_IFBC_OFFSET;
	} else {
		HISI_FB_ERR("fb%d, not support!", hisifd->index);
		return ;
	}

	set_reg(ifbc_base + IFBC_SIZE,
		((DSS_WIDTH(hisifd->panel_info.xres) << 16) |
		DSS_HEIGHT(hisifd->panel_info.yres)), 32, 0);
	set_reg(ifbc_base + IFBC_CTRL, hisifd->panel_info.ifbc_type, 10, 0);
	if (hisifd->panel_info.ifbc_type != IFBC_TYPE_NON) {
		set_reg(ifbc_base + IFBC_EN, 0x3, 2, 0);
	} else {
		set_reg(ifbc_base + IFBC_EN, 0x0, 2, 0);
	}

#if 0
	set_reg(ifbc_base + IFBC_Himax_CTRL0, 32, 0);
	set_reg(ifbc_base + IFBC_Himax_CTRL1, 32, 0);
	set_reg(ifbc_base + IFBC_Himax_CTRL2, 32, 0);
	set_reg(ifbc_base + IFBC_Himax_CTRL3, 32, 0);
	set_reg(ifbc_base + IFBC_PM_CTRL, 32, 0);
	set_reg(ifbc_base + IFBC_MEM_CTRL, 32, 0);
	set_reg(ifbc_base + IFBC_HIMAX_TEST_MODE, 32, 0);
	set_reg(ifbc_base + IFBC_CORE_GT, 32, 0);
#endif
}
struct platform_device *hisi_fb_device_alloc(struct hisi_fb_panel_data *pdata,
	uint32_t type, uint32_t id)
{
	struct platform_device *this_dev = NULL;
	char dev_name[32] = {0};

	BUG_ON(pdata == NULL);

	switch (type) {
	case PANEL_MIPI_VIDEO:
	case PANEL_MIPI_CMD:
		snprintf(dev_name, sizeof(dev_name), DEV_NAME_MIPIDSI);
		break;
	case PANEL_EDP:
		snprintf(dev_name, sizeof(dev_name), DEV_NAME_EDP);
		break;
	case PANEL_NO:
	case PANEL_LCDC:
	case PANEL_HDMI:
	case PANEL_OFFLINECOMPOSER:
	case PANEL_WRITEBACK:
		snprintf(dev_name, sizeof(dev_name), DEV_NAME_DSS_DPE);
		break;
	case PANEL_RGB2MIPI:
		snprintf(dev_name, sizeof(dev_name), DEV_NAME_RGB2MIPI);
		break;
	default:
		HISI_FB_ERR("invalid panel type = %d!\n", type);
		return NULL;
	}

	if (pdata != NULL)
		pdata->next = NULL;
	else
		return NULL;

	this_dev = platform_device_alloc(dev_name, (((uint32_t)type << 16) | (uint32_t)id));
	if (this_dev) {
		if (platform_device_add_data(this_dev, pdata, sizeof(struct hisi_fb_panel_data))) {
			HISI_FB_ERR("failed to platform_device_add_data!\n");
			platform_device_put(this_dev);
			return NULL;
		}
	}

	return this_dev;
}
static int mipi_dsi_frc_handle(struct platform_device *pdev, int fps)
{
	int ret = 0;

#if 0
	struct hisi_fb_data_type *hisifd = NULL;
	struct hisi_panel_info *pinfo = NULL;
	uint32_t hline_time = 0;
	uint32_t pixel_clk = 0;
	uint32_t vertical_timing = 0;
	uint32_t horizontal_timing = 0;
	uint32_t h_front_porch = 0;

	BUG_ON(pdev == NULL);
	hisifd = platform_get_drvdata(pdev);
	BUG_ON(hisifd == NULL);

	if (hisifd->index != PRIMARY_PANEL_IDX) {
		HISI_FB_ERR("fb%d, not support!", hisifd->index);
		return 0;
	}

	HISI_FB_DEBUG("fb%d, +.\n", hisifd->index);

	pinfo = &(hisifd->panel_info);

	/* calculate new HFP based on target_fps */
	vertical_timing = pinfo->yres + pinfo->ldi.v_back_porch
		+ pinfo->ldi.v_front_porch + pinfo->ldi.v_pulse_width;
	horizontal_timing = pinfo->pxl_clk_rate / (vertical_timing * fps);

	/* new HFP*/
	/*
	pinfo->ldi.h_front_porch = horizontal_timing - pinfo->xres
		-pinfo->ldi.h_back_porch - pinfo->ldi.h_pulse_width;
	*/
	h_front_porch = horizontal_timing - pinfo->xres
		-pinfo->ldi.h_back_porch - pinfo->ldi.h_pulse_width;

	pixel_clk = pinfo->pxl_clk_rate / 1000000;
	/* update hline_time */
	hline_time = (pinfo->ldi.h_pulse_width + pinfo->ldi.h_back_porch +
		pinfo->xres + h_front_porch) *
		(pinfo->mipi.dsi_bit_clk / 4) / pixel_clk;

	/* reset dsi core */
	set_reg(hisifd->mipi_dsi0_base + MIPIDSI_PWR_UP_OFFSET, 0x0, 1, 0);
	set_reg(hisifd->mipi_dsi0_base + MIPIDSI_VID_HLINE_TIME_OFFSET, hline_time, 15, 0);
	outp32(hisifd->dss_base + PDP_LDI_DPI0_HRZ_CTRL0,
		h_front_porch | (pinfo->ldi.h_back_porch << 16));

	/* power on dsi core */
	set_reg(hisifd->mipi_dsi0_base + MIPIDSI_PWR_UP_OFFSET, 0x1, 1, 0);

	HISI_FB_DEBUG("fb%d, -.\n", hisifd->index);
#endif

	return ret;
}
static int mipi_dsi_clk_irq_setup(struct platform_device *pdev)
{
	struct hisi_fb_data_type *hisifd = NULL;
	int ret = 0;

	BUG_ON(pdev == NULL);
	hisifd = platform_get_drvdata(pdev);
	BUG_ON(hisifd == NULL);

	hisifd->dss_dphy0_clk = devm_clk_get(&pdev->dev, hisifd->dss_dphy0_clk_name);
	if (IS_ERR(hisifd->dss_dphy0_clk)) {
		ret = PTR_ERR(hisifd->dss_dphy0_clk);
		return ret;
	} else {
		ret = clk_set_rate(hisifd->dss_dphy0_clk, DEFAULT_MIPI_CLK_RATE);
		if (ret < 0) {
			HISI_FB_ERR("fb%d dss_dphy0_clk clk_set_rate(%lu) failed, error=%d!\n",
				hisifd->index, DEFAULT_MIPI_CLK_RATE, ret);
			return -EINVAL;
		}

		HISI_FB_INFO("dss_dphy0_clk:[%lu]->[%lu].\n",
			DEFAULT_MIPI_CLK_RATE, clk_get_rate(hisifd->dss_dphy0_clk));
	}

	if (is_dual_mipi_panel(hisifd)) {
		hisifd->dss_dphy1_clk = devm_clk_get(&pdev->dev, hisifd->dss_dphy1_clk_name);
		if (IS_ERR(hisifd->dss_dphy1_clk)) {
			ret = PTR_ERR(hisifd->dss_dphy1_clk);
			return ret;
		} else {
			ret = clk_set_rate(hisifd->dss_dphy1_clk, DEFAULT_MIPI_CLK_RATE);
			if (ret < 0) {
				HISI_FB_ERR("fb%d dss_dphy1_clk clk_set_rate(%lu) failed, error=%d!\n",
					hisifd->index, DEFAULT_MIPI_CLK_RATE, ret);
				return -EINVAL;
			}

			HISI_FB_INFO("dss_dphy1_clk:[%lu]->[%lu].\n",
				DEFAULT_MIPI_CLK_RATE, clk_get_rate(hisifd->dss_dphy1_clk));
		}
	}

	return ret;
}
int mipi_dsi_clk_enable(struct hisi_fb_data_type *hisifd)
{
	int ret = 0;
	struct clk *clk_tmp = NULL;

	BUG_ON(hisifd == NULL);

	clk_tmp = hisifd->dss_dphy0_clk;
	if (clk_tmp) {
		ret = clk_prepare(clk_tmp);
		if (ret) {
			HISI_FB_ERR("fb%d dss_dphy0_clk clk_prepare failed, error=%d!\n",
				hisifd->index, ret);
			return -EINVAL;
		}

		ret = clk_enable(clk_tmp);
		if (ret) {
			HISI_FB_ERR("fb%d dss_dphy0_clk clk_enable failed, error=%d!\n",
				hisifd->index, ret);
			return -EINVAL;
		}
	}

	if (is_dual_mipi_panel(hisifd)) {
		clk_tmp = hisifd->dss_dphy1_clk;
		if (clk_tmp) {
			ret = clk_prepare(clk_tmp);
			if (ret) {
				HISI_FB_ERR("fb%d dss_dphy1_clk clk_prepare failed, error=%d!\n",
					hisifd->index, ret);
				return -EINVAL;
			}

			ret = clk_enable(clk_tmp);
			if (ret) {
				HISI_FB_ERR("fb%d dss_dphy1_clk clk_enable failed, error=%d!\n",
					hisifd->index, ret);
				return -EINVAL;
			}
		}
	}

	return 0;
}
void hisifb_vsync_register(struct platform_device *pdev)
{
	struct hisi_fb_data_type *hisifd = NULL;
	struct hisifb_vsync *vsync_ctrl = NULL;
#if defined(CONFIG_HISI_FB_VSYNC_THREAD)
	char name[64] = {0};
#endif

	BUG_ON(pdev == NULL);
	hisifd = platform_get_drvdata(pdev);
	BUG_ON(hisifd == NULL);
	vsync_ctrl = &(hisifd->vsync_ctrl);
	BUG_ON(vsync_ctrl == NULL);

	if (vsync_ctrl->vsync_created)
		return;

	vsync_ctrl->hisifd = hisifd;
	vsync_ctrl->vsync_enabled = 0;
	vsync_ctrl->vsync_timestamp = ktime_get();
	init_waitqueue_head(&(vsync_ctrl->vsync_wait));
	spin_lock_init(&(vsync_ctrl->spin_lock));
	INIT_WORK(&vsync_ctrl->vsync_ctrl_work, hisifb_vsync_ctrl_workqueue_handler);

	mutex_init(&(vsync_ctrl->vsync_lock));

	atomic_set(&(vsync_ctrl->buffer_updated), 1);
#ifdef CONFIG_REPORT_VSYNC
	vsync_ctrl->vsync_report_fnc = mali_kbase_pm_report_vsync;
#else
	vsync_ctrl->vsync_report_fnc = NULL;
#endif

#ifdef CONFIG_FAKE_VSYNC_USED
	/* hrtimer for fake vsync timing */
	hisifd->fake_vsync_used = false;
	hrtimer_init(&hisifd->fake_vsync_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
	hisifd->fake_vsync_hrtimer.function = hisifb_fake_vsync;
	hrtimer_start(&hisifd->fake_vsync_hrtimer,
		ktime_set(0, NSEC_PER_SEC / 60), HRTIMER_MODE_REL);
#endif

#if defined(CONFIG_HISI_FB_VSYNC_THREAD)
	snprintf(name, sizeof(name), "hisifb%d_vsync", hisifd->index);
	vsync_ctrl->vsync_thread = kthread_run(wait_for_vsync_thread, hisifd, name);
	if (IS_ERR(vsync_ctrl->vsync_thread)) {
		vsync_ctrl->vsync_thread = NULL;
		HISI_FB_ERR("failed to run vsync thread!\n");
		return;
	}
#else
	if (hisifd->sysfs_attrs_append_fnc)
		hisifd->sysfs_attrs_append_fnc(hisifd, &dev_attr_vsync_event.attr);
#endif

	vsync_ctrl->vsync_created = 1;
}
int hisifb_vsync_ctrl(struct fb_info *info, void __user *argp)
{
	int ret = 0;
	struct hisi_fb_data_type *hisifd = NULL;
	struct hisi_fb_panel_data *pdata = NULL;
	struct hisifb_vsync *vsync_ctrl = NULL;
	int enable = 0;

	BUG_ON(info == NULL);
	hisifd = (struct hisi_fb_data_type *)info->par;
	BUG_ON(hisifd == NULL);
	pdata = dev_get_platdata(&hisifd->pdev->dev);
	BUG_ON(pdata == NULL);
	vsync_ctrl = &(hisifd->vsync_ctrl);
	BUG_ON(vsync_ctrl == NULL);

	ret = copy_from_user(&enable, argp, sizeof(enable));
	if (ret) {
		HISI_FB_ERR("hisifb_vsync_ctrl ioctl failed!\n");
		return ret;
	}

	enable = (enable) ? 1 : 0;

	mutex_lock(&(vsync_ctrl->vsync_lock));

	if (vsync_ctrl->vsync_enabled == enable) {
		mutex_unlock(&(vsync_ctrl->vsync_lock));
		return 0;
	}

	if (g_debug_online_vsync)
		HISI_FB_INFO("fb%d, enable=%d!\n", hisifd->index, enable);

	vsync_ctrl->vsync_enabled = enable;

	mutex_unlock(&(vsync_ctrl->vsync_lock));

	down(&hisifd->blank_sem);

	if (!hisifd->panel_power_on) {
		HISI_FB_DEBUG("fb%d, panel is power off!", hisifd->index);
		up(&hisifd->blank_sem);
		return 0;
	}

	if (enable) {
		hisifb_activate_vsync(hisifd);
	} else {
		hisifb_deactivate_vsync(hisifd);
	}

	up(&hisifd->blank_sem);

	return 0;
}
int hisi_pwm_set_backlight(struct hisi_fb_data_type *hisifd)
{
	char __iomem *pwm_base = NULL;
	uint32_t bl_max = 0;
	uint32_t bl_level = 0;

	BUG_ON(hisifd == NULL);

	pwm_base = hisifd_pwm_base;
	BUG_ON(pwm_base == NULL);

	#ifdef CONFIG_BACKLIGHT_10000
	    g_bl_info.bl_max = hisifd->panel_info.bl_max;
	#endif
	bl_level = hisifd->bl_level;
	bl_max = hisifd->panel_info.bl_max;
	if (bl_level > hisifd->panel_info.bl_max) {
		bl_level = hisifd->panel_info.bl_max;
	}

	if (bl_max < 1) {
		HISI_FB_ERR("bl_max=%d is invalid!\n", bl_max);
		return -EINVAL;
	}

	if ((bl_level > 0) && (bl_level < PWM_BL_LEVEL_MIN)) {
		bl_level = PWM_BL_LEVEL_MIN;
	}

	#ifdef CONFIG_BACKLIGHT_10000
	      if(bl_level > 0){
		    bl_level= bl_level * g_bl_info.current_cabc_pwm / CABC_PWM_DUTY_MAX_LEVEL;
		    bl_level =  bl_level < PWM_BL_LEVEL_MIN ? PWM_BL_LEVEL_MIN : bl_level ;
	      }
	      g_bl_info.ap_brightness = bl_level;
	      HISI_FB_INFO("g_bl_info.ap_brightness= %d\n",bl_level);
	      if(bl_level > 0 && g_bl_info.index_cabc_dimming > 0 &&  g_bl_info.index_cabc_dimming < 33 )
	      {
		    HISI_FB_INFO("cabc is dimming and g_bl_info.index_cabc_dimming = %d\n",g_bl_info.index_cabc_dimming);
		    return;
	      }
	#endif

	bl_level = (bl_level * PWM_OUT_PRECISION) / bl_max;

	outp32(pwm_base + PWM_LOCK_OFFSET, 0x1acce551);
	outp32(pwm_base + PWM_CTL_OFFSET, 0x0);
	outp32(pwm_base + PWM_CFG_OFFSET, 0x2);
	outp32(pwm_base + PWM_PR0_OFFSET, 0x1);
	outp32(pwm_base + PWM_PR1_OFFSET, 0x2);
	outp32(pwm_base + PWM_CTL_OFFSET, 0x1);
	outp32(pwm_base + PWM_C0_MR_OFFSET, (PWM_OUT_PRECISION - 1));
	outp32(pwm_base + PWM_C0_MR0_OFFSET, bl_level);

	return 0;
}
Example #20
0
/*******************************************************************************
** handle isr
*/
irqreturn_t dss_pdp_isr(int irq, void *ptr)
{
    struct hisi_fb_data_type *hisifd = NULL;
    uint32_t isr_s1 = 0;
    uint32_t mask = 0;

    hisifd = (struct hisi_fb_data_type *)ptr;
    BUG_ON(hisifd == NULL);

    isr_s1 = inp32(hisifd->dss_base + GLB_CPU_PDP_INTS);
    outp32(hisifd->dss_base + GLB_CPU_PDP_INTS, ~0);

    if (isr_s1 & BIT_VACTIVE0_START) {
        if (hisifd->ov_vactive0_start_isr_handler)
            hisifd->ov_vactive0_start_isr_handler(hisifd);
    }

    if (isr_s1 & BIT_VSYNC) {
        if (hisifd->vsync_isr_handler) {
            hisifd->vsync_isr_handler(hisifd);
        }

        if (g_enable_ovl_optimized) {
            if (hisifd->ov_optimized)
                hisifd->ov_optimized(hisifd, DSS_OVL0);
        }

        if (hisifd->buf_sync_signal) {
            hisifd->buf_sync_signal(hisifd);
        }
    }

    if (isr_s1 & BIT_BACKLIGHT) {
        if (hisifd->sbl_isr_handler) {
            hisifd->sbl_isr_handler(hisifd);
        }
    }

    if (isr_s1 & BIT_LDI_UNFLOW) {
        if (g_debug_ldi_underflow) {
            /* ldi disable */
            set_reg(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_CTRL, 0, 1, 0);
        }

        mask = inp32(hisifd->dss_base + GLB_CPU_PDP_INT_MSK);
        mask |= BIT_LDI_UNFLOW;
        outp32(hisifd->dss_base + GLB_CPU_PDP_INT_MSK, mask);

        HISI_FB_ERR("ldi underflow!\n");
    }

    return IRQ_HANDLED;
}
static int __init lcdc_fake_panel_init(void)
{
	int ret = 0;

	ret = platform_driver_register(&this_driver);
	if (ret) {
		HISI_FB_ERR("platform_driver_register failed, error=%d!\n", ret);
		return ret;
	}

	return ret;
}
static int __init hisi_spi_init(void)
{
	int ret = 0;

	ret = spi_register_driver(&this_driver);
	if (ret) {
		HISI_FB_ERR("spi_register_driver failed, error=%d!\n", ret);
		return ret;
	}

	return ret;
}
void hisifb_activate_vsync(struct hisi_fb_data_type *hisifd)
{
	struct hisi_fb_panel_data *pdata = NULL;
	struct hisifb_vsync *vsync_ctrl = NULL;
	unsigned long flags = 0;
	int clk_enabled = 0;

	BUG_ON(hisifd == NULL);
	pdata = dev_get_platdata(&hisifd->pdev->dev);
	BUG_ON(pdata == NULL);
	vsync_ctrl = &(hisifd->vsync_ctrl);
	BUG_ON(vsync_ctrl == NULL);

	if (hisifd->panel_info.vsync_ctrl_type == VSYNC_CTRL_NONE)
		return;

	mutex_lock(&(vsync_ctrl->vsync_lock));

	if (vsync_ctrl->vsync_ctrl_enabled == 0) {
		HISI_FB_DEBUG("fb%d, dss clk on!\n", hisifd->index);
		if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_VCC_OFF) {
			dpe_regulator_enable(hisifd);
		}

		if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_CLK_OFF) {
			mipi_dsi_clk_enable(hisifd);
			dpe_clk_enable(hisifd);
		}

		if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_MIPI_ULPS) {
			mipi_dsi_ulps_cfg(hisifd, 1);
		}

		vsync_ctrl->vsync_ctrl_enabled = 1;
		clk_enabled = 1;
	}

	spin_lock_irqsave(&(vsync_ctrl->spin_lock), flags);
	vsync_ctrl->vsync_ctrl_disabled_set = 0;
	vsync_ctrl->vsync_ctrl_expire_count = 0;

	if (clk_enabled) {
		if (pdata->vsync_ctrl) {
			pdata->vsync_ctrl(hisifd->pdev, 1);
		} else {
			HISI_FB_ERR("fb%d, vsync_ctrl not supported!\n", hisifd->index);
		}
	}
	spin_unlock_irqrestore(&(vsync_ctrl->spin_lock), flags);

	mutex_unlock(&(vsync_ctrl->vsync_lock));
}
bool hisi_fb_device_probe_defer(uint32_t panel_type)
{
	bool flag = true;

	down(&hisi_fb_dts_resource_sem);

	switch (panel_type) {
	case PANEL_NO:
		if(g_dts_resouce_ready & DTS_FB_RESOURCE_INIT_READY) {
			flag = false;
		}
		break;
	case PANEL_LCDC:
	case PANEL_MIPI2RGB:
	case PANEL_RGB2MIPI:
		if ((g_dts_resouce_ready & DTS_FB_RESOURCE_INIT_READY) &&
			(g_dts_resouce_ready & DTS_PWM_READY) &&
			(g_dts_resouce_ready & DTS_SPI_READY)) {
			flag = false;
		}
		break;
	case PANEL_MIPI_VIDEO:
	case PANEL_MIPI_CMD:
	case PANEL_DUAL_MIPI_VIDEO:
	case PANEL_DUAL_MIPI_CMD:
	case PANEL_EDP:
		if ((g_dts_resouce_ready & DTS_FB_RESOURCE_INIT_READY) &&
			(g_dts_resouce_ready & DTS_PWM_READY)) {
			flag = false;
		}
		break;
	case PANEL_HDMI:
		if (g_dts_resouce_ready & DTS_PANEL_PRIMARY_READY)
			flag = false;
		break;
	case PANEL_OFFLINECOMPOSER:
		if (g_dts_resouce_ready & DTS_PANEL_EXTERNAL_READY)
			flag = false;
		break;
	case PANEL_WRITEBACK:
		if (g_dts_resouce_ready & DTS_PANEL_OFFLINECOMPOSER_READY)
			flag = false;
		break;
	default:
		HISI_FB_ERR("not support this panel type(%d).\n", panel_type);
		break;
	}

	up(&hisi_fb_dts_resource_sem);

	return flag;
}
int hisi_pwm_on(struct platform_device *pdev)
{
	int ret = 0;
	struct clk *clk_tmp = NULL;

	BUG_ON(pdev == NULL);

	clk_tmp = g_dss_pwm_clk;
	if (clk_tmp) {
		ret = clk_prepare(clk_tmp);
		if (ret) {
			HISI_FB_ERR("dss_pwm_clk clk_prepare failed, error=%d!\n", ret);
			return -EINVAL;
		}

		ret = clk_enable(clk_tmp);
		if (ret) {
			HISI_FB_ERR("dss_pwm_clk clk_enable failed, error=%d!\n", ret);
			return -EINVAL;
		}
	}

	ret = pinctrl_cmds_tx(g_pwm_pdev, pwm_pinctrl_normal_cmds,
		ARRAY_SIZE(pwm_pinctrl_normal_cmds));

	#ifdef CONFIG_BACKLIGHT_10000
		init_bl_info();
		cabc_pwm_task = kthread_create(cabc_pwm_thread, NULL, "cabc_pwm_task");
		if(IS_ERR(cabc_pwm_task))
		{
			HISI_FB_ERR("Unable to start kernel cabc_pwm_task./n");
			cabc_pwm_task = NULL;
			return -EINVAL;
		}
	#endif
	return ret;
}
static ssize_t mipi_dsi_bit_clk_upt_store(struct platform_device *pdev,
	const char *buf, size_t count)
{
	struct hisi_fb_data_type *hisifd = NULL;
	struct hisi_panel_info *pinfo = NULL;

	BUG_ON(pdev == NULL);
	hisifd = platform_get_drvdata(pdev);
	BUG_ON(hisifd == NULL);
	pinfo = &(hisifd->panel_info);

	if (!hisifd->panel_info.dsi_bit_clk_upt_support) {
		HISI_FB_ERR("fb%d, not support!", hisifd->index);
		return count;
	}

	HISI_FB_DEBUG("fb%d, +.\n", hisifd->index);

	if (!strncmp(buf, MIPI_DSI_BIT_CLK_STR1, count)) {
		pinfo->mipi.dsi_bit_clk_upt = pinfo->mipi.dsi_bit_clk_val1;
	} else if (!strncmp(buf, MIPI_DSI_BIT_CLK_STR2, count)) {
		pinfo->mipi.dsi_bit_clk_upt = pinfo->mipi.dsi_bit_clk_val2;
	} else if (!strncmp(buf, MIPI_DSI_BIT_CLK_STR3, count)) {
		pinfo->mipi.dsi_bit_clk_upt = pinfo->mipi.dsi_bit_clk_val3;
	} else if (!strncmp(buf, MIPI_DSI_BIT_CLK_STR4, count)) {
		pinfo->mipi.dsi_bit_clk_upt = pinfo->mipi.dsi_bit_clk_val4;
	} else if (!strncmp(buf, MIPI_DSI_BIT_CLK_STR5, count)) {
		pinfo->mipi.dsi_bit_clk_upt = pinfo->mipi.dsi_bit_clk_val5;
	} else {
		HISI_FB_ERR("fb%d, unknown dsi_bit_clk_index!\n", hisifd->index);
	}

	HISI_FB_DEBUG("fb%d, -.\n", hisifd->index);

	return count;
}
void hisi_dss_mctl_ov_set_ctl_dbg_reg(struct hisi_fb_data_type *hisifd, char __iomem *mctl_dgb)
{
	if (hisifd == NULL) {
		HISI_FB_ERR("hisifd is null");
		return;
	}

	if (is_mipi_cmd_panel(hisifd) && (hisifd->ldi_data_gate_en == 1)) {
		//open underflow clear
		set_reg(mctl_dgb, 0x782620, 32, 0);
	} else {
		//open underflow clear
		set_reg(mctl_dgb, 0x70A620, 32, 0);
		//set_reg(mctl_dgb, 0xB02620, 32, 0);
	}
}
void init_dpp(struct hisi_fb_data_type *hisifd)
{
	char __iomem *dpp_base = NULL;

	BUG_ON(hisifd == NULL);

	if (hisifd->index == PRIMARY_PANEL_IDX) {
		dpp_base = hisifd->dss_base + DSS_DPP0_CTRL_OFFSET;
	} else {
		HISI_FB_ERR("fb%d, not support!", hisifd->index);
		return ;
	}

	set_reg(dpp_base + DPP_IMG_HRZ, DSS_WIDTH(hisifd->panel_info.xres), 13, 0);
	set_reg(dpp_base + DPP_IMG_VRT, DSS_HEIGHT(hisifd->panel_info.yres), 13, 0);

#ifdef CONFIG_FIX_DIRTY_REGION_UPDT
	if (is_mipi_cmd_panel(hisifd)) {
		outp32(dpp_base + DPP_CLK_GT, 0xA);
	}
#endif
}
int hisi_fb_device_set_status1(struct hisi_fb_data_type *hisifd)
{
	int ret = 0;

	BUG_ON(hisifd == NULL);

	down(&hisi_fb_dts_resource_sem);

	switch (hisifd->panel_info.type) {
	case PANEL_LCDC:
	case PANEL_MIPI_VIDEO:
	case PANEL_MIPI_CMD:
	case PANEL_DUAL_MIPI_VIDEO:
	case PANEL_DUAL_MIPI_CMD:
	case PANEL_EDP:
	case PANEL_MIPI2RGB:
	case PANEL_RGB2MIPI:
		g_dts_resouce_ready |= DTS_PANEL_PRIMARY_READY;
		break;
	case PANEL_HDMI:
		g_dts_resouce_ready |= DTS_PANEL_EXTERNAL_READY;
		break;
	case PANEL_OFFLINECOMPOSER:
		g_dts_resouce_ready |= DTS_PANEL_OFFLINECOMPOSER_READY;
		break;
	case PANEL_WRITEBACK:
		g_dts_resouce_ready |= DTS_PANEL_WRITEBACK_READY;
		break;
	default:
		HISI_FB_ERR("not support this panel type(%d).\n", hisifd->panel_info.type);
		ret = -1;
		break;
	}

	up(&hisi_fb_dts_resource_sem);

	return ret;
}
void dss_underflow_debug_func(struct work_struct *work)
{
	struct clk *ddr_clk = NULL;
	unsigned long curr_ddr = 0;
	struct hisi_fb_data_type *hisifd = NULL;
	static u32 underflow_index = 0;
	static ktime_t underflow_timestamp[UNDERFLOW_EXPIRE_COUNT];
	s64 underflow_msecs = 0;
	static bool init_underflow_timestamp = false;
	int i;

	if (!init_underflow_timestamp) {
		underflow_timestamp[underflow_index] = ktime_get();
		underflow_index ++;
	}
	if (underflow_index == UNDERFLOW_EXPIRE_COUNT) {
		init_underflow_timestamp = true;
		underflow_timestamp[UNDERFLOW_EXPIRE_COUNT - 1] = ktime_get();
		underflow_msecs = ktime_to_ms(underflow_timestamp[UNDERFLOW_EXPIRE_COUNT - 1]) - ktime_to_ms(underflow_timestamp[0]);
		for(i = 0; i < UNDERFLOW_EXPIRE_COUNT - 1; i ++)
			underflow_timestamp[i] = underflow_timestamp[i+1];
	}

	ddr_clk = clk_get(NULL, "clk_ddrc_freq");
	if (ddr_clk) {
		curr_ddr = clk_get_rate(ddr_clk);
		clk_put(ddr_clk);
	} else {
		HISI_FB_ERR("Get ddr clk failed");
	}

	if (work) {
		hisifd = container_of(work, struct hisi_fb_data_type, dss_underflow_debug_work);
		if (g_underflow_stop_perf_stat) {
			dumpDssOverlay(hisifd, &hisifd->ov_req, false);
		}
	} else {