Commit f864b00e authored by Dave Airlie's avatar Dave Airlie

Merge branch 'exynos-drm-next' of...

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
parents 4eaa39c6 7ff093d0
...@@ -13,9 +13,11 @@ ...@@ -13,9 +13,11 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/component.h> #include <linux/component.h>
#include <linux/mfd/syscon.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <video/exynos5433_decon.h> #include <video/exynos5433_decon.h>
...@@ -25,6 +27,9 @@ ...@@ -25,6 +27,9 @@
#include "exynos_drm_plane.h" #include "exynos_drm_plane.h"
#include "exynos_drm_iommu.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 WINDOWS_NR 3
#define MIN_FB_WIDTH_FOR_16WORD_BURST 128 #define MIN_FB_WIDTH_FOR_16WORD_BURST 128
...@@ -57,6 +62,7 @@ struct decon_context { ...@@ -57,6 +62,7 @@ struct decon_context {
struct exynos_drm_plane planes[WINDOWS_NR]; struct exynos_drm_plane planes[WINDOWS_NR];
struct exynos_drm_plane_config configs[WINDOWS_NR]; struct exynos_drm_plane_config configs[WINDOWS_NR];
void __iomem *addr; void __iomem *addr;
struct regmap *sysreg;
struct clk *clks[ARRAY_SIZE(decon_clks_name)]; struct clk *clks[ARRAY_SIZE(decon_clks_name)];
int pipe; int pipe;
unsigned long flags; unsigned long flags;
...@@ -118,18 +124,29 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc) ...@@ -118,18 +124,29 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc)
static void decon_setup_trigger(struct decon_context *ctx) static void decon_setup_trigger(struct decon_context *ctx)
{ {
u32 val = !(ctx->out_type & I80_HW_TRG) if (!(ctx->out_type & (IFTYPE_I80 | I80_HW_TRG)))
? TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F | return;
TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN
: TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F | if (!(ctx->out_type & I80_HW_TRG)) {
TRIGCON_HWTRIGMASK | TRIGCON_HWTRIGEN; writel(TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN
writel(val, ctx->addr + DECON_TRIGCON); | 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) static void decon_commit(struct exynos_drm_crtc *crtc)
{ {
struct decon_context *ctx = crtc->ctx; struct decon_context *ctx = crtc->ctx;
struct drm_display_mode *m = &crtc->base.mode; struct drm_display_mode *m = &crtc->base.mode;
bool interlaced = false;
u32 val; u32 val;
if (test_bit(BIT_SUSPENDED, &ctx->flags)) if (test_bit(BIT_SUSPENDED, &ctx->flags))
...@@ -140,13 +157,16 @@ static void decon_commit(struct exynos_drm_crtc *crtc) ...@@ -140,13 +157,16 @@ static void decon_commit(struct exynos_drm_crtc *crtc)
m->crtc_hsync_end = m->crtc_htotal - 92; m->crtc_hsync_end = m->crtc_htotal - 92;
m->crtc_vsync_start = m->crtc_vdisplay + 1; m->crtc_vsync_start = m->crtc_vdisplay + 1;
m->crtc_vsync_end = m->crtc_vsync_start + 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 */ /* lcd on and use command if */
val = VIDOUT_LCD_ON; val = VIDOUT_LCD_ON;
if (interlaced)
val |= VIDOUT_INTERLACE_EN_F;
if (ctx->out_type & IFTYPE_I80) { if (ctx->out_type & IFTYPE_I80) {
val |= VIDOUT_COMMAND_IF; val |= VIDOUT_COMMAND_IF;
} else { } else {
...@@ -155,15 +175,21 @@ static void decon_commit(struct exynos_drm_crtc *crtc) ...@@ -155,15 +175,21 @@ static void decon_commit(struct exynos_drm_crtc *crtc)
writel(val, ctx->addr + DECON_VIDOUTCON0); writel(val, ctx->addr + DECON_VIDOUTCON0);
if (interlaced)
val = VIDTCON2_LINEVAL(m->vdisplay / 2 - 1) |
VIDTCON2_HOZVAL(m->hdisplay - 1);
else
val = VIDTCON2_LINEVAL(m->vdisplay - 1) | val = VIDTCON2_LINEVAL(m->vdisplay - 1) |
VIDTCON2_HOZVAL(m->hdisplay - 1); VIDTCON2_HOZVAL(m->hdisplay - 1);
writel(val, ctx->addr + DECON_VIDTCON2); writel(val, ctx->addr + DECON_VIDTCON2);
if (!(ctx->out_type & IFTYPE_I80)) { if (!(ctx->out_type & IFTYPE_I80)) {
val = VIDTCON00_VBPD_F( int vbp = m->crtc_vtotal - m->crtc_vsync_end;
m->crtc_vtotal - m->crtc_vsync_end - 1) | int vfp = m->crtc_vsync_start - m->crtc_vdisplay;
VIDTCON00_VFPD_F(
m->crtc_vsync_start - m->crtc_vdisplay - 1); if (interlaced)
vbp = vbp / 2 - 1;
val = VIDTCON00_VBPD_F(vbp - 1) | VIDTCON00_VFPD_F(vfp - 1);
writel(val, ctx->addr + DECON_VIDTCON00); writel(val, ctx->addr + DECON_VIDTCON00);
val = VIDTCON01_VSPW_F( val = VIDTCON01_VSPW_F(
...@@ -278,12 +304,22 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, ...@@ -278,12 +304,22 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
if (test_bit(BIT_SUSPENDED, &ctx->flags)) if (test_bit(BIT_SUSPENDED, &ctx->flags))
return; return;
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); val = COORDINATE_X(state->crtc.x) | COORDINATE_Y(state->crtc.y);
writel(val, ctx->addr + DECON_VIDOSDxA(win)); writel(val, ctx->addr + DECON_VIDOSDxA(win));
val = COORDINATE_X(state->crtc.x + state->crtc.w - 1) | val = COORDINATE_X(state->crtc.x + state->crtc.w - 1) |
COORDINATE_Y(state->crtc.y + state->crtc.h - 1); COORDINATE_Y(state->crtc.y + state->crtc.h - 1);
writel(val, ctx->addr + DECON_VIDOSDxB(win)); writel(val, ctx->addr + DECON_VIDOSDxB(win));
}
val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) |
VIDOSD_Wx_ALPHA_B_F(0x0); VIDOSD_Wx_ALPHA_B_F(0x0);
...@@ -355,8 +391,6 @@ static void decon_swreset(struct decon_context *ctx) ...@@ -355,8 +391,6 @@ static void decon_swreset(struct decon_context *ctx)
udelay(10); udelay(10);
} }
WARN(tries == 0, "failed to disable DECON\n");
writel(VIDCON0_SWRESET, ctx->addr + DECON_VIDCON0); writel(VIDCON0_SWRESET, ctx->addr + DECON_VIDCON0);
for (tries = 2000; tries; --tries) { for (tries = 2000; tries; --tries) {
if (~readl(ctx->addr + DECON_VIDCON0) & VIDCON0_SWRESET) if (~readl(ctx->addr + DECON_VIDCON0) & VIDCON0_SWRESET)
...@@ -557,6 +591,13 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id) ...@@ -557,6 +591,13 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
if (val) { if (val) {
writel(val, ctx->addr + DECON_VIDINTCON1); 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); drm_crtc_handle_vblank(&ctx->crtc->base);
} }
...@@ -637,6 +678,15 @@ static int exynos5433_decon_probe(struct platform_device *pdev) ...@@ -637,6 +678,15 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
ctx->out_type |= IFTYPE_I80; 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++) { for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) {
struct clk *clk; struct clk *clk;
......
...@@ -125,10 +125,8 @@ static struct fimd_driver_data exynos3_fimd_driver_data = { ...@@ -125,10 +125,8 @@ static struct fimd_driver_data exynos3_fimd_driver_data = {
.timing_base = 0x20000, .timing_base = 0x20000,
.lcdblk_offset = 0x210, .lcdblk_offset = 0x210,
.lcdblk_bypass_shift = 1, .lcdblk_bypass_shift = 1,
.trg_type = I80_HW_TRG,
.has_shadowcon = 1, .has_shadowcon = 1,
.has_vidoutcon = 1, .has_vidoutcon = 1,
.has_trigger_per_te = 1,
}; };
static struct fimd_driver_data exynos4_fimd_driver_data = { static struct fimd_driver_data exynos4_fimd_driver_data = {
......
...@@ -1683,7 +1683,7 @@ struct platform_driver g2d_driver = { ...@@ -1683,7 +1683,7 @@ struct platform_driver g2d_driver = {
.probe = g2d_probe, .probe = g2d_probe,
.remove = g2d_remove, .remove = g2d_remove,
.driver = { .driver = {
.name = "s5p-g2d", .name = "exynos-drm-g2d",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = &g2d_pm_ops, .pm = &g2d_pm_ops,
.of_match_table = exynos_g2d_match, .of_match_table = exynos_g2d_match,
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/hdmi.h> #include <linux/hdmi.h>
#include <linux/component.h> #include <linux/component.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
...@@ -133,6 +134,7 @@ struct hdmi_context { ...@@ -133,6 +134,7 @@ struct hdmi_context {
struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)]; struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)];
struct regulator *reg_hdmi_en; struct regulator *reg_hdmi_en;
struct exynos_drm_clk phy_clk; struct exynos_drm_clk phy_clk;
struct drm_bridge *bridge;
}; };
static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e) static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e)
...@@ -509,9 +511,9 @@ static const struct hdmiphy_config hdmiphy_5433_configs[] = { ...@@ -509,9 +511,9 @@ static const struct hdmiphy_config hdmiphy_5433_configs[] = {
{ {
.pixel_clock = 27000000, .pixel_clock = 27000000,
.conf = { .conf = {
0x01, 0x51, 0x22, 0x51, 0x08, 0xfc, 0x88, 0x46, 0x01, 0x51, 0x2d, 0x75, 0x01, 0x00, 0x88, 0x02,
0x72, 0x50, 0x24, 0x0c, 0x24, 0x0f, 0x7c, 0xa5, 0x72, 0x50, 0x44, 0x8c, 0x27, 0x00, 0x7c, 0xac,
0xd4, 0x2b, 0x87, 0x00, 0x00, 0x04, 0x00, 0x30, 0xd6, 0x2b, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30,
0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40, 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
}, },
}, },
...@@ -519,9 +521,9 @@ static const struct hdmiphy_config hdmiphy_5433_configs[] = { ...@@ -519,9 +521,9 @@ static const struct hdmiphy_config hdmiphy_5433_configs[] = {
.pixel_clock = 27027000, .pixel_clock = 27027000,
.conf = { .conf = {
0x01, 0x51, 0x2d, 0x72, 0x64, 0x09, 0x88, 0xc3, 0x01, 0x51, 0x2d, 0x72, 0x64, 0x09, 0x88, 0xc3,
0x71, 0x50, 0x24, 0x14, 0x24, 0x0f, 0x7c, 0xa5, 0x71, 0x50, 0x44, 0x8c, 0x27, 0x00, 0x7c, 0xac,
0xd4, 0x2b, 0x87, 0x00, 0x00, 0x04, 0x00, 0x30, 0xd6, 0x2b, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30,
0x28, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40, 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40,
}, },
}, },
{ {
...@@ -587,6 +589,15 @@ static const struct hdmiphy_config hdmiphy_5433_configs[] = { ...@@ -587,6 +589,15 @@ static const struct hdmiphy_config hdmiphy_5433_configs[] = {
0x08, 0x10, 0x01, 0x01, 0x48, 0x4a, 0x00, 0x40, 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[] = { static const char * const hdmi_clk_gates4[] = {
...@@ -788,7 +799,8 @@ static void hdmi_reg_infoframes(struct hdmi_context *hdata) ...@@ -788,7 +799,8 @@ static void hdmi_reg_infoframes(struct hdmi_context *hdata)
sizeof(buf)); sizeof(buf));
if (ret > 0) { if (ret > 0) {
hdmi_reg_writeb(hdata, HDMI_VSI_CON, HDMI_VSI_CON_EVERY_VSYNC); 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); ret = hdmi_audio_infoframe_init(&frm.audio);
...@@ -912,7 +924,15 @@ static int hdmi_create_connector(struct drm_encoder *encoder) ...@@ -912,7 +924,15 @@ static int hdmi_create_connector(struct drm_encoder *encoder)
drm_connector_register(connector); drm_connector_register(connector);
drm_mode_connector_attach_encoder(connector, encoder); 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, 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) ...@@ -1581,6 +1601,31 @@ static void hdmiphy_clk_enable(struct exynos_drm_clk *clk, bool enable)
hdmiphy_disable(hdata); 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) static int hdmi_resources_init(struct hdmi_context *hdata)
{ {
struct device *dev = hdata->dev; struct device *dev = hdata->dev;
...@@ -1620,17 +1665,18 @@ static int hdmi_resources_init(struct hdmi_context *hdata) ...@@ -1620,17 +1665,18 @@ static int hdmi_resources_init(struct hdmi_context *hdata)
hdata->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en"); hdata->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en");
if (PTR_ERR(hdata->reg_hdmi_en) == -ENODEV) if (PTR_ERR(hdata->reg_hdmi_en) != -ENODEV) {
return 0;
if (IS_ERR(hdata->reg_hdmi_en)) if (IS_ERR(hdata->reg_hdmi_en))
return PTR_ERR(hdata->reg_hdmi_en); return PTR_ERR(hdata->reg_hdmi_en);
ret = regulator_enable(hdata->reg_hdmi_en); ret = regulator_enable(hdata->reg_hdmi_en);
if (ret) if (ret) {
DRM_ERROR("failed to enable hdmi-en regulator\n"); 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[] = { static struct of_device_id hdmi_match_types[] = {
......
...@@ -89,6 +89,8 @@ ...@@ -89,6 +89,8 @@
#define VIDCON0_ENVID_F (1 << 0) #define VIDCON0_ENVID_F (1 << 0)
/* VIDOUTCON0 */ /* VIDOUTCON0 */
#define VIDOUT_INTERLACE_FIELD_F (1 << 29)
#define VIDOUT_INTERLACE_EN_F (1 << 28)
#define VIDOUT_LCD_ON (1 << 24) #define VIDOUT_LCD_ON (1 << 24)
#define VIDOUT_IF_F_MASK (0x3 << 20) #define VIDOUT_IF_F_MASK (0x3 << 20)
#define VIDOUT_RGB_IF (0x0 << 20) #define VIDOUT_RGB_IF (0x0 << 20)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment