2 * Copyright (C) 2012 Russell King
3 * Rewritten from the dovefb driver, and Armada510 manuals.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
10 #include <drm/drm_atomic.h>
11 #include <drm/drm_atomic_helper.h>
12 #include <drm/drm_plane_helper.h>
13 #include "armada_crtc.h"
14 #include "armada_drm.h"
15 #include "armada_fb.h"
16 #include "armada_gem.h"
17 #include "armada_hw.h"
18 #include "armada_plane.h"
19 #include "armada_trace.h"
21 static const uint32_t armada_primary_formats
[] = {
38 void armada_drm_plane_calc(struct drm_plane_state
*state
, u32 addrs
[2][3],
39 u16 pitches
[3], bool interlaced
)
41 struct drm_framebuffer
*fb
= state
->fb
;
42 const struct drm_format_info
*format
= fb
->format
;
43 unsigned int num_planes
= format
->num_planes
;
44 unsigned int x
= state
->src
.x1
>> 16;
45 unsigned int y
= state
->src
.y1
>> 16;
46 u32 addr
= drm_fb_obj(fb
)->dev_addr
;
49 DRM_DEBUG_KMS("pitch %u x %d y %d bpp %d\n",
50 fb
->pitches
[0], x
, y
, format
->cpp
[0] * 8);
55 addrs
[0][0] = addr
+ fb
->offsets
[0] + y
* fb
->pitches
[0] +
57 pitches
[0] = fb
->pitches
[0];
62 for (i
= 1; i
< num_planes
; i
++) {
63 addrs
[0][i
] = addr
+ fb
->offsets
[i
] + y
* fb
->pitches
[i
] +
65 pitches
[i
] = fb
->pitches
[i
];
72 for (i
= 0; i
< 3; i
++) {
73 addrs
[1][i
] = addrs
[0][i
] + pitches
[i
];
77 for (i
= 0; i
< 3; i
++)
78 addrs
[1][i
] = addrs
[0][i
];
82 static unsigned armada_drm_crtc_calc_fb(struct drm_plane_state
*state
,
83 struct armada_regs
*regs
, bool interlaced
)
89 armada_drm_plane_calc(state
, addrs
, pitches
, interlaced
);
91 /* write offset, base, and pitch */
92 armada_reg_queue_set(regs
, i
, addrs
[0][0], LCD_CFG_GRA_START_ADDR0
);
93 armada_reg_queue_set(regs
, i
, addrs
[1][0], LCD_CFG_GRA_START_ADDR1
);
94 armada_reg_queue_mod(regs
, i
, pitches
[0], 0xffff, LCD_CFG_GRA_PITCH
);
99 int armada_drm_plane_prepare_fb(struct drm_plane
*plane
,
100 struct drm_plane_state
*state
)
102 DRM_DEBUG_KMS("[PLANE:%d:%s] [FB:%d]\n",
103 plane
->base
.id
, plane
->name
,
104 state
->fb
? state
->fb
->base
.id
: 0);
107 * Take a reference on the new framebuffer - we want to
108 * hold on to it while the hardware is displaying it.
111 drm_framebuffer_get(state
->fb
);
115 void armada_drm_plane_cleanup_fb(struct drm_plane
*plane
,
116 struct drm_plane_state
*old_state
)
118 DRM_DEBUG_KMS("[PLANE:%d:%s] [FB:%d]\n",
119 plane
->base
.id
, plane
->name
,
120 old_state
->fb
? old_state
->fb
->base
.id
: 0);
123 drm_framebuffer_put(old_state
->fb
);
126 int armada_drm_plane_atomic_check(struct drm_plane
*plane
,
127 struct drm_plane_state
*state
)
129 if (state
->fb
&& !WARN_ON(!state
->crtc
)) {
130 struct drm_crtc
*crtc
= state
->crtc
;
131 struct drm_crtc_state
*crtc_state
;
134 crtc_state
= drm_atomic_get_existing_crtc_state(state
->state
, crtc
);
136 crtc_state
= crtc
->state
;
137 return drm_atomic_helper_check_plane_state(state
, crtc_state
,
141 state
->visible
= false;
146 static void armada_drm_primary_plane_atomic_update(struct drm_plane
*plane
,
147 struct drm_plane_state
*old_state
)
149 struct drm_plane_state
*state
= plane
->state
;
150 struct armada_crtc
*dcrtc
;
151 struct armada_regs
*regs
;
152 u32 cfg
, cfg_mask
, val
;
155 DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane
->base
.id
, plane
->name
);
157 if (!state
->fb
|| WARN_ON(!state
->crtc
))
160 DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n",
161 plane
->base
.id
, plane
->name
,
162 state
->crtc
->base
.id
, state
->crtc
->name
,
164 old_state
->visible
, state
->visible
);
166 dcrtc
= drm_to_armada_crtc(state
->crtc
);
167 regs
= dcrtc
->regs
+ dcrtc
->regs_idx
;
170 if (!old_state
->visible
&& state
->visible
) {
172 if (drm_fb_to_armada_fb(state
->fb
)->fmt
> CFG_420
)
173 val
|= CFG_PDWN256x24
;
174 armada_reg_queue_mod(regs
, idx
, 0, val
, LCD_SPU_SRAM_PARA1
);
176 val
= armada_rect_hw_fp(&state
->src
);
177 if (armada_rect_hw_fp(&old_state
->src
) != val
)
178 armada_reg_queue_set(regs
, idx
, val
, LCD_SPU_GRA_HPXL_VLN
);
179 val
= armada_rect_yx(&state
->dst
);
180 if (armada_rect_yx(&old_state
->dst
) != val
)
181 armada_reg_queue_set(regs
, idx
, val
, LCD_SPU_GRA_OVSA_HPXL_VLN
);
182 val
= armada_rect_hw(&state
->dst
);
183 if (armada_rect_hw(&old_state
->dst
) != val
)
184 armada_reg_queue_set(regs
, idx
, val
, LCD_SPU_GZM_HPXL_VLN
);
185 if (old_state
->src
.x1
!= state
->src
.x1
||
186 old_state
->src
.y1
!= state
->src
.y1
||
187 old_state
->fb
!= state
->fb
||
188 state
->crtc
->state
->mode_changed
) {
189 idx
+= armada_drm_crtc_calc_fb(state
, regs
+ idx
,
192 if (old_state
->fb
!= state
->fb
||
193 state
->crtc
->state
->mode_changed
) {
194 cfg
= CFG_GRA_FMT(drm_fb_to_armada_fb(state
->fb
)->fmt
) |
195 CFG_GRA_MOD(drm_fb_to_armada_fb(state
->fb
)->mod
);
196 if (drm_fb_to_armada_fb(state
->fb
)->fmt
> CFG_420
)
197 cfg
|= CFG_PALETTE_ENA
;
200 if (dcrtc
->interlaced
)
201 cfg
|= CFG_GRA_FTOGGLE
;
202 cfg_mask
= CFG_GRAFORMAT
|
203 CFG_GRA_MOD(CFG_SWAPRB
| CFG_SWAPUV
|
204 CFG_SWAPYU
| CFG_YUV2RGB
) |
205 CFG_PALETTE_ENA
| CFG_GRA_FTOGGLE
|
207 } else if (old_state
->visible
!= state
->visible
) {
208 cfg
= state
->visible
? CFG_GRA_ENA
: 0;
209 cfg_mask
= CFG_GRA_ENA
;
213 if (drm_rect_width(&old_state
->src
) != drm_rect_width(&state
->src
) ||
214 drm_rect_width(&old_state
->dst
) != drm_rect_width(&state
->dst
)) {
215 cfg_mask
|= CFG_GRA_HSMOOTH
;
216 if (drm_rect_width(&state
->src
) >> 16 !=
217 drm_rect_width(&state
->dst
))
218 cfg
|= CFG_GRA_HSMOOTH
;
222 armada_reg_queue_mod(regs
, idx
, cfg
, cfg_mask
,
225 dcrtc
->regs_idx
+= idx
;
228 static void armada_drm_primary_plane_atomic_disable(struct drm_plane
*plane
,
229 struct drm_plane_state
*old_state
)
231 struct armada_crtc
*dcrtc
;
232 struct armada_regs
*regs
;
233 unsigned int idx
= 0;
235 DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane
->base
.id
, plane
->name
);
237 if (!old_state
->crtc
)
240 DRM_DEBUG_KMS("[PLANE:%d:%s] was on [CRTC:%d:%s] with [FB:%d]\n",
241 plane
->base
.id
, plane
->name
,
242 old_state
->crtc
->base
.id
, old_state
->crtc
->name
,
243 old_state
->fb
->base
.id
);
245 dcrtc
= drm_to_armada_crtc(old_state
->crtc
);
246 regs
= dcrtc
->regs
+ dcrtc
->regs_idx
;
248 /* Disable plane and power down most RAMs and FIFOs */
249 armada_reg_queue_mod(regs
, idx
, 0, CFG_GRA_ENA
, LCD_SPU_DMA_CTRL0
);
250 armada_reg_queue_mod(regs
, idx
, CFG_PDWN256x32
| CFG_PDWN256x24
|
251 CFG_PDWN256x8
| CFG_PDWN32x32
| CFG_PDWN64x66
,
252 0, LCD_SPU_SRAM_PARA1
);
254 dcrtc
->regs_idx
+= idx
;
257 static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs
= {
258 .prepare_fb
= armada_drm_plane_prepare_fb
,
259 .cleanup_fb
= armada_drm_plane_cleanup_fb
,
260 .atomic_check
= armada_drm_plane_atomic_check
,
261 .atomic_update
= armada_drm_primary_plane_atomic_update
,
262 .atomic_disable
= armada_drm_primary_plane_atomic_disable
,
265 static const struct drm_plane_funcs armada_primary_plane_funcs
= {
266 .update_plane
= drm_atomic_helper_update_plane
,
267 .disable_plane
= drm_atomic_helper_disable_plane
,
268 .destroy
= drm_primary_helper_destroy
,
269 .reset
= drm_atomic_helper_plane_reset
,
270 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
271 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
274 int armada_drm_primary_plane_init(struct drm_device
*drm
,
275 struct drm_plane
*primary
)
279 drm_plane_helper_add(primary
, &armada_primary_plane_helper_funcs
);
281 ret
= drm_universal_plane_init(drm
, primary
, 0,
282 &armada_primary_plane_funcs
,
283 armada_primary_formats
,
284 ARRAY_SIZE(armada_primary_formats
),
286 DRM_PLANE_TYPE_PRIMARY
, NULL
);