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

Commit 9d0685ae authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'imx-drm-fixes-2015-02-24' of git://git.pengutronix.de/git/pza/linux into drm-fixes

imx-drm fixes for mode fixup, dw_hdmi/imx, and parallel-display

- A clock fix for too large pixel clocks depending on the
  DI clock flag simplification patch
- Pruning of unsupported modes and a missing end of array element
  for dw_hdmi-imx
- LVDS modeset fix for mode fixup
- Fix parallel-display deferred probing if drm_panel is used

* tag 'imx-drm-fixes-2015-02-24' of git://git.pengutronix.de/git/pza/linux:
  DRM: i.MX: parallel display: Support probe deferral for finding DRM panel
  drm/imx: imx-ldb: enable DI clock in encoder_mode_set
  drm/imx: dw_hdmi-imx: add end of array element to current control array
  drm/imx: dw_hdmi-imx: add mode_valid callback prune unsupported modes
  gpu: ipu-v3: do not divide by zero if the pixel clock is too large
parents 023a6007 d70e96ae
Loading
Loading
Loading
Loading
+31 −5
Original line number Original line Diff line number Diff line
@@ -70,7 +70,9 @@ static const struct dw_hdmi_curr_ctrl imx_cur_ctr[] = {
		118800000, { 0x091c, 0x091c, 0x06dc },
		118800000, { 0x091c, 0x091c, 0x06dc },
	}, {
	}, {
		216000000, { 0x06dc, 0x0b5c, 0x091c },
		216000000, { 0x06dc, 0x0b5c, 0x091c },
	}
	}, {
		~0UL, { 0x0000, 0x0000, 0x0000 },
	},
};
};


static const struct dw_hdmi_sym_term imx_sym_term[] = {
static const struct dw_hdmi_sym_term imx_sym_term[] = {
@@ -136,11 +138,34 @@ static struct drm_encoder_funcs dw_hdmi_imx_encoder_funcs = {
	.destroy = drm_encoder_cleanup,
	.destroy = drm_encoder_cleanup,
};
};


static enum drm_mode_status imx6q_hdmi_mode_valid(struct drm_connector *con,
						  struct drm_display_mode *mode)
{
	if (mode->clock < 13500)
		return MODE_CLOCK_LOW;
	if (mode->clock > 266000)
		return MODE_CLOCK_HIGH;

	return MODE_OK;
}

static enum drm_mode_status imx6dl_hdmi_mode_valid(struct drm_connector *con,
						   struct drm_display_mode *mode)
{
	if (mode->clock < 13500)
		return MODE_CLOCK_LOW;
	if (mode->clock > 270000)
		return MODE_CLOCK_HIGH;

	return MODE_OK;
}

static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
	.mpll_cfg   = imx_mpll_cfg,
	.mpll_cfg   = imx_mpll_cfg,
	.cur_ctr    = imx_cur_ctr,
	.cur_ctr    = imx_cur_ctr,
	.sym_term   = imx_sym_term,
	.sym_term   = imx_sym_term,
	.dev_type   = IMX6Q_HDMI,
	.dev_type   = IMX6Q_HDMI,
	.mode_valid = imx6q_hdmi_mode_valid,
};
};


static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
@@ -148,6 +173,7 @@ static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
	.cur_ctr  = imx_cur_ctr,
	.cur_ctr  = imx_cur_ctr,
	.sym_term = imx_sym_term,
	.sym_term = imx_sym_term,
	.dev_type = IMX6DL_HDMI,
	.dev_type = IMX6DL_HDMI,
	.mode_valid = imx6dl_hdmi_mode_valid,
};
};


static const struct of_device_id dw_hdmi_imx_dt_ids[] = {
static const struct of_device_id dw_hdmi_imx_dt_ids[] = {
+13 −15
Original line number Original line Diff line number Diff line
@@ -163,22 +163,7 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
{
{
	struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
	struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
	struct imx_ldb *ldb = imx_ldb_ch->ldb;
	struct imx_ldb *ldb = imx_ldb_ch->ldb;
	struct drm_display_mode *mode = &encoder->crtc->hwmode;
	u32 pixel_fmt;
	u32 pixel_fmt;
	unsigned long serial_clk;
	unsigned long di_clk = mode->clock * 1000;
	int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder);

	if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
		/* dual channel LVDS mode */
		serial_clk = 3500UL * mode->clock;
		imx_ldb_set_clock(ldb, mux, 0, serial_clk, di_clk);
		imx_ldb_set_clock(ldb, mux, 1, serial_clk, di_clk);
	} else {
		serial_clk = 7000UL * mode->clock;
		imx_ldb_set_clock(ldb, mux, imx_ldb_ch->chno, serial_clk,
				di_clk);
	}


	switch (imx_ldb_ch->chno) {
	switch (imx_ldb_ch->chno) {
	case 0:
	case 0:
@@ -247,6 +232,9 @@ static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
	struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
	struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
	struct imx_ldb *ldb = imx_ldb_ch->ldb;
	struct imx_ldb *ldb = imx_ldb_ch->ldb;
	int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
	int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
	unsigned long serial_clk;
	unsigned long di_clk = mode->clock * 1000;
	int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder);


	if (mode->clock > 170000) {
	if (mode->clock > 170000) {
		dev_warn(ldb->dev,
		dev_warn(ldb->dev,
@@ -257,6 +245,16 @@ static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
			 "%s: mode exceeds 85 MHz pixel clock\n", __func__);
			 "%s: mode exceeds 85 MHz pixel clock\n", __func__);
	}
	}


	if (dual) {
		serial_clk = 3500UL * mode->clock;
		imx_ldb_set_clock(ldb, mux, 0, serial_clk, di_clk);
		imx_ldb_set_clock(ldb, mux, 1, serial_clk, di_clk);
	} else {
		serial_clk = 7000UL * mode->clock;
		imx_ldb_set_clock(ldb, mux, imx_ldb_ch->chno, serial_clk,
				  di_clk);
	}

	/* FIXME - assumes straight connections DI0 --> CH0, DI1 --> CH1 */
	/* FIXME - assumes straight connections DI0 --> CH0, DI1 --> CH1 */
	if (imx_ldb_ch == &ldb->channel[0]) {
	if (imx_ldb_ch == &ldb->channel[0]) {
		if (mode->flags & DRM_MODE_FLAG_NVSYNC)
		if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+4 −1
Original line number Original line Diff line number Diff line
@@ -236,8 +236,11 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
	}
	}


	panel_node = of_parse_phandle(np, "fsl,panel", 0);
	panel_node = of_parse_phandle(np, "fsl,panel", 0);
	if (panel_node)
	if (panel_node) {
		imxpd->panel = of_drm_find_panel(panel_node);
		imxpd->panel = of_drm_find_panel(panel_node);
		if (!imxpd->panel)
			return -EPROBE_DEFER;
	}


	imxpd->dev = dev;
	imxpd->dev = dev;


+2 −0
Original line number Original line Diff line number Diff line
@@ -459,6 +459,8 @@ static void ipu_di_config_clock(struct ipu_di *di,


		clkrate = clk_get_rate(di->clk_ipu);
		clkrate = clk_get_rate(di->clk_ipu);
		div = DIV_ROUND_CLOSEST(clkrate, sig->mode.pixelclock);
		div = DIV_ROUND_CLOSEST(clkrate, sig->mode.pixelclock);
		if (div == 0)
			div = 1;
		rate = clkrate / div;
		rate = clkrate / div;


		error = rate / (sig->mode.pixelclock / 1000);
		error = rate / (sig->mode.pixelclock / 1000);