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