hc
2024-08-12 233ab1bd4c5697f5cdec94e60206e8c6ac609b4c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
// SPDX-License-Identifier:     GPL-2.0+
/*
 * Copyright (C) 2019 Rockchip Electronics Co., Ltd
 */
#include <common.h>
#include <asm/io.h>
#include <clk.h>
#include <dm.h>
#include <linux/bitops.h>
#include <misc.h>
#include <irq-generic.h>
#include <reset.h>
 
DECLARE_GLOBAL_DATA_PTR;
 
#define DECOM_CTRL        0x0
#define DECOM_ENR        0x4
#define DECOM_RADDR        0x8
#define DECOM_WADDR        0xc
#define DECOM_UDDSL        0x10
#define DECOM_UDDSH        0x14
#define DECOM_TXTHR        0x18
#define DECOM_RXTHR        0x1c
#define DECOM_SLEN        0x20
#define DECOM_STAT        0x24
#define DECOM_ISR        0x28
#define DECOM_IEN        0x2c
#define DECOM_AXI_STAT        0x30
#define DECOM_TSIZEL        0x34
#define DECOM_TSIZEH        0x38
#define DECOM_MGNUM        0x3c
#define DECOM_FRAME        0x40
#define DECOM_DICTID        0x44
#define DECOM_CSL        0x48
#define DECOM_CSH        0x4c
#define DECOM_LMTSL             0x50
#define DECOM_LMTSH             0x54
 
#define LZ4_HEAD_CSUM_CHECK_EN    BIT(1)
#define LZ4_BLOCK_CSUM_CHECK_EN    BIT(2)
#define LZ4_CONT_CSUM_CHECK_EN    BIT(3)
 
#define DSOLIEN            BIT(19)
#define ZDICTEIEN        BIT(18)
#define GCMEIEN            BIT(17)
#define GIDEIEN            BIT(16)
#define CCCEIEN            BIT(15)
#define BCCEIEN            BIT(14)
#define HCCEIEN            BIT(13)
#define CSEIEN            BIT(12)
#define DICTEIEN        BIT(11)
#define VNEIEN            BIT(10)
#define WNEIEN            BIT(9)
#define RDCEIEN            BIT(8)
#define WRCEIEN            BIT(7)
#define DISEIEN            BIT(6)
#define LENEIEN            BIT(5)
#define LITEIEN            BIT(4)
#define SQMEIEN            BIT(3)
#define SLCIEN            BIT(2)
#define HDEIEN            BIT(1)
#define DSIEN            BIT(0)
 
#define DECOM_STOP        BIT(0)
#define DECOM_COMPLETE        BIT(0)
#define DECOM_GZIP_MODE        BIT(4)
#define DECOM_ZLIB_MODE        BIT(5)
#define DECOM_DEFLATE_MODE    BIT(0)
#define DECOM_AXI_IDLE        BIT(4)
#define DECOM_LZ4_MODE        0
 
#define DECOM_ENABLE        0x1
#define DECOM_DISABLE        0x0
 
#define DECOM_IRQ        0xffff /* fixme */
 
#define DECOM_INT_MASK \
   (DSOLIEN | ZDICTEIEN | GCMEIEN | GIDEIEN | \
   CCCEIEN | BCCEIEN | HCCEIEN | CSEIEN | \
   DICTEIEN | VNEIEN | WNEIEN | RDCEIEN | WRCEIEN | \
   DISEIEN | LENEIEN | LITEIEN | SQMEIEN | SLCIEN | \
   HDEIEN | DSIEN)
 
#define DCLK_DECOM        400 * 1000 * 1000
 
struct rockchip_decom_priv {
   struct reset_ctl rst;
   void __iomem *base;
   bool idle_check_once;
   bool done;
   struct clk dclk;
   int cached; /* 1: access the data through dcache; 0: no dcache */
};
 
static int rockchip_decom_start(struct udevice *dev, void *buf)
{
   struct rockchip_decom_priv *priv = dev_get_priv(dev);
   struct decom_param *param = (struct decom_param *)buf;
   unsigned int limit_lo = param->size_dst & 0xffffffff;
   unsigned int limit_hi = param->size_dst >> 32;
   u32 irq_status;
 
#if CONFIG_IS_ENABLED(DM_RESET)
   reset_assert(&priv->rst);
   udelay(10);
   reset_deassert(&priv->rst);
#endif
   /*
    * Purpose:
    *    src: clean dcache to get the real compressed data from ddr.
    *    dst: invalidate dcache.
    *
    * flush_dcache_all() operating on set/way is faster than
    * flush_cache() and invalidate_dcache_range() operating
    * on virtual address.
    */
   if (!priv->cached)
       flush_dcache_all();
 
   priv->done = false;
 
   irq_status = readl(priv->base + DECOM_ISR);
   /* clear interrupts */
   if (irq_status)
       writel(irq_status, priv->base + DECOM_ISR);
 
   if (param->mode == DECOM_LZ4)
       writel(LZ4_CONT_CSUM_CHECK_EN |
              LZ4_HEAD_CSUM_CHECK_EN |
              LZ4_BLOCK_CSUM_CHECK_EN |
              DECOM_LZ4_MODE,
              priv->base + DECOM_CTRL);
   else if (param->mode == DECOM_GZIP)
       writel(DECOM_DEFLATE_MODE | DECOM_GZIP_MODE,
              priv->base + DECOM_CTRL);
   else if (param->mode == DECOM_ZLIB)
       writel(DECOM_DEFLATE_MODE | DECOM_ZLIB_MODE,
              priv->base + DECOM_CTRL);
 
   writel(param->addr_src, priv->base + DECOM_RADDR);
   writel(param->addr_dst, priv->base + DECOM_WADDR);
 
   writel(limit_lo, priv->base + DECOM_LMTSL);
   writel(limit_hi, priv->base + DECOM_LMTSH);
 
   if (param->flags && DCOMP_FLG_IRQ_ONESHOT)
       writel(DECOM_INT_MASK, priv->base + DECOM_IEN);
   writel(DECOM_ENABLE, priv->base + DECOM_ENR);
 
   priv->idle_check_once = true;
 
   return 0;
}
 
