Commit 3f468acc authored by Tomasz Stanislawski's avatar Tomasz Stanislawski Committed by Mauro Carvalho Chehab

[media] v4l: s5p-tv: hdmi: parametrize DV timings

This patch fixes timings configuration in HDMI register. It adds
support for numerous new presets including interlaced ones.
Signed-off-by: default avatarTomasz Stanislawski <t.stanislaws@samsung.com>
Signed-off-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: default avatarSylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 2470ea3f
...@@ -42,7 +42,23 @@ MODULE_DESCRIPTION("Samsung HDMI"); ...@@ -42,7 +42,23 @@ MODULE_DESCRIPTION("Samsung HDMI");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/* default preset configured on probe */ /* 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 hdmi_resources {
struct clk *hdmi; struct clk *hdmi;
...@@ -70,64 +86,13 @@ struct hdmi_device { ...@@ -70,64 +86,13 @@ struct hdmi_device {
/** subdev of MHL interface */ /** subdev of MHL interface */
struct v4l2_subdev *mhl_sd; struct v4l2_subdev *mhl_sd;
/** configuration of current graphic mode */ /** configuration of current graphic mode */
const struct hdmi_preset_conf *cur_conf; const struct hdmi_timings *cur_conf;
/** current preset */ /** current preset */
u32 cur_preset; u32 cur_preset;
/** other resources */ /** other resources */
struct hdmi_resources res; 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[] = { static struct platform_device_id hdmi_driver_types[] = {
{ {
.name = "s5pv210-hdmi", .name = "s5pv210-hdmi",
...@@ -165,6 +130,21 @@ void hdmi_writeb(struct hdmi_device *hdev, u32 reg_id, u8 value) ...@@ -165,6 +130,21 @@ void hdmi_writeb(struct hdmi_device *hdev, u32 reg_id, u8 value)
writeb(value, hdev->regs + reg_id); 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) static inline u32 hdmi_read(struct hdmi_device *hdev, u32 reg_id)
{ {
return readl(hdev->regs + reg_id); return readl(hdev->regs + reg_id);
...@@ -211,72 +191,63 @@ static void hdmi_reg_init(struct hdmi_device *hdev) ...@@ -211,72 +191,63 @@ static void hdmi_reg_init(struct hdmi_device *hdev)
} }
static void hdmi_timing_apply(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 */ /* setting core registers */
hdmi_writeb(hdev, HDMI_H_BLANK_0, core->h_blank[0]); hdmi_writebn(hdev, HDMI_H_BLANK_0, 2, t->hact.beg);
hdmi_writeb(hdev, HDMI_H_BLANK_1, core->h_blank[1]); hdmi_writebn(hdev, HDMI_H_SYNC_GEN_0, 3,
hdmi_writeb(hdev, HDMI_V_BLANK_0, core->v_blank[0]); (t->hsyn_pol << 20) | (t->hsyn.end << 10) | t->hsyn.beg);
hdmi_writeb(hdev, HDMI_V_BLANK_1, core->v_blank[1]); hdmi_writeb(hdev, HDMI_VSYNC_POL, t->vsyn_pol);
hdmi_writeb(hdev, HDMI_V_BLANK_2, core->v_blank[2]); hdmi_writebn(hdev, HDMI_V_BLANK_0, 3,
hdmi_writeb(hdev, HDMI_H_V_LINE_0, core->h_v_line[0]); (t->vact[0].beg << 11) | t->vact[0].end);
hdmi_writeb(hdev, HDMI_H_V_LINE_1, core->h_v_line[1]); hdmi_writebn(hdev, HDMI_V_SYNC_GEN_1_0, 3,
hdmi_writeb(hdev, HDMI_H_V_LINE_2, core->h_v_line[2]); (t->vsyn[0].beg << 12) | t->vsyn[0].end);
hdmi_writeb(hdev, HDMI_VSYNC_POL, core->vsync_pol[0]); if (t->interlaced) {
hdmi_writeb(hdev, HDMI_INT_PRO_MODE, core->int_pro_mode[0]); u32 vsyn_trans = t->hsyn.beg + t->vsyn_off;
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_INT_PRO_MODE, 1);
hdmi_writeb(hdev, HDMI_V_BLANK_F_2, core->v_blank_f[2]); hdmi_writebn(hdev, HDMI_H_V_LINE_0, 3,
hdmi_writeb(hdev, HDMI_H_SYNC_GEN_0, core->h_sync_gen[0]); (t->hact.end << 12) | t->vact[1].end);
hdmi_writeb(hdev, HDMI_H_SYNC_GEN_1, core->h_sync_gen[1]); hdmi_writebn(hdev, HDMI_V_BLANK_F_0, 3,
hdmi_writeb(hdev, HDMI_H_SYNC_GEN_2, core->h_sync_gen[2]); (t->vact[1].end << 11) | t->vact[1].beg);
hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_0, core->v_sync_gen1[0]); hdmi_writebn(hdev, HDMI_V_SYNC_GEN_2_0, 3,
hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_1, core->v_sync_gen1[1]); (t->vsyn[1].beg << 12) | t->vsyn[1].end);
hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_2, core->v_sync_gen1[2]); hdmi_writebn(hdev, HDMI_V_SYNC_GEN_3_0, 3,
hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_0, core->v_sync_gen2[0]); (vsyn_trans << 12) | vsyn_trans);
hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_1, core->v_sync_gen2[1]); } else {
hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_2, core->v_sync_gen2[2]); hdmi_writeb(hdev, HDMI_INT_PRO_MODE, 0);
hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_0, core->v_sync_gen3[0]); hdmi_writebn(hdev, HDMI_H_V_LINE_0, 3,
hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_1, core->v_sync_gen3[1]); (t->hact.end << 12) | t->vact[0].end);
hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_2, core->v_sync_gen3[2]); }
/* Timing generator registers */ /* Timing generator registers */
hdmi_writeb(hdev, HDMI_TG_H_FSZ_L, tg->h_fsz_l); hdmi_writebn(hdev, HDMI_TG_H_FSZ_L, 2, t->hact.end);
hdmi_writeb(hdev, HDMI_TG_H_FSZ_H, tg->h_fsz_h); hdmi_writebn(hdev, HDMI_TG_HACT_ST_L, 2, t->hact.beg);
hdmi_writeb(hdev, HDMI_TG_HACT_ST_L, tg->hact_st_l); hdmi_writebn(hdev, HDMI_TG_HACT_SZ_L, 2, t->hact.end - t->hact.beg);
hdmi_writeb(hdev, HDMI_TG_HACT_ST_H, tg->hact_st_h); hdmi_writebn(hdev, HDMI_TG_VSYNC_L, 2, t->vsyn[0].beg);
hdmi_writeb(hdev, HDMI_TG_HACT_SZ_L, tg->hact_sz_l); hdmi_writebn(hdev, HDMI_TG_VACT_ST_L, 2, t->vact[0].beg);
hdmi_writeb(hdev, HDMI_TG_HACT_SZ_H, tg->hact_sz_h); hdmi_writebn(hdev, HDMI_TG_VACT_SZ_L, 2,
hdmi_writeb(hdev, HDMI_TG_V_FSZ_L, tg->v_fsz_l); t->vact[0].end - t->vact[0].beg);
hdmi_writeb(hdev, HDMI_TG_V_FSZ_H, tg->v_fsz_h); hdmi_writebn(hdev, HDMI_TG_VSYNC_TOP_HDMI_L, 2, t->vsyn[0].beg);
hdmi_writeb(hdev, HDMI_TG_VSYNC_L, tg->vsync_l); hdmi_writebn(hdev, HDMI_TG_FIELD_TOP_HDMI_L, 2, t->vsyn[0].beg);
hdmi_writeb(hdev, HDMI_TG_VSYNC_H, tg->vsync_h); if (t->interlaced) {
hdmi_writeb(hdev, HDMI_TG_VSYNC2_L, tg->vsync2_l); hdmi_write_mask(hdev, HDMI_TG_CMD, ~0, HDMI_TG_FIELD_EN);
hdmi_writeb(hdev, HDMI_TG_VSYNC2_H, tg->vsync2_h); hdmi_writebn(hdev, HDMI_TG_V_FSZ_L, 2, t->vact[1].end);
hdmi_writeb(hdev, HDMI_TG_VACT_ST_L, tg->vact_st_l); hdmi_writebn(hdev, HDMI_TG_VSYNC2_L, 2, t->vsyn[1].beg);
hdmi_writeb(hdev, HDMI_TG_VACT_ST_H, tg->vact_st_h); hdmi_writebn(hdev, HDMI_TG_FIELD_CHG_L, 2, t->vact[0].end);
hdmi_writeb(hdev, HDMI_TG_VACT_SZ_L, tg->vact_sz_l); hdmi_writebn(hdev, HDMI_TG_VACT_ST2_L, 2, t->vact[1].beg);
hdmi_writeb(hdev, HDMI_TG_VACT_SZ_H, tg->vact_sz_h); hdmi_writebn(hdev, HDMI_TG_VSYNC_BOT_HDMI_L, 2, t->vsyn[1].beg);
hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_L, tg->field_chg_l); hdmi_writebn(hdev, HDMI_TG_FIELD_BOT_HDMI_L, 2, t->vsyn[1].beg);
hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_H, tg->field_chg_h); } else {
hdmi_writeb(hdev, HDMI_TG_VACT_ST2_L, tg->vact_st2_l); hdmi_write_mask(hdev, HDMI_TG_CMD, 0, HDMI_TG_FIELD_EN);
hdmi_writeb(hdev, HDMI_TG_VACT_ST2_H, tg->vact_st2_h); hdmi_writebn(hdev, HDMI_TG_V_FSZ_L, 2, t->vact[0].end);
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);
} }
static int hdmi_conf_apply(struct hdmi_device *hdmi_dev) static int hdmi_conf_apply(struct hdmi_device *hdmi_dev)
{ {
struct device *dev = hdmi_dev->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; struct v4l2_dv_preset preset;
int ret; int ret;
...@@ -398,156 +369,126 @@ static void hdmi_dumpregs(struct hdmi_device *hdev, char *prefix) ...@@ -398,156 +369,126 @@ static void hdmi_dumpregs(struct hdmi_device *hdev, char *prefix)
#undef DUMPREG #undef DUMPREG
} }
static const struct hdmi_preset_conf hdmi_conf_480p = { static const struct hdmi_timings hdmi_timings_480p = {
.core = { .hact = { .beg = 138, .end = 858 },
.h_blank = {0x8a, 0x00}, .hsyn_pol = 1,
.v_blank = {0x0d, 0x6a, 0x01}, .hsyn = { .beg = 16, .end = 16 + 62 },
.h_v_line = {0x0d, 0xa2, 0x35}, .interlaced = 0,
.vsync_pol = {0x01}, .vact[0] = { .beg = 42 + 3, .end = 522 + 3 },
.int_pro_mode = {0x00}, .vsyn_pol = 1,
.v_blank_f = {0x00, 0x00, 0x00}, .vsyn[0] = { .beg = 6 + 3, .end = 12 + 3},
.h_sync_gen = {0x0e, 0x30, 0x11}, };
.v_sync_gen1 = {0x0f, 0x90, 0x00},
/* other don't care */ static const struct hdmi_timings hdmi_timings_576p50 = {
}, .hact = { .beg = 144, .end = 864 },
.tg = { .hsyn_pol = 1,
0x00, /* cmd */ .hsyn = { .beg = 12, .end = 12 + 64 },
0x5a, 0x03, /* h_fsz */ .interlaced = 0,
0x8a, 0x00, 0xd0, 0x02, /* hact */ .vact[0] = { .beg = 44 + 5, .end = 620 + 5 },
0x0d, 0x02, /* v_fsz */ .vsyn_pol = 1,
0x01, 0x00, 0x33, 0x02, /* vsync */ .vsyn[0] = { .beg = 0 + 5, .end = 5 + 5},
0x2d, 0x00, 0xe0, 0x01, /* vact */ };
0x33, 0x02, /* field_chg */
0x49, 0x02, /* vact_st2 */ static const struct hdmi_timings hdmi_timings_720p60 = {
0x01, 0x00, 0x33, 0x02, /* vsync top/bot */ .hact = { .beg = 370, .end = 1650 },
0x01, 0x00, 0x33, 0x02, /* field top/bot */ .hsyn_pol = 0,
}, .hsyn = { .beg = 110, .end = 110 + 40 },
.mbus_fmt = { .interlaced = 0,
.width = 720, .vact[0] = { .beg = 25 + 5, .end = 745 + 5 },
.height = 480, .vsyn_pol = 0,
.code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */ .vsyn[0] = { .beg = 0 + 5, .end = 5 + 5},
.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_preset_conf hdmi_conf_720p60 = { static const struct hdmi_timings hdmi_timings_1080i60 = {
.core = { .hact = { .beg = 280, .end = 2200 },
.h_blank = {0x72, 0x01}, .hsyn_pol = 0,
.v_blank = {0xee, 0xf2, 0x00}, .hsyn = { .beg = 88, .end = 88 + 44 },
.h_v_line = {0xee, 0x22, 0x67}, .interlaced = 1,
.vsync_pol = {0x00}, .vact[0] = { .beg = 20 + 2, .end = 560 + 2 },
.int_pro_mode = {0x00}, .vact[1] = { .beg = 583 + 2, .end = 1123 + 2 },
.v_blank_f = {0x00, 0x00, 0x00}, /* don't care */ .vsyn_pol = 0,
.h_sync_gen = {0x6c, 0x50, 0x02}, .vsyn_off = 1100,
.v_sync_gen1 = {0x0a, 0x50, 0x00}, .vsyn[0] = { .beg = 0 + 2, .end = 5 + 2},
/* other don't care */ .vsyn[1] = { .beg = 562 + 2, .end = 567 + 2},
},
.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_preset_conf hdmi_conf_1080p50 = { static const struct hdmi_timings hdmi_timings_1080i50 = {
.core = { .hact = { .beg = 720, .end = 2640 },
.h_blank = {0xd0, 0x02}, .hsyn_pol = 0,
.v_blank = {0x65, 0x6c, 0x01}, .hsyn = { .beg = 528, .end = 528 + 44 },
.h_v_line = {0x65, 0x04, 0xa5}, .interlaced = 1,
.vsync_pol = {0x00}, .vact[0] = { .beg = 20 + 2, .end = 560 + 2 },
.int_pro_mode = {0x00}, .vact[1] = { .beg = 583 + 2, .end = 1123 + 2 },
.v_blank_f = {0x00, 0x00, 0x00}, /* don't care */ .vsyn_pol = 0,
.h_sync_gen = {0x0e, 0xea, 0x08}, .vsyn_off = 1320,
.v_sync_gen1 = {0x09, 0x40, 0x00}, .vsyn[0] = { .beg = 0 + 2, .end = 5 + 2},
/* other don't care */ .vsyn[1] = { .beg = 562 + 2, .end = 567 + 2},
},
.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_preset_conf hdmi_conf_1080p60 = { static const struct hdmi_timings hdmi_timings_1080p50 = {
.core = { .hact = { .beg = 720, .end = 2640 },
.h_blank = {0x18, 0x01}, .hsyn_pol = 0,
.v_blank = {0x65, 0x6c, 0x01}, .hsyn = { .beg = 528, .end = 528 + 44 },
.h_v_line = {0x65, 0x84, 0x89}, .interlaced = 0,
.vsync_pol = {0x00}, .vact[0] = { .beg = 41 + 4, .end = 1121 + 4 },
.int_pro_mode = {0x00}, .vsyn_pol = 0,
.v_blank_f = {0x00, 0x00, 0x00}, /* don't care */ .vsyn[0] = { .beg = 0 + 4, .end = 5 + 4},
.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 { static const struct {
u32 preset; u32 preset;
const struct hdmi_preset_conf *conf; const struct hdmi_timings *timings;
} hdmi_conf[] = { } hdmi_timings[] = {
{ V4L2_DV_480P59_94, &hdmi_conf_480p }, { V4L2_DV_480P59_94, &hdmi_timings_480p },
{ V4L2_DV_720P59_94, &hdmi_conf_720p60 }, { V4L2_DV_576P50, &hdmi_timings_576p50 },
{ V4L2_DV_1080P50, &hdmi_conf_1080p50 }, { V4L2_DV_720P50, &hdmi_timings_720p50 },
{ V4L2_DV_1080P30, &hdmi_conf_1080p60 }, { V4L2_DV_720P59_94, &hdmi_timings_720p60 },
{ V4L2_DV_1080P60, &hdmi_conf_1080p60 }, { 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; int i;
for (i = 0; i < ARRAY_SIZE(hdmi_conf); ++i) for (i = 0; i < ARRAY_SIZE(hdmi_timings); ++i)
if (hdmi_conf[i].preset == preset) if (hdmi_timings[i].preset == preset)
return hdmi_conf[i].conf; return hdmi_timings[i].timings;
return NULL; return NULL;
} }
...@@ -671,9 +612,9 @@ static int hdmi_s_dv_preset(struct v4l2_subdev *sd, ...@@ -671,9 +612,9 @@ static int hdmi_s_dv_preset(struct v4l2_subdev *sd,
{ {
struct hdmi_device *hdev = sd_to_hdmi_dev(sd); struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
struct device *dev = hdev->dev; 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) { if (conf == NULL) {
dev_err(dev, "preset (%u) not supported\n", preset->preset); dev_err(dev, "preset (%u) not supported\n", preset->preset);
return -EINVAL; return -EINVAL;
...@@ -695,21 +636,32 @@ static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd, ...@@ -695,21 +636,32 @@ static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *fmt) struct v4l2_mbus_framefmt *fmt)
{ {
struct hdmi_device *hdev = sd_to_hdmi_dev(sd); 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) if (!hdev->cur_conf)
return -EINVAL; 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; return 0;
} }
static int hdmi_enum_dv_presets(struct v4l2_subdev *sd, static int hdmi_enum_dv_presets(struct v4l2_subdev *sd,
struct v4l2_dv_enum_preset *preset) struct v4l2_dv_enum_preset *preset)
{ {
if (preset->index >= ARRAY_SIZE(hdmi_conf)) if (preset->index >= ARRAY_SIZE(hdmi_timings))
return -EINVAL; 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 = { static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = {
...@@ -993,7 +945,7 @@ static int __devinit hdmi_probe(struct platform_device *pdev) ...@@ -993,7 +945,7 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
strlcpy(sd->name, "s5p-hdmi", sizeof sd->name); strlcpy(sd->name, "s5p-hdmi", sizeof sd->name);
hdmi_dev->cur_preset = HDMI_DEFAULT_PRESET; hdmi_dev->cur_preset = HDMI_DEFAULT_PRESET;
/* FIXME: missing fail preset is not supported */ /* 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);
/* storing subdev for call that have only access to struct device */ /* storing subdev for call that have only access to struct device */
dev_set_drvdata(dev, sd); dev_set_drvdata(dev, sd);
......
...@@ -140,6 +140,7 @@ ...@@ -140,6 +140,7 @@
#define HDMI_MODE_MASK (3 << 0) #define HDMI_MODE_MASK (3 << 0)
/* HDMI_TG_CMD */ /* HDMI_TG_CMD */
#define HDMI_TG_FIELD_EN (1 << 1)
#define HDMI_TG_EN (1 << 0) #define HDMI_TG_EN (1 << 0)
#endif /* SAMSUNG_REGS_HDMI_H */ #endif /* SAMSUNG_REGS_HDMI_H */
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