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

Commit 406f7b8b authored by Tomi Valkeinen's avatar Tomi Valkeinen
Browse files

Merge OMAP5 DSS changes to omapdss

This series adds basic OMAP5 DSS functionality, mainly related to DSS core, DPI
and DSI.

* omap5-dss:
  OMAPDSS: DSI: make OMAP2_DSS_DSI depend on ARCH_OMAP5
  OMAPDSS: DSI: Add code to disable PHY DCC
  OMAPDSS: DSI: Add new linebuffer size for OMAP5
  OMAPDSS: DSI: Add FEAT_DSI_PLL_REFSEL
  OMAPDSS: DSI: Add FEAT_DSI_PLL_SELFREQDCO
  OMAPDSS: Add support for DPI source selection
  OMAPDSS: move dss feats to the end of dss.c
  OMAPDSS: Add basic omap5 features to dss and dispc
  OMAPDSS: DSI: improve DSI clock calcs for DISPC
parents c0ca7c38 99588589
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -84,7 +84,7 @@ config OMAP2_DSS_SDI

config OMAP2_DSS_DSI
	bool "DSI support"
	depends on ARCH_OMAP3 || ARCH_OMAP4
	depends on ARCH_OMAP3 || ARCH_OMAP4 || ARCH_OMAP5
        default n
	help
	  MIPI DSI (Display Serial Interface) support.
+2 −0
Original line number Diff line number Diff line
@@ -3829,6 +3829,8 @@ static int __init dispc_init_features(struct device *dev)
			src = &omap34xx_rev3_0_dispc_feats;
	} else if (cpu_is_omap44xx()) {
		src = &omap44xx_dispc_feats;
	} else if (soc_is_omap54xx()) {
		src = &omap44xx_dispc_feats;
	} else {
		return -ENODEV;
	}
+5 −0
Original line number Diff line number Diff line
@@ -203,6 +203,10 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
	if (r)
		goto err_get_dispc;

	r = dss_dpi_select_source(dssdev->channel);
	if (r)
		goto err_src_sel;

	if (dpi_use_dsi_pll(dssdev)) {
		r = dsi_runtime_get(dpi.dsidev);
		if (r)
@@ -237,6 +241,7 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
	if (dpi_use_dsi_pll(dssdev))
		dsi_runtime_put(dpi.dsidev);
err_get_dsi:
err_src_sel:
	dispc_runtime_put();
err_get_dispc:
	if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
+132 −35
Original line number Diff line number Diff line
@@ -1454,26 +1454,17 @@ int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev,
}

static int dsi_pll_calc_ddrfreq(struct platform_device *dsidev,
		unsigned long req_clk, struct dsi_clock_info *cinfo)
		unsigned long req_clkin4ddr, struct dsi_clock_info *cinfo)
{
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
	struct dsi_clock_info cur, best;
	unsigned long dss_sys_clk, max_dss_fck, max_dsi_fck;
	unsigned long req_clkin4ddr;

	DSSDBG("dsi_pll_calc_ddrfreq\n");

	dss_sys_clk = clk_get_rate(dsi->sys_clk);

	max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
	max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK);

	memset(&best, 0, sizeof(best));
	memset(&cur, 0, sizeof(cur));

	cur.clkin = dss_sys_clk;

	req_clkin4ddr = req_clk * 4;
	cur.clkin = clk_get_rate(dsi->sys_clk);

	for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) {
		cur.fint = cur.clkin / cur.regn;
@@ -1503,18 +1494,107 @@ static int dsi_pll_calc_ddrfreq(struct platform_device *dsidev,
		}
	}
found:
	best.regm_dispc = DIV_ROUND_UP(best.clkin4ddr, max_dss_fck);
	best.dsi_pll_hsdiv_dispc_clk = best.clkin4ddr / best.regm_dispc;

	best.regm_dsi = DIV_ROUND_UP(best.clkin4ddr, max_dsi_fck);
	best.dsi_pll_hsdiv_dsi_clk = best.clkin4ddr / best.regm_dsi;

	if (cinfo)
		*cinfo = best;

	return 0;
}

static void dsi_pll_calc_dsi_fck(struct platform_device *dsidev,
		struct dsi_clock_info *cinfo)
{
	unsigned long max_dsi_fck;

