diff options
author | Dave Airlie <airlied@redhat.com> | 2017-02-08 11:34:56 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2017-02-08 11:34:56 +1000 |
commit | f864b00e03a0308beae7c88e2e145a429d5872dd (patch) | |
tree | 0b92a75bcab2e841871499562897b688afa55a70 /drivers/gpu | |
parent | 4eaa39c63caf535dc1a8cc43b9a8677a100c09e1 (diff) | |
parent | 7ff093d09f8f027c317282e18b566473df53e8a1 (diff) |
Merge branch 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next
Summary:
- Add UHD support on TM2/TM2E boards.
. adding interlace mode support and 297MHz pixel clock support
for UHD mode, setting sysreg register in case of HW trigger mode,
and adding SiI8620 MHL bridge device support.
- Fix trigger mode issue on Rinato board.
. On Rinato board, HW trigger mode doesn't work so fix it.
- Some fixup and cleanup.
* 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos:
drm/exynos: fimd: Do not use HW trigger for exynos3250
drm/exynos/hdmi: add bridge support
drm/exynos/decon5433: signal vblank only on odd fields
drm/exynos/decon5433: add support for interlace modes
drm/exynos/hdmi: fix PLL for 27MHz settings
drm/exynos/hdmi: fix VSI infoframe registers
drm/exynos/hdmi: add 297MHz pixel clock support
drm/exynos: g2d: change platform driver name to 'exynos-drm-g2d'
drm/exynos/decon5433: configure sysreg in case of hardware trigger
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 92 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fimd.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_g2d.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_hdmi.c | 80 |
4 files changed, 135 insertions, 41 deletions
diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index d69af00bdd6a..0fd6f7a18364 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -13,9 +13,11 @@ #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/component.h> +#include <linux/mfd/syscon.h> #include <linux/of_device.h> #include <linux/of_gpio.h> #include <linux/pm_runtime.h> +#include <linux/regmap.h> #include <video/exynos5433_decon.h> @@ -25,6 +27,9 @@ #include "exynos_drm_plane.h" #include "exynos_drm_iommu.h" +#define DSD_CFG_MUX 0x1004 +#define DSD_CFG_MUX_TE_UNMASK_GLOBAL BIT(13) + #define WINDOWS_NR 3 #define MIN_FB_WIDTH_FOR_16WORD_BURST 128 @@ -57,6 +62,7 @@ struct decon_context { struct exynos_drm_plane planes[WINDOWS_NR]; struct exynos_drm_plane_config configs[WINDOWS_NR]; void __iomem *addr; + struct regmap *sysreg; struct clk *clks[ARRAY_SIZE(decon_clks_name)]; int pipe; unsigned long flags; @@ -118,18 +124,29 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc) static void decon_setup_trigger(struct decon_context *ctx) { - u32 val = !(ctx->out_type & I80_HW_TRG) - ? TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F | - TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN - : TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F | - TRIGCON_HWTRIGMASK | TRIGCON_HWTRIGEN; - writel(val, ctx->addr + DECON_TRIGCON); + if (!(ctx->out_type & (IFTYPE_I80 | I80_HW_TRG))) + return; + + if (!(ctx->out_type & I80_HW_TRG)) { + writel(TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN + | TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN, + ctx->addr + DECON_TRIGCON); + return; + } + + writel(TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F | TRIGCON_HWTRIGMASK + | TRIGCON_HWTRIGEN, ctx->addr + DECON_TRIGCON); + + if (regmap_update_bits(ctx->sysreg, DSD_CFG_MUX, + DSD_CFG_MUX_TE_UNMASK_GLOBAL, ~0)) + DRM_ERROR("Cannot update sysreg.\n"); } static void decon_commit(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; struct drm_display_mode *m = &crtc->base.mode; + bool interlaced = false; u32 val; if (test_bit(BIT_SUSPENDED, &ctx->flags)) @@ -140,13 +157,16 @@ static void decon_commit(struct exynos_drm_crtc *crtc) 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; + if (m->flags & DRM_MODE_FLAG_INTERLACE) + interlaced = true; } - if (ctx->out_type & (IFTYPE_I80 | I80_HW_TRG)) - decon_setup_trigger(ctx); + decon_setup_trigger(ctx); /* lcd on and use command if */ val = VIDOUT_LCD_ON; + if (interlaced) + val |= VIDOUT_INTERLACE_EN_F; if (ctx->out_type & IFTYPE_I80) { val |= VIDOUT_COMMAND_IF; } else { @@ -155,15 +175,21 @@ static void decon_commit(struct exynos_drm_crtc *crtc) writel(val, ctx->addr + DECON_VIDOUTCON0); - val = VIDTCON2_LINEVAL(m->vdisplay - 1) | - VIDTCON2_HOZVAL(m->hdisplay - 1); + if (interlaced) + val = VIDTCON2_LINEVAL(m->vdisplay / 2 - 1) | + VIDTCON2_HOZVAL(m->hdisplay - 1); + else + val = VIDTCON2_LINEVAL(m->vdisplay - 1) | + VIDTCON2_HOZVAL(m->hdisplay - 1); writel(val, ctx->addr + DECON_VIDTCON2); if (!(ctx->out_type & IFTYPE_I80)) { - val = VIDTCON00_VBPD_F( - m->crtc_vtotal - m->crtc_vsync_end - 1) | - VIDTCON00_VFPD_F( - m->crtc_vsync_start - m->crtc_vdisplay - 1); + int vbp = m->crtc_vtotal - m->crtc_vsync_end; + int vfp = m->crtc_vsync_start - m->crtc_vdisplay; + + if (interlaced) + vbp = vbp / 2 - 1; + val = VIDTCON00_VBPD_F(vbp - 1) | VIDTCON00_VFPD_F(vfp - 1); writel(val, ctx->addr + DECON_VIDTCON00); val = VIDTCON01_VSPW_F( @@ -278,12 +304,22 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, if (test_bit(BIT_SUSPENDED, &ctx->flags)) return; - val = COORDINATE_X(state->crtc.x) | COORDINATE_Y(state->crtc.y); - writel(val, ctx->addr + DECON_VIDOSDxA(win)); + if (crtc->base.mode.flags & DRM_MODE_FLAG_INTERLACE) { + val = COORDINATE_X(state->crtc.x) | + COORDINATE_Y(state->crtc.y / 2); + writel(val, ctx->addr + DECON_VIDOSDxA(win)); + + val = COORDINATE_X(state->crtc.x + state->crtc.w - 1) | + COORDINATE_Y((state->crtc.y + state->crtc.h) / 2 - 1); + writel(val, ctx->addr + DECON_VIDOSDxB(win)); + } else { + val = COORDINATE_X(state->crtc.x) | COORDINATE_Y(state->crtc.y); + writel(val, ctx->addr + DECON_VIDOSDxA(win)); - val = COORDINATE_X(state->crtc.x + state->crtc.w - 1) | - COORDINATE_Y(state->crtc.y + state->crtc.h - 1); - writel(val, ctx->addr + DECON_VIDOSDxB(win)); + val = COORDINATE_X(state->crtc.x + state->crtc.w - 1) | + COORDINATE_Y(state->crtc.y + state->crtc.h - 1); + writel(val, ctx->addr + DECON_VIDOSDxB(win)); + } val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | VIDOSD_Wx_ALPHA_B_F(0x0); @@ -355,8 +391,6 @@ static void decon_swreset(struct decon_context *ctx) udelay(10); } - WARN(tries == 0, "failed to disable DECON\n"); - writel(VIDCON0_SWRESET, ctx->addr + DECON_VIDCON0); for (tries = 2000; tries; --tries) { if (~readl(ctx->addr + DECON_VIDCON0) & VIDCON0_SWRESET) @@ -557,6 +591,13 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id) if (val) { writel(val, ctx->addr + DECON_VIDINTCON1); + if (ctx->out_type & IFTYPE_HDMI) { + val = readl(ctx->addr + DECON_VIDOUTCON0); + val &= VIDOUT_INTERLACE_EN_F | VIDOUT_INTERLACE_FIELD_F; + if (val == + (VIDOUT_INTERLACE_EN_F | VIDOUT_INTERLACE_FIELD_F)) + return IRQ_HANDLED; + } drm_crtc_handle_vblank(&ctx->crtc->base); } @@ -637,6 +678,15 @@ static int exynos5433_decon_probe(struct platform_device *pdev) ctx->out_type |= IFTYPE_I80; } + if (ctx->out_type | I80_HW_TRG) { + ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node, + "samsung,disp-sysreg"); + if (IS_ERR(ctx->sysreg)) { + dev_err(dev, "failed to get system register\n"); + return PTR_ERR(ctx->sysreg); + } + } + for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) { struct clk *clk; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 745cfbdf6b39..a9fa444c6053 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -125,10 +125,8 @@ static struct fimd_driver_data exynos3_fimd_driver_data = { .timing_base = 0x20000, .lcdblk_offset = 0x210, .lcdblk_bypass_shift = 1, - .trg_type = I80_HW_TRG, .has_shadowcon = 1, .has_vidoutcon = 1, - .has_trigger_per_te = 1, }; static struct fimd_driver_data exynos4_fimd_driver_data = { diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 603d8425cca6..2b8bf2dd6387 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -1683,7 +1683,7 @@ struct platform_driver g2d_driver = { .probe = g2d_probe, .remove = g2d_remove, .driver = { - .name = "s5p-g2d", + .name = "exynos-drm-g2d", .owner = THIS_MODULE, .pm = &g2d_pm_ops, .of_match_table = exynos_g2d_match, diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 5ed8b1effe71..88ccc0469316 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -35,6 +35,7 @@ #include <linux/io.h> #include <linux/of_address.h> #include <linux/of_device.h> +#include <linux/of_graph.h> #include <linux/hdmi.h> #include <linux/component.h> #include <linux/mfd/syscon.h> @@ -133,6 +134,7 @@ struct hdmi_context { struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)]; struct regulator *reg_hdmi_en; struct exynos_drm_clk phy_clk; + struct drm_bridge *bridge; }; static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e) @@ -509,9 +511,9 @@ static const struct hdmiphy_config hdmiphy_5433_configs[] = { { .pixel_clock = 27000000, .conf = { - 0x01, 0x51, 0x22, 0x51, 0x08, 0xfc, 0x88, 0x46, - 0x72, 0x50, 0x24, 0x0c, 0x24, 0x0f, 0x7c, 0xa5, - 0xd4, 0x2b, 0x87, 0x00, 0x00, 0x04, 0x00, 0x30, + 0x01, 0x51, 0x2d, 0x75, 0x01, 0x00, 0x88, 0x02, + 0x72, 0x50, 0x44, 0x8c, 0x27, 0x00, 0x7c, 0xac, + 0xd6, 0x2b, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30, 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40, }, }, @@ -519,9 +521,9 @@ static const struct hdmiphy_config hdmiphy_5433_configs[] = { .pixel_clock = 27027000, .conf = { 0x01, 0x51, 0x2d, 0x72, 0x64, 0x09, 0x88, 0xc3, - 0x71, 0x50, 0x24, 0x14, 0x24, 0x0f, 0x7c, 0xa5, - 0xd4, 0x2b, 0x87, 0x00, 0x00, 0x04, 0x00, 0x30, - 0x28, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40, + 0x71, 0x50, 0x44, 0x8c, 0x27, 0x00, 0x7c, 0xac, + 0xd6, 0x2b, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30, + 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40, }, }, { @@ -587,6 +589,15 @@ static const struct hdmiphy_config hdmiphy_5433_configs[] = { 0x08, 0x10, 0x01, 0x01, 0x48, 0x4a, 0x00, 0x40, }, }, + { + .pixel_clock = 297000000, + .conf = { + 0x01, 0x51, 0x3E, 0x05, 0x40, 0xF0, 0x88, 0xC2, + 0x52, 0x53, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC, + 0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30, + 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40, + }, + }, }; static const char * const hdmi_clk_gates4[] = { @@ -788,7 +799,8 @@ static void hdmi_reg_infoframes(struct hdmi_context *hdata) sizeof(buf)); if (ret > 0) { hdmi_reg_writeb(hdata, HDMI_VSI_CON, HDMI_VSI_CON_EVERY_VSYNC); - hdmi_reg_write_buf(hdata, HDMI_VSI_HEADER0, buf, ret); + hdmi_reg_write_buf(hdata, HDMI_VSI_HEADER0, buf, 3); + hdmi_reg_write_buf(hdata, HDMI_VSI_DATA(0), buf + 3, ret - 3); } ret = hdmi_audio_infoframe_init(&frm.audio); @@ -912,7 +924,15 @@ static int hdmi_create_connector(struct drm_encoder *encoder) drm_connector_register(connector); drm_mode_connector_attach_encoder(connector, encoder); - return 0; + if (hdata->bridge) { + encoder->bridge = hdata->bridge; + hdata->bridge->encoder = encoder; + ret = drm_bridge_attach(encoder, hdata->bridge, NULL); + if (ret) + DRM_ERROR("Failed to attach bridge\n"); + } + + return ret; } static bool hdmi_mode_fixup(struct drm_encoder *encoder, @@ -1581,6 +1601,31 @@ static void hdmiphy_clk_enable(struct exynos_drm_clk *clk, bool enable) hdmiphy_disable(hdata); } +static int hdmi_bridge_init(struct hdmi_context *hdata) +{ + struct device *dev = hdata->dev; + struct device_node *ep, *np; + + ep = of_graph_get_endpoint_by_regs(dev->of_node, 1, -1); + if (!ep) + return 0; + + np = of_graph_get_remote_port_parent(ep); + of_node_put(ep); + if (!np) { + DRM_ERROR("failed to get remote port parent"); + return -EINVAL; + } + + hdata->bridge = of_drm_find_bridge(np); + of_node_put(np); + + if (!hdata->bridge) + return -EPROBE_DEFER; + + return 0; +} + static int hdmi_resources_init(struct hdmi_context *hdata) { struct device *dev = hdata->dev; @@ -1620,17 +1665,18 @@ static int hdmi_resources_init(struct hdmi_context *hdata) hdata->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en"); - if (PTR_ERR(hdata->reg_hdmi_en) == -ENODEV) - return 0; + if (PTR_ERR(hdata->reg_hdmi_en) != -ENODEV) { + if (IS_ERR(hdata->reg_hdmi_en)) + return PTR_ERR(hdata->reg_hdmi_en); - if (IS_ERR(hdata->reg_hdmi_en)) - return PTR_ERR(hdata->reg_hdmi_en); - - ret = regulator_enable(hdata->reg_hdmi_en); - if (ret) - DRM_ERROR("failed to enable hdmi-en regulator\n"); + ret = regulator_enable(hdata->reg_hdmi_en); + if (ret) { + DRM_ERROR("failed to enable hdmi-en regulator\n"); + return ret; + } + } - return ret; + return hdmi_bridge_init(hdata); } static struct of_device_id hdmi_match_types[] = { |