Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a4ae0ba8 authored by Tomi Valkeinen's avatar Tomi Valkeinen
Browse files

Merge branch '3.8/dsi-pll-work'

Merge omapdss patches to enable using DSI PLL for DPI output.
parents 9296dbd7 0e8276ef
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -510,6 +510,9 @@ static int __init omap_dss_bus_register(void)

/* INIT */
static int (*dss_output_drv_reg_funcs[])(void) __initdata = {
#ifdef CONFIG_OMAP2_DSS_DSI
	dsi_init_platform_driver,
#endif
#ifdef CONFIG_OMAP2_DSS_DPI
	dpi_init_platform_driver,
#endif
@@ -522,15 +525,15 @@ static int (*dss_output_drv_reg_funcs[])(void) __initdata = {
#ifdef CONFIG_OMAP2_DSS_VENC
	venc_init_platform_driver,
#endif
#ifdef CONFIG_OMAP2_DSS_DSI
	dsi_init_platform_driver,
#endif
#ifdef CONFIG_OMAP4_DSS_HDMI
	hdmi_init_platform_driver,
#endif
};

static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = {
#ifdef CONFIG_OMAP2_DSS_DSI
	dsi_uninit_platform_driver,
#endif
#ifdef CONFIG_OMAP2_DSS_DPI
	dpi_uninit_platform_driver,
#endif
@@ -543,9 +546,6 @@ static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = {
#ifdef CONFIG_OMAP2_DSS_VENC
	venc_uninit_platform_driver,
#endif
#ifdef CONFIG_OMAP2_DSS_DSI
	dsi_uninit_platform_driver,
#endif
#ifdef CONFIG_OMAP4_DSS_HDMI
	hdmi_uninit_platform_driver,
#endif
+69 −30
Original line number Diff line number Diff line
@@ -49,34 +49,37 @@ static struct {
	struct omap_dss_output output;
} dpi;

static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk)
static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
{
	int dsi_module;

	dsi_module = clk == OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ? 0 : 1;

	return dsi_get_dsidev_from_id(dsi_module);
	switch (channel) {
	case OMAP_DSS_CHANNEL_LCD:
		return dsi_get_dsidev_from_id(0);
	case OMAP_DSS_CHANNEL_LCD2:
		return dsi_get_dsidev_from_id(1);
	default:
		return NULL;
	}
}

static bool dpi_use_dsi_pll(struct omap_dss_device *dssdev)
static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel)
{
	if (dssdev->clocks.dispc.dispc_fclk_src ==
			OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ||
			dssdev->clocks.dispc.dispc_fclk_src ==
			OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC ||
			dssdev->clocks.dispc.channel.lcd_clk_src ==
			OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ||
			dssdev->clocks.dispc.channel.lcd_clk_src ==
			OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC)
		return true;
	else
		return false;
	switch (channel) {
	case OMAP_DSS_CHANNEL_LCD:
		return OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC;
	case OMAP_DSS_CHANNEL_LCD2:
		return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC;
	default:
		/* this shouldn't happen */
		WARN_ON(1);
		return OMAP_DSS_CLK_SRC_FCK;
	}
}

static int dpi_set_dsi_clk(struct omap_dss_device *dssdev,
		unsigned long pck_req, unsigned long *fck, int *lck_div,
		int *pck_div)
{
	struct omap_overlay_manager *mgr = dssdev->output->manager;
	struct dsi_clock_info dsi_cinfo;
	struct dispc_clock_info dispc_cinfo;
	int r;
@@ -90,7 +93,8 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev,
	if (r)
		return r;

	dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
	dss_select_lcd_clk_source(mgr->id,
			dpi_get_alt_clk_src(mgr->id));

	dpi.mgr_config.clock_info = dispc_cinfo;

@@ -135,7 +139,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
	unsigned long pck;
	int r = 0;

	if (dpi_use_dsi_pll(dssdev))
	if (dpi.dsidev)
		r = dpi_set_dsi_clk(dssdev, t->pixel_clock * 1000, &fck,
				&lck_div, &pck_div);
	else
@@ -214,7 +218,7 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
	if (r)
		goto err_src_sel;

	if (dpi_use_dsi_pll(dssdev)) {
	if (dpi.dsidev) {
		r = dsi_runtime_get(dpi.dsidev);
		if (r)
			goto err_get_dsi;
@@ -242,10 +246,10 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)

err_mgr_enable:
err_set_mode:
	if (dpi_use_dsi_pll(dssdev))
	if (dpi.dsidev)
		dsi_pll_uninit(dpi.dsidev, true);
err_dsi_pll_init:
	if (dpi_use_dsi_pll(dssdev))
	if (dpi.dsidev)
		dsi_runtime_put(dpi.dsidev);
err_get_dsi:
err_src_sel:
@@ -271,8 +275,8 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)

	dss_mgr_disable(mgr);

	if (dpi_use_dsi_pll(dssdev)) {
		dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
	if (dpi.dsidev) {
		dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
		dsi_pll_uninit(dpi.dsidev, true);
		dsi_runtime_put(dpi.dsidev);
	}
@@ -317,7 +321,7 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
	if (timings->pixel_clock == 0)
		return -EINVAL;

	if (dpi_use_dsi_pll(dssdev)) {
	if (dpi.dsidev) {
		struct dsi_clock_info dsi_cinfo;
		r = dsi_pll_calc_clock_div_pck(dpi.dsidev,
				timings->pixel_clock * 1000,
@@ -359,8 +363,32 @@ void omapdss_dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
}
EXPORT_SYMBOL(omapdss_dpi_set_data_lines);

static int __init dpi_verify_dsi_pll(struct platform_device *dsidev)
{
	int r;

	/* do initial setup with the PLL to see if it is operational */

	r = dsi_runtime_get(dsidev);
	if (r)
		return r;

	r = dsi_pll_init(dsidev, 0, 1);
	if (r) {
		dsi_runtime_put(dsidev);
		return r;
	}

	dsi_pll_uninit(dsidev, true);
	dsi_runtime_put(dsidev);

	return 0;
}

static int __init dpi_init_display(struct omap_dss_device *dssdev)
{
	struct platform_device *dsidev;

	DSSDBG("init_display\n");

	if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) &&
@@ -377,12 +405,23 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev)
		dpi.vdds_dsi_reg = vdds_dsi;
	}

	if (dpi_use_dsi_pll(dssdev)) {
		enum omap_dss_clk_source dispc_fclk_src =
			dssdev->clocks.dispc.dispc_fclk_src;
		dpi.dsidev = dpi_get_dsidev(dispc_fclk_src);
	/*
	 * XXX We shouldn't need dssdev->channel for this. The dsi pll clock
	 * source for DPI is SoC integration detail, not something that should
	 * be configured in the dssdev
	 */
	dsidev = dpi_get_dsidev(dssdev->channel);

	if (dpi_verify_dsi_pll(dsidev)) {
		dsidev = NULL;
		DSSWARN("DSI PLL not operational\n");
	}

	if (dsidev)
		DSSDBG("using DSI PLL for DPI clock\n");

	dpi.dsidev = dsidev;

	return 0;
}

+11 −3
Original line number Diff line number Diff line
@@ -1386,6 +1386,11 @@ retry:
				cur.dsi_pll_hsdiv_dispc_clk =
					cur.clkin4ddr / cur.regm_dispc;

				if (cur.regm_dispc > 1 &&
						cur.regm_dispc % 2 != 0 &&
						req_pck >= 1000000)
					continue;

				/* this will narrow down the search a bit,
				 * but still give pixclocks below what was
				 * requested */
@@ -1736,6 +1741,12 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,

	DSSDBG("PLL init\n");

	/*
	 * It seems that on many OMAPs we need to enable both to have a
	 * functional HSDivider.
	 */
	enable_hsclk = enable_hsdiv = true;

	if (dsi->vdds_dsi_reg == NULL) {
		struct regulator *vdds_dsi;

@@ -4709,7 +4720,6 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
	if (r)
		goto err1;

	dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
	dss_select_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src);
	dss_select_lcd_clk_source(mgr->id,
			dssdev->clocks.dispc.channel.lcd_clk_src);
@@ -4744,7 +4754,6 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
err3:
	dsi_cio_uninit(dsidev);
err2:
	dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
	dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
	dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);

@@ -4771,7 +4780,6 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
	dsi_vc_enable(dsidev, 2, 0);
	dsi_vc_enable(dsidev, 3, 0);

	dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
	dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
	dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
	dsi_cio_uninit(dsidev);
+64 −2
Original line number Diff line number Diff line
@@ -304,7 +304,7 @@ static void dss_dump_regs(struct seq_file *s)
#undef DUMPREG
}

void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
{
	struct platform_device *dsidev;
	int b;
@@ -375,8 +375,10 @@ void dss_select_lcd_clk_source(enum omap_channel channel,
	struct platform_device *dsidev;
	int b, ix, pos;

	if (!dss_has_feature(FEAT_LCD_CLK_SRC))
	if (!dss_has_feature(FEAT_LCD_CLK_SRC)) {
		dss_select_dispc_clk_source(clk_src);
		return;
	}

	switch (clk_src) {
	case OMAP_DSS_CLK_SRC_FCK:
@@ -432,6 +434,29 @@ enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
	}
}

/* calculate clock rates using dividers in cinfo */
int dss_calc_clock_rates(struct dss_clock_info *cinfo)
{
	if (dss.dpll4_m4_ck) {
		unsigned long prate;

		if (cinfo->fck_div > dss.feat->fck_div_max ||
				cinfo->fck_div == 0)
			return -EINVAL;

		prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));

		cinfo->fck = prate / cinfo->fck_div *
			dss.feat->dss_fck_multiplier;
	} else {
		if (cinfo->fck_div != 0)
			return -EINVAL;
		cinfo->fck = clk_get_rate(dss.dss_clk);
	}

	return 0;
}

