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 #include <reset.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 #define DECOM_LMTSL 0x50 36 #define DECOM_LMTSH 0x54 37 38 #define LZ4_HEAD_CSUM_CHECK_EN BIT(1) 39 #define LZ4_BLOCK_CSUM_CHECK_EN BIT(2) 40 #define LZ4_CONT_CSUM_CHECK_EN BIT(3) 41 42 #define DSOLIEN BIT(19) 43 #define ZDICTEIEN BIT(18) 44 #define GCMEIEN BIT(17) 45 #define GIDEIEN BIT(16) 46 #define CCCEIEN BIT(15) 47 #define BCCEIEN BIT(14) 48 #define HCCEIEN BIT(13) 49 #define CSEIEN BIT(12) 50 #define DICTEIEN BIT(11) 51 #define VNEIEN BIT(10) 52 #define WNEIEN BIT(9) 53 #define RDCEIEN BIT(8) 54 #define WRCEIEN BIT(7) 55 #define DISEIEN BIT(6) 56 #define LENEIEN BIT(5) 57 #define LITEIEN BIT(4) 58 #define SQMEIEN BIT(3) 59 #define SLCIEN BIT(2) 60 #define HDEIEN BIT(1) 61 #define DSIEN BIT(0) 62 63 #define DECOM_STOP BIT(0) 64 #define DECOM_COMPLETE BIT(0) 65 #define DECOM_GZIP_MODE BIT(4) 66 #define DECOM_ZLIB_MODE BIT(5) 67 #define DECOM_DEFLATE_MODE BIT(0) 68 #define DECOM_AXI_IDLE BIT(4) 69 #define DECOM_LZ4_MODE 0 70 71 #define DECOM_ENABLE 0x1 72 #define DECOM_DISABLE 0x0 73 74 #define DECOM_IRQ 0xffff /* fixme */ 75 76 #define DECOM_INT_MASK \ 77 (DSOLIEN | ZDICTEIEN | GCMEIEN | GIDEIEN | \ 78 CCCEIEN | BCCEIEN | HCCEIEN | CSEIEN | \ 79 DICTEIEN | VNEIEN | WNEIEN | RDCEIEN | WRCEIEN | \ 80 DISEIEN | LENEIEN | LITEIEN | SQMEIEN | SLCIEN | \ 81 HDEIEN | DSIEN) 82 83 struct rockchip_decom_priv { 84 struct reset_ctl rst; 85 void __iomem *base; 86 bool idle_check_once; 87 bool done; 88 int cached; /* 1: access the data through dcache; 0: no dcache */ 89 }; 90 91 static int rockchip_decom_start(struct udevice *dev, void *buf) 92 { 93 struct rockchip_decom_priv *priv = dev_get_priv(dev); 94 struct decom_param *param = (struct decom_param *)buf; 95 unsigned int limit_lo = param->size_dst & 0xffffffff; 96 unsigned int limit_hi = param->size_dst >> 32; 97 ulong align_input, align_len; 98 99 #if CONFIG_IS_ENABLED(DM_RESET) 100 reset_assert(&priv->rst); 101 udelay(10); 102 reset_deassert(&priv->rst); 103 #endif 104 if (!priv->cached) { 105 /* src: make sure we get the real compressed data from ddr */ 106 align_input = 107 round_down(param->addr_src, CONFIG_SYS_CACHELINE_SIZE); 108 align_len = 109 round_up(param->size_src + (param->addr_src - align_input), 110 CONFIG_SYS_CACHELINE_SIZE); 111 flush_cache(align_input, align_len); 112 113 /* dst: invalidate dcache */ 114 align_input = 115 round_down(param->addr_dst, CONFIG_SYS_CACHELINE_SIZE); 116 align_len = 117 round_up(param->size_src + (param->addr_dst - align_input), 118 CONFIG_SYS_CACHELINE_SIZE); 119 invalidate_dcache_range(align_input, align_len); 120 } 121 122 priv->done = false; 123 124 if (param->mode == DECOM_LZ4) 125 writel(LZ4_CONT_CSUM_CHECK_EN | 126 LZ4_HEAD_CSUM_CHECK_EN | 127 LZ4_BLOCK_CSUM_CHECK_EN | 128 DECOM_LZ4_MODE, 129 priv->base + DECOM_CTRL); 130 else if (param->mode == DECOM_GZIP) 131 writel(DECOM_DEFLATE_MODE | DECOM_GZIP_MODE, 132 priv->base + DECOM_CTRL); 133 else if (param->mode == DECOM_ZLIB) 134 writel(DECOM_DEFLATE_MODE | DECOM_ZLIB_MODE, 135 priv->base + DECOM_CTRL); 136 137 writel(param->addr_src, priv->base + DECOM_RADDR); 138 writel(param->addr_dst, priv->base + DECOM_WADDR); 139 140 writel(limit_lo, priv->base + DECOM_LMTSL); 141 writel(limit_hi, priv->base + DECOM_LMTSH); 142 writel(DECOM_ENABLE, priv->base + DECOM_ENR); 143 144 priv->idle_check_once = true; 145 146 return 0; 147 } 148 149 static int rockchip_decom_stop(struct udevice *dev) 150 { 151 struct rockchip_decom_priv *priv = dev_get_priv(dev); 152 153 writel(DECOM_DISABLE, priv->base + DECOM_ENR); 154 155 return 0; 156 } 157 158 /* Caller must call this function to check if decompress done */ 159 static int rockchip_decom_done_poll(struct udevice *dev) 160 { 161 struct rockchip_decom_priv *priv = dev_get_priv(dev); 162 163 /* 164 * Test the decom is idle first time. 165 */ 166 if (!priv->idle_check_once) 167 return !(readl(priv->base + DECOM_AXI_STAT) & DECOM_AXI_IDLE); 168 169 return !(readl(priv->base + DECOM_STAT) & DECOM_COMPLETE); 170 } 171 172 static int rockchip_decom_capability(u32 *buf) 173 { 174 *buf = DECOM_GZIP; 175 176 return 0; 177 } 178 179 static int rockchip_decom_data_size(struct udevice *dev, u64 *buf) 180 { 181 struct rockchip_decom_priv *priv = dev_get_priv(dev); 182 struct decom_param *param = (struct decom_param *)buf; 183 u32 sizel, sizeh; 184 185 sizel = readl(priv->base + DECOM_TSIZEL); 186 sizeh = readl(priv->base + DECOM_TSIZEH); 187 param->size_dst = sizel | ((u64)sizeh << 32); 188 189 return 0; 190 } 191 192 /* Caller must fill in param @buf which represent struct decom_param */ 193 static int rockchip_decom_ioctl(struct udevice *dev, unsigned long request, 194 void *buf) 195 { 196 int ret = -EINVAL; 197 198 switch (request) { 199 case IOCTL_REQ_START: 200 ret = rockchip_decom_start(dev, buf); 201 break; 202 case IOCTL_REQ_POLL: 203 ret = rockchip_decom_done_poll(dev); 204 break; 205 case IOCTL_REQ_STOP: 206 ret = rockchip_decom_stop(dev); 207 break; 208 case IOCTL_REQ_CAPABILITY: 209 ret = rockchip_decom_capability(buf); 210 break; 211 case IOCTL_REQ_DATA_SIZE: 212 ret = rockchip_decom_data_size(dev, buf); 213 break; 214 default: 215 printf("Unsupported ioctl: %ld\n", (ulong)request); 216 break; 217 } 218 219 return ret; 220 } 221 222 static const struct misc_ops rockchip_decom_ops = { 223 .ioctl = rockchip_decom_ioctl, 224 }; 225 226 static int rockchip_decom_ofdata_to_platdata(struct udevice *dev) 227 { 228 struct rockchip_decom_priv *priv = dev_get_priv(dev); 229 230 priv->base = dev_read_addr_ptr(dev); 231 if (!priv->base) 232 return -ENOENT; 233 234 priv->cached = dev_read_u32_default(dev, "data-cached", 0); 235 236 return 0; 237 } 238 239 static int rockchip_decom_probe(struct udevice *dev) 240 { 241 #if CONFIG_IS_ENABLED(DM_RESET) 242 struct rockchip_decom_priv *priv = dev_get_priv(dev); 243 int ret; 244 245 ret = reset_get_by_name(dev, "dresetn", &priv->rst); 246 if (ret) { 247 debug("reset_get_by_name() failed: %d\n", ret); 248 return ret; 249 } 250 #endif 251 return 0; 252 } 253 254 static const struct udevice_id rockchip_decom_ids[] = { 255 { .compatible = "rockchip,hw-decompress" }, 256 {} 257 }; 258 259 U_BOOT_DRIVER(rockchip_hw_decompress) = { 260 .name = "rockchip_hw_decompress", 261 .id = UCLASS_MISC, 262 .of_match = rockchip_decom_ids, 263 .probe = rockchip_decom_probe, 264 .ofdata_to_platdata = rockchip_decom_ofdata_to_platdata, 265 .priv_auto_alloc_size = sizeof(struct rockchip_decom_priv), 266 .ops = &rockchip_decom_ops, 267 }; 268