	max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK);

	cinfo->regm_dsi = DIV_ROUND_UP(cinfo->clkin4ddr, max_dsi_fck);
	cinfo->dsi_pll_hsdiv_dsi_clk = cinfo->clkin4ddr / cinfo->regm_dsi;
}

static int dsi_pll_calc_dispc_fck(struct platform_device *dsidev,
		unsigned long req_pck, struct dsi_clock_info *cinfo,
		struct dispc_clock_info *dispc_cinfo)
{
	struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
	unsigned regm_dispc, best_regm_dispc;
	unsigned long dispc_clk, best_dispc_clk;
	int min_fck_per_pck;
	unsigned long max_dss_fck;
	struct dispc_clock_info best_dispc;
	bool match;

	max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);

	min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;

	if (min_fck_per_pck &&
			req_pck * min_fck_per_pck > max_dss_fck) {
		DSSERR("Requested pixel clock not possible with the current "
				"OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
				"the constraint off.\n");
		min_fck_per_pck = 0;
	}

retry:
	best_regm_dispc = 0;
	best_dispc_clk = 0;
	memset(&best_dispc, 0, sizeof(best_dispc));
	match = false;

	for (regm_dispc = 1; regm_dispc < dsi->regm_dispc_max; ++regm_dispc) {
		struct dispc_clock_info cur_dispc;

		dispc_clk = cinfo->clkin4ddr / regm_dispc;

		/* this will narrow down the search a bit,
		 * but still give pixclocks below what was
		 * requested */
		if (dispc_clk  < req_pck)
			break;

		if (dispc_clk > max_dss_fck)
			continue;

		if (min_fck_per_pck && dispc_clk < req_pck * min_fck_per_pck)
			continue;

		match = true;

		dispc_find_clk_divs(req_pck, dispc_clk, &cur_dispc);

		if (abs(cur_dispc.pck - req_pck) <
				abs(best_dispc.pck - req_pck)) {
			best_regm_dispc = regm_dispc;
			best_dispc_clk = dispc_clk;
			best_dispc = cur_dispc;

			if (cur_dispc.pck == req_pck)
				goto found;
		}
	}

	if (!match) {
		if (min_fck_per_pck) {
			DSSERR("Could not find suitable clock settings.\n"
					"Turning FCK/PCK constraint off and"
					"trying again.\n");
			min_fck_per_pck = 0;
			goto retry;
		}

		DSSERR("Could not find suitable clock settings.\n");

		return -EINVAL;
	}
found:
	cinfo->regm_dispc = best_regm_dispc;
	cinfo->dsi_pll_hsdiv_dispc_clk = best_dispc_clk;

	*dispc_cinfo = best_dispc;

	return 0;
}

int dsi_pll_set_clock_div(struct platform_device *dsidev,
		struct dsi_clock_info *cinfo)
{
@@ -1591,21 +1671,27 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev,

	BUG_ON(cinfo->fint < dsi->fint_min || cinfo->fint > dsi->fint_max);

	l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2);

	if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) {
		f = cinfo->fint < 1000000 ? 0x3 :
			cinfo->fint < 1250000 ? 0x4 :
			cinfo->fint < 1500000 ? 0x5 :
			cinfo->fint < 1750000 ? 0x6 :
			0x7;
	}

	l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2);

	if (dss_has_feature(FEAT_DSI_PLL_FREQSEL))
		l = FLD_MOD(l, f, 4, 1);	/* DSI_PLL_FREQSEL */
	} else if (dss_has_feature(FEAT_DSI_PLL_SELFREQDCO)) {
		f = cinfo->clkin4ddr < 1000000000 ? 0x2 : 0x4;

		l = FLD_MOD(l, f, 4, 1);	/* PLL_SELFREQDCO */
	}

	l = FLD_MOD(l, 1, 13, 13);		/* DSI_PLL_REFEN */
	l = FLD_MOD(l, 0, 14, 14);		/* DSIPHY_CLKINEN */
	l = FLD_MOD(l, 1, 20, 20);		/* DSI_HSDIVBYPASS */
	if (dss_has_feature(FEAT_DSI_PLL_REFSEL))
		l = FLD_MOD(l, 3, 22, 21);	/* REF_SYSCLK = sysclk */
	dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l);

	REG_FLD_MOD(dsidev, DSI_PLL_GO, 1, 0, 0);	/* DSI_PLL_GO */
