1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2012 Russell King
4 * Rewritten from the dovefb driver, and Armada510 manuals.
7 #include <drm/drm_atomic.h>
8 #include <drm/drm_atomic_helper.h>
9 #include <drm/drm_fourcc.h>
10 #include <drm/drm_plane_helper.h>
12 #include "armada_crtc.h"
13 #include "armada_drm.h"
14 #include "armada_fb.h"
15 #include "armada_gem.h"
16 #include "armada_hw.h"
17 #include "armada_plane.h"
18 #include "armada_trace.h"
20 static const uint32_t armada_primary_formats
[] = {
37 void armada_drm_plane_calc(struct drm_plane_state
*state
, u32 addrs
[2][3],
38 u16 pitches
[3], bool interlaced
)
40 struct drm_framebuffer
*fb
= state
->fb
;
41 const struct drm_format_info
*format
= fb
->format
;
42 unsigned int num_planes
= format
->num_planes
;
43 unsigned int x
= state
->src
.x1
>> 16;
44 unsigned int y
= state
->src
.y1
>> 16;
45 u32 addr
= drm_fb_obj(fb
)->dev_addr
;
48 DRM_DEBUG_KMS("pitch %u x %d y %d bpp %d\n",
49 fb
->pitches
[0], x
, y
, format
->cpp
[0] * 8);
54 addrs
[0][0] = addr
+ fb
->offsets
[0] + y
* fb
->pitches
[0] +
56 pitches
[0] = fb
->pitches
[0];
61 for (i
= 1; i
< num_planes
; i
++) {
62 addrs
[0][i
] = addr
+ fb
->offsets
[i
] + y
* fb
->pitches
[i
] +
64 pitches
[i
] = fb
->pitches
[i
];
71 for (i
= 0; i
< 3; i
++) {
72 addrs
[1][i
] = addrs
[0][i
] + pitches
[i
];
76 for (i
= 0; i
< 3; i
++)
77 addrs
[1][i
] = addrs
[0][i
];
81 int armada_drm_plane_prepare_fb(struct drm_plane
*plane
,
82 struct drm_plane_state
*state
)
84 DRM_DEBUG_KMS("[PLANE:%d:%s] [FB:%d]\n",
85 plane
->base
.id
, plane
->name
,
86 state
->fb
? state
->fb
->base
.id
: 0);
89 * Take a reference on the new framebuffer - we want to
90 * hold on to it while the hardware is displaying it.
93 drm_framebuffer_get(state
->fb
);
97 void armada_drm_plane_cleanup_fb(struct drm_plane
*plane
,
98 struct drm_plane_state
*old_state
)
100 DRM_DEBUG_KMS("[PLANE:%d:%s] [FB:%d]\n",
101 plane
->base
.id
, plane
->name
,
102 old_state
->fb
? old_state
->fb
->base
.id
: 0);
105 drm_framebuffer_put(old_state
->fb
);
108 int armada_drm_plane_atomic_check(struct drm_plane
*plane
,
109 struct drm_plane_state
*state
)
111 struct armada_plane_state
*st
= to_armada_plane_state(state
);
112 struct drm_crtc
*crtc
= state
->crtc
;
113 struct drm_crtc_state
*crtc_state
;
117 if (!state
->fb
|| WARN_ON(!state
->crtc
)) {
118 state
->visible
= false;
123 crtc_state
= drm_atomic_get_existing_crtc_state(state
->state
, crtc
);
125 crtc_state
= crtc
->state
;
127 ret
= drm_atomic_helper_check_plane_state(state
, crtc_state
, 0,
128 INT_MAX
, true, false);
132 interlace
= crtc_state
->adjusted_mode
.flags
& DRM_MODE_FLAG_INTERLACE
;
134 if ((state
->dst
.y1
| state
->dst
.y2
) & 1)
136 st
->src_hw
= drm_rect_height(&state
->src
) >> 17;
137 st
->dst_yx
= state
->dst
.y1
>> 1;
138 st
->dst_hw
= drm_rect_height(&state
->dst
) >> 1;
140 st
->src_hw
= drm_rect_height(&state
->src
) >> 16;
141 st
->dst_yx
= state
->dst
.y1
;
142 st
->dst_hw
= drm_rect_height(&state
->dst
);
146 st
->src_hw
|= drm_rect_width(&state
->src
) >> 16;
148 st
->dst_yx
|= state
->dst
.x1
& 0x0000ffff;
150 st
->dst_hw
|= drm_rect_width(&state
->dst
) & 0x0000ffff;
152 armada_drm_plane_calc(state
, st
->addrs
, st
->pitches
, interlace
);
153 st
->interlace
= interlace
;
158 static void armada_drm_primary_plane_atomic_update(struct drm_plane
*plane
,
159 struct drm_plane_state
*old_state
)
161 struct drm_plane_state
*state
= plane
->state
;
162 struct armada_crtc
*dcrtc
;
163 struct armada_regs
*regs
;
164 u32 cfg
, cfg_mask
, val
;
167 DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane
->base
.id
, plane
->name
);
169 if (!state
->fb
|| WARN_ON(!state
->crtc
))
172 DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n",
173 plane
->base
.id
, plane
->name
,
174 state
->crtc
->base
.id
, state
->crtc
->name
,
176 old_state
->visible
, state
->visible
);
178 dcrtc
= drm_to_armada_crtc(state
->crtc
);
179 regs
= dcrtc
->regs
+ dcrtc
->regs_idx
;
182 if (!old_state
->visible
&& state
->visible
) {
184 if (drm_fb_to_armada_fb(state
->fb
)->fmt
> CFG_420
)
185 val
|= CFG_PDWN256x24
;
186 armada_reg_queue_mod(regs
, idx
, 0, val
, LCD_SPU_SRAM_PARA1
);
188 val
= armada_src_hw(state
);
189 if (armada_src_hw(old_state
) != val
)
190 armada_reg_queue_set(regs
, idx
, val
, LCD_SPU_GRA_HPXL_VLN
);
191 val
= armada_dst_yx(state
);
192 if (armada_dst_yx(old_state
) != val
)
193 armada_reg_queue_set(regs
, idx
, val
, LCD_SPU_GRA_OVSA_HPXL_VLN
);
194 val
= armada_dst_hw(state
);
195 if (armada_dst_hw(old_state
) != val
)
196 armada_reg_queue_set(regs
, idx
, val
, LCD_SPU_GZM_HPXL_VLN
);
197 if (old_state
->src
.x1
!= state
->src
.x1
||
198 old_state
->src
.y1
!= state
->src
.y1
||
199 old_state
->fb
!= state
->fb
||
200 state
->crtc
->state
->mode_changed
) {
201 armada_reg_queue_set(regs
, idx
, armada_addr(state
, 0, 0),
202 LCD_CFG_GRA_START_ADDR0
);
203 armada_reg_queue_set(regs
, idx
, armada_addr(state
, 1, 0),
204 LCD_CFG_GRA_START_ADDR1
);
205 armada_reg_queue_mod(regs
, idx
, armada_pitch(state
, 0), 0xffff,
208 if (old_state
->fb
!= state
->fb
||
209 state
->crtc
->state
->mode_changed
) {
210 cfg
= CFG_GRA_FMT(drm_fb_to_armada_fb(state
->fb
)->fmt
) |
211 CFG_GRA_MOD(drm_fb_to_armada_fb(state
->fb
)->mod
);
212 if (drm_fb_to_armada_fb(state
->fb
)->fmt
> CFG_420
)
213 cfg
|= CFG_PALETTE_ENA
;
216 if (to_armada_plane_state(state
)->interlace
)
217 cfg
|= CFG_GRA_FTOGGLE
;
218 cfg_mask
= CFG_GRAFORMAT
|
219 CFG_GRA_MOD(CFG_SWAPRB
| CFG_SWAPUV
|
220 CFG_SWAPYU
| CFG_YUV2RGB
) |
221 CFG_PALETTE_ENA
| CFG_GRA_FTOGGLE
|
223 } else if (old_state
->visible
!= state
->visible
) {
224 cfg
= state
->visible
? CFG_GRA_ENA
: 0;
225 cfg_mask
= CFG_GRA_ENA
;
229 if (drm_rect_width(&old_state
->src
) != drm_rect_width(&state
->src
) ||
230 drm_rect_width(&old_state
->dst
) != drm_rect_width(&state
->dst
)) {
231 cfg_mask
|= CFG_GRA_HSMOOTH
;
232 if (drm_rect_width(&state
->src
) >> 16 !=
233 drm_rect_width(&state
->dst
))
234 cfg
|= CFG_GRA_HSMOOTH
;
238 armada_reg_queue_mod(regs
, idx
, cfg
, cfg_mask
,
241 dcrtc
->regs_idx
+= idx
;
244 static void armada_drm_primary_plane_atomic_disable(struct drm_plane
*plane
,
245 struct drm_plane_state
*old_state
)
247 struct armada_crtc
*dcrtc
;
248 struct armada_regs
*regs
;
249 unsigned int idx
= 0;
251 DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane
->base
.id
, plane
->name
);
253 if (!old_state
->crtc
)
256 DRM_DEBUG_KMS("[PLANE:%d:%s] was on [CRTC:%d:%s] with [FB:%d]\n",
257 plane
->base
.id
, plane
->name
,
258 old_state
->crtc
->base
.id
, old_state
->crtc
->name
,
259 old_state
->fb
->base
.id
);
261 dcrtc
= drm_to_armada_crtc(old_state
->crtc
);
262 regs
= dcrtc
->regs
+ dcrtc
->regs_idx
;
264 /* Disable plane and power down most RAMs and FIFOs */
265 armada_reg_queue_mod(regs
, idx
, 0, CFG_GRA_ENA
, LCD_SPU_DMA_CTRL0
);
266 armada_reg_queue_mod(regs
, idx
, CFG_PDWN256x32
| CFG_PDWN256x24
|
267 CFG_PDWN32x32
| CFG_PDWN64x66
,
268 0, LCD_SPU_SRAM_PARA1
);
270 dcrtc
->regs_idx
+= idx
;
273 static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs
= {
274 .prepare_fb
= armada_drm_plane_prepare_fb
,
275 .cleanup_fb
= armada_drm_plane_cleanup_fb
,
276 .atomic_check
= armada_drm_plane_atomic_check
,
277 .atomic_update
= armada_drm_primary_plane_atomic_update
,
278 .atomic_disable
= armada_drm_primary_plane_atomic_disable
,
281 void armada_plane_reset(struct drm_plane
*plane
)
283 struct armada_plane_state
*st
;
285 __drm_atomic_helper_plane_destroy_state(plane
->state
);
287 st
= kzalloc(sizeof(*st
), GFP_KERNEL
);
289 __drm_atomic_helper_plane_reset(plane
, &st
->base
);
292 struct drm_plane_state
*armada_plane_duplicate_state(struct drm_plane
*plane
)
294 struct armada_plane_state
*st
;
296 if (WARN_ON(!plane
->state
))
299 st
= kmemdup(plane
->state
, sizeof(*st
), GFP_KERNEL
);
301 __drm_atomic_helper_plane_duplicate_state(plane
, &st
->base
);
306 static const struct drm_plane_funcs armada_primary_plane_funcs
= {
307 .update_plane
= drm_atomic_helper_update_plane
,
308 .disable_plane
= drm_atomic_helper_disable_plane
,
309 .destroy
= drm_primary_helper_destroy
,
310 .reset
= armada_plane_reset
,
311 .atomic_duplicate_state
= armada_plane_duplicate_state
,
312 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
315 int armada_drm_primary_plane_init(struct drm_device
*drm
,
316 struct drm_plane
*primary
)
320 drm_plane_helper_add(primary
, &armada_primary_plane_helper_funcs
);
322 ret
= drm_universal_plane_init(drm
, primary
, 0,
323 &armada_primary_plane_funcs
,
324 armada_primary_formats
,
325 ARRAY_SIZE(armada_primary_formats
),
327 DRM_PLANE_TYPE_PRIMARY
, NULL
);