xref: /rk3399_rockchip-uboot/drivers/misc/rockchip_decompress.c (revision e663d2b596fd0029d58f1b4e63b30ff230480dbb)
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 
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 == LZ4_MOD)
96 		writel(LZ4_CONT_CSUM_CHECK_EN |
97 		       LZ4_HEAD_CSUM_CHECK_EN |
98 		       LZ4_BLOCK_CSUM_CHECK_EN |
99 		       LZ4_MOD, priv->base + DECOM_CTRL);
100 
101 	if (param->mode == GZIP_MOD)
102 		writel(DECOM_DEFLATE_MODE | DECOM_GZIP_MODE,
103 		       priv->base + DECOM_CTRL);
104 
105 	if (param->mode == ZLIB_MOD)
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_ability(void)
147 {
148 	return GZIP_MOD;
149 }
150 
151 /* Caller must fill in param @buf which represent struct decom_param */
152 static int rockchip_decom_ioctl(struct udevice *dev, unsigned long request,
153 				void *buf)
154 {
155 	int ret = -EINVAL;
156 
157 	switch (request) {
158 	case IOCTL_REQ_START:
159 		ret = rockchip_decom_start(dev, buf);
160 		break;
161 	case IOCTL_REQ_POLL:
162 		ret = rockchip_decom_done_poll(dev);
163 		break;
164 	case IOCTL_REQ_STOP:
165 		ret = rockchip_decom_stop(dev);
166 		break;
167 	case IOCTL_REQ_CAPABILITY:
168 		ret = rockchip_decom_ability();
169 	}
170 
171 	return ret;
172 }
173 
174 static const struct misc_ops rockchip_decom_ops = {
175 	.ioctl = rockchip_decom_ioctl,
176 };
177 
178 static int rockchip_decom_ofdata_to_platdata(struct udevice *dev)
179 {
180 	struct rockchip_decom_priv *priv = dev_get_priv(dev);
181 
182 	priv->base = dev_read_addr_ptr(dev);
183 	if (!priv->base)
184 		return -ENOENT;
185 
186 	priv->soft_reset_base = dev_read_u32_default(dev, "soft-reset-addr", 0)
187 					& 0xffffffff;
188 
189 	return 0;
190 }
191 
192 #ifndef CONFIG_SPL_BUILD
193 static void rockchip_decom_irqhandler(int irq, void *data)
194 {
195 	struct udevice *dev = data;
196 	struct rockchip_decom_priv *priv = dev_get_priv(dev);
197 	int irq_status;
198 	int decom_status;
199 
200 	irq_status = readl(priv->base + DECOM_ISR);
201 	/* clear interrupts */
202 	writel(irq_status, priv->base + DECOM_ISR);
203 	if (irq_status & DECOM_STOP) {
204 		decom_status = readl(priv->base + DECOM_STAT);
205 		if (decom_status & DECOM_COMPLETE) {
206 			priv->done = true;
207 			/*
208 			 * TODO:
209 			 * Inform someone that decompress completed
210 			 */
211 			printf("decom completed\n");
212 		} else {
213 			printf("decom failed, irq_status = 0x%x, decom_status = 0x%x\n",
214 			       irq_status, decom_status);
215 		}
216 	}
217 }
218 #endif
219 
220 static int rockchip_decom_probe(struct udevice *dev)
221 {
222 #ifndef CONFIG_SPL_BUILD
223 	irq_install_handler(DECOM_IRQ, rockchip_decom_irqhandler, dev);
224 	irq_handler_enable(DECOM_IRQ);
225 #endif
226 	return 0;
227 }
228 
229 static const struct udevice_id rockchip_decom_ids[] = {
230 	{ .compatible = "rockchip,hw-decompress" },
231 	{}
232 };
233 
234 U_BOOT_DRIVER(rockchip_hw_decompress) = {
235 	.name = "rockchip_hw_decompress",
236 	.id = UCLASS_MISC,
237 	.of_match = rockchip_decom_ids,
238 	.probe = rockchip_decom_probe,
239 	.ofdata_to_platdata = rockchip_decom_ofdata_to_platdata,
240 	.priv_auto_alloc_size = sizeof(struct rockchip_decom_priv),
241 	.ops = &rockchip_decom_ops,
242 };
243