xref: /rk3399_rockchip-uboot/drivers/misc/rockchip_decompress.c (revision d416248e51de2532f3b3ce4c61ffbd464ddb1356)
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;
1018b225c61SJoseph Chen 
102b367c66bSJoseph Chen #if CONFIG_IS_ENABLED(DM_RESET)
103b367c66bSJoseph Chen 	reset_assert(&priv->rst);
104b367c66bSJoseph Chen 	udelay(10);
105b367c66bSJoseph Chen 	reset_deassert(&priv->rst);
106b367c66bSJoseph Chen #endif
107c9f753f3SJoseph Chen 	/*
108c9f753f3SJoseph Chen 	 * Purpose:
109c9f753f3SJoseph Chen 	 *    src: clean dcache to get the real compressed data from ddr.
110c9f753f3SJoseph Chen 	 *    dst: invalidate dcache.
111c9f753f3SJoseph Chen 	 *
112c9f753f3SJoseph Chen 	 * flush_dcache_all() operating on set/way is faster than
113c9f753f3SJoseph Chen 	 * flush_cache() and invalidate_dcache_range() operating
114c9f753f3SJoseph Chen 	 * on virtual address.
115c9f753f3SJoseph Chen 	 */
116c9f753f3SJoseph Chen 	if (!priv->cached)
117c9f753f3SJoseph Chen 		flush_dcache_all();
1182bb8d138SSimon Xue 
1192bb8d138SSimon Xue 	priv->done = false;
1202bb8d138SSimon Xue 
1215b7d3298SJason Zhu 	if (param->mode == DECOM_LZ4)
1222bb8d138SSimon Xue 		writel(LZ4_CONT_CSUM_CHECK_EN |
1232bb8d138SSimon Xue 		       LZ4_HEAD_CSUM_CHECK_EN |
1242bb8d138SSimon Xue 		       LZ4_BLOCK_CSUM_CHECK_EN |
125656bdb59SJoseph Chen 		       DECOM_LZ4_MODE,
126656bdb59SJoseph Chen 		       priv->base + DECOM_CTRL);
127656bdb59SJoseph Chen 	else if (param->mode == DECOM_GZIP)
1282bb8d138SSimon Xue 		writel(DECOM_DEFLATE_MODE | DECOM_GZIP_MODE,
1292bb8d138SSimon Xue 		       priv->base + DECOM_CTRL);
130656bdb59SJoseph Chen 	else if (param->mode == DECOM_ZLIB)
1312bb8d138SSimon Xue 		writel(DECOM_DEFLATE_MODE | DECOM_ZLIB_MODE,
1322bb8d138SSimon Xue 		       priv->base + DECOM_CTRL);
1332bb8d138SSimon Xue 
1342bb8d138SSimon Xue 	writel(param->addr_src, priv->base + DECOM_RADDR);
1352bb8d138SSimon Xue 	writel(param->addr_dst, priv->base + DECOM_WADDR);
1362bb8d138SSimon Xue 
137327380daSSimon Xue 	writel(limit_lo, priv->base + DECOM_LMTSL);
138327380daSSimon Xue 	writel(limit_hi, priv->base + DECOM_LMTSH);
139406de325SWeiwen Chen 
140406de325SWeiwen Chen #if defined(CONFIG_SPL_BUILD)
141406de325SWeiwen Chen 	writel(DECOM_INT_MASK, priv->base + DECOM_IEN);
142406de325SWeiwen Chen #endif
1432bb8d138SSimon Xue 	writel(DECOM_ENABLE, priv->base + DECOM_ENR);
144656bdb59SJoseph Chen 
145809af6baSJason Zhu 	priv->idle_check_once = true;
1462bb8d138SSimon Xue 
1472bb8d138SSimon Xue 	return 0;
1482bb8d138SSimon Xue }
1492bb8d138SSimon Xue 
1502bb8d138SSimon Xue static int rockchip_decom_stop(struct udevice *dev)
1512bb8d138SSimon Xue {
1522bb8d138SSimon Xue 	struct rockchip_decom_priv *priv = dev_get_priv(dev);
1532bb8d138SSimon Xue 
1542bb8d138SSimon Xue 	writel(DECOM_DISABLE, priv->base + DECOM_ENR);
1552bb8d138SSimon Xue 
1562bb8d138SSimon Xue 	return 0;
1572bb8d138SSimon Xue }
1582bb8d138SSimon Xue 
1592bb8d138SSimon Xue /* Caller must call this function to check if decompress done */
1602bb8d138SSimon Xue static int rockchip_decom_done_poll(struct udevice *dev)
1612bb8d138SSimon Xue {
1622bb8d138SSimon Xue 	struct rockchip_decom_priv *priv = dev_get_priv(dev);
1632bb8d138SSimon Xue 
164809af6baSJason Zhu 	/*
165809af6baSJason Zhu 	 * Test the decom is idle first time.
166809af6baSJason Zhu 	 */
167809af6baSJason Zhu 	if (!priv->idle_check_once)
168809af6baSJason Zhu 		return !(readl(priv->base + DECOM_AXI_STAT) & DECOM_AXI_IDLE);
1692bb8d138SSimon Xue 
170809af6baSJason Zhu 	return !(readl(priv->base + DECOM_STAT) & DECOM_COMPLETE);
1712bb8d138SSimon Xue }
1722bb8d138SSimon Xue 
173dc33c231SJoseph Chen static int rockchip_decom_capability(u32 *buf)
174cc05bcfaSJason Zhu {
175dc33c231SJoseph Chen 	*buf = DECOM_GZIP;
176dc33c231SJoseph Chen 
177dc33c231SJoseph Chen 	return 0;
178cc05bcfaSJason Zhu }
179cc05bcfaSJason Zhu 
180656bdb59SJoseph Chen static int rockchip_decom_data_size(struct udevice *dev, u64 *buf)
181656bdb59SJoseph Chen {
182656bdb59SJoseph Chen 	struct rockchip_decom_priv *priv = dev_get_priv(dev);
183656bdb59SJoseph Chen 	struct decom_param *param = (struct decom_param *)buf;
184656bdb59SJoseph Chen 	u32 sizel, sizeh;
185656bdb59SJoseph Chen 
186656bdb59SJoseph Chen 	sizel = readl(priv->base + DECOM_TSIZEL);
187656bdb59SJoseph Chen 	sizeh = readl(priv->base + DECOM_TSIZEH);
188656bdb59SJoseph Chen 	param->size_dst = sizel | ((u64)sizeh << 32);
189656bdb59SJoseph Chen 
190656bdb59SJoseph Chen 	return 0;
191656bdb59SJoseph Chen }
192656bdb59SJoseph Chen 
193cc05bcfaSJason Zhu /* Caller must fill in param @buf which represent struct decom_param */
1942bb8d138SSimon Xue static int rockchip_decom_ioctl(struct udevice *dev, unsigned long request,
1952bb8d138SSimon Xue 				void *buf)
1962bb8d138SSimon Xue {
1972bb8d138SSimon Xue 	int ret = -EINVAL;
1982bb8d138SSimon Xue 
1992bb8d138SSimon Xue 	switch (request) {
2002bb8d138SSimon Xue 	case IOCTL_REQ_START:
2012bb8d138SSimon Xue 		ret = rockchip_decom_start(dev, buf);
2022bb8d138SSimon Xue 		break;
2032bb8d138SSimon Xue 	case IOCTL_REQ_POLL:
2042bb8d138SSimon Xue 		ret = rockchip_decom_done_poll(dev);
2052bb8d138SSimon Xue 		break;
2062bb8d138SSimon Xue 	case IOCTL_REQ_STOP:
2072bb8d138SSimon Xue 		ret = rockchip_decom_stop(dev);
2082bb8d138SSimon Xue 		break;
209cc05bcfaSJason Zhu 	case IOCTL_REQ_CAPABILITY:
210dc33c231SJoseph Chen 		ret = rockchip_decom_capability(buf);
211809af6baSJason Zhu 		break;
212656bdb59SJoseph Chen 	case IOCTL_REQ_DATA_SIZE:
213656bdb59SJoseph Chen 		ret = rockchip_decom_data_size(dev, buf);
214656bdb59SJoseph Chen 		break;
215656bdb59SJoseph Chen 	default:
216656bdb59SJoseph Chen 		printf("Unsupported ioctl: %ld\n", (ulong)request);
217656bdb59SJoseph Chen 		break;
2182bb8d138SSimon Xue 	}
2192bb8d138SSimon Xue 
2202bb8d138SSimon Xue 	return ret;
2212bb8d138SSimon Xue }
2222bb8d138SSimon Xue 
2232bb8d138SSimon Xue static const struct misc_ops rockchip_decom_ops = {
2242bb8d138SSimon Xue 	.ioctl = rockchip_decom_ioctl,
2252bb8d138SSimon Xue };
2262bb8d138SSimon Xue 
2272bb8d138SSimon Xue static int rockchip_decom_ofdata_to_platdata(struct udevice *dev)
2282bb8d138SSimon Xue {
2292bb8d138SSimon Xue 	struct rockchip_decom_priv *priv = dev_get_priv(dev);
2302bb8d138SSimon Xue 
2312bb8d138SSimon Xue 	priv->base = dev_read_addr_ptr(dev);
2322bb8d138SSimon Xue 	if (!priv->base)
2332bb8d138SSimon Xue 		return -ENOENT;
2342bb8d138SSimon Xue 
2358b225c61SJoseph Chen 	priv->cached = dev_read_u32_default(dev, "data-cached", 0);
2361540ca37SSimon Xue 
2372bb8d138SSimon Xue 	return 0;
2382bb8d138SSimon Xue }
2392bb8d138SSimon Xue 
2402bb8d138SSimon Xue static int rockchip_decom_probe(struct udevice *dev)
2412bb8d138SSimon Xue {
242b367c66bSJoseph Chen 	struct rockchip_decom_priv *priv = dev_get_priv(dev);
243b367c66bSJoseph Chen 	int ret;
244b367c66bSJoseph Chen 
245*d416248eSJoseph Chen #if CONFIG_IS_ENABLED(DM_RESET)
246b367c66bSJoseph Chen 	ret = reset_get_by_name(dev, "dresetn", &priv->rst);
247b367c66bSJoseph Chen 	if (ret) {
248b367c66bSJoseph Chen 		debug("reset_get_by_name() failed: %d\n", ret);
249b367c66bSJoseph Chen 		return ret;
250b367c66bSJoseph Chen 	}
251b367c66bSJoseph Chen #endif
2525db33a71SSimon Xue 
2535db33a71SSimon Xue 	ret = clk_get_by_name(dev, "dclk", &priv->dclk);
2545db33a71SSimon Xue 	if (ret < 0)
2555db33a71SSimon Xue 		return ret;
2565db33a71SSimon Xue 
2575db33a71SSimon Xue 	ret = clk_set_rate(&priv->dclk, DCLK_DECOM);
2585db33a71SSimon Xue 	if (ret < 0)
2595db33a71SSimon Xue 		return ret;
2605db33a71SSimon Xue 
2612bb8d138SSimon Xue 	return 0;
2622bb8d138SSimon Xue }
2632bb8d138SSimon Xue 
2642bb8d138SSimon Xue static const struct udevice_id rockchip_decom_ids[] = {
2652bb8d138SSimon Xue 	{ .compatible = "rockchip,hw-decompress" },
2662bb8d138SSimon Xue 	{}
2672bb8d138SSimon Xue };
2682bb8d138SSimon Xue 
2692bb8d138SSimon Xue U_BOOT_DRIVER(rockchip_hw_decompress) = {
2702bb8d138SSimon Xue 	.name = "rockchip_hw_decompress",
2712bb8d138SSimon Xue 	.id = UCLASS_MISC,
2722bb8d138SSimon Xue 	.of_match = rockchip_decom_ids,
2732bb8d138SSimon Xue 	.probe = rockchip_decom_probe,
2742bb8d138SSimon Xue 	.ofdata_to_platdata = rockchip_decom_ofdata_to_platdata,
2752bb8d138SSimon Xue 	.priv_auto_alloc_size = sizeof(struct rockchip_decom_priv),
2762bb8d138SSimon Xue 	.ops = &rockchip_decom_ops,
2772bb8d138SSimon Xue };
278