@@ -2069,6 +2155,8 @@ static unsigned dsi_get_line_buf_size(struct platform_device *dsidev)
		return 1194 * 3;	/* 1194x24 bits */
	case 6:
		return 1365 * 3;	/* 1365x24 bits */
	case 7:
		return 1920 * 3;	/* 1920x24 bits */
	default:
		BUG();
		return 0;
@@ -2204,6 +2292,13 @@ static void dsi_cio_timings(struct platform_device *dsidev)
	r = FLD_MOD(r, tlpx_half, 22, 16);
	r = FLD_MOD(r, tclk_trail, 15, 8);
	r = FLD_MOD(r, tclk_zero, 7, 0);

	if (dss_has_feature(FEAT_DSI_PHY_DCC)) {
		r = FLD_MOD(r, 0, 21, 21);	/* DCCEN = disable */
		r = FLD_MOD(r, 1, 22, 22);	/* CLKINP_DIVBY2EN = enable */
		r = FLD_MOD(r, 1, 23, 23);	/* CLKINP_SEL = enable */
	}

	dsi_write_reg(dsidev, DSI_DSIPHY_CFG1, r);

	r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2);
@@ -4188,33 +4283,35 @@ int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev,

	mutex_lock(&dsi->lock);

	r = dsi_pll_calc_ddrfreq(dsidev, ddr_clk, &cinfo);
	/* Calculate PLL output clock */
	r = dsi_pll_calc_ddrfreq(dsidev, ddr_clk * 4, &cinfo);
	if (r)
		goto err;

	dssdev->clocks.dsi.regn = cinfo.regn;
	dssdev->clocks.dsi.regm = cinfo.regm;
	dssdev->clocks.dsi.regm_dispc = cinfo.regm_dispc;
	dssdev->clocks.dsi.regm_dsi = cinfo.regm_dsi;
	/* Calculate PLL's DSI clock */
	dsi_pll_calc_dsi_fck(dsidev, &cinfo);

	/* Calculate PLL's DISPC clock and pck & lck divs */
	pck = cinfo.clkin4ddr / 16 * (dsi->num_lanes_used - 1) * 8 / bpp;
	DSSDBG("finding dispc dividers for pck %lu\n", pck);
	r = dsi_pll_calc_dispc_fck(dsidev, pck, &cinfo, &dispc_cinfo);
	if (r)
		goto err;

	/* Calculate LP clock */
	dsi_fclk = cinfo.dsi_pll_hsdiv_dsi_clk;
	lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk * 2);

	dssdev->clocks.dsi.lp_clk_div = lp_clk_div;

	/* pck = TxByteClkHS * datalanes * 8 / bitsperpixel */

	pck = cinfo.clkin4ddr / 16 * (dsi->num_lanes_used - 1) * 8 / bpp;

	DSSDBG("finding dispc dividers for pck %lu\n", pck);
	dssdev->clocks.dsi.regn = cinfo.regn;
	dssdev->clocks.dsi.regm = cinfo.regm;
	dssdev->clocks.dsi.regm_dispc = cinfo.regm_dispc;
	dssdev->clocks.dsi.regm_dsi = cinfo.regm_dsi;

	dispc_find_clk_divs(pck, cinfo.dsi_pll_hsdiv_dispc_clk, &dispc_cinfo);
	dssdev->clocks.dsi.lp_clk_div = lp_clk_div;

	dssdev->clocks.dispc.channel.lck_div = dispc_cinfo.lck_div;
	dssdev->clocks.dispc.channel.pck_div = dispc_cinfo.pck_div;


	dssdev->clocks.dispc.dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK;

	dssdev->clocks.dispc.channel.lcd_clk_src =
+97 −24
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ struct dss_features {
	u8 fck_div_max;
	u8 dss_fck_multiplier;
	const char *clk_name;
	int (*dpi_select_source)(enum omap_channel channel);
};

