Skip to content

Commit f888ae7

Browse files
Hans Verkuilmchehab
authored andcommitted
[media] adv7842: Make output format configurable through pad format operations
Replace the dummy video format operations by pad format operations that configure the output format. Copied from the adv7604 driver. Note: while arch/blackfin/mach-bf609/boards/ezkit.c uses adv7842_platform_data this source has not been updated because it is broken since the very beginning. It depends on a struct adv7842_output_format that does not exist. And besides that gcc has no support for bf609 so nobody can compile it except by installing a toolchain from ADI. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Cc: Scott Jiang <scott.jiang.linux@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
1 parent 71df673 commit f888ae7

File tree

2 files changed

+276
-82
lines changed

2 files changed

+276
-82
lines changed

drivers/media/i2c/adv7842.c

Lines changed: 239 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,28 @@ MODULE_LICENSE("GPL");
5656
/* ADV7842 system clock frequency */
5757
#define ADV7842_fsc (28636360)
5858

59+
#define ADV7842_RGB_OUT (1 << 1)
60+
61+
#define ADV7842_OP_FORMAT_SEL_8BIT (0 << 0)
62+
#define ADV7842_OP_FORMAT_SEL_10BIT (1 << 0)
63+
#define ADV7842_OP_FORMAT_SEL_12BIT (2 << 0)
64+
65+
#define ADV7842_OP_MODE_SEL_SDR_422 (0 << 5)
66+
#define ADV7842_OP_MODE_SEL_DDR_422 (1 << 5)
67+
#define ADV7842_OP_MODE_SEL_SDR_444 (2 << 5)
68+
#define ADV7842_OP_MODE_SEL_DDR_444 (3 << 5)
69+
#define ADV7842_OP_MODE_SEL_SDR_422_2X (4 << 5)
70+
#define ADV7842_OP_MODE_SEL_ADI_CM (5 << 5)
71+
72+
#define ADV7842_OP_CH_SEL_GBR (0 << 5)
73+
#define ADV7842_OP_CH_SEL_GRB (1 << 5)
74+
#define ADV7842_OP_CH_SEL_BGR (2 << 5)
75+
#define ADV7842_OP_CH_SEL_RGB (3 << 5)
76+
#define ADV7842_OP_CH_SEL_BRG (4 << 5)
77+
#define ADV7842_OP_CH_SEL_RBG (5 << 5)
78+
79+
#define ADV7842_OP_SWAP_CB_CR (1 << 0)
80+
5981
/*
6082
**********************************************************************
6183
*
@@ -64,6 +86,14 @@ MODULE_LICENSE("GPL");
6486
**********************************************************************
6587
*/
6688

