xref: /rk3399_rockchip-uboot/drivers/misc/rockchip_decompress.c (revision 01b8c4d110abb0dcbe36dc5b6b10d93b2b8e2667)
1 // SPDX-License-Identifier:     GPL-2.0+
2 /*
3  * Copyright (C) 2019 Rockchip Electronics Co., Ltd
4  */
5 #include <common.h>
6 #include <asm/io.h>
7 #include <dm.h>
8 #include <linux/bitops.h>
9 #include <misc.h>
10 #include <irq-generic.h>
11 
12 DECLARE_GLOBAL_DATA_PTR;
13 
14 #define DECOM_CTRL		0x0
15 #define DECOM_ENR		0x4
16 #define DECOM_RADDR		0x8
17 #define DECOM_WADDR		0xc
18 #define DECOM_UDDSL		0x10
19 #define DECOM_UDDSH		0x14
20 #define DECOM_TXTHR		0x18
21 #define DECOM_RXTHR		0x1c
22 #define DECOM_SLEN		0x20
23 #define DECOM_STAT		0x24
24 #define DECOM_ISR		0x28
25 #define DECOM_IEN		0x2c
26 #define DECOM_AXI_STAT		0x30
27 #define DECOM_TSIZEL		0x34
28 #define DECOM_TSIZEH		0x38
29 #define DECOM_MGNUM		0x3c
30 #define DECOM_FRAME		0x40
31 #define DECOM_DICTID		0x44
32 #define DECOM_CSL		0x48
33 #define DECOM_CSH		0x4c
34 
35 #define LZ4_HEAD_CSUM_CHECK_EN	BIT(1)
36 #define LZ4_BLOCK_CSUM_CHECK_EN	BIT(2)
37 #define LZ4_CONT_CSUM_CHECK_EN	BIT(3)
38 
39 #define DSOLIEN			BIT(19)
40 #define ZDICTEIEN		BIT(18)
41 #define GCMEIEN			BIT(17)
42 #define GIDEIEN			BIT(16)
43 #define CCCEIEN			BIT(15)
44 #define BCCEIEN			BIT(14)
45 #define HCCEIEN			BIT(13)
46 #define CSEIEN			BIT(12)
47 #define DICTEIEN		BIT(11)
48 #define VNEIEN			BIT(10)
49 #define WNEIEN			BIT(9)
50 #define RDCEIEN			BIT(8)
51 #define WRCEIEN			BIT(7)
52 #define DISEIEN			BIT(6)
53 #define LENEIEN			BIT(5)
54 #define LITEIEN			BIT(4)
55 #define SQMEIEN			BIT(3)
56 #define SLCIEN			BIT(2)
57 #define HDEIEN			BIT(1)
58 #define DSIEN			BIT(0)
59 
60 #define DECOM_STOP		BIT(0)
61 #define DECOM_COMPLETE		BIT(0)
62 #define DECOM_GZIP_MODE		BIT(4)
63 #define DECOM_ZLIB_MODE		BIT(5)
64 #define DECOM_DEFLATE_MODE	BIT(0)
65 #define DECOM_LZ4_MODE		0
66 
67 #define DECOM_ENABLE		0x1
68 #define DECOM_DISABLE		0x0
69 
70 #define DECOM_IRQ		0xffff /* fixme */
71 
72 #define DECOM_INT_MASK \
73 	(DSOLIEN | ZDICTEIEN | GCMEIEN | GIDEIEN | \
74 	CCCEIEN | BCCEIEN | HCCEIEN | CSEIEN | \
75 	DICTEIEN | VNEIEN | WNEIEN | RDCEIEN | WRCEIEN | \
76 	DISEIEN | LENEIEN | LITEIEN | SQMEIEN | SLCIEN | \
77 	HDEIEN | DSIEN)
78 
79 struct rockchip_decom_priv {
80 	void __iomem *base;
81 	unsigned long soft_reset_base;
82 	bool done;
83 };
84 
85 static int rockchip_decom_start(struct udevice *dev, void *buf)
86 {
87 	struct rockchip_decom_priv *priv = dev_get_priv(dev);
88 	struct decom_param *param = (struct decom_param *)buf;
89 
90 	priv->done = false;
91 
92 	writel(0x00800080, priv->soft_reset_base);
93 	writel(0x00800000, priv->soft_reset_base);
94 
95 	if (param->mode == DECOM_LZ4)
96 		writel(LZ4_CONT_CSUM_CHECK_EN |
97 		       LZ4_HEAD_CSUM_CHECK_EN |
98 		       LZ4_BLOCK_CSUM_CHECK_EN |
99 		       DECOM_LZ4_MODE, priv->base + DECOM_CTRL);
100 
101 	if (param->mode == DECOM_GZIP)
102 		writel(DECOM_DEFLATE_MODE | DECOM_GZIP_MODE,
103 		       priv->base + DECOM_CTRL);
104 
105 	if (param->mode == DECOM_ZLIB)
106 		writel(DECOM_DEFLATE_MODE | DECOM_ZLIB_MODE,
107 		       priv->base + DECOM_CTRL);
108 
109 	writel(param->addr_src, priv->base + DECOM_RADDR);
110 	writel(param->addr_dst, priv->base + DECOM_WADDR);
111 
112 	writel(DECOM_INT_MASK, priv->base + DECOM_IEN);
113 	writel(DECOM_ENABLE, priv->base + DECOM_ENR);
114 
115 	return 0;
116 }
117 
118 static int rockchip_decom_stop(struct udevice *dev)
119 {
120 	struct rockchip_decom_priv *priv = dev_get_priv(dev);
121 	int irq_status;
122 
123 	irq_status = readl(priv->base + DECOM_ISR);
124 	/* clear interrupts */
125 	if (irq_status)
126 		writel(irq_status, priv->base + DECOM_ISR);
127 
128 	writel(DECOM_DISABLE, priv->base + DECOM_ENR);
129 
130 	return 0;
131 }
132 
133 /* Caller must call this function to check if decompress done */
134 static int rockchip_decom_done_poll(struct udevice *dev)
135 {
136 	struct rockchip_decom_priv *priv = dev_get_priv(dev);
137 	int decom_status;
138 
139 	decom_status = readl(priv->base + DECOM_STAT);
140 	if (decom_status & DECOM_COMPLETE)
141 		return 0;
142 
143 	return -EINVAL;
144 }
145 
146 static int rockchip_decom_capability(u32 *buf)
147 {
148 	*buf = DECOM_GZIP;
149 
150 	return 0;
151 }
152 
153 /* Caller must fill in param @buf which represent struct decom_param */
154 static int rockchip_decom_ioctl(struct udevice *dev, unsigned long request,
155 				void *buf)
156 {
157 	int ret = -EINVAL;
158 
159 	switch (request) {
160 	case IOCTL_REQ_START:
161 		ret = rockchip_decom_start(dev, buf);
162 		break;
163 	case IOCTL_REQ_POLL:
164 		ret = rockchip_decom_done_poll(dev);
165 		break;
166 	case IOCTL_REQ_STOP:
167 		ret = rockchip_decom_stop(dev);
168 		break;
169 	case IOCTL_REQ_CAPABILITY:
170 		ret = rockchip_decom_capability(buf);
171 	}
172 
173 	return ret;
174 }
175 
176 static const struct misc_ops rockchip_decom_ops = {
177 	.ioctl = rockchip_decom_ioctl,
178 };
179 
180 static int rockchip_decom_ofdata_to_platdata(struct udevice *dev)
181 {
182 	struct rockchip_decom_priv *priv = dev_get_priv(dev);
183 
184 	priv->base = dev_read_addr_ptr(dev);
185 	if (!priv->base)
186 		return -ENOENT;
187 
188 	priv->soft_reset_base = dev_read_u32_default(dev, "soft-reset-addr", 0)
189 					& 0xffffffff;
190 
191 	return 0;
192 }
193 
194 #ifndef CONFIG_SPL_BUILD
195 static void rockchip_decom_irqhandler(int irq, void *data)
196 {
197 	struct udevice *dev = data;
198 	struct rockchip_decom_priv *priv = dev_get_priv(dev);
199 	int irq_status;
200 	int decom_status;
201 
202 	irq_status = readl(priv->base + DECOM_ISR);
203 	/* clear interrupts */
204 	writel(irq_status, priv->base + DECOM_ISR);
205 	if (irq_status & DECOM_STOP) {
206 		decom_status = readl(priv->base + DECOM_STAT);
207 		if (decom_status & DECOM_COMPLETE) {
208 			priv->done = true;
209 			/*
210 			 * TODO:
211 			 * Inform someone that decompress completed
212 			 */
213 			printf("decom completed\n");
214 		} else {
215 			printf("decom failed, irq_status = 0x%x, decom_status = 0x%x\n",
216 			       irq_status, decom_status);
217 		}
218 	}
219 }
220 #endif
221 
222 static int rockchip_decom_probe(struct udevice *dev)
223 {
224 #ifndef CONFIG_SPL_BUILD
225 	irq_install_handler(DECOM_IRQ, rockchip_decom_irqhandler, dev);
226 	irq_handler_enable(DECOM_IRQ);
227 #endif
228 	return 0;
229 }
230 
231 static const struct udevice_id rockchip_decom_ids[] = {
232 	{ .compatible = "rockchip,hw-decompress" },
233 	{}
234 };
235 
236 U_BOOT_DRIVER(rockchip_hw_decompress) = {
237 	.name = "rockchip_hw_decompress",
238 	.id = UCLASS_MISC,
239 	.of_match = rockchip_decom_ids,
240 	.probe = rockchip_decom_probe,
241 	.ofdata_to_platdata = rockchip_decom_ofdata_to_platdata,
242 	.priv_auto_alloc_size = sizeof(struct rockchip_decom_priv),
243 	.ops = &rockchip_decom_ops,
244 };
245