blob: 1d399947dde84e0209f9c65dd9b1dbe737579ba7 [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
Alan Kwong498d59f2017-02-11 18:56:34 -080044#define TRAFFIC_SHAPE_VSYNC_CLK 19200000
Benjamin Chan99eb63b2016-12-21 15:45:26 -050045
Alan Kwong9487de22016-01-16 22:06:36 -050046/* XIN mapping */
47#define XIN_SSPP 0
48#define XIN_WRITEBACK 1
49
50/* wait for at most 2 vsync for lowest refresh rate (24hz) */
Alan Kwong6bc64622017-02-04 17:36:03 -080051#define KOFF_TIMEOUT (42 * 32)
52
53/* default stream buffer headroom in lines */
54#define DEFAULT_SBUF_HEADROOM 20
Alan Kwong9487de22016-01-16 22:06:36 -050055
56/* Macro for constructing the REGDMA command */
57#define SDE_REGDMA_WRITE(p, off, data) \
58 do { \
Alan Kwong6bc64622017-02-04 17:36:03 -080059 SDEROT_DBG("SDEREG.W:[%s:0x%X] <= 0x%X\n", #off, (off),\
60 (u32)(data));\
Alan Kwong9487de22016-01-16 22:06:36 -050061 *p++ = REGDMA_OP_REGWRITE | \
62 ((off) & REGDMA_ADDR_OFFSET_MASK); \
63 *p++ = (data); \
64 } while (0)
65
66#define SDE_REGDMA_MODIFY(p, off, mask, data) \
67 do { \
Alan Kwong6bc64622017-02-04 17:36:03 -080068 SDEROT_DBG("SDEREG.M:[%s:0x%X] <= 0x%X\n", #off, (off),\
69 (u32)(data));\
Alan Kwong9487de22016-01-16 22:06:36 -050070 *p++ = REGDMA_OP_REGMODIFY | \
71 ((off) & REGDMA_ADDR_OFFSET_MASK); \
72 *p++ = (mask); \
73 *p++ = (data); \
74 } while (0)
75
76#define SDE_REGDMA_BLKWRITE_INC(p, off, len) \
77 do { \
Alan Kwong6bc64622017-02-04 17:36:03 -080078 SDEROT_DBG("SDEREG.B:[%s:0x%X:0x%X]\n", #off, (off),\
79 (u32)(len));\
Alan Kwong9487de22016-01-16 22:06:36 -050080 *p++ = REGDMA_OP_BLKWRITE_INC | \
81 ((off) & REGDMA_ADDR_OFFSET_MASK); \
82 *p++ = (len); \
83 } while (0)
84
85#define SDE_REGDMA_BLKWRITE_DATA(p, data) \
86 do { \
Alan Kwong6bc64622017-02-04 17:36:03 -080087 SDEROT_DBG("SDEREG.I:[:] <= 0x%X\n", (u32)(data));\
Alan Kwong9487de22016-01-16 22:06:36 -050088 *(p) = (data); \
89 (p)++; \
90 } while (0)
91
92/* Macro for directly accessing mapped registers */
93#define SDE_ROTREG_WRITE(base, off, data) \
Alan Kwong6bc64622017-02-04 17:36:03 -080094 do { \
95 SDEROT_DBG("SDEREG.D:[%s:0x%X] <= 0x%X\n", #off, (off)\
96 , (u32)(data));\
97 writel_relaxed(data, (base + (off))); \
98 } while (0)
Alan Kwong9487de22016-01-16 22:06:36 -050099
100#define SDE_ROTREG_READ(base, off) \
101 readl_relaxed(base + (off))
102
Alan Kwong6bc64622017-02-04 17:36:03 -0800103static u32 sde_hw_rotator_v3_inpixfmts[] = {
Alan Kwongda16e442016-08-14 20:47:18 -0400104 SDE_PIX_FMT_XRGB_8888,
105 SDE_PIX_FMT_ARGB_8888,
106 SDE_PIX_FMT_ABGR_8888,
107 SDE_PIX_FMT_RGBA_8888,
108 SDE_PIX_FMT_BGRA_8888,
109 SDE_PIX_FMT_RGBX_8888,
110 SDE_PIX_FMT_BGRX_8888,
111 SDE_PIX_FMT_XBGR_8888,
112 SDE_PIX_FMT_RGBA_5551,
113 SDE_PIX_FMT_ARGB_1555,
114 SDE_PIX_FMT_ABGR_1555,
115 SDE_PIX_FMT_BGRA_5551,
116 SDE_PIX_FMT_BGRX_5551,
117 SDE_PIX_FMT_RGBX_5551,
118 SDE_PIX_FMT_XBGR_1555,
119 SDE_PIX_FMT_XRGB_1555,
120 SDE_PIX_FMT_ARGB_4444,
121 SDE_PIX_FMT_RGBA_4444,
122 SDE_PIX_FMT_BGRA_4444,
123 SDE_PIX_FMT_ABGR_4444,
124 SDE_PIX_FMT_RGBX_4444,
125 SDE_PIX_FMT_XRGB_4444,
126 SDE_PIX_FMT_BGRX_4444,
127 SDE_PIX_FMT_XBGR_4444,
128 SDE_PIX_FMT_RGB_888,
129 SDE_PIX_FMT_BGR_888,
130 SDE_PIX_FMT_RGB_565,
131 SDE_PIX_FMT_BGR_565,
132 SDE_PIX_FMT_Y_CB_CR_H2V2,
133 SDE_PIX_FMT_Y_CR_CB_H2V2,
134 SDE_PIX_FMT_Y_CR_CB_GH2V2,
135 SDE_PIX_FMT_Y_CBCR_H2V2,
136 SDE_PIX_FMT_Y_CRCB_H2V2,
137 SDE_PIX_FMT_Y_CBCR_H1V2,
138 SDE_PIX_FMT_Y_CRCB_H1V2,
139 SDE_PIX_FMT_Y_CBCR_H2V1,
140 SDE_PIX_FMT_Y_CRCB_H2V1,
141 SDE_PIX_FMT_YCBYCR_H2V1,
142 SDE_PIX_FMT_Y_CBCR_H2V2_VENUS,
143 SDE_PIX_FMT_Y_CRCB_H2V2_VENUS,
144 SDE_PIX_FMT_RGBA_8888_UBWC,
145 SDE_PIX_FMT_RGBX_8888_UBWC,
146 SDE_PIX_FMT_RGB_565_UBWC,
147 SDE_PIX_FMT_Y_CBCR_H2V2_UBWC,
148 SDE_PIX_FMT_RGBA_1010102,
149 SDE_PIX_FMT_RGBX_1010102,
150 SDE_PIX_FMT_ARGB_2101010,
151 SDE_PIX_FMT_XRGB_2101010,
152 SDE_PIX_FMT_BGRA_1010102,
153 SDE_PIX_FMT_BGRX_1010102,
154 SDE_PIX_FMT_ABGR_2101010,
155 SDE_PIX_FMT_XBGR_2101010,
156 SDE_PIX_FMT_RGBA_1010102_UBWC,
157 SDE_PIX_FMT_RGBX_1010102_UBWC,
158 SDE_PIX_FMT_Y_CBCR_H2V2_P010,
159 SDE_PIX_FMT_Y_CBCR_H2V2_TP10,
160 SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC,
161};
162
Alan Kwong6bc64622017-02-04 17:36:03 -0800163static u32 sde_hw_rotator_v3_outpixfmts[] = {
Alan Kwongda16e442016-08-14 20:47:18 -0400164 SDE_PIX_FMT_XRGB_8888,
165 SDE_PIX_FMT_ARGB_8888,
166 SDE_PIX_FMT_ABGR_8888,
167 SDE_PIX_FMT_RGBA_8888,
168 SDE_PIX_FMT_BGRA_8888,
169 SDE_PIX_FMT_RGBX_8888,
170 SDE_PIX_FMT_BGRX_8888,
171 SDE_PIX_FMT_XBGR_8888,
172 SDE_PIX_FMT_RGBA_5551,
173 SDE_PIX_FMT_ARGB_1555,
174 SDE_PIX_FMT_ABGR_1555,
175 SDE_PIX_FMT_BGRA_5551,
176 SDE_PIX_FMT_BGRX_5551,
177 SDE_PIX_FMT_RGBX_5551,
178 SDE_PIX_FMT_XBGR_1555,
179 SDE_PIX_FMT_XRGB_1555,
180 SDE_PIX_FMT_ARGB_4444,
181 SDE_PIX_FMT_RGBA_4444,
182 SDE_PIX_FMT_BGRA_4444,
183 SDE_PIX_FMT_ABGR_4444,
184 SDE_PIX_FMT_RGBX_4444,
185 SDE_PIX_FMT_XRGB_4444,
186 SDE_PIX_FMT_BGRX_4444,
187 SDE_PIX_FMT_XBGR_4444,
188 SDE_PIX_FMT_RGB_888,
189 SDE_PIX_FMT_BGR_888,
190 SDE_PIX_FMT_RGB_565,
191 SDE_PIX_FMT_BGR_565,
192 /* SDE_PIX_FMT_Y_CB_CR_H2V2 */
193 /* SDE_PIX_FMT_Y_CR_CB_H2V2 */
194 /* SDE_PIX_FMT_Y_CR_CB_GH2V2 */
195 SDE_PIX_FMT_Y_CBCR_H2V2,
196 SDE_PIX_FMT_Y_CRCB_H2V2,
197 SDE_PIX_FMT_Y_CBCR_H1V2,
198 SDE_PIX_FMT_Y_CRCB_H1V2,
199 SDE_PIX_FMT_Y_CBCR_H2V1,
200 SDE_PIX_FMT_Y_CRCB_H2V1,
201 /* SDE_PIX_FMT_YCBYCR_H2V1 */
202 SDE_PIX_FMT_Y_CBCR_H2V2_VENUS,
203 SDE_PIX_FMT_Y_CRCB_H2V2_VENUS,
204 SDE_PIX_FMT_RGBA_8888_UBWC,
205 SDE_PIX_FMT_RGBX_8888_UBWC,
206 SDE_PIX_FMT_RGB_565_UBWC,
207 SDE_PIX_FMT_Y_CBCR_H2V2_UBWC,
208 SDE_PIX_FMT_RGBA_1010102,
209 SDE_PIX_FMT_RGBX_1010102,
210 /* SDE_PIX_FMT_ARGB_2101010 */
211 /* SDE_PIX_FMT_XRGB_2101010 */
212 SDE_PIX_FMT_BGRA_1010102,
213 SDE_PIX_FMT_BGRX_1010102,
214 /* SDE_PIX_FMT_ABGR_2101010 */
215 /* SDE_PIX_FMT_XBGR_2101010 */
216 SDE_PIX_FMT_RGBA_1010102_UBWC,
217 SDE_PIX_FMT_RGBX_1010102_UBWC,
218 SDE_PIX_FMT_Y_CBCR_H2V2_P010,
219 SDE_PIX_FMT_Y_CBCR_H2V2_TP10,
220 SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC,
221};
222
Alan Kwong6bc64622017-02-04 17:36:03 -0800223static u32 sde_hw_rotator_v4_inpixfmts[] = {
224 SDE_PIX_FMT_XRGB_8888,
225 SDE_PIX_FMT_ARGB_8888,
226 SDE_PIX_FMT_ABGR_8888,
227 SDE_PIX_FMT_RGBA_8888,
228 SDE_PIX_FMT_BGRA_8888,
229 SDE_PIX_FMT_RGBX_8888,
230 SDE_PIX_FMT_BGRX_8888,
231 SDE_PIX_FMT_XBGR_8888,
232 SDE_PIX_FMT_RGBA_5551,
233 SDE_PIX_FMT_ARGB_1555,
234 SDE_PIX_FMT_ABGR_1555,
235 SDE_PIX_FMT_BGRA_5551,
236 SDE_PIX_FMT_BGRX_5551,
237 SDE_PIX_FMT_RGBX_5551,
238 SDE_PIX_FMT_XBGR_1555,
239 SDE_PIX_FMT_XRGB_1555,
240 SDE_PIX_FMT_ARGB_4444,
241 SDE_PIX_FMT_RGBA_4444,
242 SDE_PIX_FMT_BGRA_4444,
243 SDE_PIX_FMT_ABGR_4444,
244 SDE_PIX_FMT_RGBX_4444,
245 SDE_PIX_FMT_XRGB_4444,
246 SDE_PIX_FMT_BGRX_4444,
247 SDE_PIX_FMT_XBGR_4444,
248 SDE_PIX_FMT_RGB_888,
249 SDE_PIX_FMT_BGR_888,
250 SDE_PIX_FMT_RGB_565,
251 SDE_PIX_FMT_BGR_565,
252 SDE_PIX_FMT_Y_CB_CR_H2V2,
253 SDE_PIX_FMT_Y_CR_CB_H2V2,
254 SDE_PIX_FMT_Y_CR_CB_GH2V2,
255 SDE_PIX_FMT_Y_CBCR_H2V2,
256 SDE_PIX_FMT_Y_CRCB_H2V2,
257 SDE_PIX_FMT_Y_CBCR_H1V2,
258 SDE_PIX_FMT_Y_CRCB_H1V2,
259 SDE_PIX_FMT_Y_CBCR_H2V1,
260 SDE_PIX_FMT_Y_CRCB_H2V1,
261 SDE_PIX_FMT_YCBYCR_H2V1,
262 SDE_PIX_FMT_Y_CBCR_H2V2_VENUS,
263 SDE_PIX_FMT_Y_CRCB_H2V2_VENUS,
264 SDE_PIX_FMT_RGBA_8888_UBWC,
265 SDE_PIX_FMT_RGBX_8888_UBWC,
266 SDE_PIX_FMT_RGB_565_UBWC,
267 SDE_PIX_FMT_Y_CBCR_H2V2_UBWC,
268 SDE_PIX_FMT_RGBA_1010102,
269 SDE_PIX_FMT_RGBX_1010102,
270 SDE_PIX_FMT_ARGB_2101010,
271 SDE_PIX_FMT_XRGB_2101010,
272 SDE_PIX_FMT_BGRA_1010102,
273 SDE_PIX_FMT_BGRX_1010102,
274 SDE_PIX_FMT_ABGR_2101010,
275 SDE_PIX_FMT_XBGR_2101010,
276 SDE_PIX_FMT_RGBA_1010102_UBWC,
277 SDE_PIX_FMT_RGBX_1010102_UBWC,
278 SDE_PIX_FMT_Y_CBCR_H2V2_P010,
279 SDE_PIX_FMT_Y_CBCR_H2V2_TP10,
280 SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC,
281 SDE_PIX_FMT_Y_CBCR_H2V2_TILE,
282 SDE_PIX_FMT_Y_CRCB_H2V2_TILE,
283 SDE_PIX_FMT_XRGB_8888_TILE,
284 SDE_PIX_FMT_ARGB_8888_TILE,
285 SDE_PIX_FMT_ABGR_8888_TILE,
286 SDE_PIX_FMT_XBGR_8888_TILE,
287 SDE_PIX_FMT_RGBA_8888_TILE,
288 SDE_PIX_FMT_BGRA_8888_TILE,
289 SDE_PIX_FMT_RGBX_8888_TILE,
290 SDE_PIX_FMT_BGRX_8888_TILE,
291 SDE_PIX_FMT_RGBA_1010102_TILE,
292 SDE_PIX_FMT_RGBX_1010102_TILE,
293 SDE_PIX_FMT_ARGB_2101010_TILE,
294 SDE_PIX_FMT_XRGB_2101010_TILE,
295 SDE_PIX_FMT_BGRA_1010102_TILE,
296 SDE_PIX_FMT_BGRX_1010102_TILE,
297 SDE_PIX_FMT_ABGR_2101010_TILE,
298 SDE_PIX_FMT_XBGR_2101010_TILE,
299};
300
301static u32 sde_hw_rotator_v4_outpixfmts[] = {
302 SDE_PIX_FMT_XRGB_8888,
303 SDE_PIX_FMT_ARGB_8888,
304 SDE_PIX_FMT_ABGR_8888,
305 SDE_PIX_FMT_RGBA_8888,
306 SDE_PIX_FMT_BGRA_8888,
307 SDE_PIX_FMT_RGBX_8888,
308 SDE_PIX_FMT_BGRX_8888,
309 SDE_PIX_FMT_XBGR_8888,
310 SDE_PIX_FMT_RGBA_5551,
311 SDE_PIX_FMT_ARGB_1555,
312 SDE_PIX_FMT_ABGR_1555,
313 SDE_PIX_FMT_BGRA_5551,
314 SDE_PIX_FMT_BGRX_5551,
315 SDE_PIX_FMT_RGBX_5551,
316 SDE_PIX_FMT_XBGR_1555,
317 SDE_PIX_FMT_XRGB_1555,
318 SDE_PIX_FMT_ARGB_4444,
319 SDE_PIX_FMT_RGBA_4444,
320 SDE_PIX_FMT_BGRA_4444,
321 SDE_PIX_FMT_ABGR_4444,
322 SDE_PIX_FMT_RGBX_4444,
323 SDE_PIX_FMT_XRGB_4444,
324 SDE_PIX_FMT_BGRX_4444,
325 SDE_PIX_FMT_XBGR_4444,
326 SDE_PIX_FMT_RGB_888,
327 SDE_PIX_FMT_BGR_888,
328 SDE_PIX_FMT_RGB_565,
329 SDE_PIX_FMT_BGR_565,
330 /* SDE_PIX_FMT_Y_CB_CR_H2V2 */
331 /* SDE_PIX_FMT_Y_CR_CB_H2V2 */
332 /* SDE_PIX_FMT_Y_CR_CB_GH2V2 */
333 SDE_PIX_FMT_Y_CBCR_H2V2,
334 SDE_PIX_FMT_Y_CRCB_H2V2,
335 SDE_PIX_FMT_Y_CBCR_H1V2,
336 SDE_PIX_FMT_Y_CRCB_H1V2,
337 SDE_PIX_FMT_Y_CBCR_H2V1,
338 SDE_PIX_FMT_Y_CRCB_H2V1,
339 /* SDE_PIX_FMT_YCBYCR_H2V1 */
340 SDE_PIX_FMT_Y_CBCR_H2V2_VENUS,
341 SDE_PIX_FMT_Y_CRCB_H2V2_VENUS,
342 SDE_PIX_FMT_RGBA_8888_UBWC,
343 SDE_PIX_FMT_RGBX_8888_UBWC,
344 SDE_PIX_FMT_RGB_565_UBWC,
345 SDE_PIX_FMT_Y_CBCR_H2V2_UBWC,
346 SDE_PIX_FMT_RGBA_1010102,
347 SDE_PIX_FMT_RGBX_1010102,
348 /* SDE_PIX_FMT_ARGB_2101010 */
349 /* SDE_PIX_FMT_XRGB_2101010 */
350 SDE_PIX_FMT_BGRA_1010102,
351 SDE_PIX_FMT_BGRX_1010102,
352 /* SDE_PIX_FMT_ABGR_2101010 */
353 /* SDE_PIX_FMT_XBGR_2101010 */
354 SDE_PIX_FMT_RGBA_1010102_UBWC,
355 SDE_PIX_FMT_RGBX_1010102_UBWC,
356 SDE_PIX_FMT_Y_CBCR_H2V2_P010,
357 SDE_PIX_FMT_Y_CBCR_H2V2_TP10,
358 SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC,
359 SDE_PIX_FMT_Y_CBCR_H2V2_TILE,
360 SDE_PIX_FMT_Y_CRCB_H2V2_TILE,
361 SDE_PIX_FMT_XRGB_8888_TILE,
362 SDE_PIX_FMT_ARGB_8888_TILE,
363 SDE_PIX_FMT_ABGR_8888_TILE,
364 SDE_PIX_FMT_XBGR_8888_TILE,
365 SDE_PIX_FMT_RGBA_8888_TILE,
366 SDE_PIX_FMT_BGRA_8888_TILE,
367 SDE_PIX_FMT_RGBX_8888_TILE,
368 SDE_PIX_FMT_BGRX_8888_TILE,
369 SDE_PIX_FMT_RGBA_1010102_TILE,
370 SDE_PIX_FMT_RGBX_1010102_TILE,
371 SDE_PIX_FMT_ARGB_2101010_TILE,
372 SDE_PIX_FMT_XRGB_2101010_TILE,
373 SDE_PIX_FMT_BGRA_1010102_TILE,
374 SDE_PIX_FMT_BGRX_1010102_TILE,
375 SDE_PIX_FMT_ABGR_2101010_TILE,
376 SDE_PIX_FMT_XBGR_2101010_TILE,
377};
378
Benjamin Chan53e3bce2016-08-31 14:43:29 -0400379static struct sde_rot_vbif_debug_bus nrt_vbif_dbg_bus_r3[] = {
380 {0x214, 0x21c, 16, 1, 0x10}, /* arb clients */
381 {0x214, 0x21c, 0, 12, 0x13}, /* xin blocks - axi side */
382 {0x21c, 0x214, 0, 12, 0xc}, /* xin blocks - clock side */
383};
384
385static struct sde_rot_regdump sde_rot_r3_regdump[] = {
386 { "SDEROT_ROTTOP", SDE_ROT_ROTTOP_OFFSET, 0x100, SDE_ROT_REGDUMP_READ },
387 { "SDEROT_SSPP", SDE_ROT_SSPP_OFFSET, 0x200, SDE_ROT_REGDUMP_READ },
388 { "SDEROT_WB", SDE_ROT_WB_OFFSET, 0x300, SDE_ROT_REGDUMP_READ },
389 { "SDEROT_REGDMA_CSR", SDE_ROT_REGDMA_OFFSET, 0x100,
390 SDE_ROT_REGDUMP_READ },
391 /*
392 * Need to perform a SW reset to REGDMA in order to access the
393 * REGDMA RAM especially if REGDMA is waiting for Rotator IDLE.
394 * REGDMA RAM should be dump at last.
395 */
396 { "SDEROT_REGDMA_RESET", ROTTOP_SW_RESET_OVERRIDE, 1,
397 SDE_ROT_REGDUMP_WRITE },
398 { "SDEROT_REGDMA_RAM", SDE_ROT_REGDMA_RAM_OFFSET, 0x2000,
399 SDE_ROT_REGDUMP_READ },
Benjamin Chan59a06052017-01-12 18:06:03 -0500400 { "SDEROT_VBIF_NRT", SDE_ROT_VBIF_NRT_OFFSET, 0x590,
401 SDE_ROT_REGDUMP_VBIF },
Benjamin Chan53e3bce2016-08-31 14:43:29 -0400402};
403
Alan Kwong818b7fc2016-07-24 22:07:41 -0400404/* Invalid software timestamp value for initialization */
405#define SDE_REGDMA_SWTS_INVALID (~0)
406
407/**
408 * sde_hw_rotator_elapsed_swts - Find difference of 2 software timestamps
409 * @ts_curr: current software timestamp
410 * @ts_prev: previous software timestamp
411 * @return: the amount ts_curr is ahead of ts_prev
412 */
413static int sde_hw_rotator_elapsed_swts(u32 ts_curr, u32 ts_prev)
414{
415 u32 diff = (ts_curr - ts_prev) & SDE_REGDMA_SWTS_MASK;
416
417 return sign_extend32(diff, (SDE_REGDMA_SWTS_SHIFT - 1));
418}
419
420/**
421 * sde_hw_rotator_pending_swts - Check if the given context is still pending
422 * @rot: Pointer to hw rotator
423 * @ctx: Pointer to rotator context
424 * @pswts: Pointer to returned reference software timestamp, optional
425 * @return: true if context has pending requests
426 */
427static int sde_hw_rotator_pending_swts(struct sde_hw_rotator *rot,
428 struct sde_hw_rotator_context *ctx, u32 *pswts)
429{
430 u32 swts;
431 int ts_diff;
432 bool pending;
433
434 if (ctx->last_regdma_timestamp == SDE_REGDMA_SWTS_INVALID)
435 swts = SDE_ROTREG_READ(rot->mdss_base, REGDMA_TIMESTAMP_REG);
436 else
437 swts = ctx->last_regdma_timestamp;
438
439 if (ctx->q_id == ROT_QUEUE_LOW_PRIORITY)
440 swts >>= SDE_REGDMA_SWTS_SHIFT;
441
442 swts &= SDE_REGDMA_SWTS_MASK;
443
444 ts_diff = sde_hw_rotator_elapsed_swts(ctx->timestamp, swts);
445
446 if (pswts)
447 *pswts = swts;
448
449 pending = (ts_diff > 0) ? true : false;
450
451 SDEROT_DBG("ts:0x%x, queue_id:%d, swts:0x%x, pending:%d\n",
452 ctx->timestamp, ctx->q_id, swts, pending);
Benjamin Chan0f9e61d2016-09-16 16:01:09 -0400453 SDEROT_EVTLOG(ctx->timestamp, swts, ctx->q_id, ts_diff);
Alan Kwong818b7fc2016-07-24 22:07:41 -0400454 return pending;
455}
456
457/**
Alan Kwong6bc64622017-02-04 17:36:03 -0800458 * sde_hw_rotator_update_swts - update software timestamp with given value
459 * @rot: Pointer to hw rotator
460 * @ctx: Pointer to rotator contxt
461 * @swts: new software timestamp
462 * @return: new combined swts
463 */
464static u32 sde_hw_rotator_update_swts(struct sde_hw_rotator *rot,
465 struct sde_hw_rotator_context *ctx, u32 swts)
466{
467 u32 mask = SDE_REGDMA_SWTS_MASK;
468
469 swts &= SDE_REGDMA_SWTS_MASK;
470 if (ctx->q_id == ROT_QUEUE_LOW_PRIORITY) {
471 swts <<= SDE_REGDMA_SWTS_SHIFT;
472 mask <<= SDE_REGDMA_SWTS_SHIFT;
473 }
474
475 swts |= (SDE_ROTREG_READ(rot->mdss_base, REGDMA_TIMESTAMP_REG) & ~mask);
476 SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_TIMESTAMP_REG, swts);
477
478 return swts;
479}
480
481/**
Alan Kwong818b7fc2016-07-24 22:07:41 -0400482 * sde_hw_rotator_enable_irq - Enable hw rotator interrupt with ref. count
483 * Also, clear rotator/regdma irq status.
484 * @rot: Pointer to hw rotator
485 */
486static void sde_hw_rotator_enable_irq(struct sde_hw_rotator *rot)
487{
488 SDEROT_DBG("irq_num:%d enabled:%d\n", rot->irq_num,
489 atomic_read(&rot->irq_enabled));
490
491 if (!atomic_read(&rot->irq_enabled)) {
492 if (rot->mode == ROT_REGDMA_OFF)
493 SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_CLEAR,
494 ROT_DONE_MASK);
495 else
496 SDE_ROTREG_WRITE(rot->mdss_base,
497 REGDMA_CSR_REGDMA_INT_CLEAR, REGDMA_INT_MASK);
498
499 enable_irq(rot->irq_num);
500 }
501 atomic_inc(&rot->irq_enabled);
502}
503
504/**
505 * sde_hw_rotator_disable_irq - Disable hw rotator interrupt with ref. count
506 * Also, clear rotator/regdma irq enable masks.
507 * @rot: Pointer to hw rotator
508 */
509static void sde_hw_rotator_disable_irq(struct sde_hw_rotator *rot)
510{
511 SDEROT_DBG("irq_num:%d enabled:%d\n", rot->irq_num,
512 atomic_read(&rot->irq_enabled));
513
514 if (!atomic_read(&rot->irq_enabled)) {
515 SDEROT_ERR("irq %d is already disabled\n", rot->irq_num);
516 return;
517 }
518
519 if (!atomic_dec_return(&rot->irq_enabled)) {
520 if (rot->mode == ROT_REGDMA_OFF)
521 SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_EN, 0);
522 else
523 SDE_ROTREG_WRITE(rot->mdss_base,
524 REGDMA_CSR_REGDMA_INT_EN, 0);
525 /* disable irq after last pending irq is handled, if any */
526 synchronize_irq(rot->irq_num);
527 disable_irq_nosync(rot->irq_num);
528 }
529}
530
531/**
532 * sde_hw_rotator_dump_status - Dump hw rotator status on error
533 * @rot: Pointer to hw rotator
534 */
535static void sde_hw_rotator_dump_status(struct sde_hw_rotator *rot)
536{
Benjamin Chan1b94f952017-01-23 17:42:30 -0500537 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
538
Alan Kwong818b7fc2016-07-24 22:07:41 -0400539 SDEROT_ERR(
540 "op_mode = %x, int_en = %x, int_status = %x\n",
541 SDE_ROTREG_READ(rot->mdss_base,
542 REGDMA_CSR_REGDMA_OP_MODE),
543 SDE_ROTREG_READ(rot->mdss_base,
544 REGDMA_CSR_REGDMA_INT_EN),
545 SDE_ROTREG_READ(rot->mdss_base,
546 REGDMA_CSR_REGDMA_INT_STATUS));
547
548 SDEROT_ERR(
549 "ts = %x, q0_status = %x, q1_status = %x, block_status = %x\n",
550 SDE_ROTREG_READ(rot->mdss_base,
551 REGDMA_TIMESTAMP_REG),
552 SDE_ROTREG_READ(rot->mdss_base,
553 REGDMA_CSR_REGDMA_QUEUE_0_STATUS),
554 SDE_ROTREG_READ(rot->mdss_base,
555 REGDMA_CSR_REGDMA_QUEUE_1_STATUS),
556 SDE_ROTREG_READ(rot->mdss_base,
557 REGDMA_CSR_REGDMA_BLOCK_STATUS));
558
559 SDEROT_ERR(
560 "invalid_cmd_offset = %x, fsm_state = %x\n",
561 SDE_ROTREG_READ(rot->mdss_base,
562 REGDMA_CSR_REGDMA_INVALID_CMD_RAM_OFFSET),
563 SDE_ROTREG_READ(rot->mdss_base,
564 REGDMA_CSR_REGDMA_FSM_STATE));
Benjamin Chan59a06052017-01-12 18:06:03 -0500565
566 SDEROT_ERR(
567 "UBWC decode status = %x, UBWC encode status = %x\n",
568 SDE_ROTREG_READ(rot->mdss_base, ROT_SSPP_UBWC_ERROR_STATUS),
569 SDE_ROTREG_READ(rot->mdss_base, ROT_WB_UBWC_ERROR_STATUS));
Benjamin Chan1b94f952017-01-23 17:42:30 -0500570
571 SDEROT_ERR("VBIF XIN HALT status = %x VBIF AXI HALT status = %x\n",
572 SDE_VBIF_READ(mdata, MMSS_VBIF_XIN_HALT_CTRL1),
573 SDE_VBIF_READ(mdata, MMSS_VBIF_AXI_HALT_CTRL1));
Alan Kwong6bc64622017-02-04 17:36:03 -0800574
575 SDEROT_ERR(
576 "sbuf_status_plane0 = %x, sbuf_status_plane1 = %x\n",
577 SDE_ROTREG_READ(rot->mdss_base,
578 ROT_WB_SBUF_STATUS_PLANE0),
579 SDE_ROTREG_READ(rot->mdss_base,
580 ROT_WB_SBUF_STATUS_PLANE1));
Alan Kwong818b7fc2016-07-24 22:07:41 -0400581}
582
Alan Kwong9487de22016-01-16 22:06:36 -0500583/**
584 * sde_hw_rotator_get_ctx(): Retrieve rotator context from rotator HW based
585 * on provided session_id. Each rotator has a different session_id.
586 */
587static struct sde_hw_rotator_context *sde_hw_rotator_get_ctx(
588 struct sde_hw_rotator *rot, u32 session_id,
589 enum sde_rot_queue_prio q_id)
590{
591 int i;
592 struct sde_hw_rotator_context *ctx = NULL;
593
594 for (i = 0; i < SDE_HW_ROT_REGDMA_TOTAL_CTX; i++) {
595 ctx = rot->rotCtx[q_id][i];
596
597 if (ctx && (ctx->session_id == session_id)) {
598 SDEROT_DBG(
599 "rotCtx sloti[%d][%d] ==> ctx:%p | session-id:%d\n",
600 q_id, i, ctx, ctx->session_id);
601 return ctx;
602 }
603 }
604
605 return NULL;
606}
607
608/*
609 * sde_hw_rotator_map_vaddr - map the debug buffer to kernel space
610 * @dbgbuf: Pointer to debug buffer
611 * @buf: Pointer to layer buffer structure
612 * @data: Pointer to h/w mapped buffer structure
613 */
614static void sde_hw_rotator_map_vaddr(struct sde_dbg_buf *dbgbuf,
615 struct sde_layer_buffer *buf, struct sde_mdp_data *data)
616{
617 dbgbuf->dmabuf = data->p[0].srcp_dma_buf;
618 dbgbuf->buflen = data->p[0].srcp_dma_buf->size;
619
620 dbgbuf->vaddr = NULL;
621 dbgbuf->width = buf->width;
622 dbgbuf->height = buf->height;
623
624 if (dbgbuf->dmabuf && (dbgbuf->buflen > 0)) {
Alan Kwong6ce448d2016-11-24 18:45:20 -0800625 dma_buf_begin_cpu_access(dbgbuf->dmabuf, DMA_FROM_DEVICE);
Alan Kwong9487de22016-01-16 22:06:36 -0500626 dbgbuf->vaddr = dma_buf_kmap(dbgbuf->dmabuf, 0);
627 SDEROT_DBG("vaddr mapping: 0x%p/%ld w:%d/h:%d\n",
628 dbgbuf->vaddr, dbgbuf->buflen,
629 dbgbuf->width, dbgbuf->height);
630 }
631}
632
633/*
634 * sde_hw_rotator_unmap_vaddr - unmap the debug buffer from kernel space
635 * @dbgbuf: Pointer to debug buffer
636 */
637static void sde_hw_rotator_unmap_vaddr(struct sde_dbg_buf *dbgbuf)
638{
639 if (dbgbuf->vaddr) {
640 dma_buf_kunmap(dbgbuf->dmabuf, 0, dbgbuf->vaddr);
Alan Kwong6ce448d2016-11-24 18:45:20 -0800641 dma_buf_end_cpu_access(dbgbuf->dmabuf, DMA_FROM_DEVICE);
Alan Kwong9487de22016-01-16 22:06:36 -0500642 }
643
644 dbgbuf->vaddr = NULL;
645 dbgbuf->dmabuf = NULL;
646 dbgbuf->buflen = 0;
647 dbgbuf->width = 0;
648 dbgbuf->height = 0;
649}
650
651/*
652 * sde_hw_rotator_setup_timestamp_packet - setup timestamp writeback command
653 * @ctx: Pointer to rotator context
654 * @mask: Bit mask location of the timestamp
655 * @swts: Software timestamp
656 */
657static void sde_hw_rotator_setup_timestamp_packet(
658 struct sde_hw_rotator_context *ctx, u32 mask, u32 swts)
659{
660 u32 *wrptr;
661
662 wrptr = sde_hw_rotator_get_regdma_segment(ctx);
663
664 /*
665 * Create a dummy packet write out to 1 location for timestamp
666 * generation.
667 */
668 SDE_REGDMA_BLKWRITE_INC(wrptr, ROT_SSPP_SRC_SIZE, 6);
669 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0x00010001);
670 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0);
671 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0);
672 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0x00010001);
673 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0);
674 SDE_REGDMA_BLKWRITE_DATA(wrptr, ctx->ts_addr);
675 SDE_REGDMA_WRITE(wrptr, ROT_SSPP_SRC_YSTRIDE0, 4);
676 SDE_REGDMA_BLKWRITE_INC(wrptr, ROT_SSPP_SRC_FORMAT, 4);
677 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0x004037FF);
678 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0x03020100);
679 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0x80000000);
680 SDE_REGDMA_BLKWRITE_DATA(wrptr, ctx->timestamp);
Benjamin Chan15c93d82016-08-29 10:04:22 -0400681 /*
682 * Must clear secure buffer setting for SW timestamp because
683 * SW timstamp buffer allocation is always non-secure region.
684 */
685 if (ctx->is_secure) {
686 SDE_REGDMA_WRITE(wrptr, ROT_SSPP_SRC_ADDR_SW_STATUS, 0);
687 SDE_REGDMA_WRITE(wrptr, ROT_WB_DST_ADDR_SW_STATUS, 0);
688 }
Alan Kwong9487de22016-01-16 22:06:36 -0500689 SDE_REGDMA_BLKWRITE_INC(wrptr, ROT_WB_DST_FORMAT, 4);
690 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0x000037FF);
691 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0);
692 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0x03020100);
693 SDE_REGDMA_BLKWRITE_DATA(wrptr, ctx->ts_addr);
694 SDE_REGDMA_WRITE(wrptr, ROT_WB_DST_YSTRIDE0, 4);
695 SDE_REGDMA_WRITE(wrptr, ROT_WB_OUT_SIZE, 0x00010001);
696 SDE_REGDMA_WRITE(wrptr, ROT_WB_OUT_IMG_SIZE, 0x00010001);
697 SDE_REGDMA_WRITE(wrptr, ROT_WB_OUT_XY, 0);
698 SDE_REGDMA_WRITE(wrptr, ROTTOP_DNSC, 0);
699 SDE_REGDMA_WRITE(wrptr, ROTTOP_OP_MODE, 1);
700 SDE_REGDMA_MODIFY(wrptr, REGDMA_TIMESTAMP_REG, mask, swts);
701 SDE_REGDMA_WRITE(wrptr, ROTTOP_START_CTRL, 1);
702
703 sde_hw_rotator_put_regdma_segment(ctx, wrptr);
704}
705
706/*
707 * sde_hw_rotator_setup_fetchengine - setup fetch engine
708 * @ctx: Pointer to rotator context
709 * @queue_id: Priority queue identifier
710 * @cfg: Fetch configuration
711 * @danger_lut: real-time QoS LUT for danger setting (not used)
712 * @safe_lut: real-time QoS LUT for safe setting (not used)
Benjamin Chanfb6faa32016-08-16 17:21:01 -0400713 * @dnsc_factor_w: downscale factor for width
714 * @dnsc_factor_h: downscale factor for height
Alan Kwong9487de22016-01-16 22:06:36 -0500715 * @flags: Control flag
716 */
717static void sde_hw_rotator_setup_fetchengine(struct sde_hw_rotator_context *ctx,
718 enum sde_rot_queue_prio queue_id,
719 struct sde_hw_rot_sspp_cfg *cfg, u32 danger_lut, u32 safe_lut,
Benjamin Chanfb6faa32016-08-16 17:21:01 -0400720 u32 dnsc_factor_w, u32 dnsc_factor_h, u32 flags)
Alan Kwong9487de22016-01-16 22:06:36 -0500721{
722 struct sde_hw_rotator *rot = ctx->rot;
723 struct sde_mdp_format_params *fmt;
724 struct sde_mdp_data *data;
Benjamin Chanfb6faa32016-08-16 17:21:01 -0400725 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
Alan Kwong9487de22016-01-16 22:06:36 -0500726 u32 *wrptr;
727 u32 opmode = 0;
728 u32 chroma_samp = 0;
729 u32 src_format = 0;
730 u32 unpack = 0;
731 u32 width = cfg->img_width;
732 u32 height = cfg->img_height;
733 u32 fetch_blocksize = 0;
734 int i;
735
736 if (ctx->rot->mode == ROT_REGDMA_ON) {
737 SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_INT_EN,
738 REGDMA_INT_MASK);
739 SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_OP_MODE,
740 REGDMA_EN);
741 }
742
743 wrptr = sde_hw_rotator_get_regdma_segment(ctx);
744
745 /* source image setup */
746 if ((flags & SDE_ROT_FLAG_DEINTERLACE)
747 && !(flags & SDE_ROT_FLAG_SOURCE_ROTATED_90)) {
748 for (i = 0; i < cfg->src_plane.num_planes; i++)
749 cfg->src_plane.ystride[i] *= 2;
750 width *= 2;
751 height /= 2;
752 }
753
754 /*
755 * REGDMA BLK write from SRC_SIZE to OP_MODE, total 15 registers
756 */
757 SDE_REGDMA_BLKWRITE_INC(wrptr, ROT_SSPP_SRC_SIZE, 15);
758
759 /* SRC_SIZE, SRC_IMG_SIZE, SRC_XY, OUT_SIZE, OUT_XY */
760 SDE_REGDMA_BLKWRITE_DATA(wrptr,
761 cfg->src_rect->w | (cfg->src_rect->h << 16));
762 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0); /* SRC_IMG_SIZE unused */
763 SDE_REGDMA_BLKWRITE_DATA(wrptr,
764 cfg->src_rect->x | (cfg->src_rect->y << 16));
765 SDE_REGDMA_BLKWRITE_DATA(wrptr,
766 cfg->src_rect->w | (cfg->src_rect->h << 16));
767 SDE_REGDMA_BLKWRITE_DATA(wrptr,
768 cfg->src_rect->x | (cfg->src_rect->y << 16));
769
770 /* SRC_ADDR [0-3], SRC_YSTRIDE [0-1] */
771 data = cfg->data;
772 for (i = 0; i < SDE_ROT_MAX_PLANES; i++)
773 SDE_REGDMA_BLKWRITE_DATA(wrptr, data->p[i].addr);
774 SDE_REGDMA_BLKWRITE_DATA(wrptr, cfg->src_plane.ystride[0] |
775 (cfg->src_plane.ystride[1] << 16));
776 SDE_REGDMA_BLKWRITE_DATA(wrptr, cfg->src_plane.ystride[2] |
777 (cfg->src_plane.ystride[3] << 16));
778
779 /* UNUSED, write 0 */
780 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0);
781
782 /* setup source format */
783 fmt = cfg->fmt;
784
785 chroma_samp = fmt->chroma_sample;
786 if (flags & SDE_ROT_FLAG_SOURCE_ROTATED_90) {
787 if (chroma_samp == SDE_MDP_CHROMA_H2V1)
788 chroma_samp = SDE_MDP_CHROMA_H1V2;
789 else if (chroma_samp == SDE_MDP_CHROMA_H1V2)
790 chroma_samp = SDE_MDP_CHROMA_H2V1;
791 }
792
793 src_format = (chroma_samp << 23) |
794 (fmt->fetch_planes << 19) |
795 (fmt->bits[C3_ALPHA] << 6) |
796 (fmt->bits[C2_R_Cr] << 4) |
797 (fmt->bits[C1_B_Cb] << 2) |
798 (fmt->bits[C0_G_Y] << 0);
799
800 if (fmt->alpha_enable &&
801 (fmt->fetch_planes == SDE_MDP_PLANE_INTERLEAVED))
802 src_format |= BIT(8); /* SRCC3_EN */
803
804 src_format |= ((fmt->unpack_count - 1) << 12) |
805 (fmt->unpack_tight << 17) |
806 (fmt->unpack_align_msb << 18) |
807 ((fmt->bpp - 1) << 9) |
808 ((fmt->frame_format & 3) << 30);
809
810 if (flags & SDE_ROT_FLAG_ROT_90)
811 src_format |= BIT(11); /* ROT90 */
812
813 if (sde_mdp_is_ubwc_format(fmt))
814 opmode |= BIT(0); /* BWC_DEC_EN */
815
816 /* if this is YUV pixel format, enable CSC */
817 if (sde_mdp_is_yuv_format(fmt))
818 src_format |= BIT(15); /* SRC_COLOR_SPACE */
819
820 if (fmt->pixel_mode == SDE_MDP_PIXEL_10BIT)
821 src_format |= BIT(14); /* UNPACK_DX_FORMAT */
822
823 /* SRC_FORMAT */
824 SDE_REGDMA_BLKWRITE_DATA(wrptr, src_format);
825
826 /* setup source unpack pattern */
827 unpack = (fmt->element[3] << 24) | (fmt->element[2] << 16) |
828 (fmt->element[1] << 8) | (fmt->element[0] << 0);
829
830 /* SRC_UNPACK_PATTERN */
831 SDE_REGDMA_BLKWRITE_DATA(wrptr, unpack);
832
833 /* setup source op mode */
834 if (flags & SDE_ROT_FLAG_FLIP_LR)
835 opmode |= BIT(13); /* FLIP_MODE L/R horizontal flip */
836 if (flags & SDE_ROT_FLAG_FLIP_UD)
837 opmode |= BIT(14); /* FLIP_MODE U/D vertical flip */
838 opmode |= BIT(31); /* MDSS_MDP_OP_PE_OVERRIDE */
839
840 /* SRC_OP_MODE */
841 SDE_REGDMA_BLKWRITE_DATA(wrptr, opmode);
842
843 /* setup source fetch config, TP10 uses different block size */
Benjamin Chanfb6faa32016-08-16 17:21:01 -0400844 if (test_bit(SDE_CAPS_R3_1P5_DOWNSCALE, mdata->sde_caps_map) &&
845 (dnsc_factor_w == 1) && (dnsc_factor_h == 1)) {
846 if (sde_mdp_is_tp10_format(fmt))
847 fetch_blocksize = SDE_ROT_SSPP_FETCH_BLOCKSIZE_144_EXT;
848 else
849 fetch_blocksize = SDE_ROT_SSPP_FETCH_BLOCKSIZE_192_EXT;
850 } else {
851 if (sde_mdp_is_tp10_format(fmt))
852 fetch_blocksize = SDE_ROT_SSPP_FETCH_BLOCKSIZE_96;
853 else
854 fetch_blocksize = SDE_ROT_SSPP_FETCH_BLOCKSIZE_128;
855 }
856
Alan Kwong9487de22016-01-16 22:06:36 -0500857 SDE_REGDMA_WRITE(wrptr, ROT_SSPP_FETCH_CONFIG,
858 fetch_blocksize |
859 SDE_ROT_SSPP_FETCH_CONFIG_RESET_VALUE |
860 ((rot->highest_bank & 0x3) << 18));
861
862 /* setup source buffer plane security status */
Abhijit Kulkarni298c8232016-09-26 22:32:10 -0700863 if (flags & (SDE_ROT_FLAG_SECURE_OVERLAY_SESSION |
864 SDE_ROT_FLAG_SECURE_CAMERA_SESSION)) {
Alan Kwong9487de22016-01-16 22:06:36 -0500865 SDE_REGDMA_WRITE(wrptr, ROT_SSPP_SRC_ADDR_SW_STATUS, 0xF);
866 ctx->is_secure = true;
Benjamin Chan15c93d82016-08-29 10:04:22 -0400867 } else {
868 SDE_REGDMA_WRITE(wrptr, ROT_SSPP_SRC_ADDR_SW_STATUS, 0);
869 ctx->is_secure = false;
Alan Kwong9487de22016-01-16 22:06:36 -0500870 }
871
Benjamin Chan99eb63b2016-12-21 15:45:26 -0500872 /*
873 * Determine if traffic shaping is required. Only enable traffic
874 * shaping when content is 4k@30fps. The actual traffic shaping
875 * bandwidth calculation is done in output setup.
876 */
877 if (((cfg->src_rect->w * cfg->src_rect->h) >= RES_UHD) &&
878 (cfg->fps <= 30)) {
879 SDEROT_DBG("Enable Traffic Shaper\n");
880 ctx->is_traffic_shaping = true;
881 } else {
882 SDEROT_DBG("Disable Traffic Shaper\n");
883 ctx->is_traffic_shaping = false;
884 }
885
Alan Kwong9487de22016-01-16 22:06:36 -0500886 /* Update command queue write ptr */
887 sde_hw_rotator_put_regdma_segment(ctx, wrptr);
888}
889
890/*
891 * sde_hw_rotator_setup_wbengine - setup writeback engine
892 * @ctx: Pointer to rotator context
893 * @queue_id: Priority queue identifier
894 * @cfg: Writeback configuration
895 * @flags: Control flag
896 */
897static void sde_hw_rotator_setup_wbengine(struct sde_hw_rotator_context *ctx,
898 enum sde_rot_queue_prio queue_id,
899 struct sde_hw_rot_wb_cfg *cfg,
900 u32 flags)
901{
Alan Kwong6bc64622017-02-04 17:36:03 -0800902 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
Alan Kwong9487de22016-01-16 22:06:36 -0500903 struct sde_mdp_format_params *fmt;
904 u32 *wrptr;
905 u32 pack = 0;
906 u32 dst_format = 0;
907 int i;
908
909 wrptr = sde_hw_rotator_get_regdma_segment(ctx);
910
911 fmt = cfg->fmt;
912
913 /* setup WB DST format */
914 dst_format |= (fmt->chroma_sample << 23) |
915 (fmt->fetch_planes << 19) |
916 (fmt->bits[C3_ALPHA] << 6) |
917 (fmt->bits[C2_R_Cr] << 4) |
918 (fmt->bits[C1_B_Cb] << 2) |
919 (fmt->bits[C0_G_Y] << 0);
920
921 /* alpha control */
922 if (fmt->bits[C3_ALPHA] || fmt->alpha_enable) {
923 dst_format |= BIT(8);
924 if (!fmt->alpha_enable) {
925 dst_format |= BIT(14);
926 SDE_REGDMA_WRITE(wrptr, ROT_WB_DST_ALPHA_X_VALUE, 0);
927 }
928 }
929
930 dst_format |= ((fmt->unpack_count - 1) << 12) |
931 (fmt->unpack_tight << 17) |
932 (fmt->unpack_align_msb << 18) |
933 ((fmt->bpp - 1) << 9) |
934 ((fmt->frame_format & 3) << 30);
935
936 if (sde_mdp_is_yuv_format(fmt))
937 dst_format |= BIT(15);
938
939 if (fmt->pixel_mode == SDE_MDP_PIXEL_10BIT)
940 dst_format |= BIT(21); /* PACK_DX_FORMAT */
941
942 /*
943 * REGDMA BLK write, from DST_FORMAT to DST_YSTRIDE 1, total 9 regs
944 */
945 SDE_REGDMA_BLKWRITE_INC(wrptr, ROT_WB_DST_FORMAT, 9);
946
947 /* DST_FORMAT */
948 SDE_REGDMA_BLKWRITE_DATA(wrptr, dst_format);
949
950 /* DST_OP_MODE */
951 if (sde_mdp_is_ubwc_format(fmt))
952 SDE_REGDMA_BLKWRITE_DATA(wrptr, BIT(0));
953 else
954 SDE_REGDMA_BLKWRITE_DATA(wrptr, 0);
955
956 /* DST_PACK_PATTERN */
957 pack = (fmt->element[3] << 24) | (fmt->element[2] << 16) |
958 (fmt->element[1] << 8) | (fmt->element[0] << 0);
959 SDE_REGDMA_BLKWRITE_DATA(wrptr, pack);
960
961 /* DST_ADDR [0-3], DST_YSTRIDE [0-1] */
962 for (i = 0; i < SDE_ROT_MAX_PLANES; i++)
963 SDE_REGDMA_BLKWRITE_DATA(wrptr, cfg->data->p[i].addr);
964 SDE_REGDMA_BLKWRITE_DATA(wrptr, cfg->dst_plane.ystride[0] |
965 (cfg->dst_plane.ystride[1] << 16));
966 SDE_REGDMA_BLKWRITE_DATA(wrptr, cfg->dst_plane.ystride[2] |
967 (cfg->dst_plane.ystride[3] << 16));
968
969 /* setup WB out image size and ROI */
970 SDE_REGDMA_WRITE(wrptr, ROT_WB_OUT_IMG_SIZE,
971 cfg->img_width | (cfg->img_height << 16));
972 SDE_REGDMA_WRITE(wrptr, ROT_WB_OUT_SIZE,
973 cfg->dst_rect->w | (cfg->dst_rect->h << 16));
974 SDE_REGDMA_WRITE(wrptr, ROT_WB_OUT_XY,
975 cfg->dst_rect->x | (cfg->dst_rect->y << 16));
976
Abhijit Kulkarni298c8232016-09-26 22:32:10 -0700977 if (flags & (SDE_ROT_FLAG_SECURE_OVERLAY_SESSION |
978 SDE_ROT_FLAG_SECURE_CAMERA_SESSION))
Benjamin Chan15c93d82016-08-29 10:04:22 -0400979 SDE_REGDMA_WRITE(wrptr, ROT_WB_DST_ADDR_SW_STATUS, 0x1);
980 else
981 SDE_REGDMA_WRITE(wrptr, ROT_WB_DST_ADDR_SW_STATUS, 0);
982
Alan Kwong9487de22016-01-16 22:06:36 -0500983 /*
984 * setup Downscale factor
985 */
986 SDE_REGDMA_WRITE(wrptr, ROTTOP_DNSC,
987 cfg->v_downscale_factor |
988 (cfg->h_downscale_factor << 16));
989
Alan Kwong6bc64622017-02-04 17:36:03 -0800990 /* write config setup for bank configuration */
Alan Kwong9487de22016-01-16 22:06:36 -0500991 SDE_REGDMA_WRITE(wrptr, ROT_WB_DST_WRITE_CONFIG,
992 (ctx->rot->highest_bank & 0x3) << 8);
993
Alan Kwong6bc64622017-02-04 17:36:03 -0800994 if (test_bit(SDE_CAPS_SBUF_1, mdata->sde_caps_map))
995 SDE_REGDMA_WRITE(wrptr, ROT_WB_SYS_CACHE_MODE,
996 ctx->sys_cache_mode);
997
998 SDE_REGDMA_WRITE(wrptr, ROTTOP_OP_MODE, ctx->op_mode |
999 (flags & SDE_ROT_FLAG_ROT_90 ? BIT(1) : 0) | BIT(0));
Alan Kwong9487de22016-01-16 22:06:36 -05001000
Alan Kwong498d59f2017-02-11 18:56:34 -08001001 /* setup traffic shaper for 4k 30fps content or if prefill_bw is set */
1002 if (ctx->is_traffic_shaping || cfg->prefill_bw) {
Benjamin Chan99eb63b2016-12-21 15:45:26 -05001003 u32 bw;
1004
1005 /*
1006 * Target to finish in 12ms, and we need to set number of bytes
1007 * per clock tick for traffic shaping.
1008 * Each clock tick run @ 19.2MHz, so we need we know total of
1009 * clock ticks in 14ms, i.e. 12ms/(1/19.2MHz) ==> 23040
1010 * Finally, calcualte the byte count per clock tick based on
1011 * resolution, bpp and compression ratio.
1012 */
1013 bw = cfg->dst_rect->w * cfg->dst_rect->h;
1014
1015 if (fmt->chroma_sample == SDE_MDP_CHROMA_420)
1016 bw = (bw * 3) / 2;
1017 else
1018 bw *= fmt->bpp;
1019
1020 bw /= TRAFFIC_SHAPE_CLKTICK_12MS;
Alan Kwong498d59f2017-02-11 18:56:34 -08001021
1022 /* use prefill bandwidth instead if specified */
1023 if (cfg->prefill_bw)
1024 bw = DIV_ROUND_UP(cfg->prefill_bw,
1025 TRAFFIC_SHAPE_VSYNC_CLK);
1026
Benjamin Chan99eb63b2016-12-21 15:45:26 -05001027 if (bw > 0xFF)
1028 bw = 0xFF;
1029 SDE_REGDMA_WRITE(wrptr, ROT_WB_TRAFFIC_SHAPER_WR_CLIENT,
Alan Kwong498d59f2017-02-11 18:56:34 -08001030 BIT(31) | (cfg->prefill_bw ? BIT(27) : 0) | bw);
Benjamin Chan99eb63b2016-12-21 15:45:26 -05001031 SDEROT_DBG("Enable ROT_WB Traffic Shaper:%d\n", bw);
1032 } else {
1033 SDE_REGDMA_WRITE(wrptr, ROT_WB_TRAFFIC_SHAPER_WR_CLIENT, 0);
1034 SDEROT_DBG("Disable ROT_WB Traffic Shaper\n");
1035 }
1036
Alan Kwong9487de22016-01-16 22:06:36 -05001037 /* Update command queue write ptr */
1038 sde_hw_rotator_put_regdma_segment(ctx, wrptr);
1039}
1040
1041/*
1042 * sde_hw_rotator_start_no_regdma - start non-regdma operation
1043 * @ctx: Pointer to rotator context
1044 * @queue_id: Priority queue identifier
1045 */
1046static u32 sde_hw_rotator_start_no_regdma(struct sde_hw_rotator_context *ctx,
1047 enum sde_rot_queue_prio queue_id)
1048{
1049 struct sde_hw_rotator *rot = ctx->rot;
1050 u32 *wrptr;
1051 u32 *rdptr;
1052 u8 *addr;
1053 u32 mask;
1054 u32 blksize;
1055
1056 rdptr = sde_hw_rotator_get_regdma_segment_base(ctx);
1057 wrptr = sde_hw_rotator_get_regdma_segment(ctx);
1058
1059 if (rot->irq_num >= 0) {
1060 SDE_REGDMA_WRITE(wrptr, ROTTOP_INTR_EN, 1);
1061 SDE_REGDMA_WRITE(wrptr, ROTTOP_INTR_CLEAR, 1);
1062 reinit_completion(&ctx->rot_comp);
Alan Kwong818b7fc2016-07-24 22:07:41 -04001063 sde_hw_rotator_enable_irq(rot);
Alan Kwong9487de22016-01-16 22:06:36 -05001064 }
1065
Alan Kwong6bc64622017-02-04 17:36:03 -08001066 SDE_REGDMA_WRITE(wrptr, ROTTOP_START_CTRL, ctx->start_ctrl);
Alan Kwong9487de22016-01-16 22:06:36 -05001067
1068 /* Update command queue write ptr */
1069 sde_hw_rotator_put_regdma_segment(ctx, wrptr);
1070
1071 SDEROT_DBG("BEGIN %d\n", ctx->timestamp);
1072 /* Write all command stream to Rotator blocks */
1073 /* Rotator will start right away after command stream finish writing */
1074 while (rdptr < wrptr) {
1075 u32 op = REGDMA_OP_MASK & *rdptr;
1076
1077 switch (op) {
1078 case REGDMA_OP_NOP:
1079 SDEROT_DBG("NOP\n");
1080 rdptr++;
1081 break;
1082 case REGDMA_OP_REGWRITE:
1083 SDEROT_DBG("REGW %6.6x %8.8x\n",
1084 rdptr[0] & REGDMA_ADDR_OFFSET_MASK,
1085 rdptr[1]);
1086 addr = rot->mdss_base +
1087 (*rdptr++ & REGDMA_ADDR_OFFSET_MASK);
1088 writel_relaxed(*rdptr++, addr);
1089 break;
1090 case REGDMA_OP_REGMODIFY:
1091 SDEROT_DBG("REGM %6.6x %8.8x %8.8x\n",
1092 rdptr[0] & REGDMA_ADDR_OFFSET_MASK,
1093 rdptr[1], rdptr[2]);
1094 addr = rot->mdss_base +
1095 (*rdptr++ & REGDMA_ADDR_OFFSET_MASK);
1096 mask = *rdptr++;
1097 writel_relaxed((readl_relaxed(addr) & mask) | *rdptr++,
1098 addr);
1099 break;
1100 case REGDMA_OP_BLKWRITE_SINGLE:
1101 SDEROT_DBG("BLKWS %6.6x %6.6x\n",
1102 rdptr[0] & REGDMA_ADDR_OFFSET_MASK,
1103 rdptr[1]);
1104 addr = rot->mdss_base +
1105 (*rdptr++ & REGDMA_ADDR_OFFSET_MASK);
1106 blksize = *rdptr++;
1107 while (blksize--) {
1108 SDEROT_DBG("DATA %8.8x\n", rdptr[0]);
1109 writel_relaxed(*rdptr++, addr);
1110 }
1111 break;
1112 case REGDMA_OP_BLKWRITE_INC:
1113 SDEROT_DBG("BLKWI %6.6x %6.6x\n",
1114 rdptr[0] & REGDMA_ADDR_OFFSET_MASK,
1115 rdptr[1]);
1116 addr = rot->mdss_base +
1117 (*rdptr++ & REGDMA_ADDR_OFFSET_MASK);
1118 blksize = *rdptr++;
1119 while (blksize--) {
1120 SDEROT_DBG("DATA %8.8x\n", rdptr[0]);
1121 writel_relaxed(*rdptr++, addr);
1122 addr += 4;
1123 }
1124 break;
1125 default:
1126 /* Other not supported OP mode
1127 * Skip data for now for unregonized OP mode
1128 */
1129 SDEROT_DBG("UNDEFINED\n");
1130 rdptr++;
1131 break;
1132 }
1133 }
1134 SDEROT_DBG("END %d\n", ctx->timestamp);
1135
1136 return ctx->timestamp;
1137}
1138
1139/*
1140 * sde_hw_rotator_start_regdma - start regdma operation
1141 * @ctx: Pointer to rotator context
1142 * @queue_id: Priority queue identifier
1143 */
1144static u32 sde_hw_rotator_start_regdma(struct sde_hw_rotator_context *ctx,
1145 enum sde_rot_queue_prio queue_id)
1146{
1147 struct sde_hw_rotator *rot = ctx->rot;
1148 u32 *wrptr;
1149 u32 regdmaSlot;
1150 u32 offset;
1151 long length;
1152 long ts_length;
1153 u32 enableInt;
1154 u32 swts = 0;
1155 u32 mask = 0;
Alan Kwong6bc64622017-02-04 17:36:03 -08001156 u32 trig_sel;
Alan Kwong9487de22016-01-16 22:06:36 -05001157
1158 wrptr = sde_hw_rotator_get_regdma_segment(ctx);
1159
Alan Kwong9487de22016-01-16 22:06:36 -05001160 /*
1161 * Last ROT command must be ROT_START before REGDMA start
1162 */
Alan Kwong6bc64622017-02-04 17:36:03 -08001163 SDE_REGDMA_WRITE(wrptr, ROTTOP_START_CTRL, ctx->start_ctrl);
1164
Alan Kwong9487de22016-01-16 22:06:36 -05001165 sde_hw_rotator_put_regdma_segment(ctx, wrptr);
1166
1167 /*
1168 * Start REGDMA with command offset and size
1169 */
1170 regdmaSlot = sde_hw_rotator_get_regdma_ctxidx(ctx);
1171 length = ((long)wrptr - (long)ctx->regdma_base) / 4;
1172 offset = (u32)(ctx->regdma_base - (u32 *)(rot->mdss_base +
1173 REGDMA_RAM_REGDMA_CMD_RAM));
1174 enableInt = ((ctx->timestamp & 1) + 1) << 30;
Alan Kwong6bc64622017-02-04 17:36:03 -08001175 trig_sel = ctx->sbuf_mode ? REGDMA_CMD_TRIG_SEL_MDP_FLUSH :
1176 REGDMA_CMD_TRIG_SEL_SW_START;
Alan Kwong9487de22016-01-16 22:06:36 -05001177
1178 SDEROT_DBG(
1179 "regdma(%d)[%d] <== INT:0x%X|length:%ld|offset:0x%X, ts:%X\n",
1180 queue_id, regdmaSlot, enableInt, length, offset,
1181 ctx->timestamp);
1182
1183 /* ensure the command packet is issued before the submit command */
1184 wmb();
1185
1186 /* REGDMA submission for current context */
1187 if (queue_id == ROT_QUEUE_HIGH_PRIORITY) {
1188 SDE_ROTREG_WRITE(rot->mdss_base,
1189 REGDMA_CSR_REGDMA_QUEUE_0_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;
1193 mask = ~SDE_REGDMA_SWTS_MASK;
1194 } else {
1195 SDE_ROTREG_WRITE(rot->mdss_base,
1196 REGDMA_CSR_REGDMA_QUEUE_1_SUBMIT,
Alan Kwong6bc64622017-02-04 17:36:03 -08001197 (ctx->sbuf_mode ? enableInt : 0) | trig_sel |
1198 ((length & 0x3ff) << 14) | offset);
Alan Kwong9487de22016-01-16 22:06:36 -05001199 swts = ctx->timestamp << SDE_REGDMA_SWTS_SHIFT;
1200 mask = ~(SDE_REGDMA_SWTS_MASK << SDE_REGDMA_SWTS_SHIFT);
1201 }
1202
Alan Kwong6bc64622017-02-04 17:36:03 -08001203 /* timestamp update can only be used in offline multi-context mode */
1204 if (!ctx->sbuf_mode) {
1205 /* Write timestamp after previous rotator job finished */
1206 sde_hw_rotator_setup_timestamp_packet(ctx, mask, swts);
1207 offset += length;
1208 ts_length = sde_hw_rotator_get_regdma_segment(ctx) - wrptr;
1209 WARN_ON((length + ts_length) > SDE_HW_ROT_REGDMA_SEG_SIZE);
Alan Kwong9487de22016-01-16 22:06:36 -05001210
Alan Kwong6bc64622017-02-04 17:36:03 -08001211 /* ensure command packet is issue before the submit command */
1212 wmb();
Alan Kwong9487de22016-01-16 22:06:36 -05001213
Alan Kwong6bc64622017-02-04 17:36:03 -08001214 if (queue_id == ROT_QUEUE_HIGH_PRIORITY) {
1215 SDE_ROTREG_WRITE(rot->mdss_base,
1216 REGDMA_CSR_REGDMA_QUEUE_0_SUBMIT,
1217 enableInt | (ts_length << 14) | offset);
1218 } else {
1219 SDE_ROTREG_WRITE(rot->mdss_base,
1220 REGDMA_CSR_REGDMA_QUEUE_1_SUBMIT,
1221 enableInt | (ts_length << 14) | offset);
1222 }
Alan Kwong9487de22016-01-16 22:06:36 -05001223 }
1224
Alan Kwong9487de22016-01-16 22:06:36 -05001225 /* Update command queue write ptr */
1226 sde_hw_rotator_put_regdma_segment(ctx, wrptr);
1227
1228 return ctx->timestamp;
1229}
1230
1231/*
1232 * sde_hw_rotator_wait_done_no_regdma - wait for non-regdma completion
1233 * @ctx: Pointer to rotator context
1234 * @queue_id: Priority queue identifier
1235 * @flags: Option flag
1236 */
1237static u32 sde_hw_rotator_wait_done_no_regdma(
1238 struct sde_hw_rotator_context *ctx,
1239 enum sde_rot_queue_prio queue_id, u32 flag)
1240{
1241 struct sde_hw_rotator *rot = ctx->rot;
1242 int rc = 0;
1243 u32 sts = 0;
1244 u32 status;
1245 unsigned long flags;
1246
1247 if (rot->irq_num >= 0) {
1248 SDEROT_DBG("Wait for Rotator completion\n");
1249 rc = wait_for_completion_timeout(&ctx->rot_comp,
Alan Kwong6bc64622017-02-04 17:36:03 -08001250 msecs_to_jiffies(rot->koff_timeout));
Alan Kwong9487de22016-01-16 22:06:36 -05001251
1252 spin_lock_irqsave(&rot->rotisr_lock, flags);
1253 status = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_STATUS);
1254 if (rc == 0) {
1255 /*
1256 * Timeout, there might be error,
1257 * or rotator still busy
1258 */
1259 if (status & ROT_BUSY_BIT)
1260 SDEROT_ERR(
1261 "Timeout waiting for rotator done\n");
1262 else if (status & ROT_ERROR_BIT)
1263 SDEROT_ERR(
1264 "Rotator report error status\n");
1265 else
1266 SDEROT_WARN(
1267 "Timeout waiting, but rotator job is done!!\n");
1268
Alan Kwong818b7fc2016-07-24 22:07:41 -04001269 sde_hw_rotator_disable_irq(rot);
Alan Kwong9487de22016-01-16 22:06:36 -05001270 }
1271 spin_unlock_irqrestore(&rot->rotisr_lock, flags);
1272 } else {
1273 int cnt = 200;
1274
1275 do {
1276 udelay(500);
1277 status = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_STATUS);
1278 cnt--;
1279 } while ((cnt > 0) && (status & ROT_BUSY_BIT)
1280 && ((status & ROT_ERROR_BIT) == 0));
1281
1282 if (status & ROT_ERROR_BIT)
1283 SDEROT_ERR("Rotator error\n");
1284 else if (status & ROT_BUSY_BIT)
1285 SDEROT_ERR("Rotator busy\n");
1286
1287 SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_CLEAR,
1288 ROT_DONE_CLEAR);
1289 }
1290
1291 sts = (status & ROT_ERROR_BIT) ? -ENODEV : 0;
1292
1293 return sts;
1294}
1295
1296/*
1297 * sde_hw_rotator_wait_done_regdma - wait for regdma completion
1298 * @ctx: Pointer to rotator context
1299 * @queue_id: Priority queue identifier
1300 * @flags: Option flag
1301 */
1302static u32 sde_hw_rotator_wait_done_regdma(
1303 struct sde_hw_rotator_context *ctx,
1304 enum sde_rot_queue_prio queue_id, u32 flag)
1305{
1306 struct sde_hw_rotator *rot = ctx->rot;
1307 int rc = 0;
1308 u32 status;
1309 u32 last_isr;
1310 u32 last_ts;
1311 u32 int_id;
Alan Kwong818b7fc2016-07-24 22:07:41 -04001312 u32 swts;
Alan Kwong9487de22016-01-16 22:06:36 -05001313 u32 sts = 0;
Alan Kwong9487de22016-01-16 22:06:36 -05001314 unsigned long flags;
1315
1316 if (rot->irq_num >= 0) {
1317 SDEROT_DBG("Wait for REGDMA completion, ctx:%p, ts:%X\n",
1318 ctx, ctx->timestamp);
Alan Kwong818b7fc2016-07-24 22:07:41 -04001319 rc = wait_event_timeout(ctx->regdma_waitq,
1320 !sde_hw_rotator_pending_swts(rot, ctx, &swts),
Alan Kwong6bc64622017-02-04 17:36:03 -08001321 msecs_to_jiffies(rot->koff_timeout));
Alan Kwong9487de22016-01-16 22:06:36 -05001322
Benjamin Chane7ca72e2016-12-22 18:42:34 -05001323 ATRACE_INT("sde_rot_done", 0);
Alan Kwong9487de22016-01-16 22:06:36 -05001324 spin_lock_irqsave(&rot->rotisr_lock, flags);
1325
1326 last_isr = ctx->last_regdma_isr_status;
1327 last_ts = ctx->last_regdma_timestamp;
1328 status = last_isr & REGDMA_INT_MASK;
1329 int_id = last_ts & 1;
1330 SDEROT_DBG("INT status:0x%X, INT id:%d, timestamp:0x%X\n",
1331 status, int_id, last_ts);
1332
1333 if (rc == 0 || (status & REGDMA_INT_ERR_MASK)) {
Alan Kwong818b7fc2016-07-24 22:07:41 -04001334 bool pending;
1335
1336 pending = sde_hw_rotator_pending_swts(rot, ctx, &swts);
Alan Kwong9487de22016-01-16 22:06:36 -05001337 SDEROT_ERR(
Alan Kwong818b7fc2016-07-24 22:07:41 -04001338 "Timeout wait for regdma interrupt status, ts:0x%X/0x%X pending:%d\n",
1339 ctx->timestamp, swts, pending);
Alan Kwong9487de22016-01-16 22:06:36 -05001340
1341 if (status & REGDMA_WATCHDOG_INT)
1342 SDEROT_ERR("REGDMA watchdog interrupt\n");
1343 else if (status & REGDMA_INVALID_DESCRIPTOR)
1344 SDEROT_ERR("REGDMA invalid descriptor\n");
1345 else if (status & REGDMA_INCOMPLETE_CMD)
1346 SDEROT_ERR("REGDMA incomplete command\n");
1347 else if (status & REGDMA_INVALID_CMD)
1348 SDEROT_ERR("REGDMA invalid command\n");
1349
Alan Kwong818b7fc2016-07-24 22:07:41 -04001350 sde_hw_rotator_dump_status(rot);
Alan Kwong9487de22016-01-16 22:06:36 -05001351 status = ROT_ERROR_BIT;
Alan Kwong818b7fc2016-07-24 22:07:41 -04001352 } else {
1353 if (rc == 1)
1354 SDEROT_WARN(
1355 "REGDMA done but no irq, ts:0x%X/0x%X\n",
1356 ctx->timestamp, swts);
Alan Kwong9487de22016-01-16 22:06:36 -05001357 status = 0;
1358 }
1359
Alan Kwong9487de22016-01-16 22:06:36 -05001360 spin_unlock_irqrestore(&rot->rotisr_lock, flags);
1361 } else {
1362 int cnt = 200;
Alan Kwongb0679602016-11-27 17:04:13 -08001363 bool pending;
Alan Kwong9487de22016-01-16 22:06:36 -05001364
1365 do {
1366 udelay(500);
Alan Kwongb0679602016-11-27 17:04:13 -08001367 last_isr = SDE_ROTREG_READ(rot->mdss_base,
1368 REGDMA_CSR_REGDMA_INT_STATUS);
1369 pending = sde_hw_rotator_pending_swts(rot, ctx, &swts);
Alan Kwong9487de22016-01-16 22:06:36 -05001370 cnt--;
Alan Kwongb0679602016-11-27 17:04:13 -08001371 } while ((cnt > 0) && pending &&
1372 ((last_isr & REGDMA_INT_ERR_MASK) == 0));
Alan Kwong9487de22016-01-16 22:06:36 -05001373
Alan Kwongb0679602016-11-27 17:04:13 -08001374 if (last_isr & REGDMA_INT_ERR_MASK) {
1375 SDEROT_ERR("Rotator error, ts:0x%X/0x%X status:%x\n",
1376 ctx->timestamp, swts, last_isr);
1377 sde_hw_rotator_dump_status(rot);
1378 status = ROT_ERROR_BIT;
1379 } else if (pending) {
1380 SDEROT_ERR("Rotator timeout, ts:0x%X/0x%X status:%x\n",
1381 ctx->timestamp, swts, last_isr);
1382 sde_hw_rotator_dump_status(rot);
1383 status = ROT_ERROR_BIT;
1384 } else {
1385 status = 0;
1386 }
Alan Kwong9487de22016-01-16 22:06:36 -05001387
1388 SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_INT_CLEAR,
Alan Kwongb0679602016-11-27 17:04:13 -08001389 last_isr);
Alan Kwong9487de22016-01-16 22:06:36 -05001390 }
1391
1392 sts = (status & ROT_ERROR_BIT) ? -ENODEV : 0;
1393
Benjamin Chan4ec1f1d2016-09-15 22:49:49 -04001394 if (status & ROT_ERROR_BIT)
1395 SDEROT_EVTLOG_TOUT_HANDLER("rot", "vbif_dbg_bus", "panic");
1396
Alan Kwong9487de22016-01-16 22:06:36 -05001397 return sts;
1398}
1399
1400/*
1401 * setup_rotator_ops - setup callback functions for the low-level HAL
1402 * @ops: Pointer to low-level ops callback
1403 * @mode: Operation mode (non-regdma or regdma)
1404 */
1405static void setup_rotator_ops(struct sde_hw_rotator_ops *ops,
1406 enum sde_rotator_regdma_mode mode)
1407{
1408 ops->setup_rotator_fetchengine = sde_hw_rotator_setup_fetchengine;
1409 ops->setup_rotator_wbengine = sde_hw_rotator_setup_wbengine;
1410 if (mode == ROT_REGDMA_ON) {
1411 ops->start_rotator = sde_hw_rotator_start_regdma;
1412 ops->wait_rotator_done = sde_hw_rotator_wait_done_regdma;
1413 } else {
1414 ops->start_rotator = sde_hw_rotator_start_no_regdma;
1415 ops->wait_rotator_done = sde_hw_rotator_wait_done_no_regdma;
1416 }
1417}
1418
1419/*
1420 * sde_hw_rotator_swts_create - create software timestamp buffer
1421 * @rot: Pointer to rotator hw
1422 *
1423 * This buffer is used by regdma to keep track of last completed command.
1424 */
1425static int sde_hw_rotator_swts_create(struct sde_hw_rotator *rot)
1426{
1427 int rc = 0;
1428 struct ion_handle *handle;
1429 struct sde_mdp_img_data *data;
Abhijit Kulkarni298c8232016-09-26 22:32:10 -07001430 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
Alan Kwong9487de22016-01-16 22:06:36 -05001431 u32 bufsize = sizeof(int) * SDE_HW_ROT_REGDMA_TOTAL_CTX * 2;
1432
Abhijit Kulkarni298c8232016-09-26 22:32:10 -07001433 rot->iclient = mdata->iclient;
Alan Kwong9487de22016-01-16 22:06:36 -05001434
1435 handle = ion_alloc(rot->iclient, bufsize, SZ_4K,
1436 ION_HEAP(ION_SYSTEM_HEAP_ID), 0);
1437 if (IS_ERR_OR_NULL(handle)) {
1438 SDEROT_ERR("ion memory allocation failed\n");
1439 return -ENOMEM;
1440 }
1441
1442 data = &rot->swts_buf;
1443 data->len = bufsize;
1444 data->srcp_dma_buf = ion_share_dma_buf(rot->iclient, handle);
1445 if (IS_ERR(data->srcp_dma_buf)) {
1446 SDEROT_ERR("ion_dma_buf setup failed\n");
1447 rc = -ENOMEM;
1448 goto imap_err;
1449 }
1450
1451 sde_smmu_ctrl(1);
1452
1453 data->srcp_attachment = sde_smmu_dma_buf_attach(data->srcp_dma_buf,
1454 &rot->pdev->dev, SDE_IOMMU_DOMAIN_ROT_UNSECURE);
1455 if (IS_ERR_OR_NULL(data->srcp_attachment)) {
1456 SDEROT_ERR("sde_smmu_dma_buf_attach error\n");
1457 rc = -ENOMEM;
1458 goto err_put;
1459 }
1460
1461 data->srcp_table = dma_buf_map_attachment(data->srcp_attachment,
1462 DMA_BIDIRECTIONAL);
1463 if (IS_ERR_OR_NULL(data->srcp_table)) {
1464 SDEROT_ERR("dma_buf_map_attachment error\n");
1465 rc = -ENOMEM;
1466 goto err_detach;
1467 }
1468
1469 rc = sde_smmu_map_dma_buf(data->srcp_dma_buf, data->srcp_table,
1470 SDE_IOMMU_DOMAIN_ROT_UNSECURE, &data->addr,
1471 &data->len, DMA_BIDIRECTIONAL);
Alan Kwong6ce448d2016-11-24 18:45:20 -08001472 if (rc < 0) {
Alan Kwong9487de22016-01-16 22:06:36 -05001473 SDEROT_ERR("smmu_map_dma_buf failed: (%d)\n", rc);
1474 goto err_unmap;
1475 }
1476
Alan Kwong6ce448d2016-11-24 18:45:20 -08001477 dma_buf_begin_cpu_access(data->srcp_dma_buf, DMA_FROM_DEVICE);
Alan Kwong9487de22016-01-16 22:06:36 -05001478 rot->swts_buffer = dma_buf_kmap(data->srcp_dma_buf, 0);
1479 if (IS_ERR_OR_NULL(rot->swts_buffer)) {
1480 SDEROT_ERR("ion kernel memory mapping failed\n");
1481 rc = IS_ERR(rot->swts_buffer);
1482 goto kmap_err;
1483 }
1484
1485 data->mapped = true;
1486 SDEROT_DBG("swts buffer mapped: %pad/%lx va:%p\n", &data->addr,
1487 data->len, rot->swts_buffer);
1488
1489 ion_free(rot->iclient, handle);
1490
1491 sde_smmu_ctrl(0);
1492
1493 return rc;
1494kmap_err:
1495 sde_smmu_unmap_dma_buf(data->srcp_table, SDE_IOMMU_DOMAIN_ROT_UNSECURE,
1496 DMA_FROM_DEVICE, data->srcp_dma_buf);
1497err_unmap:
1498 dma_buf_unmap_attachment(data->srcp_attachment, data->srcp_table,
1499 DMA_FROM_DEVICE);
1500err_detach:
1501 dma_buf_detach(data->srcp_dma_buf, data->srcp_attachment);
1502err_put:
1503 dma_buf_put(data->srcp_dma_buf);
1504 data->srcp_dma_buf = NULL;
1505imap_err:
1506 ion_free(rot->iclient, handle);
1507
1508 return rc;
1509}
1510
1511/*
1512 * sde_hw_rotator_swtc_destroy - destroy software timestamp buffer
1513 * @rot: Pointer to rotator hw
1514 */
1515static void sde_hw_rotator_swtc_destroy(struct sde_hw_rotator *rot)
1516{
1517 struct sde_mdp_img_data *data;
1518
1519 data = &rot->swts_buf;
1520
Alan Kwong6ce448d2016-11-24 18:45:20 -08001521 dma_buf_end_cpu_access(data->srcp_dma_buf, DMA_FROM_DEVICE);
Alan Kwong9487de22016-01-16 22:06:36 -05001522 dma_buf_kunmap(data->srcp_dma_buf, 0, rot->swts_buffer);
1523
1524 sde_smmu_unmap_dma_buf(data->srcp_table, SDE_IOMMU_DOMAIN_ROT_UNSECURE,
1525 DMA_FROM_DEVICE, data->srcp_dma_buf);
1526 dma_buf_unmap_attachment(data->srcp_attachment, data->srcp_table,
1527 DMA_FROM_DEVICE);
1528 dma_buf_detach(data->srcp_dma_buf, data->srcp_attachment);
1529 dma_buf_put(data->srcp_dma_buf);
1530 data->srcp_dma_buf = NULL;
1531}
1532
1533/*
Benjamin Chan0f9e61d2016-09-16 16:01:09 -04001534 * sde_hw_rotator_pre_pmevent - SDE rotator core will call this before a
1535 * PM event occurs
1536 * @mgr: Pointer to rotator manager
1537 * @pmon: Boolean indicate an on/off power event
1538 */
1539void sde_hw_rotator_pre_pmevent(struct sde_rot_mgr *mgr, bool pmon)
1540{
1541 struct sde_hw_rotator *rot;
1542 u32 l_ts, h_ts, swts, hwts;
1543 u32 rotsts, regdmasts;
1544
1545 /*
1546 * Check last HW timestamp with SW timestamp before power off event.
1547 * If there is a mismatch, that will be quite possible the rotator HW
1548 * is either hang or not finishing last submitted job. In that case,
1549 * it is best to do a timeout eventlog to capture some good events
1550 * log data for analysis.
1551 */
1552 if (!pmon && mgr && mgr->hw_data) {
1553 rot = mgr->hw_data;
1554 h_ts = atomic_read(&rot->timestamp[ROT_QUEUE_HIGH_PRIORITY]);
1555 l_ts = atomic_read(&rot->timestamp[ROT_QUEUE_LOW_PRIORITY]);
1556
1557 /* contruct the combined timstamp */
1558 swts = (h_ts & SDE_REGDMA_SWTS_MASK) |
1559 ((l_ts & SDE_REGDMA_SWTS_MASK) <<
1560 SDE_REGDMA_SWTS_SHIFT);
1561
1562 /* Need to turn on clock to access rotator register */
1563 sde_rotator_clk_ctrl(mgr, true);
1564 hwts = SDE_ROTREG_READ(rot->mdss_base, REGDMA_TIMESTAMP_REG);
1565 regdmasts = SDE_ROTREG_READ(rot->mdss_base,
1566 REGDMA_CSR_REGDMA_BLOCK_STATUS);
1567 rotsts = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_STATUS);
1568
1569 SDEROT_DBG(
1570 "swts:0x%x, hwts:0x%x, regdma-sts:0x%x, rottop-sts:0x%x\n",
1571 swts, hwts, regdmasts, rotsts);
1572 SDEROT_EVTLOG(swts, hwts, regdmasts, rotsts);
1573
1574 if ((swts != hwts) && ((regdmasts & REGDMA_BUSY) ||
1575 (rotsts & ROT_STATUS_MASK))) {
1576 SDEROT_ERR(
1577 "Mismatch SWTS with HWTS: swts:0x%x, hwts:0x%x, regdma-sts:0x%x, rottop-sts:0x%x\n",
1578 swts, hwts, regdmasts, rotsts);
1579 SDEROT_EVTLOG_TOUT_HANDLER("rot", "vbif_dbg_bus",
1580 "panic");
1581 }
1582
1583 /* Turn off rotator clock after checking rotator registers */
1584 sde_rotator_clk_ctrl(mgr, false);
1585 }
1586}
1587
1588/*
1589 * sde_hw_rotator_post_pmevent - SDE rotator core will call this after a
1590 * PM event occurs
1591 * @mgr: Pointer to rotator manager
1592 * @pmon: Boolean indicate an on/off power event
1593 */
1594void sde_hw_rotator_post_pmevent(struct sde_rot_mgr *mgr, bool pmon)
1595{
1596 struct sde_hw_rotator *rot;
1597 u32 l_ts, h_ts, swts;
1598
1599 /*
1600 * After a power on event, the rotator HW is reset to default setting.
1601 * It is necessary to synchronize the SW timestamp with the HW.
1602 */
1603 if (pmon && mgr && mgr->hw_data) {
1604 rot = mgr->hw_data;
1605 h_ts = atomic_read(&rot->timestamp[ROT_QUEUE_HIGH_PRIORITY]);
1606 l_ts = atomic_read(&rot->timestamp[ROT_QUEUE_LOW_PRIORITY]);
1607
1608 /* contruct the combined timstamp */
1609 swts = (h_ts & SDE_REGDMA_SWTS_MASK) |
1610 ((l_ts & SDE_REGDMA_SWTS_MASK) <<
1611 SDE_REGDMA_SWTS_SHIFT);
1612
1613 SDEROT_DBG("swts:0x%x, h_ts:0x%x, l_ts;0x%x\n",
1614 swts, h_ts, l_ts);
1615 SDEROT_EVTLOG(swts, h_ts, l_ts);
1616 rot->reset_hw_ts = true;
1617 rot->last_hw_ts = swts;
1618 }
1619}
1620
1621/*
Alan Kwong9487de22016-01-16 22:06:36 -05001622 * sde_hw_rotator_destroy - Destroy hw rotator and free allocated resources
1623 * @mgr: Pointer to rotator manager
1624 */
1625static void sde_hw_rotator_destroy(struct sde_rot_mgr *mgr)
1626{
1627 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
1628 struct sde_hw_rotator *rot;
1629
1630 if (!mgr || !mgr->pdev || !mgr->hw_data) {
1631 SDEROT_ERR("null parameters\n");
1632 return;
1633 }
1634
1635 rot = mgr->hw_data;
1636 if (rot->irq_num >= 0)
1637 devm_free_irq(&mgr->pdev->dev, rot->irq_num, mdata);
1638
1639 if (rot->mode == ROT_REGDMA_ON)
1640 sde_hw_rotator_swtc_destroy(rot);
1641
1642 devm_kfree(&mgr->pdev->dev, mgr->hw_data);
1643 mgr->hw_data = NULL;
1644}
1645
1646/*
1647 * sde_hw_rotator_alloc_ext - allocate rotator resource from rotator hw
1648 * @mgr: Pointer to rotator manager
1649 * @pipe_id: pipe identifier (not used)
1650 * @wb_id: writeback identifier/priority queue identifier
1651 *
1652 * This function allocates a new hw rotator resource for the given priority.
1653 */
1654static struct sde_rot_hw_resource *sde_hw_rotator_alloc_ext(
1655 struct sde_rot_mgr *mgr, u32 pipe_id, u32 wb_id)
1656{
1657 struct sde_hw_rotator_resource_info *resinfo;
1658
1659 if (!mgr || !mgr->hw_data) {
1660 SDEROT_ERR("null parameters\n");
1661 return NULL;
1662 }
1663
1664 /*
1665 * Allocate rotator resource info. Each allocation is per
1666 * HW priority queue
1667 */
1668 resinfo = devm_kzalloc(&mgr->pdev->dev, sizeof(*resinfo), GFP_KERNEL);
1669 if (!resinfo) {
1670 SDEROT_ERR("Failed allocation HW rotator resource info\n");
1671 return NULL;
1672 }
1673
1674 resinfo->rot = mgr->hw_data;
1675 resinfo->hw.wb_id = wb_id;
1676 atomic_set(&resinfo->hw.num_active, 0);
1677 init_waitqueue_head(&resinfo->hw.wait_queue);
1678
1679 /* For non-regdma, only support one active session */
1680 if (resinfo->rot->mode == ROT_REGDMA_OFF)
1681 resinfo->hw.max_active = 1;
1682 else {
1683 resinfo->hw.max_active = SDE_HW_ROT_REGDMA_TOTAL_CTX - 1;
1684
1685 if (resinfo->rot->iclient == NULL)
1686 sde_hw_rotator_swts_create(resinfo->rot);
1687 }
1688
Alan Kwongf987ea32016-07-06 12:11:44 -04001689 if (resinfo->rot->irq_num >= 0)
Alan Kwong818b7fc2016-07-24 22:07:41 -04001690 sde_hw_rotator_enable_irq(resinfo->rot);
Alan Kwongf987ea32016-07-06 12:11:44 -04001691
Alan Kwong9487de22016-01-16 22:06:36 -05001692 SDEROT_DBG("New rotator resource:%p, priority:%d\n",
1693 resinfo, wb_id);
1694
1695 return &resinfo->hw;
1696}
1697
1698/*
1699 * sde_hw_rotator_free_ext - free the given rotator resource
1700 * @mgr: Pointer to rotator manager
1701 * @hw: Pointer to rotator resource
1702 */
1703static void sde_hw_rotator_free_ext(struct sde_rot_mgr *mgr,
1704 struct sde_rot_hw_resource *hw)
1705{
1706 struct sde_hw_rotator_resource_info *resinfo;
1707
1708 if (!mgr || !mgr->hw_data)
1709 return;
1710
1711 resinfo = container_of(hw, struct sde_hw_rotator_resource_info, hw);
1712
1713 SDEROT_DBG(
1714 "Free rotator resource:%p, priority:%d, active:%d, pending:%d\n",
1715 resinfo, hw->wb_id, atomic_read(&hw->num_active),
1716 hw->pending_count);
1717
Alan Kwongf987ea32016-07-06 12:11:44 -04001718 if (resinfo->rot->irq_num >= 0)
Alan Kwong818b7fc2016-07-24 22:07:41 -04001719 sde_hw_rotator_disable_irq(resinfo->rot);
Alan Kwongf987ea32016-07-06 12:11:44 -04001720
Alan Kwong9487de22016-01-16 22:06:36 -05001721 devm_kfree(&mgr->pdev->dev, resinfo);
1722}
1723
1724/*
1725 * sde_hw_rotator_alloc_rotctx - allocate rotator context
1726 * @rot: Pointer to rotator hw
1727 * @hw: Pointer to rotator resource
1728 * @session_id: Session identifier of this context
Alan Kwong6bc64622017-02-04 17:36:03 -08001729 * @sbuf_mode: true if stream buffer is requested
Alan Kwong9487de22016-01-16 22:06:36 -05001730 *
1731 * This function allocates a new rotator context for the given session id.
1732 */
1733static struct sde_hw_rotator_context *sde_hw_rotator_alloc_rotctx(
1734 struct sde_hw_rotator *rot,
1735 struct sde_rot_hw_resource *hw,
Alan Kwong6bc64622017-02-04 17:36:03 -08001736 u32 session_id,
1737 bool sbuf_mode)
Alan Kwong9487de22016-01-16 22:06:36 -05001738{
1739 struct sde_hw_rotator_context *ctx;
1740
1741 /* Allocate rotator context */
1742 ctx = devm_kzalloc(&rot->pdev->dev, sizeof(*ctx), GFP_KERNEL);
1743 if (!ctx) {
1744 SDEROT_ERR("Failed allocation HW rotator context\n");
1745 return NULL;
1746 }
1747
1748 ctx->rot = rot;
1749 ctx->q_id = hw->wb_id;
1750 ctx->session_id = session_id;
1751 ctx->hwres = hw;
1752 ctx->timestamp = atomic_add_return(1, &rot->timestamp[ctx->q_id]);
1753 ctx->timestamp &= SDE_REGDMA_SWTS_MASK;
1754 ctx->is_secure = false;
Alan Kwong6bc64622017-02-04 17:36:03 -08001755 ctx->sbuf_mode = sbuf_mode;
1756 INIT_LIST_HEAD(&ctx->list);
Alan Kwong9487de22016-01-16 22:06:36 -05001757
1758 ctx->regdma_base = rot->cmd_wr_ptr[ctx->q_id]
1759 [sde_hw_rotator_get_regdma_ctxidx(ctx)];
1760 ctx->regdma_wrptr = ctx->regdma_base;
1761 ctx->ts_addr = (dma_addr_t)((u32 *)rot->swts_buf.addr +
1762 ctx->q_id * SDE_HW_ROT_REGDMA_TOTAL_CTX +
1763 sde_hw_rotator_get_regdma_ctxidx(ctx));
1764
Alan Kwong818b7fc2016-07-24 22:07:41 -04001765 ctx->last_regdma_timestamp = SDE_REGDMA_SWTS_INVALID;
1766
Alan Kwong9487de22016-01-16 22:06:36 -05001767 init_completion(&ctx->rot_comp);
Alan Kwong818b7fc2016-07-24 22:07:41 -04001768 init_waitqueue_head(&ctx->regdma_waitq);
Alan Kwong9487de22016-01-16 22:06:36 -05001769
1770 /* Store rotator context for lookup purpose */
1771 sde_hw_rotator_put_ctx(ctx);
1772
1773 SDEROT_DBG(
Alan Kwong6bc64622017-02-04 17:36:03 -08001774 "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 -05001775 ctx, sde_hw_rotator_get_regdma_ctxidx(ctx), ctx->session_id,
1776 ctx->q_id, ctx->timestamp,
Alan Kwong6bc64622017-02-04 17:36:03 -08001777 atomic_read(&ctx->hwres->num_active),
1778 ctx->sbuf_mode);
Alan Kwong9487de22016-01-16 22:06:36 -05001779
1780 return ctx;
1781}
1782
1783/*
1784 * sde_hw_rotator_free_rotctx - free the given rotator context
1785 * @rot: Pointer to rotator hw
1786 * @ctx: Pointer to rotator context
1787 */
1788static void sde_hw_rotator_free_rotctx(struct sde_hw_rotator *rot,
1789 struct sde_hw_rotator_context *ctx)
1790{
1791 if (!rot || !ctx)
1792 return;
1793
1794 SDEROT_DBG(
Alan Kwong6bc64622017-02-04 17:36:03 -08001795 "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 -05001796 ctx, sde_hw_rotator_get_regdma_ctxidx(ctx), ctx->session_id,
1797 ctx->q_id, ctx->timestamp,
Alan Kwong6bc64622017-02-04 17:36:03 -08001798 atomic_read(&ctx->hwres->num_active),
1799 ctx->sbuf_mode);
Alan Kwong9487de22016-01-16 22:06:36 -05001800
Benjamin Chanc3e185f2016-11-08 21:48:21 -05001801 /* Clear rotator context from lookup purpose */
1802 sde_hw_rotator_clr_ctx(ctx);
Alan Kwong9487de22016-01-16 22:06:36 -05001803
1804 devm_kfree(&rot->pdev->dev, ctx);
1805}
1806
1807/*
1808 * sde_hw_rotator_config - configure hw for the given rotation entry
1809 * @hw: Pointer to rotator resource
1810 * @entry: Pointer to rotation entry
1811 *
1812 * This function setup the fetch/writeback/rotator blocks, as well as VBIF
1813 * based on the given rotation entry.
1814 */
1815static int sde_hw_rotator_config(struct sde_rot_hw_resource *hw,
1816 struct sde_rot_entry *entry)
1817{
1818 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
1819 struct sde_hw_rotator *rot;
1820 struct sde_hw_rotator_resource_info *resinfo;
1821 struct sde_hw_rotator_context *ctx;
1822 struct sde_hw_rot_sspp_cfg sspp_cfg;
1823 struct sde_hw_rot_wb_cfg wb_cfg;
1824 u32 danger_lut = 0; /* applicable for realtime client only */
1825 u32 safe_lut = 0; /* applicable for realtime client only */
1826 u32 flags = 0;
1827 struct sde_rotation_item *item;
Alan Kwong6bc64622017-02-04 17:36:03 -08001828 int ret;
Alan Kwong9487de22016-01-16 22:06:36 -05001829
1830 if (!hw || !entry) {
1831 SDEROT_ERR("null hw resource/entry\n");
1832 return -EINVAL;
1833 }
1834
1835 resinfo = container_of(hw, struct sde_hw_rotator_resource_info, hw);
1836 rot = resinfo->rot;
1837 item = &entry->item;
1838
Alan Kwong6bc64622017-02-04 17:36:03 -08001839 ctx = sde_hw_rotator_alloc_rotctx(rot, hw, item->session_id,
1840 item->output.sbuf);
Alan Kwong9487de22016-01-16 22:06:36 -05001841 if (!ctx) {
1842 SDEROT_ERR("Failed allocating rotator context!!\n");
1843 return -EINVAL;
1844 }
1845
Alan Kwong6bc64622017-02-04 17:36:03 -08001846 /* save entry for debugging purposes */
1847 ctx->last_entry = entry;
1848
1849 if (test_bit(SDE_CAPS_SBUF_1, mdata->sde_caps_map)) {
1850 if (entry->dst_buf.sbuf) {
1851 u32 op_mode;
1852
1853 if (entry->item.trigger ==
1854 SDE_ROTATOR_TRIGGER_COMMAND)
1855 ctx->start_ctrl = (rot->cmd_trigger << 4);
1856 else if (entry->item.trigger ==
1857 SDE_ROTATOR_TRIGGER_VIDEO)
1858 ctx->start_ctrl = (rot->vid_trigger << 4);
1859 else
1860 ctx->start_ctrl = 0;
1861
1862 ctx->sys_cache_mode = BIT(15) |
1863 ((item->output.scid & 0x1f) << 8) |
1864 (item->output.writeback ? 0x5 : 0);
1865
1866 ctx->op_mode = BIT(4) |
1867 ((ctx->rot->sbuf_headroom & 0xff) << 8);
1868
1869 /* detect transition to inline mode */
1870 op_mode = (SDE_ROTREG_READ(rot->mdss_base,
1871 ROTTOP_OP_MODE) >> 4) & 0x3;
1872 if (!op_mode) {
1873 u32 status;
1874
1875 status = SDE_ROTREG_READ(rot->mdss_base,
1876 ROTTOP_STATUS);
1877 if (status & BIT(0)) {
1878 SDEROT_ERR("rotator busy 0x%x\n",
1879 status);
1880 sde_hw_rotator_dump_status(rot);
1881 SDEROT_EVTLOG_TOUT_HANDLER("rot",
1882 "vbif_dbg_bus",
1883 "panic");
1884 }
1885 }
1886
1887 } else {
1888 ctx->start_ctrl = BIT(0);
1889 ctx->sys_cache_mode = 0;
1890 ctx->op_mode = 0;
1891 }
1892 } else {
1893 ctx->start_ctrl = BIT(0);
1894 }
1895
1896 SDEROT_EVTLOG(ctx->start_ctrl, ctx->sys_cache_mode, ctx->op_mode);
1897
Benjamin Chan0f9e61d2016-09-16 16:01:09 -04001898 if (rot->reset_hw_ts) {
1899 SDEROT_EVTLOG(rot->last_hw_ts);
1900 SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_TIMESTAMP_REG,
1901 rot->last_hw_ts);
1902 /* ensure write is issued to the rotator HW */
1903 wmb();
1904 rot->reset_hw_ts = false;
1905 }
1906
Alan Kwong9487de22016-01-16 22:06:36 -05001907 flags = (item->flags & SDE_ROTATION_FLIP_LR) ?
1908 SDE_ROT_FLAG_FLIP_LR : 0;
1909 flags |= (item->flags & SDE_ROTATION_FLIP_UD) ?
1910 SDE_ROT_FLAG_FLIP_UD : 0;
1911 flags |= (item->flags & SDE_ROTATION_90) ?
1912 SDE_ROT_FLAG_ROT_90 : 0;
1913 flags |= (item->flags & SDE_ROTATION_DEINTERLACE) ?
1914 SDE_ROT_FLAG_DEINTERLACE : 0;
1915 flags |= (item->flags & SDE_ROTATION_SECURE) ?
1916 SDE_ROT_FLAG_SECURE_OVERLAY_SESSION : 0;
Abhijit Kulkarni298c8232016-09-26 22:32:10 -07001917 flags |= (item->flags & SDE_ROTATION_SECURE_CAMERA) ?
1918 SDE_ROT_FLAG_SECURE_CAMERA_SESSION : 0;
1919
Alan Kwong9487de22016-01-16 22:06:36 -05001920
1921 sspp_cfg.img_width = item->input.width;
1922 sspp_cfg.img_height = item->input.height;
Benjamin Chan99eb63b2016-12-21 15:45:26 -05001923 sspp_cfg.fps = entry->perf->config.frame_rate;
1924 sspp_cfg.bw = entry->perf->bw;
Alan Kwong9487de22016-01-16 22:06:36 -05001925 sspp_cfg.fmt = sde_get_format_params(item->input.format);
1926 if (!sspp_cfg.fmt) {
1927 SDEROT_ERR("null format\n");
Alan Kwong6bc64622017-02-04 17:36:03 -08001928 ret = -EINVAL;
1929 goto error;
Alan Kwong9487de22016-01-16 22:06:36 -05001930 }
1931 sspp_cfg.src_rect = &item->src_rect;
1932 sspp_cfg.data = &entry->src_buf;
1933 sde_mdp_get_plane_sizes(sspp_cfg.fmt, item->input.width,
1934 item->input.height, &sspp_cfg.src_plane,
1935 0, /* No bwc_mode */
1936 (flags & SDE_ROT_FLAG_SOURCE_ROTATED_90) ?
1937 true : false);
1938
1939 rot->ops.setup_rotator_fetchengine(ctx, ctx->q_id,
Benjamin Chanfb6faa32016-08-16 17:21:01 -04001940 &sspp_cfg, danger_lut, safe_lut,
1941 entry->dnsc_factor_w, entry->dnsc_factor_h, flags);
Alan Kwong9487de22016-01-16 22:06:36 -05001942
1943 wb_cfg.img_width = item->output.width;
1944 wb_cfg.img_height = item->output.height;
Benjamin Chan99eb63b2016-12-21 15:45:26 -05001945 wb_cfg.fps = entry->perf->config.frame_rate;
1946 wb_cfg.bw = entry->perf->bw;
Alan Kwong9487de22016-01-16 22:06:36 -05001947 wb_cfg.fmt = sde_get_format_params(item->output.format);
1948 wb_cfg.dst_rect = &item->dst_rect;
1949 wb_cfg.data = &entry->dst_buf;
1950 sde_mdp_get_plane_sizes(wb_cfg.fmt, item->output.width,
1951 item->output.height, &wb_cfg.dst_plane,
1952 0, /* No bwc_mode */
1953 (flags & SDE_ROT_FLAG_ROT_90) ? true : false);
1954
1955 wb_cfg.v_downscale_factor = entry->dnsc_factor_h;
1956 wb_cfg.h_downscale_factor = entry->dnsc_factor_w;
Alan Kwong498d59f2017-02-11 18:56:34 -08001957 wb_cfg.prefill_bw = item->prefill_bw;
Alan Kwong9487de22016-01-16 22:06:36 -05001958
1959 rot->ops.setup_rotator_wbengine(ctx, ctx->q_id, &wb_cfg, flags);
1960
1961 /* setup VA mapping for debugfs */
1962 if (rot->dbgmem) {
1963 sde_hw_rotator_map_vaddr(&ctx->src_dbgbuf,
1964 &item->input,
1965 &entry->src_buf);
1966
1967 sde_hw_rotator_map_vaddr(&ctx->dst_dbgbuf,
1968 &item->output,
1969 &entry->dst_buf);
1970 }
1971
Benjamin Chan0f9e61d2016-09-16 16:01:09 -04001972 SDEROT_EVTLOG(ctx->timestamp, flags,
1973 item->input.width, item->input.height,
Benjamin Chan53e3bce2016-08-31 14:43:29 -04001974 item->output.width, item->output.height,
Benjamin Chan59a06052017-01-12 18:06:03 -05001975 entry->src_buf.p[0].addr, entry->dst_buf.p[0].addr,
Benjamin Chan1b94f952017-01-23 17:42:30 -05001976 item->input.format, item->output.format,
1977 entry->perf->config.frame_rate);
Benjamin Chan53e3bce2016-08-31 14:43:29 -04001978
Alan Kwong9487de22016-01-16 22:06:36 -05001979 if (mdata->default_ot_rd_limit) {
1980 struct sde_mdp_set_ot_params ot_params;
1981
1982 memset(&ot_params, 0, sizeof(struct sde_mdp_set_ot_params));
1983 ot_params.xin_id = XIN_SSPP;
1984 ot_params.num = 0; /* not used */
Alan Kwongeffb5ee2016-03-12 19:47:45 -05001985 ot_params.width = entry->perf->config.input.width;
1986 ot_params.height = entry->perf->config.input.height;
1987 ot_params.fps = entry->perf->config.frame_rate;
Alan Kwong9487de22016-01-16 22:06:36 -05001988 ot_params.reg_off_vbif_lim_conf = MMSS_VBIF_RD_LIM_CONF;
1989 ot_params.reg_off_mdp_clk_ctrl =
1990 MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0;
1991 ot_params.bit_off_mdp_clk_ctrl =
1992 MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0_XIN0;
Benjamin Chan99eb63b2016-12-21 15:45:26 -05001993 ot_params.fmt = ctx->is_traffic_shaping ?
1994 SDE_PIX_FMT_ABGR_8888 :
1995 entry->perf->config.input.format;
Benjamin Chan1b94f952017-01-23 17:42:30 -05001996 ot_params.rotsts_base = rot->mdss_base + ROTTOP_STATUS;
1997 ot_params.rotsts_busy_mask = ROT_BUSY_BIT;
Alan Kwong9487de22016-01-16 22:06:36 -05001998 sde_mdp_set_ot_limit(&ot_params);
1999 }
2000
2001 if (mdata->default_ot_wr_limit) {
2002 struct sde_mdp_set_ot_params ot_params;
2003
2004 memset(&ot_params, 0, sizeof(struct sde_mdp_set_ot_params));
2005 ot_params.xin_id = XIN_WRITEBACK;
2006 ot_params.num = 0; /* not used */
Alan Kwongeffb5ee2016-03-12 19:47:45 -05002007 ot_params.width = entry->perf->config.input.width;
2008 ot_params.height = entry->perf->config.input.height;
2009 ot_params.fps = entry->perf->config.frame_rate;
Alan Kwong9487de22016-01-16 22:06:36 -05002010 ot_params.reg_off_vbif_lim_conf = MMSS_VBIF_WR_LIM_CONF;
2011 ot_params.reg_off_mdp_clk_ctrl =
2012 MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0;
2013 ot_params.bit_off_mdp_clk_ctrl =
2014 MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0_XIN1;
Benjamin Chan99eb63b2016-12-21 15:45:26 -05002015 ot_params.fmt = ctx->is_traffic_shaping ?
2016 SDE_PIX_FMT_ABGR_8888 :
2017 entry->perf->config.input.format;
Benjamin Chan1b94f952017-01-23 17:42:30 -05002018 ot_params.rotsts_base = rot->mdss_base + ROTTOP_STATUS;
2019 ot_params.rotsts_busy_mask = ROT_BUSY_BIT;
Alan Kwong9487de22016-01-16 22:06:36 -05002020 sde_mdp_set_ot_limit(&ot_params);
2021 }
2022
2023 if (test_bit(SDE_QOS_PER_PIPE_LUT, mdata->sde_qos_map)) {
2024 u32 qos_lut = 0; /* low priority for nrt read client */
2025
2026 trace_rot_perf_set_qos_luts(XIN_SSPP, sspp_cfg.fmt->format,
2027 qos_lut, sde_mdp_is_linear_format(sspp_cfg.fmt));
2028
2029 SDE_ROTREG_WRITE(rot->mdss_base, ROT_SSPP_CREQ_LUT, qos_lut);
2030 }
2031
Jayant Shekhardee61a02017-02-08 11:59:00 +05302032 /* Set CDP control registers to 0 if CDP is disabled */
2033 if (!test_bit(SDE_QOS_CDP, mdata->sde_qos_map)) {
2034 SDE_ROTREG_WRITE(rot->mdss_base, ROT_SSPP_CDP_CNTL, 0x0);
2035 SDE_ROTREG_WRITE(rot->mdss_base, ROT_WB_CDP_CNTL, 0x0);
2036 }
2037
Alan Kwong9487de22016-01-16 22:06:36 -05002038 if (mdata->npriority_lvl > 0) {
2039 u32 mask, reg_val, i, vbif_qos;
2040
2041 for (i = 0; i < mdata->npriority_lvl; i++) {
2042 reg_val = SDE_VBIF_READ(mdata,
2043 MMSS_VBIF_NRT_VBIF_QOS_REMAP_00 + i*4);
2044 mask = 0x3 << (XIN_SSPP * 2);
2045 reg_val &= ~(mask);
2046 vbif_qos = mdata->vbif_nrt_qos[i];
2047 reg_val |= vbif_qos << (XIN_SSPP * 2);
2048 /* ensure write is issued after the read operation */
2049 mb();
2050 SDE_VBIF_WRITE(mdata,
2051 MMSS_VBIF_NRT_VBIF_QOS_REMAP_00 + i*4,
2052 reg_val);
2053 }
2054 }
2055
2056 /* Enable write gather for writeback to remove write gaps, which
2057 * may hang AXI/BIMC/SDE.
2058 */
2059 SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_WRITE_GATHTER_EN,
2060 BIT(XIN_WRITEBACK));
2061
2062 return 0;
Alan Kwong6bc64622017-02-04 17:36:03 -08002063
2064error:
2065 sde_hw_rotator_free_rotctx(rot, ctx);
2066 return ret;
Alan Kwong9487de22016-01-16 22:06:36 -05002067}
2068
2069/*
2070 * sde_hw_rotator_kickoff - kickoff processing on the given entry
2071 * @hw: Pointer to rotator resource
2072 * @entry: Pointer to rotation entry
2073 */
2074static int sde_hw_rotator_kickoff(struct sde_rot_hw_resource *hw,
2075 struct sde_rot_entry *entry)
2076{
2077 struct sde_hw_rotator *rot;
2078 struct sde_hw_rotator_resource_info *resinfo;
2079 struct sde_hw_rotator_context *ctx;
Alan Kwong9487de22016-01-16 22:06:36 -05002080
2081 if (!hw || !entry) {
2082 SDEROT_ERR("null hw resource/entry\n");
2083 return -EINVAL;
2084 }
2085
2086 resinfo = container_of(hw, struct sde_hw_rotator_resource_info, hw);
2087 rot = resinfo->rot;
2088
2089 /* Lookup rotator context from session-id */
2090 ctx = sde_hw_rotator_get_ctx(rot, entry->item.session_id, hw->wb_id);
2091 if (!ctx) {
2092 SDEROT_ERR("Cannot locate rotator ctx from sesison id:%d\n",
2093 entry->item.session_id);
Benjamin Chan62b94ed2016-08-18 23:55:21 -04002094 return -EINVAL;
Alan Kwong9487de22016-01-16 22:06:36 -05002095 }
Alan Kwong9487de22016-01-16 22:06:36 -05002096
Alan Kwong9487de22016-01-16 22:06:36 -05002097 rot->ops.start_rotator(ctx, ctx->q_id);
2098
2099 return 0;
2100}
2101
2102/*
2103 * sde_hw_rotator_wait4done - wait for completion notification
2104 * @hw: Pointer to rotator resource
2105 * @entry: Pointer to rotation entry
2106 *
2107 * This function blocks until the given entry is complete, error
2108 * is detected, or timeout.
2109 */
2110static int sde_hw_rotator_wait4done(struct sde_rot_hw_resource *hw,
2111 struct sde_rot_entry *entry)
2112{
2113 struct sde_hw_rotator *rot;
2114 struct sde_hw_rotator_resource_info *resinfo;
2115 struct sde_hw_rotator_context *ctx;
2116 int ret;
2117
2118 if (!hw || !entry) {
2119 SDEROT_ERR("null hw resource/entry\n");
2120 return -EINVAL;
2121 }
2122
2123 resinfo = container_of(hw, struct sde_hw_rotator_resource_info, hw);
2124 rot = resinfo->rot;
2125
2126 /* Lookup rotator context from session-id */
2127 ctx = sde_hw_rotator_get_ctx(rot, entry->item.session_id, hw->wb_id);
2128 if (!ctx) {
2129 SDEROT_ERR("Cannot locate rotator ctx from sesison id:%d\n",
2130 entry->item.session_id);
Benjamin Chan62b94ed2016-08-18 23:55:21 -04002131 return -EINVAL;
Alan Kwong9487de22016-01-16 22:06:36 -05002132 }
Alan Kwong9487de22016-01-16 22:06:36 -05002133
2134 ret = rot->ops.wait_rotator_done(ctx, ctx->q_id, 0);
2135
Alan Kwong9487de22016-01-16 22:06:36 -05002136 if (rot->dbgmem) {
2137 sde_hw_rotator_unmap_vaddr(&ctx->src_dbgbuf);
2138 sde_hw_rotator_unmap_vaddr(&ctx->dst_dbgbuf);
2139 }
2140
2141 /* Current rotator context job is finished, time to free up*/
2142 sde_hw_rotator_free_rotctx(rot, ctx);
2143
2144 return ret;
2145}
2146
2147/*
2148 * sde_rotator_hw_rev_init - setup feature and/or capability bitmask
2149 * @rot: Pointer to hw rotator
2150 *
2151 * This function initializes feature and/or capability bitmask based on
2152 * h/w version read from the device.
2153 */
2154static int sde_rotator_hw_rev_init(struct sde_hw_rotator *rot)
2155{
2156 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
2157 u32 hw_version;
2158
2159 if (!mdata) {
2160 SDEROT_ERR("null rotator data\n");
2161 return -EINVAL;
2162 }
2163
2164 hw_version = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_HW_VERSION);
2165 SDEROT_DBG("hw version %8.8x\n", hw_version);
2166
2167 clear_bit(SDE_QOS_PER_PIPE_IB, mdata->sde_qos_map);
2168 set_bit(SDE_QOS_OVERHEAD_FACTOR, mdata->sde_qos_map);
2169 clear_bit(SDE_QOS_CDP, mdata->sde_qos_map);
2170 set_bit(SDE_QOS_OTLIM, mdata->sde_qos_map);
2171 set_bit(SDE_QOS_PER_PIPE_LUT, mdata->sde_qos_map);
2172 clear_bit(SDE_QOS_SIMPLIFIED_PREFILL, mdata->sde_qos_map);
2173
2174 set_bit(SDE_CAPS_R3_WB, mdata->sde_caps_map);
2175
Alan Kwong6bc64622017-02-04 17:36:03 -08002176 /* features exposed via rotator top h/w version */
Benjamin Chanfb6faa32016-08-16 17:21:01 -04002177 if (hw_version != SDE_ROT_TYPE_V1_0) {
2178 SDEROT_DBG("Supporting 1.5 downscale for SDE Rotator\n");
2179 set_bit(SDE_CAPS_R3_1P5_DOWNSCALE, mdata->sde_caps_map);
2180 }
2181
Abhijit Kulkarni298c8232016-09-26 22:32:10 -07002182 set_bit(SDE_CAPS_SEC_ATTACH_DETACH_SMMU, mdata->sde_caps_map);
2183
Benjamin Chan53e3bce2016-08-31 14:43:29 -04002184 mdata->nrt_vbif_dbg_bus = nrt_vbif_dbg_bus_r3;
2185 mdata->nrt_vbif_dbg_bus_size =
2186 ARRAY_SIZE(nrt_vbif_dbg_bus_r3);
2187
2188 mdata->regdump = sde_rot_r3_regdump;
2189 mdata->regdump_size = ARRAY_SIZE(sde_rot_r3_regdump);
Benjamin Chan0f9e61d2016-09-16 16:01:09 -04002190 SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_TIMESTAMP_REG, 0);
Alan Kwong6bc64622017-02-04 17:36:03 -08002191
2192 /* features exposed via mdss h/w version */
2193 if (IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, SDE_MDP_HW_REV_400)) {
2194 SDEROT_DBG("Supporting sys cache inline rotation\n");
2195 set_bit(SDE_CAPS_SBUF_1, mdata->sde_caps_map);
2196 rot->inpixfmts = sde_hw_rotator_v4_inpixfmts;
2197 rot->num_inpixfmt = ARRAY_SIZE(sde_hw_rotator_v4_inpixfmts);
2198 rot->outpixfmts = sde_hw_rotator_v4_outpixfmts;
2199 rot->num_outpixfmt = ARRAY_SIZE(sde_hw_rotator_v4_outpixfmts);
2200 rot->downscale_caps =
2201 "LINEAR/1.5/2/4/8/16/32/64 TILE/1.5/2/4 TP10/1.5/2";
2202 } else {
2203 rot->inpixfmts = sde_hw_rotator_v3_inpixfmts;
2204 rot->num_inpixfmt = ARRAY_SIZE(sde_hw_rotator_v3_inpixfmts);
2205 rot->outpixfmts = sde_hw_rotator_v3_outpixfmts;
2206 rot->num_outpixfmt = ARRAY_SIZE(sde_hw_rotator_v3_outpixfmts);
2207 rot->downscale_caps = (hw_version == SDE_ROT_TYPE_V1_0) ?
2208 "LINEAR/2/4/8/16/32/64 TILE/2/4 TP10/2" :
2209 "LINEAR/1.5/2/4/8/16/32/64 TILE/1.5/2/4 TP10/1.5/2";
2210 }
2211
Alan Kwong9487de22016-01-16 22:06:36 -05002212 return 0;
2213}
2214
2215/*
2216 * sde_hw_rotator_rotirq_handler - non-regdma interrupt handler
2217 * @irq: Interrupt number
2218 * @ptr: Pointer to private handle provided during registration
2219 *
2220 * This function services rotator interrupt and wakes up waiting client
2221 * with pending rotation requests already submitted to h/w.
2222 */
2223static irqreturn_t sde_hw_rotator_rotirq_handler(int irq, void *ptr)
2224{
2225 struct sde_hw_rotator *rot = ptr;
2226 struct sde_hw_rotator_context *ctx;
2227 irqreturn_t ret = IRQ_NONE;
2228 u32 isr;
2229
2230 isr = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_INTR_STATUS);
2231
2232 SDEROT_DBG("intr_status = %8.8x\n", isr);
2233
2234 if (isr & ROT_DONE_MASK) {
2235 if (rot->irq_num >= 0)
Alan Kwong818b7fc2016-07-24 22:07:41 -04002236 sde_hw_rotator_disable_irq(rot);
Alan Kwong9487de22016-01-16 22:06:36 -05002237 SDEROT_DBG("Notify rotator complete\n");
2238
2239 /* Normal rotator only 1 session, no need to lookup */
2240 ctx = rot->rotCtx[0][0];
2241 WARN_ON(ctx == NULL);
2242 complete_all(&ctx->rot_comp);
2243
2244 spin_lock(&rot->rotisr_lock);
2245 SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_CLEAR,
2246 ROT_DONE_CLEAR);
2247 spin_unlock(&rot->rotisr_lock);
2248 ret = IRQ_HANDLED;
2249 }
2250
2251 return ret;
2252}
2253
2254/*
2255 * sde_hw_rotator_regdmairq_handler - regdma interrupt handler
2256 * @irq: Interrupt number
2257 * @ptr: Pointer to private handle provided during registration
2258 *
2259 * This function services rotator interrupt, decoding the source of
2260 * events (high/low priority queue), and wakes up all waiting clients
2261 * with pending rotation requests already submitted to h/w.
2262 */
2263static irqreturn_t sde_hw_rotator_regdmairq_handler(int irq, void *ptr)
2264{
2265 struct sde_hw_rotator *rot = ptr;
2266 struct sde_hw_rotator_context *ctx;
2267 irqreturn_t ret = IRQ_NONE;
2268 u32 isr;
2269 u32 ts;
2270 u32 q_id;
2271
2272 isr = SDE_ROTREG_READ(rot->mdss_base, REGDMA_CSR_REGDMA_INT_STATUS);
Alan Kwong818b7fc2016-07-24 22:07:41 -04002273 /* acknowledge interrupt before reading latest timestamp */
2274 SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_INT_CLEAR, isr);
Alan Kwong9487de22016-01-16 22:06:36 -05002275 ts = SDE_ROTREG_READ(rot->mdss_base, REGDMA_TIMESTAMP_REG);
2276
2277 SDEROT_DBG("intr_status = %8.8x, sw_TS:%X\n", isr, ts);
2278
2279 /* Any REGDMA status, including error and watchdog timer, should
2280 * trigger and wake up waiting thread
2281 */
2282 if (isr & (REGDMA_INT_HIGH_MASK | REGDMA_INT_LOW_MASK)) {
2283 spin_lock(&rot->rotisr_lock);
2284
2285 /*
2286 * Obtain rotator context based on timestamp from regdma
2287 * and low/high interrupt status
2288 */
2289 if (isr & REGDMA_INT_HIGH_MASK) {
2290 q_id = ROT_QUEUE_HIGH_PRIORITY;
2291 ts = ts & SDE_REGDMA_SWTS_MASK;
2292 } else if (isr & REGDMA_INT_LOW_MASK) {
2293 q_id = ROT_QUEUE_LOW_PRIORITY;
2294 ts = (ts >> SDE_REGDMA_SWTS_SHIFT) &
2295 SDE_REGDMA_SWTS_MASK;
Benjamin Chan62b94ed2016-08-18 23:55:21 -04002296 } else {
2297 SDEROT_ERR("unknown ISR status: isr=0x%X\n", isr);
2298 goto done_isr_handle;
Alan Kwong9487de22016-01-16 22:06:36 -05002299 }
Alan Kwong6bc64622017-02-04 17:36:03 -08002300
2301 /*
2302 * Timestamp packet is not available in sbuf mode.
2303 * Simulate timestamp update in the handler instead.
2304 */
2305 if (!list_empty(&rot->sbuf_ctx[q_id])) {
2306 ctx = list_first_entry_or_null(&rot->sbuf_ctx[q_id],
2307 struct sde_hw_rotator_context, list);
2308 if (ctx) {
2309 ts = ctx->timestamp;
2310 sde_hw_rotator_update_swts(rot, ctx, ts);
2311 SDEROT_DBG("update swts:0x%X\n", ts);
2312 } else {
2313 SDEROT_ERR("invalid swts ctx\n");
2314 }
2315 }
2316
Alan Kwong9487de22016-01-16 22:06:36 -05002317 ctx = rot->rotCtx[q_id][ts & SDE_HW_ROT_REGDMA_SEG_MASK];
Alan Kwong9487de22016-01-16 22:06:36 -05002318
2319 /*
2320 * Wake up all waiting context from the current and previous
2321 * SW Timestamp.
2322 */
Alan Kwong818b7fc2016-07-24 22:07:41 -04002323 while (ctx &&
2324 sde_hw_rotator_elapsed_swts(ctx->timestamp, ts) >= 0) {
Alan Kwong9487de22016-01-16 22:06:36 -05002325 ctx->last_regdma_isr_status = isr;
2326 ctx->last_regdma_timestamp = ts;
2327 SDEROT_DBG(
Alan Kwongf987ea32016-07-06 12:11:44 -04002328 "regdma complete: ctx:%p, ts:%X\n", ctx, ts);
Alan Kwong818b7fc2016-07-24 22:07:41 -04002329 wake_up_all(&ctx->regdma_waitq);
Alan Kwong9487de22016-01-16 22:06:36 -05002330
2331 ts = (ts - 1) & SDE_REGDMA_SWTS_MASK;
2332 ctx = rot->rotCtx[q_id]
2333 [ts & SDE_HW_ROT_REGDMA_SEG_MASK];
Alan Kwong818b7fc2016-07-24 22:07:41 -04002334 };
Alan Kwong9487de22016-01-16 22:06:36 -05002335
Benjamin Chan62b94ed2016-08-18 23:55:21 -04002336done_isr_handle:
Alan Kwong9487de22016-01-16 22:06:36 -05002337 spin_unlock(&rot->rotisr_lock);
2338 ret = IRQ_HANDLED;
2339 } else if (isr & REGDMA_INT_ERR_MASK) {
2340 /*
2341 * For REGDMA Err, we save the isr info and wake up
2342 * all waiting contexts
2343 */
2344 int i, j;
2345
2346 SDEROT_ERR(
2347 "regdma err isr:%X, wake up all waiting contexts\n",
2348 isr);
2349
2350 spin_lock(&rot->rotisr_lock);
2351
2352 for (i = 0; i < ROT_QUEUE_MAX; i++) {
2353 for (j = 0; j < SDE_HW_ROT_REGDMA_TOTAL_CTX; j++) {
2354 ctx = rot->rotCtx[i][j];
2355 if (ctx && ctx->last_regdma_isr_status == 0) {
2356 ctx->last_regdma_isr_status = isr;
2357 ctx->last_regdma_timestamp = ts;
Alan Kwong818b7fc2016-07-24 22:07:41 -04002358 wake_up_all(&ctx->regdma_waitq);
Alan Kwong9487de22016-01-16 22:06:36 -05002359 SDEROT_DBG("Wakeup rotctx[%d][%d]:%p\n",
2360 i, j, ctx);
2361 }
2362 }
2363 }
2364
Alan Kwong9487de22016-01-16 22:06:36 -05002365 spin_unlock(&rot->rotisr_lock);
2366 ret = IRQ_HANDLED;
2367 }
2368
2369 return ret;
2370}
2371
2372/*
2373 * sde_hw_rotator_validate_entry - validate rotation entry
2374 * @mgr: Pointer to rotator manager
2375 * @entry: Pointer to rotation entry
2376 *
2377 * This function validates the given rotation entry and provides possible
2378 * fixup (future improvement) if available. This function returns 0 if
2379 * the entry is valid, and returns error code otherwise.
2380 */
2381static int sde_hw_rotator_validate_entry(struct sde_rot_mgr *mgr,
2382 struct sde_rot_entry *entry)
2383{
Benjamin Chanfb6faa32016-08-16 17:21:01 -04002384 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
Alan Kwong9487de22016-01-16 22:06:36 -05002385 int ret = 0;
2386 u16 src_w, src_h, dst_w, dst_h;
2387 struct sde_rotation_item *item = &entry->item;
2388 struct sde_mdp_format_params *fmt;
2389
2390 src_w = item->src_rect.w;
2391 src_h = item->src_rect.h;
2392
2393 if (item->flags & SDE_ROTATION_90) {
2394 dst_w = item->dst_rect.h;
2395 dst_h = item->dst_rect.w;
2396 } else {
2397 dst_w = item->dst_rect.w;
2398 dst_h = item->dst_rect.h;
2399 }
2400
2401 entry->dnsc_factor_w = 0;
2402 entry->dnsc_factor_h = 0;
2403
Alan Kwong6bc64622017-02-04 17:36:03 -08002404 if (item->output.sbuf &&
2405 !test_bit(SDE_CAPS_SBUF_1, mdata->sde_caps_map)) {
2406 SDEROT_ERR("stream buffer not supported\n");
2407 return -EINVAL;
2408 }
2409
Alan Kwong9487de22016-01-16 22:06:36 -05002410 if ((src_w != dst_w) || (src_h != dst_h)) {
2411 if ((src_w % dst_w) || (src_h % dst_h)) {
2412 SDEROT_DBG("non integral scale not support\n");
2413 ret = -EINVAL;
Benjamin Chanfb6faa32016-08-16 17:21:01 -04002414 goto dnsc_1p5_check;
Alan Kwong9487de22016-01-16 22:06:36 -05002415 }
2416 entry->dnsc_factor_w = src_w / dst_w;
2417 if ((entry->dnsc_factor_w & (entry->dnsc_factor_w - 1)) ||
2418 (entry->dnsc_factor_w > 64)) {
2419 SDEROT_DBG("non power-of-2 w_scale not support\n");
2420 ret = -EINVAL;
2421 goto dnsc_err;
2422 }
2423 entry->dnsc_factor_h = src_h / dst_h;
2424 if ((entry->dnsc_factor_h & (entry->dnsc_factor_h - 1)) ||
2425 (entry->dnsc_factor_h > 64)) {
2426 SDEROT_DBG("non power-of-2 h_scale not support\n");
2427 ret = -EINVAL;
2428 goto dnsc_err;
2429 }
2430 }
2431
Benjamin Chan0e96afd2017-01-17 16:49:12 -05002432 fmt = sde_get_format_params(item->output.format);
Benjamin Chan886ff672016-11-07 15:23:17 -05002433 /*
2434 * Rotator downscale support max 4 times for UBWC format and
2435 * max 2 times for TP10/TP10_UBWC format
2436 */
2437 if (sde_mdp_is_ubwc_format(fmt) && (entry->dnsc_factor_h > 4)) {
2438 SDEROT_DBG("max downscale for UBWC format is 4\n");
Alan Kwong9487de22016-01-16 22:06:36 -05002439 ret = -EINVAL;
2440 goto dnsc_err;
2441 }
Benjamin Chan886ff672016-11-07 15:23:17 -05002442 if (sde_mdp_is_tp10_format(fmt) && (entry->dnsc_factor_h > 2)) {
2443 SDEROT_DBG("downscale with TP10 cannot be more than 2\n");
Alan Kwong9487de22016-01-16 22:06:36 -05002444 ret = -EINVAL;
2445 }
Benjamin Chanfb6faa32016-08-16 17:21:01 -04002446 goto dnsc_err;
2447
2448dnsc_1p5_check:
2449 /* Check for 1.5 downscale that only applies to V2 HW */
2450 if (test_bit(SDE_CAPS_R3_1P5_DOWNSCALE, mdata->sde_caps_map)) {
2451 entry->dnsc_factor_w = src_w / dst_w;
2452 if ((entry->dnsc_factor_w != 1) ||
2453 ((dst_w * 3) != (src_w * 2))) {
2454 SDEROT_DBG(
2455 "No supporting non 1.5 downscale width ratio, src_w:%d, dst_w:%d\n",
2456 src_w, dst_w);
2457 ret = -EINVAL;
2458 goto dnsc_err;
2459 }
2460
2461 entry->dnsc_factor_h = src_h / dst_h;
2462 if ((entry->dnsc_factor_h != 1) ||
2463 ((dst_h * 3) != (src_h * 2))) {
2464 SDEROT_DBG(
2465 "Not supporting non 1.5 downscale height ratio, src_h:%d, dst_h:%d\n",
2466 src_h, dst_h);
2467 ret = -EINVAL;
2468 goto dnsc_err;
2469 }
2470 ret = 0;
2471 }
Alan Kwong9487de22016-01-16 22:06:36 -05002472
2473dnsc_err:
2474 /* Downscaler does not support asymmetrical dnsc */
2475 if (entry->dnsc_factor_w != entry->dnsc_factor_h) {
2476 SDEROT_DBG("asymmetric downscale not support\n");
2477 ret = -EINVAL;
2478 }
2479
2480 if (ret) {
2481 entry->dnsc_factor_w = 0;
2482 entry->dnsc_factor_h = 0;
2483 }
2484 return ret;
2485}
2486
2487/*
2488 * sde_hw_rotator_show_caps - output capability info to sysfs 'caps' file
2489 * @mgr: Pointer to rotator manager
2490 * @attr: Pointer to device attribute interface
2491 * @buf: Pointer to output buffer
2492 * @len: Length of output buffer
2493 */
2494static ssize_t sde_hw_rotator_show_caps(struct sde_rot_mgr *mgr,
2495 struct device_attribute *attr, char *buf, ssize_t len)
2496{
2497 struct sde_hw_rotator *hw_data;
Benjamin Chan886ff672016-11-07 15:23:17 -05002498 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
Alan Kwong9487de22016-01-16 22:06:36 -05002499 int cnt = 0;
2500
2501 if (!mgr || !buf)
2502 return 0;
2503
2504 hw_data = mgr->hw_data;
2505
2506#define SPRINT(fmt, ...) \
2507 (cnt += scnprintf(buf + cnt, len - cnt, fmt, ##__VA_ARGS__))
2508
2509 /* insert capabilities here */
Benjamin Chan886ff672016-11-07 15:23:17 -05002510 if (test_bit(SDE_CAPS_R3_1P5_DOWNSCALE, mdata->sde_caps_map))
2511 SPRINT("min_downscale=1.5\n");
2512 else
2513 SPRINT("min_downscale=2.0\n");
Alan Kwong9487de22016-01-16 22:06:36 -05002514
Benjamin Chan42db2c92016-11-22 22:50:01 -05002515 SPRINT("downscale_compression=1\n");
2516
Alan Kwong6bc64622017-02-04 17:36:03 -08002517 if (hw_data->downscale_caps)
2518 SPRINT("downscale_ratios=%s\n", hw_data->downscale_caps);
2519
Alan Kwong9487de22016-01-16 22:06:36 -05002520#undef SPRINT
2521 return cnt;
2522}
2523
2524/*
2525 * sde_hw_rotator_show_state - output state info to sysfs 'state' file
2526 * @mgr: Pointer to rotator manager
2527 * @attr: Pointer to device attribute interface
2528 * @buf: Pointer to output buffer
2529 * @len: Length of output buffer
2530 */
2531static ssize_t sde_hw_rotator_show_state(struct sde_rot_mgr *mgr,
2532 struct device_attribute *attr, char *buf, ssize_t len)
2533{
2534 struct sde_hw_rotator *rot;
2535 struct sde_hw_rotator_context *ctx;
2536 int cnt = 0;
2537 int num_active = 0;
2538 int i, j;
2539
2540 if (!mgr || !buf) {
2541 SDEROT_ERR("null parameters\n");
2542 return 0;
2543 }
2544
2545 rot = mgr->hw_data;
2546
2547#define SPRINT(fmt, ...) \
2548 (cnt += scnprintf(buf + cnt, len - cnt, fmt, ##__VA_ARGS__))
2549
2550 if (rot) {
2551 SPRINT("rot_mode=%d\n", rot->mode);
2552 SPRINT("irq_num=%d\n", rot->irq_num);
2553
2554 if (rot->mode == ROT_REGDMA_OFF) {
2555 SPRINT("max_active=1\n");
2556 SPRINT("num_active=%d\n", rot->rotCtx[0][0] ? 1 : 0);
2557 } else {
2558 for (i = 0; i < ROT_QUEUE_MAX; i++) {
2559 for (j = 0; j < SDE_HW_ROT_REGDMA_TOTAL_CTX;
2560 j++) {
2561 ctx = rot->rotCtx[i][j];
2562
2563 if (ctx) {
2564 SPRINT(
2565 "rotCtx[%d][%d]:%p\n",
2566 i, j, ctx);
2567 ++num_active;
2568 }
2569 }
2570 }
2571
2572 SPRINT("max_active=%d\n", SDE_HW_ROT_REGDMA_TOTAL_CTX);
2573 SPRINT("num_active=%d\n", num_active);
2574 }
2575 }
2576
2577#undef SPRINT
2578 return cnt;
2579}
2580
2581/*
Alan Kwongda16e442016-08-14 20:47:18 -04002582 * sde_hw_rotator_get_pixfmt - get the indexed pixel format
2583 * @mgr: Pointer to rotator manager
2584 * @index: index of pixel format
2585 * @input: true for input port; false for output port
2586 */
2587static u32 sde_hw_rotator_get_pixfmt(struct sde_rot_mgr *mgr,
2588 int index, bool input)
2589{
Alan Kwong6bc64622017-02-04 17:36:03 -08002590 struct sde_hw_rotator *rot;
2591
2592 if (!mgr || !mgr->hw_data) {
2593 SDEROT_ERR("null parameters\n");
2594 return 0;
2595 }
2596
2597 rot = mgr->hw_data;
2598
Alan Kwongda16e442016-08-14 20:47:18 -04002599 if (input) {
Alan Kwong6bc64622017-02-04 17:36:03 -08002600 if ((index < rot->num_inpixfmt) && rot->inpixfmts)
2601 return rot->inpixfmts[index];
Alan Kwongda16e442016-08-14 20:47:18 -04002602 else
2603 return 0;
2604 } else {
Alan Kwong6bc64622017-02-04 17:36:03 -08002605 if ((index < rot->num_outpixfmt) && rot->outpixfmts)
2606 return rot->outpixfmts[index];
Alan Kwongda16e442016-08-14 20:47:18 -04002607 else
2608 return 0;
2609 }
2610}
2611
2612/*
2613 * sde_hw_rotator_is_valid_pixfmt - verify if the given pixel format is valid
2614 * @mgr: Pointer to rotator manager
2615 * @pixfmt: pixel format to be verified
2616 * @input: true for input port; false for output port
2617 */
2618static int sde_hw_rotator_is_valid_pixfmt(struct sde_rot_mgr *mgr, u32 pixfmt,
2619 bool input)
2620{
Alan Kwong6bc64622017-02-04 17:36:03 -08002621 struct sde_hw_rotator *rot;
2622 u32 *pixfmts;
2623 u32 num_pixfmt;
Alan Kwongda16e442016-08-14 20:47:18 -04002624 int i;
2625
Alan Kwong6bc64622017-02-04 17:36:03 -08002626 if (!mgr || !mgr->hw_data) {
2627 SDEROT_ERR("null parameters\n");
2628 return false;
Alan Kwongda16e442016-08-14 20:47:18 -04002629 }
2630
Alan Kwong6bc64622017-02-04 17:36:03 -08002631 rot = mgr->hw_data;
2632
2633 if (input) {
2634 pixfmts = rot->inpixfmts;
2635 num_pixfmt = rot->num_inpixfmt;
2636 } else {
2637 pixfmts = rot->outpixfmts;
2638 num_pixfmt = rot->num_outpixfmt;
2639 }
2640
2641 if (!pixfmts || !num_pixfmt) {
2642 SDEROT_ERR("invalid pixel format tables\n");
2643 return false;
2644 }
2645
2646 for (i = 0; i < num_pixfmt; i++)
2647 if (pixfmts[i] == pixfmt)
2648 return true;
2649
Alan Kwongda16e442016-08-14 20:47:18 -04002650 return false;
2651}
2652
2653/*
Alan Kwong6bc64622017-02-04 17:36:03 -08002654 * sde_hw_rotator_get_downscale_caps - get scaling capability string
2655 * @mgr: Pointer to rotator manager
2656 * @caps: Pointer to capability string buffer; NULL to return maximum length
2657 * @len: length of capability string buffer
2658 * return: length of capability string
2659 */
2660static int sde_hw_rotator_get_downscale_caps(struct sde_rot_mgr *mgr,
2661 char *caps, int len)
2662{
2663 struct sde_hw_rotator *rot;
2664 int rc = 0;
2665
2666 if (!mgr || !mgr->hw_data) {
2667 SDEROT_ERR("null parameters\n");
2668 return -EINVAL;
2669 }
2670
2671 rot = mgr->hw_data;
2672
2673 if (rot->downscale_caps) {
2674 if (caps)
2675 rc = snprintf(caps, len, "%s", rot->downscale_caps);
2676 else
2677 rc = strlen(rot->downscale_caps);
2678 }
2679
2680 return rc;
2681}
2682
2683/*
Alan Kwong9487de22016-01-16 22:06:36 -05002684 * sde_hw_rotator_parse_dt - parse r3 specific device tree settings
2685 * @hw_data: Pointer to rotator hw
2686 * @dev: Pointer to platform device
2687 */
2688static int sde_hw_rotator_parse_dt(struct sde_hw_rotator *hw_data,
2689 struct platform_device *dev)
2690{
2691 int ret = 0;
2692 u32 data;
2693
2694 if (!hw_data || !dev)
2695 return -EINVAL;
2696
2697 ret = of_property_read_u32(dev->dev.of_node, "qcom,mdss-rot-mode",
2698 &data);
2699 if (ret) {
2700 SDEROT_DBG("default to regdma off\n");
2701 ret = 0;
2702 hw_data->mode = ROT_REGDMA_OFF;
2703 } else if (data < ROT_REGDMA_MAX) {
2704 SDEROT_DBG("set to regdma mode %d\n", data);
2705 hw_data->mode = data;
2706 } else {
2707 SDEROT_ERR("regdma mode out of range. default to regdma off\n");
2708 hw_data->mode = ROT_REGDMA_OFF;
2709 }
2710
2711 ret = of_property_read_u32(dev->dev.of_node,
2712 "qcom,mdss-highest-bank-bit", &data);
2713 if (ret) {
2714 SDEROT_DBG("default to A5X bank\n");
2715 ret = 0;
2716 hw_data->highest_bank = 2;
2717 } else {
2718 SDEROT_DBG("set highest bank bit to %d\n", data);
2719 hw_data->highest_bank = data;
2720 }
2721
Alan Kwong6bc64622017-02-04 17:36:03 -08002722 ret = of_property_read_u32(dev->dev.of_node,
2723 "qcom,mdss-sbuf-headroom", &data);
2724 if (ret) {
2725 ret = 0;
2726 hw_data->sbuf_headroom = DEFAULT_SBUF_HEADROOM;
2727 } else {
2728 SDEROT_DBG("set sbuf headroom to %d\n", data);
2729 hw_data->sbuf_headroom = data;
2730 }
2731
Alan Kwong9487de22016-01-16 22:06:36 -05002732 return ret;
2733}
2734
2735/*
2736 * sde_rotator_r3_init - initialize the r3 module
2737 * @mgr: Pointer to rotator manager
2738 *
2739 * This function setup r3 callback functions, parses r3 specific
2740 * device tree settings, installs r3 specific interrupt handler,
2741 * as well as initializes r3 internal data structure.
2742 */
2743int sde_rotator_r3_init(struct sde_rot_mgr *mgr)
2744{
2745 struct sde_hw_rotator *rot;
2746 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
2747 int i;
2748 int ret;
2749
2750 rot = devm_kzalloc(&mgr->pdev->dev, sizeof(*rot), GFP_KERNEL);
2751 if (!rot)
2752 return -ENOMEM;
2753
2754 mgr->hw_data = rot;
2755 mgr->queue_count = ROT_QUEUE_MAX;
2756
2757 rot->mdss_base = mdata->sde_io.base;
2758 rot->pdev = mgr->pdev;
Alan Kwong6bc64622017-02-04 17:36:03 -08002759 rot->koff_timeout = KOFF_TIMEOUT;
2760 rot->vid_trigger = ROTTOP_START_CTRL_TRIG_SEL_MDP;
2761 rot->cmd_trigger = ROTTOP_START_CTRL_TRIG_SEL_MDP;
Alan Kwong9487de22016-01-16 22:06:36 -05002762
2763 /* Assign ops */
2764 mgr->ops_hw_destroy = sde_hw_rotator_destroy;
2765 mgr->ops_hw_alloc = sde_hw_rotator_alloc_ext;
2766 mgr->ops_hw_free = sde_hw_rotator_free_ext;
2767 mgr->ops_config_hw = sde_hw_rotator_config;
2768 mgr->ops_kickoff_entry = sde_hw_rotator_kickoff;
2769 mgr->ops_wait_for_entry = sde_hw_rotator_wait4done;
2770 mgr->ops_hw_validate_entry = sde_hw_rotator_validate_entry;
2771 mgr->ops_hw_show_caps = sde_hw_rotator_show_caps;
2772 mgr->ops_hw_show_state = sde_hw_rotator_show_state;
2773 mgr->ops_hw_create_debugfs = sde_rotator_r3_create_debugfs;
Alan Kwongda16e442016-08-14 20:47:18 -04002774 mgr->ops_hw_get_pixfmt = sde_hw_rotator_get_pixfmt;
2775 mgr->ops_hw_is_valid_pixfmt = sde_hw_rotator_is_valid_pixfmt;
Benjamin Chan0f9e61d2016-09-16 16:01:09 -04002776 mgr->ops_hw_pre_pmevent = sde_hw_rotator_pre_pmevent;
2777 mgr->ops_hw_post_pmevent = sde_hw_rotator_post_pmevent;
Alan Kwong6bc64622017-02-04 17:36:03 -08002778 mgr->ops_hw_get_downscale_caps = sde_hw_rotator_get_downscale_caps;
Alan Kwong9487de22016-01-16 22:06:36 -05002779
2780 ret = sde_hw_rotator_parse_dt(mgr->hw_data, mgr->pdev);
2781 if (ret)
2782 goto error_parse_dt;
2783
2784 rot->irq_num = platform_get_irq(mgr->pdev, 0);
2785 if (rot->irq_num < 0) {
2786 SDEROT_ERR("fail to get rotator irq\n");
2787 } else {
2788 if (rot->mode == ROT_REGDMA_OFF)
2789 ret = devm_request_threaded_irq(&mgr->pdev->dev,
2790 rot->irq_num,
2791 sde_hw_rotator_rotirq_handler,
2792 NULL, 0, "sde_rotator_r3", rot);
2793 else
2794 ret = devm_request_threaded_irq(&mgr->pdev->dev,
2795 rot->irq_num,
2796 sde_hw_rotator_regdmairq_handler,
2797 NULL, 0, "sde_rotator_r3", rot);
2798 if (ret) {
2799 SDEROT_ERR("fail to request irq r:%d\n", ret);
2800 rot->irq_num = -1;
2801 } else {
2802 disable_irq(rot->irq_num);
2803 }
2804 }
Alan Kwong818b7fc2016-07-24 22:07:41 -04002805 atomic_set(&rot->irq_enabled, 0);
Alan Kwong9487de22016-01-16 22:06:36 -05002806
2807 setup_rotator_ops(&rot->ops, rot->mode);
2808
2809 spin_lock_init(&rot->rotctx_lock);
2810 spin_lock_init(&rot->rotisr_lock);
2811
2812 /* REGDMA initialization */
2813 if (rot->mode == ROT_REGDMA_OFF) {
2814 for (i = 0; i < SDE_HW_ROT_REGDMA_TOTAL_CTX; i++)
2815 rot->cmd_wr_ptr[0][i] = &rot->cmd_queue[
2816 SDE_HW_ROT_REGDMA_SEG_SIZE * i];
2817 } else {
2818 for (i = 0; i < SDE_HW_ROT_REGDMA_TOTAL_CTX; i++)
2819 rot->cmd_wr_ptr[ROT_QUEUE_HIGH_PRIORITY][i] =
2820 (u32 *)(rot->mdss_base +
2821 REGDMA_RAM_REGDMA_CMD_RAM +
2822 SDE_HW_ROT_REGDMA_SEG_SIZE * 4 * i);
2823
2824 for (i = 0; i < SDE_HW_ROT_REGDMA_TOTAL_CTX; i++)
2825 rot->cmd_wr_ptr[ROT_QUEUE_LOW_PRIORITY][i] =
2826 (u32 *)(rot->mdss_base +
2827 REGDMA_RAM_REGDMA_CMD_RAM +
2828 SDE_HW_ROT_REGDMA_SEG_SIZE * 4 *
2829 (i + SDE_HW_ROT_REGDMA_TOTAL_CTX));
2830 }
2831
Alan Kwong6bc64622017-02-04 17:36:03 -08002832 for (i = 0; i < ROT_QUEUE_MAX; i++) {
2833 atomic_set(&rot->timestamp[i], 0);
2834 INIT_LIST_HEAD(&rot->sbuf_ctx[i]);
2835 }
Alan Kwong9487de22016-01-16 22:06:36 -05002836
2837 ret = sde_rotator_hw_rev_init(rot);
2838 if (ret)
2839 goto error_hw_rev_init;
2840
Alan Kwong315cd772016-08-03 22:29:42 -04002841 /* set rotator CBCR to shutoff memory/periphery on clock off.*/
Benjamin Chan77aed192016-10-17 17:49:41 -04002842 clk_set_flags(mgr->rot_clk[SDE_ROTATOR_CLK_ROT_CORE].clk,
Alan Kwong315cd772016-08-03 22:29:42 -04002843 CLKFLAG_NORETAIN_MEM);
Benjamin Chan77aed192016-10-17 17:49:41 -04002844 clk_set_flags(mgr->rot_clk[SDE_ROTATOR_CLK_ROT_CORE].clk,
Alan Kwong315cd772016-08-03 22:29:42 -04002845 CLKFLAG_NORETAIN_PERIPH);
2846
Benjamin Chan53e3bce2016-08-31 14:43:29 -04002847 mdata->sde_rot_hw = rot;
Alan Kwong9487de22016-01-16 22:06:36 -05002848 return 0;
2849error_hw_rev_init:
2850 if (rot->irq_num >= 0)
2851 devm_free_irq(&mgr->pdev->dev, rot->irq_num, mdata);
2852 devm_kfree(&mgr->pdev->dev, mgr->hw_data);
2853error_parse_dt:
2854 return ret;
2855}