89+
struct adv7842_format_info {
90+
u32 code;
91+
u8 op_ch_sel;
92+
bool rgb_out;
93+
bool swap_cb_cr;
94+
u8 op_format_sel;
95+
};
96+
6797
struct adv7842_state {
6898
struct adv7842_platform_data pdata;
6999
struct v4l2_subdev sd;
@@ -72,6 +102,9 @@ struct adv7842_state {
72102
enum adv7842_mode mode;
73103
struct v4l2_dv_timings timings;
74104
enum adv7842_vid_std_select vid_std_select;
105+
106+
const struct adv7842_format_info *format;
107+
75108
v4l2_std_id norm;
76109
struct {
77110
u8 edid[256];
@@ -221,11 +254,21 @@ static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
221254
return &container_of(ctrl->handler, struct adv7842_state, hdl)->sd;
222255
}
223256

257+
static inline unsigned hblanking(const struct v4l2_bt_timings *t)
258+
{
259+
return V4L2_DV_BT_BLANKING_WIDTH(t);
260+
}
261+
224262
static inline unsigned htotal(const struct v4l2_bt_timings *t)
225263
{
226264
return V4L2_DV_BT_FRAME_WIDTH(t);
227265
}
228266

267+
static inline unsigned vblanking(const struct v4l2_bt_timings *t)
268+
{
269+
return V4L2_DV_BT_BLANKING_HEIGHT(t);
270+
}
271+
229272
static inline unsigned vtotal(const struct v4l2_bt_timings *t)
230273
{
231274
return V4L2_DV_BT_FRAME_HEIGHT(t);
@@ -335,6 +378,12 @@ static inline int io_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 va
335378
return io_write(sd, reg, (io_read(sd, reg) & mask) | val);
336379
}
337380

381+
static inline int io_write_clr_set(struct v4l2_subdev *sd,
382+
u8 reg, u8 mask, u8 val)
383+
{
384+
return io_write(sd, reg, (io_read(sd, reg) & ~mask) | val);
385+
}
386+
338387
static inline int avlink_read(struct v4l2_subdev *sd, u8 reg)
339388
{
340389
struct adv7842_state *state = to_state(sd);
@@ -535,6 +584,64 @@ static void main_reset(struct v4l2_subdev *sd)
535584
mdelay(5);
536585
}
537586

587+
/* -----------------------------------------------------------------------------
588+
* Format helpers
589+
*/
590+
591+
static const struct adv7842_format_info adv7842_formats[] = {
592+
{ MEDIA_BUS_FMT_RGB888_1X24, ADV7842_OP_CH_SEL_RGB, true, false,
593+
ADV7842_OP_MODE_SEL_SDR_444 | ADV7842_OP_FORMAT_SEL_8BIT },
594+
{ MEDIA_BUS_FMT_YUYV8_2X8, ADV7842_OP_CH_SEL_RGB, false, false,
595+
ADV7842_OP_MODE_SEL_SDR_422 | ADV7842_OP_FORMAT_SEL_8BIT },
596+
{ MEDIA_BUS_FMT_YVYU8_2X8, ADV7842_OP_CH_SEL_RGB, false, true,
597+
ADV7842_OP_MODE_SEL_SDR_422 | ADV7842_OP_FORMAT_SEL_8BIT },
598+
{ MEDIA_BUS_FMT_YUYV10_2X10, ADV7842_OP_CH_SEL_RGB, false, false,
599+
ADV7842_OP_MODE_SEL_SDR_422 | ADV7842_OP_FORMAT_SEL_10BIT },
600+
{ MEDIA_BUS_FMT_YVYU10_2X10, ADV7842_OP_CH_SEL_RGB, false, true,
601+
ADV7842_OP_MODE_SEL_SDR_422 | ADV7842_OP_FORMAT_SEL_10BIT },
602+
{ MEDIA_BUS_FMT_YUYV12_2X12, ADV7842_OP_CH_SEL_RGB, false, false,
603+
ADV7842_OP_MODE_SEL_SDR_422 | ADV7842_OP_FORMAT_SEL_12BIT },
604+
{ MEDIA_BUS_FMT_YVYU12_2X12, ADV7842_OP_CH_SEL_RGB, false, true,
605+
ADV7842_OP_MODE_SEL_SDR_422 | ADV7842_OP_FORMAT_SEL_12BIT },
606+
{ MEDIA_BUS_FMT_UYVY8_1X16, ADV7842_OP_CH_SEL_RBG, false, false,
607+
ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_8BIT },
608+
{ MEDIA_BUS_FMT_VYUY8_1X16, ADV7842_OP_CH_SEL_RBG, false, true,
609+
ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_8BIT },
610+
{ MEDIA_BUS_FMT_YUYV8_1X16, ADV7842_OP_CH_SEL_RGB, false, false,
611+
ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_8BIT },
612+
{ MEDIA_BUS_FMT_YVYU8_1X16, ADV7842_OP_CH_SEL_RGB, false, true,
613+
ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_8BIT },
614+
{ MEDIA_BUS_FMT_UYVY10_1X20, ADV7842_OP_CH_SEL_RBG, false, false,
615+
ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_10BIT },
616+
{ MEDIA_BUS_FMT_VYUY10_1X20, ADV7842_OP_CH_SEL_RBG, false, true,
617+
ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_10BIT },
618+
{ MEDIA_BUS_FMT_YUYV10_1X20, ADV7842_OP_CH_SEL_RGB, false, false,
619+
ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_10BIT },
620+
{ MEDIA_BUS_FMT_YVYU10_1X20, ADV7842_OP_CH_SEL_RGB, false, true,
621+
ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_10BIT },
622+
{ MEDIA_BUS_FMT_UYVY12_1X24, ADV7842_OP_CH_SEL_RBG, false, false,
623+
ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_12BIT },
624+
{ MEDIA_BUS_FMT_VYUY12_1X24, ADV7842_OP_CH_SEL_RBG, false, true,
625+
ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_12BIT },
626+
{ MEDIA_BUS_FMT_YUYV12_1X24, ADV7842_OP_CH_SEL_RGB, false, false,
627+
ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_12BIT },
628+
{ MEDIA_BUS_FMT_YVYU12_1X24, ADV7842_OP_CH_SEL_RGB, false, true,
629+
ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_12BIT },
630+
};
631+
632+
static const struct adv7842_format_info *
633+
adv7842_format_info(struct adv7842_state *state, u32 code)
634+
{
635+
unsigned int i;
636+
637+
for (i = 0; i < ARRAY_SIZE(adv7842_formats); ++i) {
638+
if (adv7842_formats[i].code == code)
639+
return &adv7842_formats[i];
640+
}
641+
642+
return NULL;
643+
}
644+
538645
/* ----------------------------------------------------------------------- */
539646

540647
static inline bool is_analog_input(struct v4l2_subdev *sd)
@@ -1440,6 +1547,8 @@ static int adv7842_query_dv_timings(struct v4l2_subdev *sd,
14401547
}
14411548
bt->interlaced = stdi.interlaced ?
14421549
V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE;
1550+
bt->standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
1551+
V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT;
14431552

14441553
if (is_digital_input(sd)) {
14451554
uint32_t freq;
@@ -1478,6 +1587,10 @@ static int adv7842_query_dv_timings(struct v4l2_subdev *sd,
14781587
hdmi_read(sd, 0x31)) / 2;
14791588
bt->il_vbackporch = ((hdmi_read(sd, 0x34) & 0x1f) * 256 +
14801589
hdmi_read(sd, 0x35)) / 2;
1590+
} else {
1591+
bt->il_vfrontporch = 0;
1592+
bt->il_vsync = 0;
1593+
bt->il_vbackporch = 0;
14811594
}
14821595
adv7842_fill_optional_dv_timings_fields(sd, timings);
14831596
} else {
@@ -1871,47 +1984,145 @@ static int adv7842_enum_mbus_code(struct v4l2_subdev *sd,
18711984
struct v4l2_subdev_pad_config *cfg,
18721985
struct v4l2_subdev_mbus_code_enum *code)
18731986
{
1874-
if (code->pad || code->index)
1987+
if (code->index >= ARRAY_SIZE(adv7842_formats))
18751988
return -EINVAL;
1876-
/* Good enough for now */
1877-
code->code = MEDIA_BUS_FMT_FIXED;
1989+
code->code = adv7842_formats[code->index].code;
18781990
return 0;
18791991
}
18801992

1881-
static int adv7842_fill_fmt(struct v4l2_subdev *sd,
1882-
struct v4l2_subdev_pad_config *cfg,
1883-
struct v4l2_subdev_format *format)
1993+
static void adv7842_fill_format(struct adv7842_state *state,
1994+
struct v4l2_mbus_framefmt *format)
1995+
{
1996+
memset(format, 0, sizeof(*format));
1997+
1998+
format->width = state->timings.bt.width;
1999+
format->height = state->timings.bt.height;
2000+
format->field = V4L2_FIELD_NONE;
2001+
format->colorspace = V4L2_COLORSPACE_SRGB;
2002+
2003+
if (state->timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO)
2004+
format->colorspace = (state->timings.bt.height <= 576) ?
2005+
V4L2_COLORSPACE_SMPTE170M : V4L2_COLORSPACE_REC709;
2006+
}
2007+
2008+
/*
2009+
* Compute the op_ch_sel value required to obtain on the bus the component order
2010+
* corresponding to the selected format taking into account bus reordering
2011+
* applied by the board at the output of the device.
2012+
*
2013+
* The following table gives the op_ch_value from the format component order
2014+
* (expressed as op_ch_sel value in column) and the bus reordering (expressed as
2015+
* adv7842_bus_order value in row).
2016+
*
2017+
* | GBR(0) GRB(1) BGR(2) RGB(3) BRG(4) RBG(5)
2018+
* ----------+-------------------------------------------------
2019+
* RGB (NOP) | GBR GRB BGR RGB BRG RBG
2020+
* GRB (1-2) | BGR RGB GBR GRB RBG BRG
2021+
* RBG (2-3) | GRB GBR BRG RBG BGR RGB
2022+
* BGR (1-3) | RBG BRG RGB BGR GRB GBR
2023+
* BRG (ROR) | BRG RBG GRB GBR RGB BGR
2024+
* GBR (ROL) | RGB BGR RBG BRG GBR GRB
2025+
*/
2026+
static unsigned int adv7842_op_ch_sel(struct adv7842_state *state)
2027+
{
2028+
#define _SEL(a, b, c, d, e, f) { \
2029+
ADV7842_OP_CH_SEL_##a, ADV7842_OP_CH_SEL_##b, ADV7842_OP_CH_SEL_##c, \
2030+
ADV7842_OP_CH_SEL_##d, ADV7842_OP_CH_SEL_##e, ADV7842_OP_CH_SEL_##f }
2031+
#define _BUS(x) [ADV7842_BUS_ORDER_##x]
2032+
2033+
static const unsigned int op_ch_sel[6][6] = {
2034+
_BUS(RGB) /* NOP */ = _SEL(GBR, GRB, BGR, RGB, BRG, RBG),
2035+
_BUS(GRB) /* 1-2 */ = _SEL(BGR, RGB, GBR, GRB, RBG, BRG),
2036+
_BUS(RBG) /* 2-3 */ = _SEL(GRB, GBR, BRG, RBG, BGR, RGB),
2037+
_BUS(BGR) /* 1-3 */ = _SEL(RBG, BRG, RGB, BGR, GRB, GBR),
2038+
_BUS(BRG) /* ROR */ = _SEL(BRG, RBG, GRB, GBR, RGB, BGR),
2039+
_BUS(GBR) /* ROL */ = _SEL(RGB, BGR, RBG, BRG, GBR, GRB),
2040+
};
2041+
2042+
return op_ch_sel[state->pdata.bus_order][state->format->op_ch_sel >> 5];
2043+
}
2044+
2045+
static void adv7842_setup_format(struct adv7842_state *state)
2046+
{
2047+
struct v4l2_subdev *sd = &state->sd;
2048+
2049+
io_write_clr_set(sd, 0x02, 0x02,
2050+
state->format->rgb_out ? ADV7842_RGB_OUT : 0);
2051+
io_write(sd, 0x03, state->format->op_format_sel |
2052+
state->pdata.op_format_mode_sel);
2053+
io_write_clr_set(sd, 0x04, 0xe0, adv7842_op_ch_sel(state));
2054+
io_write_clr_set(sd, 0x05, 0x01,
2055+
state->format->swap_cb_cr ? ADV7842_OP_SWAP_CB_CR : 0);
2056+
}
2057+
2058+
static int adv7842_get_format(struct v4l2_subdev *sd,
2059+
struct v4l2_subdev_pad_config *cfg,
2060+
struct v4l2_subdev_format *format)
18842061
{
1885-
struct v4l2_mbus_framefmt *fmt = &format->format;
18862062
struct adv7842_state *state = to_state(sd);
18872063

1888-
if (format->pad)
2064+
if (format->pad != ADV7842_PAD_SOURCE)
18892065
return -EINVAL;
18902066

1891-
fmt->width = state->timings.bt.width;
1892-
fmt->height = state->timings.bt.height;
1893-
fmt->code = MEDIA_BUS_FMT_FIXED;
1894-
fmt->field = V4L2_FIELD_NONE;
1895-
18962067
if (state->mode == ADV7842_MODE_SDP) {
18972068
/* SPD block */
1898-
if (!(sdp_read(sd, 0x5A) & 0x01))
2069+
if (!(sdp_read(sd, 0x5a) & 0x01))
18992070
return -EINVAL;
1900-
fmt->width = 720;
2071+
format->format.code = MEDIA_BUS_FMT_YUYV8_2X8;
2072+
format->format.width = 720;
19012073
/* valid signal */
19022074
if (state->norm & V4L2_STD_525_60)
1903-
fmt->height = 480;
2075+
format->format.height = 480;
19042076
else
1905-
fmt->height = 576;
1906-
fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
2077+
format->format.height = 576;
2078+
format->format.colorspace = V4L2_COLORSPACE_SMPTE170M;
19072079
return 0;
19082080
}
19092081

1910-
fmt->colorspace = V4L2_COLORSPACE_SRGB;
1911-
if (state->timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) {
1912-
fmt->colorspace = (state->timings.bt.height <= 576) ?
1913-
V4L2_COLORSPACE_SMPTE170M : V4L2_COLORSPACE_REC709;
2082+
adv7842_fill_format(state, &format->format);
2083+
2084+
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
2085+
struct v4l2_mbus_framefmt *fmt;
2086+
2087+
fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
2088+
format->format.code = fmt->code;
2089+
} else {
2090+
format->format.code = state->format->code;
19142091
}
2092+
2093+
return 0;
2094+
}
2095+
2096+
static int adv7842_set_format(struct v4l2_subdev *sd,
2097+
struct v4l2_subdev_pad_config *cfg,
2098+
struct v4l2_subdev_format *format)
2099+
{
2100+
struct adv7842_state *state = to_state(sd);
2101+
const struct adv7842_format_info *info;
2102+
2103+
if (format->pad != ADV7842_PAD_SOURCE)
2104+
return -EINVAL;
2105+
2106+
if (state->mode == ADV7842_MODE_SDP)
2107+
return adv7842_get_format(sd, cfg, format);
2108+
2109+
info = adv7842_format_info(state, format->format.code);
2110+
if (info == NULL)
2111+
info = adv7842_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8);
2112+
2113+
adv7842_fill_format(state, &format->format);
2114+
format->format.code = info->code;
2115+
2116+
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
2117+
struct v4l2_mbus_framefmt *fmt;
2118+
2119+
fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
2120+
fmt->code = format->format.code;
2121+
} else {
2122+
state->format = info;
2123+
adv7842_setup_format(state);
2124+
}
2125+
19152126
return 0;
19162127
}
19172128

