12bb8d138SSimon Xue // SPDX-License-Identifier: GPL-2.0+ 22bb8d138SSimon Xue /* 32bb8d138SSimon Xue * Copyright (C) 2019 Rockchip Electronics Co., Ltd 42bb8d138SSimon Xue */ 52bb8d138SSimon Xue #include <common.h> 62bb8d138SSimon Xue #include <asm/io.h> 75db33a71SSimon Xue #include <clk.h> 82bb8d138SSimon Xue #include <dm.h> 92bb8d138SSimon Xue #include <linux/bitops.h> 102bb8d138SSimon Xue #include <misc.h> 112bb8d138SSimon Xue #include <irq-generic.h> 12b367c66bSJoseph Chen #include <reset.h> 132bb8d138SSimon Xue 142bb8d138SSimon Xue DECLARE_GLOBAL_DATA_PTR; 152bb8d138SSimon Xue 162bb8d138SSimon Xue #define DECOM_CTRL 0x0 172bb8d138SSimon Xue #define DECOM_ENR 0x4 182bb8d138SSimon Xue #define DECOM_RADDR 0x8 192bb8d138SSimon Xue #define DECOM_WADDR 0xc 202bb8d138SSimon Xue #define DECOM_UDDSL 0x10 212bb8d138SSimon Xue #define DECOM_UDDSH 0x14 222bb8d138SSimon Xue #define DECOM_TXTHR 0x18 232bb8d138SSimon Xue #define DECOM_RXTHR 0x1c 242bb8d138SSimon Xue #define DECOM_SLEN 0x20 252bb8d138SSimon Xue #define DECOM_STAT 0x24 262bb8d138SSimon Xue #define DECOM_ISR 0x28 272bb8d138SSimon Xue #define DECOM_IEN 0x2c 282bb8d138SSimon Xue #define DECOM_AXI_STAT 0x30 292bb8d138SSimon Xue #define DECOM_TSIZEL 0x34 302bb8d138SSimon Xue #define DECOM_TSIZEH 0x38 312bb8d138SSimon Xue #define DECOM_MGNUM 0x3c 322bb8d138SSimon Xue #define DECOM_FRAME 0x40 332bb8d138SSimon Xue #define DECOM_DICTID 0x44 342bb8d138SSimon Xue #define DECOM_CSL 0x48 352bb8d138SSimon Xue #define DECOM_CSH 0x4c 36327380daSSimon Xue #define DECOM_LMTSL 0x50 37327380daSSimon Xue #define DECOM_LMTSH 0x54 382bb8d138SSimon Xue 392bb8d138SSimon Xue #define LZ4_HEAD_CSUM_CHECK_EN BIT(1) 402bb8d138SSimon Xue #define LZ4_BLOCK_CSUM_CHECK_EN BIT(2) 412bb8d138SSimon Xue #define LZ4_CONT_CSUM_CHECK_EN BIT(3) 422bb8d138SSimon Xue 432bb8d138SSimon Xue #define DSOLIEN BIT(19) 442bb8d138SSimon Xue #define ZDICTEIEN BIT(18) 452bb8d138SSimon Xue #define GCMEIEN BIT(17) 462bb8d138SSimon Xue #define GIDEIEN BIT(16) 472bb8d138SSimon Xue #define CCCEIEN BIT(15) 482bb8d138SSimon Xue #define BCCEIEN BIT(14) 492bb8d138SSimon Xue #define HCCEIEN BIT(13) 502bb8d138SSimon Xue #define CSEIEN BIT(12) 512bb8d138SSimon Xue #define DICTEIEN BIT(11) 522bb8d138SSimon Xue #define VNEIEN BIT(10) 532bb8d138SSimon Xue #define WNEIEN BIT(9) 542bb8d138SSimon Xue #define RDCEIEN BIT(8) 552bb8d138SSimon Xue #define WRCEIEN BIT(7) 562bb8d138SSimon Xue #define DISEIEN BIT(6) 572bb8d138SSimon Xue #define LENEIEN BIT(5) 582bb8d138SSimon Xue #define LITEIEN BIT(4) 592bb8d138SSimon Xue #define SQMEIEN BIT(3) 602bb8d138SSimon Xue #define SLCIEN BIT(2) 612bb8d138SSimon Xue #define HDEIEN BIT(1) 622bb8d138SSimon Xue #define DSIEN BIT(0) 632bb8d138SSimon Xue 642bb8d138SSimon Xue #define DECOM_STOP BIT(0) 652bb8d138SSimon Xue #define DECOM_COMPLETE BIT(0) 662bb8d138SSimon Xue #define DECOM_GZIP_MODE BIT(4) 672bb8d138SSimon Xue #define DECOM_ZLIB_MODE BIT(5) 682bb8d138SSimon Xue #define DECOM_DEFLATE_MODE BIT(0) 69809af6baSJason Zhu #define DECOM_AXI_IDLE BIT(4) 705b7d3298SJason Zhu #define DECOM_LZ4_MODE 0 712bb8d138SSimon Xue 722bb8d138SSimon Xue #define DECOM_ENABLE 0x1 732bb8d138SSimon Xue #define DECOM_DISABLE 0x0 742bb8d138SSimon Xue 752bb8d138SSimon Xue #define DECOM_IRQ 0xffff /* fixme */ 762bb8d138SSimon Xue 772bb8d138SSimon Xue #define DECOM_INT_MASK \ 782bb8d138SSimon Xue (DSOLIEN | ZDICTEIEN | GCMEIEN | GIDEIEN | \ 792bb8d138SSimon Xue CCCEIEN | BCCEIEN | HCCEIEN | CSEIEN | \ 802bb8d138SSimon Xue DICTEIEN | VNEIEN | WNEIEN | RDCEIEN | WRCEIEN | \ 812bb8d138SSimon Xue DISEIEN | LENEIEN | LITEIEN | SQMEIEN | SLCIEN | \ 822bb8d138SSimon Xue HDEIEN | DSIEN) 832bb8d138SSimon Xue 845db33a71SSimon Xue #define DCLK_DECOM 400 * 1000 * 1000 855db33a71SSimon Xue 862bb8d138SSimon Xue struct rockchip_decom_priv { 87b367c66bSJoseph Chen struct reset_ctl rst; 882bb8d138SSimon Xue void __iomem *base; 89809af6baSJason Zhu bool idle_check_once; 902bb8d138SSimon Xue bool done; 915db33a71SSimon Xue struct clk dclk; 928b225c61SJoseph Chen int cached; /* 1: access the data through dcache; 0: no dcache */ 932bb8d138SSimon Xue }; 942bb8d138SSimon Xue 952bb8d138SSimon Xue static int rockchip_decom_start(struct udevice *dev, void *buf) 962bb8d138SSimon Xue { 972bb8d138SSimon Xue struct rockchip_decom_priv *priv = dev_get_priv(dev); 98cc05bcfaSJason Zhu struct decom_param *param = (struct decom_param *)buf; 99e1e885d3SJoseph Chen unsigned int limit_lo = param->size_dst & 0xffffffff; 100e1e885d3SJoseph Chen unsigned int limit_hi = param->size_dst >> 32; 101369ace90SXuhui Lin u32 irq_status; 1028b225c61SJoseph Chen 103b367c66bSJoseph Chen #if CONFIG_IS_ENABLED(DM_RESET) 104b367c66bSJoseph Chen reset_assert(&priv->rst); 105b367c66bSJoseph Chen udelay(10); 106b367c66bSJoseph Chen reset_deassert(&priv->rst); 107b367c66bSJoseph Chen #endif 108c9f753f3SJoseph Chen /* 109c9f753f3SJoseph Chen * Purpose: 110c9f753f3SJoseph Chen * src: clean dcache to get the real compressed data from ddr. 111c9f753f3SJoseph Chen * dst: invalidate dcache. 112c9f753f3SJoseph Chen * 113c9f753f3SJoseph Chen * flush_dcache_all() operating on set/way is faster than 114c9f753f3SJoseph Chen * flush_cache() and invalidate_dcache_range() operating 115c9f753f3SJoseph Chen * on virtual address. 116c9f753f3SJoseph Chen */ 117c9f753f3SJoseph Chen if (!priv->cached) 118c9f753f3SJoseph Chen flush_dcache_all(); 1192bb8d138SSimon Xue 1202bb8d138SSimon Xue priv->done = false; 1212bb8d138SSimon Xue 122369ace90SXuhui Lin irq_status = readl(priv->base + DECOM_ISR); 123369ace90SXuhui Lin /* clear interrupts */ 124369ace90SXuhui Lin if (irq_status) 125369ace90SXuhui Lin writel(irq_status, priv->base + DECOM_ISR); 126369ace90SXuhui Lin 1275b7d3298SJason Zhu if (param->mode == DECOM_LZ4) 1282bb8d138SSimon Xue writel(LZ4_CONT_CSUM_CHECK_EN | 1292bb8d138SSimon Xue LZ4_HEAD_CSUM_CHECK_EN | 1302bb8d138SSimon Xue LZ4_BLOCK_CSUM_CHECK_EN | 131656bdb59SJoseph Chen DECOM_LZ4_MODE, 132656bdb59SJoseph Chen priv->base + DECOM_CTRL); 133656bdb59SJoseph Chen else if (param->mode == DECOM_GZIP) 1342bb8d138SSimon Xue writel(DECOM_DEFLATE_MODE | DECOM_GZIP_MODE, 1352bb8d138SSimon Xue priv->base + DECOM_CTRL); 136656bdb59SJoseph Chen else if (param->mode == DECOM_ZLIB) 1372bb8d138SSimon Xue writel(DECOM_DEFLATE_MODE | DECOM_ZLIB_MODE, 1382bb8d138SSimon Xue priv->base + DECOM_CTRL); 1392bb8d138SSimon Xue 1402bb8d138SSimon Xue writel(param->addr_src, priv->base + DECOM_RADDR); 1412bb8d138SSimon Xue writel(param->addr_dst, priv->base + DECOM_WADDR); 1422bb8d138SSimon Xue 143327380daSSimon Xue writel(limit_lo, priv->base + DECOM_LMTSL); 144327380daSSimon Xue writel(limit_hi, priv->base + DECOM_LMTSH); 145406de325SWeiwen Chen 146369ace90SXuhui Lin if (param->flags && DCOMP_FLG_IRQ_ONESHOT) 147369ace90SXuhui Lin writel(DECOM_INT_MASK, priv->base + DECOM_IEN); 1482bb8d138SSimon Xue writel(DECOM_ENABLE, priv->base + DECOM_ENR); 149656bdb59SJoseph Chen 150809af6baSJason Zhu priv->idle_check_once = true; 1512bb8d138SSimon Xue 1522bb8d138SSimon Xue return 0; 1532bb8d138SSimon Xue } 1542bb8d138SSimon Xue 1552bb8d138SSimon Xue static int rockchip_decom_stop(struct udevice *dev) 1562bb8d138SSimon Xue { 1572bb8d138SSimon Xue struct rockchip_decom_priv *priv = dev_get_priv(dev); 1582bb8d138SSimon Xue 1592bb8d138SSimon Xue writel(DECOM_DISABLE, priv->base + DECOM_ENR); 1602bb8d138SSimon Xue 1612bb8d138SSimon Xue return 0; 1622bb8d138SSimon Xue } 1632bb8d138SSimon Xue 1642bb8d138SSimon Xue /* Caller must call this function to check if decompress done */ 1652bb8d138SSimon Xue static int rockchip_decom_done_poll(struct udevice *dev) 1662bb8d138SSimon Xue { 1672bb8d138SSimon Xue struct rockchip_decom_priv *priv = dev_get_priv(dev); 1682bb8d138SSimon Xue 169809af6baSJason Zhu /* 170809af6baSJason Zhu * Test the decom is idle first time. 171809af6baSJason Zhu */ 172809af6baSJason Zhu if (!priv->idle_check_once) 173809af6baSJason Zhu return !(readl(priv->base + DECOM_AXI_STAT) & DECOM_AXI_IDLE); 1742bb8d138SSimon Xue 175809af6baSJason Zhu return !(readl(priv->base + DECOM_STAT) & DECOM_COMPLETE); 1762bb8d138SSimon Xue } 1772bb8d138SSimon Xue 178dc33c231SJoseph Chen static int rockchip_decom_capability(u32 *buf) 179cc05bcfaSJason Zhu { 180*04d08eceSSimon Xue *buf = DECOM_GZIP; 181*04d08eceSSimon Xue #ifndef CONFIG_ROCKCHIP_RK3576 182*04d08eceSSimon Xue *buf |= DECOM_LZ4; 183*04d08eceSSimon Xue #endif 184dc33c231SJoseph Chen return 0; 185cc05bcfaSJason Zhu } 186cc05bcfaSJason Zhu 187656bdb59SJoseph Chen static int rockchip_decom_data_size(struct udevice *dev, u64 *buf) 188656bdb59SJoseph Chen { 189656bdb59SJoseph Chen struct rockchip_decom_priv *priv = dev_get_priv(dev); 190656bdb59SJoseph Chen struct decom_param *param = (struct decom_param *)buf; 191656bdb59SJoseph Chen u32 sizel, sizeh; 192656bdb59SJoseph Chen 193656bdb59SJoseph Chen sizel = readl(priv->base + DECOM_TSIZEL); 194656bdb59SJoseph Chen sizeh = readl(priv->base + DECOM_TSIZEH); 195656bdb59SJoseph Chen param->size_dst = sizel | ((u64)sizeh << 32); 196656bdb59SJoseph Chen 197656bdb59SJoseph Chen return 0; 198656bdb59SJoseph Chen } 199656bdb59SJoseph Chen 200cc05bcfaSJason Zhu /* Caller must fill in param @buf which represent struct decom_param */ 2012bb8d138SSimon Xue static int rockchip_decom_ioctl(struct udevice *dev, unsigned long request, 2022bb8d138SSimon Xue void *buf) 2032bb8d138SSimon Xue { 2042bb8d138SSimon Xue int ret = -EINVAL; 2052bb8d138SSimon Xue 2062bb8d138SSimon Xue switch (request) { 2072bb8d138SSimon Xue case IOCTL_REQ_START: 2082bb8d138SSimon Xue ret = rockchip_decom_start(dev, buf); 2092bb8d138SSimon Xue break; 2102bb8d138SSimon Xue case IOCTL_REQ_POLL: 2112bb8d138SSimon Xue ret = rockchip_decom_done_poll(dev); 2122bb8d138SSimon Xue break; 2132bb8d138SSimon Xue case IOCTL_REQ_STOP: 2142bb8d138SSimon Xue ret = rockchip_decom_stop(dev); 2152bb8d138SSimon Xue break; 216cc05bcfaSJason Zhu case IOCTL_REQ_CAPABILITY: 217dc33c231SJoseph Chen ret = rockchip_decom_capability(buf); 218809af6baSJason Zhu break; 219656bdb59SJoseph Chen case IOCTL_REQ_DATA_SIZE: 220656bdb59SJoseph Chen ret = rockchip_decom_data_size(dev, buf); 221656bdb59SJoseph Chen break; 222656bdb59SJoseph Chen default: 223656bdb59SJoseph Chen printf("Unsupported ioctl: %ld\n", (ulong)request); 224656bdb59SJoseph Chen break; 2252bb8d138SSimon Xue } 2262bb8d138SSimon Xue 2272bb8d138SSimon Xue return ret; 2282bb8d138SSimon Xue } 2292bb8d138SSimon Xue 2302bb8d138SSimon Xue static const struct misc_ops rockchip_decom_ops = { 2312bb8d138SSimon Xue .ioctl = rockchip_decom_ioctl, 2322bb8d138SSimon Xue }; 2332bb8d138SSimon Xue 2342bb8d138SSimon Xue static int rockchip_decom_ofdata_to_platdata(struct udevice *dev) 2352bb8d138SSimon Xue { 2362bb8d138SSimon Xue struct rockchip_decom_priv *priv = dev_get_priv(dev); 2372bb8d138SSimon Xue 2382bb8d138SSimon Xue priv->base = dev_read_addr_ptr(dev); 2392bb8d138SSimon Xue if (!priv->base) 2402bb8d138SSimon Xue return -ENOENT; 2412bb8d138SSimon Xue 2428b225c61SJoseph Chen priv->cached = dev_read_u32_default(dev, "data-cached", 0); 2431540ca37SSimon Xue 2442bb8d138SSimon Xue return 0; 2452bb8d138SSimon Xue } 2462bb8d138SSimon Xue 2472bb8d138SSimon Xue static int rockchip_decom_probe(struct udevice *dev) 2482bb8d138SSimon Xue { 249b367c66bSJoseph Chen struct rockchip_decom_priv *priv = dev_get_priv(dev); 250b367c66bSJoseph Chen int ret; 251b367c66bSJoseph Chen 252d416248eSJoseph Chen #if CONFIG_IS_ENABLED(DM_RESET) 253b367c66bSJoseph Chen ret = reset_get_by_name(dev, "dresetn", &priv->rst); 254b367c66bSJoseph Chen if (ret) { 255b367c66bSJoseph Chen debug("reset_get_by_name() failed: %d\n", ret); 256b367c66bSJoseph Chen return ret; 257b367c66bSJoseph Chen } 258b367c66bSJoseph Chen #endif 2595db33a71SSimon Xue 26041f62ac5SJason Zhu ret = clk_get_by_index(dev, 1, &priv->dclk); 2615db33a71SSimon Xue if (ret < 0) 2625db33a71SSimon Xue return ret; 2635db33a71SSimon Xue 2645db33a71SSimon Xue ret = clk_set_rate(&priv->dclk, DCLK_DECOM); 2655db33a71SSimon Xue if (ret < 0) 2665db33a71SSimon Xue return ret; 2675db33a71SSimon Xue 2682bb8d138SSimon Xue return 0; 2692bb8d138SSimon Xue } 2702bb8d138SSimon Xue 2712bb8d138SSimon Xue static const struct udevice_id rockchip_decom_ids[] = { 2722bb8d138SSimon Xue { .compatible = "rockchip,hw-decompress" }, 2732bb8d138SSimon Xue {} 2742bb8d138SSimon Xue }; 2752bb8d138SSimon Xue 2762bb8d138SSimon Xue U_BOOT_DRIVER(rockchip_hw_decompress) = { 2772bb8d138SSimon Xue .name = "rockchip_hw_decompress", 2782bb8d138SSimon Xue .id = UCLASS_MISC, 2792bb8d138SSimon Xue .of_match = rockchip_decom_ids, 2802bb8d138SSimon Xue .probe = rockchip_decom_probe, 2812bb8d138SSimon Xue .ofdata_to_platdata = rockchip_decom_ofdata_to_platdata, 2822bb8d138SSimon Xue .priv_auto_alloc_size = sizeof(struct rockchip_decom_priv), 2832bb8d138SSimon Xue .ops = &rockchip_decom_ops, 2842bb8d138SSimon Xue }; 285