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, Pengutronix 8 */ 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 25 19 #define CHROMA_QUANT_OFF 90 20 #define HEIGHT_OFF 159 21 #define WIDTH_OFF 161 22 23 #define HUFF_LUMA_DC_OFF 178 24 #define HUFF_LUMA_AC_OFF 211 25 #define HUFF_CHROMA_DC_OFF 394 26 #define HUFF_CHROMA_AC_OFF 427 27 28 static 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, 63 37 }; 38 39 /* For simplicity, we keep a pre-formatted JPEG header, 40 * and we'll use fixed offsets to change the width, height 41 * quantization tables, etc. 42 */ 43 static 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 of 160 * "sizeof(hantro_jpeg_header)". The two must be equal. 161 */ 162 static_assert(sizeof(hantro_jpeg_header) == JPEG_HEADER_SIZE); 163 164 /* 165 * hantro_jpeg_header is padded with a COM segment, so that the payload 166 * of the SOS segment (the entropy-encoded image scan), which should 167 * trail the whole header, is 8-byte aligned for the hardware to write 168 * to directly. 169 */ 170 static_assert(IS_ALIGNED(sizeof(hantro_jpeg_header), 8), 171 "Hantro JPEG header size needs to be 8-byte aligned."); 172 173 static 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 186 static void 187 jpeg_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 202 static 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 else 212 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 227 void 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