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