static struct {
@@ -99,30 +100,6 @@ static const char * const dss_generic_clk_source_names[] = {
	[OMAP_DSS_CLK_SRC_FCK]			= "DSS_FCK",
};

static const struct dss_features omap24xx_dss_feats __initconst = {
	.fck_div_max		=	16,
	.dss_fck_multiplier	=	2,
	.clk_name		=	NULL,
};

static const struct dss_features omap34xx_dss_feats __initconst = {
	.fck_div_max		=	16,
	.dss_fck_multiplier	=	2,
	.clk_name		=	"dpll4_m4_ck",
};

static const struct dss_features omap3630_dss_feats __initconst = {
	.fck_div_max		=	32,
	.dss_fck_multiplier	=	1,
	.clk_name		=	"dpll4_m4_ck",
};

static const struct dss_features omap44xx_dss_feats __initconst = {
	.fck_div_max		=	32,
	.dss_fck_multiplier	=	1,
	.clk_name		=	"dpll_per_m5x2_ck",
};

static inline void dss_write_reg(const struct dss_reg idx, u32 val)
{
	__raw_writel(val, dss.base + idx.idx);
@@ -647,6 +624,65 @@ enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
	return REG_GET(DSS_CONTROL, 15, 15);
}

static int dss_dpi_select_source_omap2_omap3(enum omap_channel channel)
{
	if (channel != OMAP_DSS_CHANNEL_LCD)
		return -EINVAL;

	return 0;
}

static int dss_dpi_select_source_omap4(enum omap_channel channel)
{
	int val;

	switch (channel) {
	case OMAP_DSS_CHANNEL_LCD2:
		val = 0;
		break;
	case OMAP_DSS_CHANNEL_DIGIT:
		val = 1;
		break;
	default:
		return -EINVAL;
	}

	REG_FLD_MOD(DSS_CONTROL, val, 17, 17);

	return 0;
}

static int dss_dpi_select_source_omap5(enum omap_channel channel)
{
	int val;

	switch (channel) {
	case OMAP_DSS_CHANNEL_LCD:
		val = 1;
		break;
	case OMAP_DSS_CHANNEL_LCD2:
		val = 2;
		break;
	case OMAP_DSS_CHANNEL_LCD3:
		val = 3;
		break;
	case OMAP_DSS_CHANNEL_DIGIT:
		val = 0;
		break;
	default:
		return -EINVAL;
	}

	REG_FLD_MOD(DSS_CONTROL, val, 17, 16);

	return 0;
}

int dss_dpi_select_source(enum omap_channel channel)
{
	return dss.feat->dpi_select_source(channel);
}

static int dss_get_clocks(void)
{
	struct clk *clk;
@@ -721,6 +757,41 @@ void dss_debug_dump_clocks(struct seq_file *s)
}
#endif

static const struct dss_features omap24xx_dss_feats __initconst = {
	.fck_div_max		=	16,
	.dss_fck_multiplier	=	2,
	.clk_name		=	NULL,
	.dpi_select_source	=	&dss_dpi_select_source_omap2_omap3,
};

static const struct dss_features omap34xx_dss_feats __initconst = {
	.fck_div_max		=	16,
	.dss_fck_multiplier	=	2,
	.clk_name		=	"dpll4_m4_ck",
	.dpi_select_source	=	&dss_dpi_select_source_omap2_omap3,
};

static const struct dss_features omap3630_dss_feats __initconst = {
	.fck_div_max		=	32,
	.dss_fck_multiplier	=	1,
	.clk_name		=	"dpll4_m4_ck",
	.dpi_select_source	=	&dss_dpi_select_source_omap2_omap3,
};

static const struct dss_features omap44xx_dss_feats __initconst = {
	.fck_div_max		=	32,
	.dss_fck_multiplier	=	1,
	.clk_name		=	"dpll_per_m5x2_ck",
	.dpi_select_source	=	&dss_dpi_select_source_omap4,
};

static const struct dss_features omap54xx_dss_feats __initconst = {
	.fck_div_max		=	64,
	.dss_fck_multiplier	=	1,
	.clk_name		=	"dpll_per_h12x2_ck",
	.dpi_select_source	=	&dss_dpi_select_source_omap5,
};

static int __init dss_init_features(struct device *dev)
{
	const struct dss_features *src;
@@ -740,6 +811,8 @@ static int __init dss_init_features(struct device *dev)
		src = &omap3630_dss_feats;
	else if (cpu_is_omap44xx())
		src = &omap44xx_dss_feats;
	else if (soc_is_omap54xx())
		src = &omap54xx_dss_feats;
	else
		return -ENODEV;

Loading