xref: /rk3399_rockchip-uboot/drivers/misc/misc_decompress.c (revision e663d2b596fd0029d58f1b4e63b30ff230480dbb)
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 #include <misc_decompress.h>
10 
11 #define HEAD_CRC		2
12 #define EXTRA_FIELD		4
13 #define ORIG_NAME		8
14 #define COMMENT			0x10
15 #define RESERVED		0xe0
16 #define DEFLATED		8
17 
18 static int misc_gzip_parse_header(const unsigned char *src, unsigned long len)
19 {
20 	int i, flags;
21 
22 	/* skip header */
23 	i = 10;
24 	flags = src[3];
25 	if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
26 		debug("Error: Bad gzipped data\n");
27 		return (-1);
28 	}
29 	if ((flags & EXTRA_FIELD) != 0)
30 		i = 12 + src[10] + (src[11] << 8);
31 	if ((flags & ORIG_NAME) != 0)
32 		while (src[i++] != 0)
33 			;
34 	if ((flags & COMMENT) != 0)
35 		while (src[i++] != 0)
36 			;
37 	if ((flags & HEAD_CRC) != 0)
38 		i += 2;
39 	if (i >= len) {
40 		puts("Error: gunzip out of data in header\n");
41 		return (-1);
42 	}
43 	return i;
44 }
45 
46 struct udevice *misc_decompress_get_device(u32 capability)
47 {
48 	const struct misc_ops *ops;
49 	struct udevice *dev;
50 	struct uclass *uc;
51 	int ret;
52 	u32 cap;
53 
54 	ret = uclass_get(UCLASS_MISC, &uc);
55 	if (ret)
56 		return NULL;
57 
58 	for (uclass_first_device(UCLASS_MISC, &dev);
59 	     dev;
60 	     uclass_next_device(&dev)) {
61 		ops = device_get_ops(dev);
62 		if (!ops || !ops->ioctl)
63 			continue;
64 
65 		cap = ops->ioctl(dev, IOCTL_REQ_CAPABILITY, NULL);
66 		if ((cap & capability) == capability)
67 			return dev;
68 	}
69 
70 	return NULL;
71 }
72 
73 int misc_decompress_start(struct udevice *dev, unsigned long src,
74 			  unsigned long dst, unsigned long size)
75 {
76 	struct decom_param param;
77 
78 	param.addr_dst = dst;
79 	param.addr_src = src;
80 	param.size = size;
81 	if (misc_gzip_parse_header((unsigned char *)src, 0xffff) > 0) {
82 		param.mode = GZIP_MOD;
83 	} else {
84 		printf("Unsupported decompression format.\n");
85 		return -EPERM;
86 	}
87 
88 	return misc_ioctl(dev, IOCTL_REQ_START, &param);
89 }
90 
91 int misc_decompress_stop(struct udevice *dev)
92 {
93 	return misc_ioctl(dev, IOCTL_REQ_STOP, NULL);
94 }
95 
96 int misc_decompress_is_complete(struct udevice *dev)
97 {
98 	return misc_ioctl(dev, IOCTL_REQ_POLL, NULL);
99 }
100