From e68d547b8ae109c7ecaaaad665c8de8373a215bc Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 25 Sep 2015 14:48:14 +0200 Subject: [PATCH 01/34] drm/exynos/hdmi: remove support for deprecated compatible This compatible was marked as deprecated in Jun 2013 and it is not used since then. Additionally its driver data points to wrong pll settings, so it cannot work anyway. Signed-off-by: Andrzej Hajda Reviewed-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 932f7fa240f8..c25b89203432 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -507,13 +507,6 @@ static struct hdmi_driver_data exynos4210_hdmi_driver_data = { .is_apb_phy = 0, }; -static struct hdmi_driver_data exynos5_hdmi_driver_data = { - .type = HDMI_TYPE14, - .phy_confs = hdmiphy_v13_configs, - .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs), - .is_apb_phy = 0, -}; - static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id) { return readl(hdata->regs + reg_id); @@ -1909,9 +1902,6 @@ static int hdmi_resources_init(struct hdmi_context *hdata) static struct of_device_id hdmi_match_types[] = { { - .compatible = "samsung,exynos5-hdmi", - .data = &exynos5_hdmi_driver_data, - }, { .compatible = "samsung,exynos4210-hdmi", .data = &exynos4210_hdmi_driver_data, }, { From 633d00b327c0ef5ec0113e27d2d5e36073ebca7d Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 25 Sep 2015 14:48:16 +0200 Subject: [PATCH 02/34] drm/exynos/hdmi: use mappings for registers with IP dependent address Some registers resides at different offsets depending on device version. This patch adds infrastructure for mapping such registers to proper address based on hdmi_type. It adds also mappings to some registers. Signed-off-by: Andrzej Hajda Reviewed-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 56 ++++++++++++++++++---------- drivers/gpu/drm/exynos/regs-hdmi.h | 4 +- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index c25b89203432..622180317aca 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -66,6 +66,21 @@ enum hdmi_type { HDMI_TYPE13, HDMI_TYPE14, + HDMI_TYPE_COUNT +}; + +#define HDMI_MAPPED_BASE 0xffff0000 + +enum hdmi_mapped_regs { + HDMI_PHY_STATUS = HDMI_MAPPED_BASE, + HDMI_PHY_RSTOUT, + HDMI_ACR_CON, +}; + +static const u32 hdmi_reg_map[][HDMI_TYPE_COUNT] = { + { HDMI_V13_PHY_STATUS, HDMI_PHY_STATUS_0 }, + { HDMI_V13_PHY_RSTOUT, HDMI_V14_PHY_RSTOUT }, + { HDMI_V13_ACR_CON, HDMI_V14_ACR_CON }, }; struct hdmi_driver_data { @@ -507,20 +522,29 @@ static struct hdmi_driver_data exynos4210_hdmi_driver_data = { .is_apb_phy = 0, }; +static inline u32 hdmi_map_reg(struct hdmi_context *hdata, u32 reg_id) +{ + if ((reg_id & 0xffff0000) == HDMI_MAPPED_BASE) + return hdmi_reg_map[reg_id & 0xffff][hdata->drv_data->type]; + return reg_id; +} + static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id) { - return readl(hdata->regs + reg_id); + return readl(hdata->regs + hdmi_map_reg(hdata, reg_id)); } static inline void hdmi_reg_writeb(struct hdmi_context *hdata, u32 reg_id, u8 value) { - writeb(value, hdata->regs + reg_id); + writeb(value, hdata->regs + hdmi_map_reg(hdata, reg_id)); } static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id, int bytes, u32 val) { + reg_id = hdmi_map_reg(hdata, reg_id); + while (--bytes >= 0) { writeb(val & 0xff, hdata->regs + reg_id); val >>= 8; @@ -531,7 +555,10 @@ static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id, static inline void hdmi_reg_writemask(struct hdmi_context *hdata, u32 reg_id, u32 value, u32 mask) { - u32 old = readl(hdata->regs + reg_id); + u32 old; + + reg_id = hdmi_map_reg(hdata, reg_id); + old = readl(hdata->regs + reg_id); value = (value & mask) | (old & ~mask); writel(value, hdata->regs + reg_id); } @@ -682,7 +709,7 @@ static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix) DUMPREG(HDMI_PHY_STATUS_0); DUMPREG(HDMI_PHY_STATUS_PLL); DUMPREG(HDMI_PHY_CON_0); - DUMPREG(HDMI_PHY_RSTOUT); + DUMPREG(HDMI_V14_PHY_RSTOUT); DUMPREG(HDMI_PHY_VPLL); DUMPREG(HDMI_PHY_CMU); DUMPREG(HDMI_CORE_RSTOUT); @@ -1162,11 +1189,7 @@ static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr) hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]); hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]); hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]); - - if (hdata->drv_data->type == HDMI_TYPE13) - hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4); - else - hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4); + hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4); } static void hdmi_audio_init(struct hdmi_context *hdata) @@ -1421,7 +1444,7 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata) /* waiting for HDMIPHY's PLL to get to steady state */ for (tries = 100; tries; --tries) { - u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS); + u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS); if (val & HDMI_PHY_STATUS_READY) break; usleep_range(1000, 2000); @@ -1558,7 +1581,7 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata) /* waiting for HDMIPHY's PLL to get to steady state */ for (tries = 100; tries; --tries) { - u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0); + u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS); if (val & HDMI_PHY_STATUS_READY) break; usleep_range(1000, 2000); @@ -1587,8 +1610,6 @@ static void hdmi_mode_apply(struct hdmi_context *hdata) static void hdmiphy_conf_reset(struct hdmi_context *hdata) { - u32 reg; - clk_disable_unprepare(hdata->res.sclk_hdmi); clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel); clk_prepare_enable(hdata->res.sclk_hdmi); @@ -1597,15 +1618,10 @@ static void hdmiphy_conf_reset(struct hdmi_context *hdata) hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE, HDMI_PHY_ENABLE_MODE_SET); - if (hdata->drv_data->type == HDMI_TYPE13) - reg = HDMI_V13_PHY_RSTOUT; - else - reg = HDMI_PHY_RSTOUT; - /* reset hdmiphy */ - hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT); + hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT); usleep_range(10000, 12000); - hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT); + hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT); usleep_range(10000, 12000); } diff --git a/drivers/gpu/drm/exynos/regs-hdmi.h b/drivers/gpu/drm/exynos/regs-hdmi.h index 3f35ac6d8a47..8b2d33794573 100644 --- a/drivers/gpu/drm/exynos/regs-hdmi.h +++ b/drivers/gpu/drm/exynos/regs-hdmi.h @@ -171,7 +171,7 @@ #define HDMI_HPD_ST HDMI_CTRL_BASE(0x0044) #define HDMI_HPD_TH_X HDMI_CTRL_BASE(0x0050) #define HDMI_AUDIO_CLKSEL HDMI_CTRL_BASE(0x0070) -#define HDMI_PHY_RSTOUT HDMI_CTRL_BASE(0x0074) +#define HDMI_V14_PHY_RSTOUT HDMI_CTRL_BASE(0x0074) #define HDMI_PHY_VPLL HDMI_CTRL_BASE(0x0078) #define HDMI_PHY_CMU HDMI_CTRL_BASE(0x007C) #define HDMI_CORE_RSTOUT HDMI_CTRL_BASE(0x0080) @@ -277,7 +277,7 @@ #define HDMI_ASP_CHCFG2 HDMI_CORE_BASE(0x0318) #define HDMI_ASP_CHCFG3 HDMI_CORE_BASE(0x031C) -#define HDMI_ACR_CON HDMI_CORE_BASE(0x0400) +#define HDMI_V14_ACR_CON HDMI_CORE_BASE(0x0400) #define HDMI_ACR_MCTS0 HDMI_CORE_BASE(0x0410) #define HDMI_ACR_MCTS1 HDMI_CORE_BASE(0x0414) #define HDMI_ACR_MCTS2 HDMI_CORE_BASE(0x0418) From 8eb6d4ec99bf4c5004d4b87f4f9dc539b708bdb1 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 25 Sep 2015 14:48:17 +0200 Subject: [PATCH 03/34] drm/exynos/hdmi: move PLL stabilization check code to separate function The patch moves PLL stabilization check to separate function, adjust timeout parameters and de-duplicates code common for both HW variants. Signed-off-by: Andrzej Hajda Reviewed-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 68 +++++++++++----------------- 1 file changed, 26 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 622180317aca..414ea2d9da67 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -1351,11 +1351,27 @@ static void hdmi_conf_init(struct hdmi_context *hdata) } } +static void hdmiphy_wait_for_pll(struct hdmi_context *hdata) +{ + int tries; + + for (tries = 0; tries < 10; ++tries) { + u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS); + + if (val & HDMI_PHY_STATUS_READY) { + DRM_DEBUG_KMS("PLL stabilized after %d tries\n", tries); + return; + } + usleep_range(10, 20); + } + + DRM_ERROR("PLL could not reach steady state\n"); +} + static void hdmi_v13_mode_apply(struct hdmi_context *hdata) { struct drm_display_mode *m = &hdata->current_mode; unsigned int val; - int tries; hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay); hdmi_reg_writev(hdata, HDMI_V13_H_V_LINE_0, 3, @@ -1441,32 +1457,11 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata) hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233); hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1); hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233); - - /* waiting for HDMIPHY's PLL to get to steady state */ - for (tries = 100; tries; --tries) { - u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS); - if (val & HDMI_PHY_STATUS_READY) - break; - usleep_range(1000, 2000); - } - /* steady state not achieved */ - if (tries == 0) { - DRM_ERROR("hdmiphy's pll could not reach steady state.\n"); - hdmi_regs_dump(hdata, "timing apply"); - } - - clk_disable_unprepare(hdata->res.sclk_hdmi); - clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy); - clk_prepare_enable(hdata->res.sclk_hdmi); - - /* enable HDMI and timing generator */ - hdmi_start(hdata, true); } static void hdmi_v14_mode_apply(struct hdmi_context *hdata) { struct drm_display_mode *m = &hdata->current_mode; - int tries; hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay); hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal); @@ -1578,26 +1573,6 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata) hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1); hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1); hdmi_reg_writev(hdata, HDMI_TG_3D, 1, 0x0); - - /* waiting for HDMIPHY's PLL to get to steady state */ - for (tries = 100; tries; --tries) { - u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS); - if (val & HDMI_PHY_STATUS_READY) - break; - usleep_range(1000, 2000); - } - /* steady state not achieved */ - if (tries == 0) { - DRM_ERROR("hdmiphy's pll could not reach steady state.\n"); - hdmi_regs_dump(hdata, "timing apply"); - } - - clk_disable_unprepare(hdata->res.sclk_hdmi); - clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy); - clk_prepare_enable(hdata->res.sclk_hdmi); - - /* enable HDMI and timing generator */ - hdmi_start(hdata, true); } static void hdmi_mode_apply(struct hdmi_context *hdata) @@ -1606,6 +1581,15 @@ static void hdmi_mode_apply(struct hdmi_context *hdata) hdmi_v13_mode_apply(hdata); else hdmi_v14_mode_apply(hdata); + + hdmiphy_wait_for_pll(hdata); + + clk_disable_unprepare(hdata->res.sclk_hdmi); + clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy); + clk_prepare_enable(hdata->res.sclk_hdmi); + + /* enable HDMI and timing generator */ + hdmi_start(hdata, true); } static void hdmiphy_conf_reset(struct hdmi_context *hdata) From 74a74ff4e6fa55d9bdeba57187c3622a55ec2204 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 25 Sep 2015 14:48:18 +0200 Subject: [PATCH 04/34] drm/exynos/hdmi: simplify HDMI-PHY power sequence Currently driver tries to set specific HDMI-PHY registers in three situations: - before reset, - before power off, - after applying HDMI-PHY configuration. First two cases seems to be unnecessary - register contents will be lost anyway. The third case can be merged with HDMI-PHY configuration by fixing the last byte of configuration data. The patch has been tested with following platforms: - exynos4210-universal_c210, - exynos4412-odroidu3, - exynos5422-odroidxu3. Signed-off-by: Andrzej Hajda Reviewed-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 93 +++------------------------- 1 file changed, 8 insertions(+), 85 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 414ea2d9da67..814dd8c98b32 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -148,7 +148,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40, 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87, 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, - 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00, + 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80, }, }, { @@ -157,7 +157,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = { 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64, 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87, 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, - 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00, + 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80, }, }, { @@ -166,7 +166,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B, 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9, 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, - 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00, + 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x80, }, }, { @@ -175,7 +175,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = { 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40, 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba, 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0, - 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00, + 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x80, }, }, { @@ -184,7 +184,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40, 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba, 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0, - 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00, + 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x80, }, }, }; @@ -214,7 +214,7 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = { 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08, 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80, 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, - 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, }, }, { @@ -277,7 +277,7 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = { 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08, 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80, 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, - 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00, + 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, }, }, { @@ -340,7 +340,7 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = { 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08, 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80, 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, - 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00, + 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80, }, }, }; @@ -563,26 +563,6 @@ static inline void hdmi_reg_writemask(struct hdmi_context *hdata, writel(value, hdata->regs + reg_id); } -static int hdmiphy_reg_writeb(struct hdmi_context *hdata, - u32 reg_offset, u8 value) -{ - if (hdata->hdmiphy_port) { - u8 buffer[2]; - int ret; - - buffer[0] = reg_offset; - buffer[1] = value; - - ret = i2c_master_send(hdata->hdmiphy_port, buffer, 2); - if (ret == 2) - return 0; - return ret; - } else { - writeb(value, hdata->regs_hdmiphy + (reg_offset<<2)); - return 0; - } -} - static int hdmiphy_reg_write_buf(struct hdmi_context *hdata, u32 reg_offset, const u8 *buf, u32 len) { @@ -1598,10 +1578,6 @@ static void hdmiphy_conf_reset(struct hdmi_context *hdata) clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel); clk_prepare_enable(hdata->res.sclk_hdmi); - /* operation mode */ - hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE, - HDMI_PHY_ENABLE_MODE_SET); - /* reset hdmiphy */ hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT); usleep_range(10000, 12000); @@ -1609,48 +1585,6 @@ static void hdmiphy_conf_reset(struct hdmi_context *hdata) usleep_range(10000, 12000); } -static void hdmiphy_poweron(struct hdmi_context *hdata) -{ - if (hdata->drv_data->type != HDMI_TYPE14) - return; - - DRM_DEBUG_KMS("\n"); - - /* For PHY Mode Setting */ - hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE, - HDMI_PHY_ENABLE_MODE_SET); - /* Phy Power On */ - hdmiphy_reg_writeb(hdata, HDMIPHY_POWER, - HDMI_PHY_POWER_ON); - /* For PHY Mode Setting */ - hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE, - HDMI_PHY_DISABLE_MODE_SET); - /* PHY SW Reset */ - hdmiphy_conf_reset(hdata); -} - -static void hdmiphy_poweroff(struct hdmi_context *hdata) -{ - if (hdata->drv_data->type != HDMI_TYPE14) - return; - - DRM_DEBUG_KMS("\n"); - - /* PHY SW Reset */ - hdmiphy_conf_reset(hdata); - /* For PHY Mode Setting */ - hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE, - HDMI_PHY_ENABLE_MODE_SET); - - /* PHY Power Off */ - hdmiphy_reg_writeb(hdata, HDMIPHY_POWER, - HDMI_PHY_POWER_OFF); - - /* For PHY Mode Setting */ - hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE, - HDMI_PHY_DISABLE_MODE_SET); -} - static void hdmiphy_conf_apply(struct hdmi_context *hdata) { int ret; @@ -1671,14 +1605,6 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata) } usleep_range(10000, 12000); - - ret = hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE, - HDMI_PHY_DISABLE_MODE_SET); - if (ret) { - DRM_ERROR("failed to enable hdmiphy\n"); - return; - } - } static void hdmi_conf_apply(struct hdmi_context *hdata) @@ -1736,7 +1662,6 @@ static void hdmi_enable(struct drm_encoder *encoder) clk_prepare_enable(res->hdmi); clk_prepare_enable(res->sclk_hdmi); - hdmiphy_poweron(hdata); hdmi_conf_apply(hdata); } @@ -1767,8 +1692,6 @@ static void hdmi_disable(struct drm_encoder *encoder) /* HDMI System Disable */ hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN); - hdmiphy_poweroff(hdata); - cancel_delayed_work(&hdata->hotplug_work); clk_disable_unprepare(res->sclk_hdmi); From 1993c33942c7518ceeb77117e5f0e20d5ef269df Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 25 Sep 2015 14:48:19 +0200 Subject: [PATCH 05/34] drm/exynos/hdmi: replace all writeb with writel Registers are 32-bit, even if only lower 8-bits are used. Signed-off-by: Andrzej Hajda Reviewed-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 814dd8c98b32..50ced7091c83 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -537,7 +537,7 @@ static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id) static inline void hdmi_reg_writeb(struct hdmi_context *hdata, u32 reg_id, u8 value) { - writeb(value, hdata->regs + hdmi_map_reg(hdata, reg_id)); + writel(value, hdata->regs + hdmi_map_reg(hdata, reg_id)); } static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id, @@ -546,7 +546,7 @@ static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id, reg_id = hdmi_map_reg(hdata, reg_id); while (--bytes >= 0) { - writeb(val & 0xff, hdata->regs + reg_id); + writel(val & 0xff, hdata->regs + reg_id); val >>= 8; reg_id += 4; } @@ -579,7 +579,7 @@ static int hdmiphy_reg_write_buf(struct hdmi_context *hdata, } else { int i; for (i = 0; i < len; i++) - writeb(buf[i], hdata->regs_hdmiphy + + writel(buf[i], hdata->regs_hdmiphy + ((reg_offset + i)<<2)); return 0; } From 2445c4a44f200a3137dbaaa3603f2f095c9fdd45 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 25 Sep 2015 14:48:20 +0200 Subject: [PATCH 06/34] drm/exynos/hdmi: fix removal order DRM device should be destroyed before releasing resources. Signed-off-by: Andrzej Hajda Reviewed-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 50ced7091c83..725ddb58a624 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -2046,15 +2046,17 @@ static int hdmi_remove(struct platform_device *pdev) cancel_delayed_work_sync(&hdata->hotplug_work); + component_del(&pdev->dev, &hdmi_component_ops); + + pm_runtime_disable(&pdev->dev); + if (hdata->res.reg_hdmi_en) regulator_disable(hdata->res.reg_hdmi_en); if (hdata->hdmiphy_port) put_device(&hdata->hdmiphy_port->dev); - put_device(&hdata->ddc_adpt->dev); - pm_runtime_disable(&pdev->dev); - component_del(&pdev->dev, &hdmi_component_ops); + put_device(&hdata->ddc_adpt->dev); return 0; } From 498d5a373ac4aa20d7ad63770f2196922ae2f26c Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 25 Sep 2015 14:48:21 +0200 Subject: [PATCH 07/34] drm/exynos/hdmi: use optional regulator_get for hdmi-en hdmi-en is an optional regulator so it should be better handled by devm_regulator_get_optional call. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 725ddb58a624..841470ca7c77 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -1803,19 +1803,17 @@ static int hdmi_resources_init(struct hdmi_context *hdata) } res->regul_count = ARRAY_SIZE(supply); - res->reg_hdmi_en = devm_regulator_get(dev, "hdmi-en"); - if (IS_ERR(res->reg_hdmi_en) && PTR_ERR(res->reg_hdmi_en) != -ENOENT) { - DRM_ERROR("failed to get hdmi-en regulator\n"); + res->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en"); + + if (PTR_ERR(res->reg_hdmi_en) == -ENODEV) + return 0; + + if (IS_ERR(res->reg_hdmi_en)) return PTR_ERR(res->reg_hdmi_en); - } - if (!IS_ERR(res->reg_hdmi_en)) { - ret = regulator_enable(res->reg_hdmi_en); - if (ret) { - DRM_ERROR("failed to enable hdmi-en regulator\n"); - return ret; - } - } else - res->reg_hdmi_en = NULL; + + ret = regulator_enable(res->reg_hdmi_en); + if (ret) + DRM_ERROR("failed to enable hdmi-en regulator\n"); return ret; fail: @@ -2050,7 +2048,7 @@ static int hdmi_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); - if (hdata->res.reg_hdmi_en) + if (!IS_ERR(hdata->res.reg_hdmi_en)) regulator_disable(hdata->res.reg_hdmi_en); if (hdata->hdmiphy_port) From 1ab739db8ed86ab2815d903c0e53d88a88e315c4 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 25 Sep 2015 14:48:22 +0200 Subject: [PATCH 08/34] drm/exynos/hdmi: use constant size array for regulators Driver always uses the same number of regulators, so there is no point in dynamic allocation. Signed-off-by: Andrzej Hajda Reviewed-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 841470ca7c77..583dd5ee0cb3 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -83,6 +83,12 @@ static const u32 hdmi_reg_map[][HDMI_TYPE_COUNT] = { { HDMI_V13_ACR_CON, HDMI_V14_ACR_CON }, }; +static const char * const supply[] = { + "vdd", + "vdd_osc", + "vdd_pll", +}; + struct hdmi_driver_data { unsigned int type; const struct hdmiphy_config *phy_confs; @@ -96,9 +102,8 @@ struct hdmi_resources { struct clk *sclk_pixel; struct clk *sclk_hdmiphy; struct clk *mout_hdmi; - struct regulator_bulk_data *regul_bulk; + struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)]; struct regulator *reg_hdmi_en; - int regul_count; }; struct hdmi_context { @@ -1652,7 +1657,7 @@ static void hdmi_enable(struct drm_encoder *encoder) pm_runtime_get_sync(hdata->dev); - if (regulator_bulk_enable(res->regul_count, res->regul_bulk)) + if (regulator_bulk_enable(ARRAY_SIZE(supply), res->regul_bulk)) DRM_DEBUG_KMS("failed to enable regulator bulk\n"); /* set pmu hdmiphy control bit to enable hdmiphy */ @@ -1701,7 +1706,7 @@ static void hdmi_disable(struct drm_encoder *encoder) regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL, PMU_HDMI_PHY_ENABLE_BIT, 0); - regulator_bulk_disable(res->regul_count, res->regul_bulk); + regulator_bulk_disable(ARRAY_SIZE(supply), res->regul_bulk); pm_runtime_put_sync(hdata->dev); @@ -1743,11 +1748,6 @@ static int hdmi_resources_init(struct hdmi_context *hdata) { struct device *dev = hdata->dev; struct hdmi_resources *res = &hdata->res; - static char *supply[] = { - "vdd", - "vdd_osc", - "vdd_pll", - }; int i, ret; DRM_DEBUG_KMS("HDMI resource init\n"); @@ -1786,12 +1786,6 @@ static int hdmi_resources_init(struct hdmi_context *hdata) clk_set_parent(res->mout_hdmi, res->sclk_pixel); - res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) * - sizeof(res->regul_bulk[0]), GFP_KERNEL); - if (!res->regul_bulk) { - ret = -ENOMEM; - goto fail; - } for (i = 0; i < ARRAY_SIZE(supply); ++i) { res->regul_bulk[i].supply = supply[i]; res->regul_bulk[i].consumer = NULL; @@ -1801,7 +1795,6 @@ static int hdmi_resources_init(struct hdmi_context *hdata) DRM_ERROR("failed to get regulators\n"); return ret; } - res->regul_count = ARRAY_SIZE(supply); res->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en"); From da5e36ae963b24318e0d6b9f226abb795999106a Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 25 Sep 2015 14:48:23 +0200 Subject: [PATCH 09/34] drm/exynos/hdmi: simplify clock re-parenting Driver tries to disable sclk_hdmi during re-parenting, to avoid possible glitches. It is ineffective as the clock is used also by other devices (mixer). Anyway driver works without disabling sclk_hdmi. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 583dd5ee0cb3..475341f3f9e0 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -1569,9 +1569,7 @@ static void hdmi_mode_apply(struct hdmi_context *hdata) hdmiphy_wait_for_pll(hdata); - clk_disable_unprepare(hdata->res.sclk_hdmi); clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy); - clk_prepare_enable(hdata->res.sclk_hdmi); /* enable HDMI and timing generator */ hdmi_start(hdata, true); @@ -1579,9 +1577,7 @@ static void hdmi_mode_apply(struct hdmi_context *hdata) static void hdmiphy_conf_reset(struct hdmi_context *hdata) { - clk_disable_unprepare(hdata->res.sclk_hdmi); clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel); - clk_prepare_enable(hdata->res.sclk_hdmi); /* reset hdmiphy */ hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT); From 2228b7cda25b79f106411b97bd039ed0b97067a6 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 25 Sep 2015 14:48:24 +0200 Subject: [PATCH 10/34] drm/exynos/hdmi: convert to gpiod API The patch converts API to gpiod and moves initialization code to hdmi_resources_init. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 37 +++++++++++----------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 475341f3f9e0..c0664d53ce2e 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -30,11 +30,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -46,8 +46,6 @@ #include "exynos_drm_crtc.h" #include "exynos_mixer.h" -#include - #define ctx_from_connector(c) container_of(c, struct hdmi_context, connector) #define HOTPLUG_DEBOUNCE_MS 1100 @@ -129,7 +127,7 @@ struct hdmi_context { struct hdmi_resources res; const struct hdmi_driver_data *drv_data; - int hpd_gpio; + struct gpio_desc *hpd_gpio; void __iomem *regs_hdmiphy; struct regmap *pmureg; @@ -949,7 +947,7 @@ static enum drm_connector_status hdmi_detect(struct drm_connector *connector, { struct hdmi_context *hdata = ctx_from_connector(connector); - if (gpio_get_value(hdata->hpd_gpio)) + if (gpiod_get_value(hdata->hpd_gpio)) return connector_status_connected; return connector_status_disconnected; @@ -1748,6 +1746,17 @@ static int hdmi_resources_init(struct hdmi_context *hdata) DRM_DEBUG_KMS("HDMI resource init\n"); + hdata->hpd_gpio = devm_gpiod_get(dev, "hpd", GPIOD_IN); + if (IS_ERR(hdata->hpd_gpio)) { + DRM_ERROR("cannot get hpd gpio property\n"); + return PTR_ERR(hdata->hpd_gpio); + } + + hdata->irq = gpiod_to_irq(hdata->hpd_gpio); + if (hdata->irq < 0) { + DRM_ERROR("failed to get GPIO irq\n"); + return hdata->irq; + } /* get clocks, power */ res->hdmi = devm_clk_get(dev, "hdmi"); if (IS_ERR(res->hdmi)) { @@ -1909,11 +1918,6 @@ static int hdmi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, hdata); hdata->dev = dev; - hdata->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpio", 0); - if (hdata->hpd_gpio < 0) { - DRM_ERROR("cannot get hpd gpio property\n"); - return hdata->hpd_gpio; - } ret = hdmi_resources_init(hdata); if (ret) { @@ -1928,12 +1932,6 @@ static int hdmi_probe(struct platform_device *pdev) return ret; } - ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD"); - if (ret) { - DRM_ERROR("failed to request HPD gpio\n"); - return ret; - } - ddc_node = hdmi_legacy_ddc_dt_binding(dev); if (ddc_node) goto out_get_ddc_adpt; @@ -1981,13 +1979,6 @@ static int hdmi_probe(struct platform_device *pdev) } } - hdata->irq = gpio_to_irq(hdata->hpd_gpio); - if (hdata->irq < 0) { - DRM_ERROR("failed to get GPIO irq\n"); - ret = hdata->irq; - goto err_hdmiphy; - } - INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func); ret = devm_request_threaded_irq(dev, hdata->irq, NULL, From af1f7c24d619f2c21f7f6cbac140ef469840e6d3 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 25 Sep 2015 14:48:25 +0200 Subject: [PATCH 11/34] drm/exynos/hdmi: remove deprecated hdmi_resources structure hdmi_resources structure was filled by old platform data code and is not necessary anymore. The patch removes it at groups together resource related fields in hdmi_context. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 105 ++++++++++++--------------- 1 file changed, 46 insertions(+), 59 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index c0664d53ce2e..0d538d3cc38e 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -94,16 +94,6 @@ struct hdmi_driver_data { unsigned int is_apb_phy:1; }; -struct hdmi_resources { - struct clk *hdmi; - struct clk *sclk_hdmi; - struct clk *sclk_pixel; - struct clk *sclk_hdmiphy; - struct clk *mout_hdmi; - struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)]; - struct regulator *reg_hdmi_en; -}; - struct hdmi_context { struct drm_encoder encoder; struct device *dev; @@ -112,25 +102,25 @@ struct hdmi_context { bool hpd; bool powered; bool dvi_mode; - - void __iomem *regs; - int irq; struct delayed_work hotplug_work; - - struct i2c_adapter *ddc_adpt; - struct i2c_client *hdmiphy_port; - - /* current hdmiphy conf regs */ struct drm_display_mode current_mode; u8 cea_video_id; - - struct hdmi_resources res; const struct hdmi_driver_data *drv_data; - struct gpio_desc *hpd_gpio; + void __iomem *regs; void __iomem *regs_hdmiphy; - + struct i2c_client *hdmiphy_port; + struct i2c_adapter *ddc_adpt; + struct gpio_desc *hpd_gpio; + int irq; struct regmap *pmureg; + struct clk *hdmi; + struct clk *sclk_hdmi; + struct clk *sclk_pixel; + struct clk *sclk_hdmiphy; + struct clk *mout_hdmi; + struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)]; + struct regulator *reg_hdmi_en; }; static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e) @@ -1567,7 +1557,7 @@ static void hdmi_mode_apply(struct hdmi_context *hdata) hdmiphy_wait_for_pll(hdata); - clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy); + clk_set_parent(hdata->mout_hdmi, hdata->sclk_hdmiphy); /* enable HDMI and timing generator */ hdmi_start(hdata, true); @@ -1575,7 +1565,7 @@ static void hdmi_mode_apply(struct hdmi_context *hdata) static void hdmiphy_conf_reset(struct hdmi_context *hdata) { - clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel); + clk_set_parent(hdata->mout_hdmi, hdata->sclk_pixel); /* reset hdmiphy */ hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT); @@ -1642,7 +1632,6 @@ static void hdmi_mode_set(struct drm_encoder *encoder, static void hdmi_enable(struct drm_encoder *encoder) { struct hdmi_context *hdata = encoder_to_hdmi(encoder); - struct hdmi_resources *res = &hdata->res; if (hdata->powered) return; @@ -1651,15 +1640,15 @@ static void hdmi_enable(struct drm_encoder *encoder) pm_runtime_get_sync(hdata->dev); - if (regulator_bulk_enable(ARRAY_SIZE(supply), res->regul_bulk)) + if (regulator_bulk_enable(ARRAY_SIZE(supply), hdata->regul_bulk)) DRM_DEBUG_KMS("failed to enable regulator bulk\n"); /* set pmu hdmiphy control bit to enable hdmiphy */ regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL, PMU_HDMI_PHY_ENABLE_BIT, 1); - clk_prepare_enable(res->hdmi); - clk_prepare_enable(res->sclk_hdmi); + clk_prepare_enable(hdata->hdmi); + clk_prepare_enable(hdata->sclk_hdmi); hdmi_conf_apply(hdata); } @@ -1667,7 +1656,6 @@ static void hdmi_enable(struct drm_encoder *encoder) static void hdmi_disable(struct drm_encoder *encoder) { struct hdmi_context *hdata = encoder_to_hdmi(encoder); - struct hdmi_resources *res = &hdata->res; struct drm_crtc *crtc = encoder->crtc; const struct drm_crtc_helper_funcs *funcs = NULL; @@ -1693,14 +1681,14 @@ static void hdmi_disable(struct drm_encoder *encoder) cancel_delayed_work(&hdata->hotplug_work); - clk_disable_unprepare(res->sclk_hdmi); - clk_disable_unprepare(res->hdmi); + clk_disable_unprepare(hdata->sclk_hdmi); + clk_disable_unprepare(hdata->hdmi); /* reset pmu hdmiphy control bit to disable hdmiphy */ regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL, PMU_HDMI_PHY_ENABLE_BIT, 0); - regulator_bulk_disable(ARRAY_SIZE(supply), res->regul_bulk); + regulator_bulk_disable(ARRAY_SIZE(supply), hdata->regul_bulk); pm_runtime_put_sync(hdata->dev); @@ -1741,7 +1729,6 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg) static int hdmi_resources_init(struct hdmi_context *hdata) { struct device *dev = hdata->dev; - struct hdmi_resources *res = &hdata->res; int i, ret; DRM_DEBUG_KMS("HDMI resource init\n"); @@ -1758,58 +1745,58 @@ static int hdmi_resources_init(struct hdmi_context *hdata) return hdata->irq; } /* get clocks, power */ - res->hdmi = devm_clk_get(dev, "hdmi"); - if (IS_ERR(res->hdmi)) { + hdata->hdmi = devm_clk_get(dev, "hdmi"); + if (IS_ERR(hdata->hdmi)) { DRM_ERROR("failed to get clock 'hdmi'\n"); - ret = PTR_ERR(res->hdmi); + ret = PTR_ERR(hdata->hdmi); goto fail; } - res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi"); - if (IS_ERR(res->sclk_hdmi)) { + hdata->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi"); + if (IS_ERR(hdata->sclk_hdmi)) { DRM_ERROR("failed to get clock 'sclk_hdmi'\n"); - ret = PTR_ERR(res->sclk_hdmi); + ret = PTR_ERR(hdata->sclk_hdmi); goto fail; } - res->sclk_pixel = devm_clk_get(dev, "sclk_pixel"); - if (IS_ERR(res->sclk_pixel)) { + hdata->sclk_pixel = devm_clk_get(dev, "sclk_pixel"); + if (IS_ERR(hdata->sclk_pixel)) { DRM_ERROR("failed to get clock 'sclk_pixel'\n"); - ret = PTR_ERR(res->sclk_pixel); + ret = PTR_ERR(hdata->sclk_pixel); goto fail; } - res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy"); - if (IS_ERR(res->sclk_hdmiphy)) { + hdata->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy"); + if (IS_ERR(hdata->sclk_hdmiphy)) { DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n"); - ret = PTR_ERR(res->sclk_hdmiphy); + ret = PTR_ERR(hdata->sclk_hdmiphy); goto fail; } - res->mout_hdmi = devm_clk_get(dev, "mout_hdmi"); - if (IS_ERR(res->mout_hdmi)) { + hdata->mout_hdmi = devm_clk_get(dev, "mout_hdmi"); + if (IS_ERR(hdata->mout_hdmi)) { DRM_ERROR("failed to get clock 'mout_hdmi'\n"); - ret = PTR_ERR(res->mout_hdmi); + ret = PTR_ERR(hdata->mout_hdmi); goto fail; } - clk_set_parent(res->mout_hdmi, res->sclk_pixel); + clk_set_parent(hdata->mout_hdmi, hdata->sclk_pixel); for (i = 0; i < ARRAY_SIZE(supply); ++i) { - res->regul_bulk[i].supply = supply[i]; - res->regul_bulk[i].consumer = NULL; + hdata->regul_bulk[i].supply = supply[i]; + hdata->regul_bulk[i].consumer = NULL; } - ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk); + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), hdata->regul_bulk); if (ret) { DRM_ERROR("failed to get regulators\n"); return ret; } - res->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en"); + hdata->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en"); - if (PTR_ERR(res->reg_hdmi_en) == -ENODEV) + if (PTR_ERR(hdata->reg_hdmi_en) == -ENODEV) return 0; - if (IS_ERR(res->reg_hdmi_en)) - return PTR_ERR(res->reg_hdmi_en); + if (IS_ERR(hdata->reg_hdmi_en)) + return PTR_ERR(hdata->reg_hdmi_en); - ret = regulator_enable(res->reg_hdmi_en); + ret = regulator_enable(hdata->reg_hdmi_en); if (ret) DRM_ERROR("failed to enable hdmi-en regulator\n"); @@ -2028,8 +2015,8 @@ static int hdmi_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); - if (!IS_ERR(hdata->res.reg_hdmi_en)) - regulator_disable(hdata->res.reg_hdmi_en); + if (!IS_ERR(hdata->reg_hdmi_en)) + regulator_disable(hdata->reg_hdmi_en); if (hdata->hdmiphy_port) put_device(&hdata->hdmiphy_port->dev); From 185f22d222fb12d571eed43fc6d5d13e27813f05 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 25 Sep 2015 14:48:26 +0200 Subject: [PATCH 12/34] drm/exynos/hdmi: convert container_of macro to inline function Inline function is safer than macro, also the name has been changed to be consistent with other inline function encoder_to_hdmi. Signed-off-by: Andrzej Hajda Reviewed-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 0d538d3cc38e..c5a0617c429d 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -46,8 +46,6 @@ #include "exynos_drm_crtc.h" #include "exynos_mixer.h" -#define ctx_from_connector(c) container_of(c, struct hdmi_context, connector) - #define HOTPLUG_DEBOUNCE_MS 1100 /* AVI header and aspect ratio */ @@ -128,6 +126,11 @@ static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e) return container_of(e, struct hdmi_context, encoder); } +static inline struct hdmi_context *connector_to_hdmi(struct drm_connector *c) +{ + return container_of(c, struct hdmi_context, connector); +} + struct hdmiphy_config { int pixel_clock; u8 conf[32]; @@ -935,7 +938,7 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata, static enum drm_connector_status hdmi_detect(struct drm_connector *connector, bool force) { - struct hdmi_context *hdata = ctx_from_connector(connector); + struct hdmi_context *hdata = connector_to_hdmi(connector); if (gpiod_get_value(hdata->hpd_gpio)) return connector_status_connected; @@ -961,7 +964,7 @@ static struct drm_connector_funcs hdmi_connector_funcs = { static int hdmi_get_modes(struct drm_connector *connector) { - struct hdmi_context *hdata = ctx_from_connector(connector); + struct hdmi_context *hdata = connector_to_hdmi(connector); struct edid *edid; int ret; @@ -1001,7 +1004,7 @@ static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock) static int hdmi_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - struct hdmi_context *hdata = ctx_from_connector(connector); + struct hdmi_context *hdata = connector_to_hdmi(connector); int ret; DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n", @@ -1022,7 +1025,7 @@ static int hdmi_mode_valid(struct drm_connector *connector, static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector) { - struct hdmi_context *hdata = ctx_from_connector(connector); + struct hdmi_context *hdata = connector_to_hdmi(connector); return &hdata->encoder; } From d24bb3e59d3863304f81e71e10c0e9a1ae13c16d Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 25 Sep 2015 14:48:27 +0200 Subject: [PATCH 13/34] drm/exynos/hdmi: improve HDMI/ACR related code Simple formula can be used to calculate CTS and N coefficients. Additionaly ACR registers have different offsets for different versions of IP. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 71 +++++----------------------- drivers/gpu/drm/exynos/regs-hdmi.h | 29 ++++++++---- 2 files changed, 32 insertions(+), 68 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index c5a0617c429d..a4ec8b944610 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -71,12 +71,18 @@ enum hdmi_mapped_regs { HDMI_PHY_STATUS = HDMI_MAPPED_BASE, HDMI_PHY_RSTOUT, HDMI_ACR_CON, + HDMI_ACR_MCTS0, + HDMI_ACR_CTS0, + HDMI_ACR_N0 }; static const u32 hdmi_reg_map[][HDMI_TYPE_COUNT] = { { HDMI_V13_PHY_STATUS, HDMI_PHY_STATUS_0 }, { HDMI_V13_PHY_RSTOUT, HDMI_V14_PHY_RSTOUT }, { HDMI_V13_ACR_CON, HDMI_V14_ACR_CON }, + { HDMI_V13_ACR_MCTS0, HDMI_V14_ACR_MCTS0 }, + { HDMI_V13_ACR_CTS0, HDMI_V14_ACR_CTS0 }, + { HDMI_V13_ACR_N0, HDMI_V14_ACR_N0 }, }; static const char * const supply[] = { @@ -1106,65 +1112,16 @@ static bool hdmi_mode_fixup(struct drm_encoder *encoder, return true; } -static void hdmi_set_acr(u32 freq, u8 *acr) +static void hdmi_reg_acr(struct hdmi_context *hdata, u32 freq) { u32 n, cts; - switch (freq) { - case 32000: - n = 4096; - cts = 27000; - break; - case 44100: - n = 6272; - cts = 30000; - break; - case 88200: - n = 12544; - cts = 30000; - break; - case 176400: - n = 25088; - cts = 30000; - break; - case 48000: - n = 6144; - cts = 27000; - break; - case 96000: - n = 12288; - cts = 27000; - break; - case 192000: - n = 24576; - cts = 27000; - break; - default: - n = 0; - cts = 0; - break; - } + cts = (freq % 9) ? 27000 : 30000; + n = 128 * freq / (27000000 / cts); - acr[1] = cts >> 16; - acr[2] = cts >> 8 & 0xff; - acr[3] = cts & 0xff; - - acr[4] = n >> 16; - acr[5] = n >> 8 & 0xff; - acr[6] = n & 0xff; -} - -static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr) -{ - hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]); - hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]); - hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]); - hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]); - hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]); - hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]); - hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]); - hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]); - hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]); + hdmi_reg_writev(hdata, HDMI_ACR_N0, 3, n); + hdmi_reg_writev(hdata, HDMI_ACR_MCTS0, 3, cts); + hdmi_reg_writev(hdata, HDMI_ACR_CTS0, 3, cts); hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4); } @@ -1173,7 +1130,6 @@ static void hdmi_audio_init(struct hdmi_context *hdata) u32 sample_rate, bits_per_sample; u32 data_num, bit_ch, sample_frq; u32 val; - u8 acr[7]; sample_rate = 44100; bits_per_sample = 16; @@ -1193,8 +1149,7 @@ static void hdmi_audio_init(struct hdmi_context *hdata) break; } - hdmi_set_acr(sample_rate, acr); - hdmi_reg_acr(hdata, acr); + hdmi_reg_acr(hdata, sample_rate); hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE diff --git a/drivers/gpu/drm/exynos/regs-hdmi.h b/drivers/gpu/drm/exynos/regs-hdmi.h index 8b2d33794573..8c891e59be21 100644 --- a/drivers/gpu/drm/exynos/regs-hdmi.h +++ b/drivers/gpu/drm/exynos/regs-hdmi.h @@ -72,7 +72,6 @@ #define HDMI_V13_V_SYNC_GEN_3_0 HDMI_CORE_BASE(0x0150) #define HDMI_V13_V_SYNC_GEN_3_1 HDMI_CORE_BASE(0x0154) #define HDMI_V13_V_SYNC_GEN_3_2 HDMI_CORE_BASE(0x0158) -#define HDMI_V13_ACR_CON HDMI_CORE_BASE(0x0180) #define HDMI_V13_AVI_CON HDMI_CORE_BASE(0x0300) #define HDMI_V13_AVI_BYTE(n) HDMI_CORE_BASE(0x0320 + 4 * (n)) #define HDMI_V13_DC_CONTROL HDMI_CORE_BASE(0x05C0) @@ -277,16 +276,26 @@ #define HDMI_ASP_CHCFG2 HDMI_CORE_BASE(0x0318) #define HDMI_ASP_CHCFG3 HDMI_CORE_BASE(0x031C) +#define HDMI_V13_ACR_CON HDMI_CORE_BASE(0x0180) +#define HDMI_V13_ACR_MCTS0 HDMI_CORE_BASE(0x0184) +#define HDMI_V13_ACR_MCTS1 HDMI_CORE_BASE(0x0188) +#define HDMI_V13_ACR_MCTS2 HDMI_CORE_BASE(0x018C) +#define HDMI_V13_ACR_CTS0 HDMI_CORE_BASE(0x0190) +#define HDMI_V13_ACR_CTS1 HDMI_CORE_BASE(0x0194) +#define HDMI_V13_ACR_CTS2 HDMI_CORE_BASE(0x0198) +#define HDMI_V13_ACR_N0 HDMI_CORE_BASE(0x01A0) +#define HDMI_V13_ACR_N1 HDMI_CORE_BASE(0x01A4) +#define HDMI_V13_ACR_N2 HDMI_CORE_BASE(0x01A8) #define HDMI_V14_ACR_CON HDMI_CORE_BASE(0x0400) -#define HDMI_ACR_MCTS0 HDMI_CORE_BASE(0x0410) -#define HDMI_ACR_MCTS1 HDMI_CORE_BASE(0x0414) -#define HDMI_ACR_MCTS2 HDMI_CORE_BASE(0x0418) -#define HDMI_ACR_CTS0 HDMI_CORE_BASE(0x0420) -#define HDMI_ACR_CTS1 HDMI_CORE_BASE(0x0424) -#define HDMI_ACR_CTS2 HDMI_CORE_BASE(0x0428) -#define HDMI_ACR_N0 HDMI_CORE_BASE(0x0430) -#define HDMI_ACR_N1 HDMI_CORE_BASE(0x0434) -#define HDMI_ACR_N2 HDMI_CORE_BASE(0x0438) +#define HDMI_V14_ACR_MCTS0 HDMI_CORE_BASE(0x0410) +#define HDMI_V14_ACR_MCTS1 HDMI_CORE_BASE(0x0414) +#define HDMI_V14_ACR_MCTS2 HDMI_CORE_BASE(0x0418) +#define HDMI_V14_ACR_CTS0 HDMI_CORE_BASE(0x0420) +#define HDMI_V14_ACR_CTS1 HDMI_CORE_BASE(0x0424) +#define HDMI_V14_ACR_CTS2 HDMI_CORE_BASE(0x0428) +#define HDMI_V14_ACR_N0 HDMI_CORE_BASE(0x0430) +#define HDMI_V14_ACR_N1 HDMI_CORE_BASE(0x0434) +#define HDMI_V14_ACR_N2 HDMI_CORE_BASE(0x0438) /* Packet related registers */ #define HDMI_ACP_CON HDMI_CORE_BASE(0x0500) From cf3e0fdd54f7d792e158cbb87ead1d9e6a5c58f7 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 25 Sep 2015 14:48:28 +0200 Subject: [PATCH 14/34] drm/exynos/hdmi: remove unused field The patch removes unused hdmi_context field. Signed-off-by: Andrzej Hajda Reviewed-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index a4ec8b944610..b0f5ff4e8620 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -103,7 +103,6 @@ struct hdmi_context { struct device *dev; struct drm_device *drm_dev; struct drm_connector connector; - bool hpd; bool powered; bool dvi_mode; struct delayed_work hotplug_work; From 02b3de431111014643c48a326b46d127df061658 Mon Sep 17 00:00:00 2001 From: Tomasz Stanislawski Date: Fri, 25 Sep 2015 14:48:29 +0200 Subject: [PATCH 15/34] drm: exynos: mixer: fix using usleep() in atomic context This patch fixes calling usleep_range() after taking reg_slock using spin_lock_irqsave(). The mdelay() is used instead. Waiting in atomic context is not the best idea in general. Hopefully, waiting occurs only when Video Processor fails to reset correctly. Signed-off-by: Tomasz Stanislawski Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_mixer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 7f81cce966d4..ecf956c7020a 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -652,7 +652,7 @@ static void vp_win_reset(struct mixer_context *ctx) /* waiting until VP_SRESET_PROCESSING is 0 */ if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING) break; - usleep_range(10000, 12000); + mdelay(10); } WARN(tries == 0, "failed to reset Video Processor\n"); } From c691349ca429c3a57487eca857f87d2b2442c359 Mon Sep 17 00:00:00 2001 From: Ingi Kim Date: Fri, 2 Oct 2015 17:59:26 +0900 Subject: [PATCH 16/34] drm/exynos: fix spelling errors This patch fixes spelling errors in drm fimc/gsc inavild -> invaild Signed-off-by: Ingi Kim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fimc.c | 16 ++++++++-------- drivers/gpu/drm/exynos/exynos_drm_gsc.c | 12 ++++++------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c index dd3a5e6d58c8..c747824f3c98 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c @@ -466,7 +466,7 @@ static int fimc_src_set_fmt_order(struct fimc_context *ctx, u32 fmt) EXYNOS_MSCTRL_C_INT_IN_2PLANE); break; default: - dev_err(ippdrv->dev, "inavlid source yuv order 0x%x.\n", fmt); + dev_err(ippdrv->dev, "invalid source yuv order 0x%x.\n", fmt); return -EINVAL; } @@ -513,7 +513,7 @@ static int fimc_src_set_fmt(struct device *dev, u32 fmt) cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR420; break; default: - dev_err(ippdrv->dev, "inavlid source format 0x%x.\n", fmt); + dev_err(ippdrv->dev, "invalid source format 0x%x.\n", fmt); return -EINVAL; } @@ -578,7 +578,7 @@ static int fimc_src_set_transf(struct device *dev, cfg1 &= ~EXYNOS_MSCTRL_FLIP_Y_MIRROR; break; default: - dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree); + dev_err(ippdrv->dev, "invalid degree value %d.\n", degree); return -EINVAL; } @@ -701,7 +701,7 @@ static int fimc_src_set_addr(struct device *dev, property->prop_id, buf_id, buf_type); if (buf_id > FIMC_MAX_SRC) { - dev_info(ippdrv->dev, "inavlid buf_id %d.\n", buf_id); + dev_info(ippdrv->dev, "invalid buf_id %d.\n", buf_id); return -ENOMEM; } @@ -812,7 +812,7 @@ static int fimc_dst_set_fmt_order(struct fimc_context *ctx, u32 fmt) cfg |= EXYNOS_CIOCTRL_YCBCR_2PLANE; break; default: - dev_err(ippdrv->dev, "inavlid target yuv order 0x%x.\n", fmt); + dev_err(ippdrv->dev, "invalid target yuv order 0x%x.\n", fmt); return -EINVAL; } @@ -865,7 +865,7 @@ static int fimc_dst_set_fmt(struct device *dev, u32 fmt) cfg |= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR420; break; default: - dev_err(ippdrv->dev, "inavlid target format 0x%x.\n", + dev_err(ippdrv->dev, "invalid target format 0x%x.\n", fmt); return -EINVAL; } @@ -929,7 +929,7 @@ static int fimc_dst_set_transf(struct device *dev, cfg &= ~EXYNOS_CITRGFMT_FLIP_Y_MIRROR; break; default: - dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree); + dev_err(ippdrv->dev, "invalid degree value %d.\n", degree); return -EINVAL; } @@ -1160,7 +1160,7 @@ static int fimc_dst_set_addr(struct device *dev, property->prop_id, buf_id, buf_type); if (buf_id > FIMC_MAX_DST) { - dev_info(ippdrv->dev, "inavlid buf_id %d.\n", buf_id); + dev_info(ippdrv->dev, "invalid buf_id %d.\n", buf_id); return -ENOMEM; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c index 808a0a013780..11b87d2a7913 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c @@ -543,7 +543,7 @@ static int gsc_src_set_fmt(struct device *dev, u32 fmt) GSC_IN_YUV420_2P); break; default: - dev_err(ippdrv->dev, "inavlid target yuv order 0x%x.\n", fmt); + dev_err(ippdrv->dev, "invalid target yuv order 0x%x.\n", fmt); return -EINVAL; } @@ -595,7 +595,7 @@ static int gsc_src_set_transf(struct device *dev, cfg &= ~GSC_IN_ROT_YFLIP; break; default: - dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree); + dev_err(ippdrv->dev, "invalid degree value %d.\n", degree); return -EINVAL; } @@ -721,7 +721,7 @@ static int gsc_src_set_addr(struct device *dev, property->prop_id, buf_id, buf_type); if (buf_id > GSC_MAX_SRC) { - dev_info(ippdrv->dev, "inavlid buf_id %d.\n", buf_id); + dev_info(ippdrv->dev, "invalid buf_id %d.\n", buf_id); return -EINVAL; } @@ -814,7 +814,7 @@ static int gsc_dst_set_fmt(struct device *dev, u32 fmt) GSC_OUT_YUV420_2P); break; default: - dev_err(ippdrv->dev, "inavlid target yuv order 0x%x.\n", fmt); + dev_err(ippdrv->dev, "invalid target yuv order 0x%x.\n", fmt); return -EINVAL; } @@ -866,7 +866,7 @@ static int gsc_dst_set_transf(struct device *dev, cfg &= ~GSC_IN_ROT_YFLIP; break; default: - dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree); + dev_err(ippdrv->dev, "invalid degree value %d.\n", degree); return -EINVAL; } @@ -1176,7 +1176,7 @@ static int gsc_dst_set_addr(struct device *dev, property->prop_id, buf_id, buf_type); if (buf_id > GSC_MAX_DST) { - dev_info(ippdrv->dev, "inavlid buf_id %d.\n", buf_id); + dev_info(ippdrv->dev, "invalid buf_id %d.\n", buf_id); return -EINVAL; } From 5d3d099574ba6319998ae9275090e42140d6b37a Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 12 Oct 2015 22:07:48 +0900 Subject: [PATCH 17/34] drm/exynos: add global macro for the default primary plane Define DEFAULT_WIN as zero to help set the primary plane on all CRTCs. Some CRTCs were defining a variable to store the default window, but that is not necessary as the default (primary) window is always the window zero. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 6 ++---- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 5 ++--- drivers/gpu/drm/exynos/exynos_drm_drv.h | 2 ++ drivers/gpu/drm/exynos/exynos_drm_fimd.c | 5 ++--- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 6 ++---- drivers/gpu/drm/exynos/exynos_mixer.c | 7 +++---- 6 files changed, 13 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index b3c730770b0f..f467ce05f6cd 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -33,7 +33,6 @@ struct decon_context { struct exynos_drm_plane planes[WINDOWS_NR]; void __iomem *addr; struct clk *clks[6]; - unsigned int default_win; unsigned long irq_flags; int pipe; bool suspended; @@ -501,7 +500,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data) ctx->pipe = priv->pipe++; for (zpos = 0; zpos < WINDOWS_NR; zpos++) { - type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY : + type = (zpos == DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], 1 << ctx->pipe, type, decon_formats, @@ -510,7 +509,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data) return ret; } - exynos_plane = &ctx->planes[ctx->default_win]; + exynos_plane = &ctx->planes[DEFAULT_WIN]; ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD, &decon_crtc_ops, ctx); @@ -607,7 +606,6 @@ static int exynos5433_decon_probe(struct platform_device *pdev) if (!ctx) return -ENOMEM; - ctx->default_win = 0; ctx->suspended = true; ctx->dev = dev; if (of_get_child_by_name(dev->of_node, "i80-if-timings")) diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index e6cbaca821a4..bd0f96bbd3f6 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -51,7 +51,6 @@ struct decon_context { struct clk *eclk; struct clk *vclk; void __iomem *regs; - unsigned int default_win; unsigned long irq_flags; bool i80_if; bool suspended; @@ -690,7 +689,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data) } for (zpos = 0; zpos < WINDOWS_NR; zpos++) { - type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY : + type = (zpos == DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], 1 << ctx->pipe, type, decon_formats, @@ -699,7 +698,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data) return ret; } - exynos_plane = &ctx->planes[ctx->default_win]; + exynos_plane = &ctx->planes[DEFAULT_WIN]; ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD, &decon_crtc_ops, ctx); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 6c717ba672db..638fc43079a8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -22,6 +22,8 @@ #define MAX_PLANE 5 #define MAX_FB_BUFFER 4 +#define DEFAULT_WIN 0 + #define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc, base) #define to_exynos_plane(x) container_of(x, struct exynos_drm_plane, base) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 3d1aba67758b..7505a71c695f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -153,7 +153,6 @@ struct fimd_context { struct clk *lcd_clk; void __iomem *regs; struct regmap *sysreg; - unsigned int default_win; unsigned long irq_flags; u32 vidcon0; u32 vidcon1; @@ -949,7 +948,7 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) ctx->pipe = priv->pipe++; for (zpos = 0; zpos < WINDOWS_NR; zpos++) { - type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY : + type = (zpos == DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], 1 << ctx->pipe, type, fimd_formats, @@ -958,7 +957,7 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) return ret; } - exynos_plane = &ctx->planes[ctx->default_win]; + exynos_plane = &ctx->planes[DEFAULT_WIN]; ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD, &fimd_crtc_ops, ctx); diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 75718e1bc3dd..fc5768779445 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -42,7 +42,6 @@ struct vidi_context { struct exynos_drm_plane planes[WINDOWS_NR]; struct edid *raw_edid; unsigned int clkdiv; - unsigned int default_win; unsigned long irq_flags; unsigned int connected; bool vblank_on; @@ -446,7 +445,7 @@ static int vidi_bind(struct device *dev, struct device *master, void *data) vidi_ctx_initialize(ctx, drm_dev); for (zpos = 0; zpos < WINDOWS_NR; zpos++) { - type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY : + type = (zpos == DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], 1 << ctx->pipe, type, formats, @@ -455,7 +454,7 @@ static int vidi_bind(struct device *dev, struct device *master, void *data) return ret; } - exynos_plane = &ctx->planes[ctx->default_win]; + exynos_plane = &ctx->planes[DEFAULT_WIN]; ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, ctx->pipe, EXYNOS_DISPLAY_TYPE_VIDI, &vidi_crtc_ops, ctx); @@ -507,7 +506,6 @@ static int vidi_probe(struct platform_device *pdev) if (!ctx) return -ENOMEM; - ctx->default_win = 0; ctx->pdev = pdev; INIT_WORK(&ctx->work, vidi_fake_vblank_handler); diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index ecf956c7020a..f83e27da7e09 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -42,7 +42,6 @@ #include "exynos_mixer.h" #define MIXER_WIN_NR 3 -#define MIXER_DEFAULT_WIN 0 #define VP_DEFAULT_WIN 2 /* The pixelformats that are natively supported by the mixer. */ @@ -600,7 +599,7 @@ static void mixer_graph_buffer(struct mixer_context *ctx, /* setup display size */ if (ctx->mxr_ver == MXR_VER_128_0_0_184 && - win == MIXER_DEFAULT_WIN) { + win == DEFAULT_WIN) { val = MXR_MXR_RES_HEIGHT(mode->vdisplay); val |= MXR_MXR_RES_WIDTH(mode->hdisplay); mixer_reg_write(res, MXR_RESOLUTION, val); @@ -1197,7 +1196,7 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data) const uint32_t *formats; unsigned int fcount; - type = (zpos == MIXER_DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY : + type = (zpos == DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; if (zpos < VP_DEFAULT_WIN) { formats = mixer_formats; @@ -1214,7 +1213,7 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data) return ret; } - exynos_plane = &ctx->planes[MIXER_DEFAULT_WIN]; + exynos_plane = &ctx->planes[DEFAULT_WIN]; ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, ctx->pipe, EXYNOS_DISPLAY_TYPE_HDMI, &mixer_crtc_ops, ctx); From 323db0ed7de21dff93affd51c4c742a3dec1c103 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Fri, 4 Sep 2015 19:05:57 -0300 Subject: [PATCH 18/34] drm/exynos: add cursor plane support Set one of the planes for each crtc driver as a cursor plane enabled window managers to fully work on exynos. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 4 ++-- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 4 ++-- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 4 ++-- drivers/gpu/drm/exynos/exynos_drm_plane.c | 11 +++++++++++ drivers/gpu/drm/exynos/exynos_drm_plane.h | 2 ++ drivers/gpu/drm/exynos/exynos_drm_vidi.c | 4 ++-- drivers/gpu/drm/exynos/exynos_mixer.c | 4 ++-- 7 files changed, 23 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index f467ce05f6cd..1ea26dbb1119 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -24,6 +24,7 @@ #include "exynos_drm_iommu.h" #define WINDOWS_NR 3 +#define CURSOR_WIN 2 #define MIN_FB_WIDTH_FOR_16WORD_BURST 128 struct decon_context { @@ -500,8 +501,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data) ctx->pipe = priv->pipe++; for (zpos = 0; zpos < WINDOWS_NR; zpos++) { - type = (zpos == DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY : - DRM_PLANE_TYPE_OVERLAY; + type = exynos_plane_get_type(zpos, CURSOR_WIN); ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], 1 << ctx->pipe, type, decon_formats, ARRAY_SIZE(decon_formats), zpos); diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index bd0f96bbd3f6..ead2b16e237d 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -40,6 +40,7 @@ #define MIN_FB_WIDTH_FOR_16WORD_BURST 128 #define WINDOWS_NR 2 +#define CURSOR_WIN 1 struct decon_context { struct device *dev; @@ -689,8 +690,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data) } for (zpos = 0; zpos < WINDOWS_NR; zpos++) { - type = (zpos == DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY : - DRM_PLANE_TYPE_OVERLAY; + type = exynos_plane_get_type(zpos, CURSOR_WIN); ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], 1 << ctx->pipe, type, decon_formats, ARRAY_SIZE(decon_formats), zpos); diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 7505a71c695f..bd75c1531cac 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -87,6 +87,7 @@ /* FIMD has totally five hardware windows. */ #define WINDOWS_NR 5 +#define CURSOR_WIN 4 struct fimd_driver_data { unsigned int timing_base; @@ -948,8 +949,7 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) ctx->pipe = priv->pipe++; for (zpos = 0; zpos < WINDOWS_NR; zpos++) { - type = (zpos == DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY : - DRM_PLANE_TYPE_OVERLAY; + type = exynos_plane_get_type(zpos, CURSOR_WIN); ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], 1 << ctx->pipe, type, fimd_formats, ARRAY_SIZE(fimd_formats), zpos); diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index 714822441467..80b2151bb7a8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -208,6 +208,17 @@ static void exynos_plane_attach_zpos_property(struct drm_plane *plane, drm_object_attach_property(&plane->base, prop, zpos); } +enum drm_plane_type exynos_plane_get_type(unsigned int zpos, + unsigned int cursor_win) +{ + if (zpos == DEFAULT_WIN) + return DRM_PLANE_TYPE_PRIMARY; + else if (zpos == cursor_win) + return DRM_PLANE_TYPE_CURSOR; + else + return DRM_PLANE_TYPE_OVERLAY; +} + int exynos_plane_init(struct drm_device *dev, struct exynos_drm_plane *exynos_plane, unsigned long possible_crtcs, enum drm_plane_type type, diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.h b/drivers/gpu/drm/exynos/exynos_drm_plane.h index 476c9340b591..abb641e64c23 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.h +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.h @@ -9,6 +9,8 @@ * */ +enum drm_plane_type exynos_plane_get_type(unsigned int zpos, + unsigned int cursor_win); int exynos_plane_init(struct drm_device *dev, struct exynos_drm_plane *exynos_plane, unsigned long possible_crtcs, enum drm_plane_type type, diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index fc5768779445..669362c53f49 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -29,6 +29,7 @@ /* vidi has totally three virtual windows. */ #define WINDOWS_NR 3 +#define CURSOR_WIN 2 #define ctx_from_connector(c) container_of(c, struct vidi_context, \ connector) @@ -445,8 +446,7 @@ static int vidi_bind(struct device *dev, struct device *master, void *data) vidi_ctx_initialize(ctx, drm_dev); for (zpos = 0; zpos < WINDOWS_NR; zpos++) { - type = (zpos == DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY : - DRM_PLANE_TYPE_OVERLAY; + type = exynos_plane_get_type(zpos, CURSOR_WIN); ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], 1 << ctx->pipe, type, formats, ARRAY_SIZE(formats), zpos); diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index f83e27da7e09..3f9f07279a36 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -43,6 +43,7 @@ #define MIXER_WIN_NR 3 #define VP_DEFAULT_WIN 2 +#define CURSOR_WIN 1 /* The pixelformats that are natively supported by the mixer. */ #define MXR_FORMAT_RGB565 4 @@ -1196,8 +1197,6 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data) const uint32_t *formats; unsigned int fcount; - type = (zpos == DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY : - DRM_PLANE_TYPE_OVERLAY; if (zpos < VP_DEFAULT_WIN) { formats = mixer_formats; fcount = ARRAY_SIZE(mixer_formats); @@ -1206,6 +1205,7 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data) fcount = ARRAY_SIZE(vp_formats); } + type = exynos_plane_get_type(zpos, CURSOR_WIN); ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], 1 << ctx->pipe, type, formats, fcount, zpos); From 4d91a855989af53b81f1ad7a82250d973f9b7b01 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Fri, 2 Oct 2015 09:30:38 +0900 Subject: [PATCH 19/34] drm/exynos: fix to detach device of iommu The arm_iommu_detach_device() is a function to detach device of iommu attached by arm_iommu_attach_device(). The exynos-drm uses arm_iommu_attach_device() so it should use arm_iommu_detach_device() to detach device of iommu, not iommu_detach_device(). The drm_release_iommu_mapping() is a function to release mapping of iommu created by arm_iommu_create_mapping(). It is called by exynos_drm_unload() so shouldn't be called by drm_iommu_detach_device(). Signed-off-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_iommu.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.c b/drivers/gpu/drm/exynos/exynos_drm_iommu.c index 055e8ec2ef21..d73b9ad35b7a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_iommu.c +++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.c @@ -139,6 +139,5 @@ void drm_iommu_detach_device(struct drm_device *drm_dev, if (!mapping || !mapping->domain) return; - iommu_detach_device(mapping->domain, subdrv_dev); - drm_release_iommu_mapping(drm_dev); + arm_iommu_detach_device(subdrv_dev); } From 813fd67b57ffca0dd19fe1834f894a4558cf5e0b Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Fri, 2 Oct 2015 09:33:47 +0900 Subject: [PATCH 20/34] drm/exynos: cleanup name of gem object for exynos_drm Struct of gem object in exynos_drm driver is struct exynos_drm_gem_obj. It's too long and we can know its meaning of name without _obj postfix. We use several names to variable name of gem object for exynos_drm - exynos_gem_obj, gem_obj and obj. Especially "obj" name can cause misunderstanding with variable name "obj" of struct drm_gem_object. This will clean about name of gem object for exynos_drm as follows. s/struct exynos_drm_gem_obj/struct exynos_drm_gem s/exynos_gem_obj or gem_obj or obj/exynos_gem Signed-off-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fb.c | 45 ++-- drivers/gpu/drm/exynos/exynos_drm_fb.h | 5 +- drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 53 ++--- drivers/gpu/drm/exynos/exynos_drm_gem.c | 239 +++++++++++----------- drivers/gpu/drm/exynos/exynos_drm_gem.h | 15 +- drivers/gpu/drm/exynos/exynos_drm_plane.c | 9 +- 6 files changed, 184 insertions(+), 182 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 084280859589..fcea28bdbc42 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -32,15 +32,15 @@ * exynos specific framebuffer structure. * * @fb: drm framebuffer obejct. - * @exynos_gem_obj: array of exynos specific gem object containing a gem object. + * @exynos_gem: array of exynos specific gem object containing a gem object. */ struct exynos_drm_fb { - struct drm_framebuffer fb; - struct exynos_drm_gem_obj *exynos_gem_obj[MAX_FB_BUFFER]; + struct drm_framebuffer fb; + struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER]; }; static int check_fb_gem_memory_type(struct drm_device *drm_dev, - struct exynos_drm_gem_obj *exynos_gem_obj) + struct exynos_drm_gem *exynos_gem) { unsigned int flags; @@ -51,7 +51,7 @@ static int check_fb_gem_memory_type(struct drm_device *drm_dev, if (is_drm_iommu_supported(drm_dev)) return 0; - flags = exynos_gem_obj->flags; + flags = exynos_gem->flags; /* * without iommu support, not support physically non-continuous memory @@ -75,13 +75,13 @@ static void exynos_drm_fb_destroy(struct drm_framebuffer *fb) drm_framebuffer_cleanup(fb); - for (i = 0; i < ARRAY_SIZE(exynos_fb->exynos_gem_obj); i++) { + for (i = 0; i < ARRAY_SIZE(exynos_fb->exynos_gem); i++) { struct drm_gem_object *obj; - if (exynos_fb->exynos_gem_obj[i] == NULL) + if (exynos_fb->exynos_gem[i] == NULL) continue; - obj = &exynos_fb->exynos_gem_obj[i]->base; + obj = &exynos_fb->exynos_gem[i]->base; drm_gem_object_unreference_unlocked(obj); } @@ -96,7 +96,7 @@ static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb, struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb); return drm_gem_handle_create(file_priv, - &exynos_fb->exynos_gem_obj[0]->base, handle); + &exynos_fb->exynos_gem[0]->base, handle); } static int exynos_drm_fb_dirty(struct drm_framebuffer *fb, @@ -118,7 +118,7 @@ static struct drm_framebuffer_funcs exynos_drm_fb_funcs = { struct drm_framebuffer * exynos_drm_framebuffer_init(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, - struct exynos_drm_gem_obj **gem_obj, + struct exynos_drm_gem **exynos_gem, int count) { struct exynos_drm_fb *exynos_fb; @@ -130,11 +130,11 @@ exynos_drm_framebuffer_init(struct drm_device *dev, return ERR_PTR(-ENOMEM); for (i = 0; i < count; i++) { - ret = check_fb_gem_memory_type(dev, gem_obj[i]); + ret = check_fb_gem_memory_type(dev, exynos_gem[i]); if (ret < 0) goto err; - exynos_fb->exynos_gem_obj[i] = gem_obj[i]; + exynos_fb->exynos_gem[i] = exynos_gem[i]; } drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd); @@ -156,7 +156,7 @@ static struct drm_framebuffer * exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd) { - struct exynos_drm_gem_obj *gem_objs[MAX_FB_BUFFER]; + struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER]; struct drm_gem_object *obj; struct drm_framebuffer *fb; int i; @@ -171,10 +171,10 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, goto err; } - gem_objs[i] = to_exynos_gem_obj(obj); + exynos_gem[i] = to_exynos_gem(obj); } - fb = exynos_drm_framebuffer_init(dev, mode_cmd, gem_objs, i); + fb = exynos_drm_framebuffer_init(dev, mode_cmd, exynos_gem, i); if (IS_ERR(fb)) { ret = PTR_ERR(fb); goto err; @@ -184,27 +184,26 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, err: while (i--) - drm_gem_object_unreference_unlocked(&gem_objs[i]->base); + drm_gem_object_unreference_unlocked(&exynos_gem[i]->base); return ERR_PTR(ret); } -struct exynos_drm_gem_obj *exynos_drm_fb_gem_obj(struct drm_framebuffer *fb, - int index) +struct exynos_drm_gem *exynos_drm_fb_gem(struct drm_framebuffer *fb, int index) { struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb); - struct exynos_drm_gem_obj *obj; + struct exynos_drm_gem *exynos_gem; if (index >= MAX_FB_BUFFER) return NULL; - obj = exynos_fb->exynos_gem_obj[index]; - if (!obj) + exynos_gem = exynos_fb->exynos_gem[index]; + if (!exynos_gem) return NULL; - DRM_DEBUG_KMS("dma_addr = 0x%lx\n", (unsigned long)obj->dma_addr); + DRM_DEBUG_KMS("dma_addr: 0x%lx\n", (unsigned long)exynos_gem->dma_addr); - return obj; + return exynos_gem; } static void exynos_drm_output_poll_changed(struct drm_device *dev) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.h b/drivers/gpu/drm/exynos/exynos_drm_fb.h index 85e4445b920e..726a2d44371f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.h +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.h @@ -19,12 +19,11 @@ struct drm_framebuffer * exynos_drm_framebuffer_init(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, - struct exynos_drm_gem_obj **gem_obj, + struct exynos_drm_gem **exynos_gem, int count); /* get gem object of a drm framebuffer */ -struct exynos_drm_gem_obj *exynos_drm_fb_gem_obj(struct drm_framebuffer *fb, - int index); +struct exynos_drm_gem *exynos_drm_fb_gem(struct drm_framebuffer *fb, int index); void exynos_drm_mode_config_init(struct drm_device *dev); diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index a221f753ad9c..f6118baa8e3e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -30,8 +30,8 @@ drm_fb_helper) struct exynos_drm_fbdev { - struct drm_fb_helper drm_fb_helper; - struct exynos_drm_gem_obj *obj; + struct drm_fb_helper drm_fb_helper; + struct exynos_drm_gem *exynos_gem; }; static int exynos_drm_fb_mmap(struct fb_info *info, @@ -39,7 +39,7 @@ static int exynos_drm_fb_mmap(struct fb_info *info, { struct drm_fb_helper *helper = info->par; struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(helper); - struct exynos_drm_gem_obj *obj = exynos_fbd->obj; + struct exynos_drm_gem *exynos_gem = exynos_fbd->exynos_gem; unsigned long vm_size; int ret; @@ -47,11 +47,12 @@ static int exynos_drm_fb_mmap(struct fb_info *info, vm_size = vma->vm_end - vma->vm_start; - if (vm_size > obj->size) + if (vm_size > exynos_gem->size) return -EINVAL; - ret = dma_mmap_attrs(helper->dev->dev, vma, obj->pages, obj->dma_addr, - obj->size, &obj->dma_attrs); + ret = dma_mmap_attrs(helper->dev->dev, vma, exynos_gem->pages, + exynos_gem->dma_addr, exynos_gem->size, + &exynos_gem->dma_attrs); if (ret < 0) { DRM_ERROR("failed to mmap.\n"); return ret; @@ -75,7 +76,7 @@ static struct fb_ops exynos_drm_fb_ops = { static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes, - struct exynos_drm_gem_obj *obj) + struct exynos_drm_gem *exynos_gem) { struct fb_info *fbi; struct drm_framebuffer *fb = helper->fb; @@ -96,11 +97,11 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth); drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height); - nr_pages = obj->size >> PAGE_SHIFT; + nr_pages = exynos_gem->size >> PAGE_SHIFT; - obj->kvaddr = (void __iomem *) vmap(obj->pages, nr_pages, VM_MAP, - pgprot_writecombine(PAGE_KERNEL)); - if (!obj->kvaddr) { + exynos_gem->kvaddr = (void __iomem *) vmap(exynos_gem->pages, nr_pages, + VM_MAP, pgprot_writecombine(PAGE_KERNEL)); + if (!exynos_gem->kvaddr) { DRM_ERROR("failed to map pages to kernel space.\n"); drm_fb_helper_release_fbi(helper); return -EIO; @@ -109,7 +110,7 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3); offset += fbi->var.yoffset * fb->pitches[0]; - fbi->screen_base = obj->kvaddr + offset; + fbi->screen_base = exynos_gem->kvaddr + offset; fbi->screen_size = size; fbi->fix.smem_len = size; @@ -120,7 +121,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { struct exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper); - struct exynos_drm_gem_obj *obj; + struct exynos_drm_gem *exynos_gem; struct drm_device *dev = helper->dev; struct drm_mode_fb_cmd2 mode_cmd = { 0 }; struct platform_device *pdev = dev->platformdev; @@ -141,32 +142,34 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, size = mode_cmd.pitches[0] * mode_cmd.height; - obj = exynos_drm_gem_create(dev, EXYNOS_BO_CONTIG, size); + exynos_gem = exynos_drm_gem_create(dev, EXYNOS_BO_CONTIG, size); /* * If physically contiguous memory allocation fails and if IOMMU is * supported then try to get buffer from non physically contiguous * memory area. */ - if (IS_ERR(obj) && is_drm_iommu_supported(dev)) { + if (IS_ERR(exynos_gem) && is_drm_iommu_supported(dev)) { dev_warn(&pdev->dev, "contiguous FB allocation failed, falling back to non-contiguous\n"); - obj = exynos_drm_gem_create(dev, EXYNOS_BO_NONCONTIG, size); + exynos_gem = exynos_drm_gem_create(dev, EXYNOS_BO_NONCONTIG, + size); } - if (IS_ERR(obj)) { - ret = PTR_ERR(obj); + if (IS_ERR(exynos_gem)) { + ret = PTR_ERR(exynos_gem); goto out; } - exynos_fbdev->obj = obj; + exynos_fbdev->exynos_gem = exynos_gem; - helper->fb = exynos_drm_framebuffer_init(dev, &mode_cmd, &obj, 1); + helper->fb = + exynos_drm_framebuffer_init(dev, &mode_cmd, &exynos_gem, 1); if (IS_ERR(helper->fb)) { DRM_ERROR("failed to create drm framebuffer.\n"); ret = PTR_ERR(helper->fb); goto err_destroy_gem; } - ret = exynos_drm_fbdev_update(helper, sizes, obj); + ret = exynos_drm_fbdev_update(helper, sizes, exynos_gem); if (ret < 0) goto err_destroy_framebuffer; @@ -176,7 +179,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, err_destroy_framebuffer: drm_framebuffer_cleanup(helper->fb); err_destroy_gem: - exynos_drm_gem_destroy(obj); + exynos_drm_gem_destroy(exynos_gem); /* * if failed, all resources allocated above would be released by @@ -269,11 +272,11 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev, struct drm_fb_helper *fb_helper) { struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(fb_helper); - struct exynos_drm_gem_obj *obj = exynos_fbd->obj; + struct exynos_drm_gem *exynos_gem = exynos_fbd->exynos_gem; struct drm_framebuffer *fb; - if (obj->kvaddr) - vunmap(obj->kvaddr); + if (exynos_gem->kvaddr) + vunmap(exynos_gem->kvaddr); /* release drm framebuffer and real buffer */ if (fb_helper->fb && fb_helper->fb->funcs) { diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 407afedb6003..f1dcdd086886 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -20,97 +20,100 @@ #include "exynos_drm_gem.h" #include "exynos_drm_iommu.h" -static int exynos_drm_alloc_buf(struct exynos_drm_gem_obj *obj) +static int exynos_drm_alloc_buf(struct exynos_drm_gem *exynos_gem) { - struct drm_device *dev = obj->base.dev; + struct drm_device *dev = exynos_gem->base.dev; enum dma_attr attr; unsigned int nr_pages; - if (obj->dma_addr) { + if (exynos_gem->dma_addr) { DRM_DEBUG_KMS("already allocated.\n"); return 0; } - init_dma_attrs(&obj->dma_attrs); + init_dma_attrs(&exynos_gem->dma_attrs); /* * if EXYNOS_BO_CONTIG, fully physically contiguous memory * region will be allocated else physically contiguous * as possible. */ - if (!(obj->flags & EXYNOS_BO_NONCONTIG)) - dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &obj->dma_attrs); + if (!(exynos_gem->flags & EXYNOS_BO_NONCONTIG)) + dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &exynos_gem->dma_attrs); /* * if EXYNOS_BO_WC or EXYNOS_BO_NONCACHABLE, writecombine mapping * else cachable mapping. */ - if (obj->flags & EXYNOS_BO_WC || !(obj->flags & EXYNOS_BO_CACHABLE)) + if (exynos_gem->flags & EXYNOS_BO_WC || + !(exynos_gem->flags & EXYNOS_BO_CACHABLE)) attr = DMA_ATTR_WRITE_COMBINE; else attr = DMA_ATTR_NON_CONSISTENT; - dma_set_attr(attr, &obj->dma_attrs); - dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &obj->dma_attrs); + dma_set_attr(attr, &exynos_gem->dma_attrs); + dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &exynos_gem->dma_attrs); - nr_pages = obj->size >> PAGE_SHIFT; + nr_pages = exynos_gem->size >> PAGE_SHIFT; if (!is_drm_iommu_supported(dev)) { - obj->pages = drm_calloc_large(nr_pages, sizeof(struct page *)); - if (!obj->pages) { + exynos_gem->pages = drm_calloc_large(nr_pages, + sizeof(struct page *)); + if (!exynos_gem->pages) { DRM_ERROR("failed to allocate pages.\n"); return -ENOMEM; } } - obj->cookie = dma_alloc_attrs(dev->dev, obj->size, &obj->dma_addr, - GFP_KERNEL, &obj->dma_attrs); - if (!obj->cookie) { + exynos_gem->cookie = dma_alloc_attrs(dev->dev, exynos_gem->size, + &exynos_gem->dma_addr, GFP_KERNEL, + &exynos_gem->dma_attrs); + if (!exynos_gem->cookie) { DRM_ERROR("failed to allocate buffer.\n"); - if (obj->pages) - drm_free_large(obj->pages); + if (exynos_gem->pages) + drm_free_large(exynos_gem->pages); return -ENOMEM; } - if (obj->pages) { + if (exynos_gem->pages) { dma_addr_t start_addr; unsigned int i = 0; - start_addr = obj->dma_addr; + start_addr = exynos_gem->dma_addr; while (i < nr_pages) { - obj->pages[i] = pfn_to_page(dma_to_pfn(dev->dev, - start_addr)); + exynos_gem->pages[i] = + pfn_to_page(dma_to_pfn(dev->dev, start_addr)); start_addr += PAGE_SIZE; i++; } } else { - obj->pages = obj->cookie; + exynos_gem->pages = exynos_gem->cookie; } DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n", - (unsigned long)obj->dma_addr, - obj->size); + (unsigned long)exynos_gem->dma_addr, exynos_gem->size); return 0; } -static void exynos_drm_free_buf(struct exynos_drm_gem_obj *obj) +static void exynos_drm_free_buf(struct exynos_drm_gem *exynos_gem) { - struct drm_device *dev = obj->base.dev; + struct drm_device *dev = exynos_gem->base.dev; - if (!obj->dma_addr) { + if (!exynos_gem->dma_addr) { DRM_DEBUG_KMS("dma_addr is invalid.\n"); return; } DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n", - (unsigned long)obj->dma_addr, obj->size); + (unsigned long)exynos_gem->dma_addr, exynos_gem->size); - dma_free_attrs(dev->dev, obj->size, obj->cookie, - (dma_addr_t)obj->dma_addr, &obj->dma_attrs); + dma_free_attrs(dev->dev, exynos_gem->size, exynos_gem->cookie, + (dma_addr_t)exynos_gem->dma_addr, + &exynos_gem->dma_attrs); if (!is_drm_iommu_supported(dev)) - drm_free_large(obj->pages); + drm_free_large(exynos_gem->pages); } static int exynos_drm_gem_handle_create(struct drm_gem_object *obj, @@ -135,9 +138,9 @@ static int exynos_drm_gem_handle_create(struct drm_gem_object *obj, return 0; } -void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj) +void exynos_drm_gem_destroy(struct exynos_drm_gem *exynos_gem) { - struct drm_gem_object *obj = &exynos_gem_obj->base; + struct drm_gem_object *obj = &exynos_gem->base; DRM_DEBUG_KMS("handle count = %d\n", obj->handle_count); @@ -148,21 +151,21 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj) * once dmabuf's refcount becomes 0. */ if (obj->import_attach) - drm_prime_gem_destroy(obj, exynos_gem_obj->sgt); + drm_prime_gem_destroy(obj, exynos_gem->sgt); else - exynos_drm_free_buf(exynos_gem_obj); + exynos_drm_free_buf(exynos_gem); /* release file pointer to gem object. */ drm_gem_object_release(obj); - kfree(exynos_gem_obj); + kfree(exynos_gem); } unsigned long exynos_drm_gem_get_size(struct drm_device *dev, unsigned int gem_handle, struct drm_file *file_priv) { - struct exynos_drm_gem_obj *exynos_gem_obj; + struct exynos_drm_gem *exynos_gem; struct drm_gem_object *obj; obj = drm_gem_object_lookup(dev, file_priv, gem_handle); @@ -171,51 +174,51 @@ unsigned long exynos_drm_gem_get_size(struct drm_device *dev, return 0; } - exynos_gem_obj = to_exynos_gem_obj(obj); + exynos_gem = to_exynos_gem(obj); drm_gem_object_unreference_unlocked(obj); - return exynos_gem_obj->size; + return exynos_gem->size; } -static struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev, - unsigned long size) +static struct exynos_drm_gem *exynos_drm_gem_init(struct drm_device *dev, + unsigned long size) { - struct exynos_drm_gem_obj *exynos_gem_obj; + struct exynos_drm_gem *exynos_gem; struct drm_gem_object *obj; int ret; - exynos_gem_obj = kzalloc(sizeof(*exynos_gem_obj), GFP_KERNEL); - if (!exynos_gem_obj) + exynos_gem = kzalloc(sizeof(*exynos_gem), GFP_KERNEL); + if (!exynos_gem) return ERR_PTR(-ENOMEM); - exynos_gem_obj->size = size; - obj = &exynos_gem_obj->base; + exynos_gem->size = size; + obj = &exynos_gem->base; ret = drm_gem_object_init(dev, obj, size); if (ret < 0) { DRM_ERROR("failed to initialize gem object\n"); - kfree(exynos_gem_obj); + kfree(exynos_gem); return ERR_PTR(ret); } ret = drm_gem_create_mmap_offset(obj); if (ret < 0) { drm_gem_object_release(obj); - kfree(exynos_gem_obj); + kfree(exynos_gem); return ERR_PTR(ret); } DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp); - return exynos_gem_obj; + return exynos_gem; } -struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, - unsigned int flags, - unsigned long size) +struct exynos_drm_gem *exynos_drm_gem_create(struct drm_device *dev, + unsigned int flags, + unsigned long size) { - struct exynos_drm_gem_obj *exynos_gem_obj; + struct exynos_drm_gem *exynos_gem; int ret; if (flags & ~(EXYNOS_BO_MASK)) { @@ -230,38 +233,38 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, size = roundup(size, PAGE_SIZE); - exynos_gem_obj = exynos_drm_gem_init(dev, size); - if (IS_ERR(exynos_gem_obj)) - return exynos_gem_obj; + exynos_gem = exynos_drm_gem_init(dev, size); + if (IS_ERR(exynos_gem)) + return exynos_gem; /* set memory type and cache attribute from user side. */ - exynos_gem_obj->flags = flags; + exynos_gem->flags = flags; - ret = exynos_drm_alloc_buf(exynos_gem_obj); + ret = exynos_drm_alloc_buf(exynos_gem); if (ret < 0) { - drm_gem_object_release(&exynos_gem_obj->base); - kfree(exynos_gem_obj); + drm_gem_object_release(&exynos_gem->base); + kfree(exynos_gem); return ERR_PTR(ret); } - return exynos_gem_obj; + return exynos_gem; } int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_exynos_gem_create *args = data; - struct exynos_drm_gem_obj *exynos_gem_obj; + struct exynos_drm_gem *exynos_gem; int ret; - exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size); - if (IS_ERR(exynos_gem_obj)) - return PTR_ERR(exynos_gem_obj); + exynos_gem = exynos_drm_gem_create(dev, args->flags, args->size); + if (IS_ERR(exynos_gem)) + return PTR_ERR(exynos_gem); - ret = exynos_drm_gem_handle_create(&exynos_gem_obj->base, file_priv, - &args->handle); + ret = exynos_drm_gem_handle_create(&exynos_gem->base, file_priv, + &args->handle); if (ret) { - exynos_drm_gem_destroy(exynos_gem_obj); + exynos_drm_gem_destroy(exynos_gem); return ret; } @@ -272,7 +275,7 @@ dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev, unsigned int gem_handle, struct drm_file *filp) { - struct exynos_drm_gem_obj *exynos_gem_obj; + struct exynos_drm_gem *exynos_gem; struct drm_gem_object *obj; obj = drm_gem_object_lookup(dev, filp, gem_handle); @@ -281,9 +284,9 @@ dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev, return ERR_PTR(-EINVAL); } - exynos_gem_obj = to_exynos_gem_obj(obj); + exynos_gem = to_exynos_gem(obj); - return &exynos_gem_obj->dma_addr; + return &exynos_gem->dma_addr; } void exynos_drm_gem_put_dma_addr(struct drm_device *dev, @@ -307,10 +310,10 @@ void exynos_drm_gem_put_dma_addr(struct drm_device *dev, drm_gem_object_unreference_unlocked(obj); } -static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem_obj *exynos_gem_obj, +static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem *exynos_gem, struct vm_area_struct *vma) { - struct drm_device *drm_dev = exynos_gem_obj->base.dev; + struct drm_device *drm_dev = exynos_gem->base.dev; unsigned long vm_size; int ret; @@ -320,12 +323,12 @@ static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem_obj *exynos_gem_obj, vm_size = vma->vm_end - vma->vm_start; /* check if user-requested size is valid. */ - if (vm_size > exynos_gem_obj->size) + if (vm_size > exynos_gem->size) return -EINVAL; - ret = dma_mmap_attrs(drm_dev->dev, vma, exynos_gem_obj->pages, - exynos_gem_obj->dma_addr, exynos_gem_obj->size, - &exynos_gem_obj->dma_attrs); + ret = dma_mmap_attrs(drm_dev->dev, vma, exynos_gem->pages, + exynos_gem->dma_addr, exynos_gem->size, + &exynos_gem->dma_attrs); if (ret < 0) { DRM_ERROR("failed to mmap.\n"); return ret; @@ -337,7 +340,7 @@ static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem_obj *exynos_gem_obj, int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct exynos_drm_gem_obj *exynos_gem_obj; + struct exynos_drm_gem *exynos_gem; struct drm_exynos_gem_info *args = data; struct drm_gem_object *obj; @@ -350,10 +353,10 @@ int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, return -EINVAL; } - exynos_gem_obj = to_exynos_gem_obj(obj); + exynos_gem = to_exynos_gem(obj); - args->flags = exynos_gem_obj->flags; - args->size = exynos_gem_obj->size; + args->flags = exynos_gem->flags; + args->size = exynos_gem->size; drm_gem_object_unreference(obj); mutex_unlock(&dev->struct_mutex); @@ -389,14 +392,14 @@ void exynos_gem_unmap_sgt_from_dma(struct drm_device *drm_dev, void exynos_drm_gem_free_object(struct drm_gem_object *obj) { - exynos_drm_gem_destroy(to_exynos_gem_obj(obj)); + exynos_drm_gem_destroy(to_exynos_gem(obj)); } int exynos_drm_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev, struct drm_mode_create_dumb *args) { - struct exynos_drm_gem_obj *exynos_gem_obj; + struct exynos_drm_gem *exynos_gem; unsigned int flags; int ret; @@ -414,16 +417,16 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv, else flags = EXYNOS_BO_CONTIG | EXYNOS_BO_WC; - exynos_gem_obj = exynos_drm_gem_create(dev, flags, args->size); - if (IS_ERR(exynos_gem_obj)) { + exynos_gem = exynos_drm_gem_create(dev, flags, args->size); + if (IS_ERR(exynos_gem)) { dev_warn(dev->dev, "FB allocation failed.\n"); - return PTR_ERR(exynos_gem_obj); + return PTR_ERR(exynos_gem); } - ret = exynos_drm_gem_handle_create(&exynos_gem_obj->base, file_priv, - &args->handle); + ret = exynos_drm_gem_handle_create(&exynos_gem->base, file_priv, + &args->handle); if (ret) { - exynos_drm_gem_destroy(exynos_gem_obj); + exynos_drm_gem_destroy(exynos_gem); return ret; } @@ -464,7 +467,7 @@ int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv, int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct drm_gem_object *obj = vma->vm_private_data; - struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); + struct exynos_drm_gem *exynos_gem = to_exynos_gem(obj); unsigned long pfn; pgoff_t page_offset; int ret; @@ -472,13 +475,13 @@ int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >> PAGE_SHIFT; - if (page_offset >= (exynos_gem_obj->size >> PAGE_SHIFT)) { + if (page_offset >= (exynos_gem->size >> PAGE_SHIFT)) { DRM_ERROR("invalid page offset\n"); ret = -EINVAL; goto out; } - pfn = page_to_pfn(exynos_gem_obj->pages[page_offset]); + pfn = page_to_pfn(exynos_gem->pages[page_offset]); ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn); out: @@ -496,7 +499,7 @@ int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) { - struct exynos_drm_gem_obj *exynos_gem_obj; + struct exynos_drm_gem *exynos_gem; struct drm_gem_object *obj; int ret; @@ -508,21 +511,21 @@ int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) } obj = vma->vm_private_data; - exynos_gem_obj = to_exynos_gem_obj(obj); + exynos_gem = to_exynos_gem(obj); - DRM_DEBUG_KMS("flags = 0x%x\n", exynos_gem_obj->flags); + DRM_DEBUG_KMS("flags = 0x%x\n", exynos_gem->flags); /* non-cachable as default. */ - if (exynos_gem_obj->flags & EXYNOS_BO_CACHABLE) + if (exynos_gem->flags & EXYNOS_BO_CACHABLE) vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); - else if (exynos_gem_obj->flags & EXYNOS_BO_WC) + else if (exynos_gem->flags & EXYNOS_BO_WC) vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); else vma->vm_page_prot = pgprot_noncached(vm_get_page_prot(vma->vm_flags)); - ret = exynos_drm_gem_mmap_buffer(exynos_gem_obj, vma); + ret = exynos_drm_gem_mmap_buffer(exynos_gem, vma); if (ret) goto err_close_vm; @@ -537,12 +540,12 @@ int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) /* low-level interface prime helpers */ struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj) { - struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); + struct exynos_drm_gem *exynos_gem = to_exynos_gem(obj); int npages; - npages = exynos_gem_obj->size >> PAGE_SHIFT; + npages = exynos_gem->size >> PAGE_SHIFT; - return drm_prime_pages_to_sg(exynos_gem_obj->pages, npages); + return drm_prime_pages_to_sg(exynos_gem->pages, npages); } struct drm_gem_object * @@ -550,35 +553,35 @@ exynos_drm_gem_prime_import_sg_table(struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sgt) { - struct exynos_drm_gem_obj *exynos_gem_obj; + struct exynos_drm_gem *exynos_gem; int npages; int ret; - exynos_gem_obj = exynos_drm_gem_init(dev, attach->dmabuf->size); - if (IS_ERR(exynos_gem_obj)) { - ret = PTR_ERR(exynos_gem_obj); + exynos_gem = exynos_drm_gem_init(dev, attach->dmabuf->size); + if (IS_ERR(exynos_gem)) { + ret = PTR_ERR(exynos_gem); return ERR_PTR(ret); } - exynos_gem_obj->dma_addr = sg_dma_address(sgt->sgl); + exynos_gem->dma_addr = sg_dma_address(sgt->sgl); - npages = exynos_gem_obj->size >> PAGE_SHIFT; - exynos_gem_obj->pages = drm_malloc_ab(npages, sizeof(struct page *)); - if (!exynos_gem_obj->pages) { + npages = exynos_gem->size >> PAGE_SHIFT; + exynos_gem->pages = drm_malloc_ab(npages, sizeof(struct page *)); + if (!exynos_gem->pages) { ret = -ENOMEM; goto err; } - ret = drm_prime_sg_to_page_addr_arrays(sgt, exynos_gem_obj->pages, NULL, - npages); + ret = drm_prime_sg_to_page_addr_arrays(sgt, exynos_gem->pages, NULL, + npages); if (ret < 0) goto err_free_large; - exynos_gem_obj->sgt = sgt; + exynos_gem->sgt = sgt; if (sgt->nents == 1) { /* always physically continuous memory if sgt->nents is 1. */ - exynos_gem_obj->flags |= EXYNOS_BO_CONTIG; + exynos_gem->flags |= EXYNOS_BO_CONTIG; } else { /* * this case could be CONTIG or NONCONTIG type but for now @@ -586,16 +589,16 @@ exynos_drm_gem_prime_import_sg_table(struct drm_device *dev, * TODO. we have to find a way that exporter can notify * the type of its own buffer to importer. */ - exynos_gem_obj->flags |= EXYNOS_BO_NONCONTIG; + exynos_gem->flags |= EXYNOS_BO_NONCONTIG; } - return &exynos_gem_obj->base; + return &exynos_gem->base; err_free_large: - drm_free_large(exynos_gem_obj->pages); + drm_free_large(exynos_gem->pages); err: - drm_gem_object_release(&exynos_gem_obj->base); - kfree(exynos_gem_obj); + drm_gem_object_release(&exynos_gem->base); + kfree(exynos_gem); return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h index b62d1007c0e0..37ab8b282db6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.h +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h @@ -14,8 +14,7 @@ #include -#define to_exynos_gem_obj(x) container_of(x,\ - struct exynos_drm_gem_obj, base) +#define to_exynos_gem(x) container_of(x, struct exynos_drm_gem, base) #define IS_NONCONTIG_BUFFER(f) (f & EXYNOS_BO_NONCONTIG) @@ -44,7 +43,7 @@ * P.S. this object would be transferred to user as kms_bo.handle so * user can access the buffer through kms_bo.handle. */ -struct exynos_drm_gem_obj { +struct exynos_drm_gem { struct drm_gem_object base; unsigned int flags; unsigned long size; @@ -59,12 +58,12 @@ struct exynos_drm_gem_obj { struct page **exynos_gem_get_pages(struct drm_gem_object *obj, gfp_t gfpmask); /* destroy a buffer with gem object */ -void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj); +void exynos_drm_gem_destroy(struct exynos_drm_gem *exynos_gem); /* create a new buffer with gem object */ -struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, - unsigned int flags, - unsigned long size); +struct exynos_drm_gem *exynos_drm_gem_create(struct drm_device *dev, + unsigned int flags, + unsigned long size); /* * request gem object creation and buffer allocation as the size @@ -106,7 +105,7 @@ unsigned long exynos_drm_gem_get_size(struct drm_device *dev, struct drm_file *file_priv); /* free gem object. */ -void exynos_drm_gem_free_object(struct drm_gem_object *gem_obj); +void exynos_drm_gem_free_object(struct drm_gem_object *obj); /* create memory region for drm framebuffer. */ int exynos_drm_gem_dumb_create(struct drm_file *file_priv, diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index 80b2151bb7a8..179311760bb7 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -128,15 +128,14 @@ static int exynos_plane_atomic_check(struct drm_plane *plane, nr = drm_format_num_planes(state->fb->pixel_format); for (i = 0; i < nr; i++) { - struct exynos_drm_gem_obj *obj = - exynos_drm_fb_gem_obj(state->fb, i); - - if (!obj) { + struct exynos_drm_gem *exynos_gem = + exynos_drm_fb_gem(state->fb, i); + if (!exynos_gem) { DRM_DEBUG_KMS("gem object is null\n"); return -EFAULT; } - exynos_plane->dma_addr[i] = obj->dma_addr + + exynos_plane->dma_addr[i] = exynos_gem->dma_addr + state->fb->offsets[i]; DRM_DEBUG_KMS("buffer: %d, dma_addr = 0x%lx\n", From 4f54f21cd68eb7b2ed355b9de90a2d58b96fdda9 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Tue, 20 Oct 2015 11:22:34 +0200 Subject: [PATCH 21/34] drm/exynos/decon5433: add PCLK clock PCLK clock is used by DECON IP. The patch also replaces magic number with number of clocks in array definition. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index 1ea26dbb1119..b25d764ae5e1 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -27,13 +27,23 @@ #define CURSOR_WIN 2 #define MIN_FB_WIDTH_FOR_16WORD_BURST 128 +static const char * const decon_clks_name[] = { + "pclk", + "aclk_decon", + "aclk_smmu_decon0x", + "aclk_xiu_decon0x", + "pclk_smmu_decon0x", + "sclk_decon_vclk", + "sclk_decon_eclk", +}; + struct decon_context { struct device *dev; struct drm_device *drm_dev; struct exynos_drm_crtc *crtc; struct exynos_drm_plane planes[WINDOWS_NR]; void __iomem *addr; - struct clk *clks[6]; + struct clk *clks[ARRAY_SIZE(decon_clks_name)]; unsigned long irq_flags; int pipe; bool suspended; @@ -45,15 +55,6 @@ struct decon_context { atomic_t win_updated; }; -static const char * const decon_clks_name[] = { - "aclk_decon", - "aclk_smmu_decon0x", - "aclk_xiu_decon0x", - "pclk_smmu_decon0x", - "sclk_decon_vclk", - "sclk_decon_eclk", -}; - static const uint32_t decon_formats[] = { DRM_FORMAT_XRGB1555, DRM_FORMAT_RGB565, From 85de275ad9aff7dae5811fc583a6a43e7b5cc0f1 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Tue, 20 Oct 2015 11:22:36 +0200 Subject: [PATCH 22/34] drm/exynos/decon5433: fix timing registers writes All timing registers should contain values decreased by one. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index b25d764ae5e1..83e09396bfb3 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -104,7 +104,7 @@ static void decon_setup_trigger(struct decon_context *ctx) static void decon_commit(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; - struct drm_display_mode *mode = &crtc->base.mode; + struct drm_display_mode *m = &crtc->base.mode; u32 val; if (ctx->suspended) @@ -122,29 +122,29 @@ static void decon_commit(struct exynos_drm_crtc *crtc) val |= VIDOUT_RGB_IF; writel(val, ctx->addr + DECON_VIDOUTCON0); - val = VIDTCON2_LINEVAL(mode->vdisplay - 1) | - VIDTCON2_HOZVAL(mode->hdisplay - 1); + val = VIDTCON2_LINEVAL(m->vdisplay - 1) | + VIDTCON2_HOZVAL(m->hdisplay - 1); writel(val, ctx->addr + DECON_VIDTCON2); if (!ctx->i80_if) { val = VIDTCON00_VBPD_F( - mode->crtc_vtotal - mode->crtc_vsync_end) | + m->crtc_vtotal - m->crtc_vsync_end - 1) | VIDTCON00_VFPD_F( - mode->crtc_vsync_start - mode->crtc_vdisplay); + m->crtc_vsync_start - m->crtc_vdisplay - 1); writel(val, ctx->addr + DECON_VIDTCON00); val = VIDTCON01_VSPW_F( - mode->crtc_vsync_end - mode->crtc_vsync_start); + m->crtc_vsync_end - m->crtc_vsync_start - 1); writel(val, ctx->addr + DECON_VIDTCON01); val = VIDTCON10_HBPD_F( - mode->crtc_htotal - mode->crtc_hsync_end) | + m->crtc_htotal - m->crtc_hsync_end - 1) | VIDTCON10_HFPD_F( - mode->crtc_hsync_start - mode->crtc_hdisplay); + m->crtc_hsync_start - m->crtc_hdisplay - 1); writel(val, ctx->addr + DECON_VIDTCON10); val = VIDTCON11_HSPW_F( - mode->crtc_hsync_end - mode->crtc_hsync_start); + m->crtc_hsync_end - m->crtc_hsync_start - 1); writel(val, ctx->addr + DECON_VIDTCON11); } From b219207385dbd575ebd7e1cbf560636c8e780467 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Tue, 20 Oct 2015 11:22:37 +0200 Subject: [PATCH 23/34] drm/exynos/decon5433: add function to set particular register bits The driver often sets only particular bits of configuration registers. Using separate function to such action simplifies the code. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 69 +++++-------------- 1 file changed, 19 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index 83e09396bfb3..722c11a0a5ee 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -62,6 +62,13 @@ static const uint32_t decon_formats[] = { DRM_FORMAT_ARGB8888, }; +static inline void decon_set_bits(struct decon_context *ctx, u32 reg, u32 mask, + u32 val) +{ + val = (val & mask) | (readl(ctx->addr + reg) & ~mask); + writel(val, ctx->addr + reg); +} + static int decon_enable_vblank(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; @@ -215,16 +222,8 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win, static void decon_shadow_protect_win(struct decon_context *ctx, int win, bool protect) { - u32 val; - - val = readl(ctx->addr + DECON_SHADOWCON); - - if (protect) - val |= SHADOWCON_Wx_PROTECT(win); - else - val &= ~SHADOWCON_Wx_PROTECT(win); - - writel(val, ctx->addr + DECON_SHADOWCON); + decon_set_bits(ctx, DECON_SHADOWCON, SHADOWCON_Wx_PROTECT(win), + protect ? ~0 : 0); } static void decon_atomic_begin(struct exynos_drm_crtc *crtc, @@ -278,14 +277,10 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, decon_win_set_pixfmt(ctx, win, state->fb); /* window enable */ - val = readl(ctx->addr + DECON_WINCONx(win)); - val |= WINCONx_ENWIN_F; - writel(val, ctx->addr + DECON_WINCONx(win)); + decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, ~0); /* standalone update */ - val = readl(ctx->addr + DECON_UPDATE); - val |= STANDALONE_UPDATE_F; - writel(val, ctx->addr + DECON_UPDATE); + decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); } static void decon_disable_plane(struct exynos_drm_crtc *crtc, @@ -293,7 +288,6 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc, { struct decon_context *ctx = crtc->ctx; unsigned int win = plane->zpos; - u32 val; if (ctx->suspended) return; @@ -301,16 +295,12 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc, decon_shadow_protect_win(ctx, win, true); /* window disable */ - val = readl(ctx->addr + DECON_WINCONx(win)); - val &= ~WINCONx_ENWIN_F; - writel(val, ctx->addr + DECON_WINCONx(win)); + decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0); decon_shadow_protect_win(ctx, win, false); /* standalone update */ - val = readl(ctx->addr + DECON_UPDATE); - val |= STANDALONE_UPDATE_F; - writel(val, ctx->addr + DECON_UPDATE); + decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); } static void decon_atomic_flush(struct exynos_drm_crtc *crtc, @@ -416,17 +406,12 @@ static void decon_disable(struct exynos_drm_crtc *crtc) void decon_te_irq_handler(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; - u32 val; if (!test_bit(BIT_CLKS_ENABLED, &ctx->enabled)) return; - if (atomic_add_unless(&ctx->win_updated, -1, 0)) { - /* trigger */ - val = readl(ctx->addr + DECON_TRIGCON); - val |= TRIGCON_SWTRIGCMD; - writel(val, ctx->addr + DECON_TRIGCON); - } + if (atomic_add_unless(&ctx->win_updated, -1, 0)) + decon_set_bits(ctx, DECON_TRIGCON, TRIGCON_SWTRIGCMD, ~0); drm_crtc_handle_vblank(&ctx->crtc->base); } @@ -435,7 +420,6 @@ static void decon_clear_channels(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; int win, i, ret; - u32 val; DRM_DEBUG_KMS("%s\n", __FILE__); @@ -446,25 +430,10 @@ static void decon_clear_channels(struct exynos_drm_crtc *crtc) } for (win = 0; win < WINDOWS_NR; win++) { - /* shadow update disable */ - val = readl(ctx->addr + DECON_SHADOWCON); - val |= SHADOWCON_Wx_PROTECT(win); - writel(val, ctx->addr + DECON_SHADOWCON); - - /* window disable */ - val = readl(ctx->addr + DECON_WINCONx(win)); - val &= ~WINCONx_ENWIN_F; - writel(val, ctx->addr + DECON_WINCONx(win)); - - /* shadow update enable */ - val = readl(ctx->addr + DECON_SHADOWCON); - val &= ~SHADOWCON_Wx_PROTECT(win); - writel(val, ctx->addr + DECON_SHADOWCON); - - /* standalone update */ - val = readl(ctx->addr + DECON_UPDATE); - val |= STANDALONE_UPDATE_F; - writel(val, ctx->addr + DECON_UPDATE); + decon_shadow_protect_win(ctx, win, true); + decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0); + decon_shadow_protect_win(ctx, win, false); + decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); } /* TODO: wait for possible vsync */ msleep(50); From 7b6bb6ed01e9f9c20c86b722c733d7219c4c55f6 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Tue, 20 Oct 2015 11:22:38 +0200 Subject: [PATCH 24/34] drm/exynos/decon5433: merge different flag fields Driver uses four different fields for internal flags. They can be merged into one. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 61 +++++++++---------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index 722c11a0a5ee..265a77f5dece 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -37,6 +37,13 @@ static const char * const decon_clks_name[] = { "sclk_decon_eclk", }; +enum decon_flag_bits { + BIT_CLKS_ENABLED, + BIT_IRQS_ENABLED, + BIT_WIN_UPDATED, + BIT_SUSPENDED +}; + struct decon_context { struct device *dev; struct drm_device *drm_dev; @@ -44,15 +51,9 @@ struct decon_context { struct exynos_drm_plane planes[WINDOWS_NR]; void __iomem *addr; struct clk *clks[ARRAY_SIZE(decon_clks_name)]; - unsigned long irq_flags; int pipe; - bool suspended; - -#define BIT_CLKS_ENABLED 0 -#define BIT_IRQS_ENABLED 1 - unsigned long enabled; + unsigned long flags; bool i80_if; - atomic_t win_updated; }; static const uint32_t decon_formats[] = { @@ -74,10 +75,10 @@ static int decon_enable_vblank(struct exynos_drm_crtc *crtc) struct decon_context *ctx = crtc->ctx; u32 val; - if (ctx->suspended) + if (test_bit(BIT_SUSPENDED, &ctx->flags)) return -EPERM; - if (test_and_set_bit(0, &ctx->irq_flags)) { + if (test_and_set_bit(BIT_IRQS_ENABLED, &ctx->flags)) { val = VIDINTCON0_INTEN; if (ctx->i80_if) val |= VIDINTCON0_FRAMEDONE; @@ -94,10 +95,10 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; - if (ctx->suspended) + if (test_bit(BIT_SUSPENDED, &ctx->flags)) return; - if (test_and_clear_bit(0, &ctx->irq_flags)) + if (test_and_clear_bit(BIT_IRQS_ENABLED, &ctx->flags)) writel(0, ctx->addr + DECON_VIDINTCON0); } @@ -114,7 +115,7 @@ static void decon_commit(struct exynos_drm_crtc *crtc) struct drm_display_mode *m = &crtc->base.mode; u32 val; - if (ctx->suspended) + if (test_bit(BIT_SUSPENDED, &ctx->flags)) return; /* enable clock gate */ @@ -231,7 +232,7 @@ static void decon_atomic_begin(struct exynos_drm_crtc *crtc, { struct decon_context *ctx = crtc->ctx; - if (ctx->suspended) + if (test_bit(BIT_SUSPENDED, &ctx->flags)) return; decon_shadow_protect_win(ctx, plane->zpos, true); @@ -247,7 +248,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, unsigned int pitch = state->fb->pitches[0]; u32 val; - if (ctx->suspended) + if (test_bit(BIT_SUSPENDED, &ctx->flags)) return; val = COORDINATE_X(plane->crtc_x) | COORDINATE_Y(plane->crtc_y); @@ -289,7 +290,7 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc, struct decon_context *ctx = crtc->ctx; unsigned int win = plane->zpos; - if (ctx->suspended) + if (test_bit(BIT_SUSPENDED, &ctx->flags)) return; decon_shadow_protect_win(ctx, win, true); @@ -308,13 +309,13 @@ static void decon_atomic_flush(struct exynos_drm_crtc *crtc, { struct decon_context *ctx = crtc->ctx; - if (ctx->suspended) + if (test_bit(BIT_SUSPENDED, &ctx->flags)) return; decon_shadow_protect_win(ctx, plane->zpos, false); if (ctx->i80_if) - atomic_set(&ctx->win_updated, 1); + set_bit(BIT_WIN_UPDATED, &ctx->flags); } static void decon_swreset(struct decon_context *ctx) @@ -346,11 +347,9 @@ static void decon_enable(struct exynos_drm_crtc *crtc) int ret; int i; - if (!ctx->suspended) + if (!test_and_clear_bit(BIT_SUSPENDED, &ctx->flags)) return; - ctx->suspended = false; - pm_runtime_get_sync(ctx->dev); for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) { @@ -359,10 +358,10 @@ static void decon_enable(struct exynos_drm_crtc *crtc) goto err; } - set_bit(BIT_CLKS_ENABLED, &ctx->enabled); + set_bit(BIT_CLKS_ENABLED, &ctx->flags); /* if vblank was enabled status, enable it again. */ - if (test_and_clear_bit(0, &ctx->irq_flags)) + if (test_and_clear_bit(BIT_IRQS_ENABLED, &ctx->flags)) decon_enable_vblank(ctx->crtc); decon_commit(ctx->crtc); @@ -372,7 +371,7 @@ static void decon_enable(struct exynos_drm_crtc *crtc) while (--i >= 0) clk_disable_unprepare(ctx->clks[i]); - ctx->suspended = true; + set_bit(BIT_SUSPENDED, &ctx->flags); } static void decon_disable(struct exynos_drm_crtc *crtc) @@ -380,7 +379,7 @@ static void decon_disable(struct exynos_drm_crtc *crtc) struct decon_context *ctx = crtc->ctx; int i; - if (ctx->suspended) + if (test_bit(BIT_SUSPENDED, &ctx->flags)) return; /* @@ -396,21 +395,21 @@ static void decon_disable(struct exynos_drm_crtc *crtc) for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) clk_disable_unprepare(ctx->clks[i]); - clear_bit(BIT_CLKS_ENABLED, &ctx->enabled); + clear_bit(BIT_CLKS_ENABLED, &ctx->flags); pm_runtime_put_sync(ctx->dev); - ctx->suspended = true; + set_bit(BIT_SUSPENDED, &ctx->flags); } void decon_te_irq_handler(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; - if (!test_bit(BIT_CLKS_ENABLED, &ctx->enabled)) + if (!test_bit(BIT_CLKS_ENABLED, &ctx->flags)) return; - if (atomic_add_unless(&ctx->win_updated, -1, 0)) + if (test_and_clear_bit(BIT_WIN_UPDATED, &ctx->flags)) decon_set_bits(ctx, DECON_TRIGCON, TRIGCON_SWTRIGCMD, ~0); drm_crtc_handle_vblank(&ctx->crtc->base); @@ -520,7 +519,7 @@ static irqreturn_t decon_vsync_irq_handler(int irq, void *dev_id) struct decon_context *ctx = dev_id; u32 val; - if (!test_bit(BIT_CLKS_ENABLED, &ctx->enabled)) + if (!test_bit(BIT_CLKS_ENABLED, &ctx->flags)) goto out; val = readl(ctx->addr + DECON_VIDINTCON1); @@ -541,7 +540,7 @@ static irqreturn_t decon_lcd_sys_irq_handler(int irq, void *dev_id) u32 val; int win; - if (!test_bit(BIT_CLKS_ENABLED, &ctx->enabled)) + if (!test_bit(BIT_CLKS_ENABLED, &ctx->flags)) goto out; val = readl(ctx->addr + DECON_VIDINTCON1); @@ -576,7 +575,7 @@ static int exynos5433_decon_probe(struct platform_device *pdev) if (!ctx) return -ENOMEM; - ctx->suspended = true; + __set_bit(BIT_SUSPENDED, &ctx->flags); ctx->dev = dev; if (of_get_child_by_name(dev->of_node, "i80-if-timings")) ctx->i80_if = true; From 5d929ba50a1ea69fba1a92e24fc54d484583a109 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Tue, 20 Oct 2015 11:22:39 +0200 Subject: [PATCH 25/34] drm/exynos/decon5433: remove duplicated initialization Field .commit is already initialized few lines above. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index 265a77f5dece..3c9aa4e48f8d 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -448,7 +448,6 @@ static struct exynos_drm_crtc_ops decon_crtc_ops = { .commit = decon_commit, .enable_vblank = decon_enable_vblank, .disable_vblank = decon_disable_vblank, - .commit = decon_commit, .atomic_begin = decon_atomic_begin, .update_plane = decon_update_plane, .disable_plane = decon_disable_plane, From b8182832c5a9d9ce645d53be84e5db07f8aa5302 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Tue, 20 Oct 2015 18:22:41 +0900 Subject: [PATCH 26/34] drm/exynos/decon5433: add support for DECON-TV DECON-TV IP is responsible for generating video stream which is transferred to HDMI IP. It is almost fully compatible with DECON IP. The patch is based on initial work of Hyungwon Hwang. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 154 +++++++++++------- include/video/exynos5433_decon.h | 29 ++++ 2 files changed, 122 insertions(+), 61 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index 3c9aa4e48f8d..fbe1b3174f75 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -37,6 +38,12 @@ static const char * const decon_clks_name[] = { "sclk_decon_eclk", }; +enum decon_iftype { + IFTYPE_RGB, + IFTYPE_I80, + IFTYPE_HDMI +}; + enum decon_flag_bits { BIT_CLKS_ENABLED, BIT_IRQS_ENABLED, @@ -53,7 +60,8 @@ struct decon_context { struct clk *clks[ARRAY_SIZE(decon_clks_name)]; int pipe; unsigned long flags; - bool i80_if; + enum decon_iftype out_type; + int first_win; }; static const uint32_t decon_formats[] = { @@ -80,7 +88,7 @@ static int decon_enable_vblank(struct exynos_drm_crtc *crtc) if (test_and_set_bit(BIT_IRQS_ENABLED, &ctx->flags)) { val = VIDINTCON0_INTEN; - if (ctx->i80_if) + if (ctx->out_type == IFTYPE_I80) val |= VIDINTCON0_FRAMEDONE; else val |= VIDINTCON0_INTFRMEN; @@ -104,8 +112,11 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc) static void decon_setup_trigger(struct decon_context *ctx) { - u32 val = TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F | - TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN; + u32 val = (ctx->out_type != IFTYPE_HDMI) + ? TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F | + TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN + : TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F | + TRIGCON_HWTRIGMASK_I80_RGB | TRIGCON_HWTRIGEN_I80_RGB; writel(val, ctx->addr + DECON_TRIGCON); } @@ -118,13 +129,22 @@ static void decon_commit(struct exynos_drm_crtc *crtc) if (test_bit(BIT_SUSPENDED, &ctx->flags)) return; + if (ctx->out_type == IFTYPE_HDMI) { + m->crtc_hsync_start = m->crtc_hdisplay + 10; + m->crtc_hsync_end = m->crtc_htotal - 92; + m->crtc_vsync_start = m->crtc_vdisplay + 1; + m->crtc_vsync_end = m->crtc_vsync_start + 1; + } + + decon_set_bits(ctx, DECON_VIDCON0, VIDCON0_ENVID, 0); + /* enable clock gate */ val = CMU_CLKGAGE_MODE_SFR_F | CMU_CLKGAGE_MODE_MEM_F; writel(val, ctx->addr + DECON_CMU); /* lcd on and use command if */ val = VIDOUT_LCD_ON; - if (ctx->i80_if) + if (ctx->out_type == IFTYPE_I80) val |= VIDOUT_COMMAND_IF; else val |= VIDOUT_RGB_IF; @@ -134,7 +154,7 @@ static void decon_commit(struct exynos_drm_crtc *crtc) VIDTCON2_HOZVAL(m->hdisplay - 1); writel(val, ctx->addr + DECON_VIDTCON2); - if (!ctx->i80_if) { + if (ctx->out_type != IFTYPE_I80) { val = VIDTCON00_VBPD_F( m->crtc_vtotal - m->crtc_vsync_end - 1) | VIDTCON00_VFPD_F( @@ -159,15 +179,9 @@ static void decon_commit(struct exynos_drm_crtc *crtc) decon_setup_trigger(ctx); /* enable output and display signal */ - val = VIDCON0_ENVID | VIDCON0_ENVID_F; - writel(val, ctx->addr + DECON_VIDCON0); + decon_set_bits(ctx, DECON_VIDCON0, VIDCON0_ENVID | VIDCON0_ENVID_F, ~0); } -#define COORDINATE_X(x) (((x) & 0xfff) << 12) -#define COORDINATE_Y(x) ((x) & 0xfff) -#define OFFSIZE(x) (((x) & 0x3fff) << 14) -#define PAGEWIDTH(x) ((x) & 0x3fff) - static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win, struct drm_framebuffer *fb) { @@ -238,6 +252,10 @@ static void decon_atomic_begin(struct exynos_drm_crtc *crtc, decon_shadow_protect_win(ctx, plane->zpos, true); } +#define BIT_VAL(x, e, s) (((x) & ((1 << ((e) - (s) + 1)) - 1)) << (s)) +#define COORDINATE_X(x) BIT_VAL((x), 23, 12) +#define COORDINATE_Y(x) BIT_VAL((x), 11, 0) + static void decon_update_plane(struct exynos_drm_crtc *crtc, struct exynos_drm_plane *plane) { @@ -271,8 +289,12 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, val = plane->dma_addr[0] + pitch * plane->crtc_h; writel(val, ctx->addr + DECON_VIDW0xADD1B0(win)); - val = OFFSIZE(pitch - plane->crtc_w * bpp) - | PAGEWIDTH(plane->crtc_w * bpp); + if (ctx->out_type != IFTYPE_HDMI) + val = BIT_VAL(pitch - plane->crtc_w * bpp, 27, 14) + | BIT_VAL(plane->crtc_w * bpp, 13, 0); + else + val = BIT_VAL(pitch - plane->crtc_w * bpp, 29, 15) + | BIT_VAL(plane->crtc_w * bpp, 14, 0); writel(val, ctx->addr + DECON_VIDW0xADD2(win)); decon_win_set_pixfmt(ctx, win, state->fb); @@ -314,7 +336,7 @@ static void decon_atomic_flush(struct exynos_drm_crtc *crtc, decon_shadow_protect_win(ctx, plane->zpos, false); - if (ctx->i80_if) + if (ctx->out_type == IFTYPE_I80) set_bit(BIT_WIN_UPDATED, &ctx->flags); } @@ -339,6 +361,17 @@ static void decon_swreset(struct decon_context *ctx) } WARN(tries == 0, "failed to software reset DECON\n"); + + if (ctx->out_type != IFTYPE_HDMI) + return; + + writel(VIDCON0_CLKVALUP | VIDCON0_VLCKFREE, ctx->addr + DECON_VIDCON0); + decon_set_bits(ctx, DECON_CMU, + CMU_CLKGAGE_MODE_SFR_F | CMU_CLKGAGE_MODE_MEM_F, ~0); + writel(VIDCON1_VCLK_RUN_VDEN_DISABLE, ctx->addr + DECON_VIDCON1); + writel(CRCCTRL_CRCEN | CRCCTRL_CRCSTART_F | CRCCTRL_CRCCLKEN, + ctx->addr + DECON_CRCCTRL); + decon_setup_trigger(ctx); } static void decon_enable(struct exynos_drm_crtc *crtc) @@ -387,7 +420,7 @@ static void decon_disable(struct exynos_drm_crtc *crtc) * suspend that connector. Otherwise we might try to scan from * a destroyed buffer later. */ - for (i = 0; i < WINDOWS_NR; i++) + for (i = ctx->first_win; i < WINDOWS_NR; i++) decon_disable_plane(crtc, &ctx->planes[i]); decon_swreset(ctx); @@ -461,25 +494,30 @@ static int decon_bind(struct device *dev, struct device *master, void *data) struct drm_device *drm_dev = data; struct exynos_drm_private *priv = drm_dev->dev_private; struct exynos_drm_plane *exynos_plane; + enum exynos_drm_output_type out_type; enum drm_plane_type type; - unsigned int zpos; + unsigned int win; int ret; ctx->drm_dev = drm_dev; ctx->pipe = priv->pipe++; - for (zpos = 0; zpos < WINDOWS_NR; zpos++) { - type = exynos_plane_get_type(zpos, CURSOR_WIN); - ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], + for (win = ctx->first_win; win < WINDOWS_NR; win++) { + int tmp = (win == ctx->first_win) ? 0 : win; + + type = exynos_plane_get_type(tmp, CURSOR_WIN); + ret = exynos_plane_init(drm_dev, &ctx->planes[win], 1 << ctx->pipe, type, decon_formats, - ARRAY_SIZE(decon_formats), zpos); + ARRAY_SIZE(decon_formats), win); if (ret) return ret; } - exynos_plane = &ctx->planes[DEFAULT_WIN]; + exynos_plane = &ctx->planes[ctx->first_win]; + out_type = (ctx->out_type == IFTYPE_HDMI) ? EXYNOS_DISPLAY_TYPE_HDMI + : EXYNOS_DISPLAY_TYPE_LCD; ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, - ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD, + ctx->pipe, out_type, &decon_crtc_ops, ctx); if (IS_ERR(ctx->crtc)) { ret = PTR_ERR(ctx->crtc); @@ -513,27 +551,7 @@ static const struct component_ops decon_component_ops = { .unbind = decon_unbind, }; -static irqreturn_t decon_vsync_irq_handler(int irq, void *dev_id) -{ - struct decon_context *ctx = dev_id; - u32 val; - - if (!test_bit(BIT_CLKS_ENABLED, &ctx->flags)) - goto out; - - val = readl(ctx->addr + DECON_VIDINTCON1); - if (val & VIDINTCON1_INTFRMPEND) { - drm_crtc_handle_vblank(&ctx->crtc->base); - - /* clear */ - writel(VIDINTCON1_INTFRMPEND, ctx->addr + DECON_VIDINTCON1); - } - -out: - return IRQ_HANDLED; -} - -static irqreturn_t decon_lcd_sys_irq_handler(int irq, void *dev_id) +static irqreturn_t decon_irq_handler(int irq, void *dev_id) { struct decon_context *ctx = dev_id; u32 val; @@ -543,8 +561,10 @@ static irqreturn_t decon_lcd_sys_irq_handler(int irq, void *dev_id) goto out; val = readl(ctx->addr + DECON_VIDINTCON1); - if (val & VIDINTCON1_INTFRMDONEPEND) { - for (win = 0 ; win < WINDOWS_NR ; win++) { + val &= VIDINTCON1_INTFRMDONEPEND | VIDINTCON1_INTFRMPEND; + + if (val) { + for (win = ctx->first_win; win < WINDOWS_NR ; win++) { struct exynos_drm_plane *plane = &ctx->planes[win]; if (!plane->pending_fb) @@ -554,16 +574,29 @@ static irqreturn_t decon_lcd_sys_irq_handler(int irq, void *dev_id) } /* clear */ - writel(VIDINTCON1_INTFRMDONEPEND, - ctx->addr + DECON_VIDINTCON1); + writel(val, ctx->addr + DECON_VIDINTCON1); } out: return IRQ_HANDLED; } +static const struct of_device_id exynos5433_decon_driver_dt_match[] = { + { + .compatible = "samsung,exynos5433-decon", + .data = (void *)IFTYPE_RGB + }, + { + .compatible = "samsung,exynos5433-decon-tv", + .data = (void *)IFTYPE_HDMI + }, + {}, +}; +MODULE_DEVICE_TABLE(of, exynos5433_decon_driver_dt_match); + static int exynos5433_decon_probe(struct platform_device *pdev) { + const struct of_device_id *of_id; struct device *dev = &pdev->dev; struct decon_context *ctx; struct resource *res; @@ -576,8 +609,14 @@ static int exynos5433_decon_probe(struct platform_device *pdev) __set_bit(BIT_SUSPENDED, &ctx->flags); ctx->dev = dev; - if (of_get_child_by_name(dev->of_node, "i80-if-timings")) - ctx->i80_if = true; + + of_id = of_match_device(exynos5433_decon_driver_dt_match, &pdev->dev); + ctx->out_type = (enum decon_iftype)of_id->data; + + if (ctx->out_type == IFTYPE_HDMI) + ctx->first_win = 1; + else if (of_get_child_by_name(dev->of_node, "i80-if-timings")) + ctx->out_type = IFTYPE_I80; for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) { struct clk *clk; @@ -602,15 +641,14 @@ static int exynos5433_decon_probe(struct platform_device *pdev) } res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, - ctx->i80_if ? "lcd_sys" : "vsync"); + (ctx->out_type == IFTYPE_I80) ? "lcd_sys" : "vsync"); if (!res) { dev_err(dev, "cannot find IRQ resource\n"); return -ENXIO; } - ret = devm_request_irq(dev, res->start, ctx->i80_if ? - decon_lcd_sys_irq_handler : decon_vsync_irq_handler, 0, - "drm_decon", ctx); + ret = devm_request_irq(dev, res->start, decon_irq_handler, 0, + "drm_decon", ctx); if (ret < 0) { dev_err(dev, "lcd_sys irq request failed\n"); return ret; @@ -641,12 +679,6 @@ static int exynos5433_decon_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id exynos5433_decon_driver_dt_match[] = { - { .compatible = "samsung,exynos5433-decon" }, - {}, -}; -MODULE_DEVICE_TABLE(of, exynos5433_decon_driver_dt_match); - struct platform_driver exynos5433_decon_driver = { .probe = exynos5433_decon_probe, .remove = exynos5433_decon_remove, diff --git a/include/video/exynos5433_decon.h b/include/video/exynos5433_decon.h index 3696575b02f2..c1c1ca18abc0 100644 --- a/include/video/exynos5433_decon.h +++ b/include/video/exynos5433_decon.h @@ -82,6 +82,8 @@ /* VIDCON0 */ #define VIDCON0_SWRESET (1 << 28) +#define VIDCON0_CLKVALUP (1 << 14) +#define VIDCON0_VLCKFREE (1 << 5) #define VIDCON0_STOP_STATUS (1 << 2) #define VIDCON0_ENVID (1 << 1) #define VIDCON0_ENVID_F (1 << 0) @@ -137,6 +139,13 @@ /* DECON_UPDATE */ #define STANDALONE_UPDATE_F (1 << 0) +/* DECON_VIDCON1 */ +#define VIDCON1_VCLK_MASK (0x3 << 9) +#define VIDCON1_VCLK_RUN_VDEN_DISABLE (0x3 << 9) +#define VIDCON1_VCLK_HOLD (0x0 << 9) +#define VIDCON1_VCLK_RUN (0x1 << 9) + + /* DECON_VIDTCON00 */ #define VIDTCON00_VBPD_F(x) (((x) & 0xfff) << 16) #define VIDTCON00_VFPD_F(x) ((x) & 0xfff) @@ -159,7 +168,27 @@ #define TRIGCON_TRIGEN_PER_F (1 << 31) #define TRIGCON_TRIGEN_F (1 << 30) #define TRIGCON_TE_AUTO_MASK (1 << 29) +#define TRIGCON_WB_SWTRIGCMD (1 << 28) +#define TRIGCON_SWTRIGCMD_W4BUF (1 << 26) +#define TRIGCON_TRIGMODE_W4BUF (1 << 25) +#define TRIGCON_SWTRIGCMD_W3BUF (1 << 21) +#define TRIGCON_TRIGMODE_W3BUF (1 << 20) +#define TRIGCON_SWTRIGCMD_W2BUF (1 << 16) +#define TRIGCON_TRIGMODE_W2BUF (1 << 15) +#define TRIGCON_SWTRIGCMD_W1BUF (1 << 11) +#define TRIGCON_TRIGMODE_W1BUF (1 << 10) +#define TRIGCON_SWTRIGCMD_W0BUF (1 << 6) +#define TRIGCON_TRIGMODE_W0BUF (1 << 5) +#define TRIGCON_HWTRIGMASK_I80_RGB (1 << 4) +#define TRIGCON_HWTRIGEN_I80_RGB (1 << 3) +#define TRIGCON_HWTRIG_INV_I80_RGB (1 << 2) #define TRIGCON_SWTRIGCMD (1 << 1) #define TRIGCON_SWTRIGEN (1 << 0) +/* DECON_CRCCTRL */ +#define CRCCTRL_CRCCLKEN (0x1 << 2) +#define CRCCTRL_CRCSTART_F (0x1 << 1) +#define CRCCTRL_CRCEN (0x1 << 0) +#define CRCCTRL_MASK (0x7) + #endif /* EXYNOS_REGS_DECON_H */ From 5625b3418a5bf977e3561bb12229d4c3e96b44d8 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 26 Oct 2015 13:03:39 +0100 Subject: [PATCH 27/34] drm/exynos: add atomic_check callback to exynos_crtc Some CRTCs needs mode validation, this patch adds neccessary callback to Exynos DRM framework. It is called from DRM core via atomic_check helper for drm_crtc. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 12 ++++++++++++ drivers/gpu/drm/exynos/exynos_drm_drv.h | 3 +++ 2 files changed, 15 insertions(+) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 50dec0df160f..b3ba27fd9a6b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -50,6 +50,17 @@ exynos_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) exynos_crtc->ops->commit(exynos_crtc); } +static int exynos_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + + if (exynos_crtc->ops->atomic_check) + return exynos_crtc->ops->atomic_check(exynos_crtc, state); + + return 0; +} + static void exynos_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { @@ -86,6 +97,7 @@ static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { .enable = exynos_drm_crtc_enable, .disable = exynos_drm_crtc_disable, .mode_set_nofb = exynos_drm_crtc_mode_set_nofb, + .atomic_check = exynos_crtc_atomic_check, .atomic_begin = exynos_crtc_atomic_begin, .atomic_flush = exynos_crtc_atomic_flush, }; diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 638fc43079a8..f1eda7fa4e3c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -89,6 +89,7 @@ struct exynos_drm_plane { * @disable_vblank: specific driver callback for disabling vblank interrupt. * @wait_for_vblank: wait for vblank interrupt to make sure that * hardware overlay is updated. + * @atomic_check: validate state * @atomic_begin: prepare a window to receive a update * @atomic_flush: mark the end of a window update * @update_plane: apply hardware specific overlay data to registers. @@ -108,6 +109,8 @@ struct exynos_drm_crtc_ops { int (*enable_vblank)(struct exynos_drm_crtc *crtc); void (*disable_vblank)(struct exynos_drm_crtc *crtc); void (*wait_for_vblank)(struct exynos_drm_crtc *crtc); + int (*atomic_check)(struct exynos_drm_crtc *crtc, + struct drm_crtc_state *state); void (*atomic_begin)(struct exynos_drm_crtc *crtc, struct exynos_drm_plane *plane); void (*update_plane)(struct exynos_drm_crtc *crtc, From 3ae24362e02df0aa27ed1dc9d85b720514c99d20 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 26 Oct 2015 13:03:40 +0100 Subject: [PATCH 28/34] drm/exynos/mixer: replace direct cross-driver call with drm mode validation HDMI driver called directly function from MIXER driver to invalidate modes not supported by MIXER. The patch replaces the hack with proper .atomic_check callback. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 5 ----- drivers/gpu/drm/exynos/exynos_mixer.c | 6 ++++-- drivers/gpu/drm/exynos/exynos_mixer.h | 20 -------------------- 3 files changed, 4 insertions(+), 27 deletions(-) delete mode 100644 drivers/gpu/drm/exynos/exynos_mixer.h diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index b0f5ff4e8620..57b675563e94 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -44,7 +44,6 @@ #include "exynos_drm_drv.h" #include "exynos_drm_crtc.h" -#include "exynos_mixer.h" #define HOTPLUG_DEBOUNCE_MS 1100 @@ -1017,10 +1016,6 @@ static int hdmi_mode_valid(struct drm_connector *connector, (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true : false, mode->clock * 1000); - ret = mixer_check_mode(mode); - if (ret) - return MODE_BAD; - ret = hdmi_find_phy_conf(hdata, mode->clock * 1000); if (ret < 0) return MODE_BAD; diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 3f9f07279a36..d09f8f9a8939 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -39,7 +39,6 @@ #include "exynos_drm_crtc.h" #include "exynos_drm_plane.h" #include "exynos_drm_iommu.h" -#include "exynos_mixer.h" #define MIXER_WIN_NR 3 #define VP_DEFAULT_WIN 2 @@ -1096,8 +1095,10 @@ static void mixer_disable(struct exynos_drm_crtc *crtc) } /* Only valid for Mixer version 16.0.33.0 */ -int mixer_check_mode(struct drm_display_mode *mode) +static int mixer_atomic_check(struct exynos_drm_crtc *crtc, + struct drm_crtc_state *state) { + struct drm_display_mode *mode = &state->adjusted_mode; u32 w, h; w = mode->hdisplay; @@ -1123,6 +1124,7 @@ static const struct exynos_drm_crtc_ops mixer_crtc_ops = { .wait_for_vblank = mixer_wait_for_vblank, .update_plane = mixer_update_plane, .disable_plane = mixer_disable_plane, + .atomic_check = mixer_atomic_check, }; static struct mixer_drv_data exynos5420_mxr_drv_data = { diff --git a/drivers/gpu/drm/exynos/exynos_mixer.h b/drivers/gpu/drm/exynos/exynos_mixer.h deleted file mode 100644 index 3811e417f0e9..000000000000 --- a/drivers/gpu/drm/exynos/exynos_mixer.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2013 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - */ - -#ifndef _EXYNOS_MIXER_H_ -#define _EXYNOS_MIXER_H_ - -/* This function returns 0 if the given timing is valid for the mixer */ -int mixer_check_mode(struct drm_display_mode *mode); - -#endif From 3cb02b4a9e3e4f71ca7fefaff96ae47dd42a0adc Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 26 Oct 2015 13:03:42 +0100 Subject: [PATCH 29/34] drm/exynos: separate Mixer and HDMI drivers Latest Exynos SoCs does not have Mixer IP, but they still have HDMI IP. Their drivers should be configurable separately. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/Kconfig | 8 +++++++- drivers/gpu/drm/exynos/Makefile | 3 ++- drivers/gpu/drm/exynos/exynos_drm_drv.c | 4 +++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index bd1a4156f647..1d7d9b843354 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -62,9 +62,15 @@ config DRM_EXYNOS_DP help This enables support for DP device. +config DRM_EXYNOS_MIXER + bool "Exynos DRM Mixer" + depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_TV + help + Choose this option if you want to use Exynos Mixer for DRM. + config DRM_EXYNOS_HDMI bool "Exynos DRM HDMI" - depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_TV + depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_TV && (DRM_EXYNOS_MIXER || DRM_EXYNOS5433_DECON) help Choose this option if you want to use Exynos HDMI for DRM. diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile index 02aecfed6354..6496532aaa91 100644 --- a/drivers/gpu/drm/exynos/Makefile +++ b/drivers/gpu/drm/exynos/Makefile @@ -14,7 +14,8 @@ exynosdrm-$(CONFIG_DRM_EXYNOS7_DECON) += exynos7_drm_decon.o exynosdrm-$(CONFIG_DRM_EXYNOS_DPI) += exynos_drm_dpi.o exynosdrm-$(CONFIG_DRM_EXYNOS_DSI) += exynos_drm_dsi.o exynosdrm-$(CONFIG_DRM_EXYNOS_DP) += exynos_dp_core.o exynos_dp_reg.o -exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o +exynosdrm-$(CONFIG_DRM_EXYNOS_MIXER) += exynos_mixer.o +exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI) += exynos_drm_vidi.o exynosdrm-$(CONFIG_DRM_EXYNOS_G2D) += exynos_drm_g2d.o exynosdrm-$(CONFIG_DRM_EXYNOS_IPP) += exynos_drm_ipp.o diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 09c4c6af8cd1..2c6019d6a205 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -529,8 +529,10 @@ static struct platform_driver *const exynos_drm_kms_drivers[] = { #ifdef CONFIG_DRM_EXYNOS_DSI &dsi_driver, #endif -#ifdef CONFIG_DRM_EXYNOS_HDMI +#ifdef CONFIG_DRM_EXYNOS_MIXER &mixer_driver, +#endif +#ifdef CONFIG_DRM_EXYNOS_HDMI &hdmi_driver, #endif #ifdef CONFIG_DRM_EXYNOS_VIDI From dba6c5280d62cef3df9c67cafaddf1c7df0d5889 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 26 Oct 2015 13:03:43 +0100 Subject: [PATCH 30/34] drm/exynos: abstract out common dependency All options depends on DRM_EXYNOS so it can be moved to enclosing if clause. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/Kconfig | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 1d7d9b843354..b0107f001937 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -11,14 +11,16 @@ config DRM_EXYNOS Choose this option if you have a Samsung SoC EXYNOS chipset. If M is selected the module will be called exynosdrm. +if DRM_EXYNOS + config DRM_EXYNOS_IOMMU bool - depends on DRM_EXYNOS && EXYNOS_IOMMU && ARM_DMA_USE_IOMMU + depends on EXYNOS_IOMMU && ARM_DMA_USE_IOMMU default y config DRM_EXYNOS_FIMD bool "Exynos DRM FIMD" - depends on DRM_EXYNOS && !FB_S3C + depends on !FB_S3C select FB_MODE_HELPERS select MFD_SYSCON help @@ -26,20 +28,19 @@ config DRM_EXYNOS_FIMD config DRM_EXYNOS5433_DECON bool "Exynos5433 DRM DECON" - depends on DRM_EXYNOS help Choose this option if you want to use Exynos5433 DECON for DRM. config DRM_EXYNOS7_DECON bool "Exynos7 DRM DECON" - depends on DRM_EXYNOS && !FB_S3C + depends on !FB_S3C select FB_MODE_HELPERS help Choose this option if you want to use Exynos DECON for DRM. config DRM_EXYNOS_DPI bool "EXYNOS DRM parallel output support" - depends on DRM_EXYNOS && (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON) + depends on DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON select DRM_PANEL default n help @@ -47,7 +48,7 @@ config DRM_EXYNOS_DPI config DRM_EXYNOS_DSI bool "EXYNOS DRM MIPI-DSI driver support" - depends on DRM_EXYNOS && (DRM_EXYNOS_FIMD || DRM_EXYNOS5433_DECON || DRM_EXYNOS7_DECON) + depends on DRM_EXYNOS_FIMD || DRM_EXYNOS5433_DECON || DRM_EXYNOS7_DECON select DRM_MIPI_DSI select DRM_PANEL default n @@ -56,7 +57,7 @@ config DRM_EXYNOS_DSI config DRM_EXYNOS_DP bool "EXYNOS DRM DP driver support" - depends on DRM_EXYNOS && (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON) + depends on DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON default DRM_EXYNOS select DRM_PANEL help @@ -64,32 +65,30 @@ config DRM_EXYNOS_DP config DRM_EXYNOS_MIXER bool "Exynos DRM Mixer" - depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_TV + depends on !VIDEO_SAMSUNG_S5P_TV help Choose this option if you want to use Exynos Mixer for DRM. config DRM_EXYNOS_HDMI bool "Exynos DRM HDMI" - depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_TV && (DRM_EXYNOS_MIXER || DRM_EXYNOS5433_DECON) + depends on !VIDEO_SAMSUNG_S5P_TV && (DRM_EXYNOS_MIXER || DRM_EXYNOS5433_DECON) help Choose this option if you want to use Exynos HDMI for DRM. config DRM_EXYNOS_VIDI bool "Exynos DRM Virtual Display" - depends on DRM_EXYNOS help Choose this option if you want to use Exynos VIDI for DRM. config DRM_EXYNOS_G2D bool "Exynos DRM G2D" - depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_G2D + depends on !VIDEO_SAMSUNG_S5P_G2D select FRAME_VECTOR help Choose this option if you want to use Exynos G2D for DRM. config DRM_EXYNOS_IPP bool "Exynos DRM IPP" - depends on DRM_EXYNOS help Choose this option if you want to use IPP feature for DRM. @@ -113,6 +112,8 @@ config DRM_EXYNOS_GSC config DRM_EXYNOS_MIC bool "Exynos DRM MIC" - depends on (DRM_EXYNOS && DRM_EXYNOS5433_DECON) + depends on DRM_EXYNOS5433_DECON help Choose this option if you want to use Exynos MIC for DRM. + +endif From ea9776465d8f1617c99ffe7f90aa245fba474544 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 26 Oct 2015 13:03:44 +0100 Subject: [PATCH 31/34] drm/exynos: re-arrange Kconfig entries Exynos DRM driver have quite big number of components and options. The patch re-arranges them into three logical groups: - CRTCs, - Encoders and Bridges, - Sub-drivers. It should make driver options more clear. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/Kconfig | 38 ++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index b0107f001937..b2d6cbd63d75 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -18,6 +18,8 @@ config DRM_EXYNOS_IOMMU depends on EXYNOS_IOMMU && ARM_DMA_USE_IOMMU default y +comment "CRTCs" + config DRM_EXYNOS_FIMD bool "Exynos DRM FIMD" depends on !FB_S3C @@ -38,9 +40,22 @@ config DRM_EXYNOS7_DECON help Choose this option if you want to use Exynos DECON for DRM. +config DRM_EXYNOS_MIXER + bool "Exynos DRM Mixer" + depends on !VIDEO_SAMSUNG_S5P_TV + help + Choose this option if you want to use Exynos Mixer for DRM. + +config DRM_EXYNOS_VIDI + bool "Exynos DRM Virtual Display" + help + Choose this option if you want to use Exynos VIDI for DRM. + +comment "Encoders and Bridges" + config DRM_EXYNOS_DPI bool "EXYNOS DRM parallel output support" - depends on DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON + depends on DRM_EXYNOS_FIMD select DRM_PANEL default n help @@ -63,22 +78,19 @@ config DRM_EXYNOS_DP help This enables support for DP device. -config DRM_EXYNOS_MIXER - bool "Exynos DRM Mixer" - depends on !VIDEO_SAMSUNG_S5P_TV - help - Choose this option if you want to use Exynos Mixer for DRM. - config DRM_EXYNOS_HDMI bool "Exynos DRM HDMI" depends on !VIDEO_SAMSUNG_S5P_TV && (DRM_EXYNOS_MIXER || DRM_EXYNOS5433_DECON) help Choose this option if you want to use Exynos HDMI for DRM. -config DRM_EXYNOS_VIDI - bool "Exynos DRM Virtual Display" +config DRM_EXYNOS_MIC + bool "Exynos DRM MIC" + depends on DRM_EXYNOS5433_DECON help - Choose this option if you want to use Exynos VIDI for DRM. + Choose this option if you want to use Exynos MIC for DRM. + +comment "Sub-drivers" config DRM_EXYNOS_G2D bool "Exynos DRM G2D" @@ -110,10 +122,4 @@ config DRM_EXYNOS_GSC help Choose this option if you want to use Exynos GSC for DRM. -config DRM_EXYNOS_MIC - bool "Exynos DRM MIC" - depends on DRM_EXYNOS5433_DECON - help - Choose this option if you want to use Exynos MIC for DRM. - endif From 5a3c35b377ce5b1d438792ee4ebb8e6222dcd50d Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 26 Oct 2015 13:03:45 +0100 Subject: [PATCH 32/34] drm/exynos: simplify Kconfig component names Many Exynos DRM sub-options mentions Exynos DRM in their titles. It is redundant and can be safely shortened. The patch additionally makes some entries more descriptive. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/Kconfig | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index b2d6cbd63d75..96e86cf4455b 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -21,7 +21,7 @@ config DRM_EXYNOS_IOMMU comment "CRTCs" config DRM_EXYNOS_FIMD - bool "Exynos DRM FIMD" + bool "FIMD" depends on !FB_S3C select FB_MODE_HELPERS select MFD_SYSCON @@ -29,32 +29,32 @@ config DRM_EXYNOS_FIMD Choose this option if you want to use Exynos FIMD for DRM. config DRM_EXYNOS5433_DECON - bool "Exynos5433 DRM DECON" + bool "DECON on Exynos5433" help Choose this option if you want to use Exynos5433 DECON for DRM. config DRM_EXYNOS7_DECON - bool "Exynos7 DRM DECON" + bool "DECON on Exynos7" depends on !FB_S3C select FB_MODE_HELPERS help Choose this option if you want to use Exynos DECON for DRM. config DRM_EXYNOS_MIXER - bool "Exynos DRM Mixer" + bool "Mixer" depends on !VIDEO_SAMSUNG_S5P_TV help Choose this option if you want to use Exynos Mixer for DRM. config DRM_EXYNOS_VIDI - bool "Exynos DRM Virtual Display" + bool "Virtual Display" help Choose this option if you want to use Exynos VIDI for DRM. comment "Encoders and Bridges" config DRM_EXYNOS_DPI - bool "EXYNOS DRM parallel output support" + bool "Parallel output" depends on DRM_EXYNOS_FIMD select DRM_PANEL default n @@ -62,7 +62,7 @@ config DRM_EXYNOS_DPI This enables support for Exynos parallel output. config DRM_EXYNOS_DSI - bool "EXYNOS DRM MIPI-DSI driver support" + bool "MIPI-DSI host" depends on DRM_EXYNOS_FIMD || DRM_EXYNOS5433_DECON || DRM_EXYNOS7_DECON select DRM_MIPI_DSI select DRM_PANEL @@ -71,7 +71,7 @@ config DRM_EXYNOS_DSI This enables support for Exynos MIPI-DSI device. config DRM_EXYNOS_DP - bool "EXYNOS DRM DP driver support" + bool "Display Port" depends on DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON default DRM_EXYNOS select DRM_PANEL @@ -79,13 +79,13 @@ config DRM_EXYNOS_DP This enables support for DP device. config DRM_EXYNOS_HDMI - bool "Exynos DRM HDMI" + bool "HDMI" depends on !VIDEO_SAMSUNG_S5P_TV && (DRM_EXYNOS_MIXER || DRM_EXYNOS5433_DECON) help Choose this option if you want to use Exynos HDMI for DRM. config DRM_EXYNOS_MIC - bool "Exynos DRM MIC" + bool "Mobile Image Compressor" depends on DRM_EXYNOS5433_DECON help Choose this option if you want to use Exynos MIC for DRM. @@ -93,31 +93,31 @@ config DRM_EXYNOS_MIC comment "Sub-drivers" config DRM_EXYNOS_G2D - bool "Exynos DRM G2D" + bool "G2D" depends on !VIDEO_SAMSUNG_S5P_G2D select FRAME_VECTOR help Choose this option if you want to use Exynos G2D for DRM. config DRM_EXYNOS_IPP - bool "Exynos DRM IPP" + bool "Image Post Processor" help Choose this option if you want to use IPP feature for DRM. config DRM_EXYNOS_FIMC - bool "Exynos DRM FIMC" + bool "FIMC" depends on DRM_EXYNOS_IPP && MFD_SYSCON help Choose this option if you want to use Exynos FIMC for DRM. config DRM_EXYNOS_ROTATOR - bool "Exynos DRM Rotator" + bool "Rotator" depends on DRM_EXYNOS_IPP help Choose this option if you want to use Exynos Rotator for DRM. config DRM_EXYNOS_GSC - bool "Exynos DRM GSC" + bool "GScaler" depends on DRM_EXYNOS_IPP && ARCH_EXYNOS5 && !ARCH_MULTIPLATFORM help Choose this option if you want to use Exynos GSC for DRM. From 01351315465fe58b9ab990554467773367f74cab Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 26 Oct 2015 13:03:41 +0100 Subject: [PATCH 33/34] ARM: exynos_defconfig: enable Exynos DRM Mixer driver Mixer driver is selected by CONFIG_DRM_EXYNOS_HDMI option. Since Exynos5433 HDMI does not require Mixer. There will be separate options to select Mixer and HDMI. Adding new option to defconfig before Kconfig will allow to keep bisectability. Signed-off-by: Andrzej Hajda Reviewed-by: Krzysztof Kozlowski Acked-by: Krzysztof Kozlowski Signed-off-by: Inki Dae --- arch/arm/configs/exynos_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/exynos_defconfig b/arch/arm/configs/exynos_defconfig index 1ff2bfa2e183..af79a2166f40 100644 --- a/arch/arm/configs/exynos_defconfig +++ b/arch/arm/configs/exynos_defconfig @@ -132,6 +132,7 @@ CONFIG_DRM_PARADE_PS8622=y CONFIG_DRM_EXYNOS=y CONFIG_DRM_EXYNOS_FIMD=y CONFIG_DRM_EXYNOS_DSI=y +CONFIG_DRM_EXYNOS_MIXER=y CONFIG_DRM_EXYNOS_HDMI=y CONFIG_DRM_PANEL_SIMPLE=y CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=y From df547bf7735a623500eedff9cc6716ac1d82b95d Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Tue, 13 Oct 2015 13:47:20 +0200 Subject: [PATCH 34/34] drm/exynos/gem: remove DMA-mapping hacks used for constructing page array Exynos GEM objects contains an array of pointers to the pages, which the allocated buffer consists of. Till now the code used some hacks (like relying on DMA-mapping internal structures or using ARM-specific dma_to_pfn helper) to build this array. This patch fixes this by adding proper call to dma_get_sgtable_attrs() and using the acquired scatter-list to construct needed array. This approach is more portable (work also for ARM64) and finally fixes the layering violation that was present in this code. Signed-off-by: Marek Szyprowski Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_gem.c | 58 ++++++++++++++----------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index f1dcdd086886..252eb301470c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -25,6 +25,8 @@ static int exynos_drm_alloc_buf(struct exynos_drm_gem *exynos_gem) struct drm_device *dev = exynos_gem->base.dev; enum dma_attr attr; unsigned int nr_pages; + struct sg_table sgt; + int ret = -ENOMEM; if (exynos_gem->dma_addr) { DRM_DEBUG_KMS("already allocated.\n"); @@ -56,13 +58,10 @@ static int exynos_drm_alloc_buf(struct exynos_drm_gem *exynos_gem) nr_pages = exynos_gem->size >> PAGE_SHIFT; - if (!is_drm_iommu_supported(dev)) { - exynos_gem->pages = drm_calloc_large(nr_pages, - sizeof(struct page *)); - if (!exynos_gem->pages) { - DRM_ERROR("failed to allocate pages.\n"); - return -ENOMEM; - } + exynos_gem->pages = drm_calloc_large(nr_pages, sizeof(struct page *)); + if (!exynos_gem->pages) { + DRM_ERROR("failed to allocate pages.\n"); + return -ENOMEM; } exynos_gem->cookie = dma_alloc_attrs(dev->dev, exynos_gem->size, @@ -70,30 +69,40 @@ static int exynos_drm_alloc_buf(struct exynos_drm_gem *exynos_gem) &exynos_gem->dma_attrs); if (!exynos_gem->cookie) { DRM_ERROR("failed to allocate buffer.\n"); - if (exynos_gem->pages) - drm_free_large(exynos_gem->pages); - return -ENOMEM; + goto err_free; } - if (exynos_gem->pages) { - dma_addr_t start_addr; - unsigned int i = 0; - - start_addr = exynos_gem->dma_addr; - while (i < nr_pages) { - exynos_gem->pages[i] = - pfn_to_page(dma_to_pfn(dev->dev, start_addr)); - start_addr += PAGE_SIZE; - i++; - } - } else { - exynos_gem->pages = exynos_gem->cookie; + ret = dma_get_sgtable_attrs(dev->dev, &sgt, exynos_gem->cookie, + exynos_gem->dma_addr, exynos_gem->size, + &exynos_gem->dma_attrs); + if (ret < 0) { + DRM_ERROR("failed to get sgtable.\n"); + goto err_dma_free; } + if (drm_prime_sg_to_page_addr_arrays(&sgt, exynos_gem->pages, NULL, + nr_pages)) { + DRM_ERROR("invalid sgtable.\n"); + ret = -EINVAL; + goto err_sgt_free; + } + + sg_free_table(&sgt); + DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n", (unsigned long)exynos_gem->dma_addr, exynos_gem->size); return 0; + +err_sgt_free: + sg_free_table(&sgt); +err_dma_free: + dma_free_attrs(dev->dev, exynos_gem->size, exynos_gem->cookie, + exynos_gem->dma_addr, &exynos_gem->dma_attrs); +err_free: + drm_free_large(exynos_gem->pages); + + return ret; } static void exynos_drm_free_buf(struct exynos_drm_gem *exynos_gem) @@ -112,8 +121,7 @@ static void exynos_drm_free_buf(struct exynos_drm_gem *exynos_gem) (dma_addr_t)exynos_gem->dma_addr, &exynos_gem->dma_attrs); - if (!is_drm_iommu_supported(dev)) - drm_free_large(exynos_gem->pages); + drm_free_large(exynos_gem->pages); } static int exynos_drm_gem_handle_create(struct drm_gem_object *obj,