brintos

brintos / linux-shallow public Read only

0
0
Text · 76.0 KiB · ded11cd Raw
2733 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * v4l2-tpg-core.c - Test Pattern Generator4 *5 * Note: gen_twopix and tpg_gen_text are based on code from vivi.c. See the6 * vivi.c source for the copyright information of those functions.7 *8 * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.9 */10 11#include <linux/module.h>12#include <media/tpg/v4l2-tpg.h>13 14/* Must remain in sync with enum tpg_pattern */15const char * const tpg_pattern_strings[] = {16	"75% Colorbar",17	"100% Colorbar",18	"CSC Colorbar",19	"Horizontal 100% Colorbar",20	"100% Color Squares",21	"100% Black",22	"100% White",23	"100% Red",24	"100% Green",25	"100% Blue",26	"16x16 Checkers",27	"2x2 Checkers",28	"1x1 Checkers",29	"2x2 Red/Green Checkers",30	"1x1 Red/Green Checkers",31	"Alternating Hor Lines",32	"Alternating Vert Lines",33	"One Pixel Wide Cross",34	"Two Pixels Wide Cross",35	"Ten Pixels Wide Cross",36	"Gray Ramp",37	"Noise",38	NULL39};40EXPORT_SYMBOL_GPL(tpg_pattern_strings);41 42/* Must remain in sync with enum tpg_aspect */43const char * const tpg_aspect_strings[] = {44	"Source Width x Height",45	"4x3",46	"14x9",47	"16x9",48	"16x9 Anamorphic",49	NULL50};51EXPORT_SYMBOL_GPL(tpg_aspect_strings);52 53/*54 * Sine table: sin[0] = 127 * sin(-180 degrees)55 *             sin[128] = 127 * sin(0 degrees)56 *             sin[256] = 127 * sin(180 degrees)57 */58static const s8 sin[257] = {59	   0,   -4,   -7,  -11,  -13,  -18,  -20,  -22,  -26,  -29,  -33,  -35,  -37,  -41,  -43,  -48,60	 -50,  -52,  -56,  -58,  -62,  -63,  -65,  -69,  -71,  -75,  -76,  -78,  -82,  -83,  -87,  -88,61	 -90,  -93,  -94,  -97,  -99, -101, -103, -104, -107, -108, -110, -111, -112, -114, -115, -117,62	-118, -119, -120, -121, -122, -123, -123, -124, -125, -125, -126, -126, -127, -127, -127, -127,63	-127, -127, -127, -127, -126, -126, -125, -125, -124, -124, -123, -122, -121, -120, -119, -118,64	-117, -116, -114, -113, -111, -110, -109, -107, -105, -103, -101, -100,  -97,  -96,  -93,  -91,65	 -90,  -87,  -85,  -82,  -80,  -76,  -75,  -73,  -69,  -67,  -63,  -62,  -60,  -56,  -54,  -50,66	 -48,  -46,  -41,  -39,  -35,  -33,  -31,  -26,  -24,  -20,  -18,  -15,  -11,   -9,   -4,   -2,67	   0,    2,    4,    9,   11,   15,   18,   20,   24,   26,   31,   33,   35,   39,   41,   46,68	  48,   50,   54,   56,   60,   62,   64,   67,   69,   73,   75,   76,   80,   82,   85,   87,69	  90,   91,   93,   96,   97,  100,  101,  103,  105,  107,  109,  110,  111,  113,  114,  116,70	 117,  118,  119,  120,  121,  122,  123,  124,  124,  125,  125,  126,  126,  127,  127,  127,71	 127,  127,  127,  127,  127,  126,  126,  125,  125,  124,  123,  123,  122,  121,  120,  119,72	 118,  117,  115,  114,  112,  111,  110,  108,  107,  104,  103,  101,   99,   97,   94,   93,73	  90,   88,   87,   83,   82,   78,   76,   75,   71,   69,   65,   64,   62,   58,   56,   52,74	  50,   48,   43,   41,   37,   35,   33,   29,   26,   22,   20,   18,   13,   11,    7,    4,75	   0,76};77 78#define cos(idx) sin[((idx) + 64) % sizeof(sin)]79 80/* Global font descriptor */81static const u8 *font8x16;82 83void tpg_set_font(const u8 *f)84{85	font8x16 = f;86}87EXPORT_SYMBOL_GPL(tpg_set_font);88 89void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h)90{91	memset(tpg, 0, sizeof(*tpg));92	tpg->scaled_width = tpg->src_width = w;93	tpg->src_height = tpg->buf_height = h;94	tpg->crop.width = tpg->compose.width = w;95	tpg->crop.height = tpg->compose.height = h;96	tpg->recalc_colors = true;97	tpg->recalc_square_border = true;98	tpg->brightness = 128;99	tpg->contrast = 128;100	tpg->saturation = 128;101	tpg->hue = 0;102	tpg->mv_hor_mode = TPG_MOVE_NONE;103	tpg->mv_vert_mode = TPG_MOVE_NONE;104	tpg->field = V4L2_FIELD_NONE;105	tpg_s_fourcc(tpg, V4L2_PIX_FMT_RGB24);106	tpg->colorspace = V4L2_COLORSPACE_SRGB;107	tpg->perc_fill = 100;108	tpg->hsv_enc = V4L2_HSV_ENC_180;109}110EXPORT_SYMBOL_GPL(tpg_init);111 112int tpg_alloc(struct tpg_data *tpg, unsigned max_w)113{114	unsigned pat;115	unsigned plane;116	int ret = 0;117 118	tpg->max_line_width = max_w;119	for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) {120		for (plane = 0; plane < TPG_MAX_PLANES; plane++) {121			unsigned pixelsz = plane ? 2 : 4;122 123			tpg->lines[pat][plane] =124				vzalloc(array3_size(max_w, 2, pixelsz));125			if (!tpg->lines[pat][plane]) {126				ret = -ENOMEM;127				goto free_lines;128			}129			if (plane == 0)130				continue;131			tpg->downsampled_lines[pat][plane] =132				vzalloc(array3_size(max_w, 2, pixelsz));133			if (!tpg->downsampled_lines[pat][plane]) {134				ret = -ENOMEM;135				goto free_lines;136			}137		}138	}139	for (plane = 0; plane < TPG_MAX_PLANES; plane++) {140		unsigned pixelsz = plane ? 2 : 4;141 142		tpg->contrast_line[plane] =143			vzalloc(array_size(pixelsz, max_w));144		if (!tpg->contrast_line[plane]) {145			ret = -ENOMEM;146			goto free_contrast_line;147		}148		tpg->black_line[plane] =149			vzalloc(array_size(pixelsz, max_w));150		if (!tpg->black_line[plane]) {151			ret = -ENOMEM;152			goto free_contrast_line;153		}154		tpg->random_line[plane] =155			vzalloc(array3_size(max_w, 2, pixelsz));156		if (!tpg->random_line[plane]) {157			ret = -ENOMEM;158			goto free_contrast_line;159		}160	}161	return 0;162 163free_contrast_line:164	for (plane = 0; plane < TPG_MAX_PLANES; plane++) {165		vfree(tpg->contrast_line[plane]);166		vfree(tpg->black_line[plane]);167		vfree(tpg->random_line[plane]);168		tpg->contrast_line[plane] = NULL;169		tpg->black_line[plane] = NULL;170		tpg->random_line[plane] = NULL;171	}172free_lines:173	for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++)174		for (plane = 0; plane < TPG_MAX_PLANES; plane++) {175			vfree(tpg->lines[pat][plane]);176			tpg->lines[pat][plane] = NULL;177			if (plane == 0)178				continue;179			vfree(tpg->downsampled_lines[pat][plane]);180			tpg->downsampled_lines[pat][plane] = NULL;181		}182	return ret;183}184EXPORT_SYMBOL_GPL(tpg_alloc);185 186void tpg_free(struct tpg_data *tpg)187{188	unsigned pat;189	unsigned plane;190 191	for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++)192		for (plane = 0; plane < TPG_MAX_PLANES; plane++) {193			vfree(tpg->lines[pat][plane]);194			tpg->lines[pat][plane] = NULL;195			if (plane == 0)196				continue;197			vfree(tpg->downsampled_lines[pat][plane]);198			tpg->downsampled_lines[pat][plane] = NULL;199		}200	for (plane = 0; plane < TPG_MAX_PLANES; plane++) {201		vfree(tpg->contrast_line[plane]);202		vfree(tpg->black_line[plane]);203		vfree(tpg->random_line[plane]);204		tpg->contrast_line[plane] = NULL;205		tpg->black_line[plane] = NULL;206		tpg->random_line[plane] = NULL;207	}208}209EXPORT_SYMBOL_GPL(tpg_free);210 211bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)212{213	tpg->fourcc = fourcc;214	tpg->planes = 1;215	tpg->buffers = 1;216	tpg->recalc_colors = true;217	tpg->interleaved = false;218	tpg->vdownsampling[0] = 1;219	tpg->hdownsampling[0] = 1;220	tpg->hmask[0] = ~0;221	tpg->hmask[1] = ~0;222	tpg->hmask[2] = ~0;223 224	switch (fourcc) {225	case V4L2_PIX_FMT_SBGGR8:226	case V4L2_PIX_FMT_SGBRG8:227	case V4L2_PIX_FMT_SGRBG8:228	case V4L2_PIX_FMT_SRGGB8:229	case V4L2_PIX_FMT_SBGGR10:230	case V4L2_PIX_FMT_SGBRG10:231	case V4L2_PIX_FMT_SGRBG10:232	case V4L2_PIX_FMT_SRGGB10:233	case V4L2_PIX_FMT_SBGGR12:234	case V4L2_PIX_FMT_SGBRG12:235	case V4L2_PIX_FMT_SGRBG12:236	case V4L2_PIX_FMT_SRGGB12:237	case V4L2_PIX_FMT_SBGGR16:238	case V4L2_PIX_FMT_SGBRG16:239	case V4L2_PIX_FMT_SGRBG16:240	case V4L2_PIX_FMT_SRGGB16:241		tpg->interleaved = true;242		tpg->vdownsampling[1] = 1;243		tpg->hdownsampling[1] = 1;244		tpg->planes = 2;245		fallthrough;246	case V4L2_PIX_FMT_RGB332:247	case V4L2_PIX_FMT_RGB565:248	case V4L2_PIX_FMT_RGB565X:249	case V4L2_PIX_FMT_RGB444:250	case V4L2_PIX_FMT_XRGB444:251	case V4L2_PIX_FMT_ARGB444:252	case V4L2_PIX_FMT_RGBX444:253	case V4L2_PIX_FMT_RGBA444:254	case V4L2_PIX_FMT_XBGR444:255	case V4L2_PIX_FMT_ABGR444:256	case V4L2_PIX_FMT_BGRX444:257	case V4L2_PIX_FMT_BGRA444:258	case V4L2_PIX_FMT_RGB555:259	case V4L2_PIX_FMT_XRGB555:260	case V4L2_PIX_FMT_ARGB555:261	case V4L2_PIX_FMT_RGBX555:262	case V4L2_PIX_FMT_RGBA555:263	case V4L2_PIX_FMT_XBGR555:264	case V4L2_PIX_FMT_ABGR555:265	case V4L2_PIX_FMT_BGRX555:266	case V4L2_PIX_FMT_BGRA555:267	case V4L2_PIX_FMT_RGB555X:268	case V4L2_PIX_FMT_XRGB555X:269	case V4L2_PIX_FMT_ARGB555X:270	case V4L2_PIX_FMT_BGR666:271	case V4L2_PIX_FMT_RGB24:272	case V4L2_PIX_FMT_BGR24:273	case V4L2_PIX_FMT_RGB32:274	case V4L2_PIX_FMT_BGR32:275	case V4L2_PIX_FMT_XRGB32:276	case V4L2_PIX_FMT_XBGR32:277	case V4L2_PIX_FMT_ARGB32:278	case V4L2_PIX_FMT_ABGR32:279	case V4L2_PIX_FMT_RGBX32:280	case V4L2_PIX_FMT_BGRX32:281	case V4L2_PIX_FMT_RGBA32:282	case V4L2_PIX_FMT_BGRA32:283		tpg->color_enc = TGP_COLOR_ENC_RGB;284		break;285	case V4L2_PIX_FMT_GREY:286	case V4L2_PIX_FMT_Y10:287	case V4L2_PIX_FMT_Y12:288	case V4L2_PIX_FMT_Y16:289	case V4L2_PIX_FMT_Y16_BE:290	case V4L2_PIX_FMT_Z16:291		tpg->color_enc = TGP_COLOR_ENC_LUMA;292		break;293	case V4L2_PIX_FMT_YUV444:294	case V4L2_PIX_FMT_YUV555:295	case V4L2_PIX_FMT_YUV565:296	case V4L2_PIX_FMT_YUV32:297	case V4L2_PIX_FMT_AYUV32:298	case V4L2_PIX_FMT_XYUV32:299	case V4L2_PIX_FMT_VUYA32:300	case V4L2_PIX_FMT_VUYX32:301	case V4L2_PIX_FMT_YUVA32:302	case V4L2_PIX_FMT_YUVX32:303		tpg->color_enc = TGP_COLOR_ENC_YCBCR;304		break;305	case V4L2_PIX_FMT_YUV420M:306	case V4L2_PIX_FMT_YVU420M:307		tpg->buffers = 3;308		fallthrough;309	case V4L2_PIX_FMT_YUV420:310	case V4L2_PIX_FMT_YVU420:311		tpg->vdownsampling[1] = 2;312		tpg->vdownsampling[2] = 2;313		tpg->hdownsampling[1] = 2;314		tpg->hdownsampling[2] = 2;315		tpg->planes = 3;316		tpg->color_enc = TGP_COLOR_ENC_YCBCR;317		break;318	case V4L2_PIX_FMT_YUV422M:319	case V4L2_PIX_FMT_YVU422M:320		tpg->buffers = 3;321		fallthrough;322	case V4L2_PIX_FMT_YUV422P:323		tpg->vdownsampling[1] = 1;324		tpg->vdownsampling[2] = 1;325		tpg->hdownsampling[1] = 2;326		tpg->hdownsampling[2] = 2;327		tpg->planes = 3;328		tpg->color_enc = TGP_COLOR_ENC_YCBCR;329		break;330	case V4L2_PIX_FMT_NV16M:331	case V4L2_PIX_FMT_NV61M:332		tpg->buffers = 2;333		fallthrough;334	case V4L2_PIX_FMT_NV16:335	case V4L2_PIX_FMT_NV61:336		tpg->vdownsampling[1] = 1;337		tpg->hdownsampling[1] = 1;338		tpg->hmask[1] = ~1;339		tpg->planes = 2;340		tpg->color_enc = TGP_COLOR_ENC_YCBCR;341		break;342	case V4L2_PIX_FMT_NV12M:343	case V4L2_PIX_FMT_NV21M:344		tpg->buffers = 2;345		fallthrough;346	case V4L2_PIX_FMT_NV12:347	case V4L2_PIX_FMT_NV21:348		tpg->vdownsampling[1] = 2;349		tpg->hdownsampling[1] = 1;350		tpg->hmask[1] = ~1;351		tpg->planes = 2;352		tpg->color_enc = TGP_COLOR_ENC_YCBCR;353		break;354	case V4L2_PIX_FMT_YUV444M:355	case V4L2_PIX_FMT_YVU444M:356		tpg->buffers = 3;357		tpg->planes = 3;358		tpg->vdownsampling[1] = 1;359		tpg->vdownsampling[2] = 1;360		tpg->hdownsampling[1] = 1;361		tpg->hdownsampling[2] = 1;362		tpg->color_enc = TGP_COLOR_ENC_YCBCR;363		break;364	case V4L2_PIX_FMT_NV24:365	case V4L2_PIX_FMT_NV42:366		tpg->vdownsampling[1] = 1;367		tpg->hdownsampling[1] = 1;368		tpg->planes = 2;369		tpg->color_enc = TGP_COLOR_ENC_YCBCR;370		break;371	case V4L2_PIX_FMT_YUYV:372	case V4L2_PIX_FMT_UYVY:373	case V4L2_PIX_FMT_YVYU:374	case V4L2_PIX_FMT_VYUY:375		tpg->hmask[0] = ~1;376		tpg->color_enc = TGP_COLOR_ENC_YCBCR;377		break;378	case V4L2_PIX_FMT_HSV24:379	case V4L2_PIX_FMT_HSV32:380		tpg->color_enc = TGP_COLOR_ENC_HSV;381		break;382	default:383		return false;384	}385 386	switch (fourcc) {387	case V4L2_PIX_FMT_GREY:388	case V4L2_PIX_FMT_RGB332:389		tpg->twopixelsize[0] = 2;390		break;391	case V4L2_PIX_FMT_RGB565:392	case V4L2_PIX_FMT_RGB565X:393	case V4L2_PIX_FMT_RGB444:394	case V4L2_PIX_FMT_XRGB444:395	case V4L2_PIX_FMT_ARGB444:396	case V4L2_PIX_FMT_RGBX444:397	case V4L2_PIX_FMT_RGBA444:398	case V4L2_PIX_FMT_XBGR444:399	case V4L2_PIX_FMT_ABGR444:400	case V4L2_PIX_FMT_BGRX444:401	case V4L2_PIX_FMT_BGRA444:402	case V4L2_PIX_FMT_RGB555:403	case V4L2_PIX_FMT_XRGB555:404	case V4L2_PIX_FMT_ARGB555:405	case V4L2_PIX_FMT_RGBX555:406	case V4L2_PIX_FMT_RGBA555:407	case V4L2_PIX_FMT_XBGR555:408	case V4L2_PIX_FMT_ABGR555:409	case V4L2_PIX_FMT_BGRX555:410	case V4L2_PIX_FMT_BGRA555:411	case V4L2_PIX_FMT_RGB555X:412	case V4L2_PIX_FMT_XRGB555X:413	case V4L2_PIX_FMT_ARGB555X:414	case V4L2_PIX_FMT_YUYV:415	case V4L2_PIX_FMT_UYVY:416	case V4L2_PIX_FMT_YVYU:417	case V4L2_PIX_FMT_VYUY:418	case V4L2_PIX_FMT_YUV444:419	case V4L2_PIX_FMT_YUV555:420	case V4L2_PIX_FMT_YUV565:421	case V4L2_PIX_FMT_Y10:422	case V4L2_PIX_FMT_Y12:423	case V4L2_PIX_FMT_Y16:424	case V4L2_PIX_FMT_Y16_BE:425	case V4L2_PIX_FMT_Z16:426		tpg->twopixelsize[0] = 2 * 2;427		break;428	case V4L2_PIX_FMT_RGB24:429	case V4L2_PIX_FMT_BGR24:430	case V4L2_PIX_FMT_HSV24:431		tpg->twopixelsize[0] = 2 * 3;432		break;433	case V4L2_PIX_FMT_BGR666:434	case V4L2_PIX_FMT_RGB32:435	case V4L2_PIX_FMT_BGR32:436	case V4L2_PIX_FMT_XRGB32:437	case V4L2_PIX_FMT_XBGR32:438	case V4L2_PIX_FMT_ARGB32:439	case V4L2_PIX_FMT_ABGR32:440	case V4L2_PIX_FMT_RGBX32:441	case V4L2_PIX_FMT_BGRX32:442	case V4L2_PIX_FMT_RGBA32:443	case V4L2_PIX_FMT_BGRA32:444	case V4L2_PIX_FMT_YUV32:445	case V4L2_PIX_FMT_AYUV32:446	case V4L2_PIX_FMT_XYUV32:447	case V4L2_PIX_FMT_VUYA32:448	case V4L2_PIX_FMT_VUYX32:449	case V4L2_PIX_FMT_YUVA32:450	case V4L2_PIX_FMT_YUVX32:451	case V4L2_PIX_FMT_HSV32:452		tpg->twopixelsize[0] = 2 * 4;453		break;454	case V4L2_PIX_FMT_NV12:455	case V4L2_PIX_FMT_NV21:456	case V4L2_PIX_FMT_NV12M:457	case V4L2_PIX_FMT_NV21M:458	case V4L2_PIX_FMT_NV16:459	case V4L2_PIX_FMT_NV61:460	case V4L2_PIX_FMT_NV16M:461	case V4L2_PIX_FMT_NV61M:462	case V4L2_PIX_FMT_SBGGR8:463	case V4L2_PIX_FMT_SGBRG8:464	case V4L2_PIX_FMT_SGRBG8:465	case V4L2_PIX_FMT_SRGGB8:466		tpg->twopixelsize[0] = 2;467		tpg->twopixelsize[1] = 2;468		break;469	case V4L2_PIX_FMT_SRGGB10:470	case V4L2_PIX_FMT_SGRBG10:471	case V4L2_PIX_FMT_SGBRG10:472	case V4L2_PIX_FMT_SBGGR10:473	case V4L2_PIX_FMT_SRGGB12:474	case V4L2_PIX_FMT_SGRBG12:475	case V4L2_PIX_FMT_SGBRG12:476	case V4L2_PIX_FMT_SBGGR12:477	case V4L2_PIX_FMT_SRGGB16:478	case V4L2_PIX_FMT_SGRBG16:479	case V4L2_PIX_FMT_SGBRG16:480	case V4L2_PIX_FMT_SBGGR16:481		tpg->twopixelsize[0] = 4;482		tpg->twopixelsize[1] = 4;483		break;484	case V4L2_PIX_FMT_YUV444M:485	case V4L2_PIX_FMT_YVU444M:486	case V4L2_PIX_FMT_YUV422M:487	case V4L2_PIX_FMT_YVU422M:488	case V4L2_PIX_FMT_YUV422P:489	case V4L2_PIX_FMT_YUV420:490	case V4L2_PIX_FMT_YVU420:491	case V4L2_PIX_FMT_YUV420M:492	case V4L2_PIX_FMT_YVU420M:493		tpg->twopixelsize[0] = 2;494		tpg->twopixelsize[1] = 2;495		tpg->twopixelsize[2] = 2;496		break;497	case V4L2_PIX_FMT_NV24:498	case V4L2_PIX_FMT_NV42:499		tpg->twopixelsize[0] = 2;500		tpg->twopixelsize[1] = 4;501		break;502	}503	return true;504}505EXPORT_SYMBOL_GPL(tpg_s_fourcc);506 507void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,508		const struct v4l2_rect *compose)509{510	tpg->crop = *crop;511	tpg->compose = *compose;512	tpg->scaled_width = (tpg->src_width * tpg->compose.width +513				 tpg->crop.width - 1) / tpg->crop.width;514	tpg->scaled_width &= ~1;515	if (tpg->scaled_width > tpg->max_line_width)516		tpg->scaled_width = tpg->max_line_width;517	if (tpg->scaled_width < 2)518		tpg->scaled_width = 2;519	tpg->recalc_lines = true;520}521EXPORT_SYMBOL_GPL(tpg_s_crop_compose);522 523void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,524		       u32 field)525{526	unsigned p;527 528	tpg->src_width = width;529	tpg->src_height = height;530	tpg->field = field;531	tpg->buf_height = height;532	if (V4L2_FIELD_HAS_T_OR_B(field))533		tpg->buf_height /= 2;534	tpg->scaled_width = width;535	tpg->crop.top = tpg->crop.left = 0;536	tpg->crop.width = width;537	tpg->crop.height = height;538	tpg->compose.top = tpg->compose.left = 0;539	tpg->compose.width = width;540	tpg->compose.height = tpg->buf_height;541	for (p = 0; p < tpg->planes; p++)542		tpg->bytesperline[p] = (width * tpg->twopixelsize[p]) /543				       (2 * tpg->hdownsampling[p]);544	tpg->recalc_square_border = true;545}546EXPORT_SYMBOL_GPL(tpg_reset_source);547 548static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg)549{550	switch (tpg->pattern) {551	case TPG_PAT_BLACK:552		return TPG_COLOR_100_WHITE;553	case TPG_PAT_CSC_COLORBAR:554		return TPG_COLOR_CSC_BLACK;555	default:556		return TPG_COLOR_100_BLACK;557	}558}559 560static enum tpg_color tpg_get_textfg_color(struct tpg_data *tpg)561{562	switch (tpg->pattern) {563	case TPG_PAT_75_COLORBAR:564	case TPG_PAT_CSC_COLORBAR:565		return TPG_COLOR_CSC_WHITE;566	case TPG_PAT_BLACK:567		return TPG_COLOR_100_BLACK;568	default:569		return TPG_COLOR_100_WHITE;570	}571}572 573static inline int rec709_to_linear(int v)574{575	v = clamp(v, 0, 0xff0);576	return tpg_rec709_to_linear[v];577}578 579static inline int linear_to_rec709(int v)580{581	v = clamp(v, 0, 0xff0);582	return tpg_linear_to_rec709[v];583}584 585static void color_to_hsv(struct tpg_data *tpg, int r, int g, int b,586			   int *h, int *s, int *v)587{588	int max_rgb, min_rgb, diff_rgb;589	int aux;590	int third;591	int third_size;592 593	r >>= 4;594	g >>= 4;595	b >>= 4;596 597	/* Value */598	max_rgb = max3(r, g, b);599	*v = max_rgb;600	if (!max_rgb) {601		*h = 0;602		*s = 0;603		return;604	}605 606	/* Saturation */607	min_rgb = min3(r, g, b);608	diff_rgb = max_rgb - min_rgb;609	aux = 255 * diff_rgb;610	aux += max_rgb / 2;611	aux /= max_rgb;612	*s = aux;613	if (!aux) {614		*h = 0;615		return;616	}617 618	third_size = (tpg->real_hsv_enc == V4L2_HSV_ENC_180) ? 60 : 85;619 620	/* Hue */621	if (max_rgb == r) {622		aux =  g - b;623		third = 0;624	} else if (max_rgb == g) {625		aux =  b - r;626		third = third_size;627	} else {628		aux =  r - g;629		third = third_size * 2;630	}631 632	aux *= third_size / 2;633	aux += diff_rgb / 2;634	aux /= diff_rgb;635	aux += third;636 637	/* Clamp Hue */638	if (tpg->real_hsv_enc == V4L2_HSV_ENC_180) {639		if (aux < 0)640			aux += 180;641		else if (aux > 180)642			aux -= 180;643	} else {644		aux = aux & 0xff;645	}646 647	*h = aux;648}649 650static void rgb2ycbcr(const int m[3][3], int r, int g, int b,651			int y_offset, int *y, int *cb, int *cr)652{653	*y  = ((m[0][0] * r + m[0][1] * g + m[0][2] * b) >> 16) + (y_offset << 4);654	*cb = ((m[1][0] * r + m[1][1] * g + m[1][2] * b) >> 16) + (128 << 4);655	*cr = ((m[2][0] * r + m[2][1] * g + m[2][2] * b) >> 16) + (128 << 4);656}657 658static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,659			   int *y, int *cb, int *cr)660{661#define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))662 663	static const int bt601[3][3] = {664		{ COEFF(0.299, 219),   COEFF(0.587, 219),   COEFF(0.114, 219)   },665		{ COEFF(-0.1687, 224), COEFF(-0.3313, 224), COEFF(0.5, 224)     },666		{ COEFF(0.5, 224),     COEFF(-0.4187, 224), COEFF(-0.0813, 224) },667	};668	static const int bt601_full[3][3] = {669		{ COEFF(0.299, 255),   COEFF(0.587, 255),   COEFF(0.114, 255)   },670		{ COEFF(-0.1687, 255), COEFF(-0.3313, 255), COEFF(0.5, 255)     },671		{ COEFF(0.5, 255),     COEFF(-0.4187, 255), COEFF(-0.0813, 255) },672	};673	static const int rec709[3][3] = {674		{ COEFF(0.2126, 219),  COEFF(0.7152, 219),  COEFF(0.0722, 219)  },675		{ COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224)     },676		{ COEFF(0.5, 224),     COEFF(-0.4542, 224), COEFF(-0.0458, 224) },677	};678	static const int rec709_full[3][3] = {679		{ COEFF(0.2126, 255),  COEFF(0.7152, 255),  COEFF(0.0722, 255)  },680		{ COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255)     },681		{ COEFF(0.5, 255),     COEFF(-0.4542, 255), COEFF(-0.0458, 255) },682	};683	static const int smpte240m[3][3] = {684		{ COEFF(0.212, 219),  COEFF(0.701, 219),  COEFF(0.087, 219)  },685		{ COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224)    },686		{ COEFF(0.5, 224),    COEFF(-0.445, 224), COEFF(-0.055, 224) },687	};688	static const int smpte240m_full[3][3] = {689		{ COEFF(0.212, 255),  COEFF(0.701, 255),  COEFF(0.087, 255)  },690		{ COEFF(-0.116, 255), COEFF(-0.384, 255), COEFF(0.5, 255)    },691		{ COEFF(0.5, 255),    COEFF(-0.445, 255), COEFF(-0.055, 255) },692	};693	static const int bt2020[3][3] = {694		{ COEFF(0.2627, 219),  COEFF(0.6780, 219),  COEFF(0.0593, 219)  },695		{ COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224)     },696		{ COEFF(0.5, 224),     COEFF(-0.4598, 224), COEFF(-0.0402, 224) },697	};698	static const int bt2020_full[3][3] = {699		{ COEFF(0.2627, 255),  COEFF(0.6780, 255),  COEFF(0.0593, 255)  },700		{ COEFF(-0.1396, 255), COEFF(-0.3604, 255), COEFF(0.5, 255)     },701		{ COEFF(0.5, 255),     COEFF(-0.4598, 255), COEFF(-0.0402, 255) },702	};703	static const int bt2020c[4] = {704		COEFF(1.0 / 1.9404, 224), COEFF(1.0 / 1.5816, 224),705		COEFF(1.0 / 1.7184, 224), COEFF(1.0 / 0.9936, 224),706	};707	static const int bt2020c_full[4] = {708		COEFF(1.0 / 1.9404, 255), COEFF(1.0 / 1.5816, 255),709		COEFF(1.0 / 1.7184, 255), COEFF(1.0 / 0.9936, 255),710	};711 712	bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;713	unsigned y_offset = full ? 0 : 16;714	int lin_y, yc;715 716	switch (tpg->real_ycbcr_enc) {717	case V4L2_YCBCR_ENC_601:718		rgb2ycbcr(full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr);719		break;720	case V4L2_YCBCR_ENC_XV601:721		/* Ignore quantization range, there is only one possible722		 * Y'CbCr encoding. */723		rgb2ycbcr(bt601, r, g, b, 16, y, cb, cr);724		break;725	case V4L2_YCBCR_ENC_XV709:726		/* Ignore quantization range, there is only one possible727		 * Y'CbCr encoding. */728		rgb2ycbcr(rec709, r, g, b, 16, y, cb, cr);729		break;730	case V4L2_YCBCR_ENC_BT2020:731		rgb2ycbcr(full ? bt2020_full : bt2020, r, g, b, y_offset, y, cb, cr);732		break;733	case V4L2_YCBCR_ENC_BT2020_CONST_LUM:734		lin_y = (COEFF(0.2627, 255) * rec709_to_linear(r) +735			 COEFF(0.6780, 255) * rec709_to_linear(g) +736			 COEFF(0.0593, 255) * rec709_to_linear(b)) >> 16;737		yc = linear_to_rec709(lin_y);738		*y = full ? yc : (yc * 219) / 255 + (16 << 4);739		if (b <= yc)740			*cb = (((b - yc) * (full ? bt2020c_full[0] : bt2020c[0])) >> 16) + (128 << 4);741		else742			*cb = (((b - yc) * (full ? bt2020c_full[1] : bt2020c[1])) >> 16) + (128 << 4);743		if (r <= yc)744			*cr = (((r - yc) * (full ? bt2020c_full[2] : bt2020c[2])) >> 16) + (128 << 4);745		else746			*cr = (((r - yc) * (full ? bt2020c_full[3] : bt2020c[3])) >> 16) + (128 << 4);747		break;748	case V4L2_YCBCR_ENC_SMPTE240M:749		rgb2ycbcr(full ? smpte240m_full : smpte240m, r, g, b, y_offset, y, cb, cr);750		break;751	case V4L2_YCBCR_ENC_709:752	default:753		rgb2ycbcr(full ? rec709_full : rec709, r, g, b, y_offset, y, cb, cr);754		break;755	}756}757 758static void ycbcr2rgb(const int m[3][3], int y, int cb, int cr,759			int y_offset, int *r, int *g, int *b)760{761	y -= y_offset << 4;762	cb -= 128 << 4;763	cr -= 128 << 4;764	*r = m[0][0] * y + m[0][1] * cb + m[0][2] * cr;765	*g = m[1][0] * y + m[1][1] * cb + m[1][2] * cr;766	*b = m[2][0] * y + m[2][1] * cb + m[2][2] * cr;767	*r = clamp(*r >> 12, 0, 0xff0);768	*g = clamp(*g >> 12, 0, 0xff0);769	*b = clamp(*b >> 12, 0, 0xff0);770}771 772static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr,773			   int *r, int *g, int *b)774{775#undef COEFF776#define COEFF(v, r) ((int)(0.5 + (v) * ((255.0 * 255.0 * 16.0) / (r))))777	static const int bt601[3][3] = {778		{ COEFF(1, 219), COEFF(0, 224),       COEFF(1.4020, 224)  },779		{ COEFF(1, 219), COEFF(-0.3441, 224), COEFF(-0.7141, 224) },780		{ COEFF(1, 219), COEFF(1.7720, 224),  COEFF(0, 224)       },781	};782	static const int bt601_full[3][3] = {783		{ COEFF(1, 255), COEFF(0, 255),       COEFF(1.4020, 255)  },784		{ COEFF(1, 255), COEFF(-0.3441, 255), COEFF(-0.7141, 255) },785		{ COEFF(1, 255), COEFF(1.7720, 255),  COEFF(0, 255)       },786	};787	static const int rec709[3][3] = {788		{ COEFF(1, 219), COEFF(0, 224),       COEFF(1.5748, 224)  },789		{ COEFF(1, 219), COEFF(-0.1873, 224), COEFF(-0.4681, 224) },790		{ COEFF(1, 219), COEFF(1.8556, 224),  COEFF(0, 224)       },791	};792	static const int rec709_full[3][3] = {793		{ COEFF(1, 255), COEFF(0, 255),       COEFF(1.5748, 255)  },794		{ COEFF(1, 255), COEFF(-0.1873, 255), COEFF(-0.4681, 255) },795		{ COEFF(1, 255), COEFF(1.8556, 255),  COEFF(0, 255)       },796	};797	static const int smpte240m[3][3] = {798		{ COEFF(1, 219), COEFF(0, 224),       COEFF(1.5756, 224)  },799		{ COEFF(1, 219), COEFF(-0.2253, 224), COEFF(-0.4767, 224) },800		{ COEFF(1, 219), COEFF(1.8270, 224),  COEFF(0, 224)       },801	};802	static const int smpte240m_full[3][3] = {803		{ COEFF(1, 255), COEFF(0, 255),       COEFF(1.5756, 255)  },804		{ COEFF(1, 255), COEFF(-0.2253, 255), COEFF(-0.4767, 255) },805		{ COEFF(1, 255), COEFF(1.8270, 255),  COEFF(0, 255)       },806	};807	static const int bt2020[3][3] = {808		{ COEFF(1, 219), COEFF(0, 224),       COEFF(1.4746, 224)  },809		{ COEFF(1, 219), COEFF(-0.1646, 224), COEFF(-0.5714, 224) },810		{ COEFF(1, 219), COEFF(1.8814, 224),  COEFF(0, 224)       },811	};812	static const int bt2020_full[3][3] = {813		{ COEFF(1, 255), COEFF(0, 255),       COEFF(1.4746, 255)  },814		{ COEFF(1, 255), COEFF(-0.1646, 255), COEFF(-0.5714, 255) },815		{ COEFF(1, 255), COEFF(1.8814, 255),  COEFF(0, 255)       },816	};817	static const int bt2020c[4] = {818		COEFF(1.9404, 224), COEFF(1.5816, 224),819		COEFF(1.7184, 224), COEFF(0.9936, 224),820	};821	static const int bt2020c_full[4] = {822		COEFF(1.9404, 255), COEFF(1.5816, 255),823		COEFF(1.7184, 255), COEFF(0.9936, 255),824	};825 826	bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;827	unsigned y_offset = full ? 0 : 16;828	int y_fac = full ? COEFF(1.0, 255) : COEFF(1.0, 219);829	int lin_r, lin_g, lin_b, lin_y;830 831	switch (tpg->real_ycbcr_enc) {832	case V4L2_YCBCR_ENC_601:833		ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b);834		break;835	case V4L2_YCBCR_ENC_XV601:836		/* Ignore quantization range, there is only one possible837		 * Y'CbCr encoding. */838		ycbcr2rgb(bt601, y, cb, cr, 16, r, g, b);839		break;840	case V4L2_YCBCR_ENC_XV709:841		/* Ignore quantization range, there is only one possible842		 * Y'CbCr encoding. */843		ycbcr2rgb(rec709, y, cb, cr, 16, r, g, b);844		break;845	case V4L2_YCBCR_ENC_BT2020:846		ycbcr2rgb(full ? bt2020_full : bt2020, y, cb, cr, y_offset, r, g, b);847		break;848	case V4L2_YCBCR_ENC_BT2020_CONST_LUM:849		y -= full ? 0 : 16 << 4;850		cb -= 128 << 4;851		cr -= 128 << 4;852 853		if (cb <= 0)854			*b = y_fac * y + (full ? bt2020c_full[0] : bt2020c[0]) * cb;855		else856			*b = y_fac * y + (full ? bt2020c_full[1] : bt2020c[1]) * cb;857		*b = *b >> 12;858		if (cr <= 0)859			*r = y_fac * y + (full ? bt2020c_full[2] : bt2020c[2]) * cr;860		else861			*r = y_fac * y + (full ? bt2020c_full[3] : bt2020c[3]) * cr;862		*r = *r >> 12;863		lin_r = rec709_to_linear(*r);864		lin_b = rec709_to_linear(*b);865		lin_y = rec709_to_linear((y * 255) / (full ? 255 : 219));866 867		lin_g = COEFF(1.0 / 0.6780, 255) * lin_y -868			COEFF(0.2627 / 0.6780, 255) * lin_r -869			COEFF(0.0593 / 0.6780, 255) * lin_b;870		*g = linear_to_rec709(lin_g >> 12);871		break;872	case V4L2_YCBCR_ENC_SMPTE240M:873		ycbcr2rgb(full ? smpte240m_full : smpte240m, y, cb, cr, y_offset, r, g, b);874		break;875	case V4L2_YCBCR_ENC_709:876	default:877		ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, y_offset, r, g, b);878		break;879	}880}881 882/* precalculate color bar values to speed up rendering */883static void precalculate_color(struct tpg_data *tpg, int k)884{885	int col = k;886	int r = tpg_colors[col].r;887	int g = tpg_colors[col].g;888	int b = tpg_colors[col].b;889	int y, cb, cr;890	bool ycbcr_valid = false;891 892	if (k == TPG_COLOR_TEXTBG) {893		col = tpg_get_textbg_color(tpg);894 895		r = tpg_colors[col].r;896		g = tpg_colors[col].g;897		b = tpg_colors[col].b;898	} else if (k == TPG_COLOR_TEXTFG) {899		col = tpg_get_textfg_color(tpg);900 901		r = tpg_colors[col].r;902		g = tpg_colors[col].g;903		b = tpg_colors[col].b;904	} else if (tpg->pattern == TPG_PAT_NOISE) {905		r = g = b = get_random_u8();906	} else if (k == TPG_COLOR_RANDOM) {907		r = g = b = tpg->qual_offset + get_random_u32_below(196);908	} else if (k >= TPG_COLOR_RAMP) {909		r = g = b = k - TPG_COLOR_RAMP;910	}911 912	if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {913		r = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].r;914		g = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].g;915		b = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].b;916	} else {917		r <<= 4;918		g <<= 4;919		b <<= 4;920	}921 922	if (tpg->qual == TPG_QUAL_GRAY ||923	    tpg->color_enc ==  TGP_COLOR_ENC_LUMA) {924		/* Rec. 709 Luma function */925		/* (0.2126, 0.7152, 0.0722) * (255 * 256) */926		r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16;927	}928 929	/*930	 * The assumption is that the RGB output is always full range,931	 * so only if the rgb_range overrides the 'real' rgb range do932	 * we need to convert the RGB values.933	 *934	 * Remember that r, g and b are still in the 0 - 0xff0 range.935	 */936	if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&937	    tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL &&938	    tpg->color_enc == TGP_COLOR_ENC_RGB) {939		/*940		 * Convert from full range (which is what r, g and b are)941		 * to limited range (which is the 'real' RGB range), which942		 * is then interpreted as full range.943		 */944		r = (r * 219) / 255 + (16 << 4);945		g = (g * 219) / 255 + (16 << 4);946		b = (b * 219) / 255 + (16 << 4);947	} else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&948		   tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&949		   tpg->color_enc == TGP_COLOR_ENC_RGB) {950 951		/*952		 * Clamp r, g and b to the limited range and convert to full953		 * range since that's what we deliver.954		 */955		r = clamp(r, 16 << 4, 235 << 4);956		g = clamp(g, 16 << 4, 235 << 4);957		b = clamp(b, 16 << 4, 235 << 4);958		r = (r - (16 << 4)) * 255 / 219;959		g = (g - (16 << 4)) * 255 / 219;960		b = (b - (16 << 4)) * 255 / 219;961	}962 963	if ((tpg->brightness != 128 || tpg->contrast != 128 ||964	     tpg->saturation != 128 || tpg->hue) &&965	    tpg->color_enc != TGP_COLOR_ENC_LUMA) {966		/* Implement these operations */967		int tmp_cb, tmp_cr;968 969		/* First convert to YCbCr */970 971		color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);972 973		y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;974		y += (tpg->brightness << 4) - (128 << 4);975 976		cb -= 128 << 4;977		cr -= 128 << 4;978		tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127;979		tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127;980 981		cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128);982		cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128);983		if (tpg->color_enc == TGP_COLOR_ENC_YCBCR)984			ycbcr_valid = true;985		else986			ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b);987	} else if ((tpg->brightness != 128 || tpg->contrast != 128) &&988		   tpg->color_enc == TGP_COLOR_ENC_LUMA) {989		r = (16 << 4) + ((r - (16 << 4)) * tpg->contrast) / 128;990		r += (tpg->brightness << 4) - (128 << 4);991	}992 993	switch (tpg->color_enc) {994	case TGP_COLOR_ENC_HSV:995	{996		int h, s, v;997 998		color_to_hsv(tpg, r, g, b, &h, &s, &v);999		tpg->colors[k][0] = h;1000		tpg->colors[k][1] = s;1001		tpg->colors[k][2] = v;1002		break;1003	}1004	case TGP_COLOR_ENC_YCBCR:1005	{1006		/* Convert to YCbCr */1007		if (!ycbcr_valid)1008			color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);1009 1010		y >>= 4;1011		cb >>= 4;1012		cr >>= 4;1013		/*1014		 * XV601/709 use the header/footer margins to encode R', G'1015		 * and B' values outside the range [0-1]. So do not clamp1016		 * XV601/709 values.1017		 */1018		if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE &&1019		    tpg->real_ycbcr_enc != V4L2_YCBCR_ENC_XV601 &&1020		    tpg->real_ycbcr_enc != V4L2_YCBCR_ENC_XV709) {1021			y = clamp(y, 16, 235);1022			cb = clamp(cb, 16, 240);1023			cr = clamp(cr, 16, 240);1024		} else {1025			y = clamp(y, 1, 254);1026			cb = clamp(cb, 1, 254);1027			cr = clamp(cr, 1, 254);1028		}1029		switch (tpg->fourcc) {1030		case V4L2_PIX_FMT_YUV444:1031			y >>= 4;1032			cb >>= 4;1033			cr >>= 4;1034			break;1035		case V4L2_PIX_FMT_YUV555:1036			y >>= 3;1037			cb >>= 3;1038			cr >>= 3;1039			break;1040		case V4L2_PIX_FMT_YUV565:1041			y >>= 3;1042			cb >>= 2;1043			cr >>= 3;1044			break;1045		}1046		tpg->colors[k][0] = y;1047		tpg->colors[k][1] = cb;1048		tpg->colors[k][2] = cr;1049		break;1050	}1051	case TGP_COLOR_ENC_LUMA:1052	{1053		tpg->colors[k][0] = r >> 4;1054		break;1055	}1056	case TGP_COLOR_ENC_RGB:1057	{1058		if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {1059			r = (r * 219) / 255 + (16 << 4);1060			g = (g * 219) / 255 + (16 << 4);1061			b = (b * 219) / 255 + (16 << 4);1062		}1063		switch (tpg->fourcc) {1064		case V4L2_PIX_FMT_RGB332:1065			r >>= 9;1066			g >>= 9;1067			b >>= 10;1068			break;1069		case V4L2_PIX_FMT_RGB565:1070		case V4L2_PIX_FMT_RGB565X:1071			r >>= 7;1072			g >>= 6;1073			b >>= 7;1074			break;1075		case V4L2_PIX_FMT_RGB444:1076		case V4L2_PIX_FMT_XRGB444:1077		case V4L2_PIX_FMT_ARGB444:1078		case V4L2_PIX_FMT_RGBX444:1079		case V4L2_PIX_FMT_RGBA444:1080		case V4L2_PIX_FMT_XBGR444:1081		case V4L2_PIX_FMT_ABGR444:1082		case V4L2_PIX_FMT_BGRX444:1083		case V4L2_PIX_FMT_BGRA444:1084			r >>= 8;1085			g >>= 8;1086			b >>= 8;1087			break;1088		case V4L2_PIX_FMT_RGB555:1089		case V4L2_PIX_FMT_XRGB555:1090		case V4L2_PIX_FMT_ARGB555:1091		case V4L2_PIX_FMT_RGBX555:1092		case V4L2_PIX_FMT_RGBA555:1093		case V4L2_PIX_FMT_XBGR555:1094		case V4L2_PIX_FMT_ABGR555:1095		case V4L2_PIX_FMT_BGRX555:1096		case V4L2_PIX_FMT_BGRA555:1097		case V4L2_PIX_FMT_RGB555X:1098		case V4L2_PIX_FMT_XRGB555X:1099		case V4L2_PIX_FMT_ARGB555X:1100			r >>= 7;1101			g >>= 7;1102			b >>= 7;1103			break;1104		case V4L2_PIX_FMT_BGR666:1105			r >>= 6;1106			g >>= 6;1107			b >>= 6;1108			break;1109		default:1110			r >>= 4;1111			g >>= 4;1112			b >>= 4;1113			break;1114		}1115 1116		tpg->colors[k][0] = r;1117		tpg->colors[k][1] = g;1118		tpg->colors[k][2] = b;1119		break;1120	}1121	}1122}1123 1124static void tpg_precalculate_colors(struct tpg_data *tpg)1125{1126	int k;1127 1128	for (k = 0; k < TPG_COLOR_MAX; k++)1129		precalculate_color(tpg, k);1130}1131 1132/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */1133static void gen_twopix(struct tpg_data *tpg,1134		u8 buf[TPG_MAX_PLANES][8], int color, bool odd)1135{1136	unsigned offset = odd * tpg->twopixelsize[0] / 2;1137	u8 alpha = tpg->alpha_component;1138	u8 r_y_h, g_u_s, b_v;1139 1140	if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&1141				   color != TPG_COLOR_100_RED &&1142				   color != TPG_COLOR_75_RED)1143		alpha = 0;1144	if (color == TPG_COLOR_RANDOM)1145		precalculate_color(tpg, color);1146	r_y_h = tpg->colors[color][0]; /* R or precalculated Y, H */1147	g_u_s = tpg->colors[color][1]; /* G or precalculated U, V */1148	b_v = tpg->colors[color][2]; /* B or precalculated V */1149 1150	switch (tpg->fourcc) {1151	case V4L2_PIX_FMT_GREY:1152		buf[0][offset] = r_y_h;1153		break;1154	case V4L2_PIX_FMT_Y10:1155		buf[0][offset] = (r_y_h << 2) & 0xff;1156		buf[0][offset+1] = r_y_h >> 6;1157		break;1158	case V4L2_PIX_FMT_Y12:1159		buf[0][offset] = (r_y_h << 4) & 0xff;1160		buf[0][offset+1] = r_y_h >> 4;1161		break;1162	case V4L2_PIX_FMT_Y16:1163	case V4L2_PIX_FMT_Z16:1164		/*1165		 * Ideally both bytes should be set to r_y_h, but then you won't1166		 * be able to detect endian problems. So keep it 0 except for1167		 * the corner case where r_y_h is 0xff so white really will be1168		 * white (0xffff).1169		 */1170		buf[0][offset] = r_y_h == 0xff ? r_y_h : 0;1171		buf[0][offset+1] = r_y_h;1172		break;1173	case V4L2_PIX_FMT_Y16_BE:1174		/* See comment for V4L2_PIX_FMT_Y16 above */1175		buf[0][offset] = r_y_h;1176		buf[0][offset+1] = r_y_h == 0xff ? r_y_h : 0;1177		break;1178	case V4L2_PIX_FMT_YUV422M:1179	case V4L2_PIX_FMT_YUV422P:1180	case V4L2_PIX_FMT_YUV420:1181	case V4L2_PIX_FMT_YUV420M:1182		buf[0][offset] = r_y_h;1183		if (odd) {1184			buf[1][0] = (buf[1][0] + g_u_s) / 2;1185			buf[2][0] = (buf[2][0] + b_v) / 2;1186			buf[1][1] = buf[1][0];1187			buf[2][1] = buf[2][0];1188			break;1189		}1190		buf[1][0] = g_u_s;1191		buf[2][0] = b_v;1192		break;1193	case V4L2_PIX_FMT_YVU422M:1194	case V4L2_PIX_FMT_YVU420:1195	case V4L2_PIX_FMT_YVU420M:1196		buf[0][offset] = r_y_h;1197		if (odd) {1198			buf[1][0] = (buf[1][0] + b_v) / 2;1199			buf[2][0] = (buf[2][0] + g_u_s) / 2;1200			buf[1][1] = buf[1][0];1201			buf[2][1] = buf[2][0];1202			break;1203		}1204		buf[1][0] = b_v;1205		buf[2][0] = g_u_s;1206		break;1207 1208	case V4L2_PIX_FMT_NV12:1209	case V4L2_PIX_FMT_NV12M:1210	case V4L2_PIX_FMT_NV16:1211	case V4L2_PIX_FMT_NV16M:1212		buf[0][offset] = r_y_h;1213		if (odd) {1214			buf[1][0] = (buf[1][0] + g_u_s) / 2;1215			buf[1][1] = (buf[1][1] + b_v) / 2;1216			break;1217		}1218		buf[1][0] = g_u_s;1219		buf[1][1] = b_v;1220		break;1221	case V4L2_PIX_FMT_NV21:1222	case V4L2_PIX_FMT_NV21M:1223	case V4L2_PIX_FMT_NV61:1224	case V4L2_PIX_FMT_NV61M:1225		buf[0][offset] = r_y_h;1226		if (odd) {1227			buf[1][0] = (buf[1][0] + b_v) / 2;1228			buf[1][1] = (buf[1][1] + g_u_s) / 2;1229			break;1230		}1231		buf[1][0] = b_v;1232		buf[1][1] = g_u_s;1233		break;1234 1235	case V4L2_PIX_FMT_YUV444M:1236		buf[0][offset] = r_y_h;1237		buf[1][offset] = g_u_s;1238		buf[2][offset] = b_v;1239		break;1240 1241	case V4L2_PIX_FMT_YVU444M:1242		buf[0][offset] = r_y_h;1243		buf[1][offset] = b_v;1244		buf[2][offset] = g_u_s;1245		break;1246 1247	case V4L2_PIX_FMT_NV24:1248		buf[0][offset] = r_y_h;1249		buf[1][2 * offset] = g_u_s;1250		buf[1][(2 * offset + 1) % 8] = b_v;1251		break;1252 1253	case V4L2_PIX_FMT_NV42:1254		buf[0][offset] = r_y_h;1255		buf[1][2 * offset] = b_v;1256		buf[1][(2 * offset + 1) % 8] = g_u_s;1257		break;1258 1259	case V4L2_PIX_FMT_YUYV:1260		buf[0][offset] = r_y_h;1261		if (odd) {1262			buf[0][1] = (buf[0][1] + g_u_s) / 2;1263			buf[0][3] = (buf[0][3] + b_v) / 2;1264			break;1265		}1266		buf[0][1] = g_u_s;1267		buf[0][3] = b_v;1268		break;1269	case V4L2_PIX_FMT_UYVY:1270		buf[0][offset + 1] = r_y_h;1271		if (odd) {1272			buf[0][0] = (buf[0][0] + g_u_s) / 2;1273			buf[0][2] = (buf[0][2] + b_v) / 2;1274			break;1275		}1276		buf[0][0] = g_u_s;1277		buf[0][2] = b_v;1278		break;1279	case V4L2_PIX_FMT_YVYU:1280		buf[0][offset] = r_y_h;1281		if (odd) {1282			buf[0][1] = (buf[0][1] + b_v) / 2;1283			buf[0][3] = (buf[0][3] + g_u_s) / 2;1284			break;1285		}1286		buf[0][1] = b_v;1287		buf[0][3] = g_u_s;1288		break;1289	case V4L2_PIX_FMT_VYUY:1290		buf[0][offset + 1] = r_y_h;1291		if (odd) {1292			buf[0][0] = (buf[0][0] + b_v) / 2;1293			buf[0][2] = (buf[0][2] + g_u_s) / 2;1294			break;1295		}1296		buf[0][0] = b_v;1297		buf[0][2] = g_u_s;1298		break;1299	case V4L2_PIX_FMT_RGB332:1300		buf[0][offset] = (r_y_h << 5) | (g_u_s << 2) | b_v;1301		break;1302	case V4L2_PIX_FMT_YUV565:1303	case V4L2_PIX_FMT_RGB565:1304		buf[0][offset] = (g_u_s << 5) | b_v;1305		buf[0][offset + 1] = (r_y_h << 3) | (g_u_s >> 3);1306		break;1307	case V4L2_PIX_FMT_RGB565X:1308		buf[0][offset] = (r_y_h << 3) | (g_u_s >> 3);1309		buf[0][offset + 1] = (g_u_s << 5) | b_v;1310		break;1311	case V4L2_PIX_FMT_RGB444:1312	case V4L2_PIX_FMT_XRGB444:1313		alpha = 0;1314		fallthrough;1315	case V4L2_PIX_FMT_YUV444:1316	case V4L2_PIX_FMT_ARGB444:1317		buf[0][offset] = (g_u_s << 4) | b_v;1318		buf[0][offset + 1] = (alpha & 0xf0) | r_y_h;1319		break;1320	case V4L2_PIX_FMT_RGBX444:1321		alpha = 0;1322		fallthrough;1323	case V4L2_PIX_FMT_RGBA444:1324		buf[0][offset] = (b_v << 4) | (alpha >> 4);1325		buf[0][offset + 1] = (r_y_h << 4) | g_u_s;1326		break;1327	case V4L2_PIX_FMT_XBGR444:1328		alpha = 0;1329		fallthrough;1330	case V4L2_PIX_FMT_ABGR444:1331		buf[0][offset] = (g_u_s << 4) | r_y_h;1332		buf[0][offset + 1] = (alpha & 0xf0) | b_v;1333		break;1334	case V4L2_PIX_FMT_BGRX444:1335		alpha = 0;1336		fallthrough;1337	case V4L2_PIX_FMT_BGRA444:1338		buf[0][offset] = (r_y_h << 4) | (alpha >> 4);1339		buf[0][offset + 1] = (b_v << 4) | g_u_s;1340		break;1341	case V4L2_PIX_FMT_RGB555:1342	case V4L2_PIX_FMT_XRGB555:1343		alpha = 0;1344		fallthrough;1345	case V4L2_PIX_FMT_YUV555:1346	case V4L2_PIX_FMT_ARGB555:1347		buf[0][offset] = (g_u_s << 5) | b_v;1348		buf[0][offset + 1] = (alpha & 0x80) | (r_y_h << 2)1349						    | (g_u_s >> 3);1350		break;1351	case V4L2_PIX_FMT_RGBX555:1352		alpha = 0;1353		fallthrough;1354	case V4L2_PIX_FMT_RGBA555:1355		buf[0][offset] = (g_u_s << 6) | (b_v << 1) |1356				 ((alpha & 0x80) >> 7);1357		buf[0][offset + 1] = (r_y_h << 3) | (g_u_s >> 2);1358		break;1359	case V4L2_PIX_FMT_XBGR555:1360		alpha = 0;1361		fallthrough;1362	case V4L2_PIX_FMT_ABGR555:1363		buf[0][offset] = (g_u_s << 5) | r_y_h;1364		buf[0][offset + 1] = (alpha & 0x80) | (b_v << 2)1365						    | (g_u_s >> 3);1366		break;1367	case V4L2_PIX_FMT_BGRX555:1368		alpha = 0;1369		fallthrough;1370	case V4L2_PIX_FMT_BGRA555:1371		buf[0][offset] = (g_u_s << 6) | (r_y_h << 1) |1372				 ((alpha & 0x80) >> 7);1373		buf[0][offset + 1] = (b_v << 3) | (g_u_s >> 2);1374		break;1375	case V4L2_PIX_FMT_RGB555X:1376	case V4L2_PIX_FMT_XRGB555X:1377		alpha = 0;1378		fallthrough;1379	case V4L2_PIX_FMT_ARGB555X:1380		buf[0][offset] = (alpha & 0x80) | (r_y_h << 2) | (g_u_s >> 3);1381		buf[0][offset + 1] = (g_u_s << 5) | b_v;1382		break;1383	case V4L2_PIX_FMT_RGB24:1384	case V4L2_PIX_FMT_HSV24:1385		buf[0][offset] = r_y_h;1386		buf[0][offset + 1] = g_u_s;1387		buf[0][offset + 2] = b_v;1388		break;1389	case V4L2_PIX_FMT_BGR24:1390		buf[0][offset] = b_v;1391		buf[0][offset + 1] = g_u_s;1392		buf[0][offset + 2] = r_y_h;1393		break;1394	case V4L2_PIX_FMT_BGR666:1395		buf[0][offset] = (b_v << 2) | (g_u_s >> 4);1396		buf[0][offset + 1] = (g_u_s << 4) | (r_y_h >> 2);1397		buf[0][offset + 2] = r_y_h << 6;1398		buf[0][offset + 3] = 0;1399		break;1400	case V4L2_PIX_FMT_RGB32:1401	case V4L2_PIX_FMT_XRGB32:1402	case V4L2_PIX_FMT_HSV32:1403	case V4L2_PIX_FMT_XYUV32:1404		alpha = 0;1405		fallthrough;1406	case V4L2_PIX_FMT_YUV32:1407	case V4L2_PIX_FMT_ARGB32:1408	case V4L2_PIX_FMT_AYUV32:1409		buf[0][offset] = alpha;1410		buf[0][offset + 1] = r_y_h;1411		buf[0][offset + 2] = g_u_s;1412		buf[0][offset + 3] = b_v;1413		break;1414	case V4L2_PIX_FMT_RGBX32:1415	case V4L2_PIX_FMT_YUVX32:1416		alpha = 0;1417		fallthrough;1418	case V4L2_PIX_FMT_RGBA32:1419	case V4L2_PIX_FMT_YUVA32:1420		buf[0][offset] = r_y_h;1421		buf[0][offset + 1] = g_u_s;1422		buf[0][offset + 2] = b_v;1423		buf[0][offset + 3] = alpha;1424		break;1425	case V4L2_PIX_FMT_BGR32:1426	case V4L2_PIX_FMT_XBGR32:1427	case V4L2_PIX_FMT_VUYX32:1428		alpha = 0;1429		fallthrough;1430	case V4L2_PIX_FMT_ABGR32:1431	case V4L2_PIX_FMT_VUYA32:1432		buf[0][offset] = b_v;1433		buf[0][offset + 1] = g_u_s;1434		buf[0][offset + 2] = r_y_h;1435		buf[0][offset + 3] = alpha;1436		break;1437	case V4L2_PIX_FMT_BGRX32:1438		alpha = 0;1439		fallthrough;1440	case V4L2_PIX_FMT_BGRA32:1441		buf[0][offset] = alpha;1442		buf[0][offset + 1] = b_v;1443		buf[0][offset + 2] = g_u_s;1444		buf[0][offset + 3] = r_y_h;1445		break;1446	case V4L2_PIX_FMT_SBGGR8:1447		buf[0][offset] = odd ? g_u_s : b_v;1448		buf[1][offset] = odd ? r_y_h : g_u_s;1449		break;1450	case V4L2_PIX_FMT_SGBRG8:1451		buf[0][offset] = odd ? b_v : g_u_s;1452		buf[1][offset] = odd ? g_u_s : r_y_h;1453		break;1454	case V4L2_PIX_FMT_SGRBG8:1455		buf[0][offset] = odd ? r_y_h : g_u_s;1456		buf[1][offset] = odd ? g_u_s : b_v;1457		break;1458	case V4L2_PIX_FMT_SRGGB8:1459		buf[0][offset] = odd ? g_u_s : r_y_h;1460		buf[1][offset] = odd ? b_v : g_u_s;1461		break;1462	case V4L2_PIX_FMT_SBGGR10:1463		buf[0][offset] = odd ? g_u_s << 2 : b_v << 2;1464		buf[0][offset + 1] = odd ? g_u_s >> 6 : b_v >> 6;1465		buf[1][offset] = odd ? r_y_h << 2 : g_u_s << 2;1466		buf[1][offset + 1] = odd ? r_y_h >> 6 : g_u_s >> 6;1467		buf[0][offset] |= (buf[0][offset] >> 2) & 3;1468		buf[1][offset] |= (buf[1][offset] >> 2) & 3;1469		break;1470	case V4L2_PIX_FMT_SGBRG10:1471		buf[0][offset] = odd ? b_v << 2 : g_u_s << 2;1472		buf[0][offset + 1] = odd ? b_v >> 6 : g_u_s >> 6;1473		buf[1][offset] = odd ? g_u_s << 2 : r_y_h << 2;1474		buf[1][offset + 1] = odd ? g_u_s >> 6 : r_y_h >> 6;1475		buf[0][offset] |= (buf[0][offset] >> 2) & 3;1476		buf[1][offset] |= (buf[1][offset] >> 2) & 3;1477		break;1478	case V4L2_PIX_FMT_SGRBG10:1479		buf[0][offset] = odd ? r_y_h << 2 : g_u_s << 2;1480		buf[0][offset + 1] = odd ? r_y_h >> 6 : g_u_s >> 6;1481		buf[1][offset] = odd ? g_u_s << 2 : b_v << 2;1482		buf[1][offset + 1] = odd ? g_u_s >> 6 : b_v >> 6;1483		buf[0][offset] |= (buf[0][offset] >> 2) & 3;1484		buf[1][offset] |= (buf[1][offset] >> 2) & 3;1485		break;1486	case V4L2_PIX_FMT_SRGGB10:1487		buf[0][offset] = odd ? g_u_s << 2 : r_y_h << 2;1488		buf[0][offset + 1] = odd ? g_u_s >> 6 : r_y_h >> 6;1489		buf[1][offset] = odd ? b_v << 2 : g_u_s << 2;1490		buf[1][offset + 1] = odd ? b_v >> 6 : g_u_s >> 6;1491		buf[0][offset] |= (buf[0][offset] >> 2) & 3;1492		buf[1][offset] |= (buf[1][offset] >> 2) & 3;1493		break;1494	case V4L2_PIX_FMT_SBGGR12:1495		buf[0][offset] = odd ? g_u_s << 4 : b_v << 4;1496		buf[0][offset + 1] = odd ? g_u_s >> 4 : b_v >> 4;1497		buf[1][offset] = odd ? r_y_h << 4 : g_u_s << 4;1498		buf[1][offset + 1] = odd ? r_y_h >> 4 : g_u_s >> 4;1499		buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;1500		buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;1501		break;1502	case V4L2_PIX_FMT_SGBRG12:1503		buf[0][offset] = odd ? b_v << 4 : g_u_s << 4;1504		buf[0][offset + 1] = odd ? b_v >> 4 : g_u_s >> 4;1505		buf[1][offset] = odd ? g_u_s << 4 : r_y_h << 4;1506		buf[1][offset + 1] = odd ? g_u_s >> 4 : r_y_h >> 4;1507		buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;1508		buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;1509		break;1510	case V4L2_PIX_FMT_SGRBG12:1511		buf[0][offset] = odd ? r_y_h << 4 : g_u_s << 4;1512		buf[0][offset + 1] = odd ? r_y_h >> 4 : g_u_s >> 4;1513		buf[1][offset] = odd ? g_u_s << 4 : b_v << 4;1514		buf[1][offset + 1] = odd ? g_u_s >> 4 : b_v >> 4;1515		buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;1516		buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;1517		break;1518	case V4L2_PIX_FMT_SRGGB12:1519		buf[0][offset] = odd ? g_u_s << 4 : r_y_h << 4;1520		buf[0][offset + 1] = odd ? g_u_s >> 4 : r_y_h >> 4;1521		buf[1][offset] = odd ? b_v << 4 : g_u_s << 4;1522		buf[1][offset + 1] = odd ? b_v >> 4 : g_u_s >> 4;1523		buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;1524		buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;1525		break;1526	case V4L2_PIX_FMT_SBGGR16:1527		buf[0][offset] = buf[0][offset + 1] = odd ? g_u_s : b_v;1528		buf[1][offset] = buf[1][offset + 1] = odd ? r_y_h : g_u_s;1529		break;1530	case V4L2_PIX_FMT_SGBRG16:1531		buf[0][offset] = buf[0][offset + 1] = odd ? b_v : g_u_s;1532		buf[1][offset] = buf[1][offset + 1] = odd ? g_u_s : r_y_h;1533		break;1534	case V4L2_PIX_FMT_SGRBG16:1535		buf[0][offset] = buf[0][offset + 1] = odd ? r_y_h : g_u_s;1536		buf[1][offset] = buf[1][offset + 1] = odd ? g_u_s : b_v;1537		break;1538	case V4L2_PIX_FMT_SRGGB16:1539		buf[0][offset] = buf[0][offset + 1] = odd ? g_u_s : r_y_h;1540		buf[1][offset] = buf[1][offset + 1] = odd ? b_v : g_u_s;1541		break;1542	}1543}1544 1545unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line)1546{1547	switch (tpg->fourcc) {1548	case V4L2_PIX_FMT_SBGGR8:1549	case V4L2_PIX_FMT_SGBRG8:1550	case V4L2_PIX_FMT_SGRBG8:1551	case V4L2_PIX_FMT_SRGGB8:1552	case V4L2_PIX_FMT_SBGGR10:1553	case V4L2_PIX_FMT_SGBRG10:1554	case V4L2_PIX_FMT_SGRBG10:1555	case V4L2_PIX_FMT_SRGGB10:1556	case V4L2_PIX_FMT_SBGGR12:1557	case V4L2_PIX_FMT_SGBRG12:1558	case V4L2_PIX_FMT_SGRBG12:1559	case V4L2_PIX_FMT_SRGGB12:1560	case V4L2_PIX_FMT_SBGGR16:1561	case V4L2_PIX_FMT_SGBRG16:1562	case V4L2_PIX_FMT_SGRBG16:1563	case V4L2_PIX_FMT_SRGGB16:1564		return buf_line & 1;1565	default:1566		return 0;1567	}1568}1569EXPORT_SYMBOL_GPL(tpg_g_interleaved_plane);1570 1571/* Return how many pattern lines are used by the current pattern. */1572static unsigned tpg_get_pat_lines(const struct tpg_data *tpg)1573{1574	switch (tpg->pattern) {1575	case TPG_PAT_CHECKERS_16X16:1576	case TPG_PAT_CHECKERS_2X2:1577	case TPG_PAT_CHECKERS_1X1:1578	case TPG_PAT_COLOR_CHECKERS_2X2:1579	case TPG_PAT_COLOR_CHECKERS_1X1:1580	case TPG_PAT_ALTERNATING_HLINES:1581	case TPG_PAT_CROSS_1_PIXEL:1582	case TPG_PAT_CROSS_2_PIXELS:1583	case TPG_PAT_CROSS_10_PIXELS:1584		return 2;1585	case TPG_PAT_100_COLORSQUARES:1586	case TPG_PAT_100_HCOLORBAR:1587		return 8;1588	default:1589		return 1;1590	}1591}1592 1593/* Which pattern line should be used for the given frame line. */1594static unsigned tpg_get_pat_line(const struct tpg_data *tpg, unsigned line)1595{1596	switch (tpg->pattern) {1597	case TPG_PAT_CHECKERS_16X16:1598		return (line >> 4) & 1;1599	case TPG_PAT_CHECKERS_1X1:1600	case TPG_PAT_COLOR_CHECKERS_1X1:1601	case TPG_PAT_ALTERNATING_HLINES:1602		return line & 1;1603	case TPG_PAT_CHECKERS_2X2:1604	case TPG_PAT_COLOR_CHECKERS_2X2:1605		return (line & 2) >> 1;1606	case TPG_PAT_100_COLORSQUARES:1607	case TPG_PAT_100_HCOLORBAR:1608		return (line * 8) / tpg->src_height;1609	case TPG_PAT_CROSS_1_PIXEL:1610		return line == tpg->src_height / 2;1611	case TPG_PAT_CROSS_2_PIXELS:1612		return (line + 1) / 2 == tpg->src_height / 4;1613	case TPG_PAT_CROSS_10_PIXELS:1614		return (line + 10) / 20 == tpg->src_height / 40;1615	default:1616		return 0;1617	}1618}1619 1620/*1621 * Which color should be used for the given pattern line and X coordinate.1622 * Note: x is in the range 0 to 2 * tpg->src_width.1623 */1624static enum tpg_color tpg_get_color(const struct tpg_data *tpg,1625				    unsigned pat_line, unsigned x)1626{1627	/* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code1628	   should be modified */1629	static const enum tpg_color bars[3][8] = {1630		/* Standard ITU-R 75% color bar sequence */1631		{ TPG_COLOR_CSC_WHITE,   TPG_COLOR_75_YELLOW,1632		  TPG_COLOR_75_CYAN,     TPG_COLOR_75_GREEN,1633		  TPG_COLOR_75_MAGENTA,  TPG_COLOR_75_RED,1634		  TPG_COLOR_75_BLUE,     TPG_COLOR_100_BLACK, },1635		/* Standard ITU-R 100% color bar sequence */1636		{ TPG_COLOR_100_WHITE,   TPG_COLOR_100_YELLOW,1637		  TPG_COLOR_100_CYAN,    TPG_COLOR_100_GREEN,1638		  TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,1639		  TPG_COLOR_100_BLUE,    TPG_COLOR_100_BLACK, },1640		/* Color bar sequence suitable to test CSC */1641		{ TPG_COLOR_CSC_WHITE,   TPG_COLOR_CSC_YELLOW,1642		  TPG_COLOR_CSC_CYAN,    TPG_COLOR_CSC_GREEN,1643		  TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,1644		  TPG_COLOR_CSC_BLUE,    TPG_COLOR_CSC_BLACK, },1645	};1646 1647	switch (tpg->pattern) {1648	case TPG_PAT_75_COLORBAR:1649	case TPG_PAT_100_COLORBAR:1650	case TPG_PAT_CSC_COLORBAR:1651		return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8];1652	case TPG_PAT_100_COLORSQUARES:1653		return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8];1654	case TPG_PAT_100_HCOLORBAR:1655		return bars[1][pat_line];1656	case TPG_PAT_BLACK:1657		return TPG_COLOR_100_BLACK;1658	case TPG_PAT_WHITE:1659		return TPG_COLOR_100_WHITE;1660	case TPG_PAT_RED:1661		return TPG_COLOR_100_RED;1662	case TPG_PAT_GREEN:1663		return TPG_COLOR_100_GREEN;1664	case TPG_PAT_BLUE:1665		return TPG_COLOR_100_BLUE;1666	case TPG_PAT_CHECKERS_16X16:1667		return (((x >> 4) & 1) ^ (pat_line & 1)) ?1668			TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE;1669	case TPG_PAT_CHECKERS_1X1:1670		return ((x & 1) ^ (pat_line & 1)) ?1671			TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;1672	case TPG_PAT_COLOR_CHECKERS_1X1:1673		return ((x & 1) ^ (pat_line & 1)) ?1674			TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;1675	case TPG_PAT_CHECKERS_2X2:1676		return (((x >> 1) & 1) ^ (pat_line & 1)) ?1677			TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;1678	case TPG_PAT_COLOR_CHECKERS_2X2:1679		return (((x >> 1) & 1) ^ (pat_line & 1)) ?1680			TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;1681	case TPG_PAT_ALTERNATING_HLINES:1682		return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;1683	case TPG_PAT_ALTERNATING_VLINES:1684		return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;1685	case TPG_PAT_CROSS_1_PIXEL:1686		if (pat_line || (x % tpg->src_width) == tpg->src_width / 2)1687			return TPG_COLOR_100_BLACK;1688		return TPG_COLOR_100_WHITE;1689	case TPG_PAT_CROSS_2_PIXELS:1690		if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4)1691			return TPG_COLOR_100_BLACK;1692		return TPG_COLOR_100_WHITE;1693	case TPG_PAT_CROSS_10_PIXELS:1694		if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40)1695			return TPG_COLOR_100_BLACK;1696		return TPG_COLOR_100_WHITE;1697	case TPG_PAT_GRAY_RAMP:1698		return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width;1699	default:1700		return TPG_COLOR_100_RED;1701	}1702}1703 1704/*1705 * Given the pixel aspect ratio and video aspect ratio calculate the1706 * coordinates of a centered square and the coordinates of the border of1707 * the active video area. The coordinates are relative to the source1708 * frame rectangle.1709 */1710static void tpg_calculate_square_border(struct tpg_data *tpg)1711{1712	unsigned w = tpg->src_width;1713	unsigned h = tpg->src_height;1714	unsigned sq_w, sq_h;1715 1716	sq_w = (w * 2 / 5) & ~1;1717	if (((w - sq_w) / 2) & 1)1718		sq_w += 2;1719	sq_h = sq_w;1720	tpg->square.width = sq_w;1721	if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) {1722		unsigned ana_sq_w = (sq_w / 4) * 3;1723 1724		if (((w - ana_sq_w) / 2) & 1)1725			ana_sq_w += 2;1726		tpg->square.width = ana_sq_w;1727	}1728	tpg->square.left = (w - tpg->square.width) / 2;1729	if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC)1730		sq_h = sq_w * 10 / 11;1731	else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL)1732		sq_h = sq_w * 59 / 54;1733	tpg->square.height = sq_h;1734	tpg->square.top = (h - sq_h) / 2;1735	tpg->border.left = 0;1736	tpg->border.width = w;1737	tpg->border.top = 0;1738	tpg->border.height = h;1739	switch (tpg->vid_aspect) {1740	case TPG_VIDEO_ASPECT_4X3:1741		if (tpg->pix_aspect)1742			return;1743		if (3 * w >= 4 * h) {1744			tpg->border.width = ((4 * h) / 3) & ~1;1745			if (((w - tpg->border.width) / 2) & ~1)1746				tpg->border.width -= 2;1747			tpg->border.left = (w - tpg->border.width) / 2;1748			break;1749		}1750		tpg->border.height = ((3 * w) / 4) & ~1;1751		tpg->border.top = (h - tpg->border.height) / 2;1752		break;1753	case TPG_VIDEO_ASPECT_14X9_CENTRE:1754		if (tpg->pix_aspect) {1755			tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506;1756			tpg->border.top = (h - tpg->border.height) / 2;1757			break;1758		}1759		if (9 * w >= 14 * h) {1760			tpg->border.width = ((14 * h) / 9) & ~1;1761			if (((w - tpg->border.width) / 2) & ~1)1762				tpg->border.width -= 2;1763			tpg->border.left = (w - tpg->border.width) / 2;1764			break;1765		}1766		tpg->border.height = ((9 * w) / 14) & ~1;1767		tpg->border.top = (h - tpg->border.height) / 2;1768		break;1769	case TPG_VIDEO_ASPECT_16X9_CENTRE:1770		if (tpg->pix_aspect) {1771			tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442;1772			tpg->border.top = (h - tpg->border.height) / 2;1773			break;1774		}1775		if (9 * w >= 16 * h) {1776			tpg->border.width = ((16 * h) / 9) & ~1;1777			if (((w - tpg->border.width) / 2) & ~1)1778				tpg->border.width -= 2;1779			tpg->border.left = (w - tpg->border.width) / 2;1780			break;1781		}1782		tpg->border.height = ((9 * w) / 16) & ~1;1783		tpg->border.top = (h - tpg->border.height) / 2;1784		break;1785	default:1786		break;1787	}1788}1789 1790static void tpg_precalculate_line(struct tpg_data *tpg)1791{1792	enum tpg_color contrast;1793	u8 pix[TPG_MAX_PLANES][8];1794	unsigned pat;1795	unsigned p;1796	unsigned x;1797 1798	if (WARN_ON_ONCE(!tpg->src_width || !tpg->scaled_width))1799		return;1800 1801	switch (tpg->pattern) {1802	case TPG_PAT_GREEN:1803		contrast = TPG_COLOR_100_RED;1804		break;1805	case TPG_PAT_CSC_COLORBAR:1806		contrast = TPG_COLOR_CSC_GREEN;1807		break;1808	default:1809		contrast = TPG_COLOR_100_GREEN;1810		break;1811	}1812 1813	for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) {1814		/* Coarse scaling with Bresenham */1815		unsigned int_part = tpg->src_width / tpg->scaled_width;1816		unsigned fract_part = tpg->src_width % tpg->scaled_width;1817		unsigned src_x = 0;1818		unsigned error = 0;1819 1820		for (x = 0; x < tpg->scaled_width * 2; x += 2) {1821			unsigned real_x = src_x;1822			enum tpg_color color1, color2;1823 1824			real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;1825			color1 = tpg_get_color(tpg, pat, real_x);1826 1827			src_x += int_part;1828			error += fract_part;1829			if (error >= tpg->scaled_width) {1830				error -= tpg->scaled_width;1831				src_x++;1832			}1833 1834			real_x = src_x;1835			real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;1836			color2 = tpg_get_color(tpg, pat, real_x);1837 1838			src_x += int_part;1839			error += fract_part;1840			if (error >= tpg->scaled_width) {1841				error -= tpg->scaled_width;1842				src_x++;1843			}1844 1845			gen_twopix(tpg, pix, tpg->hflip ? color2 : color1, 0);1846			gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);1847			for (p = 0; p < tpg->planes; p++) {1848				unsigned twopixsize = tpg->twopixelsize[p];1849				unsigned hdiv = tpg->hdownsampling[p];1850				u8 *pos = tpg->lines[pat][p] + tpg_hdiv(tpg, p, x);1851 1852				memcpy(pos, pix[p], twopixsize / hdiv);1853			}1854		}1855	}1856 1857	if (tpg->vdownsampling[tpg->planes - 1] > 1) {1858		unsigned pat_lines = tpg_get_pat_lines(tpg);1859 1860		for (pat = 0; pat < pat_lines; pat++) {1861			unsigned next_pat = (pat + 1) % pat_lines;1862 1863			for (p = 1; p < tpg->planes; p++) {1864				unsigned w = tpg_hdiv(tpg, p, tpg->scaled_width * 2);1865				u8 *pos1 = tpg->lines[pat][p];1866				u8 *pos2 = tpg->lines[next_pat][p];1867				u8 *dest = tpg->downsampled_lines[pat][p];1868 1869				for (x = 0; x < w; x++, pos1++, pos2++, dest++)1870					*dest = ((u16)*pos1 + (u16)*pos2) / 2;1871			}1872		}1873	}1874 1875	gen_twopix(tpg, pix, contrast, 0);1876	gen_twopix(tpg, pix, contrast, 1);1877	for (p = 0; p < tpg->planes; p++) {1878		unsigned twopixsize = tpg->twopixelsize[p];1879		u8 *pos = tpg->contrast_line[p];1880 1881		for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)1882			memcpy(pos, pix[p], twopixsize);1883	}1884 1885	gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);1886	gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);1887	for (p = 0; p < tpg->planes; p++) {1888		unsigned twopixsize = tpg->twopixelsize[p];1889		u8 *pos = tpg->black_line[p];1890 1891		for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)1892			memcpy(pos, pix[p], twopixsize);1893	}1894 1895	for (x = 0; x < tpg->scaled_width * 2; x += 2) {1896		gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);1897		gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);1898		for (p = 0; p < tpg->planes; p++) {1899			unsigned twopixsize = tpg->twopixelsize[p];1900			u8 *pos = tpg->random_line[p] + x * twopixsize / 2;1901 1902			memcpy(pos, pix[p], twopixsize);1903		}1904	}1905 1906	gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);1907	gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);1908	gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);1909	gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 1);1910}1911 1912/* need this to do rgb24 rendering */1913typedef struct { u16 __; u8 _; } __packed x24;1914 1915#define PRINTSTR(PIXTYPE) do {	\1916	unsigned vdiv = tpg->vdownsampling[p]; \1917	unsigned hdiv = tpg->hdownsampling[p]; \1918	int line;	\1919	PIXTYPE fg;	\1920	PIXTYPE bg;	\1921	memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE));	\1922	memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE));	\1923	\1924	for (line = first; line < 16; line += vdiv * step) {	\1925		int l = tpg->vflip ? 15 - line : line; \1926		PIXTYPE *pos = (PIXTYPE *)(basep[p][(line / vdiv) & 1] + \1927			       ((y * step + l) / (vdiv * div)) * tpg->bytesperline[p] + \1928			       (x / hdiv) * sizeof(PIXTYPE));	\1929		unsigned s;	\1930	\1931		for (s = 0; s < len; s++) {	\1932			u8 chr = font8x16[(u8)text[s] * 16 + line];	\1933	\1934			if (hdiv == 2 && tpg->hflip) { \1935				pos[3] = (chr & (0x01 << 6) ? fg : bg);	\1936				pos[2] = (chr & (0x01 << 4) ? fg : bg);	\1937				pos[1] = (chr & (0x01 << 2) ? fg : bg);	\1938				pos[0] = (chr & (0x01 << 0) ? fg : bg);	\1939			} else if (hdiv == 2) { \1940				pos[0] = (chr & (0x01 << 7) ? fg : bg);	\1941				pos[1] = (chr & (0x01 << 5) ? fg : bg);	\1942				pos[2] = (chr & (0x01 << 3) ? fg : bg);	\1943				pos[3] = (chr & (0x01 << 1) ? fg : bg);	\1944			} else if (tpg->hflip) { \1945				pos[7] = (chr & (0x01 << 7) ? fg : bg);	\1946				pos[6] = (chr & (0x01 << 6) ? fg : bg);	\1947				pos[5] = (chr & (0x01 << 5) ? fg : bg);	\1948				pos[4] = (chr & (0x01 << 4) ? fg : bg);	\1949				pos[3] = (chr & (0x01 << 3) ? fg : bg);	\1950				pos[2] = (chr & (0x01 << 2) ? fg : bg);	\1951				pos[1] = (chr & (0x01 << 1) ? fg : bg);	\1952				pos[0] = (chr & (0x01 << 0) ? fg : bg);	\1953			} else { \1954				pos[0] = (chr & (0x01 << 7) ? fg : bg);	\1955				pos[1] = (chr & (0x01 << 6) ? fg : bg);	\1956				pos[2] = (chr & (0x01 << 5) ? fg : bg);	\1957				pos[3] = (chr & (0x01 << 4) ? fg : bg);	\1958				pos[4] = (chr & (0x01 << 3) ? fg : bg);	\1959				pos[5] = (chr & (0x01 << 2) ? fg : bg);	\1960				pos[6] = (chr & (0x01 << 1) ? fg : bg);	\1961				pos[7] = (chr & (0x01 << 0) ? fg : bg);	\1962			} \1963	\1964			pos += (tpg->hflip ? -8 : 8) / (int)hdiv;	\1965		}	\1966	}	\1967} while (0)1968 1969static noinline void tpg_print_str_2(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],1970			unsigned p, unsigned first, unsigned div, unsigned step,1971			int y, int x, const char *text, unsigned len)1972{1973	PRINTSTR(u8);1974}1975 1976static noinline void tpg_print_str_4(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],1977			unsigned p, unsigned first, unsigned div, unsigned step,1978			int y, int x, const char *text, unsigned len)1979{1980	PRINTSTR(u16);1981}1982 1983static noinline void tpg_print_str_6(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],1984			unsigned p, unsigned first, unsigned div, unsigned step,1985			int y, int x, const char *text, unsigned len)1986{1987	PRINTSTR(x24);1988}1989 1990static noinline void tpg_print_str_8(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],1991			unsigned p, unsigned first, unsigned div, unsigned step,1992			int y, int x, const char *text, unsigned len)1993{1994	PRINTSTR(u32);1995}1996 1997void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],1998		  int y, int x, const char *text)1999{2000	unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;2001	unsigned div = step;2002	unsigned first = 0;2003	unsigned len;2004	unsigned p;2005 2006	if (font8x16 == NULL || basep == NULL || text == NULL)2007		return;2008 2009	len = strlen(text);2010 2011	/* Checks if it is possible to show string */2012	if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)2013		return;2014 2015	if (len > (tpg->compose.width - x) / 8)2016		len = (tpg->compose.width - x) / 8;2017	if (tpg->vflip)2018		y = tpg->compose.height - y - 16;2019	if (tpg->hflip)2020		x = tpg->compose.width - x - 8;2021	y += tpg->compose.top;2022	x += tpg->compose.left;2023	if (tpg->field == V4L2_FIELD_BOTTOM)2024		first = 1;2025	else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)2026		div = 2;2027 2028	for (p = 0; p < tpg->planes; p++) {2029		/* Print text */2030		switch (tpg->twopixelsize[p]) {2031		case 2:2032			tpg_print_str_2(tpg, basep, p, first, div, step, y, x,2033					text, len);2034			break;2035		case 4:2036			tpg_print_str_4(tpg, basep, p, first, div, step, y, x,2037					text, len);2038			break;2039		case 6:2040			tpg_print_str_6(tpg, basep, p, first, div, step, y, x,2041					text, len);2042			break;2043		case 8:2044			tpg_print_str_8(tpg, basep, p, first, div, step, y, x,2045					text, len);2046			break;2047		}2048	}2049}2050EXPORT_SYMBOL_GPL(tpg_gen_text);2051 2052const char *tpg_g_color_order(const struct tpg_data *tpg)2053{2054	switch (tpg->pattern) {2055	case TPG_PAT_75_COLORBAR:2056	case TPG_PAT_100_COLORBAR:2057	case TPG_PAT_CSC_COLORBAR:2058	case TPG_PAT_100_HCOLORBAR:2059		return "White, yellow, cyan, green, magenta, red, blue, black";2060	case TPG_PAT_BLACK:2061		return "Black";2062	case TPG_PAT_WHITE:2063		return "White";2064	case TPG_PAT_RED:2065		return "Red";2066	case TPG_PAT_GREEN:2067		return "Green";2068	case TPG_PAT_BLUE:2069		return "Blue";2070	default:2071		return NULL;2072	}2073}2074EXPORT_SYMBOL_GPL(tpg_g_color_order);2075 2076void tpg_update_mv_step(struct tpg_data *tpg)2077{2078	int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;2079 2080	if (tpg->hflip)2081		factor = -factor;2082	switch (tpg->mv_hor_mode) {2083	case TPG_MOVE_NEG_FAST:2084	case TPG_MOVE_POS_FAST:2085		tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4;2086		break;2087	case TPG_MOVE_NEG:2088	case TPG_MOVE_POS:2089		tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4;2090		break;2091	case TPG_MOVE_NEG_SLOW:2092	case TPG_MOVE_POS_SLOW:2093		tpg->mv_hor_step = 2;2094		break;2095	case TPG_MOVE_NONE:2096		tpg->mv_hor_step = 0;2097		break;2098	}2099	if (factor < 0)2100		tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;2101 2102	factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1;2103	switch (tpg->mv_vert_mode) {2104	case TPG_MOVE_NEG_FAST:2105	case TPG_MOVE_POS_FAST:2106		tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4;2107		break;2108	case TPG_MOVE_NEG:2109	case TPG_MOVE_POS:2110		tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4;2111		break;2112	case TPG_MOVE_NEG_SLOW:2113	case TPG_MOVE_POS_SLOW:2114		tpg->mv_vert_step = 1;2115		break;2116	case TPG_MOVE_NONE:2117		tpg->mv_vert_step = 0;2118		break;2119	}2120	if (factor < 0)2121		tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;2122}2123EXPORT_SYMBOL_GPL(tpg_update_mv_step);2124 2125/* Map the line number relative to the crop rectangle to a frame line number */2126static unsigned tpg_calc_frameline(const struct tpg_data *tpg, unsigned src_y,2127				    unsigned field)2128{2129	switch (field) {2130	case V4L2_FIELD_TOP:2131		return tpg->crop.top + src_y * 2;2132	case V4L2_FIELD_BOTTOM:2133		return tpg->crop.top + src_y * 2 + 1;2134	default:2135		return src_y + tpg->crop.top;2136	}2137}2138 2139/*2140 * Map the line number relative to the compose rectangle to a destination2141 * buffer line number.2142 */2143static unsigned tpg_calc_buffer_line(const struct tpg_data *tpg, unsigned y,2144				    unsigned field)2145{2146	y += tpg->compose.top;2147	switch (field) {2148	case V4L2_FIELD_SEQ_TB:2149		if (y & 1)2150			return tpg->buf_height / 2 + y / 2;2151		return y / 2;2152	case V4L2_FIELD_SEQ_BT:2153		if (y & 1)2154			return y / 2;2155		return tpg->buf_height / 2 + y / 2;2156	default:2157		return y;2158	}2159}2160 2161static void tpg_recalc(struct tpg_data *tpg)2162{2163	if (tpg->recalc_colors) {2164		tpg->recalc_colors = false;2165		tpg->recalc_lines = true;2166		tpg->real_xfer_func = tpg->xfer_func;2167		tpg->real_ycbcr_enc = tpg->ycbcr_enc;2168		tpg->real_hsv_enc = tpg->hsv_enc;2169		tpg->real_quantization = tpg->quantization;2170 2171		if (tpg->xfer_func == V4L2_XFER_FUNC_DEFAULT)2172			tpg->real_xfer_func =2173				V4L2_MAP_XFER_FUNC_DEFAULT(tpg->colorspace);2174 2175		if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT)2176			tpg->real_ycbcr_enc =2177				V4L2_MAP_YCBCR_ENC_DEFAULT(tpg->colorspace);2178 2179		if (tpg->quantization == V4L2_QUANTIZATION_DEFAULT)2180			tpg->real_quantization =2181				V4L2_MAP_QUANTIZATION_DEFAULT(2182					tpg->color_enc != TGP_COLOR_ENC_YCBCR,2183					tpg->colorspace, tpg->real_ycbcr_enc);2184 2185		tpg_precalculate_colors(tpg);2186	}2187	if (tpg->recalc_square_border) {2188		tpg->recalc_square_border = false;2189		tpg_calculate_square_border(tpg);2190	}2191	if (tpg->recalc_lines) {2192		tpg->recalc_lines = false;2193		tpg_precalculate_line(tpg);2194	}2195}2196 2197void tpg_calc_text_basep(struct tpg_data *tpg,2198		u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)2199{2200	unsigned stride = tpg->bytesperline[p];2201	unsigned h = tpg->buf_height;2202 2203	tpg_recalc(tpg);2204 2205	basep[p][0] = vbuf;2206	basep[p][1] = vbuf;2207	h /= tpg->vdownsampling[p];2208	if (tpg->field == V4L2_FIELD_SEQ_TB)2209		basep[p][1] += h * stride / 2;2210	else if (tpg->field == V4L2_FIELD_SEQ_BT)2211		basep[p][0] += h * stride / 2;2212	if (p == 0 && tpg->interleaved)2213		tpg_calc_text_basep(tpg, basep, 1, vbuf);2214}2215EXPORT_SYMBOL_GPL(tpg_calc_text_basep);2216 2217static int tpg_pattern_avg(const struct tpg_data *tpg,2218			   unsigned pat1, unsigned pat2)2219{2220	unsigned pat_lines = tpg_get_pat_lines(tpg);2221 2222	if (pat1 == (pat2 + 1) % pat_lines)2223		return pat2;2224	if (pat2 == (pat1 + 1) % pat_lines)2225		return pat1;2226	return -1;2227}2228 2229static const char *tpg_color_enc_str(enum tgp_color_enc2230						 color_enc)2231{2232	switch (color_enc) {2233	case TGP_COLOR_ENC_HSV:2234		return "HSV";2235	case TGP_COLOR_ENC_YCBCR:2236		return "Y'CbCr";2237	case TGP_COLOR_ENC_LUMA:2238		return "Luma";2239	case TGP_COLOR_ENC_RGB:2240	default:2241		return "R'G'B";2242 2243	}2244}2245 2246void tpg_log_status(struct tpg_data *tpg)2247{2248	pr_info("tpg source WxH: %ux%u (%s)\n",2249		tpg->src_width, tpg->src_height,2250		tpg_color_enc_str(tpg->color_enc));2251	pr_info("tpg field: %u\n", tpg->field);2252	pr_info("tpg crop: %ux%u@%dx%d\n", tpg->crop.width, tpg->crop.height,2253			tpg->crop.left, tpg->crop.top);2254	pr_info("tpg compose: %ux%u@%dx%d\n", tpg->compose.width, tpg->compose.height,2255			tpg->compose.left, tpg->compose.top);2256	pr_info("tpg colorspace: %d\n", tpg->colorspace);2257	pr_info("tpg transfer function: %d/%d\n", tpg->xfer_func, tpg->real_xfer_func);2258	if (tpg->color_enc == TGP_COLOR_ENC_HSV)2259		pr_info("tpg HSV encoding: %d/%d\n",2260			tpg->hsv_enc, tpg->real_hsv_enc);2261	else if (tpg->color_enc == TGP_COLOR_ENC_YCBCR)2262		pr_info("tpg Y'CbCr encoding: %d/%d\n",2263			tpg->ycbcr_enc, tpg->real_ycbcr_enc);2264	pr_info("tpg quantization: %d/%d\n", tpg->quantization, tpg->real_quantization);2265	pr_info("tpg RGB range: %d/%d\n", tpg->rgb_range, tpg->real_rgb_range);2266}2267EXPORT_SYMBOL_GPL(tpg_log_status);2268 2269/*2270 * This struct contains common parameters used by both the drawing of the2271 * test pattern and the drawing of the extras (borders, square, etc.)2272 */2273struct tpg_draw_params {2274	/* common data */2275	bool is_tv;2276	bool is_60hz;2277	unsigned twopixsize;2278	unsigned img_width;2279	unsigned stride;2280	unsigned hmax;2281	unsigned frame_line;2282	unsigned frame_line_next;2283 2284	/* test pattern */2285	unsigned mv_hor_old;2286	unsigned mv_hor_new;2287	unsigned mv_vert_old;2288	unsigned mv_vert_new;2289 2290	/* extras */2291	unsigned wss_width;2292	unsigned wss_random_offset;2293	unsigned sav_eav_f;2294	unsigned left_pillar_width;2295	unsigned right_pillar_start;2296};2297 2298static void tpg_fill_params_pattern(const struct tpg_data *tpg, unsigned p,2299				    struct tpg_draw_params *params)2300{2301	params->mv_hor_old =2302		tpg_hscale_div(tpg, p, tpg->mv_hor_count % tpg->src_width);2303	params->mv_hor_new =2304		tpg_hscale_div(tpg, p, (tpg->mv_hor_count + tpg->mv_hor_step) %2305			       tpg->src_width);2306	params->mv_vert_old = tpg->mv_vert_count % tpg->src_height;2307	params->mv_vert_new =2308		(tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;2309}2310 2311static void tpg_fill_params_extras(const struct tpg_data *tpg,2312				   unsigned p,2313				   struct tpg_draw_params *params)2314{2315	unsigned left_pillar_width = 0;2316	unsigned right_pillar_start = params->img_width;2317 2318	params->wss_width = tpg->crop.left < tpg->src_width / 2 ?2319		tpg->src_width / 2 - tpg->crop.left : 0;2320	if (params->wss_width > tpg->crop.width)2321		params->wss_width = tpg->crop.width;2322	params->wss_width = tpg_hscale_div(tpg, p, params->wss_width);2323	params->wss_random_offset =2324		params->twopixsize * get_random_u32_below(tpg->src_width / 2);2325 2326	if (tpg->crop.left < tpg->border.left) {2327		left_pillar_width = tpg->border.left - tpg->crop.left;2328		if (left_pillar_width > tpg->crop.width)2329			left_pillar_width = tpg->crop.width;2330		left_pillar_width = tpg_hscale_div(tpg, p, left_pillar_width);2331	}2332	params->left_pillar_width = left_pillar_width;2333 2334	if (tpg->crop.left + tpg->crop.width >2335	    tpg->border.left + tpg->border.width) {2336		right_pillar_start =2337			tpg->border.left + tpg->border.width - tpg->crop.left;2338		right_pillar_start =2339			tpg_hscale_div(tpg, p, right_pillar_start);2340		if (right_pillar_start > params->img_width)2341			right_pillar_start = params->img_width;2342	}2343	params->right_pillar_start = right_pillar_start;2344 2345	params->sav_eav_f = tpg->field ==2346			(params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);2347}2348 2349static void tpg_fill_plane_extras(const struct tpg_data *tpg,2350				  const struct tpg_draw_params *params,2351				  unsigned p, unsigned h, u8 *vbuf)2352{2353	unsigned twopixsize = params->twopixsize;2354	unsigned img_width = params->img_width;2355	unsigned frame_line = params->frame_line;2356	const struct v4l2_rect *sq = &tpg->square;2357	const struct v4l2_rect *b = &tpg->border;2358	const struct v4l2_rect *c = &tpg->crop;2359 2360	if (params->is_tv && !params->is_60hz &&2361	    frame_line == 0 && params->wss_width) {2362		/*2363		 * Replace the first half of the top line of a 50 Hz frame2364		 * with random data to simulate a WSS signal.2365		 */2366		u8 *wss = tpg->random_line[p] + params->wss_random_offset;2367 2368		memcpy(vbuf, wss, params->wss_width);2369	}2370 2371	if (tpg->show_border && frame_line >= b->top &&2372	    frame_line < b->top + b->height) {2373		unsigned bottom = b->top + b->height - 1;2374		unsigned left = params->left_pillar_width;2375		unsigned right = params->right_pillar_start;2376 2377		if (frame_line == b->top || frame_line == b->top + 1 ||2378		    frame_line == bottom || frame_line == bottom - 1) {2379			memcpy(vbuf + left, tpg->contrast_line[p],2380					right - left);2381		} else {2382			if (b->left >= c->left &&2383			    b->left < c->left + c->width)2384				memcpy(vbuf + left,2385					tpg->contrast_line[p], twopixsize);2386			if (b->left + b->width > c->left &&2387			    b->left + b->width <= c->left + c->width)2388				memcpy(vbuf + right - twopixsize,2389					tpg->contrast_line[p], twopixsize);2390		}2391	}2392	if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&2393	    frame_line < b->top + b->height) {2394		memcpy(vbuf, tpg->black_line[p], params->left_pillar_width);2395		memcpy(vbuf + params->right_pillar_start, tpg->black_line[p],2396		       img_width - params->right_pillar_start);2397	}2398	if (tpg->show_square && frame_line >= sq->top &&2399	    frame_line < sq->top + sq->height &&2400	    sq->left < c->left + c->width &&2401	    sq->left + sq->width >= c->left) {2402		unsigned left = sq->left;2403		unsigned width = sq->width;2404 2405		if (c->left > left) {2406			width -= c->left - left;2407			left = c->left;2408		}2409		if (c->left + c->width < left + width)2410			width -= left + width - c->left - c->width;2411		left -= c->left;2412		left = tpg_hscale_div(tpg, p, left);2413		width = tpg_hscale_div(tpg, p, width);2414		memcpy(vbuf + left, tpg->contrast_line[p], width);2415	}2416	if (tpg->insert_sav) {2417		unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width / 3);2418		u8 *p = vbuf + offset;2419		unsigned vact = 0, hact = 0;2420 2421		p[0] = 0xff;2422		p[1] = 0;2423		p[2] = 0;2424		p[3] = 0x80 | (params->sav_eav_f << 6) |2425			(vact << 5) | (hact << 4) |2426			((hact ^ vact) << 3) |2427			((hact ^ params->sav_eav_f) << 2) |2428			((params->sav_eav_f ^ vact) << 1) |2429			(hact ^ vact ^ params->sav_eav_f);2430	}2431	if (tpg->insert_eav) {2432		unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width * 2 / 3);2433		u8 *p = vbuf + offset;2434		unsigned vact = 0, hact = 1;2435 2436		p[0] = 0xff;2437		p[1] = 0;2438		p[2] = 0;2439		p[3] = 0x80 | (params->sav_eav_f << 6) |2440			(vact << 5) | (hact << 4) |2441			((hact ^ vact) << 3) |2442			((hact ^ params->sav_eav_f) << 2) |2443			((params->sav_eav_f ^ vact) << 1) |2444			(hact ^ vact ^ params->sav_eav_f);2445	}2446	if (tpg->insert_hdmi_video_guard_band) {2447		unsigned int i;2448 2449		switch (tpg->fourcc) {2450		case V4L2_PIX_FMT_BGR24:2451		case V4L2_PIX_FMT_RGB24:2452			for (i = 0; i < 3 * 4; i += 3) {2453				vbuf[i] = 0xab;2454				vbuf[i + 1] = 0x55;2455				vbuf[i + 2] = 0xab;2456			}2457			break;2458		case V4L2_PIX_FMT_RGB32:2459		case V4L2_PIX_FMT_ARGB32:2460		case V4L2_PIX_FMT_XRGB32:2461		case V4L2_PIX_FMT_BGRX32:2462		case V4L2_PIX_FMT_BGRA32:2463			for (i = 0; i < 4 * 4; i += 4) {2464				vbuf[i] = 0x00;2465				vbuf[i + 1] = 0xab;2466				vbuf[i + 2] = 0x55;2467				vbuf[i + 3] = 0xab;2468			}2469			break;2470		case V4L2_PIX_FMT_BGR32:2471		case V4L2_PIX_FMT_XBGR32:2472		case V4L2_PIX_FMT_ABGR32:2473		case V4L2_PIX_FMT_RGBX32:2474		case V4L2_PIX_FMT_RGBA32:2475			for (i = 0; i < 4 * 4; i += 4) {2476				vbuf[i] = 0xab;2477				vbuf[i + 1] = 0x55;2478				vbuf[i + 2] = 0xab;2479				vbuf[i + 3] = 0x00;2480			}2481			break;2482		}2483	}2484}2485 2486static void tpg_fill_plane_pattern(const struct tpg_data *tpg,2487				   const struct tpg_draw_params *params,2488				   unsigned p, unsigned h, u8 *vbuf)2489{2490	unsigned twopixsize = params->twopixsize;2491	unsigned img_width = params->img_width;2492	unsigned mv_hor_old = params->mv_hor_old;2493	unsigned mv_hor_new = params->mv_hor_new;2494	unsigned mv_vert_old = params->mv_vert_old;2495	unsigned mv_vert_new = params->mv_vert_new;2496	unsigned frame_line = params->frame_line;2497	unsigned frame_line_next = params->frame_line_next;2498	unsigned line_offset = tpg_hscale_div(tpg, p, tpg->crop.left);2499	bool even;2500	bool fill_blank = false;2501	unsigned pat_line_old;2502	unsigned pat_line_new;2503	u8 *linestart_older;2504	u8 *linestart_newer;2505	u8 *linestart_top;2506	u8 *linestart_bottom;2507 2508	even = !(frame_line & 1);2509 2510	if (h >= params->hmax) {2511		if (params->hmax == tpg->compose.height)2512			return;2513		if (!tpg->perc_fill_blank)2514			return;2515		fill_blank = true;2516	}2517 2518	if (tpg->vflip) {2519		frame_line = tpg->src_height - frame_line - 1;2520		frame_line_next = tpg->src_height - frame_line_next - 1;2521	}2522 2523	if (fill_blank) {2524		linestart_older = tpg->contrast_line[p];2525		linestart_newer = tpg->contrast_line[p];2526	} else if (tpg->qual != TPG_QUAL_NOISE &&2527		   (frame_line < tpg->border.top ||2528		    frame_line >= tpg->border.top + tpg->border.height)) {2529		linestart_older = tpg->black_line[p];2530		linestart_newer = tpg->black_line[p];2531	} else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {2532		linestart_older = tpg->random_line[p] +2533				  twopixsize * get_random_u32_below(tpg->src_width / 2);2534		linestart_newer = tpg->random_line[p] +2535				  twopixsize * get_random_u32_below(tpg->src_width / 2);2536	} else {2537		unsigned frame_line_old =2538			(frame_line + mv_vert_old) % tpg->src_height;2539		unsigned frame_line_new =2540			(frame_line + mv_vert_new) % tpg->src_height;2541		unsigned pat_line_next_old;2542		unsigned pat_line_next_new;2543 2544		pat_line_old = tpg_get_pat_line(tpg, frame_line_old);2545		pat_line_new = tpg_get_pat_line(tpg, frame_line_new);2546		linestart_older = tpg->lines[pat_line_old][p] + mv_hor_old;2547		linestart_newer = tpg->lines[pat_line_new][p] + mv_hor_new;2548 2549		if (tpg->vdownsampling[p] > 1 && frame_line != frame_line_next) {2550			int avg_pat;2551 2552			/*2553			 * Now decide whether we need to use downsampled_lines[].2554			 * That's necessary if the two lines use different patterns.2555			 */2556			pat_line_next_old = tpg_get_pat_line(tpg,2557					(frame_line_next + mv_vert_old) % tpg->src_height);2558			pat_line_next_new = tpg_get_pat_line(tpg,2559					(frame_line_next + mv_vert_new) % tpg->src_height);2560 2561			switch (tpg->field) {2562			case V4L2_FIELD_INTERLACED:2563			case V4L2_FIELD_INTERLACED_BT:2564			case V4L2_FIELD_INTERLACED_TB:2565				avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new);2566				if (avg_pat < 0)2567					break;2568				linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old;2569				linestart_newer = linestart_older;2570				break;2571			case V4L2_FIELD_NONE:2572			case V4L2_FIELD_TOP:2573			case V4L2_FIELD_BOTTOM:2574			case V4L2_FIELD_SEQ_BT:2575			case V4L2_FIELD_SEQ_TB:2576				avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old);2577				if (avg_pat >= 0)2578					linestart_older = tpg->downsampled_lines[avg_pat][p] +2579						mv_hor_old;2580				avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new);2581				if (avg_pat >= 0)2582					linestart_newer = tpg->downsampled_lines[avg_pat][p] +2583						mv_hor_new;2584				break;2585			}2586		}2587		linestart_older += line_offset;2588		linestart_newer += line_offset;2589	}2590	if (tpg->field_alternate) {2591		linestart_top = linestart_bottom = linestart_older;2592	} else if (params->is_60hz) {2593		linestart_top = linestart_newer;2594		linestart_bottom = linestart_older;2595	} else {2596		linestart_top = linestart_older;2597		linestart_bottom = linestart_newer;2598	}2599 2600	switch (tpg->field) {2601	case V4L2_FIELD_INTERLACED:2602	case V4L2_FIELD_INTERLACED_TB:2603	case V4L2_FIELD_SEQ_TB:2604	case V4L2_FIELD_SEQ_BT:2605		if (even)2606			memcpy(vbuf, linestart_top, img_width);2607		else2608			memcpy(vbuf, linestart_bottom, img_width);2609		break;2610	case V4L2_FIELD_INTERLACED_BT:2611		if (even)2612			memcpy(vbuf, linestart_bottom, img_width);2613		else2614			memcpy(vbuf, linestart_top, img_width);2615		break;2616	case V4L2_FIELD_TOP:2617		memcpy(vbuf, linestart_top, img_width);2618		break;2619	case V4L2_FIELD_BOTTOM:2620		memcpy(vbuf, linestart_bottom, img_width);2621		break;2622	case V4L2_FIELD_NONE:2623	default:2624		memcpy(vbuf, linestart_older, img_width);2625		break;2626	}2627}2628 2629void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std,2630			   unsigned p, u8 *vbuf)2631{2632	struct tpg_draw_params params;2633	unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;2634 2635	/* Coarse scaling with Bresenham */2636	unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;2637	unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;2638	unsigned src_y = 0;2639	unsigned error = 0;2640	unsigned h;2641 2642	tpg_recalc(tpg);2643 2644	params.is_tv = std;2645	params.is_60hz = std & V4L2_STD_525_60;2646	params.twopixsize = tpg->twopixelsize[p];2647	params.img_width = tpg_hdiv(tpg, p, tpg->compose.width);2648	params.stride = tpg->bytesperline[p];2649	params.hmax = (tpg->compose.height * tpg->perc_fill) / 100;2650 2651	tpg_fill_params_pattern(tpg, p, &params);2652	tpg_fill_params_extras(tpg, p, &params);2653 2654	vbuf += tpg_hdiv(tpg, p, tpg->compose.left);2655 2656	for (h = 0; h < tpg->compose.height; h++) {2657		unsigned buf_line;2658 2659		params.frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);2660		params.frame_line_next = params.frame_line;2661		buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);2662		src_y += int_part;2663		error += fract_part;2664		if (error >= tpg->compose.height) {2665			error -= tpg->compose.height;2666			src_y++;2667		}2668 2669		/*2670		 * For line-interleaved formats determine the 'plane'2671		 * based on the buffer line.2672		 */2673		if (tpg_g_interleaved(tpg))2674			p = tpg_g_interleaved_plane(tpg, buf_line);2675 2676		if (tpg->vdownsampling[p] > 1) {2677			/*2678			 * When doing vertical downsampling the field setting2679			 * matters: for SEQ_BT/TB we downsample each field2680			 * separately (i.e. lines 0+2 are combined, as are2681			 * lines 1+3), for the other field settings we combine2682			 * odd and even lines. Doing that for SEQ_BT/TB would2683			 * be really weird.2684			 */2685			if (tpg->field == V4L2_FIELD_SEQ_BT ||2686			    tpg->field == V4L2_FIELD_SEQ_TB) {2687				unsigned next_src_y = src_y;2688 2689				if ((h & 3) >= 2)2690					continue;2691				next_src_y += int_part;2692				if (error + fract_part >= tpg->compose.height)2693					next_src_y++;2694				params.frame_line_next =2695					tpg_calc_frameline(tpg, next_src_y, tpg->field);2696			} else {2697				if (h & 1)2698					continue;2699				params.frame_line_next =2700					tpg_calc_frameline(tpg, src_y, tpg->field);2701			}2702 2703			buf_line /= tpg->vdownsampling[p];2704		}2705		tpg_fill_plane_pattern(tpg, &params, p, h,2706				vbuf + buf_line * params.stride);2707		tpg_fill_plane_extras(tpg, &params, p, h,2708				vbuf + buf_line * params.stride);2709	}2710}2711EXPORT_SYMBOL_GPL(tpg_fill_plane_buffer);2712 2713void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)2714{2715	unsigned offset = 0;2716	unsigned i;2717 2718	if (tpg->buffers > 1) {2719		tpg_fill_plane_buffer(tpg, std, p, vbuf);2720		return;2721	}2722 2723	for (i = 0; i < tpg_g_planes(tpg); i++) {2724		tpg_fill_plane_buffer(tpg, std, i, vbuf + offset);2725		offset += tpg_calc_plane_size(tpg, i);2726	}2727}2728EXPORT_SYMBOL_GPL(tpg_fillbuffer);2729 2730MODULE_DESCRIPTION("V4L2 Test Pattern Generator");2731MODULE_AUTHOR("Hans Verkuil");2732MODULE_LICENSE("GPL");2733