@@ -2551,14 +2762,11 @@ static int adv7842_core_init(struct v4l2_subdev *sd)
25512762
0xf0 |
25522763
pdata->alt_gamma << 3 |
25532764
pdata->op_656_range << 2 |
2554-
pdata->rgb_out << 1 |
25552765
pdata->alt_data_sat << 0);
2556-
io_write(sd, 0x03, pdata->op_format_sel);
2557-
io_write_and_or(sd, 0x04, 0x1f, pdata->op_ch_sel << 5);
25582766
io_write_and_or(sd, 0x05, 0xf0, pdata->blank_data << 3 |
25592767
pdata->insert_av_codes << 2 |
2560-
pdata->replicate_av_codes << 1 |
2561-
pdata->invert_cbcr << 0);
2768+
pdata->replicate_av_codes << 1);
2769+
adv7842_setup_format(state);
25622770

25632771
/* HDMI audio */
25642772
hdmi_write_and_or(sd, 0x1a, 0xf1, 0x08); /* Wait 1 s before unmute */
@@ -2818,13 +3026,13 @@ static const struct v4l2_subdev_video_ops adv7842_video_ops = {
28183026
};
28193027

28203028
static const struct v4l2_subdev_pad_ops adv7842_pad_ops = {
3029+
.enum_mbus_code = adv7842_enum_mbus_code,
3030+
.get_fmt = adv7842_get_format,
3031+
.set_fmt = adv7842_set_format,
28213032
.get_edid = adv7842_get_edid,
28223033
.set_edid = adv7842_set_edid,
28233034
.enum_dv_timings = adv7842_enum_dv_timings,
28243035
.dv_timings_cap = adv7842_dv_timings_cap,
2825-
.enum_mbus_code = adv7842_enum_mbus_code,
2826-
.get_fmt = adv7842_fill_fmt,
2827-
.set_fmt = adv7842_fill_fmt,
28283036
};
28293037

28303038
static const struct v4l2_subdev_ops adv7842_ops = {
@@ -2991,6 +3199,7 @@ static int adv7842_probe(struct i2c_client *client,
29913199
/* platform data */
29923200
state->pdata = *pdata;
29933201
state->timings = cea640x480;
3202+
state->format = adv7842_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8);
29943203

29953204
sd = &state->sd;
29963205
v4l2_i2c_subdev_init(sd, client, &adv7842_ops);

0 commit comments

Comments
 (0)