int dss_set_clock_div(struct dss_clock_info *cinfo)
{
	if (dss.dpll4_m4_ck) {
@@ -462,6 +487,36 @@ unsigned long dss_get_dpll4_rate(void)
		return 0;
}

static int dss_setup_default_clock(void)
{
	unsigned long max_dss_fck, prate;
	unsigned fck_div;
	struct dss_clock_info dss_cinfo = { 0 };
	int r;

	if (dss.dpll4_m4_ck == NULL)
		return 0;

	max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);

	prate = dss_get_dpll4_rate();

	fck_div = DIV_ROUND_UP(prate * dss.feat->dss_fck_multiplier,
			max_dss_fck);

	dss_cinfo.fck_div = fck_div;

	r = dss_calc_clock_rates(&dss_cinfo);
	if (r)
		return r;

	r = dss_set_clock_div(&dss_cinfo);
	if (r)
		return r;

	return 0;
}

int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
		struct dispc_clock_info *dispc_cinfo)
{
@@ -869,6 +924,10 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
	if (r)
		return r;

	r = dss_setup_default_clock();
	if (r)
		goto err_setup_clocks;

	pm_runtime_enable(&pdev->dev);

	r = dss_runtime_get();
@@ -878,6 +937,8 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
	/* Select DPLL */
	REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);

	dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);

#ifdef CONFIG_OMAP2_DSS_VENC
	REG_FLD_MOD(DSS_CONTROL, 1, 4, 4);	/* venc dac demen */
	REG_FLD_MOD(DSS_CONTROL, 1, 3, 3);	/* venc clock 4x enable */
@@ -901,6 +962,7 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)

err_runtime_get:
	pm_runtime_disable(&pdev->dev);
err_setup_clocks:
	dss_put_clocks();
	return r;
}
+1 −1
Original line number Diff line number Diff line
@@ -283,7 +283,6 @@ void dss_sdi_init(int datapairs);
int dss_sdi_enable(void);
void dss_sdi_disable(void);

void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src);
void dss_select_dsi_clk_source(int dsi_module,
		enum omap_dss_clk_source clk_src);
void dss_select_lcd_clk_source(enum omap_channel channel,
@@ -296,6 +295,7 @@ void dss_set_venc_output(enum omap_dss_venc_type type);
void dss_set_dac_pwrdn_bgz(bool enable);

unsigned long dss_get_dpll4_rate(void);
int dss_calc_clock_rates(struct dss_clock_info *cinfo);
int dss_set_clock_div(struct dss_clock_info *cinfo);
int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
		struct dispc_clock_info *dispc_cinfo);
Loading