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