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