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> 72bb8d138SSimon Xue #include <dm.h> 82bb8d138SSimon Xue #include <linux/bitops.h> 92bb8d138SSimon Xue #include <misc.h> 102bb8d138SSimon Xue #include <irq-generic.h> 112bb8d138SSimon Xue 122bb8d138SSimon Xue DECLARE_GLOBAL_DATA_PTR; 132bb8d138SSimon Xue 142bb8d138SSimon Xue #define DECOM_CTRL 0x0 152bb8d138SSimon Xue #define DECOM_ENR 0x4 162bb8d138SSimon Xue #define DECOM_RADDR 0x8 172bb8d138SSimon Xue #define DECOM_WADDR 0xc 182bb8d138SSimon Xue #define DECOM_UDDSL 0x10 192bb8d138SSimon Xue #define DECOM_UDDSH 0x14 202bb8d138SSimon Xue #define DECOM_TXTHR 0x18 212bb8d138SSimon Xue #define DECOM_RXTHR 0x1c 222bb8d138SSimon Xue #define DECOM_SLEN 0x20 232bb8d138SSimon Xue #define DECOM_STAT 0x24 242bb8d138SSimon Xue #define DECOM_ISR 0x28 252bb8d138SSimon Xue #define DECOM_IEN 0x2c 262bb8d138SSimon Xue #define DECOM_AXI_STAT 0x30 272bb8d138SSimon Xue #define DECOM_TSIZEL 0x34 282bb8d138SSimon Xue #define DECOM_TSIZEH 0x38 292bb8d138SSimon Xue #define DECOM_MGNUM 0x3c 302bb8d138SSimon Xue #define DECOM_FRAME 0x40 312bb8d138SSimon Xue #define DECOM_DICTID 0x44 322bb8d138SSimon Xue #define DECOM_CSL 0x48 332bb8d138SSimon Xue #define DECOM_CSH 0x4c 34327380daSSimon Xue #define DECOM_LMTSL 0x50 35327380daSSimon Xue #define DECOM_LMTSH 0x54 362bb8d138SSimon Xue 372bb8d138SSimon Xue #define LZ4_HEAD_CSUM_CHECK_EN BIT(1) 382bb8d138SSimon Xue #define LZ4_BLOCK_CSUM_CHECK_EN BIT(2) 392bb8d138SSimon Xue #define LZ4_CONT_CSUM_CHECK_EN BIT(3) 402bb8d138SSimon Xue 412bb8d138SSimon Xue #define DSOLIEN BIT(19) 422bb8d138SSimon Xue #define ZDICTEIEN BIT(18) 432bb8d138SSimon Xue #define GCMEIEN BIT(17) 442bb8d138SSimon Xue #define GIDEIEN BIT(16) 452bb8d138SSimon Xue #define CCCEIEN BIT(15) 462bb8d138SSimon Xue #define BCCEIEN BIT(14) 472bb8d138SSimon Xue #define HCCEIEN BIT(13) 482bb8d138SSimon Xue #define CSEIEN BIT(12) 492bb8d138SSimon Xue #define DICTEIEN BIT(11) 502bb8d138SSimon Xue #define VNEIEN BIT(10) 512bb8d138SSimon Xue #define WNEIEN BIT(9) 522bb8d138SSimon Xue #define RDCEIEN BIT(8) 532bb8d138SSimon Xue #define WRCEIEN BIT(7) 542bb8d138SSimon Xue #define DISEIEN BIT(6) 552bb8d138SSimon Xue #define LENEIEN BIT(5) 562bb8d138SSimon Xue #define LITEIEN BIT(4) 572bb8d138SSimon Xue #define SQMEIEN BIT(3) 582bb8d138SSimon Xue #define SLCIEN BIT(2) 592bb8d138SSimon Xue #define HDEIEN BIT(1) 602bb8d138SSimon Xue #define DSIEN BIT(0) 612bb8d138SSimon Xue 622bb8d138SSimon Xue #define DECOM_STOP BIT(0) 632bb8d138SSimon Xue #define DECOM_COMPLETE BIT(0) 642bb8d138SSimon Xue #define DECOM_GZIP_MODE BIT(4) 652bb8d138SSimon Xue #define DECOM_ZLIB_MODE BIT(5) 662bb8d138SSimon Xue #define DECOM_DEFLATE_MODE BIT(0) 67*809af6baSJason Zhu #define DECOM_AXI_IDLE BIT(4) 685b7d3298SJason Zhu #define DECOM_LZ4_MODE 0 692bb8d138SSimon Xue 702bb8d138SSimon Xue #define DECOM_ENABLE 0x1 712bb8d138SSimon Xue #define DECOM_DISABLE 0x0 722bb8d138SSimon Xue 732bb8d138SSimon Xue #define DECOM_IRQ 0xffff /* fixme */ 742bb8d138SSimon Xue 752bb8d138SSimon Xue #define DECOM_INT_MASK \ 762bb8d138SSimon Xue (DSOLIEN | ZDICTEIEN | GCMEIEN | GIDEIEN | \ 772bb8d138SSimon Xue CCCEIEN | BCCEIEN | HCCEIEN | CSEIEN | \ 782bb8d138SSimon Xue DICTEIEN | VNEIEN | WNEIEN | RDCEIEN | WRCEIEN | \ 792bb8d138SSimon Xue DISEIEN | LENEIEN | LITEIEN | SQMEIEN | SLCIEN | \ 802bb8d138SSimon Xue HDEIEN | DSIEN) 812bb8d138SSimon Xue 822bb8d138SSimon Xue struct rockchip_decom_priv { 832bb8d138SSimon Xue void __iomem *base; 841540ca37SSimon Xue unsigned long soft_reset_base; 85*809af6baSJason Zhu bool idle_check_once; 862bb8d138SSimon Xue bool done; 872bb8d138SSimon Xue }; 882bb8d138SSimon Xue 892bb8d138SSimon Xue static int rockchip_decom_start(struct udevice *dev, void *buf) 902bb8d138SSimon Xue { 912bb8d138SSimon Xue struct rockchip_decom_priv *priv = dev_get_priv(dev); 92cc05bcfaSJason Zhu struct decom_param *param = (struct decom_param *)buf; 933cafcfcdSSimon Xue unsigned int limit_lo = param->size & 0xffffffff; 943cafcfcdSSimon Xue unsigned int limit_hi = param->size >> 32; 952bb8d138SSimon Xue 962bb8d138SSimon Xue priv->done = false; 972bb8d138SSimon Xue 981540ca37SSimon Xue writel(0x00800080, priv->soft_reset_base); 991540ca37SSimon Xue writel(0x00800000, priv->soft_reset_base); 1001540ca37SSimon Xue 1015b7d3298SJason Zhu if (param->mode == DECOM_LZ4) 1022bb8d138SSimon Xue writel(LZ4_CONT_CSUM_CHECK_EN | 1032bb8d138SSimon Xue LZ4_HEAD_CSUM_CHECK_EN | 1042bb8d138SSimon Xue LZ4_BLOCK_CSUM_CHECK_EN | 1055b7d3298SJason Zhu DECOM_LZ4_MODE, priv->base + DECOM_CTRL); 1062bb8d138SSimon Xue 1075b7d3298SJason Zhu if (param->mode == DECOM_GZIP) 1082bb8d138SSimon Xue writel(DECOM_DEFLATE_MODE | DECOM_GZIP_MODE, 1092bb8d138SSimon Xue priv->base + DECOM_CTRL); 1102bb8d138SSimon Xue 1115b7d3298SJason Zhu if (param->mode == DECOM_ZLIB) 1122bb8d138SSimon Xue writel(DECOM_DEFLATE_MODE | DECOM_ZLIB_MODE, 1132bb8d138SSimon Xue priv->base + DECOM_CTRL); 1142bb8d138SSimon Xue 1152bb8d138SSimon Xue writel(param->addr_src, priv->base + DECOM_RADDR); 1162bb8d138SSimon Xue writel(param->addr_dst, priv->base + DECOM_WADDR); 1172bb8d138SSimon Xue 118327380daSSimon Xue writel(limit_lo, priv->base + DECOM_LMTSL); 119327380daSSimon Xue writel(limit_hi, priv->base + DECOM_LMTSH); 120327380daSSimon Xue 1212bb8d138SSimon Xue writel(DECOM_INT_MASK, priv->base + DECOM_IEN); 1222bb8d138SSimon Xue writel(DECOM_ENABLE, priv->base + DECOM_ENR); 123*809af6baSJason Zhu priv->idle_check_once = true; 1242bb8d138SSimon Xue 1252bb8d138SSimon Xue return 0; 1262bb8d138SSimon Xue } 1272bb8d138SSimon Xue 1282bb8d138SSimon Xue static int rockchip_decom_stop(struct udevice *dev) 1292bb8d138SSimon Xue { 1302bb8d138SSimon Xue struct rockchip_decom_priv *priv = dev_get_priv(dev); 1312bb8d138SSimon Xue int irq_status; 1322bb8d138SSimon Xue 1332bb8d138SSimon Xue irq_status = readl(priv->base + DECOM_ISR); 1342bb8d138SSimon Xue /* clear interrupts */ 1352bb8d138SSimon Xue if (irq_status) 1362bb8d138SSimon Xue writel(irq_status, priv->base + DECOM_ISR); 1372bb8d138SSimon Xue 1382bb8d138SSimon Xue writel(DECOM_DISABLE, priv->base + DECOM_ENR); 1392bb8d138SSimon Xue 1402bb8d138SSimon Xue return 0; 1412bb8d138SSimon Xue } 1422bb8d138SSimon Xue 1432bb8d138SSimon Xue /* Caller must call this function to check if decompress done */ 1442bb8d138SSimon Xue static int rockchip_decom_done_poll(struct udevice *dev) 1452bb8d138SSimon Xue { 1462bb8d138SSimon Xue struct rockchip_decom_priv *priv = dev_get_priv(dev); 1472bb8d138SSimon Xue 148*809af6baSJason Zhu /* 149*809af6baSJason Zhu * Test the decom is idle first time. 150*809af6baSJason Zhu */ 151*809af6baSJason Zhu if (!priv->idle_check_once) 152*809af6baSJason Zhu return !(readl(priv->base + DECOM_AXI_STAT) & DECOM_AXI_IDLE); 1532bb8d138SSimon Xue 154*809af6baSJason Zhu return !(readl(priv->base + DECOM_STAT) & DECOM_COMPLETE); 1552bb8d138SSimon Xue } 1562bb8d138SSimon Xue 157dc33c231SJoseph Chen static int rockchip_decom_capability(u32 *buf) 158cc05bcfaSJason Zhu { 159dc33c231SJoseph Chen *buf = DECOM_GZIP; 160dc33c231SJoseph Chen 161dc33c231SJoseph Chen return 0; 162cc05bcfaSJason Zhu } 163cc05bcfaSJason Zhu 164cc05bcfaSJason Zhu /* Caller must fill in param @buf which represent struct decom_param */ 1652bb8d138SSimon Xue static int rockchip_decom_ioctl(struct udevice *dev, unsigned long request, 1662bb8d138SSimon Xue void *buf) 1672bb8d138SSimon Xue { 1682bb8d138SSimon Xue int ret = -EINVAL; 1692bb8d138SSimon Xue 1702bb8d138SSimon Xue switch (request) { 1712bb8d138SSimon Xue case IOCTL_REQ_START: 1722bb8d138SSimon Xue ret = rockchip_decom_start(dev, buf); 1732bb8d138SSimon Xue break; 1742bb8d138SSimon Xue case IOCTL_REQ_POLL: 1752bb8d138SSimon Xue ret = rockchip_decom_done_poll(dev); 1762bb8d138SSimon Xue break; 1772bb8d138SSimon Xue case IOCTL_REQ_STOP: 1782bb8d138SSimon Xue ret = rockchip_decom_stop(dev); 1792bb8d138SSimon Xue break; 180cc05bcfaSJason Zhu case IOCTL_REQ_CAPABILITY: 181dc33c231SJoseph Chen ret = rockchip_decom_capability(buf); 182*809af6baSJason Zhu break; 1832bb8d138SSimon Xue } 1842bb8d138SSimon Xue 1852bb8d138SSimon Xue return ret; 1862bb8d138SSimon Xue } 1872bb8d138SSimon Xue 1882bb8d138SSimon Xue static const struct misc_ops rockchip_decom_ops = { 1892bb8d138SSimon Xue .ioctl = rockchip_decom_ioctl, 1902bb8d138SSimon Xue }; 1912bb8d138SSimon Xue 1922bb8d138SSimon Xue static int rockchip_decom_ofdata_to_platdata(struct udevice *dev) 1932bb8d138SSimon Xue { 1942bb8d138SSimon Xue struct rockchip_decom_priv *priv = dev_get_priv(dev); 1952bb8d138SSimon Xue 1962bb8d138SSimon Xue priv->base = dev_read_addr_ptr(dev); 1972bb8d138SSimon Xue if (!priv->base) 1982bb8d138SSimon Xue return -ENOENT; 1992bb8d138SSimon Xue 2001540ca37SSimon Xue priv->soft_reset_base = dev_read_u32_default(dev, "soft-reset-addr", 0) 2011540ca37SSimon Xue & 0xffffffff; 2021540ca37SSimon Xue 2032bb8d138SSimon Xue return 0; 2042bb8d138SSimon Xue } 2052bb8d138SSimon Xue 2062bb8d138SSimon Xue #ifndef CONFIG_SPL_BUILD 2072bb8d138SSimon Xue static void rockchip_decom_irqhandler(int irq, void *data) 2082bb8d138SSimon Xue { 2092bb8d138SSimon Xue struct udevice *dev = data; 2102bb8d138SSimon Xue struct rockchip_decom_priv *priv = dev_get_priv(dev); 2112bb8d138SSimon Xue int irq_status; 2122bb8d138SSimon Xue int decom_status; 2132bb8d138SSimon Xue 2142bb8d138SSimon Xue irq_status = readl(priv->base + DECOM_ISR); 2152bb8d138SSimon Xue /* clear interrupts */ 2162bb8d138SSimon Xue writel(irq_status, priv->base + DECOM_ISR); 2172bb8d138SSimon Xue if (irq_status & DECOM_STOP) { 2182bb8d138SSimon Xue decom_status = readl(priv->base + DECOM_STAT); 2192bb8d138SSimon Xue if (decom_status & DECOM_COMPLETE) { 2202bb8d138SSimon Xue priv->done = true; 2212bb8d138SSimon Xue /* 2222bb8d138SSimon Xue * TODO: 2232bb8d138SSimon Xue * Inform someone that decompress completed 2242bb8d138SSimon Xue */ 2252bb8d138SSimon Xue printf("decom completed\n"); 2262bb8d138SSimon Xue } else { 2272bb8d138SSimon Xue printf("decom failed, irq_status = 0x%x, decom_status = 0x%x\n", 2282bb8d138SSimon Xue irq_status, decom_status); 2292bb8d138SSimon Xue } 2302bb8d138SSimon Xue } 2312bb8d138SSimon Xue } 2322bb8d138SSimon Xue #endif 2332bb8d138SSimon Xue 2342bb8d138SSimon Xue static int rockchip_decom_probe(struct udevice *dev) 2352bb8d138SSimon Xue { 2362bb8d138SSimon Xue #ifndef CONFIG_SPL_BUILD 2372bb8d138SSimon Xue irq_install_handler(DECOM_IRQ, rockchip_decom_irqhandler, dev); 2382bb8d138SSimon Xue irq_handler_enable(DECOM_IRQ); 2392bb8d138SSimon Xue #endif 2402bb8d138SSimon Xue return 0; 2412bb8d138SSimon Xue } 2422bb8d138SSimon Xue 2432bb8d138SSimon Xue static const struct udevice_id rockchip_decom_ids[] = { 2442bb8d138SSimon Xue { .compatible = "rockchip,hw-decompress" }, 2452bb8d138SSimon Xue {} 2462bb8d138SSimon Xue }; 2472bb8d138SSimon Xue 2482bb8d138SSimon Xue U_BOOT_DRIVER(rockchip_hw_decompress) = { 2492bb8d138SSimon Xue .name = "rockchip_hw_decompress", 2502bb8d138SSimon Xue .id = UCLASS_MISC, 2512bb8d138SSimon Xue .of_match = rockchip_decom_ids, 2522bb8d138SSimon Xue .probe = rockchip_decom_probe, 2532bb8d138SSimon Xue .ofdata_to_platdata = rockchip_decom_ofdata_to_platdata, 2542bb8d138SSimon Xue .priv_auto_alloc_size = sizeof(struct rockchip_decom_priv), 2552bb8d138SSimon Xue .ops = &rockchip_decom_ops, 2562bb8d138SSimon Xue }; 257