brintos

brintos / linux-shallow public Read only

0
0
Text · 7.8 KiB · 13a6063 Raw
246 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Copyright (C) Collabora, Ltd.4 *5 * Based on GSPCA and CODA drivers:6 * Copyright (C) Jean-Francois Moine (http://moinejf.free.fr)7 * Copyright (C) 2014 Philipp Zabel, Pengutronix8 */9 10#include <linux/align.h>11#include <linux/build_bug.h>12#include <linux/kernel.h>13#include <linux/string.h>14#include <media/v4l2-jpeg.h>15#include "hantro_jpeg.h"16#include "hantro.h"17 18#define LUMA_QUANT_OFF		2519#define CHROMA_QUANT_OFF	9020#define HEIGHT_OFF		15921#define WIDTH_OFF		16122 23#define HUFF_LUMA_DC_OFF	17824#define HUFF_LUMA_AC_OFF	21125#define HUFF_CHROMA_DC_OFF	39426#define HUFF_CHROMA_AC_OFF	42727 28static const u32 hw_reorder[] = {29	 0,  8, 16, 24,  1,  9, 17, 25,30	32, 40, 48, 56, 33, 41, 49, 57,31	 2, 10, 18, 26,  3, 11, 19, 27,32	34, 42, 50, 58, 35, 43, 51, 59,33	 4, 12, 20, 28,  5, 13, 21, 29,34	36, 44, 52, 60, 37, 45, 53, 61,35	 6, 14, 22, 30,  7, 15, 23, 31,36	38, 46, 54, 62, 39, 47, 55, 6337};38 39/* For simplicity, we keep a pre-formatted JPEG header,40 * and we'll use fixed offsets to change the width, height41 * quantization tables, etc.42 */43static const unsigned char hantro_jpeg_header[] = {44	/* SOI */45	0xff, 0xd8,46 47	/* JFIF-APP0 */48	0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46,49	0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01,50	0x00, 0x00,51 52	/* DQT */53	0xff, 0xdb, 0x00, 0x84,54 55	0x00,56	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,57	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,58	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,59	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,60	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,61	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,62	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,63	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,64 65	0x01,66	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,67	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,68	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,69	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,70	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,71	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,72	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,73	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,74 75	/* SOF */76	0xff, 0xc0, 0x00, 0x11, 0x08, 0x00, 0xf0, 0x01,77	0x40, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01,78	0x03, 0x11, 0x01,79 80	/* DHT */81	0xff, 0xc4, 0x00, 0x1f, 0x00,82 83	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,84	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,85	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,86	0x00, 0x00, 0x00, 0x00,87 88	/* DHT */89	0xff, 0xc4, 0x00, 0xb5, 0x10,90 91	0x00, 0x00,92	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,93	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,94	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,95	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,96	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,97	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,98	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,99	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,100	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,101	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,102	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,103	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,104	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,105	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,106	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,107	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,108	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,109	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,110	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,111	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,112	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,113	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,114 115	/* DHT */116	0xff, 0xc4, 0x00, 0x1f, 0x01,117 118	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,119	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,120	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,121	0x00, 0x00, 0x00, 0x00,122 123	/* DHT */124	0xff, 0xc4, 0x00, 0xb5, 0x11,125 126	0x00, 0x00,127	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,128	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,129	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,130	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,131	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,132	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,133	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,134	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,135	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,136	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,137	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,138	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,139	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,140	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,141	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,142	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,143	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,144	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,145	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,146	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,147	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,148	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,149 150	/* COM */151	0xff, 0xfe, 0x00, 0x03, 0x00,152 153	/* SOS */154	0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02,155	0x11, 0x03, 0x11, 0x00, 0x3f, 0x00,156};157 158/*159 * JPEG_HEADER_SIZE is used in other parts of the driver in lieu of160 * "sizeof(hantro_jpeg_header)". The two must be equal.161 */162static_assert(sizeof(hantro_jpeg_header) == JPEG_HEADER_SIZE);163 164/*165 * hantro_jpeg_header is padded with a COM segment, so that the payload166 * of the SOS segment (the entropy-encoded image scan), which should167 * trail the whole header, is 8-byte aligned for the hardware to write168 * to directly.169 */170static_assert(IS_ALIGNED(sizeof(hantro_jpeg_header), 8),171	      "Hantro JPEG header size needs to be 8-byte aligned.");172 173static unsigned char jpeg_scale_qp(const unsigned char qp, int scale)174{175	unsigned int temp;176 177	temp = DIV_ROUND_CLOSEST((unsigned int)qp * scale, 100);178	if (temp <= 0)179		temp = 1;180	if (temp > 255)181		temp = 255;182 183	return (unsigned char)temp;184}185 186static void187jpeg_scale_quant_table(unsigned char *file_q_tab,188		       unsigned char *reordered_q_tab,189		       const unsigned char *tab, int scale)190{191	int i;192 193	BUILD_BUG_ON(ARRAY_SIZE(v4l2_jpeg_zigzag_scan_index) != JPEG_QUANT_SIZE);194	BUILD_BUG_ON(ARRAY_SIZE(hw_reorder) != JPEG_QUANT_SIZE);195 196	for (i = 0; i < JPEG_QUANT_SIZE; i++) {197		file_q_tab[i] = jpeg_scale_qp(tab[v4l2_jpeg_zigzag_scan_index[i]], scale);198		reordered_q_tab[i] = jpeg_scale_qp(tab[hw_reorder[i]], scale);199	}200}201 202static void jpeg_set_quality(struct hantro_jpeg_ctx *ctx)203{204	int scale;205	/*206	 * Non-linear scaling factor:207	 * [5,50] -> [1000..100], [51,100] -> [98..0]208	 */209	if (ctx->quality < 50)210		scale = 5000 / ctx->quality;211	else212		scale = 200 - 2 * ctx->quality;213 214	BUILD_BUG_ON(ARRAY_SIZE(v4l2_jpeg_ref_table_luma_qt) != JPEG_QUANT_SIZE);215	BUILD_BUG_ON(ARRAY_SIZE(v4l2_jpeg_ref_table_chroma_qt) != JPEG_QUANT_SIZE);216	BUILD_BUG_ON(ARRAY_SIZE(ctx->hw_luma_qtable) != JPEG_QUANT_SIZE);217	BUILD_BUG_ON(ARRAY_SIZE(ctx->hw_chroma_qtable) != JPEG_QUANT_SIZE);218 219	jpeg_scale_quant_table(ctx->buffer + LUMA_QUANT_OFF,220			       ctx->hw_luma_qtable,221			       (const unsigned char *)v4l2_jpeg_ref_table_luma_qt, scale);222	jpeg_scale_quant_table(ctx->buffer + CHROMA_QUANT_OFF,223			       ctx->hw_chroma_qtable,224			       (const unsigned char *)v4l2_jpeg_ref_table_chroma_qt, scale);225}226 227void hantro_jpeg_header_assemble(struct hantro_jpeg_ctx *ctx)228{229	char *buf = ctx->buffer;230 231	memcpy(buf, hantro_jpeg_header,232	       sizeof(hantro_jpeg_header));233 234	buf[HEIGHT_OFF + 0] = ctx->height >> 8;235	buf[HEIGHT_OFF + 1] = ctx->height;236	buf[WIDTH_OFF + 0] = ctx->width >> 8;237	buf[WIDTH_OFF + 1] = ctx->width;238 239	memcpy(buf + HUFF_LUMA_DC_OFF, v4l2_jpeg_ref_table_luma_dc_ht, V4L2_JPEG_REF_HT_DC_LEN);240	memcpy(buf + HUFF_LUMA_AC_OFF, v4l2_jpeg_ref_table_luma_ac_ht, V4L2_JPEG_REF_HT_AC_LEN);241	memcpy(buf + HUFF_CHROMA_DC_OFF, v4l2_jpeg_ref_table_chroma_dc_ht, V4L2_JPEG_REF_HT_DC_LEN);242	memcpy(buf + HUFF_CHROMA_AC_OFF, v4l2_jpeg_ref_table_chroma_ac_ht, V4L2_JPEG_REF_HT_AC_LEN);243 244	jpeg_set_quality(ctx);245}246