xref: /rk3399_rockchip-uboot/drivers/misc/misc_decompress.c (revision 4298c19d4f9c3a50727d5406472894b533ffad2f)
1cc05bcfaSJason Zhu // SPDX-License-Identifier:     GPL-2.0+
2cc05bcfaSJason Zhu /*
3cc05bcfaSJason Zhu  * Copyright (C) 2020 Rockchip Electronics Co., Ltd
4cc05bcfaSJason Zhu  */
5cc05bcfaSJason Zhu #include <common.h>
6cc05bcfaSJason Zhu #include <dm.h>
7cc05bcfaSJason Zhu #include <dm/uclass.h>
8cc05bcfaSJason Zhu #include <misc.h>
9cc05bcfaSJason Zhu 
10cc05bcfaSJason Zhu #define HEAD_CRC		2
11cc05bcfaSJason Zhu #define EXTRA_FIELD		4
12cc05bcfaSJason Zhu #define ORIG_NAME		8
13cc05bcfaSJason Zhu #define COMMENT			0x10
14cc05bcfaSJason Zhu #define RESERVED		0xe0
15cc05bcfaSJason Zhu #define DEFLATED		8
16cc05bcfaSJason Zhu 
17cc05bcfaSJason Zhu static int misc_gzip_parse_header(const unsigned char *src, unsigned long len)
18cc05bcfaSJason Zhu {
19cc05bcfaSJason Zhu 	int i, flags;
20cc05bcfaSJason Zhu 
21cc05bcfaSJason Zhu 	/* skip header */
22cc05bcfaSJason Zhu 	i = 10;
23cc05bcfaSJason Zhu 	flags = src[3];
24cc05bcfaSJason Zhu 	if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
25cc05bcfaSJason Zhu 		debug("Error: Bad gzipped data\n");
26cc05bcfaSJason Zhu 		return (-1);
27cc05bcfaSJason Zhu 	}
28cc05bcfaSJason Zhu 	if ((flags & EXTRA_FIELD) != 0)
29cc05bcfaSJason Zhu 		i = 12 + src[10] + (src[11] << 8);
30cc05bcfaSJason Zhu 	if ((flags & ORIG_NAME) != 0)
31cc05bcfaSJason Zhu 		while (src[i++] != 0)
32cc05bcfaSJason Zhu 			;
33cc05bcfaSJason Zhu 	if ((flags & COMMENT) != 0)
34cc05bcfaSJason Zhu 		while (src[i++] != 0)
35cc05bcfaSJason Zhu 			;
36cc05bcfaSJason Zhu 	if ((flags & HEAD_CRC) != 0)
37cc05bcfaSJason Zhu 		i += 2;
38cc05bcfaSJason Zhu 	if (i >= len) {
39cc05bcfaSJason Zhu 		puts("Error: gunzip out of data in header\n");
40cc05bcfaSJason Zhu 		return (-1);
41cc05bcfaSJason Zhu 	}
42cc05bcfaSJason Zhu 	return i;
43cc05bcfaSJason Zhu }
44cc05bcfaSJason Zhu 
45cc05bcfaSJason Zhu struct udevice *misc_decompress_get_device(u32 capability)
46cc05bcfaSJason Zhu {
47374c241cSJoseph Chen 	return misc_get_device_by_capability(capability);
48cc05bcfaSJason Zhu }
49cc05bcfaSJason Zhu 
50cc05bcfaSJason Zhu int misc_decompress_start(struct udevice *dev, unsigned long src,
51cc05bcfaSJason Zhu 			  unsigned long dst, unsigned long size)
52cc05bcfaSJason Zhu {
53cc05bcfaSJason Zhu 	struct decom_param param;
54cc05bcfaSJason Zhu 
55cc05bcfaSJason Zhu 	param.addr_dst = dst;
56cc05bcfaSJason Zhu 	param.addr_src = src;
57cc05bcfaSJason Zhu 	param.size = size;
58cc05bcfaSJason Zhu 	if (misc_gzip_parse_header((unsigned char *)src, 0xffff) > 0) {
595b7d3298SJason Zhu 		param.mode = DECOM_GZIP;
60cc05bcfaSJason Zhu 	} else {
61cc05bcfaSJason Zhu 		printf("Unsupported decompression format.\n");
62cc05bcfaSJason Zhu 		return -EPERM;
63cc05bcfaSJason Zhu 	}
64cc05bcfaSJason Zhu 
65cc05bcfaSJason Zhu 	return misc_ioctl(dev, IOCTL_REQ_START, &param);
66cc05bcfaSJason Zhu }
67cc05bcfaSJason Zhu 
68cc05bcfaSJason Zhu int misc_decompress_stop(struct udevice *dev)
69cc05bcfaSJason Zhu {
70cc05bcfaSJason Zhu 	return misc_ioctl(dev, IOCTL_REQ_STOP, NULL);
71cc05bcfaSJason Zhu }
72cc05bcfaSJason Zhu 
73809af6baSJason Zhu bool misc_decompress_is_complete(struct udevice *dev)
74cc05bcfaSJason Zhu {
75809af6baSJason Zhu 	if (misc_ioctl(dev, IOCTL_REQ_POLL, NULL))
76809af6baSJason Zhu 		return false;
77809af6baSJason Zhu 	else
78809af6baSJason Zhu 		return true;
79cc05bcfaSJason Zhu }
80*4298c19dSJason Zhu 
81*4298c19dSJason Zhu int misc_decompress_process(unsigned long src,
82*4298c19dSJason Zhu 			    unsigned long dst,
83*4298c19dSJason Zhu 			    unsigned long limit_size,
84*4298c19dSJason Zhu 			    u32 cap)
85*4298c19dSJason Zhu {
86*4298c19dSJason Zhu 	struct udevice *dev;
87*4298c19dSJason Zhu 	int timeout = 10000;
88*4298c19dSJason Zhu 	int ret;
89*4298c19dSJason Zhu 
90*4298c19dSJason Zhu 	dev = misc_decompress_get_device(cap);
91*4298c19dSJason Zhu 	if (!dev)
92*4298c19dSJason Zhu 		return -EIO;
93*4298c19dSJason Zhu 
94*4298c19dSJason Zhu 	while (!misc_decompress_is_complete(dev)) {
95*4298c19dSJason Zhu 		if (timeout < 0)
96*4298c19dSJason Zhu 			return -EIO;
97*4298c19dSJason Zhu 		timeout--;
98*4298c19dSJason Zhu 		udelay(10);
99*4298c19dSJason Zhu 	}
100*4298c19dSJason Zhu 
101*4298c19dSJason Zhu 	ret = misc_decompress_stop(dev);
102*4298c19dSJason Zhu 	if (ret)
103*4298c19dSJason Zhu 		return -EIO;
104*4298c19dSJason Zhu 
105*4298c19dSJason Zhu 	return misc_decompress_start(dev, src, dst, limit_size);
106*4298c19dSJason Zhu }
107