1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright 2019 NXP. |
4 | */ |
5 | |
6 | #include <linux/device.h> |
7 | #include <linux/slab.h> |
8 | |
9 | #include "dcss-dev.h" |
10 | |
11 | #define DCSS_DPR_SYSTEM_CTRL0 0x000 |
12 | #define RUN_EN BIT(0) |
13 | #define SOFT_RESET BIT(1) |
14 | #define REPEAT_EN BIT(2) |
15 | #define SHADOW_LOAD_EN BIT(3) |
16 | #define SW_SHADOW_LOAD_SEL BIT(4) |
17 | #define BCMD2AXI_MSTR_ID_CTRL BIT(16) |
18 | #define DCSS_DPR_IRQ_MASK 0x020 |
19 | #define DCSS_DPR_IRQ_MASK_STATUS 0x030 |
20 | #define DCSS_DPR_IRQ_NONMASK_STATUS 0x040 |
21 | #define IRQ_DPR_CTRL_DONE BIT(0) |
22 | #define IRQ_DPR_RUN BIT(1) |
23 | #define IRQ_DPR_SHADOW_LOADED BIT(2) |
24 | #define IRQ_AXI_READ_ERR BIT(3) |
25 | #define DPR2RTR_YRGB_FIFO_OVFL BIT(4) |
26 | #define DPR2RTR_UV_FIFO_OVFL BIT(5) |
27 | #define DPR2RTR_FIFO_LD_BUF_RDY_YRGB_ERR BIT(6) |
28 | #define DPR2RTR_FIFO_LD_BUF_RDY_UV_ERR BIT(7) |
29 | #define DCSS_DPR_MODE_CTRL0 0x050 |
30 | #define RTR_3BUF_EN BIT(0) |
31 | #define RTR_4LINE_BUF_EN BIT(1) |
32 | #define TILE_TYPE_POS 2 |
33 | #define TILE_TYPE_MASK GENMASK(4, 2) |
34 | #define YUV_EN BIT(6) |
35 | #define COMP_2PLANE_EN BIT(7) |
36 | #define PIX_SIZE_POS 8 |
37 | #define PIX_SIZE_MASK GENMASK(9, 8) |
38 | #define PIX_LUMA_UV_SWAP BIT(10) |
39 | #define PIX_UV_SWAP BIT(11) |
40 | #define B_COMP_SEL_POS 12 |
41 | #define B_COMP_SEL_MASK GENMASK(13, 12) |
42 | #define G_COMP_SEL_POS 14 |
43 | #define G_COMP_SEL_MASK GENMASK(15, 14) |
44 | #define R_COMP_SEL_POS 16 |
45 | #define R_COMP_SEL_MASK GENMASK(17, 16) |
46 | #define A_COMP_SEL_POS 18 |
47 | #define A_COMP_SEL_MASK GENMASK(19, 18) |
48 | #define DCSS_DPR_FRAME_CTRL0 0x070 |
49 | #define HFLIP_EN BIT(0) |
50 | #define VFLIP_EN BIT(1) |
51 | #define ROT_ENC_POS 2 |
52 | #define ROT_ENC_MASK GENMASK(3, 2) |
53 | #define ROT_FLIP_ORDER_EN BIT(4) |
54 | #define PITCH_POS 16 |
55 | #define PITCH_MASK GENMASK(31, 16) |
56 | #define DCSS_DPR_FRAME_1P_CTRL0 0x090 |
57 | #define DCSS_DPR_FRAME_1P_PIX_X_CTRL 0x0A0 |
58 | #define DCSS_DPR_FRAME_1P_PIX_Y_CTRL 0x0B0 |
59 | #define DCSS_DPR_FRAME_1P_BASE_ADDR 0x0C0 |
60 | #define DCSS_DPR_FRAME_2P_CTRL0 0x0E0 |
61 | #define DCSS_DPR_FRAME_2P_PIX_X_CTRL 0x0F0 |
62 | #define DCSS_DPR_FRAME_2P_PIX_Y_CTRL 0x100 |
63 | #define DCSS_DPR_FRAME_2P_BASE_ADDR 0x110 |
64 | #define DCSS_DPR_STATUS_CTRL0 0x130 |
65 | #define STATUS_MUX_SEL_MASK GENMASK(2, 0) |
66 | #define STATUS_SRC_SEL_POS 16 |
67 | #define STATUS_SRC_SEL_MASK GENMASK(18, 16) |
68 | #define DCSS_DPR_STATUS_CTRL1 0x140 |
69 | #define DCSS_DPR_RTRAM_CTRL0 0x200 |
70 | #define NUM_ROWS_ACTIVE BIT(0) |
71 | #define THRES_HIGH_POS 1 |
72 | #define THRES_HIGH_MASK GENMASK(3, 1) |
73 | #define THRES_LOW_POS 4 |
74 | #define THRES_LOW_MASK GENMASK(6, 4) |
75 | #define ABORT_SEL BIT(7) |
76 | |
77 | enum dcss_tile_type { |
78 | TILE_LINEAR = 0, |
79 | TILE_GPU_STANDARD, |
80 | TILE_GPU_SUPER, |
81 | TILE_VPU_YUV420, |
82 | TILE_VPU_VP9, |
83 | }; |
84 | |
85 | enum dcss_pix_size { |
86 | PIX_SIZE_8, |
87 | PIX_SIZE_16, |
88 | PIX_SIZE_32, |
89 | }; |
90 | |
91 | struct dcss_dpr_ch { |
92 | struct dcss_dpr *dpr; |
93 | void __iomem *base_reg; |
94 | u32 base_ofs; |
95 | |
96 | struct drm_format_info format; |
97 | enum dcss_pix_size pix_size; |
98 | enum dcss_tile_type tile; |
99 | bool rtram_4line_en; |
100 | bool rtram_3buf_en; |
101 | |
102 | u32 frame_ctrl; |
103 | u32 mode_ctrl; |
104 | u32 sys_ctrl; |
105 | u32 rtram_ctrl; |
106 | |
107 | bool sys_ctrl_chgd; |
108 | |
109 | int ch_num; |
110 | int irq; |
111 | }; |
112 | |
113 | struct dcss_dpr { |
114 | struct device *dev; |
115 | struct dcss_ctxld *ctxld; |
116 | u32 ctx_id; |
117 | |
118 | struct dcss_dpr_ch ch[3]; |
119 | }; |
120 | |
121 | static void dcss_dpr_write(struct dcss_dpr_ch *ch, u32 val, u32 ofs) |
122 | { |
123 | struct dcss_dpr *dpr = ch->dpr; |
124 | |
125 | dcss_ctxld_write(ctxld: dpr->ctxld, ctx_id: dpr->ctx_id, val, reg_idx: ch->base_ofs + ofs); |
126 | } |
127 | |
128 | static int dcss_dpr_ch_init_all(struct dcss_dpr *dpr, unsigned long dpr_base) |
129 | { |
130 | struct dcss_dpr_ch *ch; |
131 | int i; |
132 | |
133 | for (i = 0; i < 3; i++) { |
134 | ch = &dpr->ch[i]; |
135 | |
136 | ch->base_ofs = dpr_base + i * 0x1000; |
137 | |
138 | ch->base_reg = devm_ioremap(dev: dpr->dev, offset: ch->base_ofs, SZ_4K); |
139 | if (!ch->base_reg) { |
140 | dev_err(dpr->dev, "dpr: unable to remap ch %d base\n" , |
141 | i); |
142 | return -ENOMEM; |
143 | } |
144 | |
145 | ch->dpr = dpr; |
146 | ch->ch_num = i; |
147 | |
148 | dcss_writel(0xff, ch->base_reg + DCSS_DPR_IRQ_MASK); |
149 | } |
150 | |
151 | return 0; |
152 | } |
153 | |
154 | int dcss_dpr_init(struct dcss_dev *dcss, unsigned long dpr_base) |
155 | { |
156 | struct dcss_dpr *dpr; |
157 | |
158 | dpr = devm_kzalloc(dev: dcss->dev, size: sizeof(*dpr), GFP_KERNEL); |
159 | if (!dpr) |
160 | return -ENOMEM; |
161 | |
162 | dcss->dpr = dpr; |
163 | dpr->dev = dcss->dev; |
164 | dpr->ctxld = dcss->ctxld; |
165 | dpr->ctx_id = CTX_SB_HP; |
166 | |
167 | if (dcss_dpr_ch_init_all(dpr, dpr_base)) |
168 | return -ENOMEM; |
169 | |
170 | return 0; |
171 | } |
172 | |
173 | void dcss_dpr_exit(struct dcss_dpr *dpr) |
174 | { |
175 | int ch_no; |
176 | |
177 | /* stop DPR on all channels */ |
178 | for (ch_no = 0; ch_no < 3; ch_no++) { |
179 | struct dcss_dpr_ch *ch = &dpr->ch[ch_no]; |
180 | |
181 | dcss_writel(0, ch->base_reg + DCSS_DPR_SYSTEM_CTRL0); |
182 | } |
183 | } |
184 | |
185 | static u32 dcss_dpr_x_pix_wide_adjust(struct dcss_dpr_ch *ch, u32 pix_wide, |
186 | u32 pix_format) |
187 | { |
188 | u8 pix_in_64byte_map[3][5] = { |
189 | /* LIN, GPU_STD, GPU_SUP, VPU_YUV420, VPU_VP9 */ |
190 | { 64, 8, 8, 8, 16}, /* PIX_SIZE_8 */ |
191 | { 32, 8, 8, 8, 8}, /* PIX_SIZE_16 */ |
192 | { 16, 4, 4, 8, 8}, /* PIX_SIZE_32 */ |
193 | }; |
194 | u32 offset; |
195 | u32 div_64byte_mod, pix_in_64byte; |
196 | |
197 | pix_in_64byte = pix_in_64byte_map[ch->pix_size][ch->tile]; |
198 | |
199 | div_64byte_mod = pix_wide % pix_in_64byte; |
200 | offset = (div_64byte_mod == 0) ? 0 : (pix_in_64byte - div_64byte_mod); |
201 | |
202 | return pix_wide + offset; |
203 | } |
204 | |
205 | static u32 dcss_dpr_y_pix_high_adjust(struct dcss_dpr_ch *ch, u32 pix_high, |
206 | u32 pix_format) |
207 | { |
208 | u8 num_rows_buf = ch->rtram_4line_en ? 4 : 8; |
209 | u32 offset, pix_y_mod; |
210 | |
211 | pix_y_mod = pix_high % num_rows_buf; |
212 | offset = pix_y_mod ? (num_rows_buf - pix_y_mod) : 0; |
213 | |
214 | return pix_high + offset; |
215 | } |
216 | |
217 | void dcss_dpr_set_res(struct dcss_dpr *dpr, int ch_num, u32 xres, u32 yres) |
218 | { |
219 | struct dcss_dpr_ch *ch = &dpr->ch[ch_num]; |
220 | u32 pix_format = ch->format.format; |
221 | u32 gap = DCSS_DPR_FRAME_2P_BASE_ADDR - DCSS_DPR_FRAME_1P_BASE_ADDR; |
222 | int plane, max_planes = 1; |
223 | u32 pix_x_wide, pix_y_high; |
224 | |
225 | if (pix_format == DRM_FORMAT_NV12 || |
226 | pix_format == DRM_FORMAT_NV21) |
227 | max_planes = 2; |
228 | |
229 | for (plane = 0; plane < max_planes; plane++) { |
230 | yres = plane == 1 ? yres >> 1 : yres; |
231 | |
232 | pix_x_wide = dcss_dpr_x_pix_wide_adjust(ch, pix_wide: xres, pix_format); |
233 | pix_y_high = dcss_dpr_y_pix_high_adjust(ch, pix_high: yres, pix_format); |
234 | |
235 | dcss_dpr_write(ch, val: pix_x_wide, |
236 | DCSS_DPR_FRAME_1P_PIX_X_CTRL + plane * gap); |
237 | dcss_dpr_write(ch, val: pix_y_high, |
238 | DCSS_DPR_FRAME_1P_PIX_Y_CTRL + plane * gap); |
239 | |
240 | dcss_dpr_write(ch, val: 2, DCSS_DPR_FRAME_1P_CTRL0 + plane * gap); |
241 | } |
242 | } |
243 | |
244 | void dcss_dpr_addr_set(struct dcss_dpr *dpr, int ch_num, u32 luma_base_addr, |
245 | u32 chroma_base_addr, u16 pitch) |
246 | { |
247 | struct dcss_dpr_ch *ch = &dpr->ch[ch_num]; |
248 | |
249 | dcss_dpr_write(ch, val: luma_base_addr, DCSS_DPR_FRAME_1P_BASE_ADDR); |
250 | |
251 | dcss_dpr_write(ch, val: chroma_base_addr, DCSS_DPR_FRAME_2P_BASE_ADDR); |
252 | |
253 | ch->frame_ctrl &= ~PITCH_MASK; |
254 | ch->frame_ctrl |= (((u32)pitch << PITCH_POS) & PITCH_MASK); |
255 | } |
256 | |
257 | static void dcss_dpr_argb_comp_sel(struct dcss_dpr_ch *ch, int a_sel, int r_sel, |
258 | int g_sel, int b_sel) |
259 | { |
260 | u32 sel; |
261 | |
262 | sel = ((a_sel << A_COMP_SEL_POS) & A_COMP_SEL_MASK) | |
263 | ((r_sel << R_COMP_SEL_POS) & R_COMP_SEL_MASK) | |
264 | ((g_sel << G_COMP_SEL_POS) & G_COMP_SEL_MASK) | |
265 | ((b_sel << B_COMP_SEL_POS) & B_COMP_SEL_MASK); |
266 | |
267 | ch->mode_ctrl &= ~(A_COMP_SEL_MASK | R_COMP_SEL_MASK | |
268 | G_COMP_SEL_MASK | B_COMP_SEL_MASK); |
269 | ch->mode_ctrl |= sel; |
270 | } |
271 | |
272 | static void dcss_dpr_pix_size_set(struct dcss_dpr_ch *ch, |
273 | const struct drm_format_info *format) |
274 | { |
275 | u32 val; |
276 | |
277 | switch (format->format) { |
278 | case DRM_FORMAT_NV12: |
279 | case DRM_FORMAT_NV21: |
280 | val = PIX_SIZE_8; |
281 | break; |
282 | |
283 | case DRM_FORMAT_UYVY: |
284 | case DRM_FORMAT_VYUY: |
285 | case DRM_FORMAT_YUYV: |
286 | case DRM_FORMAT_YVYU: |
287 | val = PIX_SIZE_16; |
288 | break; |
289 | |
290 | default: |
291 | val = PIX_SIZE_32; |
292 | break; |
293 | } |
294 | |
295 | ch->pix_size = val; |
296 | |
297 | ch->mode_ctrl &= ~PIX_SIZE_MASK; |
298 | ch->mode_ctrl |= ((val << PIX_SIZE_POS) & PIX_SIZE_MASK); |
299 | } |
300 | |
301 | static void dcss_dpr_uv_swap(struct dcss_dpr_ch *ch, bool swap) |
302 | { |
303 | ch->mode_ctrl &= ~PIX_UV_SWAP; |
304 | ch->mode_ctrl |= (swap ? PIX_UV_SWAP : 0); |
305 | } |
306 | |
307 | static void dcss_dpr_y_uv_swap(struct dcss_dpr_ch *ch, bool swap) |
308 | { |
309 | ch->mode_ctrl &= ~PIX_LUMA_UV_SWAP; |
310 | ch->mode_ctrl |= (swap ? PIX_LUMA_UV_SWAP : 0); |
311 | } |
312 | |
313 | static void dcss_dpr_2plane_en(struct dcss_dpr_ch *ch, bool en) |
314 | { |
315 | ch->mode_ctrl &= ~COMP_2PLANE_EN; |
316 | ch->mode_ctrl |= (en ? COMP_2PLANE_EN : 0); |
317 | } |
318 | |
319 | static void dcss_dpr_yuv_en(struct dcss_dpr_ch *ch, bool en) |
320 | { |
321 | ch->mode_ctrl &= ~YUV_EN; |
322 | ch->mode_ctrl |= (en ? YUV_EN : 0); |
323 | } |
324 | |
325 | void dcss_dpr_enable(struct dcss_dpr *dpr, int ch_num, bool en) |
326 | { |
327 | struct dcss_dpr_ch *ch = &dpr->ch[ch_num]; |
328 | u32 sys_ctrl; |
329 | |
330 | sys_ctrl = (en ? REPEAT_EN | RUN_EN : 0); |
331 | |
332 | if (en) { |
333 | dcss_dpr_write(ch, val: ch->mode_ctrl, DCSS_DPR_MODE_CTRL0); |
334 | dcss_dpr_write(ch, val: ch->frame_ctrl, DCSS_DPR_FRAME_CTRL0); |
335 | dcss_dpr_write(ch, val: ch->rtram_ctrl, DCSS_DPR_RTRAM_CTRL0); |
336 | } |
337 | |
338 | if (ch->sys_ctrl != sys_ctrl) |
339 | ch->sys_ctrl_chgd = true; |
340 | |
341 | ch->sys_ctrl = sys_ctrl; |
342 | } |
343 | |
344 | struct rgb_comp_sel { |
345 | u32 drm_format; |
346 | int a_sel; |
347 | int r_sel; |
348 | int g_sel; |
349 | int b_sel; |
350 | }; |
351 | |
352 | static struct rgb_comp_sel comp_sel_map[] = { |
353 | {DRM_FORMAT_ARGB8888, 3, 2, 1, 0}, |
354 | {DRM_FORMAT_XRGB8888, 3, 2, 1, 0}, |
355 | {DRM_FORMAT_ABGR8888, 3, 0, 1, 2}, |
356 | {DRM_FORMAT_XBGR8888, 3, 0, 1, 2}, |
357 | {DRM_FORMAT_RGBA8888, 0, 3, 2, 1}, |
358 | {DRM_FORMAT_RGBX8888, 0, 3, 2, 1}, |
359 | {DRM_FORMAT_BGRA8888, 0, 1, 2, 3}, |
360 | {DRM_FORMAT_BGRX8888, 0, 1, 2, 3}, |
361 | }; |
362 | |
363 | static int to_comp_sel(u32 pix_fmt, int *a_sel, int *r_sel, int *g_sel, |
364 | int *b_sel) |
365 | { |
366 | int i; |
367 | |
368 | for (i = 0; i < ARRAY_SIZE(comp_sel_map); i++) { |
369 | if (comp_sel_map[i].drm_format == pix_fmt) { |
370 | *a_sel = comp_sel_map[i].a_sel; |
371 | *r_sel = comp_sel_map[i].r_sel; |
372 | *g_sel = comp_sel_map[i].g_sel; |
373 | *b_sel = comp_sel_map[i].b_sel; |
374 | |
375 | return 0; |
376 | } |
377 | } |
378 | |
379 | return -1; |
380 | } |
381 | |
382 | static void dcss_dpr_rtram_set(struct dcss_dpr_ch *ch, u32 pix_format) |
383 | { |
384 | u32 val, mask; |
385 | |
386 | switch (pix_format) { |
387 | case DRM_FORMAT_NV21: |
388 | case DRM_FORMAT_NV12: |
389 | ch->rtram_3buf_en = true; |
390 | ch->rtram_4line_en = false; |
391 | break; |
392 | |
393 | default: |
394 | ch->rtram_3buf_en = true; |
395 | ch->rtram_4line_en = true; |
396 | break; |
397 | } |
398 | |
399 | val = (ch->rtram_4line_en ? RTR_4LINE_BUF_EN : 0); |
400 | val |= (ch->rtram_3buf_en ? RTR_3BUF_EN : 0); |
401 | mask = RTR_4LINE_BUF_EN | RTR_3BUF_EN; |
402 | |
403 | ch->mode_ctrl &= ~mask; |
404 | ch->mode_ctrl |= (val & mask); |
405 | |
406 | val = (ch->rtram_4line_en ? 0 : NUM_ROWS_ACTIVE); |
407 | val |= (3 << THRES_LOW_POS) & THRES_LOW_MASK; |
408 | val |= (4 << THRES_HIGH_POS) & THRES_HIGH_MASK; |
409 | mask = THRES_LOW_MASK | THRES_HIGH_MASK | NUM_ROWS_ACTIVE; |
410 | |
411 | ch->rtram_ctrl &= ~mask; |
412 | ch->rtram_ctrl |= (val & mask); |
413 | } |
414 | |
415 | static void dcss_dpr_setup_components(struct dcss_dpr_ch *ch, |
416 | const struct drm_format_info *format) |
417 | { |
418 | int a_sel, r_sel, g_sel, b_sel; |
419 | bool uv_swap, y_uv_swap; |
420 | |
421 | switch (format->format) { |
422 | case DRM_FORMAT_YVYU: |
423 | uv_swap = true; |
424 | y_uv_swap = true; |
425 | break; |
426 | |
427 | case DRM_FORMAT_VYUY: |
428 | case DRM_FORMAT_NV21: |
429 | uv_swap = true; |
430 | y_uv_swap = false; |
431 | break; |
432 | |
433 | case DRM_FORMAT_YUYV: |
434 | uv_swap = false; |
435 | y_uv_swap = true; |
436 | break; |
437 | |
438 | default: |
439 | uv_swap = false; |
440 | y_uv_swap = false; |
441 | break; |
442 | } |
443 | |
444 | dcss_dpr_uv_swap(ch, swap: uv_swap); |
445 | |
446 | dcss_dpr_y_uv_swap(ch, swap: y_uv_swap); |
447 | |
448 | if (!format->is_yuv) { |
449 | if (!to_comp_sel(pix_fmt: format->format, a_sel: &a_sel, r_sel: &r_sel, |
450 | g_sel: &g_sel, b_sel: &b_sel)) { |
451 | dcss_dpr_argb_comp_sel(ch, a_sel, r_sel, g_sel, b_sel); |
452 | } else { |
453 | dcss_dpr_argb_comp_sel(ch, a_sel: 3, r_sel: 2, g_sel: 1, b_sel: 0); |
454 | } |
455 | } else { |
456 | dcss_dpr_argb_comp_sel(ch, a_sel: 0, r_sel: 0, g_sel: 0, b_sel: 0); |
457 | } |
458 | } |
459 | |
460 | static void dcss_dpr_tile_set(struct dcss_dpr_ch *ch, uint64_t modifier) |
461 | { |
462 | switch (ch->ch_num) { |
463 | case 0: |
464 | switch (modifier) { |
465 | case DRM_FORMAT_MOD_LINEAR: |
466 | ch->tile = TILE_LINEAR; |
467 | break; |
468 | case DRM_FORMAT_MOD_VIVANTE_TILED: |
469 | ch->tile = TILE_GPU_STANDARD; |
470 | break; |
471 | case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED: |
472 | ch->tile = TILE_GPU_SUPER; |
473 | break; |
474 | default: |
475 | WARN_ON(1); |
476 | break; |
477 | } |
478 | break; |
479 | case 1: |
480 | case 2: |
481 | ch->tile = TILE_LINEAR; |
482 | break; |
483 | default: |
484 | WARN_ON(1); |
485 | return; |
486 | } |
487 | |
488 | ch->mode_ctrl &= ~TILE_TYPE_MASK; |
489 | ch->mode_ctrl |= ((ch->tile << TILE_TYPE_POS) & TILE_TYPE_MASK); |
490 | } |
491 | |
492 | void dcss_dpr_format_set(struct dcss_dpr *dpr, int ch_num, |
493 | const struct drm_format_info *format, u64 modifier) |
494 | { |
495 | struct dcss_dpr_ch *ch = &dpr->ch[ch_num]; |
496 | |
497 | ch->format = *format; |
498 | |
499 | dcss_dpr_yuv_en(ch, en: format->is_yuv); |
500 | |
501 | dcss_dpr_pix_size_set(ch, format); |
502 | |
503 | dcss_dpr_setup_components(ch, format); |
504 | |
505 | dcss_dpr_2plane_en(ch, en: format->num_planes == 2); |
506 | |
507 | dcss_dpr_rtram_set(ch, pix_format: format->format); |
508 | |
509 | dcss_dpr_tile_set(ch, modifier); |
510 | } |
511 | |
512 | /* This function will be called from interrupt context. */ |
513 | void dcss_dpr_write_sysctrl(struct dcss_dpr *dpr) |
514 | { |
515 | int chnum; |
516 | |
517 | dcss_ctxld_assert_locked(ctxld: dpr->ctxld); |
518 | |
519 | for (chnum = 0; chnum < 3; chnum++) { |
520 | struct dcss_dpr_ch *ch = &dpr->ch[chnum]; |
521 | |
522 | if (ch->sys_ctrl_chgd) { |
523 | dcss_ctxld_write_irqsafe(ctlxd: dpr->ctxld, ctx_id: dpr->ctx_id, |
524 | val: ch->sys_ctrl, |
525 | reg_ofs: ch->base_ofs + |
526 | DCSS_DPR_SYSTEM_CTRL0); |
527 | ch->sys_ctrl_chgd = false; |
528 | } |
529 | } |
530 | } |
531 | |
532 | void dcss_dpr_set_rotation(struct dcss_dpr *dpr, int ch_num, u32 rotation) |
533 | { |
534 | struct dcss_dpr_ch *ch = &dpr->ch[ch_num]; |
535 | |
536 | ch->frame_ctrl &= ~(HFLIP_EN | VFLIP_EN | ROT_ENC_MASK); |
537 | |
538 | ch->frame_ctrl |= rotation & DRM_MODE_REFLECT_X ? HFLIP_EN : 0; |
539 | ch->frame_ctrl |= rotation & DRM_MODE_REFLECT_Y ? VFLIP_EN : 0; |
540 | |
541 | if (rotation & DRM_MODE_ROTATE_90) |
542 | ch->frame_ctrl |= 1 << ROT_ENC_POS; |
543 | else if (rotation & DRM_MODE_ROTATE_180) |
544 | ch->frame_ctrl |= 2 << ROT_ENC_POS; |
545 | else if (rotation & DRM_MODE_ROTATE_270) |
546 | ch->frame_ctrl |= 3 << ROT_ENC_POS; |
547 | } |
548 | |