* [PATCH 00/34] imx-drm stuff again
@ 2014-02-18 20:09 Russell King - ARM Linux
2014-02-18 20:09 ` [PATCH 01/34] imx-drm: imx-hdmi: convert HDMI clock settings to tabular form Russell King
` (33 more replies)
0 siblings, 34 replies; 35+ messages in thread
From: Russell King - ARM Linux @ 2014-02-18 20:09 UTC (permalink / raw)
To: linux-arm-kernel
So, I received a request to post this one more time, so here it is.
I've included the audio and cec backends in here again. The cec
backend is compatible with the one in FSL's kernel, but hopefully
more stable (I see people regularly complaining about FSL's one.)
--
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up. Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".
^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH 01/34] imx-drm: imx-hdmi: convert HDMI clock settings to tabular form
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
@ 2014-02-18 20:09 ` Russell King
2014-02-18 20:09 ` [PATCH 02/34] imx-drm: imx-hdmi: clean up setting CSC registers Russell King
` (32 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:09 UTC (permalink / raw)
To: linux-arm-kernel
Rather than having large if() and switch() statements, provide a table
to look up the register settings for various clock rates.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/imx-hdmi.c | 250 ++++++++++++++-----------------------
1 file changed, 95 insertions(+), 155 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 62ce0e86f14b..cb316bf3ec56 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -806,19 +806,94 @@ static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable)
HDMI_PHY_CONF0_SELDIPIF_MASK);
}
+enum {
+ RES_8,
+ RES_10,
+ RES_12,
+ RES_MAX,
+};
+
+struct mpll_config {
+ unsigned long mpixelclock;
+ struct {
+ u16 cpce;
+ u16 gmp;
+ } res[RES_MAX];
+};
+
+static const struct mpll_config mpll_config[] = {
+ {
+ 45250000, {
+ { 0x01e0, 0x0000 },
+ { 0x21e1, 0x0000 },
+ { 0x41e2, 0x0000 }
+ },
+ }, {
+ 92500000, {
+ { 0x0140, 0x0005 },
+ { 0x2141, 0x0005 },
+ { 0x4142, 0x0005 },
+ },
+ }, {
+ 148500000, {
+ { 0x00a0, 0x000a },
+ { 0x20a1, 0x000a },
+ { 0x40a2, 0x000a },
+ },
+ }, {
+ ~0UL, {
+ { 0x00a0, 0x000a },
+ { 0x2001, 0x000f },
+ { 0x4002, 0x000f },
+ },
+ }
+};
+
+struct curr_ctrl {
+ unsigned long mpixelclock;
+ u16 curr[RES_MAX];
+};
+
+static const struct curr_ctrl curr_ctrl[] = {
+ /* pixelclk bpp8 bpp10 bpp12 */
+ {
+ 54000000, { 0x091c, 0x091c, 0x06dc },
+ }, {
+ 58400000, { 0x091c, 0x06dc, 0x06dc },
+ }, {
+ 72000000, { 0x06dc, 0x06dc, 0x091c },
+ }, {
+ 74250000, { 0x06dc, 0x0b5c, 0x091c },
+ }, {
+ 118800000, { 0x091c, 0x091c, 0x06dc },
+ }, {
+ 216000000, { 0x06dc, 0x0b5c, 0x091c },
+ }
+};
+
static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
unsigned char res, int cscon)
{
+ unsigned res_idx, i;
u8 val, msec;
- /* color resolution 0 is 8 bit colour depth */
- if (!res)
- res = 8;
-
if (prep)
return -EINVAL;
- else if (res != 8 && res != 12)
+
+ switch (res) {
+ case 0: /* color resolution 0 is 8 bit colour depth */
+ case 8:
+ res_idx = RES_8;
+ break;
+ case 10:
+ res_idx = RES_10;
+ break;
+ case 12:
+ res_idx = RES_12;
+ break;
+ default:
return -EINVAL;
+ }
/* Enable csc path */
if (cscon)
@@ -845,165 +920,30 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
HDMI_PHY_I2CM_SLAVE_ADDR);
hdmi_phy_test_clear(hdmi, 0);
- if (hdmi->hdmi_data.video_mode.mpixelclock <= 45250000) {
- switch (res) {
- case 8:
- /* PLL/MPLL Cfg */
- hdmi_phy_i2c_write(hdmi, 0x01e0, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x0000, 0x15); /* GMPCTRL */
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x21e1, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x41e2, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
- break;
- default:
- return -EINVAL;
- }
- } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 92500000) {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x0140, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x2141, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x4142, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
- default:
- return -EINVAL;
- }
- } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 148500000) {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x00a0, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x20a1, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x40a2, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
- default:
- return -EINVAL;
- }
- } else {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x00a0, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
+ /* PLL/MPLL Cfg - always match on final entry */
+ for (i = 0; i < ARRAY_SIZE(mpll_config) - 1; i++)
+ if (hdmi->hdmi_data.video_mode.mpixelclock <=
+ mpll_config[i].mpixelclock)
break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x2001, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x000f, 0x15);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x4002, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x000f, 0x15);
- default:
- return -EINVAL;
- }
- }
- if (hdmi->hdmi_data.video_mode.mpixelclock <= 54000000) {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); /* CURRCTRL */
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
- break;
- default:
- return -EINVAL;
- }
- } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 58400000) {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
- break;
- default:
- return -EINVAL;
- }
- } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 72000000) {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
- break;
- default:
- return -EINVAL;
- }
- } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 74250000) {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x0b5c, 0x10);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
- break;
- default:
- return -EINVAL;
- }
- } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 118800000) {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
- break;
- default:
- return -EINVAL;
- }
- } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 216000000) {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x0b5c, 0x10);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+ hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].cpce, 0x06);
+ hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].gmp, 0x15);
+
+ for (i = 0; i < ARRAY_SIZE(curr_ctrl); i++)
+ if (hdmi->hdmi_data.video_mode.mpixelclock <=
+ curr_ctrl[i].mpixelclock)
break;
- default:
- return -EINVAL;
- }
- } else {
+
+ if (i >= ARRAY_SIZE(curr_ctrl)) {
dev_err(hdmi->dev,
"Pixel clock %d - unsupported by HDMI\n",
hdmi->hdmi_data.video_mode.mpixelclock);
return -EINVAL;
}
+ /* CURRCTRL */
+ hdmi_phy_i2c_write(hdmi, curr_ctrl[i].curr[res_idx], 0x10);
+
hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */
hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
/* RESISTANCE TERM 133Ohm Cfg */
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 02/34] imx-drm: imx-hdmi: clean up setting CSC registers
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
2014-02-18 20:09 ` [PATCH 01/34] imx-drm: imx-hdmi: convert HDMI clock settings to tabular form Russell King
@ 2014-02-18 20:09 ` Russell King
2014-02-18 20:09 ` [PATCH 03/34] imx-drm: imx-hdmi: provide register modification function Russell King
` (31 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:09 UTC (permalink / raw)
To: linux-arm-kernel
Rather than manually writing each register sequentially, we can use a
loop to reduce the amount of code.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/imx-hdmi.c | 40 +++++++++++++-------------------------
1 file changed, 14 insertions(+), 26 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index cb316bf3ec56..18de310e50e0 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -480,6 +480,7 @@ static int is_color_space_interpolation(struct imx_hdmi *hdmi)
static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
{
const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
+ unsigned i;
u32 csc_scale = 1;
u8 val;
@@ -498,32 +499,19 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
}
}
- hdmi_writeb(hdmi, ((*csc_coeff)[0][0] & 0xff), HDMI_CSC_COEF_A1_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[0][0] >> 8), HDMI_CSC_COEF_A1_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[0][1] & 0xff), HDMI_CSC_COEF_A2_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[0][1] >> 8), HDMI_CSC_COEF_A2_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[0][2] & 0xff), HDMI_CSC_COEF_A3_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[0][2] >> 8), HDMI_CSC_COEF_A3_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[0][3] & 0xff), HDMI_CSC_COEF_A4_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[0][3] >> 8), HDMI_CSC_COEF_A4_MSB);
-
- hdmi_writeb(hdmi, ((*csc_coeff)[1][0] & 0xff), HDMI_CSC_COEF_B1_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[1][0] >> 8), HDMI_CSC_COEF_B1_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[1][1] & 0xff), HDMI_CSC_COEF_B2_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[1][1] >> 8), HDMI_CSC_COEF_B2_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[1][2] & 0xff), HDMI_CSC_COEF_B3_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[1][2] >> 8), HDMI_CSC_COEF_B3_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[1][3] & 0xff), HDMI_CSC_COEF_B4_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[1][3] >> 8), HDMI_CSC_COEF_B4_MSB);
-
- hdmi_writeb(hdmi, ((*csc_coeff)[2][0] & 0xff), HDMI_CSC_COEF_C1_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[2][0] >> 8), HDMI_CSC_COEF_C1_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[2][1] & 0xff), HDMI_CSC_COEF_C2_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[2][1] >> 8), HDMI_CSC_COEF_C2_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[2][2] & 0xff), HDMI_CSC_COEF_C3_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[2][2] >> 8), HDMI_CSC_COEF_C3_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[2][3] & 0xff), HDMI_CSC_COEF_C4_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[2][3] >> 8), HDMI_CSC_COEF_C4_MSB);
+ /* The CSC registers are sequential, alternating MSB then LSB */
+ for (i = 0; i < ARRAY_SIZE(csc_coeff_default[0]); i++) {
+ u16 coeff_a = (*csc_coeff)[0][i];
+ u16 coeff_b = (*csc_coeff)[1][i];
+ u16 coeff_c = (*csc_coeff)[2][i];
+
+ hdmi_writeb(hdmi, coeff_a & 0xff, HDMI_CSC_COEF_A1_LSB + i * 2);
+ hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2);
+ hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2);
+ hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2);
+ hdmi_writeb(hdmi, coeff_c & 0xff, HDMI_CSC_COEF_C1_LSB + i * 2);
+ hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
+ }
val = hdmi_readb(hdmi, HDMI_CSC_SCALE);
val &= ~HDMI_CSC_SCALE_CSCSCALE_MASK;
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 03/34] imx-drm: imx-hdmi: provide register modification function
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
2014-02-18 20:09 ` [PATCH 01/34] imx-drm: imx-hdmi: convert HDMI clock settings to tabular form Russell King
2014-02-18 20:09 ` [PATCH 02/34] imx-drm: imx-hdmi: clean up setting CSC registers Russell King
@ 2014-02-18 20:09 ` Russell King
2014-02-18 20:09 ` [PATCH 04/34] imx-drm: imx-hdmi: clean up setting of vp_conf Russell King
` (30 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:09 UTC (permalink / raw)
To: linux-arm-kernel
There are a load of read-modify-write patterns to change bitfields in
various registers in this driver; provide a helper to perform this
manipulation.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/imx-hdmi.c | 182 +++++++++++++------------------------
1 file changed, 65 insertions(+), 117 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 18de310e50e0..2fa8658cebd4 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -156,37 +156,34 @@ static inline u8 hdmi_readb(struct imx_hdmi *hdmi, int offset)
return readb(hdmi->regs + offset);
}
+static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
+{
+ u8 val = hdmi_readb(hdmi, reg) & ~mask;
+ val |= data & mask;
+ hdmi_writeb(hdmi, val, reg);
+}
+
static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg,
u8 shift, u8 mask)
{
- u8 value = hdmi_readb(hdmi, reg) & ~mask;
- value |= (data << shift) & mask;
- hdmi_writeb(hdmi, value, reg);
+ hdmi_modb(hdmi, data << shift, mask, reg);
}
static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi,
unsigned int value)
{
- u8 val;
-
hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1);
hdmi_writeb(hdmi, (value >> 8) & 0xff, HDMI_AUD_N2);
hdmi_writeb(hdmi, (value >> 16) & 0x0f, HDMI_AUD_N3);
/* nshift factor = 0 */
- val = hdmi_readb(hdmi, HDMI_AUD_CTS3);
- val &= ~HDMI_AUD_CTS3_N_SHIFT_MASK;
- hdmi_writeb(hdmi, val, HDMI_AUD_CTS3);
+ hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
}
static void hdmi_regenerate_cts(struct imx_hdmi *hdmi, unsigned int cts)
{
- u8 val;
-
/* Must be set/cleared first */
- val = hdmi_readb(hdmi, HDMI_AUD_CTS3);
- val &= ~HDMI_AUD_CTS3_CTS_MANUAL;
- hdmi_writeb(hdmi, val, HDMI_AUD_CTS3);
+ hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
@@ -482,7 +479,6 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
unsigned i;
u32 csc_scale = 1;
- u8 val;
if (is_color_space_conversion(hdmi)) {
if (hdmi->hdmi_data.enc_out_format == RGB) {
@@ -513,10 +509,8 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
}
- val = hdmi_readb(hdmi, HDMI_CSC_SCALE);
- val &= ~HDMI_CSC_SCALE_CSCSCALE_MASK;
- val |= csc_scale & HDMI_CSC_SCALE_CSCSCALE_MASK;
- hdmi_writeb(hdmi, val, HDMI_CSC_SCALE);
+ hdmi_modb(hdmi, csc_scale, HDMI_CSC_SCALE_CSCSCALE_MASK,
+ HDMI_CSC_SCALE);
}
static void hdmi_video_csc(struct imx_hdmi *hdmi)
@@ -524,7 +518,6 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi)
int color_depth = 0;
int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE;
int decimation = 0;
- u8 val;
/* YCC422 interpolation to 444 mode */
if (is_color_space_interpolation(hdmi))
@@ -545,10 +538,8 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi)
/* Configure the CSC registers */
hdmi_writeb(hdmi, interpolation | decimation, HDMI_CSC_CFG);
- val = hdmi_readb(hdmi, HDMI_CSC_SCALE);
- val &= ~HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK;
- val |= color_depth;
- hdmi_writeb(hdmi, val, HDMI_CSC_SCALE);
+ hdmi_modb(hdmi, color_depth, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK,
+ HDMI_CSC_SCALE);
imx_hdmi_update_csc_coeffs(hdmi);
}
@@ -603,107 +594,80 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
hdmi_writeb(hdmi, val, HDMI_VP_PR_CD);
- val = hdmi_readb(hdmi, HDMI_VP_STUFF);
- val &= ~HDMI_VP_STUFF_PR_STUFFING_MASK;
- val |= HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE;
- hdmi_writeb(hdmi, val, HDMI_VP_STUFF);
+ hdmi_modb(hdmi, HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE,
+ HDMI_VP_STUFF_PR_STUFFING_MASK, HDMI_VP_STUFF);
/* Data from pixel repeater block */
if (hdmi_data->pix_repet_factor > 1) {
- val = hdmi_readb(hdmi, HDMI_VP_CONF);
- val &= ~(HDMI_VP_CONF_PR_EN_MASK |
- HDMI_VP_CONF_BYPASS_SELECT_MASK);
- val |= HDMI_VP_CONF_PR_EN_ENABLE |
- HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER;
- hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+ hdmi_modb(hdmi, HDMI_VP_CONF_PR_EN_ENABLE |
+ HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER,
+ HDMI_VP_CONF_PR_EN_MASK |
+ HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
} else { /* data from packetizer block */
- val = hdmi_readb(hdmi, HDMI_VP_CONF);
- val &= ~(HDMI_VP_CONF_PR_EN_MASK |
- HDMI_VP_CONF_BYPASS_SELECT_MASK);
- val |= HDMI_VP_CONF_PR_EN_DISABLE |
- HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
- hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+ hdmi_modb(hdmi, HDMI_VP_CONF_PR_EN_DISABLE |
+ HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER,
+ HDMI_VP_CONF_PR_EN_MASK |
+ HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
}
- val = hdmi_readb(hdmi, HDMI_VP_STUFF);
- val &= ~HDMI_VP_STUFF_IDEFAULT_PHASE_MASK;
- val |= 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET;
- hdmi_writeb(hdmi, val, HDMI_VP_STUFF);
+ hdmi_modb(hdmi, 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET,
+ HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, HDMI_VP_STUFF);
hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP);
if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) {
- val = hdmi_readb(hdmi, HDMI_VP_CONF);
- val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
- HDMI_VP_CONF_PP_EN_ENMASK |
- HDMI_VP_CONF_YCC422_EN_MASK);
- val |= HDMI_VP_CONF_BYPASS_EN_DISABLE |
- HDMI_VP_CONF_PP_EN_ENABLE |
- HDMI_VP_CONF_YCC422_EN_DISABLE;
- hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+ hdmi_modb(hdmi, HDMI_VP_CONF_BYPASS_EN_DISABLE |
+ HDMI_VP_CONF_PP_EN_ENABLE |
+ HDMI_VP_CONF_YCC422_EN_DISABLE,
+ HDMI_VP_CONF_BYPASS_EN_MASK |
+ HDMI_VP_CONF_PP_EN_ENMASK |
+ HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) {
- val = hdmi_readb(hdmi, HDMI_VP_CONF);
- val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
- HDMI_VP_CONF_PP_EN_ENMASK |
- HDMI_VP_CONF_YCC422_EN_MASK);
- val |= HDMI_VP_CONF_BYPASS_EN_DISABLE |
- HDMI_VP_CONF_PP_EN_DISABLE |
- HDMI_VP_CONF_YCC422_EN_ENABLE;
- hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+ hdmi_modb(hdmi, HDMI_VP_CONF_BYPASS_EN_DISABLE |
+ HDMI_VP_CONF_PP_EN_DISABLE |
+ HDMI_VP_CONF_YCC422_EN_ENABLE,
+ HDMI_VP_CONF_BYPASS_EN_MASK |
+ HDMI_VP_CONF_PP_EN_ENMASK |
+ HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) {
- val = hdmi_readb(hdmi, HDMI_VP_CONF);
- val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
- HDMI_VP_CONF_PP_EN_ENMASK |
- HDMI_VP_CONF_YCC422_EN_MASK);
- val |= HDMI_VP_CONF_BYPASS_EN_ENABLE |
- HDMI_VP_CONF_PP_EN_DISABLE |
- HDMI_VP_CONF_YCC422_EN_DISABLE;
- hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+ hdmi_modb(hdmi, HDMI_VP_CONF_BYPASS_EN_ENABLE |
+ HDMI_VP_CONF_PP_EN_DISABLE |
+ HDMI_VP_CONF_YCC422_EN_DISABLE,
+ HDMI_VP_CONF_BYPASS_EN_MASK |
+ HDMI_VP_CONF_PP_EN_ENMASK |
+ HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
} else {
return;
}
- val = hdmi_readb(hdmi, HDMI_VP_STUFF);
- val &= ~(HDMI_VP_STUFF_PP_STUFFING_MASK |
- HDMI_VP_STUFF_YCC422_STUFFING_MASK);
- val |= HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
- HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE;
- hdmi_writeb(hdmi, val, HDMI_VP_STUFF);
+ hdmi_modb(hdmi, HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
+ HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE,
+ HDMI_VP_STUFF_PP_STUFFING_MASK |
+ HDMI_VP_STUFF_YCC422_STUFFING_MASK, HDMI_VP_STUFF);
- val = hdmi_readb(hdmi, HDMI_VP_CONF);
- val &= ~HDMI_VP_CONF_OUTPUT_SELECTOR_MASK;
- val |= output_select;
- hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+ hdmi_modb(hdmi, output_select, HDMI_VP_CONF_OUTPUT_SELECTOR_MASK,
+ HDMI_VP_CONF);
}
static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi,
unsigned char bit)
{
- u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0);
- val &= ~HDMI_PHY_TST0_TSTCLR_MASK;
- val |= (bit << HDMI_PHY_TST0_TSTCLR_OFFSET) &
- HDMI_PHY_TST0_TSTCLR_MASK;
- hdmi_writeb(hdmi, val, HDMI_PHY_TST0);
+ hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET,
+ HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi,
unsigned char bit)
{
- u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0);
- val &= ~HDMI_PHY_TST0_TSTEN_MASK;
- val |= (bit << HDMI_PHY_TST0_TSTEN_OFFSET) &
- HDMI_PHY_TST0_TSTEN_MASK;
- hdmi_writeb(hdmi, val, HDMI_PHY_TST0);
+ hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
+ HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi,
unsigned char bit)
{
- u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0);
- val &= ~HDMI_PHY_TST0_TSTCLK_MASK;
- val |= (bit << HDMI_PHY_TST0_TSTCLK_OFFSET) &
- HDMI_PHY_TST0_TSTCLK_MASK;
- hdmi_writeb(hdmi, val, HDMI_PHY_TST0);
+ hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
+ HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi,
@@ -1000,7 +964,7 @@ static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
{
- u8 de, val;
+ u8 de;
if (hdmi->hdmi_data.video_mode.mdataenablepolarity)
de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH;
@@ -1008,20 +972,13 @@ static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW;
/* disable rx detect */
- val = hdmi_readb(hdmi, HDMI_A_HDCPCFG0);
- val &= HDMI_A_HDCPCFG0_RXDETECT_MASK;
- val |= HDMI_A_HDCPCFG0_RXDETECT_DISABLE;
- hdmi_writeb(hdmi, val, HDMI_A_HDCPCFG0);
+ hdmi_modb(hdmi, HDMI_A_HDCPCFG0_RXDETECT_DISABLE,
+ HDMI_A_HDCPCFG0_RXDETECT_MASK, HDMI_A_HDCPCFG0);
- val = hdmi_readb(hdmi, HDMI_A_VIDPOLCFG);
- val &= HDMI_A_VIDPOLCFG_DATAENPOL_MASK;
- val |= de;
- hdmi_writeb(hdmi, val, HDMI_A_VIDPOLCFG);
+ hdmi_modb(hdmi, de, HDMI_A_VIDPOLCFG_DATAENPOL_MASK, HDMI_A_VIDPOLCFG);
- val = hdmi_readb(hdmi, HDMI_A_HDCPCFG1);
- val &= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK;
- val |= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE;
- hdmi_writeb(hdmi, val, HDMI_A_HDCPCFG1);
+ hdmi_modb(hdmi, HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE,
+ HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1);
}
static void hdmi_config_AVI(struct imx_hdmi *hdmi)
@@ -1245,11 +1202,7 @@ static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi)
{
- u8 clkdis;
-
- clkdis = hdmi_readb(hdmi, HDMI_MC_CLKDIS);
- clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE;
- hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+ hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
}
/* Workaround to clear the overflow condition */
@@ -1593,7 +1546,6 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
struct imx_hdmi *hdmi = dev_id;
u8 intr_stat;
u8 phy_int_pol;
- u8 val;
intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
@@ -1603,17 +1555,13 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
if (phy_int_pol & HDMI_PHY_HPD) {
dev_dbg(hdmi->dev, "EVENT=plugin\n");
- val = hdmi_readb(hdmi, HDMI_PHY_POL0);
- val &= ~HDMI_PHY_HPD;
- hdmi_writeb(hdmi, val, HDMI_PHY_POL0);
+ hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
imx_hdmi_poweron(hdmi);
} else {
dev_dbg(hdmi->dev, "EVENT=plugout\n");
- val = hdmi_readb(hdmi, HDMI_PHY_POL0);
- val |= HDMI_PHY_HPD;
- hdmi_writeb(hdmi, val, HDMI_PHY_POL0);
+ hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD, HDMI_PHY_POL0);
imx_hdmi_poweroff(hdmi);
}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 04/34] imx-drm: imx-hdmi: clean up setting of vp_conf
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (2 preceding siblings ...)
2014-02-18 20:09 ` [PATCH 03/34] imx-drm: imx-hdmi: provide register modification function Russell King
@ 2014-02-18 20:09 ` Russell King
2014-02-18 20:10 ` [PATCH 05/34] imx-drm: imx-hdmi: fix CTS/N setup at init time Russell King
` (29 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:09 UTC (permalink / raw)
To: linux-arm-kernel
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/imx-hdmi.c | 49 +++++++++++++++++---------------------
1 file changed, 22 insertions(+), 27 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 2fa8658cebd4..ec5b5e2ada34 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -555,7 +555,7 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit;
unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP;
struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
- u8 val;
+ u8 val, vp_conf;
if (hdmi_data->enc_out_format == RGB
|| hdmi_data->enc_out_format == YCBCR444) {
@@ -599,47 +599,42 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
/* Data from pixel repeater block */
if (hdmi_data->pix_repet_factor > 1) {
- hdmi_modb(hdmi, HDMI_VP_CONF_PR_EN_ENABLE |
- HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER,
- HDMI_VP_CONF_PR_EN_MASK |
- HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
+ vp_conf = HDMI_VP_CONF_PR_EN_ENABLE |
+ HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER;
} else { /* data from packetizer block */
- hdmi_modb(hdmi, HDMI_VP_CONF_PR_EN_DISABLE |
- HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER,
- HDMI_VP_CONF_PR_EN_MASK |
- HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
+ vp_conf = HDMI_VP_CONF_PR_EN_DISABLE |
+ HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
}
+ hdmi_modb(hdmi, vp_conf,
+ HDMI_VP_CONF_PR_EN_MASK |
+ HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
+
hdmi_modb(hdmi, 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET,
HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, HDMI_VP_STUFF);
hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP);
if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) {
- hdmi_modb(hdmi, HDMI_VP_CONF_BYPASS_EN_DISABLE |
- HDMI_VP_CONF_PP_EN_ENABLE |
- HDMI_VP_CONF_YCC422_EN_DISABLE,
- HDMI_VP_CONF_BYPASS_EN_MASK |
- HDMI_VP_CONF_PP_EN_ENMASK |
- HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
+ vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
+ HDMI_VP_CONF_PP_EN_ENABLE |
+ HDMI_VP_CONF_YCC422_EN_DISABLE;
} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) {
- hdmi_modb(hdmi, HDMI_VP_CONF_BYPASS_EN_DISABLE |
- HDMI_VP_CONF_PP_EN_DISABLE |
- HDMI_VP_CONF_YCC422_EN_ENABLE,
- HDMI_VP_CONF_BYPASS_EN_MASK |
- HDMI_VP_CONF_PP_EN_ENMASK |
- HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
+ vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
+ HDMI_VP_CONF_PP_EN_DISABLE |
+ HDMI_VP_CONF_YCC422_EN_ENABLE;
} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) {
- hdmi_modb(hdmi, HDMI_VP_CONF_BYPASS_EN_ENABLE |
- HDMI_VP_CONF_PP_EN_DISABLE |
- HDMI_VP_CONF_YCC422_EN_DISABLE,
- HDMI_VP_CONF_BYPASS_EN_MASK |
- HDMI_VP_CONF_PP_EN_ENMASK |
- HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
+ vp_conf = HDMI_VP_CONF_BYPASS_EN_ENABLE |
+ HDMI_VP_CONF_PP_EN_DISABLE |
+ HDMI_VP_CONF_YCC422_EN_DISABLE;
} else {
return;
}
+ hdmi_modb(hdmi, vp_conf,
+ HDMI_VP_CONF_BYPASS_EN_MASK | HDMI_VP_CONF_PP_EN_ENMASK |
+ HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
+
hdmi_modb(hdmi, HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE,
HDMI_VP_STUFF_PP_STUFFING_MASK |
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 05/34] imx-drm: imx-hdmi: fix CTS/N setup at init time
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (3 preceding siblings ...)
2014-02-18 20:09 ` [PATCH 04/34] imx-drm: imx-hdmi: clean up setting of vp_conf Russell King
@ 2014-02-18 20:10 ` Russell King
2014-02-18 20:10 ` [PATCH 06/34] imx-drm: ipu-v3: more inteligent DI clock selection Russell King
` (28 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:10 UTC (permalink / raw)
To: linux-arm-kernel
Many of the variables for the audio clock regenerator (CTS/N) were not
initialised in any way. The pixel rate which was being used also
wasn't being adjusted at all when the display mode is modified.
Get rid of the seaprate 'pixel_clk_rate', and use the stored pixel
clock rate instead. Pass this desired pixel clock rate into
hdmi_set_clk_regenerator(). Collapse down hdmi_init_clk_regenerator()
since it is a copy of hdmi_set_clk_regenerator(), and pass a default
pixel clock rate.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/imx-hdmi.c | 48 ++++++++------------------------------
1 file changed, 10 insertions(+), 38 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index ec5b5e2ada34..05cf8a07b456 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -134,7 +134,6 @@ struct imx_hdmi {
struct i2c_adapter *ddc;
void __iomem *regs;
- unsigned long pixel_clk_rate;
unsigned int sample_rate;
int ratio;
};
@@ -328,34 +327,25 @@ static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
return (cts * ratio) / 100;
}
-static void hdmi_get_pixel_clk(struct imx_hdmi *hdmi)
-{
- unsigned long rate;
-
- rate = 65000000; /* FIXME */
-
- if (rate)
- hdmi->pixel_clk_rate = rate;
-}
-
-static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi)
+static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
+ unsigned long pixel_clk)
{
unsigned int clk_n, clk_cts;
- clk_n = hdmi_compute_n(hdmi->sample_rate, hdmi->pixel_clk_rate,
+ clk_n = hdmi_compute_n(hdmi->sample_rate, pixel_clk,
hdmi->ratio);
- clk_cts = hdmi_compute_cts(hdmi->sample_rate, hdmi->pixel_clk_rate,
+ clk_cts = hdmi_compute_cts(hdmi->sample_rate, pixel_clk,
hdmi->ratio);
if (!clk_cts) {
dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
- __func__, hdmi->pixel_clk_rate);
+ __func__, pixel_clk);
return;
}
dev_dbg(hdmi->dev, "%s: samplerate=%d ratio=%d pixelclk=%lu N=%d cts=%d\n",
__func__, hdmi->sample_rate, hdmi->ratio,
- hdmi->pixel_clk_rate, clk_n, clk_cts);
+ pixel_clk, clk_n, clk_cts);
hdmi_set_clock_regenerator_n(hdmi, clk_n);
hdmi_regenerate_cts(hdmi, clk_cts);
@@ -363,32 +353,12 @@ static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi)
static void hdmi_init_clk_regenerator(struct imx_hdmi *hdmi)
{
- unsigned int clk_n, clk_cts;
-
- clk_n = hdmi_compute_n(hdmi->sample_rate, hdmi->pixel_clk_rate,
- hdmi->ratio);
- clk_cts = hdmi_compute_cts(hdmi->sample_rate, hdmi->pixel_clk_rate,
- hdmi->ratio);
-
- if (!clk_cts) {
- dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
- __func__, hdmi->pixel_clk_rate);
- return;
- }
-
- dev_dbg(hdmi->dev, "%s: samplerate=%d ratio=%d pixelclk=%lu N=%d cts=%d\n",
- __func__, hdmi->sample_rate, hdmi->ratio,
- hdmi->pixel_clk_rate, clk_n, clk_cts);
-
- hdmi_set_clock_regenerator_n(hdmi, clk_n);
- hdmi_regenerate_cts(hdmi, clk_cts);
+ hdmi_set_clk_regenerator(hdmi, 74250000);
}
static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
{
- /* Get pixel clock from ipu */
- hdmi_get_pixel_clk(hdmi);
- hdmi_set_clk_regenerator(hdmi);
+ hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
}
/*
@@ -1636,6 +1606,8 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev)
return -ENOMEM;
hdmi->dev = &pdev->dev;
+ hdmi->sample_rate = 48000;
+ hdmi->ratio = 100;
if (of_id) {
const struct platform_device_id *device_id = of_id->data;
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 06/34] imx-drm: ipu-v3: more inteligent DI clock selection
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (4 preceding siblings ...)
2014-02-18 20:10 ` [PATCH 05/34] imx-drm: imx-hdmi: fix CTS/N setup at init time Russell King
@ 2014-02-18 20:10 ` Russell King
2014-02-18 20:10 ` [PATCH 07/34] imx-drm: ipu-v3: don't use clk_round_rate() before clk_set_rate() Russell King
` (27 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:10 UTC (permalink / raw)
To: linux-arm-kernel
The DI clock selection was very rudimentary: it would statically use
either the IPU internal clock or the DI external clock depending on
which "encoder" was being used. In the case of HDMI, it would always
use the IPU clock.
Moreover, using the IPU clock resulted in fractional divisors, which
are achieved by skipping clock pulses. This can result in the HDMI
PHY PLL being frequency modulated, and the attached device is then
unable to properly lock on to the TMDS clock.
We need at least 1% accurate and stable clocks for HDMI.
Arrange for the DI clock to be sourced from the IPU internal clock
if it can satisfy our requirements, otherwise switch to the DI
external clock and try and set the external clock to our desired
pixel clock rate.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/ipu-v3/ipu-di.c | 54 +++++++++++++++++++++++++++++++--
1 file changed, 52 insertions(+), 2 deletions(-)
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-di.c b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
index 948a49b289ef..8c7241bb435c 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-di.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
@@ -544,10 +544,48 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
if ((sig->v_sync_width == 0) || (sig->h_sync_width == 0))
return -EINVAL;
+ dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n",
+ clk_get_rate(di->clk_ipu),
+ clk_get_rate(di->clk_di),
+ sig->pixelclock);
+
+ /*
+ * CLKMODE_EXT means we must use the DI clock: this is needed
+ * for things like LVDS which needs to feed the DI and LDB with
+ * the same pixel clock.
+ *
+ * For other interfaces, we can arbitarily select between the DI
+ * specific clock and the internal IPU clock. See DI_GENERAL
+ * bit 20. We select the IPU clock if it can give us a clock
+ * rate within 1% of the requested frequency, otherwise we use
+ * the DI clock.
+ */
if (sig->clkflags & IPU_DI_CLKMODE_EXT)
parent = di->clk_di;
- else
- parent = di->clk_ipu;
+ else {
+ unsigned long rate, clkrate;
+ unsigned div, error;
+
+ clkrate = clk_get_rate(di->clk_ipu);
+ div = (clkrate + sig->pixelclock / 2) / sig->pixelclock;
+ rate = clkrate / div;
+
+ error = rate / (sig->pixelclock / 1000);
+
+ dev_dbg(di->ipu->dev, " IPU clock can give %lu with divider %u, error %d.%u%%\n",
+ rate, div, (signed)(error - 1000) / 10, error % 10);
+
+ /* Allow a 1% error */
+ if (error < 1010 && error >= 990) {
+ parent = di->clk_ipu;
+ } else {
+ parent = di->clk_di;
+
+ ret = clk_set_rate(parent, sig->pixelclock);
+ if (ret)
+ dev_err(di->ipu->dev, "Setting of DI clock failed: %d\n", ret);
+ }
+ }
ret = clk_set_parent(di->clk_di_pixel, parent);
if (ret) {
@@ -557,6 +595,11 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
return ret;
}
+ /*
+ * CLKMODE_SYNC means that we want the DI to be clocked at the
+ * same rate as the parent clock. This is needed (eg) for LDB
+ * which needs to be fed with the same pixel clock.
+ */
if (sig->clkflags & IPU_DI_CLKMODE_SYNC)
round = clk_get_rate(parent);
else
@@ -564,6 +607,13 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
ret = clk_set_rate(di->clk_di_pixel, round);
+ dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, got %luHz\n",
+ sig->pixelclock,
+ clk_get_rate(di->clk_ipu),
+ clk_get_rate(di->clk_di),
+ parent == di->clk_di ? "DI" : "IPU",
+ clk_get_rate(di->clk_di_pixel));
+
h_total = sig->width + sig->h_sync_width + sig->h_start_width +
sig->h_end_width;
v_total = sig->height + sig->v_sync_width + sig->v_start_width +
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 07/34] imx-drm: ipu-v3: don't use clk_round_rate() before clk_set_rate()
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (5 preceding siblings ...)
2014-02-18 20:10 ` [PATCH 06/34] imx-drm: ipu-v3: more inteligent DI clock selection Russell King
@ 2014-02-18 20:10 ` Russell King
2014-02-18 20:10 ` [PATCH 08/34] imx-drm: ipu-v3: more clocking fixes Russell King
` (26 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:10 UTC (permalink / raw)
To: linux-arm-kernel
This is nonsense; clk_round_rate() is just clk_set_rate() without the
side effect of changing the hardware.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/ipu-v3/ipu-di.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-di.c b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
index 8c7241bb435c..d766e18bfca0 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-di.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
@@ -560,9 +560,10 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
* rate within 1% of the requested frequency, otherwise we use
* the DI clock.
*/
- if (sig->clkflags & IPU_DI_CLKMODE_EXT)
+ round = sig->pixelclock;
+ if (sig->clkflags & IPU_DI_CLKMODE_EXT) {
parent = di->clk_di;
- else {
+ } else {
unsigned long rate, clkrate;
unsigned div, error;
@@ -584,6 +585,9 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
ret = clk_set_rate(parent, sig->pixelclock);
if (ret)
dev_err(di->ipu->dev, "Setting of DI clock failed: %d\n", ret);
+
+ /* Use the integer divisor rate - avoid fractional dividers */
+ round = rate;
}
}
@@ -599,11 +603,12 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
* CLKMODE_SYNC means that we want the DI to be clocked at the
* same rate as the parent clock. This is needed (eg) for LDB
* which needs to be fed with the same pixel clock.
+ *
+ * Note: clk_set_rate(clk, clk_round_rate(clk, rate)) is the
+ * same as clk_set_rate(clk, rate);
*/
if (sig->clkflags & IPU_DI_CLKMODE_SYNC)
round = clk_get_rate(parent);
- else
- round = clk_round_rate(di->clk_di_pixel, sig->pixelclock);
ret = clk_set_rate(di->clk_di_pixel, round);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 08/34] imx-drm: ipu-v3: more clocking fixes
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (6 preceding siblings ...)
2014-02-18 20:10 ` [PATCH 07/34] imx-drm: ipu-v3: don't use clk_round_rate() before clk_set_rate() Russell King
@ 2014-02-18 20:10 ` Russell King
2014-02-18 20:10 ` [PATCH 09/34] imx-drm: add imx6 DT configuration for HDMI Russell King
` (25 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:10 UTC (permalink / raw)
To: linux-arm-kernel
There's no point in using the clk API for this; we end up having to
violate the layering this provides.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/ipu-v3/ipu-di.c | 328 ++++++++++----------------------
1 file changed, 105 insertions(+), 223 deletions(-)
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-di.c b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
index d766e18bfca0..82a9ebad697c 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-di.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
@@ -19,9 +19,6 @@
#include <linux/io.h>
#include <linux/err.h>
#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
#include "imx-ipu-v3.h"
#include "ipu-prv.h"
@@ -33,10 +30,7 @@ struct ipu_di {
struct clk *clk_di; /* display input clock */
struct clk *clk_ipu; /* IPU bus clock */
struct clk *clk_di_pixel; /* resulting pixel clock */
- struct clk_hw clk_hw_out;
- char *clk_name;
bool inuse;
- unsigned long clkflags;
struct ipu_soc *ipu;
};
@@ -141,130 +135,6 @@ static inline void ipu_di_write(struct ipu_di *di, u32 value, unsigned offset)
writel(value, di->base + offset);
}
-static int ipu_di_clk_calc_div(unsigned long inrate, unsigned long outrate)
-{
- u64 tmp = inrate;
- int div;
-
- tmp *= 16;
-
- do_div(tmp, outrate);
-
- div = tmp;
-
- if (div < 0x10)
- div = 0x10;
-
-#ifdef WTF_IS_THIS
- /*
- * Freescale has this in their Kernel. It is neither clear what
- * it does nor why it does it
- */
- if (div & 0x10)
- div &= ~0x7;
- else {
- /* Round up divider if it gets us closer to desired pix clk */
- if ((div & 0xC) == 0xC) {
- div += 0x10;
- div &= ~0xF;
- }
- }
-#endif
- return div;
-}
-
-static unsigned long clk_di_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
- unsigned long outrate;
- u32 div = ipu_di_read(di, DI_BS_CLKGEN0);
-
- if (div < 0x10)
- div = 0x10;
-
- outrate = (parent_rate / div) * 16;
-
- return outrate;
-}
-
-static long clk_di_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
-{
- struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
- unsigned long outrate;
- int div;
- u32 val;
-
- div = ipu_di_clk_calc_div(*prate, rate);
-
- outrate = (*prate / div) * 16;
-
- val = ipu_di_read(di, DI_GENERAL);
-
- if (!(val & DI_GEN_DI_CLK_EXT) && outrate > *prate / 2)
- outrate = *prate / 2;
-
- dev_dbg(di->ipu->dev,
- "%s: inrate: %ld div: 0x%08x outrate: %ld wanted: %ld\n",
- __func__, *prate, div, outrate, rate);
-
- return outrate;
-}
-
-static int clk_di_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
- int div;
- u32 clkgen0;
-
- clkgen0 = ipu_di_read(di, DI_BS_CLKGEN0) & ~0xfff;
-
- div = ipu_di_clk_calc_div(parent_rate, rate);
-
- ipu_di_write(di, clkgen0 | div, DI_BS_CLKGEN0);
-
- dev_dbg(di->ipu->dev, "%s: inrate: %ld desired: %ld div: 0x%08x\n",
- __func__, parent_rate, rate, div);
- return 0;
-}
-
-static u8 clk_di_get_parent(struct clk_hw *hw)
-{
- struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
- u32 val;
-
- val = ipu_di_read(di, DI_GENERAL);
-
- return val & DI_GEN_DI_CLK_EXT ? 1 : 0;
-}
-
-static int clk_di_set_parent(struct clk_hw *hw, u8 index)
-{
- struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
- u32 val;
-
- val = ipu_di_read(di, DI_GENERAL);
-
- if (index)
- val |= DI_GEN_DI_CLK_EXT;
- else
- val &= ~DI_GEN_DI_CLK_EXT;
-
- ipu_di_write(di, val, DI_GENERAL);
-
- return 0;
-}
-
-static struct clk_ops clk_di_ops = {
- .round_rate = clk_di_round_rate,
- .set_rate = clk_di_set_rate,
- .recalc_rate = clk_di_recalc_rate,
- .set_parent = clk_di_set_parent,
- .get_parent = clk_di_get_parent,
-};
-
static void ipu_di_data_wave_config(struct ipu_di *di,
int wave_gen,
int access_size, int component_size)
@@ -528,42 +398,58 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
ipu_di_sync_config(di, cfg_vga, 0, ARRAY_SIZE(cfg_vga));
}
-int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
+static void ipu_di_config_clock(struct ipu_di *di,
+ const struct ipu_di_signal_cfg *sig)
{
- u32 reg;
- u32 di_gen, vsync_cnt;
- u32 div;
- u32 h_total, v_total;
- int ret;
- unsigned long round;
- struct clk *parent;
+ struct clk *clk;
+ unsigned clkgen0;
+ uint32_t val;
- dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n",
- di->id, sig->width, sig->height);
+ if (sig->clkflags & IPU_DI_CLKMODE_EXT) {
+ /*
+ * CLKMODE_EXT means we must use the DI clock: this is
+ * needed for things like LVDS which needs to feed the
+ * DI and LDB with the same pixel clock.
+ */
+ clk = di->clk_di;
+
+ if (sig->clkflags & IPU_DI_CLKMODE_SYNC) {
+ /*
+ * CLKMODE_SYNC means that we want the DI to be
+ * clocked at the same rate as the parent clock.
+ * This is needed (eg) for LDB which needs to be
+ * fed with the same pixel clock. We assume that
+ * the LDB clock has already been set correctly.
+ */
+ clkgen0 = 1 << 4;
+ } else {
+ /*
+ * We can use the divider. We should really have
+ * a flag here indicating whether the bridge can
+ * cope with a fractional divider or not. For the
+ * time being, let's go for simplicitly and
+ * reliability.
+ */
+ unsigned long in_rate;
+ unsigned div;
- if ((sig->v_sync_width == 0) || (sig->h_sync_width == 0))
- return -EINVAL;
+ clk_set_rate(clk, sig->pixelclock);
- dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n",
- clk_get_rate(di->clk_ipu),
- clk_get_rate(di->clk_di),
- sig->pixelclock);
+ in_rate = clk_get_rate(clk);
+ div = (in_rate + sig->pixelclock / 2) / sig->pixelclock;
+ if (div == 0)
+ div = 1;
- /*
- * CLKMODE_EXT means we must use the DI clock: this is needed
- * for things like LVDS which needs to feed the DI and LDB with
- * the same pixel clock.
- *
- * For other interfaces, we can arbitarily select between the DI
- * specific clock and the internal IPU clock. See DI_GENERAL
- * bit 20. We select the IPU clock if it can give us a clock
- * rate within 1% of the requested frequency, otherwise we use
- * the DI clock.
- */
- round = sig->pixelclock;
- if (sig->clkflags & IPU_DI_CLKMODE_EXT) {
- parent = di->clk_di;
+ clkgen0 = div << 4;
+ }
} else {
+ /*
+ * For other interfaces, we can arbitarily select between
+ * the DI specific clock and the internal IPU clock. See
+ * DI_GENERAL bit 20. We select the IPU clock if it can
+ * give us a clock rate within 1% of the requested frequency,
+ * otherwise we use the DI clock.
+ */
unsigned long rate, clkrate;
unsigned div, error;
@@ -578,54 +464,80 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
/* Allow a 1% error */
if (error < 1010 && error >= 990) {
- parent = di->clk_ipu;
+ clk = di->clk_ipu;
+
+ clkgen0 = div << 4;
} else {
- parent = di->clk_di;
+ unsigned long in_rate;
+ unsigned div;
+
+ clk = di->clk_di;
- ret = clk_set_rate(parent, sig->pixelclock);
- if (ret)
- dev_err(di->ipu->dev, "Setting of DI clock failed: %d\n", ret);
+ clk_set_rate(clk, sig->pixelclock);
- /* Use the integer divisor rate - avoid fractional dividers */
- round = rate;
+ in_rate = clk_get_rate(clk);
+ div = (in_rate + sig->pixelclock / 2) / sig->pixelclock;
+ if (div == 0)
+ div = 1;
+
+ clkgen0 = div << 4;
}
}
- ret = clk_set_parent(di->clk_di_pixel, parent);
- if (ret) {
- dev_err(di->ipu->dev,
- "setting pixel clock to parent %s failed with %d\n",
- __clk_get_name(parent), ret);
- return ret;
- }
+ di->clk_di_pixel = clk;
+
+ /* Set the divider */
+ ipu_di_write(di, clkgen0, DI_BS_CLKGEN0);
/*
- * CLKMODE_SYNC means that we want the DI to be clocked at the
- * same rate as the parent clock. This is needed (eg) for LDB
- * which needs to be fed with the same pixel clock.
- *
- * Note: clk_set_rate(clk, clk_round_rate(clk, rate)) is the
- * same as clk_set_rate(clk, rate);
+ * Set the high/low periods. Bits 24:16 give us the falling edge,
+ * and bits 8:0 give the rising edge. LSB is fraction, and is
+ * based on the divider above. We want a 50% duty cycle, so set
+ * the falling edge to be half the divider.
*/
- if (sig->clkflags & IPU_DI_CLKMODE_SYNC)
- round = clk_get_rate(parent);
+ ipu_di_write(di, (clkgen0 >> 4) << 16, DI_BS_CLKGEN1);
- ret = clk_set_rate(di->clk_di_pixel, round);
+ /* Finally select the input clock */
+ val = ipu_di_read(di, DI_GENERAL) & ~DI_GEN_DI_CLK_EXT;
+ if (clk == di->clk_di)
+ val |= DI_GEN_DI_CLK_EXT;
+ ipu_di_write(di, val, DI_GENERAL);
- dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, got %luHz\n",
+ dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, %luHz\n",
sig->pixelclock,
clk_get_rate(di->clk_ipu),
clk_get_rate(di->clk_di),
- parent == di->clk_di ? "DI" : "IPU",
- clk_get_rate(di->clk_di_pixel));
+ clk == di->clk_di ? "DI" : "IPU",
+ clk_get_rate(di->clk_di_pixel) / (clkgen0 >> 4));
+}
+
+int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
+{
+ u32 reg;
+ u32 di_gen, vsync_cnt;
+ u32 div;
+ u32 h_total, v_total;
+
+ dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n",
+ di->id, sig->width, sig->height);
+
+ if ((sig->v_sync_width == 0) || (sig->h_sync_width == 0))
+ return -EINVAL;
h_total = sig->width + sig->h_sync_width + sig->h_start_width +
sig->h_end_width;
v_total = sig->height + sig->v_sync_width + sig->v_start_width +
sig->v_end_width;
+ dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n",
+ clk_get_rate(di->clk_ipu),
+ clk_get_rate(di->clk_di),
+ sig->pixelclock);
+
mutex_lock(&di_mutex);
+ ipu_di_config_clock(di, sig);
+
div = ipu_di_read(di, DI_BS_CLKGEN0) & 0xfff;
div = div / 16; /* Now divider is integer portion */
@@ -709,7 +621,11 @@ EXPORT_SYMBOL_GPL(ipu_di_init_sync_panel);
int ipu_di_enable(struct ipu_di *di)
{
- int ret = clk_prepare_enable(di->clk_di_pixel);
+ int ret;
+
+ WARN_ON(IS_ERR(di->clk_di_pixel));
+
+ ret = clk_prepare_enable(di->clk_di_pixel);
if (ret)
return ret;
@@ -721,6 +637,8 @@ EXPORT_SYMBOL_GPL(ipu_di_enable);
int ipu_di_disable(struct ipu_di *di)
{
+ WARN_ON(IS_ERR(di->clk_di_pixel));
+
ipu_module_disable(di->ipu, di->module);
clk_disable_unprepare(di->clk_di_pixel);
@@ -776,13 +694,6 @@ int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
u32 module, struct clk *clk_ipu)
{
struct ipu_di *di;
- int ret;
- const char *di_parent[2];
- struct clk_init_data init = {
- .ops = &clk_di_ops,
- .num_parents = 2,
- .flags = 0,
- };
if (id > 1)
return -ENODEV;
@@ -804,45 +715,16 @@ int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
if (!di->base)
return -ENOMEM;
- di_parent[0] = __clk_get_name(di->clk_ipu);
- di_parent[1] = __clk_get_name(di->clk_di);
-
ipu_di_write(di, 0x10, DI_BS_CLKGEN0);
- init.parent_names = (const char **)&di_parent;
- di->clk_name = kasprintf(GFP_KERNEL, "%s_di%d_pixel",
- dev_name(dev), id);
- if (!di->clk_name)
- return -ENOMEM;
-
- init.name = di->clk_name;
-
- di->clk_hw_out.init = &init;
- di->clk_di_pixel = clk_register(dev, &di->clk_hw_out);
-
- if (IS_ERR(di->clk_di_pixel)) {
- ret = PTR_ERR(di->clk_di_pixel);
- goto failed_clk_register;
- }
-
dev_dbg(dev, "DI%d base: 0x%08lx remapped to %p\n",
id, base, di->base);
di->inuse = false;
di->ipu = ipu;
return 0;
-
-failed_clk_register:
-
- kfree(di->clk_name);
-
- return ret;
}
void ipu_di_exit(struct ipu_soc *ipu, int id)
{
- struct ipu_di *di = ipu->di_priv[id];
-
- clk_unregister(di->clk_di_pixel);
- kfree(di->clk_name);
}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 09/34] imx-drm: add imx6 DT configuration for HDMI
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (7 preceding siblings ...)
2014-02-18 20:10 ` [PATCH 08/34] imx-drm: ipu-v3: more clocking fixes Russell King
@ 2014-02-18 20:10 ` Russell King
2014-02-18 20:10 ` [PATCH 10/34] imx-drm: update and fix imx6 DT descriptions for v3 HDMI driver Russell King
` (24 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:10 UTC (permalink / raw)
To: linux-arm-kernel
Extracted from another patch by Fabio Estevam, this adds the DT
configuration for HDMI output on the IMX6 SoCs
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
arch/arm/boot/dts/imx6dl.dtsi | 4 ++++
arch/arm/boot/dts/imx6q.dtsi | 4 ++++
arch/arm/boot/dts/imx6qdl.dtsi | 10 ++++++++++
3 files changed, 18 insertions(+)
diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi
index 9e8ae118fdd4..65e54b4529c5 100644
--- a/arch/arm/boot/dts/imx6dl.dtsi
+++ b/arch/arm/boot/dts/imx6dl.dtsi
@@ -88,3 +88,7 @@
crtcs = <&ipu1 0>, <&ipu1 1>;
};
};
+
+&hdmi {
+ crtcs = <&ipu1 0>, <&ipu1 1>;
+}
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index f024ef28b34b..d2467f532de6 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -159,3 +159,7 @@
crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
};
};
+
+&hdmi {
+ crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
+};
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index fb28b2ecb1db..400bbc624f25 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -1368,6 +1368,16 @@
};
};
+ hdmi: hdmi at 0120000 {
+ compatible = "fsl,imx6q-hdmi";
+ reg = <0x00120000 0x9000>;
+ interrupts = <0 115 0x04>;
+ gpr = <&gpr>;
+ clocks = <&clks 123>, <&clks 124>;
+ clock-names = "iahb", "isfr";
+ status = "disabled";
+ };
+
dcic1: dcic at 020e4000 {
reg = <0x020e4000 0x4000>;
interrupts = <0 124 0x04>;
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 10/34] imx-drm: update and fix imx6 DT descriptions for v3 HDMI driver
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (8 preceding siblings ...)
2014-02-18 20:10 ` [PATCH 09/34] imx-drm: add imx6 DT configuration for HDMI Russell King
@ 2014-02-18 20:10 ` Russell King
2014-02-18 20:10 ` [PATCH 11/34] imx-drm: imx-drm-core: sanitise imx_drm_encoder_get_mux_id() Russell King
` (23 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:10 UTC (permalink / raw)
To: linux-arm-kernel
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
arch/arm/boot/dts/imx6dl.dtsi | 3 ++-
arch/arm/boot/dts/imx6q.dtsi | 1 +
arch/arm/boot/dts/imx6qdl.dtsi | 1 -
3 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi
index 65e54b4529c5..6dc397022214 100644
--- a/arch/arm/boot/dts/imx6dl.dtsi
+++ b/arch/arm/boot/dts/imx6dl.dtsi
@@ -90,5 +90,6 @@
};
&hdmi {
+ compatible = "fsl,imx6dl-hdmi";
crtcs = <&ipu1 0>, <&ipu1 1>;
-}
+};
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index d2467f532de6..187fe33ba515 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -161,5 +161,6 @@
};
&hdmi {
+ compatible = "fsl,imx6q-hdmi";
crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
};
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 400bbc624f25..930ebe0c2937 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -1369,7 +1369,6 @@
};
hdmi: hdmi at 0120000 {
- compatible = "fsl,imx6q-hdmi";
reg = <0x00120000 0x9000>;
interrupts = <0 115 0x04>;
gpr = <&gpr>;
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 11/34] imx-drm: imx-drm-core: sanitise imx_drm_encoder_get_mux_id()
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (9 preceding siblings ...)
2014-02-18 20:10 ` [PATCH 10/34] imx-drm: update and fix imx6 DT descriptions for v3 HDMI driver Russell King
@ 2014-02-18 20:10 ` Russell King
2014-02-18 20:10 ` [PATCH 12/34] imx-drm: imx-drm-core: use array instead of list for CRTCs Russell King
` (22 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:10 UTC (permalink / raw)
To: linux-arm-kernel
Address the following issues:
- imx_drm_encoder_get_mux_id() searches the CRTC list for the matching
CRTC, and returns the position within this list as the MUX programming
value for encoders. This is sub-optimal for two reasons:
1. It relies upon the CRTC list not changing during the lifetime of
the driver.
2. It is dependent on the initialisation order of the CRTCs.
We address (1) in this patch, leaving (2) until a better solution can
be found, as (2) requires larger changes.
- imx_drm_encoder is unused. Instead, pass the drm_encoder which is
slightly more useful; all callers pass encoder->crtc as the required
crtc, so move this inside the function.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/imx-drm-core.c | 17 ++++++-----------
drivers/staging/imx-drm/imx-drm.h | 3 +--
drivers/staging/imx-drm/imx-hdmi.c | 3 +--
drivers/staging/imx-drm/imx-ldb.c | 6 ++----
4 files changed, 10 insertions(+), 19 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 236ed66f116a..92fde89f58ac 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -53,6 +53,7 @@ struct imx_drm_crtc {
struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs;
struct module *owner;
struct crtc_cookie cookie;
+ int mux_id;
};
struct imx_drm_encoder {
@@ -503,7 +504,7 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
imx_drm_crtc->pipe = imxdrm->pipes++;
imx_drm_crtc->cookie.cookie = cookie;
imx_drm_crtc->cookie.id = id;
-
+ imx_drm_crtc->mux_id = imx_drm_crtc->pipe;
imx_drm_crtc->crtc = crtc;
imx_drm_crtc->imxdrm = imxdrm;
@@ -657,22 +658,16 @@ int imx_drm_encoder_add_possible_crtcs(
}
EXPORT_SYMBOL_GPL(imx_drm_encoder_add_possible_crtcs);
-int imx_drm_encoder_get_mux_id(struct imx_drm_encoder *imx_drm_encoder,
- struct drm_crtc *crtc)
+int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder)
{
struct imx_drm_device *imxdrm = __imx_drm_device();
struct imx_drm_crtc *imx_crtc;
- int i = 0;
- list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list) {
- if (imx_crtc->crtc == crtc)
- goto found;
- i++;
- }
+ list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list)
+ if (imx_crtc->crtc == encoder->crtc)
+ return imx_crtc->mux_id;
return -EINVAL;
-found:
- return i;
}
EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id);
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index ae90c9c15312..5649f180dc44 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -64,8 +64,7 @@ void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper);
struct device_node;
-int imx_drm_encoder_get_mux_id(struct imx_drm_encoder *imx_drm_encoder,
- struct drm_crtc *crtc);
+int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder);
int imx_drm_encoder_add_possible_crtcs(struct imx_drm_encoder *imx_drm_encoder,
struct device_node *np);
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 05cf8a07b456..a90f08d52ee7 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -1467,8 +1467,7 @@ static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
static void imx_hdmi_encoder_commit(struct drm_encoder *encoder)
{
struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
- int mux = imx_drm_encoder_get_mux_id(hdmi->imx_drm_encoder,
- encoder->crtc);
+ int mux = imx_drm_encoder_get_mux_id(encoder);
imx_hdmi_set_ipu_di_mux(hdmi, mux);
diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c
index 7e593296ac47..4aa47ae2a3ca 100644
--- a/drivers/staging/imx-drm/imx-ldb.c
+++ b/drivers/staging/imx-drm/imx-ldb.c
@@ -179,8 +179,7 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
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->imx_drm_encoder,
- encoder->crtc);
+ int mux = imx_drm_encoder_get_mux_id(encoder);
if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
/* dual channel LVDS mode */
@@ -216,8 +215,7 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
struct imx_ldb *ldb = imx_ldb_ch->ldb;
int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
- int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->imx_drm_encoder,
- encoder->crtc);
+ int mux = imx_drm_encoder_get_mux_id(encoder);
if (dual) {
clk_prepare_enable(ldb->clk[0]);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 12/34] imx-drm: imx-drm-core: use array instead of list for CRTCs
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (10 preceding siblings ...)
2014-02-18 20:10 ` [PATCH 11/34] imx-drm: imx-drm-core: sanitise imx_drm_encoder_get_mux_id() Russell King
@ 2014-02-18 20:10 ` Russell King
2014-02-18 20:10 ` [PATCH 13/34] imx-drm: provide common connector mode validation function Russell King
` (21 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:10 UTC (permalink / raw)
To: linux-arm-kernel
The DRM core indexes vblank by number, so there's little point
maintaining a list, and have to scan the list to find the appropriate
structure. Instead, use an array of pointers to the CRTCs.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/imx-drm-core.c | 57 ++++++++++++++--------------------
1 file changed, 23 insertions(+), 34 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 92fde89f58ac..c5268847a54e 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -34,10 +34,12 @@ struct crtc_cookie {
struct list_head list;
};
+struct imx_drm_crtc;
+
struct imx_drm_device {
struct drm_device *drm;
struct device *dev;
- struct list_head crtc_list;
+ struct imx_drm_crtc *crtc[MAX_CRTC];
struct list_head encoder_list;
struct list_head connector_list;
struct mutex mutex;
@@ -47,7 +49,6 @@ struct imx_drm_device {
struct imx_drm_crtc {
struct drm_crtc *crtc;
- struct list_head list;
struct imx_drm_device *imxdrm;
int pipe;
struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs;
@@ -69,6 +70,8 @@ struct imx_drm_connector {
struct module *owner;
};
+static struct imx_drm_device *__imx_drm_device(void);
+
int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
{
return crtc->pipe;
@@ -96,34 +99,28 @@ static int imx_drm_driver_unload(struct drm_device *drm)
return 0;
}
-/*
- * We don't care at all for crtc numbers, but the core expects the
- * crtcs to be numbered
- */
-static struct imx_drm_crtc *imx_drm_crtc_by_num(struct imx_drm_device *imxdrm,
- int num)
+struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc)
{
- struct imx_drm_crtc *imx_drm_crtc;
+ struct imx_drm_device *imxdrm = __imx_drm_device();
+ unsigned i;
+
+ for (i = 0; i < MAX_CRTC; i++)
+ if (imxdrm->crtc[i] && imxdrm->crtc[i]->crtc == crtc)
+ return imxdrm->crtc[i];
- list_for_each_entry(imx_drm_crtc, &imxdrm->crtc_list, list)
- if (imx_drm_crtc->pipe == num)
- return imx_drm_crtc;
return NULL;
}
int imx_drm_crtc_panel_format_pins(struct drm_crtc *crtc, u32 encoder_type,
u32 interface_pix_fmt, int hsync_pin, int vsync_pin)
{
- struct imx_drm_device *imxdrm = crtc->dev->dev_private;
- struct imx_drm_crtc *imx_crtc;
struct imx_drm_crtc_helper_funcs *helper;
+ struct imx_drm_crtc *imx_crtc;
- list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list)
- if (imx_crtc->crtc == crtc)
- goto found;
+ imx_crtc = imx_drm_find_crtc(crtc);
+ if (!imx_crtc)
+ return -EINVAL;
- return -EINVAL;
-found:
helper = &imx_crtc->imx_drm_helper_funcs;
if (helper->set_interface_pix_fmt)
return helper->set_interface_pix_fmt(crtc,
@@ -162,10 +159,9 @@ EXPORT_SYMBOL_GPL(imx_drm_handle_vblank);
static int imx_drm_enable_vblank(struct drm_device *drm, int crtc)
{
struct imx_drm_device *imxdrm = drm->dev_private;
- struct imx_drm_crtc *imx_drm_crtc;
+ struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc];
int ret;
- imx_drm_crtc = imx_drm_crtc_by_num(imxdrm, crtc);
if (!imx_drm_crtc)
return -EINVAL;
@@ -181,9 +177,8 @@ static int imx_drm_enable_vblank(struct drm_device *drm, int crtc)
static void imx_drm_disable_vblank(struct drm_device *drm, int crtc)
{
struct imx_drm_device *imxdrm = drm->dev_private;
- struct imx_drm_crtc *imx_drm_crtc;
+ struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc];
- imx_drm_crtc = imx_drm_crtc_by_num(imxdrm, crtc);
if (!imx_drm_crtc)
return;
@@ -510,7 +505,7 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
imx_drm_crtc->owner = owner;
- list_add_tail(&imx_drm_crtc->list, &imxdrm->crtc_list);
+ imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
*new_crtc = imx_drm_crtc;
@@ -533,7 +528,7 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
return 0;
err_register:
- list_del(&imx_drm_crtc->list);
+ imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
kfree(imx_drm_crtc);
err_alloc:
err_busy:
@@ -553,7 +548,7 @@ int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
drm_crtc_cleanup(imx_drm_crtc->crtc);
- list_del(&imx_drm_crtc->list);
+ imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
drm_mode_group_reinit(imxdrm->drm);
@@ -660,14 +655,9 @@ EXPORT_SYMBOL_GPL(imx_drm_encoder_add_possible_crtcs);
int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder)
{
- struct imx_drm_device *imxdrm = __imx_drm_device();
- struct imx_drm_crtc *imx_crtc;
-
- list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list)
- if (imx_crtc->crtc == encoder->crtc)
- return imx_crtc->mux_id;
+ struct imx_drm_crtc *imx_crtc = imx_drm_find_crtc(encoder->crtc);
- return -EINVAL;
+ return imx_crtc ? imx_crtc->mux_id : -EINVAL;
}
EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id);
@@ -854,7 +844,6 @@ static int __init imx_drm_init(void)
return -ENOMEM;
mutex_init(&imx_drm_device->mutex);
- INIT_LIST_HEAD(&imx_drm_device->crtc_list);
INIT_LIST_HEAD(&imx_drm_device->connector_list);
INIT_LIST_HEAD(&imx_drm_device->encoder_list);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 13/34] imx-drm: provide common connector mode validation function
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (11 preceding siblings ...)
2014-02-18 20:10 ` [PATCH 12/34] imx-drm: imx-drm-core: use array instead of list for CRTCs Russell King
@ 2014-02-18 20:10 ` Russell King
2014-02-18 20:10 ` [PATCH 14/34] imx-drm: simplify setup of panel format Russell King
` (20 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:10 UTC (permalink / raw)
To: linux-arm-kernel
Provide a common connector mode validation function, which can be used
to limit the available modes according to other components in the
system.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/imx-drm-core.c | 7 +++++++
drivers/staging/imx-drm/imx-drm.h | 3 +++
drivers/staging/imx-drm/imx-hdmi.c | 9 +--------
drivers/staging/imx-drm/imx-ldb.c | 8 +-------
drivers/staging/imx-drm/imx-tve.c | 5 +++++
drivers/staging/imx-drm/parallel-display.c | 8 +-------
6 files changed, 18 insertions(+), 22 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index c5268847a54e..7f14ed040072 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -211,6 +211,13 @@ static const struct file_operations imx_drm_driver_fops = {
.llseek = noop_llseek,
};
+int imx_drm_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ return MODE_OK;
+}
+EXPORT_SYMBOL(imx_drm_connector_mode_valid);
+
static struct imx_drm_device *imx_drm_device;
static struct imx_drm_device *__imx_drm_device(void)
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index 5649f180dc44..4eb594ce9cff 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -68,4 +68,7 @@ int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder);
int imx_drm_encoder_add_possible_crtcs(struct imx_drm_encoder *imx_drm_encoder,
struct device_node *np);
+int imx_drm_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode);
+
#endif /* _IMX_DRM_H_ */
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index a90f08d52ee7..4b690459f3bb 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -1406,13 +1406,6 @@ static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
return 0;
}
-static int imx_hdmi_connector_mode_valid(struct drm_connector *connector,
- struct drm_display_mode *mode)
-{
-
- return MODE_OK;
-}
-
static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector
*connector)
{
@@ -1501,7 +1494,7 @@ static struct drm_connector_funcs imx_hdmi_connector_funcs = {
static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
.get_modes = imx_hdmi_connector_get_modes,
- .mode_valid = imx_hdmi_connector_mode_valid,
+ .mode_valid = imx_drm_connector_mode_valid,
.best_encoder = imx_hdmi_connector_best_encoder,
};
diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c
index 4aa47ae2a3ca..c6ec1e9e95cc 100644
--- a/drivers/staging/imx-drm/imx-ldb.c
+++ b/drivers/staging/imx-drm/imx-ldb.c
@@ -120,12 +120,6 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector)
return num_modes;
}
-static int imx_ldb_connector_mode_valid(struct drm_connector *connector,
- struct drm_display_mode *mode)
-{
- return 0;
-}
-
static struct drm_encoder *imx_ldb_connector_best_encoder(
struct drm_connector *connector)
{
@@ -329,7 +323,7 @@ static struct drm_connector_funcs imx_ldb_connector_funcs = {
static struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = {
.get_modes = imx_ldb_connector_get_modes,
.best_encoder = imx_ldb_connector_best_encoder,
- .mode_valid = imx_ldb_connector_mode_valid,
+ .mode_valid = imx_drm_connector_mode_valid,
};
static struct drm_encoder_funcs imx_ldb_encoder_funcs = {
diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c
index 9abc7ca8b6cf..2d4e0973a02a 100644
--- a/drivers/staging/imx-drm/imx-tve.c
+++ b/drivers/staging/imx-drm/imx-tve.c
@@ -254,6 +254,11 @@ static int imx_tve_connector_mode_valid(struct drm_connector *connector,
{
struct imx_tve *tve = con_to_tve(connector);
unsigned long rate;
+ int ret;
+
+ ret = imx_drm_connector_mode_valid(connector, mode);
+ if (ret != MODE_OK)
+ return ret;
/* pixel clock with 2x oversampling */
rate = clk_round_rate(tve->clk, 2000UL * mode->clock) / 2000;
diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c
index 351d61dede00..18a3e8aae22a 100644
--- a/drivers/staging/imx-drm/parallel-display.c
+++ b/drivers/staging/imx-drm/parallel-display.c
@@ -85,12 +85,6 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector)
return num_modes;
}
-static int imx_pd_connector_mode_valid(struct drm_connector *connector,
- struct drm_display_mode *mode)
-{
- return 0;
-}
-
static struct drm_encoder *imx_pd_connector_best_encoder(
struct drm_connector *connector)
{
@@ -147,7 +141,7 @@ static struct drm_connector_funcs imx_pd_connector_funcs = {
static struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
.get_modes = imx_pd_connector_get_modes,
.best_encoder = imx_pd_connector_best_encoder,
- .mode_valid = imx_pd_connector_mode_valid,
+ .mode_valid = imx_drm_connector_mode_valid,
};
static struct drm_encoder_funcs imx_pd_encoder_funcs = {
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 14/34] imx-drm: simplify setup of panel format
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (12 preceding siblings ...)
2014-02-18 20:10 ` [PATCH 13/34] imx-drm: provide common connector mode validation function Russell King
@ 2014-02-18 20:10 ` Russell King
2014-02-18 20:10 ` [PATCH 15/34] imx-drm: convert to componentised device support Russell King
` (19 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:10 UTC (permalink / raw)
To: linux-arm-kernel
The encoder format passed into imx_drm_crtc_panel_format*() is the
encoder format used for DRM in most cases; the HDMI encoder sets
this to none, but this is incorrect, it should be TMDS.
Since this is the case, we can pass the drm_encoder structure
directly into this function and use the supplied fields there to
configure the CRTC.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/imx-drm-core.c | 18 ++++++++----------
drivers/staging/imx-drm/imx-drm.h | 4 ++--
drivers/staging/imx-drm/imx-hdmi.c | 3 +--
drivers/staging/imx-drm/imx-ldb.c | 3 +--
drivers/staging/imx-drm/imx-tve.c | 12 +++++++-----
drivers/staging/imx-drm/ipuv3-crtc.c | 1 +
drivers/staging/imx-drm/parallel-display.c | 3 +--
7 files changed, 21 insertions(+), 23 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 7f14ed040072..d9786eca3a36 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -111,32 +111,30 @@ struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc)
return NULL;
}
-int imx_drm_crtc_panel_format_pins(struct drm_crtc *crtc, u32 encoder_type,
+int imx_drm_panel_format_pins(struct drm_encoder *encoder,
u32 interface_pix_fmt, int hsync_pin, int vsync_pin)
{
struct imx_drm_crtc_helper_funcs *helper;
struct imx_drm_crtc *imx_crtc;
- imx_crtc = imx_drm_find_crtc(crtc);
+ imx_crtc = imx_drm_find_crtc(encoder->crtc);
if (!imx_crtc)
return -EINVAL;
helper = &imx_crtc->imx_drm_helper_funcs;
if (helper->set_interface_pix_fmt)
- return helper->set_interface_pix_fmt(crtc,
- encoder_type, interface_pix_fmt,
+ return helper->set_interface_pix_fmt(encoder->crtc,
+ encoder->encoder_type, interface_pix_fmt,
hsync_pin, vsync_pin);
return 0;
}
-EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format_pins);
+EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins);
-int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type,
- u32 interface_pix_fmt)
+int imx_drm_panel_format(struct drm_encoder *encoder, u32 interface_pix_fmt)
{
- return imx_drm_crtc_panel_format_pins(crtc, encoder_type,
- interface_pix_fmt, 2, 3);
+ return imx_drm_panel_format_pins(encoder, interface_pix_fmt, 2, 3);
}
-EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format);
+EXPORT_SYMBOL_GPL(imx_drm_panel_format);
int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
{
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index 4eb594ce9cff..e3ca0c6b6a39 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -56,9 +56,9 @@ struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
struct drm_device *imx_drm_device_get(void);
void imx_drm_device_put(void);
-int imx_drm_crtc_panel_format_pins(struct drm_crtc *crtc, u32 encoder_type,
+int imx_drm_panel_format_pins(struct drm_encoder *encoder,
u32 interface_pix_fmt, int hsync_pin, int vsync_pin);
-int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type,
+int imx_drm_panel_format(struct drm_encoder *encoder,
u32 interface_pix_fmt);
void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper);
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 4b690459f3bb..50475e606849 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -1453,8 +1453,7 @@ static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
imx_hdmi_poweroff(hdmi);
- imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_NONE,
- V4L2_PIX_FMT_RGB24);
+ imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
}
static void imx_hdmi_encoder_commit(struct drm_encoder *encoder)
diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c
index c6ec1e9e95cc..dd29a4aad376 100644
--- a/drivers/staging/imx-drm/imx-ldb.c
+++ b/drivers/staging/imx-drm/imx-ldb.c
@@ -200,8 +200,7 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
pixel_fmt = V4L2_PIX_FMT_RGB24;
}
- imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_LVDS,
- pixel_fmt);
+ imx_drm_panel_format(encoder, pixel_fmt);
}
static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c
index 2d4e0973a02a..77131e5770f3 100644
--- a/drivers/staging/imx-drm/imx-tve.c
+++ b/drivers/staging/imx-drm/imx-tve.c
@@ -310,13 +310,11 @@ static void imx_tve_encoder_prepare(struct drm_encoder *encoder)
switch (tve->mode) {
case TVE_MODE_VGA:
- imx_drm_crtc_panel_format_pins(encoder->crtc,
- DRM_MODE_ENCODER_DAC, IPU_PIX_FMT_GBR24,
+ imx_drm_panel_format_pins(encoder, IPU_PIX_FMT_GBR24,
tve->hsync_pin, tve->vsync_pin);
break;
case TVE_MODE_TVOUT:
- imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_TVDAC,
- V4L2_PIX_FMT_YUV444);
+ imx_drm_panel_format(encoder, V4L2_PIX_FMT_YUV444);
break;
}
}
@@ -510,12 +508,16 @@ static int tve_clk_init(struct imx_tve *tve, void __iomem *base)
static int imx_tve_register(struct imx_tve *tve)
{
+ int encoder_type;
int ret;
+ encoder_type = tve->mode == TVE_MODE_VGA ?
+ DRM_MODE_ENCODER_DAC : DRM_MODE_ENCODER_TVDAC;
+
tve->connector.funcs = &imx_tve_connector_funcs;
tve->encoder.funcs = &imx_tve_encoder_funcs;
- tve->encoder.encoder_type = DRM_MODE_ENCODER_NONE;
+ tve->encoder.encoder_type = encoder_type;
tve->connector.connector_type = DRM_MODE_CONNECTOR_VGA;
drm_encoder_helper_add(&tve->encoder, &imx_tve_encoder_helper_funcs);
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index 22be104fbda9..08e0a3b29174 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -284,6 +284,7 @@ static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, u32 encoder_type,
ipu_crtc->di_clkflags = IPU_DI_CLKMODE_SYNC |
IPU_DI_CLKMODE_EXT;
break;
+ case DRM_MODE_ENCODER_TMDS:
case DRM_MODE_ENCODER_NONE:
ipu_crtc->di_clkflags = 0;
break;
diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c
index 18a3e8aae22a..12bcf4f58bdf 100644
--- a/drivers/staging/imx-drm/parallel-display.c
+++ b/drivers/staging/imx-drm/parallel-display.c
@@ -108,8 +108,7 @@ static void imx_pd_encoder_prepare(struct drm_encoder *encoder)
{
struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
- imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_NONE,
- imxpd->interface_pix_fmt);
+ imx_drm_panel_format(encoder, imxpd->interface_pix_fmt);
}
static void imx_pd_encoder_commit(struct drm_encoder *encoder)
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 15/34] imx-drm: convert to componentised device support
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (13 preceding siblings ...)
2014-02-18 20:10 ` [PATCH 14/34] imx-drm: simplify setup of panel format Russell King
@ 2014-02-18 20:10 ` Russell King
2014-02-18 20:10 ` [PATCH 16/34] imx-drm: imx-hdmi: convert to a component device Russell King
` (18 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:10 UTC (permalink / raw)
To: linux-arm-kernel
Use the componentised device support for imx-drm. This requires all
the sub-components and the master device to register with the component
device support.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
arch/arm/boot/dts/imx51-babbage.dts | 10 ++-
arch/arm/boot/dts/imx53-m53evk.dts | 8 ++-
arch/arm/boot/dts/imx53-mba53.dts | 6 ++
arch/arm/boot/dts/imx53-qsb.dts | 8 ++-
arch/arm/boot/dts/imx6q-sabresd.dts | 4 ++
arch/arm/boot/dts/imx6qdl-sabresd.dtsi | 6 ++
drivers/staging/imx-drm/imx-drm-core.c | 105 +++++++++++++++++++++++------
drivers/staging/imx-drm/imx-ldb.c | 40 +++++++----
drivers/staging/imx-drm/imx-tve.c | 63 ++++++++++-------
drivers/staging/imx-drm/ipuv3-crtc.c | 46 +++++++++----
drivers/staging/imx-drm/parallel-display.c | 30 +++++++--
11 files changed, 246 insertions(+), 80 deletions(-)
diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts
index be1407cf5abd..6ff15a0eacb3 100644
--- a/arch/arm/boot/dts/imx51-babbage.dts
+++ b/arch/arm/boot/dts/imx51-babbage.dts
@@ -21,7 +21,7 @@
reg = <0x90000000 0x20000000>;
};
- display at di0 {
+ display0: display at di0 {
compatible = "fsl,imx-parallel-display";
crtcs = <&ipu 0>;
interface-pix-fmt = "rgb24";
@@ -43,7 +43,7 @@
};
};
- display at di1 {
+ display1: display at di1 {
compatible = "fsl,imx-parallel-display";
crtcs = <&ipu 1>;
interface-pix-fmt = "rgb565";
@@ -81,6 +81,12 @@
};
};
+ imx-drm {
+ compatible = "fsl,imx-drm";
+ crtcs = <&ipu 0>, <&ipu 1>;
+ connectors = <&display0>, <&display1>;
+ };
+
sound {
compatible = "fsl,imx51-babbage-sgtl5000",
"fsl,imx-audio-sgtl5000";
diff --git a/arch/arm/boot/dts/imx53-m53evk.dts b/arch/arm/boot/dts/imx53-m53evk.dts
index 7d304d02ed38..ee6107b6484c 100644
--- a/arch/arm/boot/dts/imx53-m53evk.dts
+++ b/arch/arm/boot/dts/imx53-m53evk.dts
@@ -21,7 +21,7 @@
};
soc {
- display at di1 {
+ display1: display at di1 {
compatible = "fsl,imx-parallel-display";
crtcs = <&ipu 1>;
interface-pix-fmt = "bgr666";
@@ -53,6 +53,12 @@
default-brightness-level = <6>;
};
+ imx-drm {
+ compatible = "fsl,imx-drm";
+ crtcs = <&ipu 1>;
+ connectors = <&display1>;
+ };
+
leds {
compatible = "gpio-leds";
pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/imx53-mba53.dts b/arch/arm/boot/dts/imx53-mba53.dts
index a63090267941..9b6e76980a74 100644
--- a/arch/arm/boot/dts/imx53-mba53.dts
+++ b/arch/arm/boot/dts/imx53-mba53.dts
@@ -43,6 +43,12 @@
status = "disabled";
};
+ imx-drm {
+ compatible = "fsl,imx-drm";
+ crtcs = <&ipu 1>;
+ connectors = <&disp1>, <&tve>;
+ };
+
reg_3p2v: 3p2v {
compatible = "regulator-fixed";
regulator-name = "3P2V";
diff --git a/arch/arm/boot/dts/imx53-qsb.dts b/arch/arm/boot/dts/imx53-qsb.dts
index 91a5935a4aac..3cb4f7791a91 100644
--- a/arch/arm/boot/dts/imx53-qsb.dts
+++ b/arch/arm/boot/dts/imx53-qsb.dts
@@ -21,7 +21,7 @@
reg = <0x70000000 0x40000000>;
};
- display at di0 {
+ display0: display at di0 {
compatible = "fsl,imx-parallel-display";
crtcs = <&ipu 0>;
interface-pix-fmt = "rgb565";
@@ -72,6 +72,12 @@
};
};
+ imx-drm {
+ compatible = "fsl,imx-drm";
+ crtcs = <&ipu 0>;
+ connectors = <&display0>;
+ };
+
leds {
compatible = "gpio-leds";
pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/imx6q-sabresd.dts b/arch/arm/boot/dts/imx6q-sabresd.dts
index 9cbdfe7a0931..66f220a82e45 100644
--- a/arch/arm/boot/dts/imx6q-sabresd.dts
+++ b/arch/arm/boot/dts/imx6q-sabresd.dts
@@ -20,6 +20,10 @@
compatible = "fsl,imx6q-sabresd", "fsl,imx6q";
};
+&imx_drm {
+ crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
+};
+
&sata {
status = "okay";
};
diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
index e75e11b36dff..dfca3e001398 100644
--- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
@@ -62,6 +62,12 @@
};
};
+ imx_drm: imx-drm {
+ compatible = "fsl,imx-drm";
+ crtcs = <&ipu1 0>, <&ipu1 1>;
+ connectors = <&ldb>;
+ };
+
sound {
compatible = "fsl,imx6q-sabresd-wm8962",
"fsl,imx-audio-wm8962";
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index d9786eca3a36..82b0337096b0 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
*/
-
+#include <linux/component.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <drm/drmP.h>
@@ -90,6 +90,8 @@ static int imx_drm_driver_unload(struct drm_device *drm)
{
struct imx_drm_device *imxdrm = drm->dev_private;
+ component_unbind_all(drm->dev, drm);
+
imx_drm_device_put();
drm_vblank_cleanup(drm);
@@ -371,11 +373,8 @@ static void imx_drm_connector_unregister(
}
/*
- * Called by the CRTC driver when all CRTCs are registered. This
- * puts all the pieces together and initializes the driver.
- * Once this is called no more CRTCs can be registered since
- * the drm core has hardcoded the number of crtcs in several
- * places.
+ * Main DRM initialisation. This binds, initialises and registers
+ * with DRM the subcomponents of the driver.
*/
static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
{
@@ -428,8 +427,15 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
platform_set_drvdata(drm->platformdev, drm);
mutex_unlock(&imxdrm->mutex);
+
+ /* Now try and bind all our sub-components */
+ ret = component_bind_all(drm->dev, drm);
+ if (ret)
+ goto err_relock;
return 0;
+err_relock:
+ mutex_lock(&imxdrm->mutex);
err_vblank:
drm_vblank_cleanup(drm);
err_kms:
@@ -809,6 +815,70 @@ static struct drm_driver imx_drm_driver = {
.patchlevel = 0,
};
+static int compare_parent_of(struct device *dev, void *data)
+{
+ struct of_phandle_args *args = data;
+ return dev->parent && dev->parent->of_node == args->np;
+}
+
+static int compare_of(struct device *dev, void *data)
+{
+ return dev->of_node == data;
+}
+
+static int imx_drm_add_components(struct device *master, struct master *m)
+{
+ struct device_node *np = master->of_node;
+ unsigned i;
+ int ret;
+
+ for (i = 0; ; i++) {
+ struct of_phandle_args args;
+
+ ret = of_parse_phandle_with_fixed_args(np, "crtcs", 1,
+ i, &args);
+ if (ret)
+ break;
+
+ ret = component_master_add_child(m, compare_parent_of, &args);
+ of_node_put(args.np);
+
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; ; i++) {
+ struct device_node *node;
+
+ node = of_parse_phandle(np, "connectors", i);
+ if (!node)
+ break;
+
+ ret = component_master_add_child(m, compare_of, node);
+ of_node_put(node);
+
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static int imx_drm_bind(struct device *dev)
+{
+ return drm_platform_init(&imx_drm_driver, to_platform_device(dev));
+}
+
+static void imx_drm_unbind(struct device *dev)
+{
+ drm_put_dev(dev_get_drvdata(dev));
+}
+
+static const struct component_master_ops imx_drm_ops = {
+ .add_components = imx_drm_add_components,
+ .bind = imx_drm_bind,
+ .unbind = imx_drm_unbind,
+};
+
static int imx_drm_platform_probe(struct platform_device *pdev)
{
int ret;
@@ -819,27 +889,31 @@ static int imx_drm_platform_probe(struct platform_device *pdev)
imx_drm_device->dev = &pdev->dev;
- return drm_platform_init(&imx_drm_driver, pdev);
+ return component_master_add(&pdev->dev, &imx_drm_ops);
}
static int imx_drm_platform_remove(struct platform_device *pdev)
{
- drm_put_dev(platform_get_drvdata(pdev));
-
+ component_master_del(&pdev->dev, &imx_drm_ops);
return 0;
}
+static const struct of_device_id imx_drm_dt_ids[] = {
+ { .compatible = "fsl,imx-drm", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, imx_drm_dt_ids);
+
static struct platform_driver imx_drm_pdrv = {
.probe = imx_drm_platform_probe,
.remove = imx_drm_platform_remove,
.driver = {
.owner = THIS_MODULE,
.name = "imx-drm",
+ .of_match_table = imx_drm_dt_ids,
},
};
-static struct platform_device *imx_drm_pdev;
-
static int __init imx_drm_init(void)
{
int ret;
@@ -852,12 +926,6 @@ static int __init imx_drm_init(void)
INIT_LIST_HEAD(&imx_drm_device->connector_list);
INIT_LIST_HEAD(&imx_drm_device->encoder_list);
- imx_drm_pdev = platform_device_register_simple("imx-drm", -1, NULL, 0);
- if (IS_ERR(imx_drm_pdev)) {
- ret = PTR_ERR(imx_drm_pdev);
- goto err_pdev;
- }
-
ret = platform_driver_register(&imx_drm_pdrv);
if (ret)
goto err_pdrv;
@@ -865,8 +933,6 @@ static int __init imx_drm_init(void)
return 0;
err_pdrv:
- platform_device_unregister(imx_drm_pdev);
-err_pdev:
kfree(imx_drm_device);
return ret;
@@ -874,7 +940,6 @@ static int __init imx_drm_init(void)
static void __exit imx_drm_exit(void)
{
- platform_device_unregister(imx_drm_pdev);
platform_driver_unregister(&imx_drm_pdrv);
kfree(imx_drm_device);
diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c
index dd29a4aad376..d00f93f3440d 100644
--- a/drivers/staging/imx-drm/imx-ldb.c
+++ b/drivers/staging/imx-drm/imx-ldb.c
@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/clk.h>
+#include <linux/component.h>
#include <drm/drmP.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
@@ -450,11 +451,11 @@ static const struct of_device_id imx_ldb_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids);
-static int imx_ldb_probe(struct platform_device *pdev)
+static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
{
- struct device_node *np = pdev->dev.of_node;
+ struct device_node *np = dev->of_node;
const struct of_device_id *of_id =
- of_match_device(imx_ldb_dt_ids, &pdev->dev);
+ of_match_device(imx_ldb_dt_ids, dev);
struct device_node *child;
const u8 *edidp;
struct imx_ldb *imx_ldb;
@@ -464,17 +465,17 @@ static int imx_ldb_probe(struct platform_device *pdev)
int ret;
int i;
- imx_ldb = devm_kzalloc(&pdev->dev, sizeof(*imx_ldb), GFP_KERNEL);
+ imx_ldb = devm_kzalloc(dev, sizeof(*imx_ldb), GFP_KERNEL);
if (!imx_ldb)
return -ENOMEM;
imx_ldb->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
if (IS_ERR(imx_ldb->regmap)) {
- dev_err(&pdev->dev, "failed to get parent regmap\n");
+ dev_err(dev, "failed to get parent regmap\n");
return PTR_ERR(imx_ldb->regmap);
}
- imx_ldb->dev = &pdev->dev;
+ imx_ldb->dev = dev;
if (of_id)
imx_ldb->lvds_mux = of_id->data;
@@ -512,7 +513,7 @@ static int imx_ldb_probe(struct platform_device *pdev)
return -EINVAL;
if (dual && i > 0) {
- dev_warn(&pdev->dev, "dual-channel mode, ignoring second output\n");
+ dev_warn(dev, "dual-channel mode, ignoring second output\n");
continue;
}
@@ -551,7 +552,7 @@ static int imx_ldb_probe(struct platform_device *pdev)
break;
case LVDS_BIT_MAP_JEIDA:
if (datawidth == 18) {
- dev_err(&pdev->dev, "JEIDA standard only supported in 24 bit\n");
+ dev_err(dev, "JEIDA standard only supported in 24 bit\n");
return -EINVAL;
}
if (i == 0 || dual)
@@ -560,7 +561,7 @@ static int imx_ldb_probe(struct platform_device *pdev)
imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 | LDB_BIT_MAP_CH1_JEIDA;
break;
default:
- dev_err(&pdev->dev, "data mapping not specified or invalid\n");
+ dev_err(dev, "data mapping not specified or invalid\n");
return -EINVAL;
}
@@ -571,14 +572,15 @@ static int imx_ldb_probe(struct platform_device *pdev)
imx_drm_encoder_add_possible_crtcs(channel->imx_drm_encoder, child);
}
- platform_set_drvdata(pdev, imx_ldb);
+ dev_set_drvdata(dev, imx_ldb);
return 0;
}
-static int imx_ldb_remove(struct platform_device *pdev)
+static void imx_ldb_unbind(struct device *dev, struct device *master,
+ void *data)
{
- struct imx_ldb *imx_ldb = platform_get_drvdata(pdev);
+ struct imx_ldb *imx_ldb = dev_get_drvdata(dev);
int i;
for (i = 0; i < 2; i++) {
@@ -591,7 +593,21 @@ static int imx_ldb_remove(struct platform_device *pdev)
imx_drm_remove_connector(channel->imx_drm_connector);
imx_drm_remove_encoder(channel->imx_drm_encoder);
}
+}
+static const struct component_ops imx_ldb_ops = {
+ .bind = imx_ldb_bind,
+ .unbind = imx_ldb_unbind,
+};
+
+static int imx_ldb_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &imx_ldb_ops);
+}
+
+static int imx_ldb_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &imx_ldb_ops);
return 0;
}
diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c
index 77131e5770f3..ad840d78a09a 100644
--- a/drivers/staging/imx-drm/imx-tve.c
+++ b/drivers/staging/imx-drm/imx-tve.c
@@ -20,6 +20,7 @@
#include <linux/clk.h>
#include <linux/clk-provider.h>
+#include <linux/component.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
@@ -583,9 +584,10 @@ static const int of_get_tve_mode(struct device_node *np)
return -EINVAL;
}
-static int imx_tve_probe(struct platform_device *pdev)
+static int imx_tve_bind(struct device *dev, struct device *master, void *data)
{
- struct device_node *np = pdev->dev.of_node;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct device_node *np = dev->of_node;
struct device_node *ddc_node;
struct imx_tve *tve;
struct resource *res;
@@ -594,11 +596,11 @@ static int imx_tve_probe(struct platform_device *pdev)
int irq;
int ret;
- tve = devm_kzalloc(&pdev->dev, sizeof(*tve), GFP_KERNEL);
+ tve = devm_kzalloc(dev, sizeof(*tve), GFP_KERNEL);
if (!tve)
return -ENOMEM;
- tve->dev = &pdev->dev;
+ tve->dev = dev;
spin_lock_init(&tve->lock);
ddc_node = of_parse_phandle(np, "ddc", 0);
@@ -609,7 +611,7 @@ static int imx_tve_probe(struct platform_device *pdev)
tve->mode = of_get_tve_mode(np);
if (tve->mode != TVE_MODE_VGA) {
- dev_err(&pdev->dev, "only VGA mode supported, currently\n");
+ dev_err(dev, "only VGA mode supported, currently\n");
return -EINVAL;
}
@@ -618,7 +620,7 @@ static int imx_tve_probe(struct platform_device *pdev)
&tve->hsync_pin);
if (ret < 0) {
- dev_err(&pdev->dev, "failed to get vsync pin\n");
+ dev_err(dev, "failed to get vsync pin\n");
return ret;
}
@@ -626,40 +628,40 @@ static int imx_tve_probe(struct platform_device *pdev)
&tve->vsync_pin);
if (ret < 0) {
- dev_err(&pdev->dev, "failed to get vsync pin\n");
+ dev_err(dev, "failed to get vsync pin\n");
return ret;
}
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(&pdev->dev, res);
+ base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
tve_regmap_config.lock_arg = tve;
- tve->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "tve", base,
+ tve->regmap = devm_regmap_init_mmio_clk(dev, "tve", base,
&tve_regmap_config);
if (IS_ERR(tve->regmap)) {
- dev_err(&pdev->dev, "failed to init regmap: %ld\n",
+ dev_err(dev, "failed to init regmap: %ld\n",
PTR_ERR(tve->regmap));
return PTR_ERR(tve->regmap);
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
- dev_err(&pdev->dev, "failed to get irq\n");
+ dev_err(dev, "failed to get irq\n");
return irq;
}
- ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ ret = devm_request_threaded_irq(dev, irq, NULL,
imx_tve_irq_handler, IRQF_ONESHOT,
"imx-tve", tve);
if (ret < 0) {
- dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
+ dev_err(dev, "failed to request irq: %d\n", ret);
return ret;
}
- tve->dac_reg = devm_regulator_get(&pdev->dev, "dac");
+ tve->dac_reg = devm_regulator_get(dev, "dac");
if (!IS_ERR(tve->dac_reg)) {
regulator_set_voltage(tve->dac_reg, 2750000, 2750000);
ret = regulator_enable(tve->dac_reg);
@@ -667,17 +669,17 @@ static int imx_tve_probe(struct platform_device *pdev)
return ret;
}
- tve->clk = devm_clk_get(&pdev->dev, "tve");
+ tve->clk = devm_clk_get(dev, "tve");
if (IS_ERR(tve->clk)) {
- dev_err(&pdev->dev, "failed to get high speed tve clock: %ld\n",
+ dev_err(dev, "failed to get high speed tve clock: %ld\n",
PTR_ERR(tve->clk));
return PTR_ERR(tve->clk);
}
/* this is the IPU DI clock input selector, can be parented to tve_di */
- tve->di_sel_clk = devm_clk_get(&pdev->dev, "di_sel");
+ tve->di_sel_clk = devm_clk_get(dev, "di_sel");
if (IS_ERR(tve->di_sel_clk)) {
- dev_err(&pdev->dev, "failed to get ipu di mux clock: %ld\n",
+ dev_err(dev, "failed to get ipu di mux clock: %ld\n",
PTR_ERR(tve->di_sel_clk));
return PTR_ERR(tve->di_sel_clk);
}
@@ -688,11 +690,11 @@ static int imx_tve_probe(struct platform_device *pdev)
ret = regmap_read(tve->regmap, TVE_COM_CONF_REG, &val);
if (ret < 0) {
- dev_err(&pdev->dev, "failed to read configuration register: %d\n", ret);
+ dev_err(dev, "failed to read configuration register: %d\n", ret);
return ret;
}
if (val != 0x00100000) {
- dev_err(&pdev->dev, "configuration register default value indicates this is not a TVEv2\n");
+ dev_err(dev, "configuration register default value indicates this is not a TVEv2\n");
return -ENODEV;
}
@@ -705,14 +707,15 @@ static int imx_tve_probe(struct platform_device *pdev)
ret = imx_drm_encoder_add_possible_crtcs(tve->imx_drm_encoder, np);
- platform_set_drvdata(pdev, tve);
+ dev_set_drvdata(dev, tve);
return 0;
}
-static int imx_tve_remove(struct platform_device *pdev)
+static void imx_tve_unbind(struct device *dev, struct device *master,
+ void *data)
{
- struct imx_tve *tve = platform_get_drvdata(pdev);
+ struct imx_tve *tve = dev_get_drvdata(dev);
struct drm_connector *connector = &tve->connector;
struct drm_encoder *encoder = &tve->encoder;
@@ -723,7 +726,21 @@ static int imx_tve_remove(struct platform_device *pdev)
if (!IS_ERR(tve->dac_reg))
regulator_disable(tve->dac_reg);
+}
+static const struct component_ops imx_tve_ops = {
+ .bind = imx_tve_bind,
+ .unbind = imx_tve_unbind,
+};
+
+static int imx_tve_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &imx_tve_ops);
+}
+
+static int imx_tve_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &imx_tve_ops);
return 0;
}
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index 08e0a3b29174..d779ad2d1f4e 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -17,6 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
+#include <linux/component.h>
#include <linux/module.h>
#include <linux/export.h>
#include <linux/device.h>
@@ -400,43 +401,60 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
return ret;
}
-static int ipu_drm_probe(struct platform_device *pdev)
+static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
{
- struct ipu_client_platformdata *pdata = pdev->dev.platform_data;
+ struct ipu_client_platformdata *pdata = dev->platform_data;
struct ipu_crtc *ipu_crtc;
int ret;
- if (!pdata)
- return -EINVAL;
-
- ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
- if (ret)
- return ret;
-
- ipu_crtc = devm_kzalloc(&pdev->dev, sizeof(*ipu_crtc), GFP_KERNEL);
+ ipu_crtc = devm_kzalloc(dev, sizeof(*ipu_crtc), GFP_KERNEL);
if (!ipu_crtc)
return -ENOMEM;
- ipu_crtc->dev = &pdev->dev;
+ ipu_crtc->dev = dev;
ret = ipu_crtc_init(ipu_crtc, pdata);
if (ret)
return ret;
- platform_set_drvdata(pdev, ipu_crtc);
+ dev_set_drvdata(dev, ipu_crtc);
return 0;
}
-static int ipu_drm_remove(struct platform_device *pdev)
+static void ipu_drm_unbind(struct device *dev, struct device *master,
+ void *data)
{
- struct ipu_crtc *ipu_crtc = platform_get_drvdata(pdev);
+ struct ipu_crtc *ipu_crtc = dev_get_drvdata(dev);
imx_drm_remove_crtc(ipu_crtc->imx_crtc);
ipu_plane_put_resources(ipu_crtc->plane[0]);
ipu_put_resources(ipu_crtc);
+}
+
+static const struct component_ops ipu_crtc_ops = {
+ .bind = ipu_drm_bind,
+ .unbind = ipu_drm_unbind,
+};
+static int ipu_drm_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ if (!pdev->dev.platform_data)
+ return -EINVAL;
+
+ ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
+ return component_add(&pdev->dev, &ipu_crtc_ops);
+}
+
+static int ipu_drm_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &ipu_crtc_ops);
return 0;
}
diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c
index 12bcf4f58bdf..4019cae35ff9 100644
--- a/drivers/staging/imx-drm/parallel-display.c
+++ b/drivers/staging/imx-drm/parallel-display.c
@@ -18,6 +18,7 @@
* MA 02110-1301, USA.
*/
+#include <linux/component.h>
#include <linux/module.h>
#include <drm/drmP.h>
#include <drm/drm_fb_helper.h>
@@ -192,15 +193,15 @@ static int imx_pd_register(struct imx_parallel_display *imxpd)
return 0;
}
-static int imx_pd_probe(struct platform_device *pdev)
+static int imx_pd_bind(struct device *dev, struct device *master, void *data)
{
- struct device_node *np = pdev->dev.of_node;
+ struct device_node *np = dev->of_node;
const u8 *edidp;
struct imx_parallel_display *imxpd;
int ret;
const char *fmt;
- imxpd = devm_kzalloc(&pdev->dev, sizeof(*imxpd), GFP_KERNEL);
+ imxpd = devm_kzalloc(dev, sizeof(*imxpd), GFP_KERNEL);
if (!imxpd)
return -ENOMEM;
@@ -218,7 +219,7 @@ static int imx_pd_probe(struct platform_device *pdev)
imxpd->interface_pix_fmt = V4L2_PIX_FMT_BGR666;
}
- imxpd->dev = &pdev->dev;
+ imxpd->dev = dev;
ret = imx_pd_register(imxpd);
if (ret)
@@ -226,14 +227,15 @@ static int imx_pd_probe(struct platform_device *pdev)
ret = imx_drm_encoder_add_possible_crtcs(imxpd->imx_drm_encoder, np);
- platform_set_drvdata(pdev, imxpd);
+ dev_set_drvdata(dev, imxpd);
return 0;
}
-static int imx_pd_remove(struct platform_device *pdev)
+static void imx_pd_unbind(struct device *dev, struct device *master,
+ void *data)
{
- struct imx_parallel_display *imxpd = platform_get_drvdata(pdev);
+ struct imx_parallel_display *imxpd = dev_get_drvdata(dev);
struct drm_connector *connector = &imxpd->connector;
struct drm_encoder *encoder = &imxpd->encoder;
@@ -241,7 +243,21 @@ static int imx_pd_remove(struct platform_device *pdev)
imx_drm_remove_connector(imxpd->imx_drm_connector);
imx_drm_remove_encoder(imxpd->imx_drm_encoder);
+}
+static const struct component_ops imx_pd_ops = {
+ .bind = imx_pd_bind,
+ .unbind = imx_pd_unbind,
+};
+
+static int imx_pd_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &imx_pd_ops);
+}
+
+static int imx_pd_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &imx_pd_ops);
return 0;
}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 16/34] imx-drm: imx-hdmi: convert to a component device
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (14 preceding siblings ...)
2014-02-18 20:10 ` [PATCH 15/34] imx-drm: convert to componentised device support Russell King
@ 2014-02-18 20:10 ` Russell King
2014-02-18 20:11 ` [PATCH 17/34] imx-drm: delay publishing sysfs connector entries Russell King
` (17 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:10 UTC (permalink / raw)
To: linux-arm-kernel
Convert imx-hdmi to be a component device; it will bind and unbind
at the appropriate moment in the main DRM driver's functions.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/imx-hdmi.c | 41 +++++++++++++++++++++++++++-----------
1 file changed, 29 insertions(+), 12 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 50475e606849..14b4a4b976b9 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -12,6 +12,7 @@
* Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
*/
+#include <linux/component.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/err.h>
@@ -1582,21 +1583,22 @@ static const struct of_device_id imx_hdmi_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
-static int imx_hdmi_platform_probe(struct platform_device *pdev)
+static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
{
+ struct platform_device *pdev = to_platform_device(dev);
const struct of_device_id *of_id =
- of_match_device(imx_hdmi_dt_ids, &pdev->dev);
- struct device_node *np = pdev->dev.of_node;
+ of_match_device(imx_hdmi_dt_ids, dev);
+ struct device_node *np = dev->of_node;
struct device_node *ddc_node;
struct imx_hdmi *hdmi;
struct resource *iores;
int ret, irq;
- hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+ hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
if (!hdmi)
return -ENOMEM;
- hdmi->dev = &pdev->dev;
+ hdmi->dev = dev;
hdmi->sample_rate = 48000;
hdmi->ratio = 100;
@@ -1620,13 +1622,13 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev)
if (irq < 0)
return -EINVAL;
- ret = devm_request_irq(&pdev->dev, irq, imx_hdmi_irq, 0,
- dev_name(&pdev->dev), hdmi);
+ ret = devm_request_irq(dev, irq, imx_hdmi_irq, 0,
+ dev_name(dev), hdmi);
if (ret)
return ret;
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hdmi->regs = devm_ioremap_resource(&pdev->dev, iores);
+ hdmi->regs = devm_ioremap_resource(dev, iores);
if (IS_ERR(hdmi->regs))
return PTR_ERR(hdmi->regs);
@@ -1665,7 +1667,7 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev)
}
/* Product and revision IDs */
- dev_info(&pdev->dev,
+ dev_info(dev,
"Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
hdmi_readb(hdmi, HDMI_DESIGN_ID),
hdmi_readb(hdmi, HDMI_REVISION_ID),
@@ -1699,7 +1701,7 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev)
imx_drm_encoder_add_possible_crtcs(hdmi->imx_drm_encoder, np);
- platform_set_drvdata(pdev, hdmi);
+ dev_set_drvdata(dev, hdmi);
return 0;
@@ -1711,9 +1713,10 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev)
return ret;
}
-static int imx_hdmi_platform_remove(struct platform_device *pdev)
+static void imx_hdmi_unbind(struct device *dev, struct device *master,
+ void *data)
{
- struct imx_hdmi *hdmi = platform_get_drvdata(pdev);
+ struct imx_hdmi *hdmi = dev_get_drvdata(dev);
struct drm_connector *connector = &hdmi->connector;
struct drm_encoder *encoder = &hdmi->encoder;
@@ -1724,7 +1727,21 @@ static int imx_hdmi_platform_remove(struct platform_device *pdev)
clk_disable_unprepare(hdmi->iahb_clk);
clk_disable_unprepare(hdmi->isfr_clk);
i2c_put_adapter(hdmi->ddc);
+}
+static const struct component_ops hdmi_ops = {
+ .bind = imx_hdmi_bind,
+ .unbind = imx_hdmi_unbind,
+};
+
+static int imx_hdmi_platform_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &hdmi_ops);
+}
+
+static int imx_hdmi_platform_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &hdmi_ops);
return 0;
}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 17/34] imx-drm: delay publishing sysfs connector entries
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (15 preceding siblings ...)
2014-02-18 20:10 ` [PATCH 16/34] imx-drm: imx-hdmi: convert to a component device Russell King
@ 2014-02-18 20:11 ` Russell King
2014-02-18 20:11 ` [PATCH 18/34] imx-drm: remove separate imx-fbdev Russell King
` (16 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:11 UTC (permalink / raw)
To: linux-arm-kernel
Delay publishing sysfs connector entries until all components have
initialised. This reduces the probability of generating false hotplug
events when we're uncertain whether the driver can fully initialise.
This also pulls that code out of the individual imx-drm connector
drivers.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/imx-drm-core.c | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 82b0337096b0..3cd330e646f7 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -355,7 +355,7 @@ static int imx_drm_connector_register(
imx_drm_connector->connector->connector_type);
drm_mode_group_reinit(imxdrm->drm);
- return drm_sysfs_connector_add(imx_drm_connector->connector);
+ return 0;
}
/*
@@ -379,6 +379,7 @@ static void imx_drm_connector_unregister(
static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
{
struct imx_drm_device *imxdrm = __imx_drm_device();
+ struct drm_connector *connector;
int ret;
imxdrm->drm = drm;
@@ -432,8 +433,27 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
ret = component_bind_all(drm->dev, drm);
if (ret)
goto err_relock;
+
+ /*
+ * All components are now added, we can publish the connector sysfs
+ * entries to userspace. This will generate hotplug events and so
+ * userspace will expect to be able to access DRM at this point.
+ */
+ list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
+ ret = drm_sysfs_connector_add(connector);
+ if (ret) {
+ dev_err(drm->dev,
+ "[CONNECTOR:%d:%s] drm_sysfs_connector_add failed: %d\n",
+ connector->base.id,
+ drm_get_connector_name(connector), ret);
+ goto err_unbind;
+ }
+ }
+
return 0;
+err_unbind:
+ component_unbind_all(drm->dev, drm);
err_relock:
mutex_lock(&imxdrm->mutex);
err_vblank:
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 18/34] imx-drm: remove separate imx-fbdev
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (16 preceding siblings ...)
2014-02-18 20:11 ` [PATCH 17/34] imx-drm: delay publishing sysfs connector entries Russell King
@ 2014-02-18 20:11 ` Russell King
2014-02-18 20:11 ` [PATCH 19/34] imx-drm: remove imx-fb.c Russell King
` (15 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:11 UTC (permalink / raw)
To: linux-arm-kernel
Now that we know when the components of the imx-drm subsystem will be
initialised, we can move the fbdev helper initialisation and teardown
into imx-drm-core. This gives us the required ordering that DRM wants
in both driver load and unload methods.
We can also stop exporting the imx_drm_device_get() and
imx_drm_device_put() methods; nothing but the fbdev helper was making
use of these.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/Makefile | 1 -
drivers/staging/imx-drm/imx-drm-core.c | 43 ++++++++++++++------
drivers/staging/imx-drm/imx-drm.h | 3 --
drivers/staging/imx-drm/imx-fbdev.c | 74 ----------------------------------
4 files changed, 31 insertions(+), 90 deletions(-)
delete mode 100644 drivers/staging/imx-drm/imx-fbdev.c
diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 4677585b5ad5..5239f908ceec 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -6,7 +6,6 @@ obj-$(CONFIG_DRM_IMX) += imxdrm.o
obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) += parallel-display.o
obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
-obj-$(CONFIG_DRM_IMX_FB_HELPER) += imx-fbdev.o
obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/
imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 3cd330e646f7..5a60886b3a6b 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -70,6 +70,10 @@ struct imx_drm_connector {
struct module *owner;
};
+static int legacyfb_depth = 16;
+module_param(legacyfb_depth, int, 0444);
+
+static void imx_drm_device_put(void);
static struct imx_drm_device *__imx_drm_device(void);
int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
@@ -80,16 +84,23 @@ EXPORT_SYMBOL_GPL(imx_drm_crtc_id);
static void imx_drm_driver_lastclose(struct drm_device *drm)
{
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
struct imx_drm_device *imxdrm = drm->dev_private;
if (imxdrm->fbhelper)
drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
+#endif
}
static int imx_drm_driver_unload(struct drm_device *drm)
{
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
struct imx_drm_device *imxdrm = drm->dev_private;
+ if (imxdrm->fbhelper)
+ drm_fbdev_cma_fini(imxdrm->fbhelper);
+#endif
+
component_unbind_all(drm->dev, drm);
imx_drm_device_put();
@@ -225,7 +236,7 @@ static struct imx_drm_device *__imx_drm_device(void)
return imx_drm_device;
}
-struct drm_device *imx_drm_device_get(void)
+static struct drm_device *imx_drm_device_get(void)
{
struct imx_drm_device *imxdrm = __imx_drm_device();
struct imx_drm_encoder *enc;
@@ -273,9 +284,8 @@ struct drm_device *imx_drm_device_get(void)
return NULL;
}
-EXPORT_SYMBOL_GPL(imx_drm_device_get);
-void imx_drm_device_put(void)
+static void imx_drm_device_put(void)
{
struct imx_drm_device *imxdrm = __imx_drm_device();
struct imx_drm_encoder *enc;
@@ -295,7 +305,6 @@ void imx_drm_device_put(void)
mutex_unlock(&imxdrm->mutex);
}
-EXPORT_SYMBOL_GPL(imx_drm_device_put);
static int drm_mode_group_reinit(struct drm_device *dev)
{
@@ -450,6 +459,24 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
}
}
+ /*
+ * All components are now initialised, so setup the fb helper.
+ * The fb helper takes copies of key hardware information, so the
+ * crtcs/connectors/encoders must not change after this point.
+ */
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
+ if (legacyfb_depth != 16 && legacyfb_depth != 32) {
+ dev_warn(drm->dev, "Invalid legacyfb_depth. Defaulting to 16bpp\n");
+ legacyfb_depth = 16;
+ }
+ imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
+ drm->mode_config.num_crtc, MAX_CRTC);
+ if (IS_ERR(imxdrm->fbhelper)) {
+ ret = PTR_ERR(imxdrm->fbhelper);
+ imxdrm->fbhelper = NULL;
+ goto err_unbind;
+ }
+#endif
return 0;
err_unbind:
@@ -767,14 +794,6 @@ int imx_drm_add_connector(struct drm_connector *connector,
}
EXPORT_SYMBOL_GPL(imx_drm_add_connector);
-void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
-
- imxdrm->fbhelper = fbdev_helper;
-}
-EXPORT_SYMBOL_GPL(imx_drm_fb_helper_set);
-
/*
* imx_drm_remove_connector - remove a connector
*/
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index e3ca0c6b6a39..d1fb1146240e 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -54,13 +54,10 @@ void imx_drm_mode_config_init(struct drm_device *drm);
struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
-struct drm_device *imx_drm_device_get(void);
-void imx_drm_device_put(void);
int imx_drm_panel_format_pins(struct drm_encoder *encoder,
u32 interface_pix_fmt, int hsync_pin, int vsync_pin);
int imx_drm_panel_format(struct drm_encoder *encoder,
u32 interface_pix_fmt);
-void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper);
struct device_node;
diff --git a/drivers/staging/imx-drm/imx-fbdev.c b/drivers/staging/imx-drm/imx-fbdev.c
deleted file mode 100644
index 8331739c3d08..000000000000
--- a/drivers/staging/imx-drm/imx-fbdev.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * i.MX drm driver
- *
- * Copyright (C) 2012 Sascha Hauer, Pengutronix
- *
- * Based on Samsung Exynos code
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-#include <linux/module.h>
-#include <drm/drmP.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_fb_cma_helper.h>
-
-#include "imx-drm.h"
-
-#define MAX_CONNECTOR 4
-#define PREFERRED_BPP 16
-
-static struct drm_fbdev_cma *fbdev_cma;
-
-static int legacyfb_depth = 16;
-
-module_param(legacyfb_depth, int, 0444);
-
-static int __init imx_fb_helper_init(void)
-{
- struct drm_device *drm = imx_drm_device_get();
-
- if (!drm)
- return -EINVAL;
-
- if (legacyfb_depth != 16 && legacyfb_depth != 32) {
- pr_warn("i.MX legacyfb: invalid legacyfb_depth setting. defaulting to 16bpp\n");
- legacyfb_depth = 16;
- }
-
- fbdev_cma = drm_fbdev_cma_init(drm, legacyfb_depth,
- drm->mode_config.num_crtc, MAX_CONNECTOR);
-
- if (IS_ERR(fbdev_cma)) {
- imx_drm_device_put();
- return PTR_ERR(fbdev_cma);
- }
-
- imx_drm_fb_helper_set(fbdev_cma);
-
- return 0;
-}
-
-static void __exit imx_fb_helper_exit(void)
-{
- imx_drm_fb_helper_set(NULL);
- drm_fbdev_cma_fini(fbdev_cma);
- imx_drm_device_put();
-}
-
-late_initcall(imx_fb_helper_init);
-module_exit(imx_fb_helper_exit);
-
-MODULE_DESCRIPTION("Freescale i.MX legacy fb driver");
-MODULE_AUTHOR("Sascha Hauer, Pengutronix");
-MODULE_LICENSE("GPL");
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 19/34] imx-drm: remove imx-fb.c
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (17 preceding siblings ...)
2014-02-18 20:11 ` [PATCH 18/34] imx-drm: remove separate imx-fbdev Russell King
@ 2014-02-18 20:11 ` Russell King
2014-02-18 20:11 ` [PATCH 20/34] imx-drm: use supplied drm_device where possible Russell King
` (14 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:11 UTC (permalink / raw)
To: linux-arm-kernel
imx-fb.c doesn't need to be separate from imx-drm-core.c - all it is
doing is setting up the minimum and maximum sizes of the scanout
buffers, and setting up the mode_config function pointers. Move the
contents into imx-drm-core.c and kill this file.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/Makefile | 2 +-
drivers/staging/imx-drm/imx-drm-core.c | 16 +++++++++++-
drivers/staging/imx-drm/imx-fb.c | 47 ----------------------------------
3 files changed, 16 insertions(+), 49 deletions(-)
delete mode 100644 drivers/staging/imx-drm/imx-fb.c
diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 5239f908ceec..129e3a3f59f1 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -1,5 +1,5 @@
-imxdrm-objs := imx-drm-core.o imx-fb.o
+imxdrm-objs := imx-drm-core.o
obj-$(CONFIG_DRM_IMX) += imxdrm.o
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 5a60886b3a6b..3e3fd281fe6e 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -381,6 +381,10 @@ static void imx_drm_connector_unregister(
drm_mode_group_reinit(imxdrm->drm);
}
+static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
+ .fb_create = drm_fb_cma_create,
+};
+
/*
* Main DRM initialisation. This binds, initialises and registers
* with DRM the subcomponents of the driver.
@@ -406,8 +410,18 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
*/
drm->irq_enabled = true;
+ /*
+ * set max width and height as default value(4096x4096).
+ * this value would be used to check framebuffer size limitation
+ * at drm_mode_addfb().
+ */
+ drm->mode_config.min_width = 64;
+ drm->mode_config.min_height = 64;
+ drm->mode_config.max_width = 4096;
+ drm->mode_config.max_height = 4096;
+ drm->mode_config.funcs = &imx_drm_mode_config_funcs;
+
drm_mode_config_init(drm);
- imx_drm_mode_config_init(drm);
mutex_lock(&imxdrm->mutex);
diff --git a/drivers/staging/imx-drm/imx-fb.c b/drivers/staging/imx-drm/imx-fb.c
deleted file mode 100644
index 03a7b4e14f67..000000000000
--- a/drivers/staging/imx-drm/imx-fb.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * i.MX drm driver
- *
- * Copyright (C) 2012 Sascha Hauer, Pengutronix
- *
- * Based on Samsung Exynos code
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-#include <linux/module.h>
-#include <drm/drmP.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_gem_cma_helper.h>
-#include <drm/drm_fb_cma_helper.h>
-
-#include "imx-drm.h"
-
-static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
- .fb_create = drm_fb_cma_create,
-};
-
-void imx_drm_mode_config_init(struct drm_device *dev)
-{
- dev->mode_config.min_width = 64;
- dev->mode_config.min_height = 64;
-
- /*
- * set max width and height as default value(4096x4096).
- * this value would be used to check framebuffer size limitation
- * at drm_mode_addfb().
- */
- dev->mode_config.max_width = 4096;
- dev->mode_config.max_height = 4096;
-
- dev->mode_config.funcs = &imx_drm_mode_config_funcs;
-}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 20/34] imx-drm: use supplied drm_device where possible
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (18 preceding siblings ...)
2014-02-18 20:11 ` [PATCH 19/34] imx-drm: remove imx-fb.c Russell King
@ 2014-02-18 20:11 ` Russell King
2014-02-18 20:11 ` [PATCH 21/34] imx-drm: imx-drm-core: provide helper function to parse possible crtcs Russell King
` (13 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:11 UTC (permalink / raw)
To: linux-arm-kernel
The component helper provides us the drm_device which is being
registered. Rather than having to reference a global in imx-drm-core,
use this to get the imxdrm device, and also use it to register the CRTC
against.
This means we never have CRTCs/encoders/connectors without the drivers
private data being accessible.
Remove the module owner field as well; this provides no protection
against the device being unbound.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/imx-drm-core.c | 34 +++++-----------------------------
drivers/staging/imx-drm/imx-drm.h | 4 ++--
drivers/staging/imx-drm/ipuv3-crtc.c | 9 +++++----
3 files changed, 12 insertions(+), 35 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 3e3fd281fe6e..3d1c6b6c4388 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -52,7 +52,6 @@ struct imx_drm_crtc {
struct imx_drm_device *imxdrm;
int pipe;
struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs;
- struct module *owner;
struct crtc_cookie cookie;
int mux_id;
};
@@ -74,7 +73,6 @@ static int legacyfb_depth = 16;
module_param(legacyfb_depth, int, 0444);
static void imx_drm_device_put(void);
-static struct imx_drm_device *__imx_drm_device(void);
int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
{
@@ -114,7 +112,7 @@ static int imx_drm_driver_unload(struct drm_device *drm)
struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc)
{
- struct imx_drm_device *imxdrm = __imx_drm_device();
+ struct imx_drm_device *imxdrm = crtc->dev->dev_private;
unsigned i;
for (i = 0; i < MAX_CRTC; i++)
@@ -241,7 +239,6 @@ static struct drm_device *imx_drm_device_get(void)
struct imx_drm_device *imxdrm = __imx_drm_device();
struct imx_drm_encoder *enc;
struct imx_drm_connector *con;
- struct imx_drm_crtc *crtc;
list_for_each_entry(enc, &imxdrm->encoder_list, list) {
if (!try_module_get(enc->owner)) {
@@ -259,19 +256,8 @@ static struct drm_device *imx_drm_device_get(void)
}
}
- list_for_each_entry(crtc, &imxdrm->crtc_list, list) {
- if (!try_module_get(crtc->owner)) {
- dev_err(imxdrm->dev, "could not get module %s\n",
- module_name(crtc->owner));
- goto unwind_crtc;
- }
- }
-
return imxdrm->drm;
-unwind_crtc:
- list_for_each_entry_continue_reverse(crtc, &imxdrm->crtc_list, list)
- module_put(crtc->owner);
unwind_con:
list_for_each_entry_continue_reverse(con, &imxdrm->connector_list, list)
module_put(con->owner);
@@ -290,13 +276,9 @@ static void imx_drm_device_put(void)
struct imx_drm_device *imxdrm = __imx_drm_device();
struct imx_drm_encoder *enc;
struct imx_drm_connector *con;
- struct imx_drm_crtc *crtc;
mutex_lock(&imxdrm->mutex);
- list_for_each_entry(crtc, &imxdrm->crtc_list, list)
- module_put(crtc->owner);
-
list_for_each_entry(con, &imxdrm->connector_list, list)
module_put(con->owner);
@@ -536,12 +518,12 @@ static void imx_drm_update_possible_crtcs(void)
* The return value if !NULL is a cookie for the caller to pass to
* imx_drm_remove_crtc later.
*/
-int imx_drm_add_crtc(struct drm_crtc *crtc,
+int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
struct imx_drm_crtc **new_crtc,
const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs,
- struct module *owner, void *cookie, int id)
+ void *cookie, int id)
{
- struct imx_drm_device *imxdrm = __imx_drm_device();
+ struct imx_drm_device *imxdrm = drm->dev_private;
struct imx_drm_crtc *imx_drm_crtc;
int ret;
@@ -575,8 +557,6 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
imx_drm_crtc->crtc = crtc;
imx_drm_crtc->imxdrm = imxdrm;
- imx_drm_crtc->owner = owner;
-
imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
*new_crtc = imx_drm_crtc;
@@ -588,11 +568,9 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
drm_crtc_helper_add(crtc,
imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
- drm_crtc_init(imxdrm->drm, crtc,
+ drm_crtc_init(drm, crtc,
imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
- drm_mode_group_reinit(imxdrm->drm);
-
imx_drm_update_possible_crtcs();
mutex_unlock(&imxdrm->mutex);
@@ -622,8 +600,6 @@ int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
- drm_mode_group_reinit(imxdrm->drm);
-
mutex_unlock(&imxdrm->mutex);
kfree(imx_drm_crtc);
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index d1fb1146240e..78465239ed4c 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -25,10 +25,10 @@ struct imx_drm_crtc_helper_funcs {
const struct drm_crtc_funcs *crtc_funcs;
};
-int imx_drm_add_crtc(struct drm_crtc *crtc,
+int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
struct imx_drm_crtc **new_crtc,
const struct imx_drm_crtc_helper_funcs *imx_helper_funcs,
- struct module *owner, void *cookie, int id);
+ void *cookie, int id);
int imx_drm_remove_crtc(struct imx_drm_crtc *);
int imx_drm_init_drm(struct platform_device *pdev,
int preferred_bpp);
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index d779ad2d1f4e..e646017c32ac 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -336,7 +336,7 @@ static int ipu_get_resources(struct ipu_crtc *ipu_crtc,
}
static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
- struct ipu_client_platformdata *pdata)
+ struct ipu_client_platformdata *pdata, struct drm_device *drm)
{
struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
int dp = -EINVAL;
@@ -350,9 +350,9 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
return ret;
}
- ret = imx_drm_add_crtc(&ipu_crtc->base,
+ ret = imx_drm_add_crtc(drm, &ipu_crtc->base,
&ipu_crtc->imx_crtc,
- &ipu_crtc_helper_funcs, THIS_MODULE,
+ &ipu_crtc_helper_funcs,
ipu_crtc->dev->parent->of_node, pdata->di);
if (ret) {
dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret);
@@ -404,6 +404,7 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
{
struct ipu_client_platformdata *pdata = dev->platform_data;
+ struct drm_device *drm = data;
struct ipu_crtc *ipu_crtc;
int ret;
@@ -413,7 +414,7 @@ static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
ipu_crtc->dev = dev;
- ret = ipu_crtc_init(ipu_crtc, pdata);
+ ret = ipu_crtc_init(ipu_crtc, pdata, drm);
if (ret)
return ret;
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 21/34] imx-drm: imx-drm-core: provide helper function to parse possible crtcs
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (19 preceding siblings ...)
2014-02-18 20:11 ` [PATCH 20/34] imx-drm: use supplied drm_device where possible Russell King
@ 2014-02-18 20:11 ` Russell King
2014-02-18 20:11 ` [PATCH 22/34] imx-drm: imx-drm-core: provide common connector and encoder cleanup functions Russell King
` (12 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:11 UTC (permalink / raw)
To: linux-arm-kernel
Provide a helper function to parse possible crtcs before the encoder
is registered. The crtc mask is derived from the position of the
CRTCs registered in the drm_device.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/imx-drm-core.c | 66 ++++++++++++++++++++++++++++++++++
drivers/staging/imx-drm/imx-drm.h | 2 ++
2 files changed, 68 insertions(+)
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 3d1c6b6c4388..5cac6ee24472 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -658,6 +658,72 @@ int imx_drm_add_encoder(struct drm_encoder *encoder,
}
EXPORT_SYMBOL_GPL(imx_drm_add_encoder);
+/*
+ * Find the DRM CRTC possible mask for the device node cookie/id.
+ *
+ * The encoder possible masks are defined by their position in the
+ * mode_config crtc_list. This means that CRTCs must not be added
+ * or removed once the DRM device has been fully initialised.
+ */
+static uint32_t imx_drm_find_crtc_mask(struct imx_drm_device *imxdrm,
+ void *cookie, int id)
+{
+ unsigned i;
+
+ for (i = 0; i < MAX_CRTC; i++) {
+ struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[i];
+ if (imx_drm_crtc && imx_drm_crtc->cookie.id == id &&
+ imx_drm_crtc->cookie.cookie == cookie)
+ return drm_crtc_mask(imx_drm_crtc->crtc);
+ }
+
+ return 0;
+}
+
+int imx_drm_encoder_parse_of(struct drm_device *drm,
+ struct drm_encoder *encoder, struct device_node *np)
+{
+ struct imx_drm_device *imxdrm = drm->dev_private;
+ uint32_t crtc_mask = 0;
+ int i, ret = 0;
+
+ for (i = 0; !ret; i++) {
+ struct of_phandle_args args;
+ uint32_t mask;
+ int id;
+
+ ret = of_parse_phandle_with_args(np, "crtcs", "#crtc-cells", i,
+ &args);
+ if (ret == -ENOENT)
+ break;
+ if (ret < 0)
+ return ret;
+
+ id = args.args_count > 0 ? args.args[0] : 0;
+ mask = imx_drm_find_crtc_mask(imxdrm, args.np, id);
+ of_node_put(args.np);
+
+ /*
+ * If we failed to find the CRTC(s) which this encoder is
+ * supposed to be connected to, it's because the CRTC has
+ * not been registered yet. Defer probing, and hope that
+ * the required CRTC is added later.
+ */
+ if (mask == 0)
+ return -EPROBE_DEFER;
+
+ crtc_mask |= mask;
+ }
+
+ encoder->possible_crtcs = crtc_mask;
+
+ /* FIXME: this is the mask of outputs which can clone this output. */
+ encoder->possible_clones = ~0;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of);
+
int imx_drm_encoder_add_possible_crtcs(
struct imx_drm_encoder *imx_drm_encoder,
struct device_node *np)
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index 78465239ed4c..49d4aaf33f97 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -64,6 +64,8 @@ struct device_node;
int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder);
int imx_drm_encoder_add_possible_crtcs(struct imx_drm_encoder *imx_drm_encoder,
struct device_node *np);
+int imx_drm_encoder_parse_of(struct drm_device *drm,
+ struct drm_encoder *encoder, struct device_node *np);
int imx_drm_connector_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 22/34] imx-drm: imx-drm-core: provide common connector and encoder cleanup functions
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (20 preceding siblings ...)
2014-02-18 20:11 ` [PATCH 21/34] imx-drm: imx-drm-core: provide helper function to parse possible crtcs Russell King
@ 2014-02-18 20:11 ` Russell King
2014-02-18 20:11 ` [PATCH 23/34] imx-drm: parallel-display,imx-tve,imx-ldb: initialise drm components directly Russell King
` (11 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:11 UTC (permalink / raw)
To: linux-arm-kernel
Provide two helper functions to assist with cleaning up imx-drm
connectors and encoders.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/imx-drm-core.c | 13 +++++++++++++
drivers/staging/imx-drm/imx-drm.h | 3 +++
2 files changed, 16 insertions(+)
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 5cac6ee24472..1f50acd5a982 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -363,6 +363,19 @@ static void imx_drm_connector_unregister(
drm_mode_group_reinit(imxdrm->drm);
}
+void imx_drm_connector_destroy(struct drm_connector *connector)
+{
+ drm_sysfs_connector_remove(connector);
+ drm_connector_cleanup(connector);
+}
+EXPORT_SYMBOL_GPL(imx_drm_connector_destroy);
+
+void imx_drm_encoder_destroy(struct drm_encoder *encoder)
+{
+ drm_encoder_cleanup(encoder);
+}
+EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy);
+
static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
.fb_create = drm_fb_cma_create,
};
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index 49d4aaf33f97..0543606c587a 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -8,6 +8,7 @@
struct drm_crtc;
struct drm_connector;
struct drm_device;
+struct drm_display_mode;
struct drm_encoder;
struct imx_drm_crtc;
struct drm_fbdev_cma;
@@ -69,5 +70,7 @@ int imx_drm_encoder_parse_of(struct drm_device *drm,
int imx_drm_connector_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode);
+void imx_drm_connector_destroy(struct drm_connector *connector);
+void imx_drm_encoder_destroy(struct drm_encoder *encoder);
#endif /* _IMX_DRM_H_ */
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 23/34] imx-drm: parallel-display,imx-tve,imx-ldb: initialise drm components directly
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (21 preceding siblings ...)
2014-02-18 20:11 ` [PATCH 22/34] imx-drm: imx-drm-core: provide common connector and encoder cleanup functions Russell King
@ 2014-02-18 20:11 ` Russell King
2014-02-18 20:11 ` [PATCH 24/34] imx-drm: imx-hdmi: " Russell King
` (10 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:11 UTC (permalink / raw)
To: linux-arm-kernel
Now that our bind function is only ever called during the main DRM
driver ->load callback, we don't need to have the imx_drm_connector or
imx_drm_encoder abstractions anymore. So let's get rid of it, and move
the DRM connector and encoder setup into the connector support files.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/imx-ldb.c | 68 ++++++++++--------------------
drivers/staging/imx-drm/imx-tve.c | 58 +++++++------------------
drivers/staging/imx-drm/parallel-display.c | 61 ++++++++-------------------
3 files changed, 54 insertions(+), 133 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c
index d00f93f3440d..5168c76cff53 100644
--- a/drivers/staging/imx-drm/imx-ldb.c
+++ b/drivers/staging/imx-drm/imx-ldb.c
@@ -59,9 +59,8 @@ struct imx_ldb;
struct imx_ldb_channel {
struct imx_ldb *ldb;
struct drm_connector connector;
- struct imx_drm_connector *imx_drm_connector;
struct drm_encoder encoder;
- struct imx_drm_encoder *imx_drm_encoder;
+ struct device_node *child;
int chno;
void *edid;
int edid_len;
@@ -92,11 +91,6 @@ static enum drm_connector_status imx_ldb_connector_detect(
return connector_status_connected;
}
-static void imx_ldb_connector_destroy(struct drm_connector *connector)
-{
- /* do not free here */
-}
-
static int imx_ldb_connector_get_modes(struct drm_connector *connector)
{
struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector);
@@ -308,16 +302,11 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder)
}
}
-static void imx_ldb_encoder_destroy(struct drm_encoder *encoder)
-{
- /* do not free here */
-}
-
static struct drm_connector_funcs imx_ldb_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = imx_ldb_connector_detect,
- .destroy = imx_ldb_connector_destroy,
+ .destroy = imx_drm_connector_destroy,
};
static struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = {
@@ -327,7 +316,7 @@ static struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = {
};
static struct drm_encoder_funcs imx_ldb_encoder_funcs = {
- .destroy = imx_ldb_encoder_destroy,
+ .destroy = imx_drm_encoder_destroy,
};
static struct drm_encoder_helper_funcs imx_ldb_encoder_helper_funcs = {
@@ -354,45 +343,36 @@ static int imx_ldb_get_clk(struct imx_ldb *ldb, int chno)
return PTR_ERR_OR_ZERO(ldb->clk_pll[chno]);
}
-static int imx_ldb_register(struct imx_ldb_channel *imx_ldb_ch)
+static int imx_ldb_register(struct drm_device *drm,
+ struct imx_ldb_channel *imx_ldb_ch)
{
- int ret;
struct imx_ldb *ldb = imx_ldb_ch->ldb;
+ int ret;
+
+ ret = imx_drm_encoder_parse_of(drm, &imx_ldb_ch->encoder,
+ imx_ldb_ch->child);
+ if (ret)
+ return ret;
ret = imx_ldb_get_clk(ldb, imx_ldb_ch->chno);
if (ret)
return ret;
+
if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
- ret |= imx_ldb_get_clk(ldb, 1);
+ ret = imx_ldb_get_clk(ldb, 1);
if (ret)
return ret;
}
- imx_ldb_ch->connector.funcs = &imx_ldb_connector_funcs;
- imx_ldb_ch->encoder.funcs = &imx_ldb_encoder_funcs;
-
- imx_ldb_ch->encoder.encoder_type = DRM_MODE_ENCODER_LVDS;
- imx_ldb_ch->connector.connector_type = DRM_MODE_CONNECTOR_LVDS;
-
drm_encoder_helper_add(&imx_ldb_ch->encoder,
&imx_ldb_encoder_helper_funcs);
- ret = imx_drm_add_encoder(&imx_ldb_ch->encoder,
- &imx_ldb_ch->imx_drm_encoder, THIS_MODULE);
- if (ret) {
- dev_err(ldb->dev, "adding encoder failed with %d\n", ret);
- return ret;
- }
+ drm_encoder_init(drm, &imx_ldb_ch->encoder, &imx_ldb_encoder_funcs,
+ DRM_MODE_ENCODER_LVDS);
drm_connector_helper_add(&imx_ldb_ch->connector,
&imx_ldb_connector_helper_funcs);
-
- ret = imx_drm_add_connector(&imx_ldb_ch->connector,
- &imx_ldb_ch->imx_drm_connector, THIS_MODULE);
- if (ret) {
- imx_drm_remove_encoder(imx_ldb_ch->imx_drm_encoder);
- dev_err(ldb->dev, "adding connector failed with %d\n", ret);
- return ret;
- }
+ drm_connector_init(drm, &imx_ldb_ch->connector,
+ &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
drm_mode_connector_attach_encoder(&imx_ldb_ch->connector,
&imx_ldb_ch->encoder);
@@ -453,6 +433,7 @@ MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids);
static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
{
+ struct drm_device *drm = data;
struct device_node *np = dev->of_node;
const struct of_device_id *of_id =
of_match_device(imx_ldb_dt_ids, dev);
@@ -523,6 +504,7 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
channel = &imx_ldb->channel[i];
channel->ldb = imx_ldb;
channel->chno = i;
+ channel->child = child;
edidp = of_get_property(child, "edid", &channel->edid_len);
if (edidp) {
@@ -565,11 +547,9 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
return -EINVAL;
}
- ret = imx_ldb_register(channel);
+ ret = imx_ldb_register(drm, channel);
if (ret)
return ret;
-
- imx_drm_encoder_add_possible_crtcs(channel->imx_drm_encoder, child);
}
dev_set_drvdata(dev, imx_ldb);
@@ -585,13 +565,9 @@ static void imx_ldb_unbind(struct device *dev, struct device *master,
for (i = 0; i < 2; i++) {
struct imx_ldb_channel *channel = &imx_ldb->channel[i];
- struct drm_connector *connector = &channel->connector;
- struct drm_encoder *encoder = &channel->encoder;
-
- drm_mode_connector_detach_encoder(connector, encoder);
- imx_drm_remove_connector(channel->imx_drm_connector);
- imx_drm_remove_encoder(channel->imx_drm_encoder);
+ channel->connector.funcs->destroy(&channel->connector);
+ channel->encoder.funcs->destroy(&channel->encoder);
}
}
diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c
index ad840d78a09a..702c0c3204ed 100644
--- a/drivers/staging/imx-drm/imx-tve.c
+++ b/drivers/staging/imx-drm/imx-tve.c
@@ -111,9 +111,7 @@ enum {
struct imx_tve {
struct drm_connector connector;
- struct imx_drm_connector *imx_drm_connector;
struct drm_encoder encoder;
- struct imx_drm_encoder *imx_drm_encoder;
struct device *dev;
spinlock_t lock; /* register lock */
bool enabled;
@@ -226,11 +224,6 @@ static enum drm_connector_status imx_tve_connector_detect(
return connector_status_connected;
}
-static void imx_tve_connector_destroy(struct drm_connector *connector)
-{
- /* do not free here */
-}
-
static int imx_tve_connector_get_modes(struct drm_connector *connector)
{
struct imx_tve *tve = con_to_tve(connector);
@@ -368,16 +361,11 @@ static void imx_tve_encoder_disable(struct drm_encoder *encoder)
tve_disable(tve);
}
-static void imx_tve_encoder_destroy(struct drm_encoder *encoder)
-{
- /* do not free here */
-}
-
static struct drm_connector_funcs imx_tve_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = imx_tve_connector_detect,
- .destroy = imx_tve_connector_destroy,
+ .destroy = imx_drm_connector_destroy,
};
static struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = {
@@ -387,7 +375,7 @@ static struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = {
};
static struct drm_encoder_funcs imx_tve_encoder_funcs = {
- .destroy = imx_tve_encoder_destroy,
+ .destroy = imx_drm_encoder_destroy,
};
static struct drm_encoder_helper_funcs imx_tve_encoder_helper_funcs = {
@@ -507,7 +495,7 @@ static int tve_clk_init(struct imx_tve *tve, void __iomem *base)
return 0;
}
-static int imx_tve_register(struct imx_tve *tve)
+static int imx_tve_register(struct drm_device *drm, struct imx_tve *tve)
{
int encoder_type;
int ret;
@@ -515,30 +503,19 @@ static int imx_tve_register(struct imx_tve *tve)
encoder_type = tve->mode == TVE_MODE_VGA ?
DRM_MODE_ENCODER_DAC : DRM_MODE_ENCODER_TVDAC;
- tve->connector.funcs = &imx_tve_connector_funcs;
- tve->encoder.funcs = &imx_tve_encoder_funcs;
-
- tve->encoder.encoder_type = encoder_type;
- tve->connector.connector_type = DRM_MODE_CONNECTOR_VGA;
+ ret = imx_drm_encoder_parse_of(drm, &tve->encoder,
+ tve->dev->of_node);
+ if (ret)
+ return ret;
drm_encoder_helper_add(&tve->encoder, &imx_tve_encoder_helper_funcs);
- ret = imx_drm_add_encoder(&tve->encoder, &tve->imx_drm_encoder,
- THIS_MODULE);
- if (ret) {
- dev_err(tve->dev, "adding encoder failed with %d\n", ret);
- return ret;
- }
+ drm_encoder_init(drm, &tve->encoder, &imx_tve_encoder_funcs,
+ encoder_type);
drm_connector_helper_add(&tve->connector,
&imx_tve_connector_helper_funcs);
-
- ret = imx_drm_add_connector(&tve->connector,
- &tve->imx_drm_connector, THIS_MODULE);
- if (ret) {
- imx_drm_remove_encoder(tve->imx_drm_encoder);
- dev_err(tve->dev, "adding connector failed with %d\n", ret);
- return ret;
- }
+ drm_connector_init(drm, &tve->connector, &imx_tve_connector_funcs,
+ DRM_MODE_CONNECTOR_VGA);
drm_mode_connector_attach_encoder(&tve->connector, &tve->encoder);
@@ -587,6 +564,7 @@ static const int of_get_tve_mode(struct device_node *np)
static int imx_tve_bind(struct device *dev, struct device *master, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
+ struct drm_device *drm = data;
struct device_node *np = dev->of_node;
struct device_node *ddc_node;
struct imx_tve *tve;
@@ -701,12 +679,10 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data)
/* disable cable detection for VGA mode */
ret = regmap_write(tve->regmap, TVE_CD_CONT_REG, 0);
- ret = imx_tve_register(tve);
+ ret = imx_tve_register(drm, tve);
if (ret)
return ret;
- ret = imx_drm_encoder_add_possible_crtcs(tve->imx_drm_encoder, np);
-
dev_set_drvdata(dev, tve);
return 0;
@@ -716,13 +692,9 @@ static void imx_tve_unbind(struct device *dev, struct device *master,
void *data)
{
struct imx_tve *tve = dev_get_drvdata(dev);
- struct drm_connector *connector = &tve->connector;
- struct drm_encoder *encoder = &tve->encoder;
-
- drm_mode_connector_detach_encoder(connector, encoder);
- imx_drm_remove_connector(tve->imx_drm_connector);
- imx_drm_remove_encoder(tve->imx_drm_encoder);
+ tve->connector.funcs->destroy(&tve->connector);
+ tve->encoder.funcs->destroy(&tve->encoder);
if (!IS_ERR(tve->dac_reg))
regulator_disable(tve->dac_reg);
diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c
index 4019cae35ff9..d610f0726bb2 100644
--- a/drivers/staging/imx-drm/parallel-display.c
+++ b/drivers/staging/imx-drm/parallel-display.c
@@ -33,9 +33,7 @@
struct imx_parallel_display {
struct drm_connector connector;
- struct imx_drm_connector *imx_drm_connector;
struct drm_encoder encoder;
- struct imx_drm_encoder *imx_drm_encoder;
struct device *dev;
void *edid;
int edid_len;
@@ -50,11 +48,6 @@ static enum drm_connector_status imx_pd_connector_detect(
return connector_status_connected;
}
-static void imx_pd_connector_destroy(struct drm_connector *connector)
-{
- /* do not free here */
-}
-
static int imx_pd_connector_get_modes(struct drm_connector *connector)
{
struct imx_parallel_display *imxpd = con_to_imxpd(connector);
@@ -126,16 +119,11 @@ static void imx_pd_encoder_disable(struct drm_encoder *encoder)
{
}
-static void imx_pd_encoder_destroy(struct drm_encoder *encoder)
-{
- /* do not free here */
-}
-
static struct drm_connector_funcs imx_pd_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = imx_pd_connector_detect,
- .destroy = imx_pd_connector_destroy,
+ .destroy = imx_drm_connector_destroy,
};
static struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
@@ -145,7 +133,7 @@ static struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
};
static struct drm_encoder_funcs imx_pd_encoder_funcs = {
- .destroy = imx_pd_encoder_destroy,
+ .destroy = imx_drm_encoder_destroy,
};
static struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = {
@@ -157,36 +145,26 @@ static struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = {
.disable = imx_pd_encoder_disable,
};
-static int imx_pd_register(struct imx_parallel_display *imxpd)
+static int imx_pd_register(struct drm_device *drm,
+ struct imx_parallel_display *imxpd)
{
int ret;
- drm_mode_connector_attach_encoder(&imxpd->connector, &imxpd->encoder);
-
- imxpd->connector.funcs = &imx_pd_connector_funcs;
- imxpd->encoder.funcs = &imx_pd_encoder_funcs;
-
- imxpd->encoder.encoder_type = DRM_MODE_ENCODER_NONE;
- imxpd->connector.connector_type = DRM_MODE_CONNECTOR_VGA;
+ ret = imx_drm_encoder_parse_of(drm, &imxpd->encoder,
+ imxpd->dev->of_node);
+ if (ret)
+ return ret;
drm_encoder_helper_add(&imxpd->encoder, &imx_pd_encoder_helper_funcs);
- ret = imx_drm_add_encoder(&imxpd->encoder, &imxpd->imx_drm_encoder,
- THIS_MODULE);
- if (ret) {
- dev_err(imxpd->dev, "adding encoder failed with %d\n", ret);
- return ret;
- }
+ drm_encoder_init(drm, &imxpd->encoder, &imx_pd_encoder_funcs,
+ DRM_MODE_ENCODER_NONE);
drm_connector_helper_add(&imxpd->connector,
&imx_pd_connector_helper_funcs);
+ drm_connector_init(drm, &imxpd->connector, &imx_pd_connector_funcs,
+ DRM_MODE_CONNECTOR_VGA);
- ret = imx_drm_add_connector(&imxpd->connector,
- &imxpd->imx_drm_connector, THIS_MODULE);
- if (ret) {
- imx_drm_remove_encoder(imxpd->imx_drm_encoder);
- dev_err(imxpd->dev, "adding connector failed with %d\n", ret);
- return ret;
- }
+ drm_mode_connector_attach_encoder(&imxpd->connector, &imxpd->encoder);
imxpd->connector.encoder = &imxpd->encoder;
@@ -195,6 +173,7 @@ static int imx_pd_register(struct imx_parallel_display *imxpd)
static int imx_pd_bind(struct device *dev, struct device *master, void *data)
{
+ struct drm_device *drm = data;
struct device_node *np = dev->of_node;
const u8 *edidp;
struct imx_parallel_display *imxpd;
@@ -221,12 +200,10 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
imxpd->dev = dev;
- ret = imx_pd_register(imxpd);
+ ret = imx_pd_register(drm, imxpd);
if (ret)
return ret;
- ret = imx_drm_encoder_add_possible_crtcs(imxpd->imx_drm_encoder, np);
-
dev_set_drvdata(dev, imxpd);
return 0;
@@ -236,13 +213,9 @@ static void imx_pd_unbind(struct device *dev, struct device *master,
void *data)
{
struct imx_parallel_display *imxpd = dev_get_drvdata(dev);
- struct drm_connector *connector = &imxpd->connector;
- struct drm_encoder *encoder = &imxpd->encoder;
-
- drm_mode_connector_detach_encoder(connector, encoder);
- imx_drm_remove_connector(imxpd->imx_drm_connector);
- imx_drm_remove_encoder(imxpd->imx_drm_encoder);
+ imxpd->encoder.funcs->destroy(&imxpd->encoder);
+ imxpd->connector.funcs->destroy(&imxpd->connector);
}
static const struct component_ops imx_pd_ops = {
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 24/34] imx-drm: imx-hdmi: initialise drm components directly
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (22 preceding siblings ...)
2014-02-18 20:11 ` [PATCH 23/34] imx-drm: parallel-display,imx-tve,imx-ldb: initialise drm components directly Russell King
@ 2014-02-18 20:11 ` Russell King
2014-02-18 20:11 ` [PATCH 25/34] imx-drm: imx-drm-core: remove imx_drm_connector and imx_drm_encoder code Russell King
` (9 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:11 UTC (permalink / raw)
To: linux-arm-kernel
Rather than calling into imx-drm-core to setup and register the encoders
and connectors, do this ourselves.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/imx-hdmi.c | 56 ++++++++++----------------------------
1 file changed, 15 insertions(+), 41 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 14b4a4b976b9..8c586453df11 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -113,9 +113,7 @@ struct hdmi_data_info {
struct imx_hdmi {
struct drm_connector connector;
- struct imx_drm_connector *imx_drm_connector;
struct drm_encoder encoder;
- struct imx_drm_encoder *imx_drm_encoder;
enum imx_hdmi_devtype dev_type;
struct device *dev;
@@ -1378,10 +1376,6 @@ static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
return connector_status_connected;
}
-static void imx_hdmi_connector_destroy(struct drm_connector *connector)
-{
-}
-
static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
{
struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
@@ -1467,13 +1461,8 @@ static void imx_hdmi_encoder_commit(struct drm_encoder *encoder)
imx_hdmi_poweron(hdmi);
}
-static void imx_hdmi_encoder_destroy(struct drm_encoder *encoder)
-{
- return;
-}
-
static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
- .destroy = imx_hdmi_encoder_destroy,
+ .destroy = imx_drm_encoder_destroy,
};
static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
@@ -1489,7 +1478,7 @@ static struct drm_connector_funcs imx_hdmi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = imx_hdmi_connector_detect,
- .destroy = imx_hdmi_connector_destroy,
+ .destroy = imx_drm_connector_destroy,
};
static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
@@ -1529,34 +1518,23 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int imx_hdmi_register(struct imx_hdmi *hdmi)
+static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
{
int ret;
- hdmi->connector.funcs = &imx_hdmi_connector_funcs;
- hdmi->encoder.funcs = &imx_hdmi_encoder_funcs;
-
- hdmi->encoder.encoder_type = DRM_MODE_ENCODER_TMDS;
- hdmi->connector.connector_type = DRM_MODE_CONNECTOR_HDMIA;
+ ret = imx_drm_encoder_parse_of(drm, &hdmi->encoder,
+ hdmi->dev->of_node);
+ if (ret)
+ return ret;
drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs);
- ret = imx_drm_add_encoder(&hdmi->encoder, &hdmi->imx_drm_encoder,
- THIS_MODULE);
- if (ret) {
- dev_err(hdmi->dev, "adding encoder failed: %d\n", ret);
- return ret;
- }
+ drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS);
drm_connector_helper_add(&hdmi->connector,
&imx_hdmi_connector_helper_funcs);
-
- ret = imx_drm_add_connector(&hdmi->connector,
- &hdmi->imx_drm_connector, THIS_MODULE);
- if (ret) {
- imx_drm_remove_encoder(hdmi->imx_drm_encoder);
- dev_err(hdmi->dev, "adding connector failed: %d\n", ret);
- return ret;
- }
+ drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);
hdmi->connector.encoder = &hdmi->encoder;
@@ -1588,6 +1566,7 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
struct platform_device *pdev = to_platform_device(dev);
const struct of_device_id *of_id =
of_match_device(imx_hdmi_dt_ids, dev);
+ struct drm_device *drm = data;
struct device_node *np = dev->of_node;
struct device_node *ddc_node;
struct imx_hdmi *hdmi;
@@ -1695,12 +1674,10 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
if (ret)
goto err_iahb;
- ret = imx_hdmi_register(hdmi);
+ ret = imx_hdmi_register(drm, hdmi);
if (ret)
goto err_iahb;
- imx_drm_encoder_add_possible_crtcs(hdmi->imx_drm_encoder, np);
-
dev_set_drvdata(dev, hdmi);
return 0;
@@ -1717,12 +1694,9 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
void *data)
{
struct imx_hdmi *hdmi = dev_get_drvdata(dev);
- struct drm_connector *connector = &hdmi->connector;
- struct drm_encoder *encoder = &hdmi->encoder;
- drm_mode_connector_detach_encoder(connector, encoder);
- imx_drm_remove_connector(hdmi->imx_drm_connector);
- imx_drm_remove_encoder(hdmi->imx_drm_encoder);
+ hdmi->connector.funcs->destroy(&hdmi->connector);
+ hdmi->encoder.funcs->destroy(&hdmi->encoder);
clk_disable_unprepare(hdmi->iahb_clk);
clk_disable_unprepare(hdmi->isfr_clk);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 25/34] imx-drm: imx-drm-core: remove imx_drm_connector and imx_drm_encoder code
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (23 preceding siblings ...)
2014-02-18 20:11 ` [PATCH 24/34] imx-drm: imx-hdmi: " Russell King
@ 2014-02-18 20:11 ` Russell King
2014-02-18 20:11 ` [PATCH 26/34] imx-drm: imx-drm-core: get rid of drm_mode_group_init_legacy_group() Russell King
` (8 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:11 UTC (permalink / raw)
To: linux-arm-kernel
The core imx_drm_connector and imx_drm_encoder code is no longer
required - the connectors and encoders are all using the component
support, so we can remove this.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/imx-drm-core.c | 371 +--------------------------------
drivers/staging/imx-drm/imx-drm.h | 14 --
2 files changed, 1 insertion(+), 384 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 1f50acd5a982..b27c42539e49 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -40,8 +40,6 @@ struct imx_drm_device {
struct drm_device *drm;
struct device *dev;
struct imx_drm_crtc *crtc[MAX_CRTC];
- struct list_head encoder_list;
- struct list_head connector_list;
struct mutex mutex;
int pipes;
struct drm_fbdev_cma *fbhelper;
@@ -56,24 +54,9 @@ struct imx_drm_crtc {
int mux_id;
};
-struct imx_drm_encoder {
- struct drm_encoder *encoder;
- struct list_head list;
- struct module *owner;
- struct list_head possible_crtcs;
-};
-
-struct imx_drm_connector {
- struct drm_connector *connector;
- struct list_head list;
- struct module *owner;
-};
-
static int legacyfb_depth = 16;
module_param(legacyfb_depth, int, 0444);
-static void imx_drm_device_put(void);
-
int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
{
return crtc->pipe;
@@ -101,8 +84,6 @@ static int imx_drm_driver_unload(struct drm_device *drm)
component_unbind_all(drm->dev, drm);
- imx_drm_device_put();
-
drm_vblank_cleanup(drm);
drm_kms_helper_poll_fini(drm);
drm_mode_config_cleanup(drm);
@@ -234,135 +215,6 @@ static struct imx_drm_device *__imx_drm_device(void)
return imx_drm_device;
}
-static struct drm_device *imx_drm_device_get(void)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
- struct imx_drm_encoder *enc;
- struct imx_drm_connector *con;
-
- list_for_each_entry(enc, &imxdrm->encoder_list, list) {
- if (!try_module_get(enc->owner)) {
- dev_err(imxdrm->dev, "could not get module %s\n",
- module_name(enc->owner));
- goto unwind_enc;
- }
- }
-
- list_for_each_entry(con, &imxdrm->connector_list, list) {
- if (!try_module_get(con->owner)) {
- dev_err(imxdrm->dev, "could not get module %s\n",
- module_name(con->owner));
- goto unwind_con;
- }
- }
-
- return imxdrm->drm;
-
-unwind_con:
- list_for_each_entry_continue_reverse(con, &imxdrm->connector_list, list)
- module_put(con->owner);
-unwind_enc:
- list_for_each_entry_continue_reverse(enc, &imxdrm->encoder_list, list)
- module_put(enc->owner);
-
- mutex_unlock(&imxdrm->mutex);
-
- return NULL;
-
-}
-
-static void imx_drm_device_put(void)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
- struct imx_drm_encoder *enc;
- struct imx_drm_connector *con;
-
- mutex_lock(&imxdrm->mutex);
-
- list_for_each_entry(con, &imxdrm->connector_list, list)
- module_put(con->owner);
-
- list_for_each_entry(enc, &imxdrm->encoder_list, list)
- module_put(enc->owner);
-
- mutex_unlock(&imxdrm->mutex);
-}
-
-static int drm_mode_group_reinit(struct drm_device *dev)
-{
- struct drm_mode_group *group = &dev->primary->mode_group;
- uint32_t *id_list = group->id_list;
- int ret;
-
- ret = drm_mode_group_init_legacy_group(dev, group);
- if (ret < 0)
- return ret;
-
- kfree(id_list);
- return 0;
-}
-
-/*
- * register an encoder to the drm core
- */
-static int imx_drm_encoder_register(struct imx_drm_encoder *imx_drm_encoder)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
-
- INIT_LIST_HEAD(&imx_drm_encoder->possible_crtcs);
-
- drm_encoder_init(imxdrm->drm, imx_drm_encoder->encoder,
- imx_drm_encoder->encoder->funcs,
- imx_drm_encoder->encoder->encoder_type);
-
- drm_mode_group_reinit(imxdrm->drm);
-
- return 0;
-}
-
-/*
- * unregister an encoder from the drm core
- */
-static void imx_drm_encoder_unregister(struct imx_drm_encoder
- *imx_drm_encoder)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
-
- drm_encoder_cleanup(imx_drm_encoder->encoder);
-
- drm_mode_group_reinit(imxdrm->drm);
-}
-
-/*
- * register a connector to the drm core
- */
-static int imx_drm_connector_register(
- struct imx_drm_connector *imx_drm_connector)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
-
- drm_connector_init(imxdrm->drm, imx_drm_connector->connector,
- imx_drm_connector->connector->funcs,
- imx_drm_connector->connector->connector_type);
- drm_mode_group_reinit(imxdrm->drm);
-
- return 0;
-}
-
-/*
- * unregister a connector from the drm core
- */
-static void imx_drm_connector_unregister(
- struct imx_drm_connector *imx_drm_connector)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
-
- drm_sysfs_connector_remove(imx_drm_connector->connector);
- drm_connector_cleanup(imx_drm_connector->connector);
-
- drm_mode_group_reinit(imxdrm->drm);
-}
-
void imx_drm_connector_destroy(struct drm_connector *connector)
{
drm_sysfs_connector_remove(connector);
@@ -439,12 +291,8 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
*/
drm->vblank_disable_allowed = true;
- if (!imx_drm_device_get()) {
- ret = -EINVAL;
- goto err_vblank;
- }
-
platform_set_drvdata(drm->platformdev, drm);
+
mutex_unlock(&imxdrm->mutex);
/* Now try and bind all our sub-components */
@@ -492,7 +340,6 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
component_unbind_all(drm->dev, drm);
err_relock:
mutex_lock(&imxdrm->mutex);
-err_vblank:
drm_vblank_cleanup(drm);
err_kms:
drm_kms_helper_poll_fini(drm);
@@ -502,29 +349,6 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
return ret;
}
-static void imx_drm_update_possible_crtcs(void)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
- struct imx_drm_crtc *imx_drm_crtc;
- struct imx_drm_encoder *enc;
- struct crtc_cookie *cookie;
-
- list_for_each_entry(enc, &imxdrm->encoder_list, list) {
- u32 possible_crtcs = 0;
-
- list_for_each_entry(cookie, &enc->possible_crtcs, list) {
- list_for_each_entry(imx_drm_crtc, &imxdrm->crtc_list, list) {
- if (imx_drm_crtc->cookie.cookie == cookie->cookie &&
- imx_drm_crtc->cookie.id == cookie->id) {
- possible_crtcs |= 1 << imx_drm_crtc->pipe;
- }
- }
- }
- enc->encoder->possible_crtcs = possible_crtcs;
- enc->encoder->possible_clones = possible_crtcs;
- }
-}
-
/*
* imx_drm_add_crtc - add a new crtc
*
@@ -584,8 +408,6 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
drm_crtc_init(drm, crtc,
imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
- imx_drm_update_possible_crtcs();
-
mutex_unlock(&imxdrm->mutex);
return 0;
@@ -622,56 +444,6 @@ int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
EXPORT_SYMBOL_GPL(imx_drm_remove_crtc);
/*
- * imx_drm_add_encoder - add a new encoder
- */
-int imx_drm_add_encoder(struct drm_encoder *encoder,
- struct imx_drm_encoder **newenc, struct module *owner)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
- struct imx_drm_encoder *imx_drm_encoder;
- int ret;
-
- mutex_lock(&imxdrm->mutex);
-
- if (imxdrm->drm->open_count) {
- ret = -EBUSY;
- goto err_busy;
- }
-
- imx_drm_encoder = kzalloc(sizeof(*imx_drm_encoder), GFP_KERNEL);
- if (!imx_drm_encoder) {
- ret = -ENOMEM;
- goto err_alloc;
- }
-
- imx_drm_encoder->encoder = encoder;
- imx_drm_encoder->owner = owner;
-
- ret = imx_drm_encoder_register(imx_drm_encoder);
- if (ret) {
- ret = -ENOMEM;
- goto err_register;
- }
-
- list_add_tail(&imx_drm_encoder->list, &imxdrm->encoder_list);
-
- *newenc = imx_drm_encoder;
-
- mutex_unlock(&imxdrm->mutex);
-
- return 0;
-
-err_register:
- kfree(imx_drm_encoder);
-err_alloc:
-err_busy:
- mutex_unlock(&imxdrm->mutex);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(imx_drm_add_encoder);
-
-/*
* Find the DRM CRTC possible mask for the device node cookie/id.
*
* The encoder possible masks are defined by their position in the
@@ -737,49 +509,6 @@ int imx_drm_encoder_parse_of(struct drm_device *drm,
}
EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of);
-int imx_drm_encoder_add_possible_crtcs(
- struct imx_drm_encoder *imx_drm_encoder,
- struct device_node *np)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
- struct of_phandle_args args;
- struct crtc_cookie *c;
- int ret = 0;
- int i;
-
- if (!list_empty(&imx_drm_encoder->possible_crtcs))
- return -EBUSY;
-
- for (i = 0; !ret; i++) {
- ret = of_parse_phandle_with_args(np, "crtcs",
- "#crtc-cells", i, &args);
- if (ret < 0)
- break;
-
- c = kzalloc(sizeof(*c), GFP_KERNEL);
- if (!c) {
- of_node_put(args.np);
- return -ENOMEM;
- }
-
- c->cookie = args.np;
- c->id = args.args_count > 0 ? args.args[0] : 0;
-
- of_node_put(args.np);
-
- mutex_lock(&imxdrm->mutex);
-
- list_add_tail(&c->list, &imx_drm_encoder->possible_crtcs);
-
- mutex_unlock(&imxdrm->mutex);
- }
-
- imx_drm_update_possible_crtcs();
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(imx_drm_encoder_add_possible_crtcs);
-
int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder)
{
struct imx_drm_crtc *imx_crtc = imx_drm_find_crtc(encoder->crtc);
@@ -788,102 +517,6 @@ int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder)
}
EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id);
-/*
- * imx_drm_remove_encoder - remove an encoder
- */
-int imx_drm_remove_encoder(struct imx_drm_encoder *imx_drm_encoder)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
- struct crtc_cookie *c, *tmp;
-
- mutex_lock(&imxdrm->mutex);
-
- imx_drm_encoder_unregister(imx_drm_encoder);
-
- list_del(&imx_drm_encoder->list);
-
- list_for_each_entry_safe(c, tmp, &imx_drm_encoder->possible_crtcs,
- list)
- kfree(c);
-
- mutex_unlock(&imxdrm->mutex);
-
- kfree(imx_drm_encoder);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(imx_drm_remove_encoder);
-
-/*
- * imx_drm_add_connector - add a connector
- */
-int imx_drm_add_connector(struct drm_connector *connector,
- struct imx_drm_connector **new_con,
- struct module *owner)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
- struct imx_drm_connector *imx_drm_connector;
- int ret;
-
- mutex_lock(&imxdrm->mutex);
-
- if (imxdrm->drm->open_count) {
- ret = -EBUSY;
- goto err_busy;
- }
-
- imx_drm_connector = kzalloc(sizeof(*imx_drm_connector), GFP_KERNEL);
- if (!imx_drm_connector) {
- ret = -ENOMEM;
- goto err_alloc;
- }
-
- imx_drm_connector->connector = connector;
- imx_drm_connector->owner = owner;
-
- ret = imx_drm_connector_register(imx_drm_connector);
- if (ret)
- goto err_register;
-
- list_add_tail(&imx_drm_connector->list, &imxdrm->connector_list);
-
- *new_con = imx_drm_connector;
-
- mutex_unlock(&imxdrm->mutex);
-
- return 0;
-
-err_register:
- kfree(imx_drm_connector);
-err_alloc:
-err_busy:
- mutex_unlock(&imxdrm->mutex);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(imx_drm_add_connector);
-
-/*
- * imx_drm_remove_connector - remove a connector
- */
-int imx_drm_remove_connector(struct imx_drm_connector *imx_drm_connector)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
-
- mutex_lock(&imxdrm->mutex);
-
- imx_drm_connector_unregister(imx_drm_connector);
-
- list_del(&imx_drm_connector->list);
-
- mutex_unlock(&imxdrm->mutex);
-
- kfree(imx_drm_connector);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(imx_drm_remove_connector);
-
static const struct drm_ioctl_desc imx_drm_ioctls[] = {
/* none so far */
};
@@ -1031,8 +664,6 @@ static int __init imx_drm_init(void)
return -ENOMEM;
mutex_init(&imx_drm_device->mutex);
- INIT_LIST_HEAD(&imx_drm_device->connector_list);
- INIT_LIST_HEAD(&imx_drm_device->encoder_list);
ret = platform_driver_register(&imx_drm_pdrv);
if (ret)
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index 0543606c587a..ae9c96d181fa 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -39,18 +39,6 @@ int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc);
void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc);
void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc);
-struct imx_drm_encoder;
-int imx_drm_add_encoder(struct drm_encoder *encoder,
- struct imx_drm_encoder **new_enc,
- struct module *owner);
-int imx_drm_remove_encoder(struct imx_drm_encoder *);
-
-struct imx_drm_connector;
-int imx_drm_add_connector(struct drm_connector *connector,
- struct imx_drm_connector **new_con,
- struct module *owner);
-int imx_drm_remove_connector(struct imx_drm_connector *);
-
void imx_drm_mode_config_init(struct drm_device *drm);
struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
@@ -63,8 +51,6 @@ int imx_drm_panel_format(struct drm_encoder *encoder,
struct device_node;
int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder);
-int imx_drm_encoder_add_possible_crtcs(struct imx_drm_encoder *imx_drm_encoder,
- struct device_node *np);
int imx_drm_encoder_parse_of(struct drm_device *drm,
struct drm_encoder *encoder, struct device_node *np);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 26/34] imx-drm: imx-drm-core: get rid of drm_mode_group_init_legacy_group()
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (24 preceding siblings ...)
2014-02-18 20:11 ` [PATCH 25/34] imx-drm: imx-drm-core: remove imx_drm_connector and imx_drm_encoder code Russell King
@ 2014-02-18 20:11 ` Russell King
2014-02-18 20:11 ` [PATCH 27/34] imx-drm: imx-drm-core: kill off mutex Russell King
` (7 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:11 UTC (permalink / raw)
To: linux-arm-kernel
Since we're now operating like a conventional DRM driver, doing all
the initialisation within the driver's ->load callback, we don't
need to mess around with the mode groups - we can rely on the one
in the DRM platform code.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/imx-drm-core.c | 6 ------
1 file changed, 6 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index b27c42539e49..dd97412d6c8a 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -274,12 +274,6 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
drm_kms_helper_poll_init(drm);
- /* setup the grouping for the legacy output */
- ret = drm_mode_group_init_legacy_group(drm,
- &drm->primary->mode_group);
- if (ret)
- goto err_kms;
-
ret = drm_vblank_init(drm, MAX_CRTC);
if (ret)
goto err_kms;
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 27/34] imx-drm: imx-drm-core: kill off mutex
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (25 preceding siblings ...)
2014-02-18 20:11 ` [PATCH 26/34] imx-drm: imx-drm-core: get rid of drm_mode_group_init_legacy_group() Russell King
@ 2014-02-18 20:11 ` Russell King
2014-02-18 20:12 ` [PATCH 28/34] imx-drm: imx-drm-core: move allocation of imxdrm device to driver load function Russell King
` (6 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:11 UTC (permalink / raw)
To: linux-arm-kernel
This mutex doesn't protect anything anymore; get rid of it.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/imx-drm-core.c | 26 +++-----------------------
1 file changed, 3 insertions(+), 23 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index dd97412d6c8a..d5b82cb0cfae 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -40,14 +40,12 @@ struct imx_drm_device {
struct drm_device *drm;
struct device *dev;
struct imx_drm_crtc *crtc[MAX_CRTC];
- struct mutex mutex;
int pipes;
struct drm_fbdev_cma *fbhelper;
};
struct imx_drm_crtc {
struct drm_crtc *crtc;
- struct imx_drm_device *imxdrm;
int pipe;
struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs;
struct crtc_cookie cookie;
@@ -270,8 +268,6 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
drm_mode_config_init(drm);
- mutex_lock(&imxdrm->mutex);
-
drm_kms_helper_poll_init(drm);
ret = drm_vblank_init(drm, MAX_CRTC);
@@ -287,12 +283,10 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
platform_set_drvdata(drm->platformdev, drm);
- mutex_unlock(&imxdrm->mutex);
-
/* Now try and bind all our sub-components */
ret = component_bind_all(drm->dev, drm);
if (ret)
- goto err_relock;
+ goto err_vblank;
/*
* All components are now added, we can publish the connector sysfs
@@ -332,13 +326,11 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
err_unbind:
component_unbind_all(drm->dev, drm);
-err_relock:
- mutex_lock(&imxdrm->mutex);
+err_vblank:
drm_vblank_cleanup(drm);
err_kms:
drm_kms_helper_poll_fini(drm);
drm_mode_config_cleanup(drm);
- mutex_unlock(&imxdrm->mutex);
return ret;
}
@@ -358,8 +350,6 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
struct imx_drm_crtc *imx_drm_crtc;
int ret;
- mutex_lock(&imxdrm->mutex);
-
/*
* The vblank arrays are dimensioned by MAX_CRTC - we can't
* pass IDs greater than this to those functions.
@@ -386,7 +376,6 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
imx_drm_crtc->cookie.id = id;
imx_drm_crtc->mux_id = imx_drm_crtc->pipe;
imx_drm_crtc->crtc = crtc;
- imx_drm_crtc->imxdrm = imxdrm;
imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
@@ -402,8 +391,6 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
drm_crtc_init(drm, crtc,
imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
- mutex_unlock(&imxdrm->mutex);
-
return 0;
err_register:
@@ -411,7 +398,6 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
kfree(imx_drm_crtc);
err_alloc:
err_busy:
- mutex_unlock(&imxdrm->mutex);
return ret;
}
EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
@@ -421,16 +407,12 @@ EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
*/
int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
{
- struct imx_drm_device *imxdrm = imx_drm_crtc->imxdrm;
-
- mutex_lock(&imxdrm->mutex);
+ struct imx_drm_device *imxdrm = imx_drm_crtc->crtc->dev->dev_private;
drm_crtc_cleanup(imx_drm_crtc->crtc);
imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
- mutex_unlock(&imxdrm->mutex);
-
kfree(imx_drm_crtc);
return 0;
@@ -657,8 +639,6 @@ static int __init imx_drm_init(void)
if (!imx_drm_device)
return -ENOMEM;
- mutex_init(&imx_drm_device->mutex);
-
ret = platform_driver_register(&imx_drm_pdrv);
if (ret)
goto err_pdrv;
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 28/34] imx-drm: imx-drm-core: move allocation of imxdrm device to driver load function
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (26 preceding siblings ...)
2014-02-18 20:11 ` [PATCH 27/34] imx-drm: imx-drm-core: kill off mutex Russell King
@ 2014-02-18 20:12 ` Russell King
2014-02-18 20:12 ` [PATCH 29/34] imx-drm: imx-drm-core: various cleanups Russell King
` (5 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:12 UTC (permalink / raw)
To: linux-arm-kernel
It is now no longer necessary to keep this structure around; we can
allocate it upon DRM driver load and destroy it thereafter without
affecting the other components now.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/imx-drm-core.c | 47 +++++-----------------------------
1 file changed, 6 insertions(+), 41 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index d5b82cb0cfae..35c8f7cf6900 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -38,7 +38,6 @@ struct imx_drm_crtc;
struct imx_drm_device {
struct drm_device *drm;
- struct device *dev;
struct imx_drm_crtc *crtc[MAX_CRTC];
int pipes;
struct drm_fbdev_cma *fbhelper;
@@ -206,13 +205,6 @@ int imx_drm_connector_mode_valid(struct drm_connector *connector,
}
EXPORT_SYMBOL(imx_drm_connector_mode_valid);
-static struct imx_drm_device *imx_drm_device;
-
-static struct imx_drm_device *__imx_drm_device(void)
-{
- return imx_drm_device;
-}
-
void imx_drm_connector_destroy(struct drm_connector *connector)
{
drm_sysfs_connector_remove(connector);
@@ -236,10 +228,14 @@ static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
*/
static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
{
- struct imx_drm_device *imxdrm = __imx_drm_device();
+ struct imx_drm_device *imxdrm;
struct drm_connector *connector;
int ret;
+ imxdrm = devm_kzalloc(drm->dev, sizeof(*imxdrm), GFP_KERNEL);
+ if (!imxdrm)
+ return -ENOMEM;
+
imxdrm->drm = drm;
drm->dev_private = imxdrm;
@@ -604,8 +600,6 @@ static int imx_drm_platform_probe(struct platform_device *pdev)
if (ret)
return ret;
- imx_drm_device->dev = &pdev->dev;
-
return component_master_add(&pdev->dev, &imx_drm_ops);
}
@@ -630,36 +624,7 @@ static struct platform_driver imx_drm_pdrv = {
.of_match_table = imx_drm_dt_ids,
},
};
-
-static int __init imx_drm_init(void)
-{
- int ret;
-
- imx_drm_device = kzalloc(sizeof(*imx_drm_device), GFP_KERNEL);
- if (!imx_drm_device)
- return -ENOMEM;
-
- ret = platform_driver_register(&imx_drm_pdrv);
- if (ret)
- goto err_pdrv;
-
- return 0;
-
-err_pdrv:
- kfree(imx_drm_device);
-
- return ret;
-}
-
-static void __exit imx_drm_exit(void)
-{
- platform_driver_unregister(&imx_drm_pdrv);
-
- kfree(imx_drm_device);
-}
-
-module_init(imx_drm_init);
-module_exit(imx_drm_exit);
+module_platform_driver(imx_drm_pdrv);
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
MODULE_DESCRIPTION("i.MX drm driver core");
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 29/34] imx-drm: imx-drm-core: various cleanups
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (27 preceding siblings ...)
2014-02-18 20:12 ` [PATCH 28/34] imx-drm: imx-drm-core: move allocation of imxdrm device to driver load function Russell King
@ 2014-02-18 20:12 ` Russell King
2014-02-18 20:12 ` [PATCH 30/34] imx-drm: imx-drm-core: add core hotplug connector support Russell King
` (4 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:12 UTC (permalink / raw)
To: linux-arm-kernel
Various cleanups are possible after the previous round of changes; these
have no real functional bearing other than tidying up the code.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/imx-drm-core.c | 47 ++++++++++++----------------------
drivers/staging/imx-drm/imx-drm.h | 5 ++--
2 files changed, 19 insertions(+), 33 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 35c8f7cf6900..7939cea8311a 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -15,12 +15,12 @@
*/
#include <linux/component.h>
#include <linux/device.h>
+#include <linux/fb.h>
+#include <linux/module.h>
#include <linux/platform_device.h>
#include <drm/drmP.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
-#include <linux/fb.h>
-#include <linux/module.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_cma_helper.h>
@@ -28,12 +28,6 @@
#define MAX_CRTC 4
-struct crtc_cookie {
- void *cookie;
- int id;
- struct list_head list;
-};
-
struct imx_drm_crtc;
struct imx_drm_device {
@@ -47,7 +41,8 @@ struct imx_drm_crtc {
struct drm_crtc *crtc;
int pipe;
struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs;
- struct crtc_cookie cookie;
+ void *cookie;
+ int id;
int mux_id;
};
@@ -271,9 +266,9 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
goto err_kms;
/*
- * with vblank_disable_allowed = true, vblank interrupt will be disabled
- * by drm timer once a current process gives up ownership of
- * vblank event.(after drm_vblank_put function is called)
+ * with vblank_disable_allowed = true, vblank interrupt will be
+ * disabled by drm timer once a current process gives up ownership
+ * of vblank event. (after drm_vblank_put function is called)
*/
drm->vblank_disable_allowed = true;
@@ -350,26 +345,20 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
* The vblank arrays are dimensioned by MAX_CRTC - we can't
* pass IDs greater than this to those functions.
*/
- if (imxdrm->pipes >= MAX_CRTC) {
- ret = -EINVAL;
- goto err_busy;
- }
+ if (imxdrm->pipes >= MAX_CRTC)
+ return -EINVAL;
- if (imxdrm->drm->open_count) {
- ret = -EBUSY;
- goto err_busy;
- }
+ if (imxdrm->drm->open_count)
+ return -EBUSY;
imx_drm_crtc = kzalloc(sizeof(*imx_drm_crtc), GFP_KERNEL);
- if (!imx_drm_crtc) {
- ret = -ENOMEM;
- goto err_alloc;
- }
+ if (!imx_drm_crtc)
+ return -ENOMEM;
imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs;
imx_drm_crtc->pipe = imxdrm->pipes++;
- imx_drm_crtc->cookie.cookie = cookie;
- imx_drm_crtc->cookie.id = id;
+ imx_drm_crtc->cookie = cookie;
+ imx_drm_crtc->id = id;
imx_drm_crtc->mux_id = imx_drm_crtc->pipe;
imx_drm_crtc->crtc = crtc;
@@ -392,8 +381,6 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
err_register:
imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
kfree(imx_drm_crtc);
-err_alloc:
-err_busy:
return ret;
}
EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
@@ -429,8 +416,8 @@ static uint32_t imx_drm_find_crtc_mask(struct imx_drm_device *imxdrm,
for (i = 0; i < MAX_CRTC; i++) {
struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[i];
- if (imx_drm_crtc && imx_drm_crtc->cookie.id == id &&
- imx_drm_crtc->cookie.cookie == cookie)
+ if (imx_drm_crtc && imx_drm_crtc->id == id &&
+ imx_drm_crtc->cookie == cookie)
return drm_crtc_mask(imx_drm_crtc->crtc);
}
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index ae9c96d181fa..aa2102866689 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -5,14 +5,15 @@
#define IPU_PIX_FMT_GBR24 v4l2_fourcc('G', 'B', 'R', '3')
+struct device_node;
struct drm_crtc;
struct drm_connector;
struct drm_device;
struct drm_display_mode;
struct drm_encoder;
-struct imx_drm_crtc;
struct drm_fbdev_cma;
struct drm_framebuffer;
+struct imx_drm_crtc;
struct platform_device;
int imx_drm_crtc_id(struct imx_drm_crtc *crtc);
@@ -48,8 +49,6 @@ int imx_drm_panel_format_pins(struct drm_encoder *encoder,
int imx_drm_panel_format(struct drm_encoder *encoder,
u32 interface_pix_fmt);
-struct device_node;
-
int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder);
int imx_drm_encoder_parse_of(struct drm_device *drm,
struct drm_encoder *encoder, struct device_node *np);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 30/34] imx-drm: imx-drm-core: add core hotplug connector support
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (28 preceding siblings ...)
2014-02-18 20:12 ` [PATCH 29/34] imx-drm: imx-drm-core: various cleanups Russell King
@ 2014-02-18 20:12 ` Russell King
2014-02-18 20:12 ` [PATCH 31/34] imx-drm: imx-hdmi: add hotplug support to HDMI component Russell King
` (3 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:12 UTC (permalink / raw)
To: linux-arm-kernel
Add core imx-drm support for hotplug connector support. We need to
setup the poll helper after we've setup the connectors; the helper
scans the connectors to determine their capabilities.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/imx-drm-core.c | 21 +++++++++++++++++----
1 file changed, 17 insertions(+), 4 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 7939cea8311a..dcba51853e8a 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -69,7 +69,11 @@ static int imx_drm_driver_unload(struct drm_device *drm)
{
#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
struct imx_drm_device *imxdrm = drm->dev_private;
+#endif
+
+ drm_kms_helper_poll_fini(drm);
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
if (imxdrm->fbhelper)
drm_fbdev_cma_fini(imxdrm->fbhelper);
#endif
@@ -77,7 +81,6 @@ static int imx_drm_driver_unload(struct drm_device *drm)
component_unbind_all(drm->dev, drm);
drm_vblank_cleanup(drm);
- drm_kms_helper_poll_fini(drm);
drm_mode_config_cleanup(drm);
return 0;
@@ -213,8 +216,18 @@ void imx_drm_encoder_destroy(struct drm_encoder *encoder)
}
EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy);
+static void imx_drm_output_poll_changed(struct drm_device *drm)
+{
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
+ struct imx_drm_device *imxdrm = drm->dev_private;
+
+ drm_fbdev_cma_hotplug_event(imxdrm->fbhelper);
+#endif
+}
+
static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
.fb_create = drm_fb_cma_create,
+ .output_poll_changed = imx_drm_output_poll_changed,
};
/*
@@ -259,8 +272,6 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
drm_mode_config_init(drm);
- drm_kms_helper_poll_init(drm);
-
ret = drm_vblank_init(drm, MAX_CRTC);
if (ret)
goto err_kms;
@@ -313,6 +324,9 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
goto err_unbind;
}
#endif
+
+ drm_kms_helper_poll_init(drm);
+
return 0;
err_unbind:
@@ -320,7 +334,6 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
err_vblank:
drm_vblank_cleanup(drm);
err_kms:
- drm_kms_helper_poll_fini(drm);
drm_mode_config_cleanup(drm);
return ret;
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 31/34] imx-drm: imx-hdmi: add hotplug support to HDMI component
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (29 preceding siblings ...)
2014-02-18 20:12 ` [PATCH 30/34] imx-drm: imx-drm-core: add core hotplug connector support Russell King
@ 2014-02-18 20:12 ` Russell King
2014-02-18 20:12 ` [PATCH 32/34] imx-drm: dw-hdmi-audio: add audio driver Russell King
` (2 subsequent siblings)
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:12 UTC (permalink / raw)
To: linux-arm-kernel
Add hotplug support. We have to make the interrupt handler threaded so
we can call drm_helper_hpd_irq_event(). Keeping in mind that we will
want to share the interrupt with other HDMI interface drivers (eg, audio
and CEC) put the groundwork in now for that, rather than just using
IRQF_ONESHOT.
Also, we must not call drm_helper_hpd_irq_event() until we have fully
setup the connector; keep the interrupt(s) muted until after that point.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/imx-hdmi.c | 40 +++++++++++++++++++++++++++++++-------
1 file changed, 33 insertions(+), 7 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 8c586453df11..ab16aba7788d 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -120,6 +120,8 @@ struct imx_hdmi {
struct clk *isfr_clk;
struct clk *iahb_clk;
+ enum drm_connector_status connector_status;
+
struct hdmi_data_info hdmi_data;
int vic;
@@ -1301,9 +1303,6 @@ static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
/* Clear Hotplug interrupts */
hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
- /* Unmute interrupts */
- hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
-
return 0;
}
@@ -1372,8 +1371,9 @@ static void imx_hdmi_poweroff(struct imx_hdmi *hdmi)
static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
*connector, bool force)
{
- /* FIXME */
- return connector_status_connected;
+ struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+ connector);
+ return hdmi->connector_status;
}
static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
@@ -1487,6 +1487,18 @@ static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
.best_encoder = imx_hdmi_connector_best_encoder,
};
+static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
+{
+ struct imx_hdmi *hdmi = dev_id;
+ u8 intr_stat;
+
+ intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
+ if (intr_stat)
+ hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+
+ return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE;
+}
+
static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
{
struct imx_hdmi *hdmi = dev_id;
@@ -1503,17 +1515,21 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
+ hdmi->connector_status = connector_status_connected;
imx_hdmi_poweron(hdmi);
} else {
dev_dbg(hdmi->dev, "EVENT=plugout\n");
hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD, HDMI_PHY_POL0);
+ hdmi->connector_status = connector_status_disconnected;
imx_hdmi_poweroff(hdmi);
}
+ drm_helper_hpd_irq_event(hdmi->connector.dev);
}
hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
+ hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
return IRQ_HANDLED;
}
@@ -1527,6 +1543,8 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
if (ret)
return ret;
+ hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
+
drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs);
drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs,
DRM_MODE_ENCODER_TMDS);
@@ -1578,6 +1596,7 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
return -ENOMEM;
hdmi->dev = dev;
+ hdmi->connector_status = connector_status_disconnected;
hdmi->sample_rate = 48000;
hdmi->ratio = 100;
@@ -1601,8 +1620,9 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
if (irq < 0)
return -EINVAL;
- ret = devm_request_irq(dev, irq, imx_hdmi_irq, 0,
- dev_name(dev), hdmi);
+ ret = devm_request_threaded_irq(dev, irq, imx_hdmi_hardirq,
+ imx_hdmi_irq, IRQF_SHARED,
+ dev_name(dev), hdmi);
if (ret)
return ret;
@@ -1678,6 +1698,9 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
if (ret)
goto err_iahb;
+ /* Unmute interrupts */
+ hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
+
dev_set_drvdata(dev, hdmi);
return 0;
@@ -1695,6 +1718,9 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
{
struct imx_hdmi *hdmi = dev_get_drvdata(dev);
+ /* Disable all interrupts */
+ hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+
hdmi->connector.funcs->destroy(&hdmi->connector);
hdmi->encoder.funcs->destroy(&hdmi->encoder);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 32/34] imx-drm: dw-hdmi-audio: add audio driver
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (30 preceding siblings ...)
2014-02-18 20:12 ` [PATCH 31/34] imx-drm: imx-hdmi: add hotplug support to HDMI component Russell King
@ 2014-02-18 20:12 ` Russell King
2014-02-18 20:12 ` [PATCH 33/34] imx-drm: dw-hdmi-audio: parse ELD from HDMI driver Russell King
2014-02-18 20:12 ` [PATCH 34/34] imx-drm: add CEC " Russell King
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:12 UTC (permalink / raw)
To: linux-arm-kernel
Add ALSA based HDMI audio driver for imx-hdmi. The imx-hdmi is a
Synopsis DesignWare module, so let's name it after that. The only
buffer format supported is its own special IEC958 based format, which
is not compatible with any ALSA format. To avoid doing too much data
manipulation within the driver, we support only ALSAs IEC958 LE, and
24-bit PCM formats for 2 to 6 channels.
This allows us to modify the buffer in place as each period is passed
for DMA without needing a separate buffer.
A more desirable solution would be to have this conversion in userspace,
but ALSA does not appear to allow such transformations outside of
libasound itself.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/Makefile | 3 +-
drivers/staging/imx-drm/dw-hdmi-audio.c | 499 ++++++++++++++++++++++++++++++++
drivers/staging/imx-drm/dw-hdmi-audio.h | 13 +
drivers/staging/imx-drm/imx-hdmi.c | 21 ++
drivers/staging/imx-drm/imx-hdmi.h | 4 +
5 files changed, 539 insertions(+), 1 deletion(-)
create mode 100644 drivers/staging/imx-drm/dw-hdmi-audio.c
create mode 100644 drivers/staging/imx-drm/dw-hdmi-audio.h
diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 129e3a3f59f1..f554aa631993 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -1,5 +1,6 @@
imxdrm-objs := imx-drm-core.o
+imxhdmi-objs := imx-hdmi.o dw-hdmi-audio.o
obj-$(CONFIG_DRM_IMX) += imxdrm.o
@@ -10,4 +11,4 @@ obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/
imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o
obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o
-obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o
+obj-$(CONFIG_DRM_IMX_HDMI) += imxhdmi.o
diff --git a/drivers/staging/imx-drm/dw-hdmi-audio.c b/drivers/staging/imx-drm/dw-hdmi-audio.c
new file mode 100644
index 000000000000..a17714dfa86d
--- /dev/null
+++ b/drivers/staging/imx-drm/dw-hdmi-audio.c
@@ -0,0 +1,499 @@
+/*
+ * DesignWare HDMI audio driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Written and tested against the (alleged) DW HDMI Tx found in iMX6S.
+ */
+#include <linux/io.h>
+#include <linux/interrupt.h>
+
+#include <sound/asoundef.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+
+#include "imx-hdmi.h"
+#include "dw-hdmi-audio.h"
+
+#define DRIVER_NAME "dw-hdmi-audio"
+
+/* Provide some bits rather than bit offsets */
+enum {
+ HDMI_AHB_DMA_CONF0_SW_FIFO_RST = HDMI_AHB_DMA_CONF0_SW_FIFO_RST_MASK,
+ HDMI_AHB_DMA_CONF0_EN_HLOCK = HDMI_AHB_DMA_CONF0_EN_HLOCK_MASK,
+ HDMI_AHB_DMA_START_START = BIT(HDMI_AHB_DMA_START_START_OFFSET),
+ HDMI_AHB_DMA_STOP_STOP = BIT(HDMI_AHB_DMA_STOP_STOP_OFFSET),
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL =
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR |
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST |
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY |
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE |
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL |
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY,
+ HDMI_IH_AHBDMAAUD_STAT0_ALL =
+ HDMI_IH_AHBDMAAUD_STAT0_ERROR |
+ HDMI_IH_AHBDMAAUD_STAT0_LOST |
+ HDMI_IH_AHBDMAAUD_STAT0_RETRY |
+ HDMI_IH_AHBDMAAUD_STAT0_DONE |
+ HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL |
+ HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY,
+};
+
+struct snd_dw_hdmi {
+ struct snd_card *card;
+ struct snd_pcm *pcm;
+ void __iomem *base;
+ int irq;
+ struct imx_hdmi *hdmi;
+ struct snd_pcm_substream *substream;
+ void (*reformat)(struct snd_dw_hdmi *, size_t, size_t);
+ void *buf_base;
+ dma_addr_t buf_addr;
+ unsigned buf_offset;
+ unsigned buf_period;
+ unsigned buf_size;
+ unsigned channels;
+ uint8_t revision;
+ uint8_t iec_offset;
+ uint8_t cs[192][8];
+};
+
+static void dw_hdmi_writeb(unsigned long val, void __iomem *ptr)
+{
+ writeb(val, ptr);
+}
+
+static unsigned dw_hdmi_readb(void __iomem *ptr)
+{
+ return readb(ptr);
+}
+
+static void dw_hdmi_writel(unsigned long val, void __iomem *ptr)
+{
+ writeb_relaxed(val, ptr);
+ writeb_relaxed(val >> 8, ptr + 1);
+ writeb_relaxed(val >> 16, ptr + 2);
+ writeb_relaxed(val >> 24, ptr + 3);
+}
+
+/*
+ * Convert to hardware format: The userspace buffer contains IEC958 samples,
+ * with the PCUV bits in bits 31..28 and audio samples in bits 27..4. We
+ * need these to be in bits 27..24, with the IEC B bit in bit 28, and audio
+ * samples in 23..0.
+ *
+ * Default preamble in bits 3..0: 8 = block start, 4 = even 2 = odd
+ *
+ * Ideally, we could do with having the data properly formatted in userspace.
+ */
+static void dw_hdmi_reformat_iec958(struct snd_dw_hdmi *dw,
+ size_t offset, size_t bytes)
+{
+ uint32_t *ptr = dw->buf_base + offset;
+ uint32_t *end = dw->buf_base + offset + bytes;
+
+ do {
+ uint32_t b, sample = *ptr;
+
+ b = (sample & 8) << (28 - 3);
+
+ sample >>= 4;
+
+ *ptr++ = sample | b;
+ } while (ptr < end);
+}
+
+static uint32_t parity(uint32_t sample)
+{
+ sample ^= sample >> 16;
+ sample ^= sample >> 8;
+ sample ^= sample >> 4;
+ sample ^= sample >> 2;
+ sample ^= sample >> 1;
+ return (sample & 1) << 27;
+}
+
+static void dw_hdmi_reformat_s24(struct snd_dw_hdmi *dw,
+ size_t offset, size_t bytes)
+{
+ uint32_t *ptr = dw->buf_base + offset;
+ uint32_t *end = dw->buf_base + offset + bytes;
+
+ do {
+ unsigned i;
+ uint8_t *cs;
+
+ cs = dw->cs[dw->iec_offset++];
+ if (dw->iec_offset >= 192)
+ dw->iec_offset = 0;
+
+ i = dw->channels;
+ do {
+ uint32_t sample = *ptr;
+
+ sample &= ~0xff000000;
+ sample |= *cs++ << 24;
+ sample |= parity(sample & ~0xf8000000);
+
+ *ptr++ = sample;
+ } while (--i);
+ } while (ptr < end);
+}
+
+static void dw_hdmi_create_cs(struct snd_dw_hdmi *dw,
+ struct snd_pcm_runtime *runtime)
+{
+ uint8_t cs[3];
+ unsigned ch, i, j;
+
+ cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE;
+ cs[1] = IEC958_AES1_CON_GENERAL;
+ cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC;
+ cs[3] = IEC958_AES3_CON_CLOCK_1000PPM;
+
+ switch (runtime->rate) {
+ case 32000:
+ cs[3] |= IEC958_AES3_CON_FS_32000;
+ break;
+ case 44100:
+ cs[3] |= IEC958_AES3_CON_FS_44100;
+ break;
+ case 48000:
+ cs[3] |= IEC958_AES3_CON_FS_48000;
+ break;
+ case 88200:
+ cs[3] |= IEC958_AES3_CON_FS_88200;
+ break;
+ case 96000:
+ cs[3] |= IEC958_AES3_CON_FS_96000;
+ break;
+ case 176400:
+ cs[3] |= IEC958_AES3_CON_FS_176400;
+ break;
+ case 192000:
+ cs[3] |= IEC958_AES3_CON_FS_192000;
+ break;
+ }
+
+ memset(dw->cs, 0, sizeof(dw->cs));
+
+ for (ch = 0; ch < 8; ch++) {
+ cs[2] &= ~IEC958_AES2_CON_CHANNEL;
+ cs[2] |= (ch + 1) << 4;
+
+ for (i = 0; i < ARRAY_SIZE(cs); i++) {
+ unsigned c = cs[i];
+
+ for (j = 0; j < 8; j++, c >>= 1)
+ dw->cs[i * 8 + j][ch] = (c & 1) << 2;
+ }
+ }
+ dw->cs[0][0] |= BIT(4);
+}
+
+static void dw_hdmi_start_dma(struct snd_dw_hdmi *dw)
+{
+ unsigned long start, stop;
+
+ start = dw->buf_addr + dw->buf_offset;
+ stop = start + dw->buf_period - 1;
+
+ dw->reformat(dw, dw->buf_offset, dw->buf_period);
+
+ /* Setup the hardware start/stop addresses */
+ dw_hdmi_writel(start, dw->base + HDMI_AHB_DMA_STRADDR0);
+ dw_hdmi_writel(stop, dw->base + HDMI_AHB_DMA_STPADDR0);
+
+ /* Clear all irqs before enabling irqs and starting DMA */
+ dw_hdmi_writeb(HDMI_IH_AHBDMAAUD_STAT0_ALL,
+ dw->base + HDMI_IH_AHBDMAAUD_STAT0);
+ dw_hdmi_writeb(~HDMI_AHB_DMA_DONE, dw->base + HDMI_AHB_DMA_MASK);
+ dw_hdmi_writeb(HDMI_AHB_DMA_START_START, dw->base + HDMI_AHB_DMA_START);
+}
+
+static void dw_hdmi_stop_dma(struct snd_dw_hdmi *dw)
+{
+ dw->substream = NULL;
+
+ /* Disable interrupts before disabling DMA */
+ dw_hdmi_writeb(~0, dw->base + HDMI_AHB_DMA_MASK);
+ dw_hdmi_writeb(HDMI_AHB_DMA_STOP_STOP, dw->base + HDMI_AHB_DMA_STOP);
+}
+
+static irqreturn_t snd_dw_hdmi_irq(int irq, void *data)
+{
+ struct snd_dw_hdmi *dw = data;
+ struct snd_pcm_substream *substream;
+ unsigned stat;
+
+ stat = dw_hdmi_readb(dw->base + HDMI_IH_AHBDMAAUD_STAT0);
+ if (!stat)
+ return IRQ_NONE;
+
+ dw_hdmi_writeb(stat, dw->base + HDMI_IH_AHBDMAAUD_STAT0);
+
+ substream = dw->substream;
+ if (stat & HDMI_IH_AHBDMAAUD_STAT0_DONE && substream) {
+ dw->buf_offset += dw->buf_period;
+ if (dw->buf_offset >= dw->buf_size)
+ dw->buf_offset = 0;
+
+ snd_pcm_period_elapsed(substream);
+ if (dw->substream)
+ dw_hdmi_start_dma(dw);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static struct snd_pcm_hardware dw_hdmi_hw = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID,
+ .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .rates = SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000,
+ .channels_min = 2,
+ .channels_max = 8,
+ .buffer_bytes_max = 64 * 1024,
+ .period_bytes_min = 256,
+ .period_bytes_max = 8192, /* ERR004323: must limit to 8k */
+ .periods_min = 2,
+ .periods_max = 16,
+ .fifo_size = 0,
+};
+
+static int dw_hdmi_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_dw_hdmi *dw = substream->private_data;
+ int ret;
+
+ /* Clear FIFO */
+ dw_hdmi_writeb(HDMI_AHB_DMA_CONF0_SW_FIFO_RST,
+ dw->base + HDMI_AHB_DMA_CONF0);
+
+ /* Configure interrupt polarities */
+ dw_hdmi_writeb(~0, dw->base + HDMI_AHB_DMA_POL);
+ dw_hdmi_writeb(~0, dw->base + HDMI_AHB_DMA_BUFFPOL);
+
+ /* Keep interrupts masked */
+ dw_hdmi_writeb(~0, dw->base + HDMI_AHB_DMA_MASK);
+
+ ret = request_irq(dw->irq, snd_dw_hdmi_irq, IRQF_SHARED,
+ "dw-hdmi-audio", dw);
+ if (ret)
+ return ret;
+
+ /* Un-mute done interrupt */
+ dw_hdmi_writeb(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL &
+ ~HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE,
+ dw->base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
+
+ runtime->hw = dw_hdmi_hw;
+ snd_pcm_limit_hw_rates(runtime);
+
+ return 0;
+}
+
+static int dw_hdmi_close(struct snd_pcm_substream *substream)
+{
+ struct snd_dw_hdmi *dw = substream->private_data;
+
+ /* Mute all interrupts */
+ dw_hdmi_writeb(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL,
+ dw->base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
+
+ free_irq(dw->irq, dw);
+
+ return 0;
+}
+
+static int dw_hdmi_hw_free(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_lib_free_pages(substream);
+}
+
+static int dw_hdmi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ return snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(params));
+}
+
+static int dw_hdmi_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_dw_hdmi *dw = substream->private_data;
+ uint8_t threshold, conf0, conf1;
+
+ /* Setup as per 3.0.5 FSL 4.1.0 BSP */
+ switch (dw->revision) {
+ case 0x0a:
+ conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE |
+ HDMI_AHB_DMA_CONF0_INCR4;
+ if (runtime->channels == 2)
+ threshold = 126;
+ else
+ threshold = 124;
+ break;
+ case 0x1a:
+ conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE |
+ HDMI_AHB_DMA_CONF0_INCR8;
+ threshold = 128;
+ break;
+ default:
+ /* NOTREACHED */
+ return -EINVAL;
+ }
+
+ imx_hdmi_set_sample_rate(dw->hdmi, runtime->rate);
+
+ /* Minimum number of bytes in the fifo. */
+ runtime->hw.fifo_size = threshold * 32;
+
+ conf0 |= HDMI_AHB_DMA_CONF0_EN_HLOCK;
+ conf1 = (1 << runtime->channels) - 1;
+
+ dw_hdmi_writeb(threshold, dw->base + HDMI_AHB_DMA_THRSLD);
+ dw_hdmi_writeb(conf0, dw->base + HDMI_AHB_DMA_CONF0);
+ dw_hdmi_writeb(conf1, dw->base + HDMI_AHB_DMA_CONF1);
+
+ switch (runtime->format) {
+ case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
+ dw->reformat = dw_hdmi_reformat_iec958;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ dw_hdmi_create_cs(dw, runtime);
+ dw->reformat = dw_hdmi_reformat_s24;
+ break;
+ }
+ dw->iec_offset = 0;
+ dw->channels = runtime->channels;
+ dw->buf_base = runtime->dma_area;
+ dw->buf_addr = runtime->dma_addr;
+ dw->buf_period = snd_pcm_lib_period_bytes(substream);
+ dw->buf_size = snd_pcm_lib_buffer_bytes(substream);
+
+ return 0;
+}
+
+static int dw_hdmi_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_dw_hdmi *dw = substream->private_data;
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ dw->buf_offset = 0;
+ dw->substream = substream;
+ dw_hdmi_start_dma(dw);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ dw_hdmi_stop_dma(dw);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static snd_pcm_uframes_t dw_hdmi_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_dw_hdmi *dw = substream->private_data;
+
+ return bytes_to_frames(runtime, dw->buf_offset);
+}
+
+static struct snd_pcm_ops snd_dw_hdmi_ops = {
+ .open = dw_hdmi_open,
+ .close = dw_hdmi_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = dw_hdmi_hw_params,
+ .hw_free = dw_hdmi_hw_free,
+ .prepare = dw_hdmi_prepare,
+ .trigger = dw_hdmi_trigger,
+ .pointer = dw_hdmi_pointer,
+};
+
+int snd_dw_hdmi_probe(struct snd_dw_hdmi **dwp, struct device *dev,
+ void __iomem *base, int irq, struct imx_hdmi *hdmi)
+{
+ struct snd_dw_hdmi *dw;
+ struct snd_card *card;
+ struct snd_pcm *pcm;
+ unsigned revision;
+ int ret;
+
+ dw_hdmi_writeb(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL,
+ base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
+ revision = dw_hdmi_readb(base + HDMI_REVISION_ID);
+ if (revision != 0x0a && revision != 0x1a) {
+ dev_err(dev, "dw-hdmi-audio: unknown revision 0x%02x\n",
+ revision);
+ return -ENXIO;
+ }
+
+ ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, sizeof(struct snd_dw_hdmi), &card);
+ if (ret < 0)
+ return ret;
+
+ snd_card_set_dev(card, dev);
+
+ strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver));
+ strlcpy(card->shortname, "DW-HDMI", sizeof(card->shortname));
+ snprintf(card->longname, sizeof(card->longname),
+ "%s rev 0x%02x, irq %d", card->shortname, revision, irq);
+
+ dw = card->private_data;
+ dw->card = card;
+ dw->base = base;
+ dw->irq = irq;
+ dw->hdmi = hdmi;
+ dw->revision = revision;
+
+ ret = snd_pcm_new(card, "DW HDMI", 0, 1, 0, &pcm);
+ if (ret < 0)
+ goto err;
+
+ dw->pcm = pcm;
+ pcm->private_data = dw;
+ strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name));
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_dw_hdmi_ops);
+
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+ NULL, 0, 64 * 1024);
+
+ ret = snd_card_register(card);
+ if (ret < 0)
+ goto err;
+
+ *dwp = dw;
+
+ return 0;
+
+err:
+ snd_card_free(card);
+ return ret;
+}
+
+void snd_dw_hdmi_remove(struct snd_dw_hdmi *dw)
+{
+ snd_card_free(dw->card);
+}
diff --git a/drivers/staging/imx-drm/dw-hdmi-audio.h b/drivers/staging/imx-drm/dw-hdmi-audio.h
new file mode 100644
index 000000000000..82a709c9f612
--- /dev/null
+++ b/drivers/staging/imx-drm/dw-hdmi-audio.h
@@ -0,0 +1,13 @@
+#ifndef DW_HDMI_AUDIO_H
+#define DW_HDMI_AUDIO_H
+
+#include <linux/irqreturn.h>
+
+struct snd_dw_hdmi;
+struct imx_hdmi;
+
+int snd_dw_hdmi_probe(struct snd_dw_hdmi **dwp, struct device *,
+ void __iomem *, int, struct imx_hdmi *);
+void snd_dw_hdmi_remove(struct snd_dw_hdmi *dw);
+
+#endif
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index ab16aba7788d..5755368f7454 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -28,6 +28,7 @@
#include <drm/drm_edid.h>
#include <drm/drm_encoder_slave.h>
+#include "dw-hdmi-audio.h"
#include "ipu-v3/imx-ipu-v3.h"
#include "imx-hdmi.h"
#include "imx-drm.h"
@@ -115,6 +116,7 @@ struct imx_hdmi {
struct drm_connector connector;
struct drm_encoder encoder;
+ struct snd_dw_hdmi *audio;
enum imx_hdmi_devtype dev_type;
struct device *dev;
struct clk *isfr_clk;
@@ -362,6 +364,13 @@ static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
}
+void imx_hdmi_set_sample_rate(struct imx_hdmi *hdmi, unsigned int rate)
+{
+ hdmi->sample_rate = rate;
+ hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
+}
+EXPORT_SYMBOL(imx_hdmi_set_sample_rate);
+
/*
* this submodule is responsible for the video data synchronization.
* for example, for RGB 4:4:4 input, the data map is defined as
@@ -1701,10 +1710,20 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
/* Unmute interrupts */
hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
+ ret = snd_dw_hdmi_probe(&hdmi->audio, dev, hdmi->regs, irq, hdmi);
+ if (ret)
+ goto err_audio;
+
dev_set_drvdata(dev, hdmi);
return 0;
+err_audio:
+ /* Disable all interrupts */
+ hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+
+ hdmi->connector.funcs->destroy(&hdmi->connector);
+ hdmi->encoder.funcs->destroy(&hdmi->encoder);
err_iahb:
clk_disable_unprepare(hdmi->iahb_clk);
err_isfr:
@@ -1718,6 +1737,8 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
{
struct imx_hdmi *hdmi = dev_get_drvdata(dev);
+ snd_dw_hdmi_remove(hdmi->audio);
+
/* Disable all interrupts */
hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
diff --git a/drivers/staging/imx-drm/imx-hdmi.h b/drivers/staging/imx-drm/imx-hdmi.h
index 39b677689db6..8029febdbabe 100644
--- a/drivers/staging/imx-drm/imx-hdmi.h
+++ b/drivers/staging/imx-drm/imx-hdmi.h
@@ -1029,4 +1029,8 @@ enum {
HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH = 0x2,
HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0,
};
+
+struct imx_hdmi;
+void imx_hdmi_set_sample_rate(struct imx_hdmi *hdmi, unsigned int rate);
+
#endif /* __IMX_HDMI_H__ */
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 33/34] imx-drm: dw-hdmi-audio: parse ELD from HDMI driver
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (31 preceding siblings ...)
2014-02-18 20:12 ` [PATCH 32/34] imx-drm: dw-hdmi-audio: add audio driver Russell King
@ 2014-02-18 20:12 ` Russell King
2014-02-18 20:12 ` [PATCH 34/34] imx-drm: add CEC " Russell King
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:12 UTC (permalink / raw)
To: linux-arm-kernel
Parse the ELD (EDID like data) stored from the HDMI driver to restrict
the sample rates and channels which are available to ALSA. This causes
the ALSA device to reflect the capabilities of the overall audio path,
not just what is supported at the HDMI source interface level.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/dw-hdmi-audio.c | 51 +++++++++++++++++++++++++++++++++
drivers/staging/imx-drm/imx-hdmi.c | 8 ++++++
drivers/staging/imx-drm/imx-hdmi.h | 1 +
3 files changed, 60 insertions(+)
diff --git a/drivers/staging/imx-drm/dw-hdmi-audio.c b/drivers/staging/imx-drm/dw-hdmi-audio.c
index a17714dfa86d..7bff8c95beec 100644
--- a/drivers/staging/imx-drm/dw-hdmi-audio.c
+++ b/drivers/staging/imx-drm/dw-hdmi-audio.c
@@ -273,6 +273,56 @@ static struct snd_pcm_hardware dw_hdmi_hw = {
.fifo_size = 0,
};
+static unsigned rates_mask[] = {
+ SNDRV_PCM_RATE_32000,
+ SNDRV_PCM_RATE_44100,
+ SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_88200,
+ SNDRV_PCM_RATE_96000,
+ SNDRV_PCM_RATE_176400,
+ SNDRV_PCM_RATE_192000,
+};
+
+static void dw_hdmi_parse_eld(struct snd_dw_hdmi *dw,
+ struct snd_pcm_runtime *runtime)
+{
+ uint8_t *sad, *eld = imx_hdmi_get_eld(dw->hdmi);
+ unsigned eld_ver, mnl, sad_count, rates, rate_mask, i;
+ unsigned max_channels;
+
+ eld_ver = eld[0] >> 3;
+ if (eld_ver != 2 && eld_ver != 31)
+ return;
+
+ mnl = eld[4] & 0x1f;
+ if (mnl > 16)
+ return;
+
+ sad_count = eld[5] >> 4;
+ sad = eld + 20 + mnl;
+
+ /* Start from the basic audio settings */
+ max_channels = 2;
+ rates = 7;
+ while (sad_count > 0) {
+ switch (sad[0] & 0x78) {
+ case 0x08: /* PCM */
+ max_channels = max(max_channels, (sad[0] & 7) + 1u);
+ rates |= sad[1];
+ break;
+ }
+ sad += 3;
+ sad_count -= 1;
+ }
+
+ for (rate_mask = i = 0; i < ARRAY_SIZE(rates_mask); i++)
+ if (rates & 1 << i)
+ rate_mask |= rates_mask[i];
+
+ runtime->hw.rates &= rate_mask;
+ runtime->hw.channels_max = min(runtime->hw.channels_max, max_channels);
+}
+
static int dw_hdmi_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -301,6 +351,7 @@ static int dw_hdmi_open(struct snd_pcm_substream *substream)
dw->base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
runtime->hw = dw_hdmi_hw;
+ dw_hdmi_parse_eld(dw, runtime);
snd_pcm_limit_hw_rates(runtime);
return 0;
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 5755368f7454..df20f94c33e2 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -371,6 +371,12 @@ void imx_hdmi_set_sample_rate(struct imx_hdmi *hdmi, unsigned int rate)
}
EXPORT_SYMBOL(imx_hdmi_set_sample_rate);
+uint8_t *imx_hdmi_get_eld(struct imx_hdmi *hdmi)
+{
+ return hdmi->connector.eld;
+}
+EXPORT_SYMBOL(imx_hdmi_get_eld);
+
/*
* this submodule is responsible for the video data synchronization.
* for example, for RGB 4:4:4 input, the data map is defined as
@@ -1402,6 +1408,8 @@ static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
drm_mode_connector_update_edid_property(connector, edid);
ret = drm_add_edid_modes(connector, edid);
+ /* Store the ELD */
+ drm_edid_to_eld(connector, edid);
kfree(edid);
} else {
dev_dbg(hdmi->dev, "failed to get edid\n");
diff --git a/drivers/staging/imx-drm/imx-hdmi.h b/drivers/staging/imx-drm/imx-hdmi.h
index 8029febdbabe..5baaa9cba943 100644
--- a/drivers/staging/imx-drm/imx-hdmi.h
+++ b/drivers/staging/imx-drm/imx-hdmi.h
@@ -1032,5 +1032,6 @@ enum {
struct imx_hdmi;
void imx_hdmi_set_sample_rate(struct imx_hdmi *hdmi, unsigned int rate);
+uint8_t *imx_hdmi_get_eld(struct imx_hdmi *hdmi);
#endif /* __IMX_HDMI_H__ */
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 34/34] imx-drm: add CEC HDMI driver
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
` (32 preceding siblings ...)
2014-02-18 20:12 ` [PATCH 33/34] imx-drm: dw-hdmi-audio: parse ELD from HDMI driver Russell King
@ 2014-02-18 20:12 ` Russell King
33 siblings, 0 replies; 35+ messages in thread
From: Russell King @ 2014-02-18 20:12 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/staging/imx-drm/Kconfig | 8 +
drivers/staging/imx-drm/Makefile | 1 +
drivers/staging/imx-drm/dw-hdmi-cec.c | 561 ++++++++++++++++++++++++++++++++++
drivers/staging/imx-drm/dw-hdmi-cec.h | 16 +
drivers/staging/imx-drm/imx-hdmi.c | 66 +++-
drivers/staging/imx-drm/imx-hdmi.h | 3 +
6 files changed, 645 insertions(+), 10 deletions(-)
create mode 100644 drivers/staging/imx-drm/dw-hdmi-cec.c
create mode 100644 drivers/staging/imx-drm/dw-hdmi-cec.h
diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig
index 78319ad176cd..8f4c568a6417 100644
--- a/drivers/staging/imx-drm/Kconfig
+++ b/drivers/staging/imx-drm/Kconfig
@@ -59,3 +59,11 @@ config DRM_IMX_HDMI
depends on DRM_IMX
help
Choose this if you want to use HDMI on i.MX6.
+
+config DRM_DW_HDMI_CEC
+ tristate "Synopsis Designware CEC interface"
+ depends on DRM_IMX_HDMI != n
+ help
+ Support the CEC interface which is part of the Synposis
+ Designware HDMI block. This is used in conjunction with
+ the i.MX HDMI driver.
diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index f554aa631993..53bc725d8b08 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/
imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o
obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o
obj-$(CONFIG_DRM_IMX_HDMI) += imxhdmi.o
+obj-$(CONFIG_DRM_DW_HDMI_CEC) += dw-hdmi-cec.o
diff --git a/drivers/staging/imx-drm/dw-hdmi-cec.c b/drivers/staging/imx-drm/dw-hdmi-cec.c
new file mode 100644
index 000000000000..fee508d76457
--- /dev/null
+++ b/drivers/staging/imx-drm/dw-hdmi-cec.c
@@ -0,0 +1,561 @@
+/* http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c?h=imx_3.0.35_4.1.0 */
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+
+#include "imx-hdmi.h"
+#include "dw-hdmi-cec.h"
+
+#define MAX_MESSAGE_LEN 16
+#define DEV_NAME "mxc_hdmi_cec"
+
+enum {
+ CEC_STAT_DONE = BIT(0),
+ CEC_STAT_EOM = BIT(1),
+ CEC_STAT_NACK = BIT(2),
+ CEC_STAT_ARBLOST = BIT(3),
+ CEC_STAT_ERROR_INIT = BIT(4),
+ CEC_STAT_ERROR_FOLL = BIT(5),
+ CEC_STAT_WAKEUP = BIT(6),
+
+ CEC_CTRL_START = BIT(0),
+ CEC_CTRL_NORMAL = 1 << 1,
+};
+
+static struct class *cec_class;
+static int cec_major;
+
+struct dw_hdmi_cec {
+ struct device *dev;
+ struct cdev cdev;
+ void __iomem *base;
+ const struct dw_hdmi_cec_ops *ops;
+ void *ops_data;
+ int irq;
+
+ struct mutex mutex;
+ unsigned users;
+
+ spinlock_t lock;
+ wait_queue_head_t waitq;
+ struct list_head events;
+ uint8_t write_busy;
+
+ uint8_t retries;
+ uint16_t addresses;
+ uint16_t physical;
+};
+
+enum {
+ MESSAGE_TYPE_RECEIVE_SUCCESS = 1,
+ MESSAGE_TYPE_NOACK,
+ MESSAGE_TYPE_DISCONNECTED,
+ MESSAGE_TYPE_CONNECTED,
+ MESSAGE_TYPE_SEND_SUCCESS,
+ MESSAGE_TYPE_SEND_ERROR,
+};
+
+enum {
+ HDMICEC_IOC_MAGIC = 'H',
+ /* This is wrong: we pass the argument as a number, not a pointer */
+ HDMICEC_IOC_O_SETLOGICALADDRESS = _IOW(HDMICEC_IOC_MAGIC, 1, unsigned char),
+ HDMICEC_IOC_SETLOGICALADDRESS = _IO(HDMICEC_IOC_MAGIC, 1),
+ HDMICEC_IOC_STARTDEVICE = _IO(HDMICEC_IOC_MAGIC, 2),
+ HDMICEC_IOC_STOPDEVICE = _IO(HDMICEC_IOC_MAGIC, 3),
+ HDMICEC_IOC_GETPHYADDRESS = _IOR(HDMICEC_IOC_MAGIC, 4, unsigned char[4]),
+};
+
+struct dw_hdmi_cec_user_event {
+ uint32_t event_type;
+ uint32_t msg_len;
+ uint8_t msg[MAX_MESSAGE_LEN];
+};
+
+struct dw_hdmi_cec_event {
+ struct dw_hdmi_cec_user_event usr;
+ struct list_head node;
+};
+
+static void dw_hdmi_event(struct dw_hdmi_cec *cec, int type)
+{
+ struct dw_hdmi_cec_event *event;
+ unsigned long flags;
+
+ event = kzalloc(sizeof(*event), GFP_ATOMIC);
+ if (event) {
+ event->usr.event_type = type;
+
+ if (type == MESSAGE_TYPE_RECEIVE_SUCCESS) {
+ unsigned i;
+
+ event->usr.msg_len = readb(cec->base + HDMI_CEC_RX_CNT);
+
+ for (i = 0; i < event->usr.msg_len; i++)
+ event->usr.msg[i] = readb(cec->base + HDMI_CEC_RX_DATA0 + i);
+
+ writeb(0, cec->base + HDMI_CEC_LOCK);
+ }
+
+ spin_lock_irqsave(&cec->lock, flags);
+ list_add_tail(&event->node, &cec->events);
+ spin_unlock_irqrestore(&cec->lock, flags);
+ wake_up(&cec->waitq);
+ }
+}
+
+static void dw_hdmi_set_address(struct dw_hdmi_cec *cec)
+{
+ writeb(cec->addresses & 255, cec->base + HDMI_CEC_ADDR_L);
+ writeb(cec->addresses >> 8, cec->base + HDMI_CEC_ADDR_H);
+}
+
+static void dw_hdmi_send_message(struct dw_hdmi_cec *cec, uint8_t *msg,
+ size_t count)
+{
+ unsigned long flags;
+ unsigned i;
+
+ for (i = 0; i < count; i++)
+ writeb(msg[i], cec->base + HDMI_CEC_TX_DATA0 + i);
+
+ writeb(count, cec->base + HDMI_CEC_TX_CNT);
+
+ spin_lock_irqsave(&cec->lock, flags);
+ cec->retries = 5;
+ cec->write_busy = 1;
+ writeb(CEC_CTRL_NORMAL | CEC_CTRL_START, cec->base + HDMI_CEC_CTRL);
+ spin_unlock_irqrestore(&cec->lock, flags);
+}
+
+static int dw_hdmi_lock_write(struct dw_hdmi_cec *cec, struct file *file)
+ __acquires(cec->mutex)
+{
+ int ret;
+
+ do {
+ if (file->f_flags & O_NONBLOCK) {
+ if (cec->write_busy)
+ return -EAGAIN;
+ } else {
+ ret = wait_event_interruptible(cec->waitq,
+ !cec->write_busy);
+ if (ret)
+ break;
+ }
+
+ ret = mutex_lock_interruptible(&cec->mutex);
+ if (ret)
+ break;
+
+ if (!cec->write_busy)
+ break;
+
+ mutex_unlock(&cec->mutex);
+ } while (1);
+
+ return ret;
+}
+
+static irqreturn_t dw_hdmi_cec_irq(int irq, void *data)
+{
+ struct dw_hdmi_cec *cec = data;
+ unsigned stat = readb(cec->base + HDMI_IH_CEC_STAT0);
+
+ if (stat == 0)
+ return IRQ_NONE;
+
+ writeb(stat, cec->base + HDMI_IH_CEC_STAT0);
+
+ if (stat & CEC_STAT_ERROR_INIT) {
+ if (cec->retries) {
+ unsigned v = readb(cec->base + HDMI_CEC_CTRL);
+ writeb(v | CEC_CTRL_START, cec->base + HDMI_CEC_CTRL);
+ cec->retries -= 1;
+ } else {
+ cec->write_busy = 0;
+ dw_hdmi_event(cec, MESSAGE_TYPE_SEND_ERROR);
+ }
+ } else if (stat & (CEC_STAT_DONE | CEC_STAT_NACK)) {
+ cec->retries = 0;
+ cec->write_busy = 0;
+ if (stat & CEC_STAT_DONE) {
+ dw_hdmi_event(cec, MESSAGE_TYPE_SEND_SUCCESS);
+ } else {
+ dw_hdmi_event(cec, MESSAGE_TYPE_NOACK);
+ }
+ }
+
+ if (stat & CEC_STAT_EOM)
+ dw_hdmi_event(cec, MESSAGE_TYPE_RECEIVE_SUCCESS);
+
+ return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(dw_hdmi_cec_irq);
+
+static ssize_t dw_hdmi_cec_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct dw_hdmi_cec *cec = file->private_data;
+ ssize_t ret;
+
+ if (count > sizeof(struct dw_hdmi_cec_user_event))
+ count = sizeof(struct dw_hdmi_cec_user_event);
+
+ if (!access_ok(VERIFY_WRITE, buf, count))
+ return -EFAULT;
+
+ do {
+ struct dw_hdmi_cec_event *event = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cec->lock, flags);
+ if (!list_empty(&cec->events)) {
+ event = list_first_entry(&cec->events,
+ struct dw_hdmi_cec_event, node);
+ list_del(&event->node);
+ }
+ spin_unlock_irqrestore(&cec->lock, flags);
+
+ if (event) {
+ ret = __copy_to_user(buf, &event->usr, count) ?
+ -EFAULT : count;
+ kfree(event);
+ break;
+ }
+
+ if (file->f_flags & O_NONBLOCK) {
+ ret = -EAGAIN;
+ break;
+ }
+
+ ret = wait_event_interruptible(cec->waitq,
+ !list_empty(&cec->events));
+ if (ret)
+ break;
+ } while (1);
+
+ return ret;
+}
+
+static ssize_t dw_hdmi_cec_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct dw_hdmi_cec *cec = file->private_data;
+ uint8_t msg[MAX_MESSAGE_LEN];
+ int ret;
+
+ if (count > sizeof(msg))
+ return -E2BIG;
+
+ if (copy_from_user(msg, buf, count))
+ return -EFAULT;
+
+ ret = dw_hdmi_lock_write(cec, file);
+ if (ret)
+ return ret;
+
+ dw_hdmi_send_message(cec, msg, count);
+
+ mutex_unlock(&cec->mutex);
+
+ return count;
+}
+
+static long dw_hdmi_cec_ioctl(struct file *file, u_int cmd, unsigned long arg)
+{
+ struct dw_hdmi_cec *cec = file->private_data;
+ int ret;
+
+ switch (cmd) {
+ case HDMICEC_IOC_O_SETLOGICALADDRESS:
+ case HDMICEC_IOC_SETLOGICALADDRESS:
+ if (arg > 15) {
+ ret = -EINVAL;
+ break;
+ }
+
+ ret = dw_hdmi_lock_write(cec, file);
+ if (ret == 0) {
+ unsigned char msg[1];
+
+ cec->addresses = BIT(arg);
+ dw_hdmi_set_address(cec);
+
+ /*
+ * Send a ping message with the source and destination
+ * set to our address; the result indicates whether
+ * unit has chosen our address simultaneously.
+ */
+ msg[0] = arg << 4 | arg;
+ dw_hdmi_send_message(cec, msg, sizeof(msg));
+ mutex_unlock(&cec->mutex);
+ }
+ break;
+
+ case HDMICEC_IOC_STARTDEVICE:
+ ret = mutex_lock_interruptible(&cec->mutex);
+ if (ret == 0) {
+ cec->addresses = BIT(15);
+ dw_hdmi_set_address(cec);
+ mutex_unlock(&cec->mutex);
+ }
+ break;
+
+ case HDMICEC_IOC_STOPDEVICE:
+ ret = 0;
+ break;
+
+ case HDMICEC_IOC_GETPHYADDRESS:
+ ret = put_user(cec->physical, (uint16_t __user *)arg);
+ ret = -ENOIOCTLCMD;
+ break;
+
+ default:
+ ret = -ENOIOCTLCMD;
+ break;
+ }
+
+ return ret;
+}
+
+static unsigned dw_hdmi_cec_poll(struct file *file, poll_table *wait)
+{
+ struct dw_hdmi_cec *cec = file->private_data;
+ unsigned mask = 0;
+
+ poll_wait(file, &cec->waitq, wait);
+
+ if (cec->write_busy == 0)
+ mask |= POLLOUT | POLLWRNORM;
+ if (!list_empty(&cec->events))
+ mask |= POLLIN | POLLRDNORM;
+
+ return mask;
+}
+
+static int dw_hdmi_cec_open(struct inode *inode, struct file *file)
+{
+ struct dw_hdmi_cec *cec = container_of(inode->i_cdev,
+ struct dw_hdmi_cec, cdev);
+ int ret = 0;
+
+ nonseekable_open(inode, file);
+
+ file->private_data = cec;
+
+ ret = mutex_lock_interruptible(&cec->mutex);
+ if (ret)
+ return ret;
+
+ if (cec->users++ == 0) {
+ unsigned irqs;
+
+ writeb(0, cec->base + HDMI_CEC_CTRL);
+ writeb(~0, cec->base + HDMI_IH_CEC_STAT0);
+ writeb(0, cec->base + HDMI_CEC_LOCK);
+
+ ret = request_irq(cec->irq, dw_hdmi_cec_irq, IRQF_SHARED,
+ DEV_NAME, cec);
+ if (ret < 0) {
+ cec->users = 0;
+ goto unlock;
+ }
+
+ cec->addresses = BIT(15);
+ dw_hdmi_set_address(cec);
+
+ cec->ops->enable(cec->ops_data);
+
+ irqs = CEC_STAT_ERROR_INIT | CEC_STAT_NACK | CEC_STAT_EOM |
+ CEC_STAT_DONE;
+ writeb(irqs, cec->base + HDMI_CEC_POLARITY);
+ writeb(~irqs, cec->base + HDMI_CEC_MASK);
+ writeb(~irqs, cec->base + HDMI_IH_MUTE_CEC_STAT0);
+ }
+ unlock:
+ mutex_unlock(&cec->mutex);
+
+ return ret;
+}
+
+static int dw_hdmi_cec_release(struct inode *inode, struct file *file)
+{
+ struct dw_hdmi_cec *cec = file->private_data;
+
+ mutex_lock(&cec->mutex);
+ if (cec->users >= 1)
+ cec->users -= 1;
+ if (cec->users == 0) {
+ /*
+ * Wait for any write to complete before shutting down.
+ * A message should complete in a maximum of 2.75ms *
+ * 160 bits + 4.7ms, or 444.7ms. Let's call that 500ms.
+ * If we time out, shutdown anyway.
+ */
+ wait_event_timeout(cec->waitq, !cec->write_busy,
+ msecs_to_jiffies(500));
+
+ writeb(~0, cec->base + HDMI_CEC_MASK);
+ writeb(~0, cec->base + HDMI_IH_MUTE_CEC_STAT0);
+ writeb(0, cec->base + HDMI_CEC_POLARITY);
+
+ free_irq(cec->irq, cec);
+
+ cec->ops->disable(cec->ops_data);
+
+ while (!list_empty(&cec->events)) {
+ struct dw_hdmi_cec_event *event;
+
+ event = list_first_entry(&cec->events,
+ struct dw_hdmi_cec_event, node);
+ list_del(&event->node);
+ kfree(event);
+ }
+ }
+ mutex_unlock(&cec->mutex);
+ return 0;
+}
+
+static const struct file_operations hdmi_cec_fops = {
+ .owner = THIS_MODULE,
+ .read = dw_hdmi_cec_read,
+ .write = dw_hdmi_cec_write,
+ .open = dw_hdmi_cec_open,
+ .unlocked_ioctl = dw_hdmi_cec_ioctl,
+ .release = dw_hdmi_cec_release,
+ .poll = dw_hdmi_cec_poll,
+};
+
+static int dw_hdmi_cec_probe(struct platform_device *pdev)
+{
+ struct dw_hdmi_cec_data *data = dev_get_platdata(&pdev->dev);
+ struct dw_hdmi_cec *cec;
+ struct device *cd;
+ dev_t devn = MKDEV(cec_major, 0);
+ int ret;
+
+ if (!data)
+ return -ENXIO;
+
+ cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL);
+ if (!cec)
+ return -ENOMEM;
+
+ cec->dev = &pdev->dev;
+ cec->base = data->base;
+ cec->irq = data->irq;
+ cec->ops = data->ops;
+ cec->ops_data = data->ops_data;
+
+ INIT_LIST_HEAD(&cec->events);
+ init_waitqueue_head(&cec->waitq);
+ spin_lock_init(&cec->lock);
+ mutex_init(&cec->mutex);
+
+ /* FIXME: soft-reset the CEC interface */
+
+ cec->addresses = BIT(15);
+ dw_hdmi_set_address(cec);
+ writeb(0, cec->base + HDMI_CEC_TX_CNT);
+ writeb(~0, cec->base + HDMI_CEC_MASK);
+ writeb(~0, cec->base + HDMI_IH_MUTE_CEC_STAT0);
+ writeb(0, cec->base + HDMI_CEC_POLARITY);
+
+ cdev_init(&cec->cdev, &hdmi_cec_fops);
+ cec->cdev.owner = THIS_MODULE;
+ ret = cdev_add(&cec->cdev, devn, 1);
+ if (ret < 0)
+ goto err_cdev;
+
+ cd = device_create(cec_class, cec->dev, devn, NULL, DEV_NAME);
+ if (IS_ERR(cd)) {
+ ret = PTR_ERR(cd);
+ dev_err(cec->dev, "can't create device: %d\n", ret);
+ goto err_dev;
+ }
+
+ return 0;
+
+ err_dev:
+ cdev_del(&cec->cdev);
+ err_cdev:
+ return ret;
+}
+
+static int dw_hdmi_cec_remove(struct platform_device *pdev)
+{
+ struct dw_hdmi_cec *cec = platform_get_drvdata(pdev);
+ dev_t devn = MKDEV(cec_major, 0);
+
+ device_destroy(cec_class, devn);
+ cdev_del(&cec->cdev);
+
+ return 0;
+}
+
+static struct platform_driver dw_hdmi_cec_driver = {
+ .probe = dw_hdmi_cec_probe,
+ .remove = dw_hdmi_cec_remove,
+ .driver = {
+ .name = "dw-hdmi-cec",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int dw_hdmi_cec_init(void)
+{
+ dev_t dev;
+ int ret;
+
+ cec_class = class_create(THIS_MODULE, DEV_NAME);
+ if (IS_ERR(cec_class)) {
+ ret = PTR_ERR(cec_class);
+ pr_err("cec: can't create cec class: %d\n", ret);
+ goto err_class;
+ }
+
+ ret = alloc_chrdev_region(&dev, 0, 1, DEV_NAME);
+ if (ret) {
+ pr_err("cec: can't create character devices: %d\n", ret);
+ goto err_chrdev;
+ }
+
+ cec_major = MAJOR(dev);
+
+ ret = platform_driver_register(&dw_hdmi_cec_driver);
+ if (ret)
+ goto err_driver;
+
+ return 0;
+
+ err_driver:
+ unregister_chrdev_region(MKDEV(cec_major, 0), 1);
+ err_chrdev:
+ class_destroy(cec_class);
+ err_class:
+ return ret;
+}
+module_init(dw_hdmi_cec_init);
+
+static void dw_hdmi_cec_exit(void)
+{
+ platform_driver_unregister(&dw_hdmi_cec_driver);
+ unregister_chrdev_region(MKDEV(cec_major, 0), 1);
+ class_destroy(cec_class);
+}
+module_exit(dw_hdmi_cec_exit);
+
+MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
+MODULE_DESCRIPTION("Synopsis Designware HDMI CEC driver for i.MX");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS(PLATFORM_MODULE_PREFIX "dw-hdmi-cec");
diff --git a/drivers/staging/imx-drm/dw-hdmi-cec.h b/drivers/staging/imx-drm/dw-hdmi-cec.h
new file mode 100644
index 000000000000..5ff40cc237a8
--- /dev/null
+++ b/drivers/staging/imx-drm/dw-hdmi-cec.h
@@ -0,0 +1,16 @@
+#ifndef DW_HDMI_CEC_H
+#define DW_HDMI_CEC_H
+
+struct dw_hdmi_cec_ops {
+ void (*enable)(void *);
+ void (*disable)(void *);
+};
+
+struct dw_hdmi_cec_data {
+ void __iomem *base;
+ int irq;
+ const struct dw_hdmi_cec_ops *ops;
+ void *ops_data;
+};
+
+#endif
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index df20f94c33e2..60219136dd3a 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -29,6 +29,7 @@
#include <drm/drm_encoder_slave.h>
#include "dw-hdmi-audio.h"
+#include "dw-hdmi-cec.h"
#include "ipu-v3/imx-ipu-v3.h"
#include "imx-hdmi.h"
#include "imx-drm.h"
@@ -116,6 +117,7 @@ struct imx_hdmi {
struct drm_connector connector;
struct drm_encoder encoder;
+ struct platform_device *cec;
struct snd_dw_hdmi *audio;
enum imx_hdmi_devtype dev_type;
struct device *dev;
@@ -128,6 +130,7 @@ struct imx_hdmi {
int vic;
u8 edid[HDMI_EDID_LEN];
+ u8 mc_clkdis;
bool cable_plugin;
bool phy_enabled;
@@ -1154,8 +1157,6 @@ static void imx_hdmi_phy_disable(struct imx_hdmi *hdmi)
/* HDMI Initialization Step B.4 */
static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
{
- u8 clkdis;
-
/* control period minimum duration */
hdmi_writeb(hdmi, 12, HDMI_FC_CTRLDUR);
hdmi_writeb(hdmi, 32, HDMI_FC_EXCTRLDUR);
@@ -1167,23 +1168,28 @@ static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
hdmi_writeb(hdmi, 0x21, HDMI_FC_CH2PREAM);
/* Enable pixel clock and tmds data path */
- clkdis = 0x7F;
- clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
- hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+ hdmi->mc_clkdis |= HDMI_MC_CLKDIS_HDCPCLK_DISABLE |
+ HDMI_MC_CLKDIS_CSCCLK_DISABLE |
+ HDMI_MC_CLKDIS_AUDCLK_DISABLE |
+ HDMI_MC_CLKDIS_PREPCLK_DISABLE |
+ HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
+ hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
+ hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
- clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
- hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+ hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
+ hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
/* Enable csc path */
if (is_color_space_conversion(hdmi)) {
- clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
- hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+ hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
+ hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
}
}
static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi)
{
- hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
+ hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE;
+ hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
}
/* Workaround to clear the overflow condition */
@@ -1578,6 +1584,27 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
return 0;
}
+static void imx_hdmi_cec_enable(void *data)
+{
+ struct imx_hdmi *hdmi = data;
+
+ hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_CECCLK_DISABLE;
+ hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
+}
+
+static void imx_hdmi_cec_disable(void *data)
+{
+ struct imx_hdmi *hdmi = data;
+
+ hdmi->mc_clkdis |= HDMI_MC_CLKDIS_CECCLK_DISABLE;
+ hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
+}
+
+static const struct dw_hdmi_cec_ops imx_hdmi_cec_ops = {
+ .enable = imx_hdmi_cec_enable,
+ .disable = imx_hdmi_cec_disable,
+};
+
static struct platform_device_id imx_hdmi_devtype[] = {
{
.name = "imx6q-hdmi",
@@ -1599,11 +1626,13 @@ MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
+ struct platform_device_info pdevinfo;
const struct of_device_id *of_id =
of_match_device(imx_hdmi_dt_ids, dev);
struct drm_device *drm = data;
struct device_node *np = dev->of_node;
struct device_node *ddc_node;
+ struct dw_hdmi_cec_data cec;
struct imx_hdmi *hdmi;
struct resource *iores;
int ret, irq;
@@ -1616,6 +1645,7 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
hdmi->connector_status = connector_status_disconnected;
hdmi->sample_rate = 48000;
hdmi->ratio = 100;
+ hdmi->mc_clkdis = 0x7f;
if (of_id) {
const struct platform_device_id *device_id = of_id->data;
@@ -1722,6 +1752,20 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
if (ret)
goto err_audio;
+ cec.base = hdmi->regs;
+ cec.irq = irq;
+ cec.ops = &imx_hdmi_cec_ops;
+ cec.ops_data = hdmi;
+
+ memset(&pdevinfo, 0, sizeof(pdevinfo));
+ pdevinfo.parent = dev;
+ pdevinfo.name = "dw-hdmi-cec";
+ pdevinfo.id = PLATFORM_DEVID_AUTO;
+ pdevinfo.data = &cec;
+ pdevinfo.size_data = sizeof(cec);
+
+ hdmi->cec = platform_device_register_full(&pdevinfo);
+
dev_set_drvdata(dev, hdmi);
return 0;
@@ -1745,6 +1789,8 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
{
struct imx_hdmi *hdmi = dev_get_drvdata(dev);
+ if (!IS_ERR(hdmi->cec))
+ platform_device_unregister(hdmi->cec);
snd_dw_hdmi_remove(hdmi->audio);
/* Disable all interrupts */
diff --git a/drivers/staging/imx-drm/imx-hdmi.h b/drivers/staging/imx-drm/imx-hdmi.h
index 5baaa9cba943..3dbd3766d6b3 100644
--- a/drivers/staging/imx-drm/imx-hdmi.h
+++ b/drivers/staging/imx-drm/imx-hdmi.h
@@ -1034,4 +1034,7 @@ struct imx_hdmi;
void imx_hdmi_set_sample_rate(struct imx_hdmi *hdmi, unsigned int rate);
uint8_t *imx_hdmi_get_eld(struct imx_hdmi *hdmi);
+void hdmi_enable_cec(struct imx_hdmi *hdmi);
+void hdmi_disable_cec(struct imx_hdmi *hdmi);
+
#endif /* __IMX_HDMI_H__ */
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
end of thread, other threads:[~2014-02-18 20:12 UTC | newest]
Thread overview: 35+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-02-18 20:09 [PATCH 00/34] imx-drm stuff again Russell King - ARM Linux
2014-02-18 20:09 ` [PATCH 01/34] imx-drm: imx-hdmi: convert HDMI clock settings to tabular form Russell King
2014-02-18 20:09 ` [PATCH 02/34] imx-drm: imx-hdmi: clean up setting CSC registers Russell King
2014-02-18 20:09 ` [PATCH 03/34] imx-drm: imx-hdmi: provide register modification function Russell King
2014-02-18 20:09 ` [PATCH 04/34] imx-drm: imx-hdmi: clean up setting of vp_conf Russell King
2014-02-18 20:10 ` [PATCH 05/34] imx-drm: imx-hdmi: fix CTS/N setup at init time Russell King
2014-02-18 20:10 ` [PATCH 06/34] imx-drm: ipu-v3: more inteligent DI clock selection Russell King
2014-02-18 20:10 ` [PATCH 07/34] imx-drm: ipu-v3: don't use clk_round_rate() before clk_set_rate() Russell King
2014-02-18 20:10 ` [PATCH 08/34] imx-drm: ipu-v3: more clocking fixes Russell King
2014-02-18 20:10 ` [PATCH 09/34] imx-drm: add imx6 DT configuration for HDMI Russell King
2014-02-18 20:10 ` [PATCH 10/34] imx-drm: update and fix imx6 DT descriptions for v3 HDMI driver Russell King
2014-02-18 20:10 ` [PATCH 11/34] imx-drm: imx-drm-core: sanitise imx_drm_encoder_get_mux_id() Russell King
2014-02-18 20:10 ` [PATCH 12/34] imx-drm: imx-drm-core: use array instead of list for CRTCs Russell King
2014-02-18 20:10 ` [PATCH 13/34] imx-drm: provide common connector mode validation function Russell King
2014-02-18 20:10 ` [PATCH 14/34] imx-drm: simplify setup of panel format Russell King
2014-02-18 20:10 ` [PATCH 15/34] imx-drm: convert to componentised device support Russell King
2014-02-18 20:10 ` [PATCH 16/34] imx-drm: imx-hdmi: convert to a component device Russell King
2014-02-18 20:11 ` [PATCH 17/34] imx-drm: delay publishing sysfs connector entries Russell King
2014-02-18 20:11 ` [PATCH 18/34] imx-drm: remove separate imx-fbdev Russell King
2014-02-18 20:11 ` [PATCH 19/34] imx-drm: remove imx-fb.c Russell King
2014-02-18 20:11 ` [PATCH 20/34] imx-drm: use supplied drm_device where possible Russell King
2014-02-18 20:11 ` [PATCH 21/34] imx-drm: imx-drm-core: provide helper function to parse possible crtcs Russell King
2014-02-18 20:11 ` [PATCH 22/34] imx-drm: imx-drm-core: provide common connector and encoder cleanup functions Russell King
2014-02-18 20:11 ` [PATCH 23/34] imx-drm: parallel-display,imx-tve,imx-ldb: initialise drm components directly Russell King
2014-02-18 20:11 ` [PATCH 24/34] imx-drm: imx-hdmi: " Russell King
2014-02-18 20:11 ` [PATCH 25/34] imx-drm: imx-drm-core: remove imx_drm_connector and imx_drm_encoder code Russell King
2014-02-18 20:11 ` [PATCH 26/34] imx-drm: imx-drm-core: get rid of drm_mode_group_init_legacy_group() Russell King
2014-02-18 20:11 ` [PATCH 27/34] imx-drm: imx-drm-core: kill off mutex Russell King
2014-02-18 20:12 ` [PATCH 28/34] imx-drm: imx-drm-core: move allocation of imxdrm device to driver load function Russell King
2014-02-18 20:12 ` [PATCH 29/34] imx-drm: imx-drm-core: various cleanups Russell King
2014-02-18 20:12 ` [PATCH 30/34] imx-drm: imx-drm-core: add core hotplug connector support Russell King
2014-02-18 20:12 ` [PATCH 31/34] imx-drm: imx-hdmi: add hotplug support to HDMI component Russell King
2014-02-18 20:12 ` [PATCH 32/34] imx-drm: dw-hdmi-audio: add audio driver Russell King
2014-02-18 20:12 ` [PATCH 33/34] imx-drm: dw-hdmi-audio: parse ELD from HDMI driver Russell King
2014-02-18 20:12 ` [PATCH 34/34] imx-drm: add CEC " Russell King
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).