1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2019 Rockchip Electronics Co., Ltd 4 */ 5 #include <common.h> 6 #include <asm/io.h> 7 #include <dm.h> 8 #include <linux/bitops.h> 9 #include <misc.h> 10 #include <irq-generic.h> 11 12 DECLARE_GLOBAL_DATA_PTR; 13 14 #define DECOM_CTRL 0x0 15 #define DECOM_ENR 0x4 16 #define DECOM_RADDR 0x8 17 #define DECOM_WADDR 0xc 18 #define DECOM_UDDSL 0x10 19 #define DECOM_UDDSH 0x14 20 #define DECOM_TXTHR 0x18 21 #define DECOM_RXTHR 0x1c 22 #define DECOM_SLEN 0x20 23 #define DECOM_STAT 0x24 24 #define DECOM_ISR 0x28 25 #define DECOM_IEN 0x2c 26 #define DECOM_AXI_STAT 0x30 27 #define DECOM_TSIZEL 0x34 28 #define DECOM_TSIZEH 0x38 29 #define DECOM_MGNUM 0x3c 30 #define DECOM_FRAME 0x40 31 #define DECOM_DICTID 0x44 32 #define DECOM_CSL 0x48 33 #define DECOM_CSH 0x4c 34 35 #define LZ4_HEAD_CSUM_CHECK_EN BIT(1) 36 #define LZ4_BLOCK_CSUM_CHECK_EN BIT(2) 37 #define LZ4_CONT_CSUM_CHECK_EN BIT(3) 38 39 #define DSOLIEN BIT(19) 40 #define ZDICTEIEN BIT(18) 41 #define GCMEIEN BIT(17) 42 #define GIDEIEN BIT(16) 43 #define CCCEIEN BIT(15) 44 #define BCCEIEN BIT(14) 45 #define HCCEIEN BIT(13) 46 #define CSEIEN BIT(12) 47 #define DICTEIEN BIT(11) 48 #define VNEIEN BIT(10) 49 #define WNEIEN BIT(9) 50 #define RDCEIEN BIT(8) 51 #define WRCEIEN BIT(7) 52 #define DISEIEN BIT(6) 53 #define LENEIEN BIT(5) 54 #define LITEIEN BIT(4) 55 #define SQMEIEN BIT(3) 56 #define SLCIEN BIT(2) 57 #define HDEIEN BIT(1) 58 #define DSIEN BIT(0) 59 60 #define DECOM_STOP BIT(0) 61 #define DECOM_COMPLETE BIT(0) 62 #define DECOM_GZIP_MODE BIT(4) 63 #define DECOM_ZLIB_MODE BIT(5) 64 #define DECOM_DEFLATE_MODE BIT(0) 65 66 #define DECOM_ENABLE 0x1 67 #define DECOM_DISABLE 0x0 68 69 #define DECOM_IRQ 0xffff /* fixme */ 70 71 #define DECOM_INT_MASK \ 72 (DSOLIEN | ZDICTEIEN | GCMEIEN | GIDEIEN | \ 73 CCCEIEN | BCCEIEN | HCCEIEN | CSEIEN | \ 74 DICTEIEN | VNEIEN | WNEIEN | RDCEIEN | WRCEIEN | \ 75 DISEIEN | LENEIEN | LITEIEN | SQMEIEN | SLCIEN | \ 76 HDEIEN | DSIEN) 77 78 enum decom_mod { 79 LZ4_MOD, 80 GZIP_MOD, 81 ZLIB_MOD, 82 }; 83 84 struct rockchip_decom_param { 85 unsigned long addr_src; 86 unsigned long addr_dst; 87 unsigned long size; 88 enum decom_mod mode; 89 }; 90 91 struct rockchip_decom_priv { 92 void __iomem *base; 93 bool done; 94 }; 95 96 static int rockchip_decom_start(struct udevice *dev, void *buf) 97 { 98 struct rockchip_decom_priv *priv = dev_get_priv(dev); 99 struct rockchip_decom_param *param = (struct rockchip_decom_param *)buf; 100 101 priv->done = false; 102 103 if (param->mode == LZ4_MOD) 104 writel(LZ4_CONT_CSUM_CHECK_EN | 105 LZ4_HEAD_CSUM_CHECK_EN | 106 LZ4_BLOCK_CSUM_CHECK_EN | 107 LZ4_MOD, priv->base + DECOM_CTRL); 108 109 if (param->mode == GZIP_MOD) 110 writel(DECOM_DEFLATE_MODE | DECOM_GZIP_MODE, 111 priv->base + DECOM_CTRL); 112 113 if (param->mode == ZLIB_MOD) 114 writel(DECOM_DEFLATE_MODE | DECOM_ZLIB_MODE, 115 priv->base + DECOM_CTRL); 116 117 writel(param->addr_src, priv->base + DECOM_RADDR); 118 writel(param->addr_dst, priv->base + DECOM_WADDR); 119 120 writel(DECOM_INT_MASK, priv->base + DECOM_IEN); 121 writel(DECOM_ENABLE, priv->base + DECOM_ENR); 122 123 return 0; 124 } 125 126 static int rockchip_decom_stop(struct udevice *dev) 127 { 128 struct rockchip_decom_priv *priv = dev_get_priv(dev); 129 int irq_status; 130 131 irq_status = readl(priv->base + DECOM_ISR); 132 /* clear interrupts */ 133 if (irq_status) 134 writel(irq_status, priv->base + DECOM_ISR); 135 136 writel(DECOM_DISABLE, priv->base + DECOM_ENR); 137 138 return 0; 139 } 140 141 /* Caller must call this function to check if decompress done */ 142 static int rockchip_decom_done_poll(struct udevice *dev) 143 { 144 struct rockchip_decom_priv *priv = dev_get_priv(dev); 145 int decom_status; 146 147 decom_status = readl(priv->base + DECOM_STAT); 148 if (decom_status & DECOM_COMPLETE) 149 return 0; 150 151 return -EINVAL; 152 } 153 154 /* Caller must fill in param @buf which represent struct rockchip_decom_param */ 155 static int rockchip_decom_ioctl(struct udevice *dev, unsigned long request, 156 void *buf) 157 { 158 int ret = -EINVAL; 159 160 switch (request) { 161 case IOCTL_REQ_START: 162 ret = rockchip_decom_start(dev, buf); 163 break; 164 case IOCTL_REQ_POLL: 165 ret = rockchip_decom_done_poll(dev); 166 break; 167 case IOCTL_REQ_STOP: 168 ret = rockchip_decom_stop(dev); 169 break; 170 } 171 172 return ret; 173 } 174 175 static const struct misc_ops rockchip_decom_ops = { 176 .ioctl = rockchip_decom_ioctl, 177 }; 178 179 static int rockchip_decom_ofdata_to_platdata(struct udevice *dev) 180 { 181 struct rockchip_decom_priv *priv = dev_get_priv(dev); 182 183 priv->base = dev_read_addr_ptr(dev); 184 if (!priv->base) 185 return -ENOENT; 186 187 return 0; 188 } 189 190 #ifndef CONFIG_SPL_BUILD 191 static void rockchip_decom_irqhandler(int irq, void *data) 192 { 193 struct udevice *dev = data; 194 struct rockchip_decom_priv *priv = dev_get_priv(dev); 195 int irq_status; 196 int decom_status; 197 198 irq_status = readl(priv->base + DECOM_ISR); 199 /* clear interrupts */ 200 writel(irq_status, priv->base + DECOM_ISR); 201 if (irq_status & DECOM_STOP) { 202 decom_status = readl(priv->base + DECOM_STAT); 203 if (decom_status & DECOM_COMPLETE) { 204 priv->done = true; 205 /* 206 * TODO: 207 * Inform someone that decompress completed 208 */ 209 printf("decom completed\n"); 210 } else { 211 printf("decom failed, irq_status = 0x%x, decom_status = 0x%x\n", 212 irq_status, decom_status); 213 } 214 } 215 } 216 #endif 217 218 static int rockchip_decom_probe(struct udevice *dev) 219 { 220 #ifndef CONFIG_SPL_BUILD 221 irq_install_handler(DECOM_IRQ, rockchip_decom_irqhandler, dev); 222 irq_handler_enable(DECOM_IRQ); 223 #endif 224 return 0; 225 } 226 227 static const struct udevice_id rockchip_decom_ids[] = { 228 { .compatible = "rockchip,hw-decompress" }, 229 {} 230 }; 231 232 U_BOOT_DRIVER(rockchip_hw_decompress) = { 233 .name = "rockchip_hw_decompress", 234 .id = UCLASS_MISC, 235 .of_match = rockchip_decom_ids, 236 .probe = rockchip_decom_probe, 237 .ofdata_to_platdata = rockchip_decom_ofdata_to_platdata, 238 .priv_auto_alloc_size = sizeof(struct rockchip_decom_priv), 239 .ops = &rockchip_decom_ops, 240 }; 241