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