1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (c) 2016 MediaTek Inc.
4 * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com>
5 *         Rick Chang <rick.chang@mediatek.com>
6 */
7
8#include <linux/kernel.h>
9#include <linux/videodev2.h>
10#include <media/jpeg.h>
11
12#include "mtk_jpeg_dec_parse.h"
13
14struct mtk_jpeg_stream {
15	u8 *addr;
16	u32 size;
17	u32 curr;
18};
19
20static int read_byte(struct mtk_jpeg_stream *stream)
21{
22	if (stream->curr >= stream->size)
23		return -1;
24	return stream->addr[stream->curr++];
25}
26
27static int read_word_be(struct mtk_jpeg_stream *stream, u32 *word)
28{
29	u32 temp;
30	int byte;
31
32	byte = read_byte(stream);
33	if (byte == -1)
34		return -1;
35	temp = byte << 8;
36	byte = read_byte(stream);
37	if (byte == -1)
38		return -1;
39	*word = (u32)byte | temp;
40
41	return 0;
42}
43
44static void read_skip(struct mtk_jpeg_stream *stream, long len)
45{
46	if (len <= 0)
47		return;
48	while (len--)
49		read_byte(stream);
50}
51
52static bool mtk_jpeg_do_parse(struct mtk_jpeg_dec_param *param, u8 *src_addr_va,
53			      u32 src_size)
54{
55	bool notfound = true;
56	struct mtk_jpeg_stream stream;
57
58	stream.addr = src_addr_va;
59	stream.size = src_size;
60	stream.curr = 0;
61
62	while (notfound) {
63		int i, length, byte;
64		u32 word;
65
66		byte = read_byte(&stream);
67		if (byte == -1)
68			return false;
69		if (byte != 0xff)
70			continue;
71		do
72			byte = read_byte(&stream);
73		while (byte == 0xff);
74		if (byte == -1)
75			return false;
76		if (byte == 0)
77			continue;
78
79		length = 0;
80		switch (byte) {
81		case JPEG_MARKER_SOF0:
82			/* length */
83			if (read_word_be(&stream, &word))
84				break;
85
86			/* precision */
87			if (read_byte(&stream) == -1)
88				break;
89
90			if (read_word_be(&stream, &word))
91				break;
92			param->pic_h = word;
93
94			if (read_word_be(&stream, &word))
95				break;
96			param->pic_w = word;
97
98			param->comp_num = read_byte(&stream);
99			if (param->comp_num != 1 && param->comp_num != 3)
100				break;
101
102			for (i = 0; i < param->comp_num; i++) {
103				param->comp_id[i] = read_byte(&stream);
104				if (param->comp_id[i] == -1)
105					break;
106
107				/* sampling */
108				byte = read_byte(&stream);
109				if (byte == -1)
110					break;
111				param->sampling_w[i] = (byte >> 4) & 0x0F;
112				param->sampling_h[i] = byte & 0x0F;
113
114				param->qtbl_num[i] = read_byte(&stream);
115				if (param->qtbl_num[i] == -1)
116					break;
117			}
118
119			notfound = !(i == param->comp_num);
120			break;
121		case JPEG_MARKER_RST ... JPEG_MARKER_RST + 7:
122		case JPEG_MARKER_SOI:
123		case JPEG_MARKER_EOI:
124		case JPEG_MARKER_TEM:
125			break;
126		default:
127			if (read_word_be(&stream, &word))
128				break;
129			length = (long)word - 2;
130			read_skip(&stream, length);
131			break;
132		}
133	}
134
135	return !notfound;
136}
137
138bool mtk_jpeg_parse(struct mtk_jpeg_dec_param *param, u8 *src_addr_va,
139		    u32 src_size)
140{
141	if (!mtk_jpeg_do_parse(param, src_addr_va, src_size))
142		return false;
143	if (mtk_jpeg_dec_fill_param(param))
144		return false;
145
146	return true;
147}
148