static int rockchip_decom_stop(struct udevice *dev)
{
   struct rockchip_decom_priv *priv = dev_get_priv(dev);
 
   writel(DECOM_DISABLE, priv->base + DECOM_ENR);
 
   return 0;
}
 
/* Caller must call this function to check if decompress done */
static int rockchip_decom_done_poll(struct udevice *dev)
{
   struct rockchip_decom_priv *priv = dev_get_priv(dev);
 
   /*
    * Test the decom is idle first time.
    */
   if (!priv->idle_check_once)
       return !(readl(priv->base + DECOM_AXI_STAT) & DECOM_AXI_IDLE);
 
   return !(readl(priv->base + DECOM_STAT) & DECOM_COMPLETE);
}
 
static int rockchip_decom_capability(u32 *buf)
{
   *buf = DECOM_GZIP | DECOM_LZ4;
 
   return 0;
}
 
static int rockchip_decom_data_size(struct udevice *dev, u64 *buf)
{
   struct rockchip_decom_priv *priv = dev_get_priv(dev);
   struct decom_param *param = (struct decom_param *)buf;
   u32 sizel, sizeh;
 
   sizel = readl(priv->base + DECOM_TSIZEL);
   sizeh = readl(priv->base + DECOM_TSIZEH);
   param->size_dst = sizel | ((u64)sizeh << 32);
 
   return 0;
}
 
/* Caller must fill in param @buf which represent struct decom_param */
static int rockchip_decom_ioctl(struct udevice *dev, unsigned long request,
               void *buf)
{
   int ret = -EINVAL;
 
   switch (request) {
   case IOCTL_REQ_START:
       ret = rockchip_decom_start(dev, buf);
       break;
   case IOCTL_REQ_POLL:
       ret = rockchip_decom_done_poll(dev);
       break;
   case IOCTL_REQ_STOP:
       ret = rockchip_decom_stop(dev);
       break;
   case IOCTL_REQ_CAPABILITY:
       ret = rockchip_decom_capability(buf);
       break;
   case IOCTL_REQ_DATA_SIZE:
       ret = rockchip_decom_data_size(dev, buf);
       break;
   default:
       printf("Unsupported ioctl: %ld\n", (ulong)request);
       break;
   }
 
   return ret;
}
 
static const struct misc_ops rockchip_decom_ops = {
   .ioctl = rockchip_decom_ioctl,
};
 
static int rockchip_decom_ofdata_to_platdata(struct udevice *dev)
{
   struct rockchip_decom_priv *priv = dev_get_priv(dev);
 
   priv->base = dev_read_addr_ptr(dev);
   if (!priv->base)
       return -ENOENT;
 
   priv->cached = dev_read_u32_default(dev, "data-cached", 0);
 
   return 0;
}
 
static int rockchip_decom_probe(struct udevice *dev)
{
   struct rockchip_decom_priv *priv = dev_get_priv(dev);
   int ret;
 
#if CONFIG_IS_ENABLED(DM_RESET)
   ret = reset_get_by_name(dev, "dresetn", &priv->rst);
   if (ret) {
       debug("reset_get_by_name() failed: %d\n", ret);
       return ret;
   }
#endif
 
   ret = clk_get_by_index(dev, 1, &priv->dclk);
   if (ret < 0)
       return ret;
 
   ret = clk_set_rate(&priv->dclk, DCLK_DECOM);
   if (ret < 0)
       return ret;
 
   return 0;
}
 
static const struct udevice_id rockchip_decom_ids[] = {
   { .compatible = "rockchip,hw-decompress" },
   {}
};
 
U_BOOT_DRIVER(rockchip_hw_decompress) = {
   .name = "rockchip_hw_decompress",
   .id = UCLASS_MISC,
   .of_match = rockchip_decom_ids,
   .probe = rockchip_decom_probe,
   .ofdata_to_platdata = rockchip_decom_ofdata_to_platdata,
   .priv_auto_alloc_size = sizeof(struct rockchip_decom_priv),
   .ops = &rockchip_decom_ops,
};