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, ¶m); 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