diff options
Diffstat (limited to 'drivers/media/video/s5p-tv')
-rw-r--r-- | drivers/media/video/s5p-tv/hdmi_drv.c | 480 | ||||
-rw-r--r-- | drivers/media/video/s5p-tv/hdmiphy_drv.c | 225 | ||||
-rw-r--r-- | drivers/media/video/s5p-tv/mixer.h | 3 | ||||
-rw-r--r-- | drivers/media/video/s5p-tv/mixer_drv.c | 2 | ||||
-rw-r--r-- | drivers/media/video/s5p-tv/mixer_reg.c | 15 | ||||
-rw-r--r-- | drivers/media/video/s5p-tv/mixer_video.c | 10 | ||||
-rw-r--r-- | drivers/media/video/s5p-tv/regs-hdmi.h | 1 |
7 files changed, 431 insertions, 305 deletions
diff --git a/drivers/media/video/s5p-tv/hdmi_drv.c b/drivers/media/video/s5p-tv/hdmi_drv.c index 4865d25a0e57..20cb6eef2979 100644 --- a/drivers/media/video/s5p-tv/hdmi_drv.c +++ b/drivers/media/video/s5p-tv/hdmi_drv.c @@ -42,7 +42,23 @@ MODULE_DESCRIPTION("Samsung HDMI"); MODULE_LICENSE("GPL"); /* default preset configured on probe */ -#define HDMI_DEFAULT_PRESET V4L2_DV_1080P60 +#define HDMI_DEFAULT_PRESET V4L2_DV_480P59_94 + +struct hdmi_pulse { + u32 beg; + u32 end; +}; + +struct hdmi_timings { + struct hdmi_pulse hact; + u32 hsyn_pol; /* 0 - high, 1 - low */ + struct hdmi_pulse hsyn; + u32 interlaced; + struct hdmi_pulse vact[2]; + u32 vsyn_pol; /* 0 - high, 1 - low */ + u32 vsyn_off; + struct hdmi_pulse vsyn[2]; +}; struct hdmi_resources { struct clk *hdmi; @@ -70,64 +86,15 @@ struct hdmi_device { /** subdev of MHL interface */ struct v4l2_subdev *mhl_sd; /** configuration of current graphic mode */ - const struct hdmi_preset_conf *cur_conf; + const struct hdmi_timings *cur_conf; + /** flag indicating that timings are dirty */ + int cur_conf_dirty; /** current preset */ u32 cur_preset; /** other resources */ struct hdmi_resources res; }; -struct hdmi_tg_regs { - u8 cmd; - u8 h_fsz_l; - u8 h_fsz_h; - u8 hact_st_l; - u8 hact_st_h; - u8 hact_sz_l; - u8 hact_sz_h; - u8 v_fsz_l; - u8 v_fsz_h; - u8 vsync_l; - u8 vsync_h; - u8 vsync2_l; - u8 vsync2_h; - u8 vact_st_l; - u8 vact_st_h; - u8 vact_sz_l; - u8 vact_sz_h; - u8 field_chg_l; - u8 field_chg_h; - u8 vact_st2_l; - u8 vact_st2_h; - u8 vsync_top_hdmi_l; - u8 vsync_top_hdmi_h; - u8 vsync_bot_hdmi_l; - u8 vsync_bot_hdmi_h; - u8 field_top_hdmi_l; - u8 field_top_hdmi_h; - u8 field_bot_hdmi_l; - u8 field_bot_hdmi_h; -}; - -struct hdmi_core_regs { - u8 h_blank[2]; - u8 v_blank[3]; - u8 h_v_line[3]; - u8 vsync_pol[1]; - u8 int_pro_mode[1]; - u8 v_blank_f[3]; - u8 h_sync_gen[3]; - u8 v_sync_gen1[3]; - u8 v_sync_gen2[3]; - u8 v_sync_gen3[3]; -}; - -struct hdmi_preset_conf { - struct hdmi_core_regs core; - struct hdmi_tg_regs tg; - struct v4l2_mbus_framefmt mbus_fmt; -}; - static struct platform_device_id hdmi_driver_types[] = { { .name = "s5pv210-hdmi", @@ -165,6 +132,21 @@ void hdmi_writeb(struct hdmi_device *hdev, u32 reg_id, u8 value) writeb(value, hdev->regs + reg_id); } +static inline +void hdmi_writebn(struct hdmi_device *hdev, u32 reg_id, int n, u32 value) +{ + switch (n) { + default: + writeb(value >> 24, hdev->regs + reg_id + 12); + case 3: + writeb(value >> 16, hdev->regs + reg_id + 8); + case 2: + writeb(value >> 8, hdev->regs + reg_id + 4); + case 1: + writeb(value >> 0, hdev->regs + reg_id + 0); + } +} + static inline u32 hdmi_read(struct hdmi_device *hdev, u32 reg_id) { return readl(hdev->regs + reg_id); @@ -211,77 +193,72 @@ static void hdmi_reg_init(struct hdmi_device *hdev) } static void hdmi_timing_apply(struct hdmi_device *hdev, - const struct hdmi_preset_conf *conf) + const struct hdmi_timings *t) { - const struct hdmi_core_regs *core = &conf->core; - const struct hdmi_tg_regs *tg = &conf->tg; - /* setting core registers */ - hdmi_writeb(hdev, HDMI_H_BLANK_0, core->h_blank[0]); - hdmi_writeb(hdev, HDMI_H_BLANK_1, core->h_blank[1]); - hdmi_writeb(hdev, HDMI_V_BLANK_0, core->v_blank[0]); - hdmi_writeb(hdev, HDMI_V_BLANK_1, core->v_blank[1]); - hdmi_writeb(hdev, HDMI_V_BLANK_2, core->v_blank[2]); - hdmi_writeb(hdev, HDMI_H_V_LINE_0, core->h_v_line[0]); - hdmi_writeb(hdev, HDMI_H_V_LINE_1, core->h_v_line[1]); - hdmi_writeb(hdev, HDMI_H_V_LINE_2, core->h_v_line[2]); - hdmi_writeb(hdev, HDMI_VSYNC_POL, core->vsync_pol[0]); - hdmi_writeb(hdev, HDMI_INT_PRO_MODE, core->int_pro_mode[0]); - hdmi_writeb(hdev, HDMI_V_BLANK_F_0, core->v_blank_f[0]); - hdmi_writeb(hdev, HDMI_V_BLANK_F_1, core->v_blank_f[1]); - hdmi_writeb(hdev, HDMI_V_BLANK_F_2, core->v_blank_f[2]); - hdmi_writeb(hdev, HDMI_H_SYNC_GEN_0, core->h_sync_gen[0]); - hdmi_writeb(hdev, HDMI_H_SYNC_GEN_1, core->h_sync_gen[1]); - hdmi_writeb(hdev, HDMI_H_SYNC_GEN_2, core->h_sync_gen[2]); - hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_0, core->v_sync_gen1[0]); - hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_1, core->v_sync_gen1[1]); - hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_2, core->v_sync_gen1[2]); - hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_0, core->v_sync_gen2[0]); - hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_1, core->v_sync_gen2[1]); - hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_2, core->v_sync_gen2[2]); - hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_0, core->v_sync_gen3[0]); - hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_1, core->v_sync_gen3[1]); - hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_2, core->v_sync_gen3[2]); + hdmi_writebn(hdev, HDMI_H_BLANK_0, 2, t->hact.beg); + hdmi_writebn(hdev, HDMI_H_SYNC_GEN_0, 3, + (t->hsyn_pol << 20) | (t->hsyn.end << 10) | t->hsyn.beg); + hdmi_writeb(hdev, HDMI_VSYNC_POL, t->vsyn_pol); + hdmi_writebn(hdev, HDMI_V_BLANK_0, 3, + (t->vact[0].beg << 11) | t->vact[0].end); + hdmi_writebn(hdev, HDMI_V_SYNC_GEN_1_0, 3, + (t->vsyn[0].beg << 12) | t->vsyn[0].end); + if (t->interlaced) { + u32 vsyn_trans = t->hsyn.beg + t->vsyn_off; + + hdmi_writeb(hdev, HDMI_INT_PRO_MODE, 1); + hdmi_writebn(hdev, HDMI_H_V_LINE_0, 3, + (t->hact.end << 12) | t->vact[1].end); + hdmi_writebn(hdev, HDMI_V_BLANK_F_0, 3, + (t->vact[1].end << 11) | t->vact[1].beg); + hdmi_writebn(hdev, HDMI_V_SYNC_GEN_2_0, 3, + (t->vsyn[1].beg << 12) | t->vsyn[1].end); + hdmi_writebn(hdev, HDMI_V_SYNC_GEN_3_0, 3, + (vsyn_trans << 12) | vsyn_trans); + } else { + hdmi_writeb(hdev, HDMI_INT_PRO_MODE, 0); + hdmi_writebn(hdev, HDMI_H_V_LINE_0, 3, + (t->hact.end << 12) | t->vact[0].end); + } + /* Timing generator registers */ - hdmi_writeb(hdev, HDMI_TG_H_FSZ_L, tg->h_fsz_l); - hdmi_writeb(hdev, HDMI_TG_H_FSZ_H, tg->h_fsz_h); - hdmi_writeb(hdev, HDMI_TG_HACT_ST_L, tg->hact_st_l); - hdmi_writeb(hdev, HDMI_TG_HACT_ST_H, tg->hact_st_h); - hdmi_writeb(hdev, HDMI_TG_HACT_SZ_L, tg->hact_sz_l); - hdmi_writeb(hdev, HDMI_TG_HACT_SZ_H, tg->hact_sz_h); - hdmi_writeb(hdev, HDMI_TG_V_FSZ_L, tg->v_fsz_l); - hdmi_writeb(hdev, HDMI_TG_V_FSZ_H, tg->v_fsz_h); - hdmi_writeb(hdev, HDMI_TG_VSYNC_L, tg->vsync_l); - hdmi_writeb(hdev, HDMI_TG_VSYNC_H, tg->vsync_h); - hdmi_writeb(hdev, HDMI_TG_VSYNC2_L, tg->vsync2_l); - hdmi_writeb(hdev, HDMI_TG_VSYNC2_H, tg->vsync2_h); - hdmi_writeb(hdev, HDMI_TG_VACT_ST_L, tg->vact_st_l); - hdmi_writeb(hdev, HDMI_TG_VACT_ST_H, tg->vact_st_h); - hdmi_writeb(hdev, HDMI_TG_VACT_SZ_L, tg->vact_sz_l); - hdmi_writeb(hdev, HDMI_TG_VACT_SZ_H, tg->vact_sz_h); - hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_L, tg->field_chg_l); - hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_H, tg->field_chg_h); - hdmi_writeb(hdev, HDMI_TG_VACT_ST2_L, tg->vact_st2_l); - hdmi_writeb(hdev, HDMI_TG_VACT_ST2_H, tg->vact_st2_h); - hdmi_writeb(hdev, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi_l); - hdmi_writeb(hdev, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi_h); - hdmi_writeb(hdev, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi_l); - hdmi_writeb(hdev, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi_h); - hdmi_writeb(hdev, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi_l); - hdmi_writeb(hdev, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi_h); - hdmi_writeb(hdev, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi_l); - hdmi_writeb(hdev, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi_h); + hdmi_writebn(hdev, HDMI_TG_H_FSZ_L, 2, t->hact.end); + hdmi_writebn(hdev, HDMI_TG_HACT_ST_L, 2, t->hact.beg); + hdmi_writebn(hdev, HDMI_TG_HACT_SZ_L, 2, t->hact.end - t->hact.beg); + hdmi_writebn(hdev, HDMI_TG_VSYNC_L, 2, t->vsyn[0].beg); + hdmi_writebn(hdev, HDMI_TG_VACT_ST_L, 2, t->vact[0].beg); + hdmi_writebn(hdev, HDMI_TG_VACT_SZ_L, 2, + t->vact[0].end - t->vact[0].beg); + hdmi_writebn(hdev, HDMI_TG_VSYNC_TOP_HDMI_L, 2, t->vsyn[0].beg); + hdmi_writebn(hdev, HDMI_TG_FIELD_TOP_HDMI_L, 2, t->vsyn[0].beg); + if (t->interlaced) { + hdmi_write_mask(hdev, HDMI_TG_CMD, ~0, HDMI_TG_FIELD_EN); + hdmi_writebn(hdev, HDMI_TG_V_FSZ_L, 2, t->vact[1].end); + hdmi_writebn(hdev, HDMI_TG_VSYNC2_L, 2, t->vsyn[1].beg); + hdmi_writebn(hdev, HDMI_TG_FIELD_CHG_L, 2, t->vact[0].end); + hdmi_writebn(hdev, HDMI_TG_VACT_ST2_L, 2, t->vact[1].beg); + hdmi_writebn(hdev, HDMI_TG_VSYNC_BOT_HDMI_L, 2, t->vsyn[1].beg); + hdmi_writebn(hdev, HDMI_TG_FIELD_BOT_HDMI_L, 2, t->vsyn[1].beg); + } else { + hdmi_write_mask(hdev, HDMI_TG_CMD, 0, HDMI_TG_FIELD_EN); + hdmi_writebn(hdev, HDMI_TG_V_FSZ_L, 2, t->vact[0].end); + } } static int hdmi_conf_apply(struct hdmi_device *hdmi_dev) { struct device *dev = hdmi_dev->dev; - const struct hdmi_preset_conf *conf = hdmi_dev->cur_conf; + const struct hdmi_timings *conf = hdmi_dev->cur_conf; struct v4l2_dv_preset preset; int ret; dev_dbg(dev, "%s\n", __func__); + /* skip if conf is already synchronized with HW */ + if (!hdmi_dev->cur_conf_dirty) + return 0; + /* reset hdmiphy */ hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT); mdelay(10); @@ -307,6 +284,8 @@ static int hdmi_conf_apply(struct hdmi_device *hdmi_dev) /* setting core registers */ hdmi_timing_apply(hdmi_dev, conf); + hdmi_dev->cur_conf_dirty = 0; + return 0; } @@ -398,156 +377,126 @@ static void hdmi_dumpregs(struct hdmi_device *hdev, char *prefix) #undef DUMPREG } -static const struct hdmi_preset_conf hdmi_conf_480p = { - .core = { - .h_blank = {0x8a, 0x00}, - .v_blank = {0x0d, 0x6a, 0x01}, - .h_v_line = {0x0d, 0xa2, 0x35}, - .vsync_pol = {0x01}, - .int_pro_mode = {0x00}, - .v_blank_f = {0x00, 0x00, 0x00}, - .h_sync_gen = {0x0e, 0x30, 0x11}, - .v_sync_gen1 = {0x0f, 0x90, 0x00}, - /* other don't care */ - }, - .tg = { - 0x00, /* cmd */ - 0x5a, 0x03, /* h_fsz */ - 0x8a, 0x00, 0xd0, 0x02, /* hact */ - 0x0d, 0x02, /* v_fsz */ - 0x01, 0x00, 0x33, 0x02, /* vsync */ - 0x2d, 0x00, 0xe0, 0x01, /* vact */ - 0x33, 0x02, /* field_chg */ - 0x49, 0x02, /* vact_st2 */ - 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */ - 0x01, 0x00, 0x33, 0x02, /* field top/bot */ - }, - .mbus_fmt = { - .width = 720, - .height = 480, - .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */ - .field = V4L2_FIELD_NONE, - .colorspace = V4L2_COLORSPACE_SRGB, - }, +static const struct hdmi_timings hdmi_timings_480p = { + .hact = { .beg = 138, .end = 858 }, + .hsyn_pol = 1, + .hsyn = { .beg = 16, .end = 16 + 62 }, + .interlaced = 0, + .vact[0] = { .beg = 42 + 3, .end = 522 + 3 }, + .vsyn_pol = 1, + .vsyn[0] = { .beg = 6 + 3, .end = 12 + 3}, }; -static const struct hdmi_preset_conf hdmi_conf_720p60 = { - .core = { - .h_blank = {0x72, 0x01}, - .v_blank = {0xee, 0xf2, 0x00}, - .h_v_line = {0xee, 0x22, 0x67}, - .vsync_pol = {0x00}, - .int_pro_mode = {0x00}, - .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */ - .h_sync_gen = {0x6c, 0x50, 0x02}, - .v_sync_gen1 = {0x0a, 0x50, 0x00}, - /* other don't care */ - }, - .tg = { - 0x00, /* cmd */ - 0x72, 0x06, /* h_fsz */ - 0x72, 0x01, 0x00, 0x05, /* hact */ - 0xee, 0x02, /* v_fsz */ - 0x01, 0x00, 0x33, 0x02, /* vsync */ - 0x1e, 0x00, 0xd0, 0x02, /* vact */ - 0x33, 0x02, /* field_chg */ - 0x49, 0x02, /* vact_st2 */ - 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */ - 0x01, 0x00, 0x33, 0x02, /* field top/bot */ - }, - .mbus_fmt = { - .width = 1280, - .height = 720, - .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */ - .field = V4L2_FIELD_NONE, - .colorspace = V4L2_COLORSPACE_SRGB, - }, +static const struct hdmi_timings hdmi_timings_576p50 = { + .hact = { .beg = 144, .end = 864 }, + .hsyn_pol = 1, + .hsyn = { .beg = 12, .end = 12 + 64 }, + .interlaced = 0, + .vact[0] = { .beg = 44 + 5, .end = 620 + 5 }, + .vsyn_pol = 1, + .vsyn[0] = { .beg = 0 + 5, .end = 5 + 5}, }; -static const struct hdmi_preset_conf hdmi_conf_1080p50 = { - .core = { - .h_blank = {0xd0, 0x02}, - .v_blank = {0x65, 0x6c, 0x01}, - .h_v_line = {0x65, 0x04, 0xa5}, - .vsync_pol = {0x00}, - .int_pro_mode = {0x00}, - .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */ - .h_sync_gen = {0x0e, 0xea, 0x08}, - .v_sync_gen1 = {0x09, 0x40, 0x00}, - /* other don't care */ - }, - .tg = { - 0x00, /* cmd */ - 0x98, 0x08, /* h_fsz */ - 0x18, 0x01, 0x80, 0x07, /* hact */ - 0x65, 0x04, /* v_fsz */ - 0x01, 0x00, 0x33, 0x02, /* vsync */ - 0x2d, 0x00, 0x38, 0x04, /* vact */ - 0x33, 0x02, /* field_chg */ - 0x49, 0x02, /* vact_st2 */ - 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */ - 0x01, 0x00, 0x33, 0x02, /* field top/bot */ - }, - .mbus_fmt = { - .width = 1920, - .height = 1080, - .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */ - .field = V4L2_FIELD_NONE, - .colorspace = V4L2_COLORSPACE_SRGB, - }, +static const struct hdmi_timings hdmi_timings_720p60 = { + .hact = { .beg = 370, .end = 1650 }, + .hsyn_pol = 0, + .hsyn = { .beg = 110, .end = 110 + 40 }, + .interlaced = 0, + .vact[0] = { .beg = 25 + 5, .end = 745 + 5 }, + .vsyn_pol = 0, + .vsyn[0] = { .beg = 0 + 5, .end = 5 + 5}, }; -static const struct hdmi_preset_conf hdmi_conf_1080p60 = { - .core = { - .h_blank = {0x18, 0x01}, - .v_blank = {0x65, 0x6c, 0x01}, - .h_v_line = {0x65, 0x84, 0x89}, - .vsync_pol = {0x00}, - .int_pro_mode = {0x00}, - .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */ - .h_sync_gen = {0x56, 0x08, 0x02}, - .v_sync_gen1 = {0x09, 0x40, 0x00}, - /* other don't care */ - }, - .tg = { - 0x00, /* cmd */ - 0x98, 0x08, /* h_fsz */ - 0x18, 0x01, 0x80, 0x07, /* hact */ - 0x65, 0x04, /* v_fsz */ - 0x01, 0x00, 0x33, 0x02, /* vsync */ - 0x2d, 0x00, 0x38, 0x04, /* vact */ - 0x33, 0x02, /* field_chg */ - 0x48, 0x02, /* vact_st2 */ - 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */ - 0x01, 0x00, 0x33, 0x02, /* field top/bot */ - }, - .mbus_fmt = { - .width = 1920, - .height = 1080, - .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */ - .field = V4L2_FIELD_NONE, - .colorspace = V4L2_COLORSPACE_SRGB, - }, +static const struct hdmi_timings hdmi_timings_720p50 = { + .hact = { .beg = 700, .end = 1980 }, + .hsyn_pol = 0, + .hsyn = { .beg = 440, .end = 440 + 40 }, + .interlaced = 0, + .vact[0] = { .beg = 25 + 5, .end = 745 + 5 }, + .vsyn_pol = 0, + .vsyn[0] = { .beg = 0 + 5, .end = 5 + 5}, +}; + +static const struct hdmi_timings hdmi_timings_1080p24 = { + .hact = { .beg = 830, .end = 2750 }, + .hsyn_pol = 0, + .hsyn = { .beg = 638, .end = 638 + 44 }, + .interlaced = 0, + .vact[0] = { .beg = 41 + 4, .end = 1121 + 4 }, + .vsyn_pol = 0, + .vsyn[0] = { .beg = 0 + 4, .end = 5 + 4}, +}; + +static const struct hdmi_timings hdmi_timings_1080p60 = { + .hact = { .beg = 280, .end = 2200 }, + .hsyn_pol = 0, + .hsyn = { .beg = 88, .end = 88 + 44 }, + .interlaced = 0, + .vact[0] = { .beg = 41 + 4, .end = 1121 + 4 }, + .vsyn_pol = 0, + .vsyn[0] = { .beg = 0 + 4, .end = 5 + 4}, +}; + +static const struct hdmi_timings hdmi_timings_1080i60 = { + .hact = { .beg = 280, .end = 2200 }, + .hsyn_pol = 0, + .hsyn = { .beg = 88, .end = 88 + 44 }, + .interlaced = 1, + .vact[0] = { .beg = 20 + 2, .end = 560 + 2 }, + .vact[1] = { .beg = 583 + 2, .end = 1123 + 2 }, + .vsyn_pol = 0, + .vsyn_off = 1100, + .vsyn[0] = { .beg = 0 + 2, .end = 5 + 2}, + .vsyn[1] = { .beg = 562 + 2, .end = 567 + 2}, +}; + +static const struct hdmi_timings hdmi_timings_1080i50 = { + .hact = { .beg = 720, .end = 2640 }, + .hsyn_pol = 0, + .hsyn = { .beg = 528, .end = 528 + 44 }, + .interlaced = 1, + .vact[0] = { .beg = 20 + 2, .end = 560 + 2 }, + .vact[1] = { .beg = 583 + 2, .end = 1123 + 2 }, + .vsyn_pol = 0, + .vsyn_off = 1320, + .vsyn[0] = { .beg = 0 + 2, .end = 5 + 2}, + .vsyn[1] = { .beg = 562 + 2, .end = 567 + 2}, +}; + +static const struct hdmi_timings hdmi_timings_1080p50 = { + .hact = { .beg = 720, .end = 2640 }, + .hsyn_pol = 0, + .hsyn = { .beg = 528, .end = 528 + 44 }, + .interlaced = 0, + .vact[0] = { .beg = 41 + 4, .end = 1121 + 4 }, + .vsyn_pol = 0, + .vsyn[0] = { .beg = 0 + 4, .end = 5 + 4}, }; static const struct { u32 preset; - const struct hdmi_preset_conf *conf; -} hdmi_conf[] = { - { V4L2_DV_480P59_94, &hdmi_conf_480p }, - { V4L2_DV_720P59_94, &hdmi_conf_720p60 }, - { V4L2_DV_1080P50, &hdmi_conf_1080p50 }, - { V4L2_DV_1080P30, &hdmi_conf_1080p60 }, - { V4L2_DV_1080P60, &hdmi_conf_1080p60 }, + const struct hdmi_timings *timings; +} hdmi_timings[] = { + { V4L2_DV_480P59_94, &hdmi_timings_480p }, + { V4L2_DV_576P50, &hdmi_timings_576p50 }, + { V4L2_DV_720P50, &hdmi_timings_720p50 }, + { V4L2_DV_720P59_94, &hdmi_timings_720p60 }, + { V4L2_DV_720P60, &hdmi_timings_720p60 }, + { V4L2_DV_1080P24, &hdmi_timings_1080p24 }, + { V4L2_DV_1080P30, &hdmi_timings_1080p60 }, + { V4L2_DV_1080P50, &hdmi_timings_1080p50 }, + { V4L2_DV_1080I50, &hdmi_timings_1080i50 }, + { V4L2_DV_1080I60, &hdmi_timings_1080i60 }, + { V4L2_DV_1080P60, &hdmi_timings_1080p60 }, }; -static const struct hdmi_preset_conf *hdmi_preset2conf(u32 preset) +static const struct hdmi_timings *hdmi_preset2timings(u32 preset) { int i; - for (i = 0; i < ARRAY_SIZE(hdmi_conf); ++i) - if (hdmi_conf[i].preset == preset) - return hdmi_conf[i].conf; + for (i = 0; i < ARRAY_SIZE(hdmi_timings); ++i) + if (hdmi_timings[i].preset == preset) + return hdmi_timings[i].timings; return NULL; } @@ -559,6 +508,10 @@ static int hdmi_streamon(struct hdmi_device *hdev) dev_dbg(dev, "%s\n", __func__); + ret = hdmi_conf_apply(hdev); + if (ret) + return ret; + ret = v4l2_subdev_call(hdev->phy_sd, video, s_stream, 1); if (ret) return ret; @@ -671,14 +624,15 @@ static int hdmi_s_dv_preset(struct v4l2_subdev *sd, { struct hdmi_device *hdev = sd_to_hdmi_dev(sd); struct device *dev = hdev->dev; - const struct hdmi_preset_conf *conf; + const struct hdmi_timings *conf; - conf = hdmi_preset2conf(preset->preset); + conf = hdmi_preset2timings(preset->preset); if (conf == NULL) { dev_err(dev, "preset (%u) not supported\n", preset->preset); return -EINVAL; } hdev->cur_conf = conf; + hdev->cur_conf_dirty = 1; hdev->cur_preset = preset->preset; return 0; } @@ -695,21 +649,32 @@ static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) { struct hdmi_device *hdev = sd_to_hdmi_dev(sd); - struct device *dev = hdev->dev; + const struct hdmi_timings *t = hdev->cur_conf; - dev_dbg(dev, "%s\n", __func__); + dev_dbg(hdev->dev, "%s\n", __func__); if (!hdev->cur_conf) return -EINVAL; - *fmt = hdev->cur_conf->mbus_fmt; + memset(fmt, 0, sizeof *fmt); + fmt->width = t->hact.end - t->hact.beg; + fmt->height = t->vact[0].end - t->vact[0].beg; + fmt->code = V4L2_MBUS_FMT_FIXED; /* means RGB888 */ + fmt->colorspace = V4L2_COLORSPACE_SRGB; + if (t->interlaced) { + fmt->field = V4L2_FIELD_INTERLACED; + fmt->height *= 2; + } else { + fmt->field = V4L2_FIELD_NONE; + } return 0; } static int hdmi_enum_dv_presets(struct v4l2_subdev *sd, struct v4l2_dv_enum_preset *preset) { - if (preset->index >= ARRAY_SIZE(hdmi_conf)) + if (preset->index >= ARRAY_SIZE(hdmi_timings)) return -EINVAL; - return v4l_fill_dv_preset_info(hdmi_conf[preset->index].preset, preset); + return v4l_fill_dv_preset_info(hdmi_timings[preset->index].preset, + preset); } static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = { @@ -737,6 +702,8 @@ static int hdmi_runtime_suspend(struct device *dev) dev_dbg(dev, "%s\n", __func__); v4l2_subdev_call(hdev->mhl_sd, core, s_power, 0); hdmi_resource_poweroff(&hdev->res); + /* flag that device context is lost */ + hdev->cur_conf_dirty = 1; return 0; } @@ -750,10 +717,6 @@ static int hdmi_runtime_resume(struct device *dev) hdmi_resource_poweron(&hdev->res); - ret = hdmi_conf_apply(hdev); - if (ret) - goto fail; - /* starting MHL */ ret = v4l2_subdev_call(hdev->mhl_sd, core, s_power, 1); if (hdev->mhl_sd && ret) @@ -993,7 +956,8 @@ static int __devinit hdmi_probe(struct platform_device *pdev) strlcpy(sd->name, "s5p-hdmi", sizeof sd->name); hdmi_dev->cur_preset = HDMI_DEFAULT_PRESET; /* FIXME: missing fail preset is not supported */ - hdmi_dev->cur_conf = hdmi_preset2conf(hdmi_dev->cur_preset); + hdmi_dev->cur_conf = hdmi_preset2timings(hdmi_dev->cur_preset); + hdmi_dev->cur_conf_dirty = 1; /* storing subdev for call that have only access to struct device */ dev_set_drvdata(dev, sd); diff --git a/drivers/media/video/s5p-tv/hdmiphy_drv.c b/drivers/media/video/s5p-tv/hdmiphy_drv.c index 0afef77747e5..f67b38631801 100644 --- a/drivers/media/video/s5p-tv/hdmiphy_drv.c +++ b/drivers/media/video/s5p-tv/hdmiphy_drv.c @@ -26,53 +26,188 @@ MODULE_DESCRIPTION("Samsung HDMI Physical interface driver"); MODULE_LICENSE("GPL"); struct hdmiphy_conf { - u32 preset; + unsigned long pixclk; const u8 *data; }; -static const u8 hdmiphy_conf27[32] = { - 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, +struct hdmiphy_ctx { + struct v4l2_subdev sd; + const struct hdmiphy_conf *conf_tab; }; -static const u8 hdmiphy_conf74_175[32] = { - 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, +static const struct hdmiphy_conf hdmiphy_conf_s5pv210[] = { + { .pixclk = 27000000, .data = (u8 [32]) { + 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40, + 0x6B, 0x10, 0x02, 0x52, 0xDF, 0xF2, 0x54, 0x87, + 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, + 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00, } + }, + { .pixclk = 27027000, .data = (u8 [32]) { + 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64, + 0x6B, 0x10, 0x02, 0x52, 0xDF, 0xF2, 0x54, 0x87, + 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, + 0x22, 0x40, 0xE2, 0x26, 0x00, 0x00, 0x00, 0x00, } + }, + { .pixclk = 74176000, .data = (u8 [32]) { + 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xEF, 0x5B, + 0x6D, 0x10, 0x01, 0x52, 0xEF, 0xF3, 0x54, 0xB9, + 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, + 0x22, 0x40, 0xA5, 0x26, 0x01, 0x00, 0x00, 0x00, } + }, + { .pixclk = 74250000, .data = (u8 [32]) { + 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xF8, 0x40, + 0x6A, 0x10, 0x01, 0x52, 0xFF, 0xF1, 0x54, 0xBA, + 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0, + 0x22, 0x40, 0xA4, 0x26, 0x01, 0x00, 0x00, 0x00, } + }, + { /* end marker */ } }; -static const u8 hdmiphy_conf74_25[32] = { - 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40, - 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba, - 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xe0, - 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00, +static const struct hdmiphy_conf hdmiphy_conf_exynos4210[] = { + { .pixclk = 27000000, .data = (u8 [32]) { + 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, } + }, + { .pixclk = 27027000, .data = (u8 [32]) { + 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, 0xE2, 0x26, 0x00, 0x00, 0x00, 0x00, } + }, + { .pixclk = 74176000, .data = (u8 [32]) { + 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, } + }, + { .pixclk = 74250000, .data = (u8 [32]) { + 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, } + }, + { .pixclk = 148352000, .data = (u8 [32]) { + 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xEF, 0x5B, + 0x6D, 0x18, 0x00, 0x51, 0xEF, 0xF3, 0x54, 0xB9, + 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, + 0x11, 0x40, 0xA5, 0x26, 0x02, 0x00, 0x00, 0x00, } + }, + { .pixclk = 148500000, .data = (u8 [32]) { + 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xF8, 0x40, + 0x6A, 0x18, 0x00, 0x51, 0xFF, 0xF1, 0x54, 0xBA, + 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0, + 0x11, 0x40, 0xA4, 0x26, 0x02, 0x00, 0x00, 0x00, } + }, + { /* end marker */ } }; -static const u8 hdmiphy_conf148_5[32] = { - 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, +static const struct hdmiphy_conf hdmiphy_conf_exynos4212[] = { + { .pixclk = 27000000, .data = (u8 [32]) { + 0x01, 0x11, 0x2D, 0x75, 0x00, 0x01, 0x00, 0x08, + 0x82, 0x00, 0x0E, 0xD9, 0x45, 0xA0, 0x34, 0xC0, + 0x0B, 0x80, 0x12, 0x87, 0x08, 0x24, 0x24, 0x71, + 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, } + }, + { .pixclk = 27027000, .data = (u8 [32]) { + 0x01, 0x91, 0x2D, 0x72, 0x00, 0x64, 0x12, 0x08, + 0x43, 0x20, 0x0E, 0xD9, 0x45, 0xA0, 0x34, 0xC0, + 0x0B, 0x80, 0x12, 0x87, 0x08, 0x24, 0x24, 0x71, + 0x54, 0xE2, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, } + }, + { .pixclk = 74176000, .data = (u8 [32]) { + 0x01, 0x91, 0x3E, 0x35, 0x00, 0x5B, 0xDE, 0x08, + 0x82, 0x20, 0x73, 0xD9, 0x45, 0xA0, 0x34, 0xC0, + 0x0B, 0x80, 0x12, 0x87, 0x08, 0x24, 0x24, 0x52, + 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00, } + }, + { .pixclk = 74250000, .data = (u8 [32]) { + 0x01, 0x91, 0x3E, 0x35, 0x00, 0x40, 0xF0, 0x08, + 0x82, 0x20, 0x73, 0xD9, 0x45, 0xA0, 0x34, 0xC0, + 0x0B, 0x80, 0x12, 0x87, 0x08, 0x24, 0x24, 0x52, + 0x54, 0xA4, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00, } + }, + { .pixclk = 148500000, .data = (u8 [32]) { + 0x01, 0x91, 0x3E, 0x15, 0x00, 0x40, 0xF0, 0x08, + 0x82, 0x20, 0x73, 0xD9, 0x45, 0xA0, 0x34, 0xC0, + 0x0B, 0x80, 0x12, 0x87, 0x08, 0x24, 0x24, 0xA4, + 0x54, 0x4A, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00, } + }, + { /* end marker */ } }; -static const struct hdmiphy_conf hdmiphy_conf[] = { - { V4L2_DV_480P59_94, hdmiphy_conf27 }, - { V4L2_DV_1080P30, hdmiphy_conf74_175 }, - { V4L2_DV_720P59_94, hdmiphy_conf74_175 }, - { V4L2_DV_720P60, hdmiphy_conf74_25 }, - { V4L2_DV_1080P50, hdmiphy_conf148_5 }, - { V4L2_DV_1080P60, hdmiphy_conf148_5 }, +static const struct hdmiphy_conf hdmiphy_conf_exynos4412[] = { + { .pixclk = 27000000, .data = (u8 [32]) { + 0x01, 0x11, 0x2D, 0x75, 0x40, 0x01, 0x00, 0x08, + 0x82, 0x00, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80, + 0x08, 0x80, 0x11, 0x84, 0x02, 0x22, 0x44, 0x86, + 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, } + }, + { .pixclk = 27027000, .data = (u8 [32]) { + 0x01, 0x91, 0x2D, 0x72, 0x40, 0x64, 0x12, 0x08, + 0x43, 0x20, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80, + 0x08, 0x80, 0x11, 0x84, 0x02, 0x22, 0x44, 0x86, + 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, } + }, + { .pixclk = 74176000, .data = (u8 [32]) { + 0x01, 0x91, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0x08, + 0x81, 0x20, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80, + 0x08, 0x80, 0x11, 0x84, 0x02, 0x22, 0x44, 0x86, + 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00, } + }, + { .pixclk = 74250000, .data = (u8 [32]) { + 0x01, 0x91, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08, + 0x81, 0x20, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80, + 0x08, 0x80, 0x11, 0x84, 0x02, 0x22, 0x44, 0x86, + 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00, } + }, + { .pixclk = 148500000, .data = (u8 [32]) { + 0x01, 0x91, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08, + 0x81, 0x20, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80, + 0x08, 0x80, 0x11, 0x84, 0x02, 0x22, 0x44, 0x86, + 0x54, 0x4B, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00, } + }, + { /* end marker */ } }; -const u8 *hdmiphy_preset2conf(u32 preset) +static inline struct hdmiphy_ctx *sd_to_ctx(struct v4l2_subdev *sd) +{ + return container_of(sd, struct hdmiphy_ctx, sd); +} + +static unsigned long hdmiphy_preset_to_pixclk(u32 preset) +{ + static const unsigned long pixclk[] = { + [V4L2_DV_480P59_94] = 27000000, + [V4L2_DV_576P50] = 27000000, + [V4L2_DV_720P59_94] = 74176000, + [V4L2_DV_720P50] = 74250000, + [V4L2_DV_720P60] = 74250000, + [V4L2_DV_1080P24] = 74250000, + [V4L2_DV_1080P30] = 74250000, + [V4L2_DV_1080I50] = 74250000, + [V4L2_DV_1080I60] = 74250000, + [V4L2_DV_1080P50] = 148500000, + [V4L2_DV_1080P60] = 148500000, + }; + if (preset < ARRAY_SIZE(pixclk)) + return pixclk[preset]; + else + return 0; +} + +static const u8 *hdmiphy_find_conf(u32 preset, const struct hdmiphy_conf *conf) { - int i; - for (i = 0; i < ARRAY_SIZE(hdmiphy_conf); ++i) - if (hdmiphy_conf[i].preset == preset) - return hdmiphy_conf[i].data; + unsigned long pixclk; + + pixclk = hdmiphy_preset_to_pixclk(preset); + if (!pixclk) + return NULL; + + for (; conf->pixclk; ++conf) + if (conf->pixclk == pixclk) + return conf->data; return NULL; } @@ -88,11 +223,12 @@ static int hdmiphy_s_dv_preset(struct v4l2_subdev *sd, const u8 *data; u8 buffer[32]; int ret; + struct hdmiphy_ctx *ctx = sd_to_ctx(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); struct device *dev = &client->dev; dev_info(dev, "s_dv_preset(preset = %d)\n", preset->preset); - data = hdmiphy_preset2conf(preset->preset); + data = hdmiphy_find_conf(preset->preset, ctx->conf_tab); if (!data) { dev_err(dev, "format not supported\n"); return -EINVAL; @@ -146,21 +282,36 @@ static const struct v4l2_subdev_ops hdmiphy_ops = { static int __devinit hdmiphy_probe(struct i2c_client *client, const struct i2c_device_id *id) { - static struct v4l2_subdev sd; + struct hdmiphy_ctx *ctx; + + ctx = kzalloc(sizeof *ctx, GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->conf_tab = (struct hdmiphy_conf *)id->driver_data; + v4l2_i2c_subdev_init(&ctx->sd, client, &hdmiphy_ops); - v4l2_i2c_subdev_init(&sd, client, &hdmiphy_ops); dev_info(&client->dev, "probe successful\n"); return 0; } static int __devexit hdmiphy_remove(struct i2c_client *client) { + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct hdmiphy_ctx *ctx = sd_to_ctx(sd); + + kfree(ctx); dev_info(&client->dev, "remove successful\n"); + return 0; } static const struct i2c_device_id hdmiphy_id[] = { - { "hdmiphy", 0 }, + { "hdmiphy", (unsigned long)hdmiphy_conf_exynos4210 }, + { "hdmiphy-s5pv210", (unsigned long)hdmiphy_conf_s5pv210 }, + { "hdmiphy-exynos4210", (unsigned long)hdmiphy_conf_exynos4210 }, + { "hdmiphy-exynos4212", (unsigned long)hdmiphy_conf_exynos4212 }, + { "hdmiphy-exynos4412", (unsigned long)hdmiphy_conf_exynos4412 }, { }, }; MODULE_DEVICE_TABLE(i2c, hdmiphy_id); diff --git a/drivers/media/video/s5p-tv/mixer.h b/drivers/media/video/s5p-tv/mixer.h index 1597078c4a50..ddb422e23550 100644 --- a/drivers/media/video/s5p-tv/mixer.h +++ b/drivers/media/video/s5p-tv/mixer.h @@ -226,6 +226,7 @@ struct mxr_resources { /* event flags used */ enum mxr_devide_flags { MXR_EVENT_VSYNC = 0, + MXR_EVENT_TOP = 1, }; /** drivers instance */ @@ -293,7 +294,7 @@ int __devinit mxr_acquire_video(struct mxr_device *mdev, struct mxr_output_conf *output_cont, int output_count); /** releasing common video resources */ -void __devexit mxr_release_video(struct mxr_device *mdev); +void mxr_release_video(struct mxr_device *mdev); struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx); struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx); diff --git a/drivers/media/video/s5p-tv/mixer_drv.c b/drivers/media/video/s5p-tv/mixer_drv.c index a2c0c25ad130..edca06592883 100644 --- a/drivers/media/video/s5p-tv/mixer_drv.c +++ b/drivers/media/video/s5p-tv/mixer_drv.c @@ -461,7 +461,7 @@ static struct platform_driver mxr_driver __refdata = { static int __init mxr_init(void) { int i, ret; - static const char banner[] __initdata = KERN_INFO + static const char banner[] __initconst = KERN_INFO "Samsung TV Mixer driver, " "(c) 2010-2011 Samsung Electronics Co., Ltd.\n"; printk(banner); diff --git a/drivers/media/video/s5p-tv/mixer_reg.c b/drivers/media/video/s5p-tv/mixer_reg.c index 4800a3cbb297..3b1670a045f4 100644 --- a/drivers/media/video/s5p-tv/mixer_reg.c +++ b/drivers/media/video/s5p-tv/mixer_reg.c @@ -296,21 +296,25 @@ irqreturn_t mxr_irq_handler(int irq, void *dev_data) /* wake up process waiting for VSYNC */ if (val & MXR_INT_STATUS_VSYNC) { set_bit(MXR_EVENT_VSYNC, &mdev->event_flags); + /* toggle TOP field event if working in interlaced mode */ + if (~mxr_read(mdev, MXR_CFG) & MXR_CFG_SCAN_PROGRASSIVE) + change_bit(MXR_EVENT_TOP, &mdev->event_flags); wake_up(&mdev->event_queue); - } - - /* clear interrupts */ - if (~val & MXR_INT_EN_VSYNC) { /* vsync interrupt use different bit for read and clear */ - val &= ~MXR_INT_EN_VSYNC; + val &= ~MXR_INT_STATUS_VSYNC; val |= MXR_INT_CLEAR_VSYNC; } + + /* clear interrupts */ mxr_write(mdev, MXR_INT_STATUS, val); spin_unlock(&mdev->reg_slock); /* leave on non-vsync event */ if (~val & MXR_INT_CLEAR_VSYNC) return IRQ_HANDLED; + /* skip layer update on bottom field */ + if (!test_bit(MXR_EVENT_TOP, &mdev->event_flags)) + return IRQ_HANDLED; for (i = 0; i < MXR_MAX_LAYERS; ++i) mxr_irq_layer_handle(mdev->layer[i]); return IRQ_HANDLED; @@ -333,6 +337,7 @@ void mxr_reg_streamon(struct mxr_device *mdev) /* start MIXER */ mxr_write_mask(mdev, MXR_STATUS, ~0, MXR_STATUS_REG_RUN); + set_bit(MXR_EVENT_TOP, &mdev->event_flags); spin_unlock_irqrestore(&mdev->reg_slock, flags); } diff --git a/drivers/media/video/s5p-tv/mixer_video.c b/drivers/media/video/s5p-tv/mixer_video.c index f7ca5cc143c6..33fde2a763ec 100644 --- a/drivers/media/video/s5p-tv/mixer_video.c +++ b/drivers/media/video/s5p-tv/mixer_video.c @@ -140,7 +140,7 @@ fail: return ret; } -void __devexit mxr_release_video(struct mxr_device *mdev) +void mxr_release_video(struct mxr_device *mdev) { int i; @@ -853,8 +853,8 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt, *nplanes = fmt->num_subframes; for (i = 0; i < fmt->num_subframes; ++i) { alloc_ctxs[i] = layer->mdev->alloc_ctx; - sizes[i] = PAGE_ALIGN(planes[i].sizeimage); - mxr_dbg(mdev, "size[%d] = %08lx\n", i, sizes[i]); + sizes[i] = planes[i].sizeimage; + mxr_dbg(mdev, "size[%d] = %08x\n", i, sizes[i]); } if (*nbuffers == 0) @@ -1069,6 +1069,10 @@ struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev, set_bit(V4L2_FL_USE_FH_PRIO, &layer->vfd.flags); video_set_drvdata(&layer->vfd, layer); + /* Locking in file operations other than ioctl should be done + by the driver, not the V4L2 core. + This driver needs auditing so that this flag can be removed. */ + set_bit(V4L2_FL_LOCK_ALL_FOPS, &layer->vfd.flags); layer->vfd.lock = &layer->mutex; layer->vfd.v4l2_dev = &mdev->v4l2_dev; diff --git a/drivers/media/video/s5p-tv/regs-hdmi.h b/drivers/media/video/s5p-tv/regs-hdmi.h index 33247d13e4c0..a889d1f57f28 100644 --- a/drivers/media/video/s5p-tv/regs-hdmi.h +++ b/drivers/media/video/s5p-tv/regs-hdmi.h @@ -140,6 +140,7 @@ #define HDMI_MODE_MASK (3 << 0) /* HDMI_TG_CMD */ +#define HDMI_TG_FIELD_EN (1 << 1) #define HDMI_TG_EN (1 << 0) #endif /* SAMSUNG_REGS_HDMI_H */ |