blob: 7dadbb2310c79c0fa8fc2b0a5142b26d5245ebf0 [file] [log] [blame]
Benjamin Chan99eb63b2016-12-21 15:45:26 -05001/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
Alan Kwong9487de22016-01-16 22:06:36 -05002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#define pr_fmt(fmt) "%s: " fmt, __func__
15
16#include <linux/platform_device.h>
17#include <linux/module.h>
18#include <linux/fs.h>
19#include <linux/file.h>
Alan Kwong9487de22016-01-16 22:06:36 -050020#include <linux/delay.h>
21#include <linux/debugfs.h>
22#include <linux/interrupt.h>
23#include <linux/dma-mapping.h>
24#include <linux/dma-buf.h>
25#include <linux/msm_ion.h>
Alan Kwong6ce448d2016-11-24 18:45:20 -080026#include <linux/clk.h>
27#include <linux/clk/qcom.h>
Alan Kwong9487de22016-01-16 22:06:36 -050028
29#include "sde_rotator_core.h"
30#include "sde_rotator_util.h"
31#include "sde_rotator_smmu.h"
32#include "sde_rotator_r3.h"
33#include "sde_rotator_r3_internal.h"
34#include "sde_rotator_r3_hwio.h"
35#include "sde_rotator_r3_debug.h"
36#include "sde_rotator_trace.h"
Benjamin Chan53e3bce2016-08-31 14:43:29 -040037#include "sde_rotator_debug.h"
Alan Kwong9487de22016-01-16 22:06:36 -050038
Benjamin Chan99eb63b2016-12-21 15:45:26 -050039#define RES_UHD (3840*2160)
40
41/* traffic shaping clock ticks = finish_time x 19.2MHz */
42#define TRAFFIC_SHAPE_CLKTICK_14MS 268800
43#define TRAFFIC_SHAPE_CLKTICK_12MS 230400
44
Alan Kwong9487de22016-01-16 22:06:36 -050045/* XIN mapping */
46#define XIN_SSPP 0
47#define XIN_WRITEBACK 1
48
49/* wait for at most 2 vsync for lowest refresh rate (24hz) */
Alan Kwong6bc64622017-02-04 17:36:03 -080050#define KOFF_TIMEOUT (42 * 32)
51
52/* default stream buffer headroom in lines */
53#define DEFAULT_SBUF_HEADROOM 20
Alan Kwong9487de22016-01-16 22:06:36 -050054
55/* Macro for constructing the REGDMA command */
56#define SDE_REGDMA_WRITE(p, off, data) \
57 do { \
Alan Kwong6bc64622017-02-04 17:36:03 -080058 SDEROT_DBG("SDEREG.W:[%s:0x%X] <= 0x%X\n", #off, (off),\
59 (u32)(data));\
Alan Kwong9487de22016-01-16 22:06:36 -050060 *p++ = REGDMA_OP_REGWRITE | \
61 ((off) & REGDMA_ADDR_OFFSET_MASK); \
62 *p++ = (data); \
63 } while (0)
64
65#define SDE_REGDMA_MODIFY(p, off, mask, data) \
66 do { \
Alan Kwong6bc64622017-02-04 17:36:03 -080067 SDEROT_DBG("SDEREG.M:[%s:0x%X] <= 0x%X\n", #off, (off),\
68 (u32)(data));\
Alan Kwong9487de22016-01-16 22:06:36 -050069 *p++ = REGDMA_OP_REGMODIFY | \
70 ((off) & REGDMA_ADDR_OFFSET_MASK); \
71 *p++ = (mask); \
72 *p++ = (data); \
73 } while (0)
74
75#define SDE_REGDMA_BLKWRITE_INC(p, off, len) \
76 do { \
Alan Kwong6bc64622017-02-04 17:36:03 -080077 SDEROT_DBG("SDEREG.B:[%s:0x%X:0x%X]\n", #off, (off),\
78 (u32)(len));\
Alan Kwong9487de22016-01-16 22:06:36 -050079 *p++ = REGDMA_OP_BLKWRITE_INC | \
80 ((off) & REGDMA_ADDR_OFFSET_MASK); \
81 *p++ = (len); \
82 } while (0)
83
84#define SDE_REGDMA_BLKWRITE_DATA(p, data) \
85 do { \
Alan Kwong6bc64622017-02-04 17:36:03 -080086 SDEROT_DBG("SDEREG.I:[:] <= 0x%X\n", (u32)(data));\
Alan Kwong9487de22016-01-16 22:06:36 -050087 *(p) = (data); \
88 (p)++; \
89 } while (0)
90
91/* Macro for directly accessing mapped registers */
92#define SDE_ROTREG_WRITE(base, off, data) \
Alan Kwong6bc64622017-02-04 17:36:03 -080093 do { \
94 SDEROT_DBG("SDEREG.D:[%s:0x%X] <= 0x%X\n", #off, (off)\
95 , (u32)(data));\
96 writel_relaxed(data, (base + (off))); \
97 } while (0)
Alan Kwong9487de22016-01-16 22:06:36 -050098
99#define SDE_ROTREG_READ(base, off) \
100 readl_relaxed(base + (off))
101
Alan Kwong6bc64622017-02-04 17:36:03 -0800102static u32 sde_hw_rotator_v3_inpixfmts[] = {
Alan Kwongda16e442016-08-14 20:47:18 -0400103 SDE_PIX_FMT_XRGB_8888,
104 SDE_PIX_FMT_ARGB_8888,
105 SDE_PIX_FMT_ABGR_8888,
106 SDE_PIX_FMT_RGBA_8888,
107 SDE_PIX_FMT_BGRA_8888,
108 SDE_PIX_FMT_RGBX_8888,
109 SDE_PIX_FMT_BGRX_8888,
110 SDE_PIX_FMT_XBGR_8888,
111 SDE_PIX_FMT_RGBA_5551,
112 SDE_PIX_FMT_ARGB_1555,
113 SDE_PIX_FMT_ABGR_1555,
114 SDE_PIX_FMT_BGRA_5551,
115 SDE_PIX_FMT_BGRX_5551,
116 SDE_PIX_FMT_RGBX_5551,
117 SDE_PIX_FMT_XBGR_1555,
118 SDE_PIX_FMT_XRGB_1555,
119 SDE_PIX_FMT_ARGB_4444,
120 SDE_PIX_FMT_RGBA_4444,
121 SDE_PIX_FMT_BGRA_4444,
122 SDE_PIX_FMT_ABGR_4444,
123 SDE_PIX_FMT_RGBX_4444,
124 SDE_PIX_FMT_XRGB_4444,
125 SDE_PIX_FMT_BGRX_4444,
126 SDE_PIX_FMT_XBGR_4444,
127 SDE_PIX_FMT_RGB_888,
128 SDE_PIX_FMT_BGR_888,
129 SDE_PIX_FMT_RGB_565,
130 SDE_PIX_FMT_BGR_565,
131 SDE_PIX_FMT_Y_CB_CR_H2V2,
132 SDE_PIX_FMT_Y_CR_CB_H2V2,
133 SDE_PIX_FMT_Y_CR_CB_GH2V2,
134 SDE_PIX_FMT_Y_CBCR_H2V2,
135 SDE_PIX_FMT_Y_CRCB_H2V2,
136 SDE_PIX_FMT_Y_CBCR_H1V2,
137 SDE_PIX_FMT_Y_CRCB_H1V2,
138 SDE_PIX_FMT_Y_CBCR_H2V1,
139 SDE_PIX_FMT_Y_CRCB_H2V1,
140 SDE_PIX_FMT_YCBYCR_H2V1,
141 SDE_PIX_FMT_Y_CBCR_H2V2_VENUS,
142 SDE_PIX_FMT_Y_CRCB_H2V2_VENUS,
143 SDE_PIX_FMT_RGBA_8888_UBWC,
144 SDE_PIX_FMT_RGBX_8888_UBWC,
145 SDE_PIX_FMT_RGB_565_UBWC,
146 SDE_PIX_FMT_Y_CBCR_H2V2_UBWC,
147 SDE_PIX_FMT_RGBA_1010102,
148 SDE_PIX_FMT_RGBX_1010102,
149 SDE_PIX_FMT_ARGB_2101010,
150 SDE_PIX_FMT_XRGB_2101010,
151 SDE_PIX_FMT_BGRA_1010102,
152 SDE_PIX_FMT_BGRX_1010102,
153 SDE_PIX_FMT_ABGR_2101010,
154 SDE_PIX_FMT_XBGR_2101010,
155 SDE_PIX_FMT_RGBA_1010102_UBWC,
156 SDE_PIX_FMT_RGBX_1010102_UBWC,
157 SDE_PIX_FMT_Y_CBCR_H2V2_P010,
158 SDE_PIX_FMT_Y_CBCR_H2V2_TP10,
159 SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC,
160};
161
Alan Kwong6bc64622017-02-04 17:36:03 -0800162static u32 sde_hw_rotator_v3_outpixfmts[] = {
Alan Kwongda16e442016-08-14 20:47:18 -0400163 SDE_PIX_FMT_XRGB_8888,
164 SDE_PIX_FMT_ARGB_8888,
165 SDE_PIX_FMT_ABGR_8888,
166 SDE_PIX_FMT_RGBA_8888,
167 SDE_PIX_FMT_BGRA_8888,
168 SDE_PIX_FMT_RGBX_8888,
169 SDE_PIX_FMT_BGRX_8888,
170 SDE_PIX_FMT_XBGR_8888,
171 SDE_PIX_FMT_RGBA_5551,
172 SDE_PIX_FMT_ARGB_1555,
173 SDE_PIX_FMT_ABGR_1555,
174 SDE_PIX_FMT_BGRA_5551,
175 SDE_PIX_FMT_BGRX_5551,
176 SDE_PIX_FMT_RGBX_5551,
177 SDE_PIX_FMT_XBGR_1555,
178 SDE_PIX_FMT_XRGB_1555,
179 SDE_PIX_FMT_ARGB_4444,
180 SDE_PIX_FMT_RGBA_4444,
181 SDE_PIX_FMT_BGRA_4444,
182 SDE_PIX_FMT_ABGR_4444,
183 SDE_PIX_FMT_RGBX_4444,
184 SDE_PIX_FMT_XRGB_4444,
185 SDE_PIX_FMT_BGRX_4444,
186 SDE_PIX_FMT_XBGR_4444,
187 SDE_PIX_FMT_RGB_888,
188 SDE_PIX_FMT_BGR_888,
189 SDE_PIX_FMT_RGB_565,
190 SDE_PIX_FMT_BGR_565,
191 /* SDE_PIX_FMT_Y_CB_CR_H2V2 */
192 /* SDE_PIX_FMT_Y_CR_CB_H2V2 */
193 /* SDE_PIX_FMT_Y_CR_CB_GH2V2 */
194 SDE_PIX_FMT_Y_CBCR_H2V2,
195 SDE_PIX_FMT_Y_CRCB_H2V2,
196 SDE_PIX_FMT_Y_CBCR_H1V2,
197 SDE_PIX_FMT_Y_CRCB_H1V2,
198 SDE_PIX_FMT_Y_CBCR_H2V1,
199 SDE_PIX_FMT_Y_CRCB_H2V1,
200 /* SDE_PIX_FMT_YCBYCR_H2V1 */
201 SDE_PIX_FMT_Y_CBCR_H2V2_VENUS,
202 SDE_PIX_FMT_Y_CRCB_H2V2_VENUS,
203 SDE_PIX_FMT_RGBA_8888_UBWC,
204 SDE_PIX_FMT_RGBX_8888_UBWC,
205 SDE_PIX_FMT_RGB_565_UBWC,
206 SDE_PIX_FMT_Y_CBCR_H2V2_UBWC,
207 SDE_PIX_FMT_RGBA_1010102,
208 SDE_PIX_FMT_RGBX_1010102,
209 /* SDE_PIX_FMT_ARGB_2101010 */
210 /* SDE_PIX_FMT_XRGB_2101010 */
211 SDE_PIX_FMT_BGRA_1010102,
212 SDE_PIX_FMT_BGRX_1010102,
213 /* SDE_PIX_FMT_ABGR_2101010 */
214 /* SDE_PIX_FMT_XBGR_2101010 */
215 SDE_PIX_FMT_RGBA_1010102_UBWC,
216 SDE_PIX_FMT_RGBX_1010102_UBWC,
217 SDE_PIX_FMT_Y_CBCR_H2V2_P010,
218 SDE_PIX_FMT_Y_CBCR_H2V2_TP10,
219 SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC,
220};
221
Alan Kwong6bc64622017-02-04 17:36:03 -0800222static u32 sde_hw_rotator_v4_inpixfmts[] = {
223 SDE_PIX_FMT_XRGB_8888,
224 SDE_PIX_FMT_ARGB_8888,
225 SDE_PIX_FMT_ABGR_8888,
226 SDE_PIX_FMT_RGBA_8888,
227 SDE_PIX_FMT_BGRA_8888,
228 SDE_PIX_FMT_RGBX_8888,
229 SDE_PIX_FMT_BGRX_8888,
230 SDE_PIX_FMT_XBGR_8888,
231 SDE_PIX_FMT_RGBA_5551,
232 SDE_PIX_FMT_ARGB_1555,
233 SDE_PIX_FMT_ABGR_1555,
234 SDE_PIX_FMT_BGRA_5551,
235 SDE_PIX_FMT_BGRX_5551,
236 SDE_PIX_FMT_RGBX_5551,
237 SDE_PIX_FMT_XBGR_1555,
238 SDE_PIX_FMT_XRGB_1555,
239 SDE_PIX_FMT_ARGB_4444,
240 SDE_PIX_FMT_RGBA_4444,
241 SDE_PIX_FMT_BGRA_4444,
242 SDE_PIX_FMT_ABGR_4444,
243 SDE_PIX_FMT_RGBX_4444,
244 SDE_PIX_FMT_XRGB_4444,
245 SDE_PIX_FMT_BGRX_4444,
246 SDE_PIX_FMT_XBGR_4444,
247 SDE_PIX_FMT_RGB_888,
248 SDE_PIX_FMT_BGR_888,
249 SDE_PIX_FMT_RGB_565,
250 SDE_PIX_FMT_BGR_565,
251 SDE_PIX_FMT_Y_CB_CR_H2V2,
252 SDE_PIX_FMT_Y_CR_CB_H2V2,
253 SDE_PIX_FMT_Y_CR_CB_GH2V2,
254 SDE_PIX_FMT_Y_CBCR_H2V2,
255 SDE_PIX_FMT_Y_CRCB_H2V2,
256 SDE_PIX_FMT_Y_CBCR_H1V2,
257 SDE_PIX_FMT_Y_CRCB_H1V2,
258 SDE_PIX_FMT_Y_CBCR_H2V1,
259 SDE_PIX_FMT_Y_CRCB_H2V1,
260 SDE_PIX_FMT_YCBYCR_H2V1,
261 SDE_PIX_FMT_Y_CBCR_H2V2_VENUS,
262 SDE_PIX_FMT_Y_CRCB_H2V2_VENUS,
263 SDE_PIX_FMT_RGBA_8888_UBWC,
264 SDE_PIX_FMT_RGBX_8888_UBWC,
265 SDE_PIX_FMT_RGB_565_UBWC,
266 SDE_PIX_FMT_Y_CBCR_H2V2_UBWC,
267 SDE_PIX_FMT_RGBA_1010102,
268 SDE_PIX_FMT_RGBX_1010102,
269 SDE_PIX_FMT_ARGB_2101010,
270 SDE_PIX_FMT_XRGB_2101010,
271 SDE_PIX_FMT_BGRA_1010102,
272 SDE_PIX_FMT_BGRX_1010102,
273 SDE_PIX_FMT_ABGR_2101010,
274 SDE_PIX_FMT_XBGR_2101010,
275 SDE_PIX_FMT_RGBA_1010102_UBWC,
276 SDE_PIX_FMT_RGBX_1010102_UBWC,
277 SDE_PIX_FMT_Y_CBCR_H2V2_P010,
278 SDE_PIX_FMT_Y_CBCR_H2V2_TP10,
279 SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC,
280 SDE_PIX_FMT_Y_CBCR_H2V2_TILE,
281 SDE_PIX_FMT_Y_CRCB_H2V2_TILE,
282 SDE_PIX_FMT_XRGB_8888_TILE,
283 SDE_PIX_FMT_ARGB_8888_TILE,
284 SDE_PIX_FMT_ABGR_8888_TILE,
285 SDE_PIX_FMT_XBGR_8888_TILE,
286 SDE_PIX_FMT_RGBA_8888_TILE,
287 SDE_PIX_FMT_BGRA_8888_TILE,
288 SDE_PIX_FMT_RGBX_8888_TILE,
289 SDE_PIX_FMT_BGRX_8888_TILE,
290 SDE_PIX_FMT_RGBA_1010102_TILE,
291 SDE_PIX_FMT_RGBX_1010102_TILE,
292 SDE_PIX_FMT_ARGB_2101010_TILE,
293 SDE_PIX_FMT_XRGB_2101010_TILE,
294 SDE_PIX_FMT_BGRA_1010102_TILE,
295 SDE_PIX_FMT_BGRX_1010102_TILE,
296 SDE_PIX_FMT_ABGR_2101010_TILE,
297 SDE_PIX_FMT_XBGR_2101010_TILE,
298};
299
300static u32 sde_hw_rotator_v4_outpixfmts[] = {
301 SDE_PIX_FMT_XRGB_8888,
302 SDE_PIX_FMT_ARGB_8888,
303 SDE_PIX_FMT_ABGR_8888,
304 SDE_PIX_FMT_RGBA_8888,
305 SDE_PIX_FMT_BGRA_8888,
306 SDE_PIX_FMT_RGBX_8888,
307 SDE_PIX_FMT_BGRX_8888,
308 SDE_PIX_FMT_XBGR_8888,
309 SDE_PIX_FMT_RGBA_5551,
310 SDE_PIX_FMT_ARGB_1555,
311 SDE_PIX_FMT_ABGR_1555,
312 SDE_PIX_FMT_BGRA_5551,
313 SDE_PIX_FMT_BGRX_5551,
314 SDE_PIX_FMT_RGBX_5551,
315 SDE_PIX_FMT_XBGR_1555,
316 SDE_PIX_FMT_XRGB_1555,
317 SDE_PIX_FMT_ARGB_4444,
318 SDE_PIX_FMT_RGBA_4444,
319 SDE_PIX_FMT_BGRA_4444,
320 SDE_PIX_FMT_ABGR_4444,
321 SDE_PIX_FMT_RGBX_4444,
322 SDE_PIX_FMT_XRGB_4444,
323 SDE_PIX_FMT_BGRX_4444,
324 SDE_PIX_FMT_XBGR_4444,
325 SDE_PIX_FMT_RGB_888,
326 SDE_PIX_FMT_BGR_888,
327 SDE_PIX_FMT_RGB_565,
328 SDE_PIX_FMT_BGR_565,
329 /* SDE_PIX_FMT_Y_CB_CR_H2V2 */
330 /* SDE_PIX_FMT_Y_CR_CB_H2V2 */
331 /* SDE_PIX_FMT_Y_CR_CB_GH2V2 */
332 SDE_PIX_FMT_Y_CBCR_H2V2,
333 SDE_PIX_FMT_Y_CRCB_H2V2,
334 SDE_PIX_FMT_Y_CBCR_H1V2,
335 SDE_PIX_FMT_Y_CRCB_H1V2,
336 SDE_PIX_FMT_Y_CBCR_H2V1,
337 SDE_PIX_FMT_Y_CRCB_H2V1,
338 /* SDE_PIX_FMT_YCBYCR_H2V1 */
339 SDE_PIX_FMT_Y_CBCR_H2V2_VENUS,
340 SDE_PIX_FMT_Y_CRCB_H2V2_VENUS,
341 SDE_PIX_FMT_RGBA_8888_UBWC,
342 SDE_PIX_FMT_RGBX_8888_UBWC,
343 SDE_PIX_FMT_RGB_565_UBWC,
344 SDE_PIX_FMT_Y_CBCR_H2V2_UBWC,
345 SDE_PIX_FMT_RGBA_1010102,
346 SDE_PIX_FMT_RGBX_1010102,
347 /* SDE_PIX_FMT_ARGB_2101010 */
348 /* SDE_PIX_FMT_XRGB_2101010 */
349 SDE_PIX_FMT_BGRA_1010102,
350 SDE_PIX_FMT_BGRX_1010102,
351 /* SDE_PIX_FMT_ABGR_2101010 */
352 /* SDE_PIX_FMT_XBGR_2101010 */
353 SDE_PIX_FMT_RGBA_1010102_UBWC,
354 SDE_PIX_FMT_RGBX_1010102_UBWC,
355 SDE_PIX_FMT_Y_CBCR_H2V2_P010,
356 SDE_PIX_FMT_Y_CBCR_H2V2_TP10,
357 SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC,
358 SDE_PIX_FMT_Y_CBCR_H2V2_TILE,
359 SDE_PIX_FMT_Y_CRCB_H2V2_TILE,
360 SDE_PIX_FMT_XRGB_8888_TILE,
361 SDE_PIX_FMT_ARGB_8888_TILE,
362 SDE_PIX_FMT_ABGR_8888_TILE,
363 SDE_PIX_FMT_XBGR_8888_TILE,
364 SDE_PIX_FMT_RGBA_8888_TILE,
365 SDE_PIX_FMT_BGRA_8888_TILE,
366 SDE_PIX_FMT_RGBX_8888_TILE,
367 SDE_PIX_FMT_BGRX_8888_TILE,
368 SDE_PIX_FMT_RGBA_1010102_TILE,
369 SDE_PIX_FMT_RGBX_1010102_TILE,
370 SDE_PIX_FMT_ARGB_2101010_TILE,
371 SDE_PIX_FMT_XRGB_2101010_TILE,
372 SDE_PIX_FMT_BGRA_1010102_TILE,
373 SDE_PIX_FMT_BGRX_1010102_TILE,
374 SDE_PIX_FMT_ABGR_2101010_TILE,
375 SDE_PIX_FMT_XBGR_2101010_TILE,
376};
377
Benjamin Chan53e3bce2016-08-31 14:43:29 -0400378static struct sde_rot_vbif_debug_bus nrt_vbif_dbg_bus_r3[] = {
379 {0x214, 0x21c, 16, 1, 0x10}, /* arb clients */
380 {0x214, 0x21c, 0, 12, 0x13}, /* xin blocks - axi side */
381 {0x21c, 0x214, 0, 12, 0xc}, /* xin blocks - clock side */
382};
383
384static struct sde_rot_regdump sde_rot_r3_regdump[] = {
385 { "SDEROT_ROTTOP", SDE_ROT_ROTTOP_OFFSET, 0x100, SDE_ROT_REGDUMP_READ },
386 { "SDEROT_SSPP", SDE_ROT_SSPP_OFFSET, 0x200, SDE_ROT_REGDUMP_READ },
387 { "SDEROT_WB", SDE_ROT_WB_OFFSET, 0x300, SDE_ROT_REGDUMP_READ },
388 { "SDEROT_REGDMA_CSR", SDE_ROT_REGDMA_OFFSET, 0x100,
389 SDE_ROT_REGDUMP_READ },
390 /*
391 * Need to perform a SW reset to REGDMA in order to access the
392 * REGDMA RAM especially if REGDMA is waiting for Rotator IDLE.
393 * REGDMA RAM should be dump at last.
394 */
395 { "SDEROT_REGDMA_RESET", ROTTOP_SW_RESET_OVERRIDE, 1,
396 SDE_ROT_REGDUMP_WRITE },
397 { "SDEROT_REGDMA_RAM", SDE_ROT_REGDMA_RAM_OFFSET, 0x2000,
398 SDE_ROT_REGDUMP_READ },
Benjamin Chan59a06052017-01-12 18:06:03 -0500399 { "SDEROT_VBIF_NRT", SDE_ROT_VBIF_NRT_OFFSET, 0x590,
400 SDE_ROT_REGDUMP_VBIF },
Benjamin Chan53e3bce2016-08-31 14:43:29 -0400401};
402
Alan Kwong818b7fc2016-07-24 22:07:41 -0400403/* Invalid software timestamp value for initialization */
404#define SDE_REGDMA_SWTS_INVALID (~0)
405
406/**
407 * sde_hw_rotator_elapsed_swts - Find difference of 2 software timestamps
408 * @ts_curr: current software timestamp
409 * @ts_prev: previous software timestamp
410 * @return: the amount ts_curr is ahead of ts_prev
411 */
412static int sde_hw_rotator_elapsed_swts(u32 ts_curr, u32 ts_prev)
413{
414 u32 diff = (ts_curr - ts_prev) & SDE_REGDMA_SWTS_MASK;
415
416 return sign_extend32(diff, (SDE_REGDMA_SWTS_SHIFT - 1));
417}
418
419/**
420 * sde_hw_rotator_pending_swts - Check if the given context is still pending
421 * @rot: Pointer to hw rotator
422 * @ctx: Pointer to rotator context
423 * @pswts: Pointer to returned reference software timestamp, optional
424 * @return: true if context has pending requests
425 */
426static int sde_hw_rotator_pending_swts(struct sde_hw_rotator *rot,
427 struct sde_hw_rotator_context *ctx, u32 *pswts)
428{
429 u32 swts;
430 int ts_diff;
431 bool pending;
432
433 if (ctx->last_regdma_timestamp == SDE_REGDMA_SWTS_INVALID)
434 swts = SDE_ROTREG_READ(rot->mdss_base, REGDMA_TIMESTAMP_REG);
435 else
436 swts = ctx->last_regdma_timestamp;
437
438 if (ctx->q_id == ROT_QUEUE_LOW_PRIORITY)
439 swts >>= SDE_REGDMA_SWTS_SHIFT;
440
441 swts &= SDE_REGDMA_SWTS_MASK;
442
443 ts_diff = sde_hw_rotator_elapsed_swts(ctx->timestamp, swts);
444
445 if (pswts)
446 *pswts = swts;
447
448 pending = (ts_diff > 0) ? true : false;
449
450 SDEROT_DBG("ts:0x%x, queue_id:%d, swts:0x%x, pending:%d\n",
451 ctx->timestamp, ctx->q_id, swts, pending);
Benjamin Chan0f9e61d2016-09-16 16:01:09 -0400452 SDEROT_EVTLOG(ctx->timestamp, swts, ctx->q_id, ts_diff);
Alan Kwong818b7fc2016-07-24 22:07:41 -0400453 return pending;
454}
455
456/**
Alan Kwong6bc64622017-02-04 17:36:03 -0800457 * sde_hw_rotator_update_swts - update software timestamp with given value
458 * @rot: Pointer to hw rotator
459 * @ctx: Pointer to rotator contxt
460 * @swts: new software timestamp
461 * @return: new combined swts
462 */
463static u32 sde_hw_rotator_update_swts(struct sde_hw_rotator *rot,
464 struct sde_hw_rotator_context *ctx, u32 swts)
465{
466 u32 mask = SDE_REGDMA_SWTS_MASK;
467
468 swts &= SDE_REGDMA_SWTS_MASK;
469 if (ctx->q_id == ROT_QUEUE_LOW_PRIORITY) {
470 swts <<= SDE_REGDMA_SWTS_SHIFT;
471 mask <<= SDE_REGDMA_SWTS_SHIFT;
472 }
473
474 swts |= (SDE_ROTREG_READ(rot->mdss_base, REGDMA_TIMESTAMP_REG) & ~mask);
475 SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_TIMESTAMP_REG, swts);
476
477 return swts;
478}
479
480/**
Alan Kwong818b7fc2016-07-24 22:07:41 -0400481 * sde_hw_rotator_enable_irq - Enable hw rotator interrupt with ref. count
482 * Also, clear rotator/regdma irq status.
483 * @rot: Pointer to hw rotator
484 */
485static void sde_hw_rotator_enable_irq(struct sde_hw_rotator *rot)
486{
487 SDEROT_DBG("irq_num:%d enabled:%d\n", rot->irq_num,
488 atomic_read(&rot->irq_enabled));
489
490 if (!atomic_read(&rot->irq_enabled)) {
491 if (rot->mode == ROT_REGDMA_OFF)
492 SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_CLEAR,
493 ROT_DONE_MASK);
494 else
495 SDE_ROTREG_WRITE(rot->mdss_base,
496 REGDMA_CSR_REGDMA_INT_CLEAR, REGDMA_INT_MASK);
497
498 enable_irq(rot->irq_num);
499 }
500 atomic_inc(&rot->irq_enabled);
501}
502
503/**
504 * sde_hw_rotator_disable_irq - Disable hw rotator interrupt with ref. count
505 * Also, clear rotator/regdma irq enable masks.
506 * @rot: Pointer to hw rotator
507 */
508static void sde_hw_rotator_disable_irq(struct sde_hw_rotator *rot)
509{
510 SDEROT_DBG("irq_num:%d enabled:%d\n", rot->irq_num,
511 atomic_read(&rot->irq_enabled));
512
513 if (!atomic_read(&rot->irq_enabled)) {
514 SDEROT_ERR("irq %d is already disabled\n", rot->irq_num);
515 return;
516 }
517
518 if (!atomic_dec_return(&rot->irq_enabled)) {
519 if (rot->mode == ROT_REGDMA_OFF)
520 SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_EN, 0);
521 else
522 SDE_ROTREG_WRITE(rot->mdss_base,
523 REGDMA_CSR_REGDMA_INT_EN, 0);
524 /* disable irq after last pending irq is handled, if any */
525 synchronize_irq(rot->irq_num);
526 disable_irq_nosync(rot->irq_num);
527 }
528}
529
530/**
531 * sde_hw_rotator_dump_status - Dump hw rotator status on error
532 * @rot: Pointer to hw rotator
533 */
534static void sde_hw_rotator_dump_status(struct sde_hw_rotator *rot)
535{
Benjamin Chan1b94f952017-01-23 17:42:30 -0500536 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
537
Alan Kwong818b7fc2016-07-24 22:07:41 -0400538 SDEROT_ERR(
539 "op_mode = %x, int_en = %x, int_status = %x\n",
540 SDE_ROTREG_READ(rot->mdss_base,
541 REGDMA_CSR_REGDMA_OP_MODE),
542 SDE_ROTREG_READ(rot->mdss_base,
543 REGDMA_CSR_REGDMA_INT_EN),
544 SDE_ROTREG_READ(rot->mdss_base,
545 REGDMA_CSR_REGDMA_INT_STATUS));
546
547 SDEROT_ERR(
548 "ts = %x, q0_status = %x, q1_status = %x, block_status = %x\n",
549 SDE_ROTREG_READ(rot->mdss_base,
550 REGDMA_TIMESTAMP_REG),
551 SDE_ROTREG_READ(rot->mdss_base,
552 REGDMA_CSR_REGDMA_QUEUE_0_STATUS),
553 SDE_ROTREG_READ(rot->mdss_base,
554 REGDMA_CSR_REGDMA_QUEUE_1_STATUS),
555 SDE_ROTREG_READ(rot->mdss_base,
556 REGDMA_CSR_REGDMA_BLOCK_STATUS));
557
558 SDEROT_ERR(
559 "invalid_cmd_offset = %x, fsm_state = %x\n",
560 SDE_ROTREG_READ(rot->mdss_base,
561 REGDMA_CSR_REGDMA_INVALID_CMD_RAM_OFFSET),
562 SDE_ROTREG_READ(rot->mdss_base,
563 REGDMA_CSR_REGDMA_FSM_STATE));
Benjamin Chan59a06052017-01-12 18:06:03 -0500564
565 SDEROT_ERR(
566 "UBWC decode status = %x, UBWC encode status = %x\n",
567 SDE_ROTREG_READ(rot->mdss_base, ROT_SSPP_UBWC_ERROR_STATUS),
568 SDE_ROTREG_READ(rot->mdss_base, ROT_WB_UBWC_ERROR_STATUS));
Benjamin Chan1b94f952017-01-23 17:42:30 -0500569
570 SDEROT_ERR("VBIF XIN HALT status = %x VBIF AXI HALT status = %x\n",
571 SDE_VBIF_READ(mdata, MMSS_VBIF_XIN_HALT_CTRL1),
572 SDE_VBIF_READ(mdata, MMSS_VBIF_AXI_HALT_CTRL1));
Alan Kwong6bc64622017-02-04 17:36:03 -0800573
574 SDEROT_ERR(
575 "sbuf_status_plane0 = %x, sbuf_status_plane1 = %x\n",
576 SDE_ROTREG_READ(rot->mdss_base,
577 ROT_WB_SBUF_STATUS_PLANE0),
578 SDE_ROTREG_READ(rot->mdss_base,
579 ROT_WB_SBUF_STATUS_PLANE1));
Alan Kwong818b7fc2016-07-24 22:07:41 -0400580}
581
Alan Kwong9487de22016-01-16 22:06:36 -0500582/**
583 * sde_hw_rotator_get_ctx(): Retrieve rotator context from rotator HW based
584 * on provided session_id. Each rotator has a different session_id.
585 */
586static struct sde_hw_rotator_context *sde_hw_rotator_get_ctx(
587 struct sde_hw_rotator *rot, u32 session_id,
588 enum sde_rot_queue_prio q_id)
589{
590 int i;
591 struct sde_hw_rotator_context *ctx = NULL;
592
593 for (i = 0; i < SDE_HW_ROT_REGDMA_TOTAL_CTX; i++) {
594 ctx = rot->rotCtx[q_id][i];
595
596 if (ctx && (ctx->session_id == session_id)) {
597 SDEROT_DBG(
598 "rotCtx sloti[%d][%d] ==> ctx:%p | session-id:%d\n",
599 q_id, i, ctx, ctx->session_id);
600 return ctx;
601 }
602 }
603
604 return NULL;
605}
606
607/*
608 * sde_hw_rotator_map_vaddr - map the debug buffer to kernel space
609 * @dbgbuf: Pointer to debug buffer
610 * @buf: Pointer to layer buffer structure
611 * @data: Pointer to h/w mapped buffer structure
612 */
613static void sde_hw_rotator_map_vaddr(struct sde_dbg_buf *dbgbuf,
614 struct sde_layer_buffer *buf, struct sde_mdp_data *data)
615{
616 dbgbuf->dmabuf = data->p[0].srcp_dma_buf;
617 dbgbuf->buflen = data->p[0].srcp_dma_buf->size;
618
619 dbgbuf->vaddr = NULL;
620 dbgbuf->width = buf->width;
621 dbgbuf->height = buf->height;
622
623 if (dbgbuf->dmabuf && (dbgbuf->buflen > 0)) {
Alan Kwong6ce448d2016-11-24 18:45:20 -0800624 dma_buf_begin_cpu_access(dbgbuf->dmabuf, DMA_FROM_DEVICE);
Alan Kwong9487de22016-01-16 22:06:36 -0500625 dbgbuf->vaddr = dma_buf_kmap(dbgbuf->dmabuf, 0);
626 SDEROT_DBG("vaddr mapping: 0x%p/%ld w:%d/h:%d\n",
627 dbgbuf->vaddr, dbgbuf->buflen,
628 dbgbuf->width, dbgbuf->height);
629 }
630}
631
632/*
633 * sde_hw_rotator_unmap_vaddr - unmap the debug buffer from kernel space
634 * @dbgbuf: Pointer to debug buffer
635 */
636static void sde_hw_rotator_unmap_vaddr(struct sde_dbg_buf *dbgbuf)
637{
638 if (dbgbuf->vaddr) {
639 dma_buf_kunmap(dbgbuf->dmabuf, 0, dbgbuf->vaddr);
Alan Kwong6ce448d2016-11-24 18:45:20 -0800640 dma_buf_end_cpu_access(dbgbuf->dmabuf, DMA_FROM_DEVICE);
Alan Kwong9487de22016-01-16 22:06:36 -0500641 }
642
643 dbgbuf->vaddr = NULL;
644 dbgbuf->dmabuf = NULL;
645 dbgbuf->buflen = 0;
646 dbgbuf->width = 0;
647 dbgbuf->height = 0;
648}
649
650/*
651 * sde_hw_rotator_setup_timestamp_packet - setup timestamp writeback command
652 * @ctx: Pointer to rotator context
653 * @mask: Bit mask location of the timestamp
654 * @swts: Software timestamp
655 */
656static void sde_hw_rotator_setup_timestamp_packet(
657 struct sde_hw_rotator_context *ctx, u32 mask, u32 swts)
658{
659 u32 *wrptr;
660
661 wrptr = sde_hw_rotator_get_regdma_segment(ctx);
662
663 /*
664 * Create a dummy packet write out to 1 location for timestamp
665 * generation.
666 */
667 SDE_REGDMA_BLKWRITE_INC(wrptr, ROT_SSPP_SRC_SIZE, 6);
668 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0x00010001);
669 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0);
670 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0);
671 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0x00010001);
672 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0);
673 SDE_REGDMA_BLKWRITE_DATA(wrptr, ctx->ts_addr);
674 SDE_REGDMA_WRITE(wrptr, ROT_SSPP_SRC_YSTRIDE0, 4);
675 SDE_REGDMA_BLKWRITE_INC(wrptr, ROT_SSPP_SRC_FORMAT, 4);
676 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0x004037FF);
677 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0x03020100);
678 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0x80000000);
679 SDE_REGDMA_BLKWRITE_DATA(wrptr, ctx->timestamp);
Benjamin Chan15c93d82016-08-29 10:04:22 -0400680 /*
681 * Must clear secure buffer setting for SW timestamp because
682 * SW timstamp buffer allocation is always non-secure region.
683 */
684 if (ctx->is_secure) {
685 SDE_REGDMA_WRITE(wrptr, ROT_SSPP_SRC_ADDR_SW_STATUS, 0);
686 SDE_REGDMA_WRITE(wrptr, ROT_WB_DST_ADDR_SW_STATUS, 0);
687 }
Alan Kwong9487de22016-01-16 22:06:36 -0500688 SDE_REGDMA_BLKWRITE_INC(wrptr, ROT_WB_DST_FORMAT, 4);
689 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0x000037FF);
690 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0);
691 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0x03020100);
692 SDE_REGDMA_BLKWRITE_DATA(wrptr, ctx->ts_addr);
693 SDE_REGDMA_WRITE(wrptr, ROT_WB_DST_YSTRIDE0, 4);
694 SDE_REGDMA_WRITE(wrptr, ROT_WB_OUT_SIZE, 0x00010001);
695 SDE_REGDMA_WRITE(wrptr, ROT_WB_OUT_IMG_SIZE, 0x00010001);
696 SDE_REGDMA_WRITE(wrptr, ROT_WB_OUT_XY, 0);
697 SDE_REGDMA_WRITE(wrptr, ROTTOP_DNSC, 0);
698 SDE_REGDMA_WRITE(wrptr, ROTTOP_OP_MODE, 1);
699 SDE_REGDMA_MODIFY(wrptr, REGDMA_TIMESTAMP_REG, mask, swts);
700 SDE_REGDMA_WRITE(wrptr, ROTTOP_START_CTRL, 1);
701
702 sde_hw_rotator_put_regdma_segment(ctx, wrptr);
703}
704
705/*
706 * sde_hw_rotator_setup_fetchengine - setup fetch engine
707 * @ctx: Pointer to rotator context
708 * @queue_id: Priority queue identifier
709 * @cfg: Fetch configuration
710 * @danger_lut: real-time QoS LUT for danger setting (not used)
711 * @safe_lut: real-time QoS LUT for safe setting (not used)
Benjamin Chanfb6faa32016-08-16 17:21:01 -0400712 * @dnsc_factor_w: downscale factor for width
713 * @dnsc_factor_h: downscale factor for height
Alan Kwong9487de22016-01-16 22:06:36 -0500714 * @flags: Control flag
715 */
716static void sde_hw_rotator_setup_fetchengine(struct sde_hw_rotator_context *ctx,
717 enum sde_rot_queue_prio queue_id,
718 struct sde_hw_rot_sspp_cfg *cfg, u32 danger_lut, u32 safe_lut,
Benjamin Chanfb6faa32016-08-16 17:21:01 -0400719 u32 dnsc_factor_w, u32 dnsc_factor_h, u32 flags)
Alan Kwong9487de22016-01-16 22:06:36 -0500720{
721 struct sde_hw_rotator *rot = ctx->rot;
722 struct sde_mdp_format_params *fmt;
723 struct sde_mdp_data *data;
Benjamin Chanfb6faa32016-08-16 17:21:01 -0400724 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
Alan Kwong9487de22016-01-16 22:06:36 -0500725 u32 *wrptr;
726 u32 opmode = 0;
727 u32 chroma_samp = 0;
728 u32 src_format = 0;
729 u32 unpack = 0;
730 u32 width = cfg->img_width;
731 u32 height = cfg->img_height;
732 u32 fetch_blocksize = 0;
733 int i;
734
735 if (ctx->rot->mode == ROT_REGDMA_ON) {
736 SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_INT_EN,
737 REGDMA_INT_MASK);
738 SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_OP_MODE,
739 REGDMA_EN);
740 }
741
742 wrptr = sde_hw_rotator_get_regdma_segment(ctx);
743
744 /* source image setup */
745 if ((flags & SDE_ROT_FLAG_DEINTERLACE)
746 && !(flags & SDE_ROT_FLAG_SOURCE_ROTATED_90)) {
747 for (i = 0; i < cfg->src_plane.num_planes; i++)
748 cfg->src_plane.ystride[i] *= 2;
749 width *= 2;
750 height /= 2;
751 }
752
753 /*
754 * REGDMA BLK write from SRC_SIZE to OP_MODE, total 15 registers
755 */
756 SDE_REGDMA_BLKWRITE_INC(wrptr, ROT_SSPP_SRC_SIZE, 15);
757
758 /* SRC_SIZE, SRC_IMG_SIZE, SRC_XY, OUT_SIZE, OUT_XY */
759 SDE_REGDMA_BLKWRITE_DATA(wrptr,
760 cfg->src_rect->w | (cfg->src_rect->h << 16));
761 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0); /* SRC_IMG_SIZE unused */
762 SDE_REGDMA_BLKWRITE_DATA(wrptr,
763 cfg->src_rect->x | (cfg->src_rect->y << 16));
764 SDE_REGDMA_BLKWRITE_DATA(wrptr,
765 cfg->src_rect->w | (cfg->src_rect->h << 16));
766 SDE_REGDMA_BLKWRITE_DATA(wrptr,
767 cfg->src_rect->x | (cfg->src_rect->y << 16));
768
769 /* SRC_ADDR [0-3], SRC_YSTRIDE [0-1] */
770 data = cfg->data;
771 for (i = 0; i < SDE_ROT_MAX_PLANES; i++)
772 SDE_REGDMA_BLKWRITE_DATA(wrptr, data->p[i].addr);
773 SDE_REGDMA_BLKWRITE_DATA(wrptr, cfg->src_plane.ystride[0] |
774 (cfg->src_plane.ystride[1] << 16));
775 SDE_REGDMA_BLKWRITE_DATA(wrptr, cfg->src_plane.ystride[2] |
776 (cfg->src_plane.ystride[3] << 16));
777
778 /* UNUSED, write 0 */
779 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0);
780
781 /* setup source format */
782 fmt = cfg->fmt;
783
784 chroma_samp = fmt->chroma_sample;
785 if (flags & SDE_ROT_FLAG_SOURCE_ROTATED_90) {
786 if (chroma_samp == SDE_MDP_CHROMA_H2V1)
787 chroma_samp = SDE_MDP_CHROMA_H1V2;
788 else if (chroma_samp == SDE_MDP_CHROMA_H1V2)
789 chroma_samp = SDE_MDP_CHROMA_H2V1;
790 }
791
792 src_format = (chroma_samp << 23) |
793 (fmt->fetch_planes << 19) |
794 (fmt->bits[C3_ALPHA] << 6) |
795 (fmt->bits[C2_R_Cr] << 4) |
796 (fmt->bits[C1_B_Cb] << 2) |
797 (fmt->bits[C0_G_Y] << 0);
798
799 if (fmt->alpha_enable &&
800 (fmt->fetch_planes == SDE_MDP_PLANE_INTERLEAVED))
801 src_format |= BIT(8); /* SRCC3_EN */
802
803 src_format |= ((fmt->unpack_count - 1) << 12) |
804 (fmt->unpack_tight << 17) |
805 (fmt->unpack_align_msb << 18) |
806 ((fmt->bpp - 1) << 9) |
807 ((fmt->frame_format & 3) << 30);
808
809 if (flags & SDE_ROT_FLAG_ROT_90)
810 src_format |= BIT(11); /* ROT90 */
811
812 if (sde_mdp_is_ubwc_format(fmt))
813 opmode |= BIT(0); /* BWC_DEC_EN */
814
815 /* if this is YUV pixel format, enable CSC */
816 if (sde_mdp_is_yuv_format(fmt))
817 src_format |= BIT(15); /* SRC_COLOR_SPACE */
818
819 if (fmt->pixel_mode == SDE_MDP_PIXEL_10BIT)
820 src_format |= BIT(14); /* UNPACK_DX_FORMAT */
821
822 /* SRC_FORMAT */
823 SDE_REGDMA_BLKWRITE_DATA(wrptr, src_format);
824
825 /* setup source unpack pattern */
826 unpack = (fmt->element[3] << 24) | (fmt->element[2] << 16) |
827 (fmt->element[1] << 8) | (fmt->element[0] << 0);
828
829 /* SRC_UNPACK_PATTERN */
830 SDE_REGDMA_BLKWRITE_DATA(wrptr, unpack);
831
832 /* setup source op mode */
833 if (flags & SDE_ROT_FLAG_FLIP_LR)
834 opmode |= BIT(13); /* FLIP_MODE L/R horizontal flip */
835 if (flags & SDE_ROT_FLAG_FLIP_UD)
836 opmode |= BIT(14); /* FLIP_MODE U/D vertical flip */
837 opmode |= BIT(31); /* MDSS_MDP_OP_PE_OVERRIDE */
838
839 /* SRC_OP_MODE */
840 SDE_REGDMA_BLKWRITE_DATA(wrptr, opmode);
841
842 /* setup source fetch config, TP10 uses different block size */
Benjamin Chanfb6faa32016-08-16 17:21:01 -0400843 if (test_bit(SDE_CAPS_R3_1P5_DOWNSCALE, mdata->sde_caps_map) &&
844 (dnsc_factor_w == 1) && (dnsc_factor_h == 1)) {
845 if (sde_mdp_is_tp10_format(fmt))
846 fetch_blocksize = SDE_ROT_SSPP_FETCH_BLOCKSIZE_144_EXT;
847 else
848 fetch_blocksize = SDE_ROT_SSPP_FETCH_BLOCKSIZE_192_EXT;
849 } else {
850 if (sde_mdp_is_tp10_format(fmt))
851 fetch_blocksize = SDE_ROT_SSPP_FETCH_BLOCKSIZE_96;
852 else
853 fetch_blocksize = SDE_ROT_SSPP_FETCH_BLOCKSIZE_128;
854 }
855
Alan Kwong9487de22016-01-16 22:06:36 -0500856 SDE_REGDMA_WRITE(wrptr, ROT_SSPP_FETCH_CONFIG,
857 fetch_blocksize |
858 SDE_ROT_SSPP_FETCH_CONFIG_RESET_VALUE |
859 ((rot->highest_bank & 0x3) << 18));
860
861 /* setup source buffer plane security status */
Abhijit Kulkarni298c8232016-09-26 22:32:10 -0700862 if (flags & (SDE_ROT_FLAG_SECURE_OVERLAY_SESSION |
863 SDE_ROT_FLAG_SECURE_CAMERA_SESSION)) {
Alan Kwong9487de22016-01-16 22:06:36 -0500864 SDE_REGDMA_WRITE(wrptr, ROT_SSPP_SRC_ADDR_SW_STATUS, 0xF);
865 ctx->is_secure = true;
Benjamin Chan15c93d82016-08-29 10:04:22 -0400866 } else {
867 SDE_REGDMA_WRITE(wrptr, ROT_SSPP_SRC_ADDR_SW_STATUS, 0);
868 ctx->is_secure = false;
Alan Kwong9487de22016-01-16 22:06:36 -0500869 }
870
Benjamin Chan99eb63b2016-12-21 15:45:26 -0500871 /*
872 * Determine if traffic shaping is required. Only enable traffic
873 * shaping when content is 4k@30fps. The actual traffic shaping
874 * bandwidth calculation is done in output setup.
875 */
876 if (((cfg->src_rect->w * cfg->src_rect->h) >= RES_UHD) &&
877 (cfg->fps <= 30)) {
878 SDEROT_DBG("Enable Traffic Shaper\n");
879 ctx->is_traffic_shaping = true;
880 } else {
881 SDEROT_DBG("Disable Traffic Shaper\n");
882 ctx->is_traffic_shaping = false;
883 }
884
Alan Kwong9487de22016-01-16 22:06:36 -0500885 /* Update command queue write ptr */
886 sde_hw_rotator_put_regdma_segment(ctx, wrptr);
887}
888
889/*
890 * sde_hw_rotator_setup_wbengine - setup writeback engine
891 * @ctx: Pointer to rotator context
892 * @queue_id: Priority queue identifier
893 * @cfg: Writeback configuration
894 * @flags: Control flag
895 */
896static void sde_hw_rotator_setup_wbengine(struct sde_hw_rotator_context *ctx,
897 enum sde_rot_queue_prio queue_id,
898 struct sde_hw_rot_wb_cfg *cfg,
899 u32 flags)
900{
Alan Kwong6bc64622017-02-04 17:36:03 -0800901 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
Alan Kwong9487de22016-01-16 22:06:36 -0500902 struct sde_mdp_format_params *fmt;
903 u32 *wrptr;
904 u32 pack = 0;
905 u32 dst_format = 0;
906 int i;
907
908 wrptr = sde_hw_rotator_get_regdma_segment(ctx);
909
910 fmt = cfg->fmt;
911
912 /* setup WB DST format */
913 dst_format |= (fmt->chroma_sample << 23) |
914 (fmt->fetch_planes << 19) |
915 (fmt->bits[C3_ALPHA] << 6) |
916 (fmt->bits[C2_R_Cr] << 4) |
917 (fmt->bits[C1_B_Cb] << 2) |
918 (fmt->bits[C0_G_Y] << 0);
919
920 /* alpha control */
921 if (fmt->bits[C3_ALPHA] || fmt->alpha_enable) {
922 dst_format |= BIT(8);
923 if (!fmt->alpha_enable) {
924 dst_format |= BIT(14);
925 SDE_REGDMA_WRITE(wrptr, ROT_WB_DST_ALPHA_X_VALUE, 0);
926 }
927 }
928
929 dst_format |= ((fmt->unpack_count - 1) << 12) |
930 (fmt->unpack_tight << 17) |
931 (fmt->unpack_align_msb << 18) |
932 ((fmt->bpp - 1) << 9) |
933 ((fmt->frame_format & 3) << 30);
934
935 if (sde_mdp_is_yuv_format(fmt))
936 dst_format |= BIT(15);
937
938 if (fmt->pixel_mode == SDE_MDP_PIXEL_10BIT)
939 dst_format |= BIT(21); /* PACK_DX_FORMAT */
940
941 /*
942 * REGDMA BLK write, from DST_FORMAT to DST_YSTRIDE 1, total 9 regs
943 */
944 SDE_REGDMA_BLKWRITE_INC(wrptr, ROT_WB_DST_FORMAT, 9);
945
946 /* DST_FORMAT */
947 SDE_REGDMA_BLKWRITE_DATA(wrptr, dst_format);
948
949 /* DST_OP_MODE */
950 if (sde_mdp_is_ubwc_format(fmt))
951 SDE_REGDMA_BLKWRITE_DATA(wrptr, BIT(0));
952 else
953 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0);
954
955 /* DST_PACK_PATTERN */
956 pack = (fmt->element[3] << 24) | (fmt->element[2] << 16) |
957 (fmt->element[1] << 8) | (fmt->element[0] << 0);
958 SDE_REGDMA_BLKWRITE_DATA(wrptr, pack);
959
960 /* DST_ADDR [0-3], DST_YSTRIDE [0-1] */
961 for (i = 0; i < SDE_ROT_MAX_PLANES; i++)
962 SDE_REGDMA_BLKWRITE_DATA(wrptr, cfg->data->p[i].addr);
963 SDE_REGDMA_BLKWRITE_DATA(wrptr, cfg->dst_plane.ystride[0] |
964 (cfg->dst_plane.ystride[1] << 16));
965 SDE_REGDMA_BLKWRITE_DATA(wrptr, cfg->dst_plane.ystride[2] |
966 (cfg->dst_plane.ystride[3] << 16));
967
968 /* setup WB out image size and ROI */
969 SDE_REGDMA_WRITE(wrptr, ROT_WB_OUT_IMG_SIZE,
970 cfg->img_width | (cfg->img_height << 16));
971 SDE_REGDMA_WRITE(wrptr, ROT_WB_OUT_SIZE,
972 cfg->dst_rect->w | (cfg->dst_rect->h << 16));
973 SDE_REGDMA_WRITE(wrptr, ROT_WB_OUT_XY,
974 cfg->dst_rect->x | (cfg->dst_rect->y << 16));
975
Abhijit Kulkarni298c8232016-09-26 22:32:10 -0700976 if (flags & (SDE_ROT_FLAG_SECURE_OVERLAY_SESSION |
977 SDE_ROT_FLAG_SECURE_CAMERA_SESSION))
Benjamin Chan15c93d82016-08-29 10:04:22 -0400978 SDE_REGDMA_WRITE(wrptr, ROT_WB_DST_ADDR_SW_STATUS, 0x1);
979 else
980 SDE_REGDMA_WRITE(wrptr, ROT_WB_DST_ADDR_SW_STATUS, 0);
981
Alan Kwong9487de22016-01-16 22:06:36 -0500982 /*
983 * setup Downscale factor
984 */
985 SDE_REGDMA_WRITE(wrptr, ROTTOP_DNSC,
986 cfg->v_downscale_factor |
987 (cfg->h_downscale_factor << 16));
988
Alan Kwong6bc64622017-02-04 17:36:03 -0800989 /* write config setup for bank configuration */
Alan Kwong9487de22016-01-16 22:06:36 -0500990 SDE_REGDMA_WRITE(wrptr, ROT_WB_DST_WRITE_CONFIG,
991 (ctx->rot->highest_bank & 0x3) << 8);
992
Alan Kwong6bc64622017-02-04 17:36:03 -0800993 if (test_bit(SDE_CAPS_SBUF_1, mdata->sde_caps_map))
994 SDE_REGDMA_WRITE(wrptr, ROT_WB_SYS_CACHE_MODE,
995 ctx->sys_cache_mode);
996
997 SDE_REGDMA_WRITE(wrptr, ROTTOP_OP_MODE, ctx->op_mode |
998 (flags & SDE_ROT_FLAG_ROT_90 ? BIT(1) : 0) | BIT(0));
Alan Kwong9487de22016-01-16 22:06:36 -0500999
Benjamin Chan99eb63b2016-12-21 15:45:26 -05001000 /* setup traffic shaper for 4k 30fps content */
1001 if (ctx->is_traffic_shaping) {
1002 u32 bw;
1003
1004 /*
1005 * Target to finish in 12ms, and we need to set number of bytes
1006 * per clock tick for traffic shaping.
1007 * Each clock tick run @ 19.2MHz, so we need we know total of
1008 * clock ticks in 14ms, i.e. 12ms/(1/19.2MHz) ==> 23040
1009 * Finally, calcualte the byte count per clock tick based on
1010 * resolution, bpp and compression ratio.
1011 */
1012 bw = cfg->dst_rect->w * cfg->dst_rect->h;
1013
1014 if (fmt->chroma_sample == SDE_MDP_CHROMA_420)
1015 bw = (bw * 3) / 2;
1016 else
1017 bw *= fmt->bpp;
1018
1019 bw /= TRAFFIC_SHAPE_CLKTICK_12MS;
1020 if (bw > 0xFF)
1021 bw = 0xFF;
1022 SDE_REGDMA_WRITE(wrptr, ROT_WB_TRAFFIC_SHAPER_WR_CLIENT,
1023 BIT(31) | bw);
1024 SDEROT_DBG("Enable ROT_WB Traffic Shaper:%d\n", bw);
1025 } else {
1026 SDE_REGDMA_WRITE(wrptr, ROT_WB_TRAFFIC_SHAPER_WR_CLIENT, 0);
1027 SDEROT_DBG("Disable ROT_WB Traffic Shaper\n");
1028 }
1029
Alan Kwong9487de22016-01-16 22:06:36 -05001030 /* Update command queue write ptr */
1031 sde_hw_rotator_put_regdma_segment(ctx, wrptr);
1032}
1033
1034/*
1035 * sde_hw_rotator_start_no_regdma - start non-regdma operation
1036 * @ctx: Pointer to rotator context
1037 * @queue_id: Priority queue identifier
1038 */
1039static u32 sde_hw_rotator_start_no_regdma(struct sde_hw_rotator_context *ctx,
1040 enum sde_rot_queue_prio queue_id)
1041{
1042 struct sde_hw_rotator *rot = ctx->rot;
1043 u32 *wrptr;
1044 u32 *rdptr;
1045 u8 *addr;
1046 u32 mask;
1047 u32 blksize;
1048
1049 rdptr = sde_hw_rotator_get_regdma_segment_base(ctx);
1050 wrptr = sde_hw_rotator_get_regdma_segment(ctx);
1051
1052 if (rot->irq_num >= 0) {
1053 SDE_REGDMA_WRITE(wrptr, ROTTOP_INTR_EN, 1);
1054 SDE_REGDMA_WRITE(wrptr, ROTTOP_INTR_CLEAR, 1);
1055 reinit_completion(&ctx->rot_comp);
Alan Kwong818b7fc2016-07-24 22:07:41 -04001056 sde_hw_rotator_enable_irq(rot);
Alan Kwong9487de22016-01-16 22:06:36 -05001057 }
1058
Alan Kwong6bc64622017-02-04 17:36:03 -08001059 SDE_REGDMA_WRITE(wrptr, ROTTOP_START_CTRL, ctx->start_ctrl);
Alan Kwong9487de22016-01-16 22:06:36 -05001060
1061 /* Update command queue write ptr */
1062 sde_hw_rotator_put_regdma_segment(ctx, wrptr);
1063
1064 SDEROT_DBG("BEGIN %d\n", ctx->timestamp);
1065 /* Write all command stream to Rotator blocks */
1066 /* Rotator will start right away after command stream finish writing */
1067 while (rdptr < wrptr) {
1068 u32 op = REGDMA_OP_MASK & *rdptr;
1069
1070 switch (op) {
1071 case REGDMA_OP_NOP:
1072 SDEROT_DBG("NOP\n");
1073 rdptr++;
1074 break;
1075 case REGDMA_OP_REGWRITE:
1076 SDEROT_DBG("REGW %6.6x %8.8x\n",
1077 rdptr[0] & REGDMA_ADDR_OFFSET_MASK,
1078 rdptr[1]);
1079 addr = rot->mdss_base +
1080 (*rdptr++ & REGDMA_ADDR_OFFSET_MASK);
1081 writel_relaxed(*rdptr++, addr);
1082 break;
1083 case REGDMA_OP_REGMODIFY:
1084 SDEROT_DBG("REGM %6.6x %8.8x %8.8x\n",
1085 rdptr[0] & REGDMA_ADDR_OFFSET_MASK,
1086 rdptr[1], rdptr[2]);
1087 addr = rot->mdss_base +
1088 (*rdptr++ & REGDMA_ADDR_OFFSET_MASK);
1089 mask = *rdptr++;
1090 writel_relaxed((readl_relaxed(addr) & mask) | *rdptr++,
1091 addr);
1092 break;
1093 case REGDMA_OP_BLKWRITE_SINGLE:
1094 SDEROT_DBG("BLKWS %6.6x %6.6x\n",
1095 rdptr[0] & REGDMA_ADDR_OFFSET_MASK,
1096 rdptr[1]);
1097 addr = rot->mdss_base +
1098 (*rdptr++ & REGDMA_ADDR_OFFSET_MASK);
1099 blksize = *rdptr++;
1100 while (blksize--) {
1101 SDEROT_DBG("DATA %8.8x\n", rdptr[0]);
1102 writel_relaxed(*rdptr++, addr);
1103 }
1104 break;
1105 case REGDMA_OP_BLKWRITE_INC:
1106 SDEROT_DBG("BLKWI %6.6x %6.6x\n",
1107 rdptr[0] & REGDMA_ADDR_OFFSET_MASK,
1108 rdptr[1]);
1109 addr = rot->mdss_base +
1110 (*rdptr++ & REGDMA_ADDR_OFFSET_MASK);
1111 blksize = *rdptr++;
1112 while (blksize--) {
1113 SDEROT_DBG("DATA %8.8x\n", rdptr[0]);
1114 writel_relaxed(*rdptr++, addr);
1115 addr += 4;
1116 }
1117 break;
1118 default:
1119 /* Other not supported OP mode
1120 * Skip data for now for unregonized OP mode
1121 */
1122 SDEROT_DBG("UNDEFINED\n");
1123 rdptr++;
1124 break;
1125 }
1126 }
1127 SDEROT_DBG("END %d\n", ctx->timestamp);
1128
1129 return ctx->timestamp;
1130}
1131
1132/*
1133 * sde_hw_rotator_start_regdma - start regdma operation
1134 * @ctx: Pointer to rotator context
1135 * @queue_id: Priority queue identifier
1136 */
1137static u32 sde_hw_rotator_start_regdma(struct sde_hw_rotator_context *ctx,
1138 enum sde_rot_queue_prio queue_id)
1139{
1140 struct sde_hw_rotator *rot = ctx->rot;
1141 u32 *wrptr;
1142 u32 regdmaSlot;
1143 u32 offset;
1144 long length;
1145 long ts_length;
1146 u32 enableInt;
1147 u32 swts = 0;
1148 u32 mask = 0;
Alan Kwong6bc64622017-02-04 17:36:03 -08001149 u32 trig_sel;
Alan Kwong9487de22016-01-16 22:06:36 -05001150
1151 wrptr = sde_hw_rotator_get_regdma_segment(ctx);
1152
Alan Kwong9487de22016-01-16 22:06:36 -05001153 /*
1154 * Last ROT command must be ROT_START before REGDMA start
1155 */
Alan Kwong6bc64622017-02-04 17:36:03 -08001156 SDE_REGDMA_WRITE(wrptr, ROTTOP_START_CTRL, ctx->start_ctrl);
1157
Alan Kwong9487de22016-01-16 22:06:36 -05001158 sde_hw_rotator_put_regdma_segment(ctx, wrptr);
1159
1160 /*
1161 * Start REGDMA with command offset and size
1162 */
1163 regdmaSlot = sde_hw_rotator_get_regdma_ctxidx(ctx);
1164 length = ((long)wrptr - (long)ctx->regdma_base) / 4;
1165 offset = (u32)(ctx->regdma_base - (u32 *)(rot->mdss_base +
1166 REGDMA_RAM_REGDMA_CMD_RAM));
1167 enableInt = ((ctx->timestamp & 1) + 1) << 30;
Alan Kwong6bc64622017-02-04 17:36:03 -08001168 trig_sel = ctx->sbuf_mode ? REGDMA_CMD_TRIG_SEL_MDP_FLUSH :
1169 REGDMA_CMD_TRIG_SEL_SW_START;
Alan Kwong9487de22016-01-16 22:06:36 -05001170
1171 SDEROT_DBG(
1172 "regdma(%d)[%d] <== INT:0x%X|length:%ld|offset:0x%X, ts:%X\n",
1173 queue_id, regdmaSlot, enableInt, length, offset,
1174 ctx->timestamp);
1175
1176 /* ensure the command packet is issued before the submit command */
1177 wmb();
1178
1179 /* REGDMA submission for current context */
1180 if (queue_id == ROT_QUEUE_HIGH_PRIORITY) {
1181 SDE_ROTREG_WRITE(rot->mdss_base,
1182 REGDMA_CSR_REGDMA_QUEUE_0_SUBMIT,
Alan Kwong6bc64622017-02-04 17:36:03 -08001183 (ctx->sbuf_mode ? enableInt : 0) | trig_sel |
1184 ((length & 0x3ff) << 14) | offset);
Alan Kwong9487de22016-01-16 22:06:36 -05001185 swts = ctx->timestamp;
1186 mask = ~SDE_REGDMA_SWTS_MASK;
1187 } else {
1188 SDE_ROTREG_WRITE(rot->mdss_base,
1189 REGDMA_CSR_REGDMA_QUEUE_1_SUBMIT,
Alan Kwong6bc64622017-02-04 17:36:03 -08001190 (ctx->sbuf_mode ? enableInt : 0) | trig_sel |
1191 ((length & 0x3ff) << 14) | offset);
Alan Kwong9487de22016-01-16 22:06:36 -05001192 swts = ctx->timestamp << SDE_REGDMA_SWTS_SHIFT;
1193 mask = ~(SDE_REGDMA_SWTS_MASK << SDE_REGDMA_SWTS_SHIFT);
1194 }
1195
Alan Kwong6bc64622017-02-04 17:36:03 -08001196 /* timestamp update can only be used in offline multi-context mode */
1197 if (!ctx->sbuf_mode) {
1198 /* Write timestamp after previous rotator job finished */
1199 sde_hw_rotator_setup_timestamp_packet(ctx, mask, swts);
1200 offset += length;
1201 ts_length = sde_hw_rotator_get_regdma_segment(ctx) - wrptr;
1202 WARN_ON((length + ts_length) > SDE_HW_ROT_REGDMA_SEG_SIZE);
Alan Kwong9487de22016-01-16 22:06:36 -05001203
Alan Kwong6bc64622017-02-04 17:36:03 -08001204 /* ensure command packet is issue before the submit command */
1205 wmb();
Alan Kwong9487de22016-01-16 22:06:36 -05001206
Alan Kwong6bc64622017-02-04 17:36:03 -08001207 if (queue_id == ROT_QUEUE_HIGH_PRIORITY) {
1208 SDE_ROTREG_WRITE(rot->mdss_base,
1209 REGDMA_CSR_REGDMA_QUEUE_0_SUBMIT,
1210 enableInt | (ts_length << 14) | offset);
1211 } else {
1212 SDE_ROTREG_WRITE(rot->mdss_base,
1213 REGDMA_CSR_REGDMA_QUEUE_1_SUBMIT,
1214 enableInt | (ts_length << 14) | offset);
1215 }
Alan Kwong9487de22016-01-16 22:06:36 -05001216 }
1217
Alan Kwong9487de22016-01-16 22:06:36 -05001218 /* Update command queue write ptr */
1219 sde_hw_rotator_put_regdma_segment(ctx, wrptr);
1220
1221 return ctx->timestamp;
1222}
1223
1224/*
1225 * sde_hw_rotator_wait_done_no_regdma - wait for non-regdma completion
1226 * @ctx: Pointer to rotator context
1227 * @queue_id: Priority queue identifier
1228 * @flags: Option flag
1229 */
1230static u32 sde_hw_rotator_wait_done_no_regdma(
1231 struct sde_hw_rotator_context *ctx,
1232 enum sde_rot_queue_prio queue_id, u32 flag)
1233{
1234 struct sde_hw_rotator *rot = ctx->rot;
1235 int rc = 0;
1236 u32 sts = 0;
1237 u32 status;
1238 unsigned long flags;
1239
1240 if (rot->irq_num >= 0) {
1241 SDEROT_DBG("Wait for Rotator completion\n");
1242 rc = wait_for_completion_timeout(&ctx->rot_comp,
Alan Kwong6bc64622017-02-04 17:36:03 -08001243 msecs_to_jiffies(rot->koff_timeout));
Alan Kwong9487de22016-01-16 22:06:36 -05001244
1245 spin_lock_irqsave(&rot->rotisr_lock, flags);
1246 status = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_STATUS);
1247 if (rc == 0) {
1248 /*
1249 * Timeout, there might be error,
1250 * or rotator still busy
1251 */
1252 if (status & ROT_BUSY_BIT)
1253 SDEROT_ERR(
1254 "Timeout waiting for rotator done\n");
1255 else if (status & ROT_ERROR_BIT)
1256 SDEROT_ERR(
1257 "Rotator report error status\n");
1258 else
1259 SDEROT_WARN(
1260 "Timeout waiting, but rotator job is done!!\n");
1261
Alan Kwong818b7fc2016-07-24 22:07:41 -04001262 sde_hw_rotator_disable_irq(rot);
Alan Kwong9487de22016-01-16 22:06:36 -05001263 }
1264 spin_unlock_irqrestore(&rot->rotisr_lock, flags);
1265 } else {
1266 int cnt = 200;
1267
1268 do {
1269 udelay(500);
1270 status = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_STATUS);
1271 cnt--;
1272 } while ((cnt > 0) && (status & ROT_BUSY_BIT)
1273 && ((status & ROT_ERROR_BIT) == 0));
1274
1275 if (status & ROT_ERROR_BIT)
1276 SDEROT_ERR("Rotator error\n");
1277 else if (status & ROT_BUSY_BIT)
1278 SDEROT_ERR("Rotator busy\n");
1279
1280 SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_CLEAR,
1281 ROT_DONE_CLEAR);
1282 }
1283
1284 sts = (status & ROT_ERROR_BIT) ? -ENODEV : 0;
1285
1286 return sts;
1287}
1288
1289/*
1290 * sde_hw_rotator_wait_done_regdma - wait for regdma completion
1291 * @ctx: Pointer to rotator context
1292 * @queue_id: Priority queue identifier
1293 * @flags: Option flag
1294 */
1295static u32 sde_hw_rotator_wait_done_regdma(
1296 struct sde_hw_rotator_context *ctx,
1297 enum sde_rot_queue_prio queue_id, u32 flag)
1298{
1299 struct sde_hw_rotator *rot = ctx->rot;
1300 int rc = 0;
1301 u32 status;
1302 u32 last_isr;
1303 u32 last_ts;
1304 u32 int_id;
Alan Kwong818b7fc2016-07-24 22:07:41 -04001305 u32 swts;
Alan Kwong9487de22016-01-16 22:06:36 -05001306 u32 sts = 0;
Alan Kwong9487de22016-01-16 22:06:36 -05001307 unsigned long flags;
1308
1309 if (rot->irq_num >= 0) {
1310 SDEROT_DBG("Wait for REGDMA completion, ctx:%p, ts:%X\n",
1311 ctx, ctx->timestamp);
Alan Kwong818b7fc2016-07-24 22:07:41 -04001312 rc = wait_event_timeout(ctx->regdma_waitq,
1313 !sde_hw_rotator_pending_swts(rot, ctx, &swts),
Alan Kwong6bc64622017-02-04 17:36:03 -08001314 msecs_to_jiffies(rot->koff_timeout));
Alan Kwong9487de22016-01-16 22:06:36 -05001315
Benjamin Chane7ca72e2016-12-22 18:42:34 -05001316 ATRACE_INT("sde_rot_done", 0);
Alan Kwong9487de22016-01-16 22:06:36 -05001317 spin_lock_irqsave(&rot->rotisr_lock, flags);
1318
1319 last_isr = ctx->last_regdma_isr_status;
1320 last_ts = ctx->last_regdma_timestamp;
1321 status = last_isr & REGDMA_INT_MASK;
1322 int_id = last_ts & 1;
1323 SDEROT_DBG("INT status:0x%X, INT id:%d, timestamp:0x%X\n",
1324 status, int_id, last_ts);
1325
1326 if (rc == 0 || (status & REGDMA_INT_ERR_MASK)) {
Alan Kwong818b7fc2016-07-24 22:07:41 -04001327 bool pending;
1328
1329 pending = sde_hw_rotator_pending_swts(rot, ctx, &swts);
Alan Kwong9487de22016-01-16 22:06:36 -05001330 SDEROT_ERR(
Alan Kwong818b7fc2016-07-24 22:07:41 -04001331 "Timeout wait for regdma interrupt status, ts:0x%X/0x%X pending:%d\n",
1332 ctx->timestamp, swts, pending);
Alan Kwong9487de22016-01-16 22:06:36 -05001333
1334 if (status & REGDMA_WATCHDOG_INT)
1335 SDEROT_ERR("REGDMA watchdog interrupt\n");
1336 else if (status & REGDMA_INVALID_DESCRIPTOR)
1337 SDEROT_ERR("REGDMA invalid descriptor\n");
1338 else if (status & REGDMA_INCOMPLETE_CMD)
1339 SDEROT_ERR("REGDMA incomplete command\n");
1340 else if (status & REGDMA_INVALID_CMD)
1341 SDEROT_ERR("REGDMA invalid command\n");
1342
Alan Kwong818b7fc2016-07-24 22:07:41 -04001343 sde_hw_rotator_dump_status(rot);
Alan Kwong9487de22016-01-16 22:06:36 -05001344 status = ROT_ERROR_BIT;
Alan Kwong818b7fc2016-07-24 22:07:41 -04001345 } else {
1346 if (rc == 1)
1347 SDEROT_WARN(
1348 "REGDMA done but no irq, ts:0x%X/0x%X\n",
1349 ctx->timestamp, swts);
Alan Kwong9487de22016-01-16 22:06:36 -05001350 status = 0;
1351 }
1352
Alan Kwong9487de22016-01-16 22:06:36 -05001353 spin_unlock_irqrestore(&rot->rotisr_lock, flags);
1354 } else {
1355 int cnt = 200;
Alan Kwongb0679602016-11-27 17:04:13 -08001356 bool pending;
Alan Kwong9487de22016-01-16 22:06:36 -05001357
1358 do {
1359 udelay(500);
Alan Kwongb0679602016-11-27 17:04:13 -08001360 last_isr = SDE_ROTREG_READ(rot->mdss_base,
1361 REGDMA_CSR_REGDMA_INT_STATUS);
1362 pending = sde_hw_rotator_pending_swts(rot, ctx, &swts);
Alan Kwong9487de22016-01-16 22:06:36 -05001363 cnt--;
Alan Kwongb0679602016-11-27 17:04:13 -08001364 } while ((cnt > 0) && pending &&
1365 ((last_isr & REGDMA_INT_ERR_MASK) == 0));
Alan Kwong9487de22016-01-16 22:06:36 -05001366
Alan Kwongb0679602016-11-27 17:04:13 -08001367 if (last_isr & REGDMA_INT_ERR_MASK) {
1368 SDEROT_ERR("Rotator error, ts:0x%X/0x%X status:%x\n",
1369 ctx->timestamp, swts, last_isr);
1370 sde_hw_rotator_dump_status(rot);
1371 status = ROT_ERROR_BIT;
1372 } else if (pending) {
1373 SDEROT_ERR("Rotator timeout, ts:0x%X/0x%X status:%x\n",
1374 ctx->timestamp, swts, last_isr);
1375 sde_hw_rotator_dump_status(rot);
1376 status = ROT_ERROR_BIT;
1377 } else {
1378 status = 0;
1379 }
Alan Kwong9487de22016-01-16 22:06:36 -05001380
1381 SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_INT_CLEAR,
Alan Kwongb0679602016-11-27 17:04:13 -08001382 last_isr);
Alan Kwong9487de22016-01-16 22:06:36 -05001383 }
1384
1385 sts = (status & ROT_ERROR_BIT) ? -ENODEV : 0;
1386
Benjamin Chan4ec1f1d2016-09-15 22:49:49 -04001387 if (status & ROT_ERROR_BIT)
1388 SDEROT_EVTLOG_TOUT_HANDLER("rot", "vbif_dbg_bus", "panic");
1389
Alan Kwong9487de22016-01-16 22:06:36 -05001390 return sts;
1391}
1392
1393/*
1394 * setup_rotator_ops - setup callback functions for the low-level HAL
1395 * @ops: Pointer to low-level ops callback
1396 * @mode: Operation mode (non-regdma or regdma)
1397 */
1398static void setup_rotator_ops(struct sde_hw_rotator_ops *ops,
1399 enum sde_rotator_regdma_mode mode)
1400{
1401 ops->setup_rotator_fetchengine = sde_hw_rotator_setup_fetchengine;
1402 ops->setup_rotator_wbengine = sde_hw_rotator_setup_wbengine;
1403 if (mode == ROT_REGDMA_ON) {
1404 ops->start_rotator = sde_hw_rotator_start_regdma;
1405 ops->wait_rotator_done = sde_hw_rotator_wait_done_regdma;
1406 } else {
1407 ops->start_rotator = sde_hw_rotator_start_no_regdma;
1408 ops->wait_rotator_done = sde_hw_rotator_wait_done_no_regdma;
1409 }
1410}
1411
1412/*
1413 * sde_hw_rotator_swts_create - create software timestamp buffer
1414 * @rot: Pointer to rotator hw
1415 *
1416 * This buffer is used by regdma to keep track of last completed command.
1417 */
1418static int sde_hw_rotator_swts_create(struct sde_hw_rotator *rot)
1419{
1420 int rc = 0;
1421 struct ion_handle *handle;
1422 struct sde_mdp_img_data *data;
Abhijit Kulkarni298c8232016-09-26 22:32:10 -07001423 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
Alan Kwong9487de22016-01-16 22:06:36 -05001424 u32 bufsize = sizeof(int) * SDE_HW_ROT_REGDMA_TOTAL_CTX * 2;
1425
Abhijit Kulkarni298c8232016-09-26 22:32:10 -07001426 rot->iclient = mdata->iclient;
Alan Kwong9487de22016-01-16 22:06:36 -05001427
1428 handle = ion_alloc(rot->iclient, bufsize, SZ_4K,
1429 ION_HEAP(ION_SYSTEM_HEAP_ID), 0);
1430 if (IS_ERR_OR_NULL(handle)) {
1431 SDEROT_ERR("ion memory allocation failed\n");
1432 return -ENOMEM;
1433 }
1434
1435 data = &rot->swts_buf;
1436 data->len = bufsize;
1437 data->srcp_dma_buf = ion_share_dma_buf(rot->iclient, handle);
1438 if (IS_ERR(data->srcp_dma_buf)) {
1439 SDEROT_ERR("ion_dma_buf setup failed\n");
1440 rc = -ENOMEM;
1441 goto imap_err;
1442 }
1443
1444 sde_smmu_ctrl(1);
1445
1446 data->srcp_attachment = sde_smmu_dma_buf_attach(data->srcp_dma_buf,
1447 &rot->pdev->dev, SDE_IOMMU_DOMAIN_ROT_UNSECURE);
1448 if (IS_ERR_OR_NULL(data->srcp_attachment)) {
1449 SDEROT_ERR("sde_smmu_dma_buf_attach error\n");
1450 rc = -ENOMEM;
1451 goto err_put;
1452 }
1453
1454 data->srcp_table = dma_buf_map_attachment(data->srcp_attachment,
1455 DMA_BIDIRECTIONAL);
1456 if (IS_ERR_OR_NULL(data->srcp_table)) {
1457 SDEROT_ERR("dma_buf_map_attachment error\n");
1458 rc = -ENOMEM;
1459 goto err_detach;
1460 }
1461
1462 rc = sde_smmu_map_dma_buf(data->srcp_dma_buf, data->srcp_table,
1463 SDE_IOMMU_DOMAIN_ROT_UNSECURE, &data->addr,
1464 &data->len, DMA_BIDIRECTIONAL);
Alan Kwong6ce448d2016-11-24 18:45:20 -08001465 if (rc < 0) {
Alan Kwong9487de22016-01-16 22:06:36 -05001466 SDEROT_ERR("smmu_map_dma_buf failed: (%d)\n", rc);
1467 goto err_unmap;
1468 }
1469
Alan Kwong6ce448d2016-11-24 18:45:20 -08001470 dma_buf_begin_cpu_access(data->srcp_dma_buf, DMA_FROM_DEVICE);
Alan Kwong9487de22016-01-16 22:06:36 -05001471 rot->swts_buffer = dma_buf_kmap(data->srcp_dma_buf, 0);
1472 if (IS_ERR_OR_NULL(rot->swts_buffer)) {
1473 SDEROT_ERR("ion kernel memory mapping failed\n");
1474 rc = IS_ERR(rot->swts_buffer);
1475 goto kmap_err;
1476 }
1477
1478 data->mapped = true;
1479 SDEROT_DBG("swts buffer mapped: %pad/%lx va:%p\n", &data->addr,
1480 data->len, rot->swts_buffer);
1481
1482 ion_free(rot->iclient, handle);
1483
1484 sde_smmu_ctrl(0);
1485
1486 return rc;
1487kmap_err:
1488 sde_smmu_unmap_dma_buf(data->srcp_table, SDE_IOMMU_DOMAIN_ROT_UNSECURE,
1489 DMA_FROM_DEVICE, data->srcp_dma_buf);
1490err_unmap:
1491 dma_buf_unmap_attachment(data->srcp_attachment, data->srcp_table,
1492 DMA_FROM_DEVICE);
1493err_detach:
1494 dma_buf_detach(data->srcp_dma_buf, data->srcp_attachment);
1495err_put:
1496 dma_buf_put(data->srcp_dma_buf);
1497 data->srcp_dma_buf = NULL;
1498imap_err:
1499 ion_free(rot->iclient, handle);
1500
1501 return rc;
1502}
1503
1504/*
1505 * sde_hw_rotator_swtc_destroy - destroy software timestamp buffer
1506 * @rot: Pointer to rotator hw
1507 */
1508static void sde_hw_rotator_swtc_destroy(struct sde_hw_rotator *rot)
1509{
1510 struct sde_mdp_img_data *data;
1511
1512 data = &rot->swts_buf;
1513
Alan Kwong6ce448d2016-11-24 18:45:20 -08001514 dma_buf_end_cpu_access(data->srcp_dma_buf, DMA_FROM_DEVICE);
Alan Kwong9487de22016-01-16 22:06:36 -05001515 dma_buf_kunmap(data->srcp_dma_buf, 0, rot->swts_buffer);
1516
1517 sde_smmu_unmap_dma_buf(data->srcp_table, SDE_IOMMU_DOMAIN_ROT_UNSECURE,
1518 DMA_FROM_DEVICE, data->srcp_dma_buf);
1519 dma_buf_unmap_attachment(data->srcp_attachment, data->srcp_table,
1520 DMA_FROM_DEVICE);
1521 dma_buf_detach(data->srcp_dma_buf, data->srcp_attachment);
1522 dma_buf_put(data->srcp_dma_buf);
1523 data->srcp_dma_buf = NULL;
1524}
1525
1526/*
Benjamin Chan0f9e61d2016-09-16 16:01:09 -04001527 * sde_hw_rotator_pre_pmevent - SDE rotator core will call this before a
1528 * PM event occurs
1529 * @mgr: Pointer to rotator manager
1530 * @pmon: Boolean indicate an on/off power event
1531 */
1532void sde_hw_rotator_pre_pmevent(struct sde_rot_mgr *mgr, bool pmon)
1533{
1534 struct sde_hw_rotator *rot;
1535 u32 l_ts, h_ts, swts, hwts;
1536 u32 rotsts, regdmasts;
1537
1538 /*
1539 * Check last HW timestamp with SW timestamp before power off event.
1540 * If there is a mismatch, that will be quite possible the rotator HW
1541 * is either hang or not finishing last submitted job. In that case,
1542 * it is best to do a timeout eventlog to capture some good events
1543 * log data for analysis.
1544 */
1545 if (!pmon && mgr && mgr->hw_data) {
1546 rot = mgr->hw_data;
1547 h_ts = atomic_read(&rot->timestamp[ROT_QUEUE_HIGH_PRIORITY]);
1548 l_ts = atomic_read(&rot->timestamp[ROT_QUEUE_LOW_PRIORITY]);
1549
1550 /* contruct the combined timstamp */
1551 swts = (h_ts & SDE_REGDMA_SWTS_MASK) |
1552 ((l_ts & SDE_REGDMA_SWTS_MASK) <<
1553 SDE_REGDMA_SWTS_SHIFT);
1554
1555 /* Need to turn on clock to access rotator register */
1556 sde_rotator_clk_ctrl(mgr, true);
1557 hwts = SDE_ROTREG_READ(rot->mdss_base, REGDMA_TIMESTAMP_REG);
1558 regdmasts = SDE_ROTREG_READ(rot->mdss_base,
1559 REGDMA_CSR_REGDMA_BLOCK_STATUS);
1560 rotsts = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_STATUS);
1561
1562 SDEROT_DBG(
1563 "swts:0x%x, hwts:0x%x, regdma-sts:0x%x, rottop-sts:0x%x\n",
1564 swts, hwts, regdmasts, rotsts);
1565 SDEROT_EVTLOG(swts, hwts, regdmasts, rotsts);
1566
1567 if ((swts != hwts) && ((regdmasts & REGDMA_BUSY) ||
1568 (rotsts & ROT_STATUS_MASK))) {
1569 SDEROT_ERR(
1570 "Mismatch SWTS with HWTS: swts:0x%x, hwts:0x%x, regdma-sts:0x%x, rottop-sts:0x%x\n",
1571 swts, hwts, regdmasts, rotsts);
1572 SDEROT_EVTLOG_TOUT_HANDLER("rot", "vbif_dbg_bus",
1573 "panic");
1574 }
1575
1576 /* Turn off rotator clock after checking rotator registers */
1577 sde_rotator_clk_ctrl(mgr, false);
1578 }
1579}
1580
1581/*
1582 * sde_hw_rotator_post_pmevent - SDE rotator core will call this after a
1583 * PM event occurs
1584 * @mgr: Pointer to rotator manager
1585 * @pmon: Boolean indicate an on/off power event
1586 */
1587void sde_hw_rotator_post_pmevent(struct sde_rot_mgr *mgr, bool pmon)
1588{
1589 struct sde_hw_rotator *rot;
1590 u32 l_ts, h_ts, swts;
1591
1592 /*
1593 * After a power on event, the rotator HW is reset to default setting.
1594 * It is necessary to synchronize the SW timestamp with the HW.
1595 */
1596 if (pmon && mgr && mgr->hw_data) {
1597 rot = mgr->hw_data;
1598 h_ts = atomic_read(&rot->timestamp[ROT_QUEUE_HIGH_PRIORITY]);
1599 l_ts = atomic_read(&rot->timestamp[ROT_QUEUE_LOW_PRIORITY]);
1600
1601 /* contruct the combined timstamp */
1602 swts = (h_ts & SDE_REGDMA_SWTS_MASK) |
1603 ((l_ts & SDE_REGDMA_SWTS_MASK) <<
1604 SDE_REGDMA_SWTS_SHIFT);
1605
1606 SDEROT_DBG("swts:0x%x, h_ts:0x%x, l_ts;0x%x\n",
1607 swts, h_ts, l_ts);
1608 SDEROT_EVTLOG(swts, h_ts, l_ts);
1609 rot->reset_hw_ts = true;
1610 rot->last_hw_ts = swts;
1611 }
1612}
1613
1614/*
Alan Kwong9487de22016-01-16 22:06:36 -05001615 * sde_hw_rotator_destroy - Destroy hw rotator and free allocated resources
1616 * @mgr: Pointer to rotator manager
1617 */
1618static void sde_hw_rotator_destroy(struct sde_rot_mgr *mgr)
1619{
1620 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
1621 struct sde_hw_rotator *rot;
1622
1623 if (!mgr || !mgr->pdev || !mgr->hw_data) {
1624 SDEROT_ERR("null parameters\n");
1625 return;
1626 }
1627
1628 rot = mgr->hw_data;
1629 if (rot->irq_num >= 0)
1630 devm_free_irq(&mgr->pdev->dev, rot->irq_num, mdata);
1631
1632 if (rot->mode == ROT_REGDMA_ON)
1633 sde_hw_rotator_swtc_destroy(rot);
1634
1635 devm_kfree(&mgr->pdev->dev, mgr->hw_data);
1636 mgr->hw_data = NULL;
1637}
1638
1639/*
1640 * sde_hw_rotator_alloc_ext - allocate rotator resource from rotator hw
1641 * @mgr: Pointer to rotator manager
1642 * @pipe_id: pipe identifier (not used)
1643 * @wb_id: writeback identifier/priority queue identifier
1644 *
1645 * This function allocates a new hw rotator resource for the given priority.
1646 */
1647static struct sde_rot_hw_resource *sde_hw_rotator_alloc_ext(
1648 struct sde_rot_mgr *mgr, u32 pipe_id, u32 wb_id)
1649{
1650 struct sde_hw_rotator_resource_info *resinfo;
1651
1652 if (!mgr || !mgr->hw_data) {
1653 SDEROT_ERR("null parameters\n");
1654 return NULL;
1655 }
1656
1657 /*
1658 * Allocate rotator resource info. Each allocation is per
1659 * HW priority queue
1660 */
1661 resinfo = devm_kzalloc(&mgr->pdev->dev, sizeof(*resinfo), GFP_KERNEL);
1662 if (!resinfo) {
1663 SDEROT_ERR("Failed allocation HW rotator resource info\n");
1664 return NULL;
1665 }
1666
1667 resinfo->rot = mgr->hw_data;
1668 resinfo->hw.wb_id = wb_id;
1669 atomic_set(&resinfo->hw.num_active, 0);
1670 init_waitqueue_head(&resinfo->hw.wait_queue);
1671
1672 /* For non-regdma, only support one active session */
1673 if (resinfo->rot->mode == ROT_REGDMA_OFF)
1674 resinfo->hw.max_active = 1;
1675 else {
1676 resinfo->hw.max_active = SDE_HW_ROT_REGDMA_TOTAL_CTX - 1;
1677
1678 if (resinfo->rot->iclient == NULL)
1679 sde_hw_rotator_swts_create(resinfo->rot);
1680 }
1681
Alan Kwongf987ea32016-07-06 12:11:44 -04001682 if (resinfo->rot->irq_num >= 0)
Alan Kwong818b7fc2016-07-24 22:07:41 -04001683 sde_hw_rotator_enable_irq(resinfo->rot);
Alan Kwongf987ea32016-07-06 12:11:44 -04001684
Alan Kwong9487de22016-01-16 22:06:36 -05001685 SDEROT_DBG("New rotator resource:%p, priority:%d\n",
1686 resinfo, wb_id);
1687
1688 return &resinfo->hw;
1689}
1690
1691/*
1692 * sde_hw_rotator_free_ext - free the given rotator resource
1693 * @mgr: Pointer to rotator manager
1694 * @hw: Pointer to rotator resource
1695 */
1696static void sde_hw_rotator_free_ext(struct sde_rot_mgr *mgr,
1697 struct sde_rot_hw_resource *hw)
1698{
1699 struct sde_hw_rotator_resource_info *resinfo;
1700
1701 if (!mgr || !mgr->hw_data)
1702 return;
1703
1704 resinfo = container_of(hw, struct sde_hw_rotator_resource_info, hw);
1705
1706 SDEROT_DBG(
1707 "Free rotator resource:%p, priority:%d, active:%d, pending:%d\n",
1708 resinfo, hw->wb_id, atomic_read(&hw->num_active),
1709 hw->pending_count);
1710
Alan Kwongf987ea32016-07-06 12:11:44 -04001711 if (resinfo->rot->irq_num >= 0)
Alan Kwong818b7fc2016-07-24 22:07:41 -04001712 sde_hw_rotator_disable_irq(resinfo->rot);
Alan Kwongf987ea32016-07-06 12:11:44 -04001713
Alan Kwong9487de22016-01-16 22:06:36 -05001714 devm_kfree(&mgr->pdev->dev, resinfo);
1715}
1716
1717/*
1718 * sde_hw_rotator_alloc_rotctx - allocate rotator context
1719 * @rot: Pointer to rotator hw
1720 * @hw: Pointer to rotator resource
1721 * @session_id: Session identifier of this context
Alan Kwong6bc64622017-02-04 17:36:03 -08001722 * @sbuf_mode: true if stream buffer is requested
Alan Kwong9487de22016-01-16 22:06:36 -05001723 *
1724 * This function allocates a new rotator context for the given session id.
1725 */
1726static struct sde_hw_rotator_context *sde_hw_rotator_alloc_rotctx(
1727 struct sde_hw_rotator *rot,
1728 struct sde_rot_hw_resource *hw,
Alan Kwong6bc64622017-02-04 17:36:03 -08001729 u32 session_id,
1730 bool sbuf_mode)
Alan Kwong9487de22016-01-16 22:06:36 -05001731{
1732 struct sde_hw_rotator_context *ctx;
1733
1734 /* Allocate rotator context */
1735 ctx = devm_kzalloc(&rot->pdev->dev, sizeof(*ctx), GFP_KERNEL);
1736 if (!ctx) {
1737 SDEROT_ERR("Failed allocation HW rotator context\n");
1738 return NULL;
1739 }
1740
1741 ctx->rot = rot;
1742 ctx->q_id = hw->wb_id;
1743 ctx->session_id = session_id;
1744 ctx->hwres = hw;
1745 ctx->timestamp = atomic_add_return(1, &rot->timestamp[ctx->q_id]);
1746 ctx->timestamp &= SDE_REGDMA_SWTS_MASK;
1747 ctx->is_secure = false;
Alan Kwong6bc64622017-02-04 17:36:03 -08001748 ctx->sbuf_mode = sbuf_mode;
1749 INIT_LIST_HEAD(&ctx->list);
Alan Kwong9487de22016-01-16 22:06:36 -05001750
1751 ctx->regdma_base = rot->cmd_wr_ptr[ctx->q_id]
1752 [sde_hw_rotator_get_regdma_ctxidx(ctx)];
1753 ctx->regdma_wrptr = ctx->regdma_base;
1754 ctx->ts_addr = (dma_addr_t)((u32 *)rot->swts_buf.addr +
1755 ctx->q_id * SDE_HW_ROT_REGDMA_TOTAL_CTX +
1756 sde_hw_rotator_get_regdma_ctxidx(ctx));
1757
Alan Kwong818b7fc2016-07-24 22:07:41 -04001758 ctx->last_regdma_timestamp = SDE_REGDMA_SWTS_INVALID;
1759
Alan Kwong9487de22016-01-16 22:06:36 -05001760 init_completion(&ctx->rot_comp);
Alan Kwong818b7fc2016-07-24 22:07:41 -04001761 init_waitqueue_head(&ctx->regdma_waitq);
Alan Kwong9487de22016-01-16 22:06:36 -05001762
1763 /* Store rotator context for lookup purpose */
1764 sde_hw_rotator_put_ctx(ctx);
1765
1766 SDEROT_DBG(
Alan Kwong6bc64622017-02-04 17:36:03 -08001767 "New rot CTX:%p, ctxidx:%d, session-id:%d, prio:%d, timestamp:%X, active:%d sbuf:%d\n",
Alan Kwong9487de22016-01-16 22:06:36 -05001768 ctx, sde_hw_rotator_get_regdma_ctxidx(ctx), ctx->session_id,
1769 ctx->q_id, ctx->timestamp,
Alan Kwong6bc64622017-02-04 17:36:03 -08001770 atomic_read(&ctx->hwres->num_active),
1771 ctx->sbuf_mode);
Alan Kwong9487de22016-01-16 22:06:36 -05001772
1773 return ctx;
1774}
1775
1776/*
1777 * sde_hw_rotator_free_rotctx - free the given rotator context
1778 * @rot: Pointer to rotator hw
1779 * @ctx: Pointer to rotator context
1780 */
1781static void sde_hw_rotator_free_rotctx(struct sde_hw_rotator *rot,
1782 struct sde_hw_rotator_context *ctx)
1783{
1784 if (!rot || !ctx)
1785 return;
1786
1787 SDEROT_DBG(
Alan Kwong6bc64622017-02-04 17:36:03 -08001788 "Free rot CTX:%p, ctxidx:%d, session-id:%d, prio:%d, timestamp:%X, active:%d sbuf:%d\n",
Alan Kwong9487de22016-01-16 22:06:36 -05001789 ctx, sde_hw_rotator_get_regdma_ctxidx(ctx), ctx->session_id,
1790 ctx->q_id, ctx->timestamp,
Alan Kwong6bc64622017-02-04 17:36:03 -08001791 atomic_read(&ctx->hwres->num_active),
1792 ctx->sbuf_mode);
Alan Kwong9487de22016-01-16 22:06:36 -05001793
Benjamin Chanc3e185f2016-11-08 21:48:21 -05001794 /* Clear rotator context from lookup purpose */
1795 sde_hw_rotator_clr_ctx(ctx);
Alan Kwong9487de22016-01-16 22:06:36 -05001796
1797 devm_kfree(&rot->pdev->dev, ctx);
1798}
1799
1800/*
1801 * sde_hw_rotator_config - configure hw for the given rotation entry
1802 * @hw: Pointer to rotator resource
1803 * @entry: Pointer to rotation entry
1804 *
1805 * This function setup the fetch/writeback/rotator blocks, as well as VBIF
1806 * based on the given rotation entry.
1807 */
1808static int sde_hw_rotator_config(struct sde_rot_hw_resource *hw,
1809 struct sde_rot_entry *entry)
1810{
1811 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
1812 struct sde_hw_rotator *rot;
1813 struct sde_hw_rotator_resource_info *resinfo;
1814 struct sde_hw_rotator_context *ctx;
1815 struct sde_hw_rot_sspp_cfg sspp_cfg;
1816 struct sde_hw_rot_wb_cfg wb_cfg;
1817 u32 danger_lut = 0; /* applicable for realtime client only */
1818 u32 safe_lut = 0; /* applicable for realtime client only */
1819 u32 flags = 0;
1820 struct sde_rotation_item *item;
Alan Kwong6bc64622017-02-04 17:36:03 -08001821 int ret;
Alan Kwong9487de22016-01-16 22:06:36 -05001822
1823 if (!hw || !entry) {
1824 SDEROT_ERR("null hw resource/entry\n");
1825 return -EINVAL;
1826 }
1827
1828 resinfo = container_of(hw, struct sde_hw_rotator_resource_info, hw);
1829 rot = resinfo->rot;
1830 item = &entry->item;
1831
Alan Kwong6bc64622017-02-04 17:36:03 -08001832 ctx = sde_hw_rotator_alloc_rotctx(rot, hw, item->session_id,
1833 item->output.sbuf);
Alan Kwong9487de22016-01-16 22:06:36 -05001834 if (!ctx) {
1835 SDEROT_ERR("Failed allocating rotator context!!\n");
1836 return -EINVAL;
1837 }
1838
Alan Kwong6bc64622017-02-04 17:36:03 -08001839 /* save entry for debugging purposes */
1840 ctx->last_entry = entry;
1841
1842 if (test_bit(SDE_CAPS_SBUF_1, mdata->sde_caps_map)) {
1843 if (entry->dst_buf.sbuf) {
1844 u32 op_mode;
1845
1846 if (entry->item.trigger ==
1847 SDE_ROTATOR_TRIGGER_COMMAND)
1848 ctx->start_ctrl = (rot->cmd_trigger << 4);
1849 else if (entry->item.trigger ==
1850 SDE_ROTATOR_TRIGGER_VIDEO)
1851 ctx->start_ctrl = (rot->vid_trigger << 4);
1852 else
1853 ctx->start_ctrl = 0;
1854
1855 ctx->sys_cache_mode = BIT(15) |
1856 ((item->output.scid & 0x1f) << 8) |
1857 (item->output.writeback ? 0x5 : 0);
1858
1859 ctx->op_mode = BIT(4) |
1860 ((ctx->rot->sbuf_headroom & 0xff) << 8);
1861
1862 /* detect transition to inline mode */
1863 op_mode = (SDE_ROTREG_READ(rot->mdss_base,
1864 ROTTOP_OP_MODE) >> 4) & 0x3;
1865 if (!op_mode) {
1866 u32 status;
1867
1868 status = SDE_ROTREG_READ(rot->mdss_base,
1869 ROTTOP_STATUS);
1870 if (status & BIT(0)) {
1871 SDEROT_ERR("rotator busy 0x%x\n",
1872 status);
1873 sde_hw_rotator_dump_status(rot);
1874 SDEROT_EVTLOG_TOUT_HANDLER("rot",
1875 "vbif_dbg_bus",
1876 "panic");
1877 }
1878 }
1879
1880 } else {
1881 ctx->start_ctrl = BIT(0);
1882 ctx->sys_cache_mode = 0;
1883 ctx->op_mode = 0;
1884 }
1885 } else {
1886 ctx->start_ctrl = BIT(0);
1887 }
1888
1889 SDEROT_EVTLOG(ctx->start_ctrl, ctx->sys_cache_mode, ctx->op_mode);
1890
Benjamin Chan0f9e61d2016-09-16 16:01:09 -04001891 if (rot->reset_hw_ts) {
1892 SDEROT_EVTLOG(rot->last_hw_ts);
1893 SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_TIMESTAMP_REG,
1894 rot->last_hw_ts);
1895 /* ensure write is issued to the rotator HW */
1896 wmb();
1897 rot->reset_hw_ts = false;
1898 }
1899
Alan Kwong9487de22016-01-16 22:06:36 -05001900 flags = (item->flags & SDE_ROTATION_FLIP_LR) ?
1901 SDE_ROT_FLAG_FLIP_LR : 0;
1902 flags |= (item->flags & SDE_ROTATION_FLIP_UD) ?
1903 SDE_ROT_FLAG_FLIP_UD : 0;
1904 flags |= (item->flags & SDE_ROTATION_90) ?
1905 SDE_ROT_FLAG_ROT_90 : 0;
1906 flags |= (item->flags & SDE_ROTATION_DEINTERLACE) ?
1907 SDE_ROT_FLAG_DEINTERLACE : 0;
1908 flags |= (item->flags & SDE_ROTATION_SECURE) ?
1909 SDE_ROT_FLAG_SECURE_OVERLAY_SESSION : 0;
Abhijit Kulkarni298c8232016-09-26 22:32:10 -07001910 flags |= (item->flags & SDE_ROTATION_SECURE_CAMERA) ?
1911 SDE_ROT_FLAG_SECURE_CAMERA_SESSION : 0;
1912
Alan Kwong9487de22016-01-16 22:06:36 -05001913
1914 sspp_cfg.img_width = item->input.width;
1915 sspp_cfg.img_height = item->input.height;
Benjamin Chan99eb63b2016-12-21 15:45:26 -05001916 sspp_cfg.fps = entry->perf->config.frame_rate;
1917 sspp_cfg.bw = entry->perf->bw;
Alan Kwong9487de22016-01-16 22:06:36 -05001918 sspp_cfg.fmt = sde_get_format_params(item->input.format);
1919 if (!sspp_cfg.fmt) {
1920 SDEROT_ERR("null format\n");
Alan Kwong6bc64622017-02-04 17:36:03 -08001921 ret = -EINVAL;
1922 goto error;
Alan Kwong9487de22016-01-16 22:06:36 -05001923 }
1924 sspp_cfg.src_rect = &item->src_rect;
1925 sspp_cfg.data = &entry->src_buf;
1926 sde_mdp_get_plane_sizes(sspp_cfg.fmt, item->input.width,
1927 item->input.height, &sspp_cfg.src_plane,
1928 0, /* No bwc_mode */
1929 (flags & SDE_ROT_FLAG_SOURCE_ROTATED_90) ?
1930 true : false);
1931
1932 rot->ops.setup_rotator_fetchengine(ctx, ctx->q_id,
Benjamin Chanfb6faa32016-08-16 17:21:01 -04001933 &sspp_cfg, danger_lut, safe_lut,
1934 entry->dnsc_factor_w, entry->dnsc_factor_h, flags);
Alan Kwong9487de22016-01-16 22:06:36 -05001935
1936 wb_cfg.img_width = item->output.width;
1937 wb_cfg.img_height = item->output.height;
Benjamin Chan99eb63b2016-12-21 15:45:26 -05001938 wb_cfg.fps = entry->perf->config.frame_rate;
1939 wb_cfg.bw = entry->perf->bw;
Alan Kwong9487de22016-01-16 22:06:36 -05001940 wb_cfg.fmt = sde_get_format_params(item->output.format);
1941 wb_cfg.dst_rect = &item->dst_rect;
1942 wb_cfg.data = &entry->dst_buf;
1943 sde_mdp_get_plane_sizes(wb_cfg.fmt, item->output.width,
1944 item->output.height, &wb_cfg.dst_plane,
1945 0, /* No bwc_mode */
1946 (flags & SDE_ROT_FLAG_ROT_90) ? true : false);
1947
1948 wb_cfg.v_downscale_factor = entry->dnsc_factor_h;
1949 wb_cfg.h_downscale_factor = entry->dnsc_factor_w;
1950
1951 rot->ops.setup_rotator_wbengine(ctx, ctx->q_id, &wb_cfg, flags);
1952
1953 /* setup VA mapping for debugfs */
1954 if (rot->dbgmem) {
1955 sde_hw_rotator_map_vaddr(&ctx->src_dbgbuf,
1956 &item->input,
1957 &entry->src_buf);
1958
1959 sde_hw_rotator_map_vaddr(&ctx->dst_dbgbuf,
1960 &item->output,
1961 &entry->dst_buf);
1962 }
1963
Benjamin Chan0f9e61d2016-09-16 16:01:09 -04001964 SDEROT_EVTLOG(ctx->timestamp, flags,
1965 item->input.width, item->input.height,
Benjamin Chan53e3bce2016-08-31 14:43:29 -04001966 item->output.width, item->output.height,
Benjamin Chan59a06052017-01-12 18:06:03 -05001967 entry->src_buf.p[0].addr, entry->dst_buf.p[0].addr,
Benjamin Chan1b94f952017-01-23 17:42:30 -05001968 item->input.format, item->output.format,
1969 entry->perf->config.frame_rate);
Benjamin Chan53e3bce2016-08-31 14:43:29 -04001970
Alan Kwong9487de22016-01-16 22:06:36 -05001971 if (mdata->default_ot_rd_limit) {
1972 struct sde_mdp_set_ot_params ot_params;
1973
1974 memset(&ot_params, 0, sizeof(struct sde_mdp_set_ot_params));
1975 ot_params.xin_id = XIN_SSPP;
1976 ot_params.num = 0; /* not used */
Alan Kwongeffb5ee2016-03-12 19:47:45 -05001977 ot_params.width = entry->perf->config.input.width;
1978 ot_params.height = entry->perf->config.input.height;
1979 ot_params.fps = entry->perf->config.frame_rate;
Alan Kwong9487de22016-01-16 22:06:36 -05001980 ot_params.reg_off_vbif_lim_conf = MMSS_VBIF_RD_LIM_CONF;
1981 ot_params.reg_off_mdp_clk_ctrl =
1982 MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0;
1983 ot_params.bit_off_mdp_clk_ctrl =
1984 MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0_XIN0;
Benjamin Chan99eb63b2016-12-21 15:45:26 -05001985 ot_params.fmt = ctx->is_traffic_shaping ?
1986 SDE_PIX_FMT_ABGR_8888 :
1987 entry->perf->config.input.format;
Benjamin Chan1b94f952017-01-23 17:42:30 -05001988 ot_params.rotsts_base = rot->mdss_base + ROTTOP_STATUS;
1989 ot_params.rotsts_busy_mask = ROT_BUSY_BIT;
Alan Kwong9487de22016-01-16 22:06:36 -05001990 sde_mdp_set_ot_limit(&ot_params);
1991 }
1992
1993 if (mdata->default_ot_wr_limit) {
1994 struct sde_mdp_set_ot_params ot_params;
1995
1996 memset(&ot_params, 0, sizeof(struct sde_mdp_set_ot_params));
1997 ot_params.xin_id = XIN_WRITEBACK;
1998 ot_params.num = 0; /* not used */
Alan Kwongeffb5ee2016-03-12 19:47:45 -05001999 ot_params.width = entry->perf->config.input.width;
2000 ot_params.height = entry->perf->config.input.height;
2001 ot_params.fps = entry->perf->config.frame_rate;
Alan Kwong9487de22016-01-16 22:06:36 -05002002 ot_params.reg_off_vbif_lim_conf = MMSS_VBIF_WR_LIM_CONF;
2003 ot_params.reg_off_mdp_clk_ctrl =
2004 MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0;
2005 ot_params.bit_off_mdp_clk_ctrl =
2006 MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0_XIN1;
Benjamin Chan99eb63b2016-12-21 15:45:26 -05002007 ot_params.fmt = ctx->is_traffic_shaping ?
2008 SDE_PIX_FMT_ABGR_8888 :
2009 entry->perf->config.input.format;
Benjamin Chan1b94f952017-01-23 17:42:30 -05002010 ot_params.rotsts_base = rot->mdss_base + ROTTOP_STATUS;
2011 ot_params.rotsts_busy_mask = ROT_BUSY_BIT;
Alan Kwong9487de22016-01-16 22:06:36 -05002012 sde_mdp_set_ot_limit(&ot_params);
2013 }
2014
2015 if (test_bit(SDE_QOS_PER_PIPE_LUT, mdata->sde_qos_map)) {
2016 u32 qos_lut = 0; /* low priority for nrt read client */
2017
2018 trace_rot_perf_set_qos_luts(XIN_SSPP, sspp_cfg.fmt->format,
2019 qos_lut, sde_mdp_is_linear_format(sspp_cfg.fmt));
2020
2021 SDE_ROTREG_WRITE(rot->mdss_base, ROT_SSPP_CREQ_LUT, qos_lut);
2022 }
2023
Jayant Shekhardee61a02017-02-08 11:59:00 +05302024 /* Set CDP control registers to 0 if CDP is disabled */
2025 if (!test_bit(SDE_QOS_CDP, mdata->sde_qos_map)) {
2026 SDE_ROTREG_WRITE(rot->mdss_base, ROT_SSPP_CDP_CNTL, 0x0);
2027 SDE_ROTREG_WRITE(rot->mdss_base, ROT_WB_CDP_CNTL, 0x0);
2028 }
2029
Alan Kwong9487de22016-01-16 22:06:36 -05002030 if (mdata->npriority_lvl > 0) {
2031 u32 mask, reg_val, i, vbif_qos;
2032
2033 for (i = 0; i < mdata->npriority_lvl; i++) {
2034 reg_val = SDE_VBIF_READ(mdata,
2035 MMSS_VBIF_NRT_VBIF_QOS_REMAP_00 + i*4);
2036 mask = 0x3 << (XIN_SSPP * 2);
2037 reg_val &= ~(mask);
2038 vbif_qos = mdata->vbif_nrt_qos[i];
2039 reg_val |= vbif_qos << (XIN_SSPP * 2);
2040 /* ensure write is issued after the read operation */
2041 mb();
2042 SDE_VBIF_WRITE(mdata,
2043 MMSS_VBIF_NRT_VBIF_QOS_REMAP_00 + i*4,
2044 reg_val);
2045 }
2046 }
2047
2048 /* Enable write gather for writeback to remove write gaps, which
2049 * may hang AXI/BIMC/SDE.
2050 */
2051 SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_WRITE_GATHTER_EN,
2052 BIT(XIN_WRITEBACK));
2053
2054 return 0;
Alan Kwong6bc64622017-02-04 17:36:03 -08002055
2056error:
2057 sde_hw_rotator_free_rotctx(rot, ctx);
2058 return ret;
Alan Kwong9487de22016-01-16 22:06:36 -05002059}
2060
2061/*
2062 * sde_hw_rotator_kickoff - kickoff processing on the given entry
2063 * @hw: Pointer to rotator resource
2064 * @entry: Pointer to rotation entry
2065 */
2066static int sde_hw_rotator_kickoff(struct sde_rot_hw_resource *hw,
2067 struct sde_rot_entry *entry)
2068{
2069 struct sde_hw_rotator *rot;
2070 struct sde_hw_rotator_resource_info *resinfo;
2071 struct sde_hw_rotator_context *ctx;
Alan Kwong9487de22016-01-16 22:06:36 -05002072
2073 if (!hw || !entry) {
2074 SDEROT_ERR("null hw resource/entry\n");
2075 return -EINVAL;
2076 }
2077
2078 resinfo = container_of(hw, struct sde_hw_rotator_resource_info, hw);
2079 rot = resinfo->rot;
2080
2081 /* Lookup rotator context from session-id */
2082 ctx = sde_hw_rotator_get_ctx(rot, entry->item.session_id, hw->wb_id);
2083 if (!ctx) {
2084 SDEROT_ERR("Cannot locate rotator ctx from sesison id:%d\n",
2085 entry->item.session_id);
Benjamin Chan62b94ed2016-08-18 23:55:21 -04002086 return -EINVAL;
Alan Kwong9487de22016-01-16 22:06:36 -05002087 }
Alan Kwong9487de22016-01-16 22:06:36 -05002088
Alan Kwong9487de22016-01-16 22:06:36 -05002089 rot->ops.start_rotator(ctx, ctx->q_id);
2090
2091 return 0;
2092}
2093
2094/*
2095 * sde_hw_rotator_wait4done - wait for completion notification
2096 * @hw: Pointer to rotator resource
2097 * @entry: Pointer to rotation entry
2098 *
2099 * This function blocks until the given entry is complete, error
2100 * is detected, or timeout.
2101 */
2102static int sde_hw_rotator_wait4done(struct sde_rot_hw_resource *hw,
2103 struct sde_rot_entry *entry)
2104{
2105 struct sde_hw_rotator *rot;
2106 struct sde_hw_rotator_resource_info *resinfo;
2107 struct sde_hw_rotator_context *ctx;
2108 int ret;
2109
2110 if (!hw || !entry) {
2111 SDEROT_ERR("null hw resource/entry\n");
2112 return -EINVAL;
2113 }
2114
2115 resinfo = container_of(hw, struct sde_hw_rotator_resource_info, hw);
2116 rot = resinfo->rot;
2117
2118 /* Lookup rotator context from session-id */
2119 ctx = sde_hw_rotator_get_ctx(rot, entry->item.session_id, hw->wb_id);
2120 if (!ctx) {
2121 SDEROT_ERR("Cannot locate rotator ctx from sesison id:%d\n",
2122 entry->item.session_id);
Benjamin Chan62b94ed2016-08-18 23:55:21 -04002123 return -EINVAL;
Alan Kwong9487de22016-01-16 22:06:36 -05002124 }
Alan Kwong9487de22016-01-16 22:06:36 -05002125
2126 ret = rot->ops.wait_rotator_done(ctx, ctx->q_id, 0);
2127
Alan Kwong9487de22016-01-16 22:06:36 -05002128 if (rot->dbgmem) {
2129 sde_hw_rotator_unmap_vaddr(&ctx->src_dbgbuf);
2130 sde_hw_rotator_unmap_vaddr(&ctx->dst_dbgbuf);
2131 }
2132
2133 /* Current rotator context job is finished, time to free up*/
2134 sde_hw_rotator_free_rotctx(rot, ctx);
2135
2136 return ret;
2137}
2138
2139/*
2140 * sde_rotator_hw_rev_init - setup feature and/or capability bitmask
2141 * @rot: Pointer to hw rotator
2142 *
2143 * This function initializes feature and/or capability bitmask based on
2144 * h/w version read from the device.
2145 */
2146static int sde_rotator_hw_rev_init(struct sde_hw_rotator *rot)
2147{
2148 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
2149 u32 hw_version;
2150
2151 if (!mdata) {
2152 SDEROT_ERR("null rotator data\n");
2153 return -EINVAL;
2154 }
2155
2156 hw_version = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_HW_VERSION);
2157 SDEROT_DBG("hw version %8.8x\n", hw_version);
2158
2159 clear_bit(SDE_QOS_PER_PIPE_IB, mdata->sde_qos_map);
2160 set_bit(SDE_QOS_OVERHEAD_FACTOR, mdata->sde_qos_map);
2161 clear_bit(SDE_QOS_CDP, mdata->sde_qos_map);
2162 set_bit(SDE_QOS_OTLIM, mdata->sde_qos_map);
2163 set_bit(SDE_QOS_PER_PIPE_LUT, mdata->sde_qos_map);
2164 clear_bit(SDE_QOS_SIMPLIFIED_PREFILL, mdata->sde_qos_map);
2165
2166 set_bit(SDE_CAPS_R3_WB, mdata->sde_caps_map);
2167
Alan Kwong6bc64622017-02-04 17:36:03 -08002168 /* features exposed via rotator top h/w version */
Benjamin Chanfb6faa32016-08-16 17:21:01 -04002169 if (hw_version != SDE_ROT_TYPE_V1_0) {
2170 SDEROT_DBG("Supporting 1.5 downscale for SDE Rotator\n");
2171 set_bit(SDE_CAPS_R3_1P5_DOWNSCALE, mdata->sde_caps_map);
2172 }
2173
Abhijit Kulkarni298c8232016-09-26 22:32:10 -07002174 set_bit(SDE_CAPS_SEC_ATTACH_DETACH_SMMU, mdata->sde_caps_map);
2175
Benjamin Chan53e3bce2016-08-31 14:43:29 -04002176 mdata->nrt_vbif_dbg_bus = nrt_vbif_dbg_bus_r3;
2177 mdata->nrt_vbif_dbg_bus_size =
2178 ARRAY_SIZE(nrt_vbif_dbg_bus_r3);
2179
2180 mdata->regdump = sde_rot_r3_regdump;
2181 mdata->regdump_size = ARRAY_SIZE(sde_rot_r3_regdump);
Benjamin Chan0f9e61d2016-09-16 16:01:09 -04002182 SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_TIMESTAMP_REG, 0);
Alan Kwong6bc64622017-02-04 17:36:03 -08002183
2184 /* features exposed via mdss h/w version */
2185 if (IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, SDE_MDP_HW_REV_400)) {
2186 SDEROT_DBG("Supporting sys cache inline rotation\n");
2187 set_bit(SDE_CAPS_SBUF_1, mdata->sde_caps_map);
2188 rot->inpixfmts = sde_hw_rotator_v4_inpixfmts;
2189 rot->num_inpixfmt = ARRAY_SIZE(sde_hw_rotator_v4_inpixfmts);
2190 rot->outpixfmts = sde_hw_rotator_v4_outpixfmts;
2191 rot->num_outpixfmt = ARRAY_SIZE(sde_hw_rotator_v4_outpixfmts);
2192 rot->downscale_caps =
2193 "LINEAR/1.5/2/4/8/16/32/64 TILE/1.5/2/4 TP10/1.5/2";
2194 } else {
2195 rot->inpixfmts = sde_hw_rotator_v3_inpixfmts;
2196 rot->num_inpixfmt = ARRAY_SIZE(sde_hw_rotator_v3_inpixfmts);
2197 rot->outpixfmts = sde_hw_rotator_v3_outpixfmts;
2198 rot->num_outpixfmt = ARRAY_SIZE(sde_hw_rotator_v3_outpixfmts);
2199 rot->downscale_caps = (hw_version == SDE_ROT_TYPE_V1_0) ?
2200 "LINEAR/2/4/8/16/32/64 TILE/2/4 TP10/2" :
2201 "LINEAR/1.5/2/4/8/16/32/64 TILE/1.5/2/4 TP10/1.5/2";
2202 }
2203
Alan Kwong9487de22016-01-16 22:06:36 -05002204 return 0;
2205}
2206
2207/*
2208 * sde_hw_rotator_rotirq_handler - non-regdma interrupt handler
2209 * @irq: Interrupt number
2210 * @ptr: Pointer to private handle provided during registration
2211 *
2212 * This function services rotator interrupt and wakes up waiting client
2213 * with pending rotation requests already submitted to h/w.
2214 */
2215static irqreturn_t sde_hw_rotator_rotirq_handler(int irq, void *ptr)
2216{
2217 struct sde_hw_rotator *rot = ptr;
2218 struct sde_hw_rotator_context *ctx;
2219 irqreturn_t ret = IRQ_NONE;
2220 u32 isr;
2221
2222 isr = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_INTR_STATUS);
2223
2224 SDEROT_DBG("intr_status = %8.8x\n", isr);
2225
2226 if (isr & ROT_DONE_MASK) {
2227 if (rot->irq_num >= 0)
Alan Kwong818b7fc2016-07-24 22:07:41 -04002228 sde_hw_rotator_disable_irq(rot);
Alan Kwong9487de22016-01-16 22:06:36 -05002229 SDEROT_DBG("Notify rotator complete\n");
2230
2231 /* Normal rotator only 1 session, no need to lookup */
2232 ctx = rot->rotCtx[0][0];
2233 WARN_ON(ctx == NULL);
2234 complete_all(&ctx->rot_comp);
2235
2236 spin_lock(&rot->rotisr_lock);
2237 SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_CLEAR,
2238 ROT_DONE_CLEAR);
2239 spin_unlock(&rot->rotisr_lock);
2240 ret = IRQ_HANDLED;
2241 }
2242
2243 return ret;
2244}
2245
2246/*
2247 * sde_hw_rotator_regdmairq_handler - regdma interrupt handler
2248 * @irq: Interrupt number
2249 * @ptr: Pointer to private handle provided during registration
2250 *
2251 * This function services rotator interrupt, decoding the source of
2252 * events (high/low priority queue), and wakes up all waiting clients
2253 * with pending rotation requests already submitted to h/w.
2254 */
2255static irqreturn_t sde_hw_rotator_regdmairq_handler(int irq, void *ptr)
2256{
2257 struct sde_hw_rotator *rot = ptr;
2258 struct sde_hw_rotator_context *ctx;
2259 irqreturn_t ret = IRQ_NONE;
2260 u32 isr;
2261 u32 ts;
2262 u32 q_id;
2263
2264 isr = SDE_ROTREG_READ(rot->mdss_base, REGDMA_CSR_REGDMA_INT_STATUS);
Alan Kwong818b7fc2016-07-24 22:07:41 -04002265 /* acknowledge interrupt before reading latest timestamp */
2266 SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_INT_CLEAR, isr);
Alan Kwong9487de22016-01-16 22:06:36 -05002267 ts = SDE_ROTREG_READ(rot->mdss_base, REGDMA_TIMESTAMP_REG);
2268
2269 SDEROT_DBG("intr_status = %8.8x, sw_TS:%X\n", isr, ts);
2270
2271 /* Any REGDMA status, including error and watchdog timer, should
2272 * trigger and wake up waiting thread
2273 */
2274 if (isr & (REGDMA_INT_HIGH_MASK | REGDMA_INT_LOW_MASK)) {
2275 spin_lock(&rot->rotisr_lock);
2276
2277 /*
2278 * Obtain rotator context based on timestamp from regdma
2279 * and low/high interrupt status
2280 */
2281 if (isr & REGDMA_INT_HIGH_MASK) {
2282 q_id = ROT_QUEUE_HIGH_PRIORITY;
2283 ts = ts & SDE_REGDMA_SWTS_MASK;
2284 } else if (isr & REGDMA_INT_LOW_MASK) {
2285 q_id = ROT_QUEUE_LOW_PRIORITY;
2286 ts = (ts >> SDE_REGDMA_SWTS_SHIFT) &
2287 SDE_REGDMA_SWTS_MASK;
Benjamin Chan62b94ed2016-08-18 23:55:21 -04002288 } else {
2289 SDEROT_ERR("unknown ISR status: isr=0x%X\n", isr);
2290 goto done_isr_handle;
Alan Kwong9487de22016-01-16 22:06:36 -05002291 }
Alan Kwong6bc64622017-02-04 17:36:03 -08002292
2293 /*
2294 * Timestamp packet is not available in sbuf mode.
2295 * Simulate timestamp update in the handler instead.
2296 */
2297 if (!list_empty(&rot->sbuf_ctx[q_id])) {
2298 ctx = list_first_entry_or_null(&rot->sbuf_ctx[q_id],
2299 struct sde_hw_rotator_context, list);
2300 if (ctx) {
2301 ts = ctx->timestamp;
2302 sde_hw_rotator_update_swts(rot, ctx, ts);
2303 SDEROT_DBG("update swts:0x%X\n", ts);
2304 } else {
2305 SDEROT_ERR("invalid swts ctx\n");
2306 }
2307 }
2308
Alan Kwong9487de22016-01-16 22:06:36 -05002309 ctx = rot->rotCtx[q_id][ts & SDE_HW_ROT_REGDMA_SEG_MASK];
Alan Kwong9487de22016-01-16 22:06:36 -05002310
2311 /*
2312 * Wake up all waiting context from the current and previous
2313 * SW Timestamp.
2314 */
Alan Kwong818b7fc2016-07-24 22:07:41 -04002315 while (ctx &&
2316 sde_hw_rotator_elapsed_swts(ctx->timestamp, ts) >= 0) {
Alan Kwong9487de22016-01-16 22:06:36 -05002317 ctx->last_regdma_isr_status = isr;
2318 ctx->last_regdma_timestamp = ts;
2319 SDEROT_DBG(
Alan Kwongf987ea32016-07-06 12:11:44 -04002320 "regdma complete: ctx:%p, ts:%X\n", ctx, ts);
Alan Kwong818b7fc2016-07-24 22:07:41 -04002321 wake_up_all(&ctx->regdma_waitq);
Alan Kwong9487de22016-01-16 22:06:36 -05002322
2323 ts = (ts - 1) & SDE_REGDMA_SWTS_MASK;
2324 ctx = rot->rotCtx[q_id]
2325 [ts & SDE_HW_ROT_REGDMA_SEG_MASK];
Alan Kwong818b7fc2016-07-24 22:07:41 -04002326 };
Alan Kwong9487de22016-01-16 22:06:36 -05002327
Benjamin Chan62b94ed2016-08-18 23:55:21 -04002328done_isr_handle:
Alan Kwong9487de22016-01-16 22:06:36 -05002329 spin_unlock(&rot->rotisr_lock);
2330 ret = IRQ_HANDLED;
2331 } else if (isr & REGDMA_INT_ERR_MASK) {
2332 /*
2333 * For REGDMA Err, we save the isr info and wake up
2334 * all waiting contexts
2335 */
2336 int i, j;
2337
2338 SDEROT_ERR(
2339 "regdma err isr:%X, wake up all waiting contexts\n",
2340 isr);
2341
2342 spin_lock(&rot->rotisr_lock);
2343
2344 for (i = 0; i < ROT_QUEUE_MAX; i++) {
2345 for (j = 0; j < SDE_HW_ROT_REGDMA_TOTAL_CTX; j++) {
2346 ctx = rot->rotCtx[i][j];
2347 if (ctx && ctx->last_regdma_isr_status == 0) {
2348 ctx->last_regdma_isr_status = isr;
2349 ctx->last_regdma_timestamp = ts;
Alan Kwong818b7fc2016-07-24 22:07:41 -04002350 wake_up_all(&ctx->regdma_waitq);
Alan Kwong9487de22016-01-16 22:06:36 -05002351 SDEROT_DBG("Wakeup rotctx[%d][%d]:%p\n",
2352 i, j, ctx);
2353 }
2354 }
2355 }
2356
Alan Kwong9487de22016-01-16 22:06:36 -05002357 spin_unlock(&rot->rotisr_lock);
2358 ret = IRQ_HANDLED;
2359 }
2360
2361 return ret;
2362}
2363
2364/*
2365 * sde_hw_rotator_validate_entry - validate rotation entry
2366 * @mgr: Pointer to rotator manager
2367 * @entry: Pointer to rotation entry
2368 *
2369 * This function validates the given rotation entry and provides possible
2370 * fixup (future improvement) if available. This function returns 0 if
2371 * the entry is valid, and returns error code otherwise.
2372 */
2373static int sde_hw_rotator_validate_entry(struct sde_rot_mgr *mgr,
2374 struct sde_rot_entry *entry)
2375{
Benjamin Chanfb6faa32016-08-16 17:21:01 -04002376 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
Alan Kwong9487de22016-01-16 22:06:36 -05002377 int ret = 0;
2378 u16 src_w, src_h, dst_w, dst_h;
2379 struct sde_rotation_item *item = &entry->item;
2380 struct sde_mdp_format_params *fmt;
2381
2382 src_w = item->src_rect.w;
2383 src_h = item->src_rect.h;
2384
2385 if (item->flags & SDE_ROTATION_90) {
2386 dst_w = item->dst_rect.h;
2387 dst_h = item->dst_rect.w;
2388 } else {
2389 dst_w = item->dst_rect.w;
2390 dst_h = item->dst_rect.h;
2391 }
2392
2393 entry->dnsc_factor_w = 0;
2394 entry->dnsc_factor_h = 0;
2395
Alan Kwong6bc64622017-02-04 17:36:03 -08002396 if (item->output.sbuf &&
2397 !test_bit(SDE_CAPS_SBUF_1, mdata->sde_caps_map)) {
2398 SDEROT_ERR("stream buffer not supported\n");
2399 return -EINVAL;
2400 }
2401
Alan Kwong9487de22016-01-16 22:06:36 -05002402 if ((src_w != dst_w) || (src_h != dst_h)) {
2403 if ((src_w % dst_w) || (src_h % dst_h)) {
2404 SDEROT_DBG("non integral scale not support\n");
2405 ret = -EINVAL;
Benjamin Chanfb6faa32016-08-16 17:21:01 -04002406 goto dnsc_1p5_check;
Alan Kwong9487de22016-01-16 22:06:36 -05002407 }
2408 entry->dnsc_factor_w = src_w / dst_w;
2409 if ((entry->dnsc_factor_w & (entry->dnsc_factor_w - 1)) ||
2410 (entry->dnsc_factor_w > 64)) {
2411 SDEROT_DBG("non power-of-2 w_scale not support\n");
2412 ret = -EINVAL;
2413 goto dnsc_err;
2414 }
2415 entry->dnsc_factor_h = src_h / dst_h;
2416 if ((entry->dnsc_factor_h & (entry->dnsc_factor_h - 1)) ||
2417 (entry->dnsc_factor_h > 64)) {
2418 SDEROT_DBG("non power-of-2 h_scale not support\n");
2419 ret = -EINVAL;
2420 goto dnsc_err;
2421 }
2422 }
2423
Benjamin Chan0e96afd2017-01-17 16:49:12 -05002424 fmt = sde_get_format_params(item->output.format);
Benjamin Chan886ff672016-11-07 15:23:17 -05002425 /*
2426 * Rotator downscale support max 4 times for UBWC format and
2427 * max 2 times for TP10/TP10_UBWC format
2428 */
2429 if (sde_mdp_is_ubwc_format(fmt) && (entry->dnsc_factor_h > 4)) {
2430 SDEROT_DBG("max downscale for UBWC format is 4\n");
Alan Kwong9487de22016-01-16 22:06:36 -05002431 ret = -EINVAL;
2432 goto dnsc_err;
2433 }
Benjamin Chan886ff672016-11-07 15:23:17 -05002434 if (sde_mdp_is_tp10_format(fmt) && (entry->dnsc_factor_h > 2)) {
2435 SDEROT_DBG("downscale with TP10 cannot be more than 2\n");
Alan Kwong9487de22016-01-16 22:06:36 -05002436 ret = -EINVAL;
2437 }
Benjamin Chanfb6faa32016-08-16 17:21:01 -04002438 goto dnsc_err;
2439
2440dnsc_1p5_check:
2441 /* Check for 1.5 downscale that only applies to V2 HW */
2442 if (test_bit(SDE_CAPS_R3_1P5_DOWNSCALE, mdata->sde_caps_map)) {
2443 entry->dnsc_factor_w = src_w / dst_w;
2444 if ((entry->dnsc_factor_w != 1) ||
2445 ((dst_w * 3) != (src_w * 2))) {
2446 SDEROT_DBG(
2447 "No supporting non 1.5 downscale width ratio, src_w:%d, dst_w:%d\n",
2448 src_w, dst_w);
2449 ret = -EINVAL;
2450 goto dnsc_err;
2451 }
2452
2453 entry->dnsc_factor_h = src_h / dst_h;
2454 if ((entry->dnsc_factor_h != 1) ||
2455 ((dst_h * 3) != (src_h * 2))) {
2456 SDEROT_DBG(
2457 "Not supporting non 1.5 downscale height ratio, src_h:%d, dst_h:%d\n",
2458 src_h, dst_h);
2459 ret = -EINVAL;
2460 goto dnsc_err;
2461 }
2462 ret = 0;
2463 }
Alan Kwong9487de22016-01-16 22:06:36 -05002464
2465dnsc_err:
2466 /* Downscaler does not support asymmetrical dnsc */
2467 if (entry->dnsc_factor_w != entry->dnsc_factor_h) {
2468 SDEROT_DBG("asymmetric downscale not support\n");
2469 ret = -EINVAL;
2470 }
2471
2472 if (ret) {
2473 entry->dnsc_factor_w = 0;
2474 entry->dnsc_factor_h = 0;
2475 }
2476 return ret;
2477}
2478
2479/*
2480 * sde_hw_rotator_show_caps - output capability info to sysfs 'caps' file
2481 * @mgr: Pointer to rotator manager
2482 * @attr: Pointer to device attribute interface
2483 * @buf: Pointer to output buffer
2484 * @len: Length of output buffer
2485 */
2486static ssize_t sde_hw_rotator_show_caps(struct sde_rot_mgr *mgr,
2487 struct device_attribute *attr, char *buf, ssize_t len)
2488{
2489 struct sde_hw_rotator *hw_data;
Benjamin Chan886ff672016-11-07 15:23:17 -05002490 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
Alan Kwong9487de22016-01-16 22:06:36 -05002491 int cnt = 0;
2492
2493 if (!mgr || !buf)
2494 return 0;
2495
2496 hw_data = mgr->hw_data;
2497
2498#define SPRINT(fmt, ...) \
2499 (cnt += scnprintf(buf + cnt, len - cnt, fmt, ##__VA_ARGS__))
2500
2501 /* insert capabilities here */
Benjamin Chan886ff672016-11-07 15:23:17 -05002502 if (test_bit(SDE_CAPS_R3_1P5_DOWNSCALE, mdata->sde_caps_map))
2503 SPRINT("min_downscale=1.5\n");
2504 else
2505 SPRINT("min_downscale=2.0\n");
Alan Kwong9487de22016-01-16 22:06:36 -05002506
Benjamin Chan42db2c92016-11-22 22:50:01 -05002507 SPRINT("downscale_compression=1\n");
2508
Alan Kwong6bc64622017-02-04 17:36:03 -08002509 if (hw_data->downscale_caps)
2510 SPRINT("downscale_ratios=%s\n", hw_data->downscale_caps);
2511
Alan Kwong9487de22016-01-16 22:06:36 -05002512#undef SPRINT
2513 return cnt;
2514}
2515
2516/*
2517 * sde_hw_rotator_show_state - output state info to sysfs 'state' file
2518 * @mgr: Pointer to rotator manager
2519 * @attr: Pointer to device attribute interface
2520 * @buf: Pointer to output buffer
2521 * @len: Length of output buffer
2522 */
2523static ssize_t sde_hw_rotator_show_state(struct sde_rot_mgr *mgr,
2524 struct device_attribute *attr, char *buf, ssize_t len)
2525{
2526 struct sde_hw_rotator *rot;
2527 struct sde_hw_rotator_context *ctx;
2528 int cnt = 0;
2529 int num_active = 0;
2530 int i, j;
2531
2532 if (!mgr || !buf) {
2533 SDEROT_ERR("null parameters\n");
2534 return 0;
2535 }
2536
2537 rot = mgr->hw_data;
2538
2539#define SPRINT(fmt, ...) \
2540 (cnt += scnprintf(buf + cnt, len - cnt, fmt, ##__VA_ARGS__))
2541
2542 if (rot) {
2543 SPRINT("rot_mode=%d\n", rot->mode);
2544 SPRINT("irq_num=%d\n", rot->irq_num);
2545
2546 if (rot->mode == ROT_REGDMA_OFF) {
2547 SPRINT("max_active=1\n");
2548 SPRINT("num_active=%d\n", rot->rotCtx[0][0] ? 1 : 0);
2549 } else {
2550 for (i = 0; i < ROT_QUEUE_MAX; i++) {
2551 for (j = 0; j < SDE_HW_ROT_REGDMA_TOTAL_CTX;
2552 j++) {
2553 ctx = rot->rotCtx[i][j];
2554
2555 if (ctx) {
2556 SPRINT(
2557 "rotCtx[%d][%d]:%p\n",
2558 i, j, ctx);
2559 ++num_active;
2560 }
2561 }
2562 }
2563
2564 SPRINT("max_active=%d\n", SDE_HW_ROT_REGDMA_TOTAL_CTX);
2565 SPRINT("num_active=%d\n", num_active);
2566 }
2567 }
2568
2569#undef SPRINT
2570 return cnt;
2571}
2572
2573/*
Alan Kwongda16e442016-08-14 20:47:18 -04002574 * sde_hw_rotator_get_pixfmt - get the indexed pixel format
2575 * @mgr: Pointer to rotator manager
2576 * @index: index of pixel format
2577 * @input: true for input port; false for output port
2578 */
2579static u32 sde_hw_rotator_get_pixfmt(struct sde_rot_mgr *mgr,
2580 int index, bool input)
2581{
Alan Kwong6bc64622017-02-04 17:36:03 -08002582 struct sde_hw_rotator *rot;
2583
2584 if (!mgr || !mgr->hw_data) {
2585 SDEROT_ERR("null parameters\n");
2586 return 0;
2587 }
2588
2589 rot = mgr->hw_data;
2590
Alan Kwongda16e442016-08-14 20:47:18 -04002591 if (input) {
Alan Kwong6bc64622017-02-04 17:36:03 -08002592 if ((index < rot->num_inpixfmt) && rot->inpixfmts)
2593 return rot->inpixfmts[index];
Alan Kwongda16e442016-08-14 20:47:18 -04002594 else
2595 return 0;
2596 } else {
Alan Kwong6bc64622017-02-04 17:36:03 -08002597 if ((index < rot->num_outpixfmt) && rot->outpixfmts)
2598 return rot->outpixfmts[index];
Alan Kwongda16e442016-08-14 20:47:18 -04002599 else
2600 return 0;
2601 }
2602}
2603
2604/*
2605 * sde_hw_rotator_is_valid_pixfmt - verify if the given pixel format is valid
2606 * @mgr: Pointer to rotator manager
2607 * @pixfmt: pixel format to be verified
2608 * @input: true for input port; false for output port
2609 */
2610static int sde_hw_rotator_is_valid_pixfmt(struct sde_rot_mgr *mgr, u32 pixfmt,
2611 bool input)
2612{
Alan Kwong6bc64622017-02-04 17:36:03 -08002613 struct sde_hw_rotator *rot;
2614 u32 *pixfmts;
2615 u32 num_pixfmt;
Alan Kwongda16e442016-08-14 20:47:18 -04002616 int i;
2617
Alan Kwong6bc64622017-02-04 17:36:03 -08002618 if (!mgr || !mgr->hw_data) {
2619 SDEROT_ERR("null parameters\n");
2620 return false;
Alan Kwongda16e442016-08-14 20:47:18 -04002621 }
2622
Alan Kwong6bc64622017-02-04 17:36:03 -08002623 rot = mgr->hw_data;
2624
2625 if (input) {
2626 pixfmts = rot->inpixfmts;
2627 num_pixfmt = rot->num_inpixfmt;
2628 } else {
2629 pixfmts = rot->outpixfmts;
2630 num_pixfmt = rot->num_outpixfmt;
2631 }
2632
2633 if (!pixfmts || !num_pixfmt) {
2634 SDEROT_ERR("invalid pixel format tables\n");
2635 return false;
2636 }
2637
2638 for (i = 0; i < num_pixfmt; i++)
2639 if (pixfmts[i] == pixfmt)
2640 return true;
2641
Alan Kwongda16e442016-08-14 20:47:18 -04002642 return false;
2643}
2644
2645/*
Alan Kwong6bc64622017-02-04 17:36:03 -08002646 * sde_hw_rotator_get_downscale_caps - get scaling capability string
2647 * @mgr: Pointer to rotator manager
2648 * @caps: Pointer to capability string buffer; NULL to return maximum length
2649 * @len: length of capability string buffer
2650 * return: length of capability string
2651 */
2652static int sde_hw_rotator_get_downscale_caps(struct sde_rot_mgr *mgr,
2653 char *caps, int len)
2654{
2655 struct sde_hw_rotator *rot;
2656 int rc = 0;
2657
2658 if (!mgr || !mgr->hw_data) {
2659 SDEROT_ERR("null parameters\n");
2660 return -EINVAL;
2661 }
2662
2663 rot = mgr->hw_data;
2664
2665 if (rot->downscale_caps) {
2666 if (caps)
2667 rc = snprintf(caps, len, "%s", rot->downscale_caps);
2668 else
2669 rc = strlen(rot->downscale_caps);
2670 }
2671
2672 return rc;
2673}
2674
2675/*
Alan Kwong9487de22016-01-16 22:06:36 -05002676 * sde_hw_rotator_parse_dt - parse r3 specific device tree settings
2677 * @hw_data: Pointer to rotator hw
2678 * @dev: Pointer to platform device
2679 */
2680static int sde_hw_rotator_parse_dt(struct sde_hw_rotator *hw_data,
2681 struct platform_device *dev)
2682{
2683 int ret = 0;
2684 u32 data;
2685
2686 if (!hw_data || !dev)
2687 return -EINVAL;
2688
2689 ret = of_property_read_u32(dev->dev.of_node, "qcom,mdss-rot-mode",
2690 &data);
2691 if (ret) {
2692 SDEROT_DBG("default to regdma off\n");
2693 ret = 0;
2694 hw_data->mode = ROT_REGDMA_OFF;
2695 } else if (data < ROT_REGDMA_MAX) {
2696 SDEROT_DBG("set to regdma mode %d\n", data);
2697 hw_data->mode = data;
2698 } else {
2699 SDEROT_ERR("regdma mode out of range. default to regdma off\n");
2700 hw_data->mode = ROT_REGDMA_OFF;
2701 }
2702
2703 ret = of_property_read_u32(dev->dev.of_node,
2704 "qcom,mdss-highest-bank-bit", &data);
2705 if (ret) {
2706 SDEROT_DBG("default to A5X bank\n");
2707 ret = 0;
2708 hw_data->highest_bank = 2;
2709 } else {
2710 SDEROT_DBG("set highest bank bit to %d\n", data);
2711 hw_data->highest_bank = data;
2712 }
2713
Alan Kwong6bc64622017-02-04 17:36:03 -08002714 ret = of_property_read_u32(dev->dev.of_node,
2715 "qcom,mdss-sbuf-headroom", &data);
2716 if (ret) {
2717 ret = 0;
2718 hw_data->sbuf_headroom = DEFAULT_SBUF_HEADROOM;
2719 } else {
2720 SDEROT_DBG("set sbuf headroom to %d\n", data);
2721 hw_data->sbuf_headroom = data;
2722 }
2723
Alan Kwong9487de22016-01-16 22:06:36 -05002724 return ret;
2725}
2726
2727/*
2728 * sde_rotator_r3_init - initialize the r3 module
2729 * @mgr: Pointer to rotator manager
2730 *
2731 * This function setup r3 callback functions, parses r3 specific
2732 * device tree settings, installs r3 specific interrupt handler,
2733 * as well as initializes r3 internal data structure.
2734 */
2735int sde_rotator_r3_init(struct sde_rot_mgr *mgr)
2736{
2737 struct sde_hw_rotator *rot;
2738 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
2739 int i;
2740 int ret;
2741
2742 rot = devm_kzalloc(&mgr->pdev->dev, sizeof(*rot), GFP_KERNEL);
2743 if (!rot)
2744 return -ENOMEM;
2745
2746 mgr->hw_data = rot;
2747 mgr->queue_count = ROT_QUEUE_MAX;
2748
2749 rot->mdss_base = mdata->sde_io.base;
2750 rot->pdev = mgr->pdev;
Alan Kwong6bc64622017-02-04 17:36:03 -08002751 rot->koff_timeout = KOFF_TIMEOUT;
2752 rot->vid_trigger = ROTTOP_START_CTRL_TRIG_SEL_MDP;
2753 rot->cmd_trigger = ROTTOP_START_CTRL_TRIG_SEL_MDP;
Alan Kwong9487de22016-01-16 22:06:36 -05002754
2755 /* Assign ops */
2756 mgr->ops_hw_destroy = sde_hw_rotator_destroy;
2757 mgr->ops_hw_alloc = sde_hw_rotator_alloc_ext;
2758 mgr->ops_hw_free = sde_hw_rotator_free_ext;
2759 mgr->ops_config_hw = sde_hw_rotator_config;
2760 mgr->ops_kickoff_entry = sde_hw_rotator_kickoff;
2761 mgr->ops_wait_for_entry = sde_hw_rotator_wait4done;
2762 mgr->ops_hw_validate_entry = sde_hw_rotator_validate_entry;
2763 mgr->ops_hw_show_caps = sde_hw_rotator_show_caps;
2764 mgr->ops_hw_show_state = sde_hw_rotator_show_state;
2765 mgr->ops_hw_create_debugfs = sde_rotator_r3_create_debugfs;
Alan Kwongda16e442016-08-14 20:47:18 -04002766 mgr->ops_hw_get_pixfmt = sde_hw_rotator_get_pixfmt;
2767 mgr->ops_hw_is_valid_pixfmt = sde_hw_rotator_is_valid_pixfmt;
Benjamin Chan0f9e61d2016-09-16 16:01:09 -04002768 mgr->ops_hw_pre_pmevent = sde_hw_rotator_pre_pmevent;
2769 mgr->ops_hw_post_pmevent = sde_hw_rotator_post_pmevent;
Alan Kwong6bc64622017-02-04 17:36:03 -08002770 mgr->ops_hw_get_downscale_caps = sde_hw_rotator_get_downscale_caps;
Alan Kwong9487de22016-01-16 22:06:36 -05002771
2772 ret = sde_hw_rotator_parse_dt(mgr->hw_data, mgr->pdev);
2773 if (ret)
2774 goto error_parse_dt;
2775
2776 rot->irq_num = platform_get_irq(mgr->pdev, 0);
2777 if (rot->irq_num < 0) {
2778 SDEROT_ERR("fail to get rotator irq\n");
2779 } else {
2780 if (rot->mode == ROT_REGDMA_OFF)
2781 ret = devm_request_threaded_irq(&mgr->pdev->dev,
2782 rot->irq_num,
2783 sde_hw_rotator_rotirq_handler,
2784 NULL, 0, "sde_rotator_r3", rot);
2785 else
2786 ret = devm_request_threaded_irq(&mgr->pdev->dev,
2787 rot->irq_num,
2788 sde_hw_rotator_regdmairq_handler,
2789 NULL, 0, "sde_rotator_r3", rot);
2790 if (ret) {
2791 SDEROT_ERR("fail to request irq r:%d\n", ret);
2792 rot->irq_num = -1;
2793 } else {
2794 disable_irq(rot->irq_num);
2795 }
2796 }
Alan Kwong818b7fc2016-07-24 22:07:41 -04002797 atomic_set(&rot->irq_enabled, 0);
Alan Kwong9487de22016-01-16 22:06:36 -05002798
2799 setup_rotator_ops(&rot->ops, rot->mode);
2800
2801 spin_lock_init(&rot->rotctx_lock);
2802 spin_lock_init(&rot->rotisr_lock);
2803
2804 /* REGDMA initialization */
2805 if (rot->mode == ROT_REGDMA_OFF) {
2806 for (i = 0; i < SDE_HW_ROT_REGDMA_TOTAL_CTX; i++)
2807 rot->cmd_wr_ptr[0][i] = &rot->cmd_queue[
2808 SDE_HW_ROT_REGDMA_SEG_SIZE * i];
2809 } else {
2810 for (i = 0; i < SDE_HW_ROT_REGDMA_TOTAL_CTX; i++)
2811 rot->cmd_wr_ptr[ROT_QUEUE_HIGH_PRIORITY][i] =
2812 (u32 *)(rot->mdss_base +
2813 REGDMA_RAM_REGDMA_CMD_RAM +
2814 SDE_HW_ROT_REGDMA_SEG_SIZE * 4 * i);
2815
2816 for (i = 0; i < SDE_HW_ROT_REGDMA_TOTAL_CTX; i++)
2817 rot->cmd_wr_ptr[ROT_QUEUE_LOW_PRIORITY][i] =
2818 (u32 *)(rot->mdss_base +
2819 REGDMA_RAM_REGDMA_CMD_RAM +
2820 SDE_HW_ROT_REGDMA_SEG_SIZE * 4 *
2821 (i + SDE_HW_ROT_REGDMA_TOTAL_CTX));
2822 }
2823
Alan Kwong6bc64622017-02-04 17:36:03 -08002824 for (i = 0; i < ROT_QUEUE_MAX; i++) {
2825 atomic_set(&rot->timestamp[i], 0);
2826 INIT_LIST_HEAD(&rot->sbuf_ctx[i]);
2827 }
Alan Kwong9487de22016-01-16 22:06:36 -05002828
2829 ret = sde_rotator_hw_rev_init(rot);
2830 if (ret)
2831 goto error_hw_rev_init;
2832
Alan Kwong315cd772016-08-03 22:29:42 -04002833 /* set rotator CBCR to shutoff memory/periphery on clock off.*/
Benjamin Chan77aed192016-10-17 17:49:41 -04002834 clk_set_flags(mgr->rot_clk[SDE_ROTATOR_CLK_ROT_CORE].clk,
Alan Kwong315cd772016-08-03 22:29:42 -04002835 CLKFLAG_NORETAIN_MEM);
Benjamin Chan77aed192016-10-17 17:49:41 -04002836 clk_set_flags(mgr->rot_clk[SDE_ROTATOR_CLK_ROT_CORE].clk,
Alan Kwong315cd772016-08-03 22:29:42 -04002837 CLKFLAG_NORETAIN_PERIPH);
2838
Benjamin Chan53e3bce2016-08-31 14:43:29 -04002839 mdata->sde_rot_hw = rot;
Alan Kwong9487de22016-01-16 22:06:36 -05002840 return 0;
2841error_hw_rev_init:
2842 if (rot->irq_num >= 0)
2843 devm_free_irq(&mgr->pdev->dev, rot->irq_num, mdata);
2844 devm_kfree(&mgr->pdev->dev, mgr->hw_data);
2845error_parse_dt:
2846 return ret;
2847}