xref: /rk3399_rockchip-uboot/drivers/misc/rockchip_decompress.c (revision b367c66bb3cd834baab78d47a264ba044293e8dc)
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>
11*b367c66bSJoseph Chen #include <reset.h>
122bb8d138SSimon Xue 
132bb8d138SSimon Xue DECLARE_GLOBAL_DATA_PTR;
142bb8d138SSimon Xue 
152bb8d138SSimon Xue #define DECOM_CTRL		0x0
162bb8d138SSimon Xue #define DECOM_ENR		0x4
172bb8d138SSimon Xue #define DECOM_RADDR		0x8
182bb8d138SSimon Xue #define DECOM_WADDR		0xc
192bb8d138SSimon Xue #define DECOM_UDDSL		0x10
202bb8d138SSimon Xue #define DECOM_UDDSH		0x14
212bb8d138SSimon Xue #define DECOM_TXTHR		0x18
222bb8d138SSimon Xue #define DECOM_RXTHR		0x1c
232bb8d138SSimon Xue #define DECOM_SLEN		0x20
242bb8d138SSimon Xue #define DECOM_STAT		0x24
252bb8d138SSimon Xue #define DECOM_ISR		0x28
262bb8d138SSimon Xue #define DECOM_IEN		0x2c
272bb8d138SSimon Xue #define DECOM_AXI_STAT		0x30
282bb8d138SSimon Xue #define DECOM_TSIZEL		0x34
292bb8d138SSimon Xue #define DECOM_TSIZEH		0x38
302bb8d138SSimon Xue #define DECOM_MGNUM		0x3c
312bb8d138SSimon Xue #define DECOM_FRAME		0x40
322bb8d138SSimon Xue #define DECOM_DICTID		0x44
332bb8d138SSimon Xue #define DECOM_CSL		0x48
342bb8d138SSimon Xue #define DECOM_CSH		0x4c
35327380daSSimon Xue #define DECOM_LMTSL             0x50
36327380daSSimon Xue #define DECOM_LMTSH             0x54
372bb8d138SSimon Xue 
382bb8d138SSimon Xue #define LZ4_HEAD_CSUM_CHECK_EN	BIT(1)
392bb8d138SSimon Xue #define LZ4_BLOCK_CSUM_CHECK_EN	BIT(2)
402bb8d138SSimon Xue #define LZ4_CONT_CSUM_CHECK_EN	BIT(3)
412bb8d138SSimon Xue 
422bb8d138SSimon Xue #define DSOLIEN			BIT(19)
432bb8d138SSimon Xue #define ZDICTEIEN		BIT(18)
442bb8d138SSimon Xue #define GCMEIEN			BIT(17)
452bb8d138SSimon Xue #define GIDEIEN			BIT(16)
462bb8d138SSimon Xue #define CCCEIEN			BIT(15)
472bb8d138SSimon Xue #define BCCEIEN			BIT(14)
482bb8d138SSimon Xue #define HCCEIEN			BIT(13)
492bb8d138SSimon Xue #define CSEIEN			BIT(12)
502bb8d138SSimon Xue #define DICTEIEN		BIT(11)
512bb8d138SSimon Xue #define VNEIEN			BIT(10)
522bb8d138SSimon Xue #define WNEIEN			BIT(9)
532bb8d138SSimon Xue #define RDCEIEN			BIT(8)
542bb8d138SSimon Xue #define WRCEIEN			BIT(7)
552bb8d138SSimon Xue #define DISEIEN			BIT(6)
562bb8d138SSimon Xue #define LENEIEN			BIT(5)
572bb8d138SSimon Xue #define LITEIEN			BIT(4)
582bb8d138SSimon Xue #define SQMEIEN			BIT(3)
592bb8d138SSimon Xue #define SLCIEN			BIT(2)
602bb8d138SSimon Xue #define HDEIEN			BIT(1)
612bb8d138SSimon Xue #define DSIEN			BIT(0)
622bb8d138SSimon Xue 
632bb8d138SSimon Xue #define DECOM_STOP		BIT(0)
642bb8d138SSimon Xue #define DECOM_COMPLETE		BIT(0)
652bb8d138SSimon Xue #define DECOM_GZIP_MODE		BIT(4)
662bb8d138SSimon Xue #define DECOM_ZLIB_MODE		BIT(5)
672bb8d138SSimon Xue #define DECOM_DEFLATE_MODE	BIT(0)
68809af6baSJason Zhu #define DECOM_AXI_IDLE		BIT(4)
695b7d3298SJason Zhu #define DECOM_LZ4_MODE		0
702bb8d138SSimon Xue 
712bb8d138SSimon Xue #define DECOM_ENABLE		0x1
722bb8d138SSimon Xue #define DECOM_DISABLE		0x0
732bb8d138SSimon Xue 
742bb8d138SSimon Xue #define DECOM_IRQ		0xffff /* fixme */
752bb8d138SSimon Xue 
762bb8d138SSimon Xue #define DECOM_INT_MASK \
772bb8d138SSimon Xue 	(DSOLIEN | ZDICTEIEN | GCMEIEN | GIDEIEN | \
782bb8d138SSimon Xue 	CCCEIEN | BCCEIEN | HCCEIEN | CSEIEN | \
792bb8d138SSimon Xue 	DICTEIEN | VNEIEN | WNEIEN | RDCEIEN | WRCEIEN | \
802bb8d138SSimon Xue 	DISEIEN | LENEIEN | LITEIEN | SQMEIEN | SLCIEN | \
812bb8d138SSimon Xue 	HDEIEN | DSIEN)
822bb8d138SSimon Xue 
832bb8d138SSimon Xue struct rockchip_decom_priv {
84*b367c66bSJoseph Chen 	struct reset_ctl rst;
852bb8d138SSimon Xue 	void __iomem *base;
86809af6baSJason Zhu 	bool idle_check_once;
872bb8d138SSimon Xue 	bool done;
888b225c61SJoseph Chen 	int cached; /* 1: access the data through dcache; 0: no dcache */
892bb8d138SSimon Xue };
902bb8d138SSimon Xue 
912bb8d138SSimon Xue static int rockchip_decom_start(struct udevice *dev, void *buf)
922bb8d138SSimon Xue {
932bb8d138SSimon Xue 	struct rockchip_decom_priv *priv = dev_get_priv(dev);
94cc05bcfaSJason Zhu 	struct decom_param *param = (struct decom_param *)buf;
95656bdb59SJoseph Chen 	unsigned int limit_lo = param->size_src & 0xffffffff;
96656bdb59SJoseph Chen 	unsigned int limit_hi = param->size_src >> 32;
978b225c61SJoseph Chen 	ulong align_input, align_len;
988b225c61SJoseph Chen 
99*b367c66bSJoseph Chen #if CONFIG_IS_ENABLED(DM_RESET)
100*b367c66bSJoseph Chen 	reset_assert(&priv->rst);
101*b367c66bSJoseph Chen 	udelay(10);
102*b367c66bSJoseph Chen 	reset_deassert(&priv->rst);
103*b367c66bSJoseph Chen #endif
1048b225c61SJoseph Chen 	if (!priv->cached) {
1058b225c61SJoseph Chen 		/* src: make sure we get the real compressed data from ddr */
1068b225c61SJoseph Chen 		align_input =
1078b225c61SJoseph Chen 		     round_down(param->addr_src, CONFIG_SYS_CACHELINE_SIZE);
1088b225c61SJoseph Chen 		align_len =
1098b225c61SJoseph Chen 		     round_up(param->size_src + (param->addr_src - align_input),
1108b225c61SJoseph Chen 			      CONFIG_SYS_CACHELINE_SIZE);
1118b225c61SJoseph Chen 		flush_cache(align_input, align_len);
1128b225c61SJoseph Chen 
1138b225c61SJoseph Chen 		/*
1148b225c61SJoseph Chen 		 * dst: actually we prefer to invalidate dcache after decompress
1158b225c61SJoseph Chen 		 * done, but it seems there is not cache invalidate API for us.
1168b225c61SJoseph Chen 		 * so let's flush this area.
1178b225c61SJoseph Chen 		 */
1188b225c61SJoseph Chen 		align_input =
1198b225c61SJoseph Chen 		     round_down(param->addr_dst, CONFIG_SYS_CACHELINE_SIZE);
1208b225c61SJoseph Chen 		align_len =
1218b225c61SJoseph Chen 		     round_up(param->size_src + (param->addr_dst - align_input),
1228b225c61SJoseph Chen 			      CONFIG_SYS_CACHELINE_SIZE);
1238b225c61SJoseph Chen 		flush_cache(align_input, align_len);
1248b225c61SJoseph Chen 	}
1252bb8d138SSimon Xue 
1262bb8d138SSimon Xue 	priv->done = false;
1272bb8d138SSimon Xue 
1285b7d3298SJason Zhu 	if (param->mode == DECOM_LZ4)
1292bb8d138SSimon Xue 		writel(LZ4_CONT_CSUM_CHECK_EN |
1302bb8d138SSimon Xue 		       LZ4_HEAD_CSUM_CHECK_EN |
1312bb8d138SSimon Xue 		       LZ4_BLOCK_CSUM_CHECK_EN |
132656bdb59SJoseph Chen 		       DECOM_LZ4_MODE,
133656bdb59SJoseph Chen 		       priv->base + DECOM_CTRL);
134656bdb59SJoseph Chen 	else if (param->mode == DECOM_GZIP)
1352bb8d138SSimon Xue 		writel(DECOM_DEFLATE_MODE | DECOM_GZIP_MODE,
1362bb8d138SSimon Xue 		       priv->base + DECOM_CTRL);
137656bdb59SJoseph Chen 	else if (param->mode == DECOM_ZLIB)
1382bb8d138SSimon Xue 		writel(DECOM_DEFLATE_MODE | DECOM_ZLIB_MODE,
1392bb8d138SSimon Xue 		       priv->base + DECOM_CTRL);
1402bb8d138SSimon Xue 
1412bb8d138SSimon Xue 	writel(param->addr_src, priv->base + DECOM_RADDR);
1422bb8d138SSimon Xue 	writel(param->addr_dst, priv->base + DECOM_WADDR);
1432bb8d138SSimon Xue 
144327380daSSimon Xue 	writel(limit_lo, priv->base + DECOM_LMTSL);
145327380daSSimon Xue 	writel(limit_hi, priv->base + DECOM_LMTSH);
1462bb8d138SSimon Xue 	writel(DECOM_ENABLE, priv->base + DECOM_ENR);
147656bdb59SJoseph Chen 
148809af6baSJason Zhu 	priv->idle_check_once = true;
1492bb8d138SSimon Xue 
1502bb8d138SSimon Xue 	return 0;
1512bb8d138SSimon Xue }
1522bb8d138SSimon Xue 
1532bb8d138SSimon Xue static int rockchip_decom_stop(struct udevice *dev)
1542bb8d138SSimon Xue {
1552bb8d138SSimon Xue 	struct rockchip_decom_priv *priv = dev_get_priv(dev);
1562bb8d138SSimon Xue 
1572bb8d138SSimon Xue 	writel(DECOM_DISABLE, priv->base + DECOM_ENR);
1582bb8d138SSimon Xue 
1592bb8d138SSimon Xue 	return 0;
1602bb8d138SSimon Xue }
1612bb8d138SSimon Xue 
1622bb8d138SSimon Xue /* Caller must call this function to check if decompress done */
1632bb8d138SSimon Xue static int rockchip_decom_done_poll(struct udevice *dev)
1642bb8d138SSimon Xue {
1652bb8d138SSimon Xue 	struct rockchip_decom_priv *priv = dev_get_priv(dev);
1662bb8d138SSimon Xue 
167809af6baSJason Zhu 	/*
168809af6baSJason Zhu 	 * Test the decom is idle first time.
169809af6baSJason Zhu 	 */
170809af6baSJason Zhu 	if (!priv->idle_check_once)
171809af6baSJason Zhu 		return !(readl(priv->base + DECOM_AXI_STAT) & DECOM_AXI_IDLE);
1722bb8d138SSimon Xue 
173809af6baSJason Zhu 	return !(readl(priv->base + DECOM_STAT) & DECOM_COMPLETE);
1742bb8d138SSimon Xue }
1752bb8d138SSimon Xue 
176dc33c231SJoseph Chen static int rockchip_decom_capability(u32 *buf)
177cc05bcfaSJason Zhu {
178dc33c231SJoseph Chen 	*buf = DECOM_GZIP;
179dc33c231SJoseph Chen 
180dc33c231SJoseph Chen 	return 0;
181cc05bcfaSJason Zhu }
182cc05bcfaSJason Zhu 
183656bdb59SJoseph Chen static int rockchip_decom_data_size(struct udevice *dev, u64 *buf)
184656bdb59SJoseph Chen {
185656bdb59SJoseph Chen 	struct rockchip_decom_priv *priv = dev_get_priv(dev);
186656bdb59SJoseph Chen 	struct decom_param *param = (struct decom_param *)buf;
187656bdb59SJoseph Chen 	u32 sizel, sizeh;
188656bdb59SJoseph Chen 
189656bdb59SJoseph Chen 	sizel = readl(priv->base + DECOM_TSIZEL);
190656bdb59SJoseph Chen 	sizeh = readl(priv->base + DECOM_TSIZEH);
191656bdb59SJoseph Chen 	param->size_dst = sizel | ((u64)sizeh << 32);
192656bdb59SJoseph Chen 
193656bdb59SJoseph Chen 	return 0;
194656bdb59SJoseph Chen }
195656bdb59SJoseph Chen 
196cc05bcfaSJason Zhu /* Caller must fill in param @buf which represent struct decom_param */
1972bb8d138SSimon Xue static int rockchip_decom_ioctl(struct udevice *dev, unsigned long request,
1982bb8d138SSimon Xue 				void *buf)
1992bb8d138SSimon Xue {
2002bb8d138SSimon Xue 	int ret = -EINVAL;
2012bb8d138SSimon Xue 
2022bb8d138SSimon Xue 	switch (request) {
2032bb8d138SSimon Xue 	case IOCTL_REQ_START:
2042bb8d138SSimon Xue 		ret = rockchip_decom_start(dev, buf);
2052bb8d138SSimon Xue 		break;
2062bb8d138SSimon Xue 	case IOCTL_REQ_POLL:
2072bb8d138SSimon Xue 		ret = rockchip_decom_done_poll(dev);
2082bb8d138SSimon Xue 		break;
2092bb8d138SSimon Xue 	case IOCTL_REQ_STOP:
2102bb8d138SSimon Xue 		ret = rockchip_decom_stop(dev);
2112bb8d138SSimon Xue 		break;
212cc05bcfaSJason Zhu 	case IOCTL_REQ_CAPABILITY:
213dc33c231SJoseph Chen 		ret = rockchip_decom_capability(buf);
214809af6baSJason Zhu 		break;
215656bdb59SJoseph Chen 	case IOCTL_REQ_DATA_SIZE:
216656bdb59SJoseph Chen 		ret = rockchip_decom_data_size(dev, buf);
217656bdb59SJoseph Chen 		break;
218656bdb59SJoseph Chen 	default:
219656bdb59SJoseph Chen 		printf("Unsupported ioctl: %ld\n", (ulong)request);
220656bdb59SJoseph Chen 		break;
2212bb8d138SSimon Xue 	}
2222bb8d138SSimon Xue 
2232bb8d138SSimon Xue 	return ret;
2242bb8d138SSimon Xue }
2252bb8d138SSimon Xue 
2262bb8d138SSimon Xue static const struct misc_ops rockchip_decom_ops = {
2272bb8d138SSimon Xue 	.ioctl = rockchip_decom_ioctl,
2282bb8d138SSimon Xue };
2292bb8d138SSimon Xue 
2302bb8d138SSimon Xue static int rockchip_decom_ofdata_to_platdata(struct udevice *dev)
2312bb8d138SSimon Xue {
2322bb8d138SSimon Xue 	struct rockchip_decom_priv *priv = dev_get_priv(dev);
2332bb8d138SSimon Xue 
2342bb8d138SSimon Xue 	priv->base = dev_read_addr_ptr(dev);
2352bb8d138SSimon Xue 	if (!priv->base)
2362bb8d138SSimon Xue 		return -ENOENT;
2372bb8d138SSimon Xue 
2388b225c61SJoseph Chen 	priv->cached = dev_read_u32_default(dev, "data-cached", 0);
2391540ca37SSimon Xue 
2402bb8d138SSimon Xue 	return 0;
2412bb8d138SSimon Xue }
2422bb8d138SSimon Xue 
2432bb8d138SSimon Xue static int rockchip_decom_probe(struct udevice *dev)
2442bb8d138SSimon Xue {
245*b367c66bSJoseph Chen #if CONFIG_IS_ENABLED(DM_RESET)
246*b367c66bSJoseph Chen 	struct rockchip_decom_priv *priv = dev_get_priv(dev);
247*b367c66bSJoseph Chen 	int ret;
248*b367c66bSJoseph Chen 
249*b367c66bSJoseph Chen 	ret = reset_get_by_name(dev, "dresetn", &priv->rst);
250*b367c66bSJoseph Chen 	if (ret) {
251*b367c66bSJoseph Chen 		debug("reset_get_by_name() failed: %d\n", ret);
252*b367c66bSJoseph Chen 		return ret;
253*b367c66bSJoseph Chen 	}
254*b367c66bSJoseph Chen #endif
2552bb8d138SSimon Xue 	return 0;
2562bb8d138SSimon Xue }
2572bb8d138SSimon Xue 
2582bb8d138SSimon Xue static const struct udevice_id rockchip_decom_ids[] = {
2592bb8d138SSimon Xue 	{ .compatible = "rockchip,hw-decompress" },
2602bb8d138SSimon Xue 	{}
2612bb8d138SSimon Xue };
2622bb8d138SSimon Xue 
2632bb8d138SSimon Xue U_BOOT_DRIVER(rockchip_hw_decompress) = {
2642bb8d138SSimon Xue 	.name = "rockchip_hw_decompress",
2652bb8d138SSimon Xue 	.id = UCLASS_MISC,
2662bb8d138SSimon Xue 	.of_match = rockchip_decom_ids,
2672bb8d138SSimon Xue 	.probe = rockchip_decom_probe,
2682bb8d138SSimon Xue 	.ofdata_to_platdata = rockchip_decom_ofdata_to_platdata,
2692bb8d138SSimon Xue 	.priv_auto_alloc_size = sizeof(struct rockchip_decom_priv),
2702bb8d138SSimon Xue 	.ops = &rockchip_decom_ops,
2712bb8d138SSimon Xue };
272