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