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
rockchip_decom_start(struct udevice * dev,void * buf)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
103*1bd990deSSimon Xue /* Increase limit_size by 16 to avoid premature decompression termination by decom */
104*1bd990deSSimon Xue limit_lo += 16;
105*1bd990deSSimon Xue
106b367c66bSJoseph Chen #if CONFIG_IS_ENABLED(DM_RESET)
107b367c66bSJoseph Chen reset_assert(&priv->rst);
108b367c66bSJoseph Chen udelay(10);
109b367c66bSJoseph Chen reset_deassert(&priv->rst);
110b367c66bSJoseph Chen #endif
111c9f753f3SJoseph Chen /*
112c9f753f3SJoseph Chen * Purpose:
113c9f753f3SJoseph Chen * src: clean dcache to get the real compressed data from ddr.
114c9f753f3SJoseph Chen * dst: invalidate dcache.
115c9f753f3SJoseph Chen *
116c9f753f3SJoseph Chen * flush_dcache_all() operating on set/way is faster than
117c9f753f3SJoseph Chen * flush_cache() and invalidate_dcache_range() operating
118c9f753f3SJoseph Chen * on virtual address.
119c9f753f3SJoseph Chen */
120c9f753f3SJoseph Chen if (!priv->cached)
121c9f753f3SJoseph Chen flush_dcache_all();
1222bb8d138SSimon Xue
1232bb8d138SSimon Xue priv->done = false;
1242bb8d138SSimon Xue
125369ace90SXuhui Lin irq_status = readl(priv->base + DECOM_ISR);
126369ace90SXuhui Lin /* clear interrupts */
127369ace90SXuhui Lin if (irq_status)
128369ace90SXuhui Lin writel(irq_status, priv->base + DECOM_ISR);
129369ace90SXuhui Lin
1305b7d3298SJason Zhu if (param->mode == DECOM_LZ4)
1312bb8d138SSimon Xue writel(LZ4_CONT_CSUM_CHECK_EN |
1322bb8d138SSimon Xue LZ4_HEAD_CSUM_CHECK_EN |
1332bb8d138SSimon Xue LZ4_BLOCK_CSUM_CHECK_EN |
134656bdb59SJoseph Chen DECOM_LZ4_MODE,
135656bdb59SJoseph Chen priv->base + DECOM_CTRL);
136656bdb59SJoseph Chen else if (param->mode == DECOM_GZIP)
1372bb8d138SSimon Xue writel(DECOM_DEFLATE_MODE | DECOM_GZIP_MODE,
1382bb8d138SSimon Xue priv->base + DECOM_CTRL);
139656bdb59SJoseph Chen else if (param->mode == DECOM_ZLIB)
1402bb8d138SSimon Xue writel(DECOM_DEFLATE_MODE | DECOM_ZLIB_MODE,
1412bb8d138SSimon Xue priv->base + DECOM_CTRL);
1422bb8d138SSimon Xue
1432bb8d138SSimon Xue writel(param->addr_src, priv->base + DECOM_RADDR);
1442bb8d138SSimon Xue writel(param->addr_dst, priv->base + DECOM_WADDR);
1452bb8d138SSimon Xue
146327380daSSimon Xue writel(limit_lo, priv->base + DECOM_LMTSL);
147327380daSSimon Xue writel(limit_hi, priv->base + DECOM_LMTSH);
148406de325SWeiwen Chen
149369ace90SXuhui Lin if (param->flags && DCOMP_FLG_IRQ_ONESHOT)
150369ace90SXuhui Lin writel(DECOM_INT_MASK, priv->base + DECOM_IEN);
1512bb8d138SSimon Xue writel(DECOM_ENABLE, priv->base + DECOM_ENR);
152656bdb59SJoseph Chen
153809af6baSJason Zhu priv->idle_check_once = true;
1542bb8d138SSimon Xue
1552bb8d138SSimon Xue return 0;
1562bb8d138SSimon Xue }
1572bb8d138SSimon Xue
rockchip_decom_stop(struct udevice * dev)1582bb8d138SSimon Xue static int rockchip_decom_stop(struct udevice *dev)
1592bb8d138SSimon Xue {
1602bb8d138SSimon Xue struct rockchip_decom_priv *priv = dev_get_priv(dev);
1612bb8d138SSimon Xue
1622bb8d138SSimon Xue writel(DECOM_DISABLE, priv->base + DECOM_ENR);
1632bb8d138SSimon Xue
1642bb8d138SSimon Xue return 0;
1652bb8d138SSimon Xue }
1662bb8d138SSimon Xue
1672bb8d138SSimon Xue /* Caller must call this function to check if decompress done */
rockchip_decom_done_poll(struct udevice * dev)1682bb8d138SSimon Xue static int rockchip_decom_done_poll(struct udevice *dev)
1692bb8d138SSimon Xue {
1702bb8d138SSimon Xue struct rockchip_decom_priv *priv = dev_get_priv(dev);
1712bb8d138SSimon Xue
172809af6baSJason Zhu /*
173809af6baSJason Zhu * Test the decom is idle first time.
174809af6baSJason Zhu */
175809af6baSJason Zhu if (!priv->idle_check_once)
176809af6baSJason Zhu return !(readl(priv->base + DECOM_AXI_STAT) & DECOM_AXI_IDLE);
1772bb8d138SSimon Xue
178809af6baSJason Zhu return !(readl(priv->base + DECOM_STAT) & DECOM_COMPLETE);
1792bb8d138SSimon Xue }
1802bb8d138SSimon Xue
rockchip_decom_capability(u32 * buf)181dc33c231SJoseph Chen static int rockchip_decom_capability(u32 *buf)
182cc05bcfaSJason Zhu {
18304d08eceSSimon Xue *buf = DECOM_GZIP;
1847163e0a1SXuhui Lin #if !defined(CONFIG_ROCKCHIP_RK3576) && !defined(CONFIG_ROCKCHIP_RV1103B) && \
1857163e0a1SXuhui Lin !defined(CONFIG_ROCKCHIP_RV1126B)
18604d08eceSSimon Xue *buf |= DECOM_LZ4;
18704d08eceSSimon Xue #endif
188dc33c231SJoseph Chen return 0;
189cc05bcfaSJason Zhu }
190cc05bcfaSJason Zhu
rockchip_decom_data_size(struct udevice * dev,u64 * buf)191656bdb59SJoseph Chen static int rockchip_decom_data_size(struct udevice *dev, u64 *buf)
192656bdb59SJoseph Chen {
193656bdb59SJoseph Chen struct rockchip_decom_priv *priv = dev_get_priv(dev);
194656bdb59SJoseph Chen struct decom_param *param = (struct decom_param *)buf;
195656bdb59SJoseph Chen u32 sizel, sizeh;
196656bdb59SJoseph Chen
197656bdb59SJoseph Chen sizel = readl(priv->base + DECOM_TSIZEL);
198656bdb59SJoseph Chen sizeh = readl(priv->base + DECOM_TSIZEH);
199656bdb59SJoseph Chen param->size_dst = sizel | ((u64)sizeh << 32);
200656bdb59SJoseph Chen
201656bdb59SJoseph Chen return 0;
202656bdb59SJoseph Chen }
203656bdb59SJoseph Chen
204cc05bcfaSJason Zhu /* Caller must fill in param @buf which represent struct decom_param */
rockchip_decom_ioctl(struct udevice * dev,unsigned long request,void * buf)2052bb8d138SSimon Xue static int rockchip_decom_ioctl(struct udevice *dev, unsigned long request,
2062bb8d138SSimon Xue void *buf)
2072bb8d138SSimon Xue {
2082bb8d138SSimon Xue int ret = -EINVAL;
2092bb8d138SSimon Xue
2102bb8d138SSimon Xue switch (request) {
2112bb8d138SSimon Xue case IOCTL_REQ_START:
2122bb8d138SSimon Xue ret = rockchip_decom_start(dev, buf);
2132bb8d138SSimon Xue break;
2142bb8d138SSimon Xue case IOCTL_REQ_POLL:
2152bb8d138SSimon Xue ret = rockchip_decom_done_poll(dev);
2162bb8d138SSimon Xue break;
2172bb8d138SSimon Xue case IOCTL_REQ_STOP:
2182bb8d138SSimon Xue ret = rockchip_decom_stop(dev);
2192bb8d138SSimon Xue break;
220cc05bcfaSJason Zhu case IOCTL_REQ_CAPABILITY:
221dc33c231SJoseph Chen ret = rockchip_decom_capability(buf);
222809af6baSJason Zhu break;
223656bdb59SJoseph Chen case IOCTL_REQ_DATA_SIZE:
224656bdb59SJoseph Chen ret = rockchip_decom_data_size(dev, buf);
225656bdb59SJoseph Chen break;
226656bdb59SJoseph Chen default:
227656bdb59SJoseph Chen printf("Unsupported ioctl: %ld\n", (ulong)request);
228656bdb59SJoseph Chen break;
2292bb8d138SSimon Xue }
2302bb8d138SSimon Xue
2312bb8d138SSimon Xue return ret;
2322bb8d138SSimon Xue }
2332bb8d138SSimon Xue
2342bb8d138SSimon Xue static const struct misc_ops rockchip_decom_ops = {
2352bb8d138SSimon Xue .ioctl = rockchip_decom_ioctl,
2362bb8d138SSimon Xue };
2372bb8d138SSimon Xue
rockchip_decom_ofdata_to_platdata(struct udevice * dev)2382bb8d138SSimon Xue static int rockchip_decom_ofdata_to_platdata(struct udevice *dev)
2392bb8d138SSimon Xue {
2402bb8d138SSimon Xue struct rockchip_decom_priv *priv = dev_get_priv(dev);
2412bb8d138SSimon Xue
2422bb8d138SSimon Xue priv->base = dev_read_addr_ptr(dev);
2432bb8d138SSimon Xue if (!priv->base)
2442bb8d138SSimon Xue return -ENOENT;
2452bb8d138SSimon Xue
2468b225c61SJoseph Chen priv->cached = dev_read_u32_default(dev, "data-cached", 0);
2471540ca37SSimon Xue
2482bb8d138SSimon Xue return 0;
2492bb8d138SSimon Xue }
2502bb8d138SSimon Xue
rockchip_decom_probe(struct udevice * dev)2512bb8d138SSimon Xue static int rockchip_decom_probe(struct udevice *dev)
2522bb8d138SSimon Xue {
253b367c66bSJoseph Chen struct rockchip_decom_priv *priv = dev_get_priv(dev);
254b367c66bSJoseph Chen int ret;
255b367c66bSJoseph Chen
256d416248eSJoseph Chen #if CONFIG_IS_ENABLED(DM_RESET)
257b367c66bSJoseph Chen ret = reset_get_by_name(dev, "dresetn", &priv->rst);
258b367c66bSJoseph Chen if (ret) {
259b367c66bSJoseph Chen debug("reset_get_by_name() failed: %d\n", ret);
260b367c66bSJoseph Chen return ret;
261b367c66bSJoseph Chen }
262b367c66bSJoseph Chen #endif
2635db33a71SSimon Xue
26441f62ac5SJason Zhu ret = clk_get_by_index(dev, 1, &priv->dclk);
2655db33a71SSimon Xue if (ret < 0)
2665db33a71SSimon Xue return ret;
2675db33a71SSimon Xue
2685db33a71SSimon Xue ret = clk_set_rate(&priv->dclk, DCLK_DECOM);
2695db33a71SSimon Xue if (ret < 0)
2705db33a71SSimon Xue return ret;
2715db33a71SSimon Xue
2722bb8d138SSimon Xue return 0;
2732bb8d138SSimon Xue }
2742bb8d138SSimon Xue
2752bb8d138SSimon Xue static const struct udevice_id rockchip_decom_ids[] = {
2762bb8d138SSimon Xue { .compatible = "rockchip,hw-decompress" },
2772bb8d138SSimon Xue {}
2782bb8d138SSimon Xue };
2792bb8d138SSimon Xue
2802bb8d138SSimon Xue U_BOOT_DRIVER(rockchip_hw_decompress) = {
2812bb8d138SSimon Xue .name = "rockchip_hw_decompress",
2822bb8d138SSimon Xue .id = UCLASS_MISC,
2832bb8d138SSimon Xue .of_match = rockchip_decom_ids,
2842bb8d138SSimon Xue .probe = rockchip_decom_probe,
2852bb8d138SSimon Xue .ofdata_to_platdata = rockchip_decom_ofdata_to_platdata,
2862bb8d138SSimon Xue .priv_auto_alloc_size = sizeof(struct rockchip_decom_priv),
2872bb8d138SSimon Xue .ops = &rockchip_decom_ops,
2882bb8d138SSimon Xue };
289