xref: /rk3399_rockchip-uboot/drivers/misc/misc_decompress.c (revision 1cef1b20c4e10aadfa427e1de63a0750321327ea)
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 	const struct misc_ops *ops;
48 	struct udevice *dev;
49 	struct uclass *uc;
50 	int ret;
51 	u32 cap;
52 
53 	ret = uclass_get(UCLASS_MISC, &uc);
54 	if (ret)
55 		return NULL;
56 
57 	for (uclass_first_device(UCLASS_MISC, &dev);
58 	     dev;
59 	     uclass_next_device(&dev)) {
60 		ops = device_get_ops(dev);
61 		if (!ops || !ops->ioctl)
62 			continue;
63 
64 		cap = ops->ioctl(dev, IOCTL_REQ_CAPABILITY, NULL);
65 		if ((cap & capability) == capability)
66 			return dev;
67 	}
68 
69 	return NULL;
70 }
71 
72 int misc_decompress_start(struct udevice *dev, unsigned long src,
73 			  unsigned long dst, unsigned long size)
74 {
75 	struct decom_param param;
76 
77 	param.addr_dst = dst;
78 	param.addr_src = src;
79 	param.size = size;
80 	if (misc_gzip_parse_header((unsigned char *)src, 0xffff) > 0) {
81 		param.mode = DECOM_GZIP;
82 	} else {
83 		printf("Unsupported decompression format.\n");
84 		return -EPERM;
85 	}
86 
87 	return misc_ioctl(dev, IOCTL_REQ_START, &param);
88 }
89 
90 int misc_decompress_stop(struct udevice *dev)
91 {
92 	return misc_ioctl(dev, IOCTL_REQ_STOP, NULL);
93 }
94 
95 int misc_decompress_is_complete(struct udevice *dev)
96 {
97 	return misc_ioctl(dev, IOCTL_REQ_POLL, NULL);
98 }
99