xref: /rk3399_rockchip-uboot/drivers/misc/rockchip_decompress.c (revision 1bd990de87631a61539b6e72bee3d3fdcd2799cd)
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