0001
0002
0003
0004
0005
0006
0007 #include <drm/drm_atomic.h>
0008 #include <drm/drm_atomic_helper.h>
0009 #include <drm/drm_fourcc.h>
0010 #include <drm/drm_plane_helper.h>
0011
0012 #include "armada_crtc.h"
0013 #include "armada_drm.h"
0014 #include "armada_fb.h"
0015 #include "armada_gem.h"
0016 #include "armada_hw.h"
0017 #include "armada_plane.h"
0018 #include "armada_trace.h"
0019
0020 static const uint32_t armada_primary_formats[] = {
0021 DRM_FORMAT_UYVY,
0022 DRM_FORMAT_YUYV,
0023 DRM_FORMAT_VYUY,
0024 DRM_FORMAT_YVYU,
0025 DRM_FORMAT_ARGB8888,
0026 DRM_FORMAT_ABGR8888,
0027 DRM_FORMAT_XRGB8888,
0028 DRM_FORMAT_XBGR8888,
0029 DRM_FORMAT_RGB888,
0030 DRM_FORMAT_BGR888,
0031 DRM_FORMAT_ARGB1555,
0032 DRM_FORMAT_ABGR1555,
0033 DRM_FORMAT_RGB565,
0034 DRM_FORMAT_BGR565,
0035 };
0036
0037 void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3],
0038 u16 pitches[3], bool interlaced)
0039 {
0040 struct drm_framebuffer *fb = state->fb;
0041 const struct drm_format_info *format = fb->format;
0042 unsigned int num_planes = format->num_planes;
0043 unsigned int x = state->src.x1 >> 16;
0044 unsigned int y = state->src.y1 >> 16;
0045 u32 addr = drm_fb_obj(fb)->dev_addr;
0046 int i;
0047
0048 DRM_DEBUG_KMS("pitch %u x %d y %d bpp %d\n",
0049 fb->pitches[0], x, y, format->cpp[0] * 8);
0050
0051 if (num_planes > 3)
0052 num_planes = 3;
0053
0054 addrs[0][0] = addr + fb->offsets[0] + y * fb->pitches[0] +
0055 x * format->cpp[0];
0056 pitches[0] = fb->pitches[0];
0057
0058 y /= format->vsub;
0059 x /= format->hsub;
0060
0061 for (i = 1; i < num_planes; i++) {
0062 addrs[0][i] = addr + fb->offsets[i] + y * fb->pitches[i] +
0063 x * format->cpp[i];
0064 pitches[i] = fb->pitches[i];
0065 }
0066 for (; i < 3; i++) {
0067 addrs[0][i] = 0;
0068 pitches[i] = 0;
0069 }
0070 if (interlaced) {
0071 for (i = 0; i < 3; i++) {
0072 addrs[1][i] = addrs[0][i] + pitches[i];
0073 pitches[i] *= 2;
0074 }
0075 } else {
0076 for (i = 0; i < 3; i++)
0077 addrs[1][i] = addrs[0][i];
0078 }
0079 }
0080
0081 int armada_drm_plane_atomic_check(struct drm_plane *plane,
0082 struct drm_atomic_state *state)
0083 {
0084 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
0085 plane);
0086 struct armada_plane_state *st = to_armada_plane_state(new_plane_state);
0087 struct drm_crtc *crtc = new_plane_state->crtc;
0088 struct drm_crtc_state *crtc_state;
0089 bool interlace;
0090 int ret;
0091
0092 if (!new_plane_state->fb || WARN_ON(!new_plane_state->crtc)) {
0093 new_plane_state->visible = false;
0094 return 0;
0095 }
0096
0097 if (state)
0098 crtc_state = drm_atomic_get_existing_crtc_state(state,
0099 crtc);
0100 else
0101 crtc_state = crtc->state;
0102
0103 ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
0104 0,
0105 INT_MAX, true, false);
0106 if (ret)
0107 return ret;
0108
0109 interlace = crtc_state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE;
0110 if (interlace) {
0111 if ((new_plane_state->dst.y1 | new_plane_state->dst.y2) & 1)
0112 return -EINVAL;
0113 st->src_hw = drm_rect_height(&new_plane_state->src) >> 17;
0114 st->dst_yx = new_plane_state->dst.y1 >> 1;
0115 st->dst_hw = drm_rect_height(&new_plane_state->dst) >> 1;
0116 } else {
0117 st->src_hw = drm_rect_height(&new_plane_state->src) >> 16;
0118 st->dst_yx = new_plane_state->dst.y1;
0119 st->dst_hw = drm_rect_height(&new_plane_state->dst);
0120 }
0121
0122 st->src_hw <<= 16;
0123 st->src_hw |= drm_rect_width(&new_plane_state->src) >> 16;
0124 st->dst_yx <<= 16;
0125 st->dst_yx |= new_plane_state->dst.x1 & 0x0000ffff;
0126 st->dst_hw <<= 16;
0127 st->dst_hw |= drm_rect_width(&new_plane_state->dst) & 0x0000ffff;
0128
0129 armada_drm_plane_calc(new_plane_state, st->addrs, st->pitches,
0130 interlace);
0131 st->interlace = interlace;
0132
0133 return 0;
0134 }
0135
0136 static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane,
0137 struct drm_atomic_state *state)
0138 {
0139 struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
0140 plane);
0141 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
0142 plane);
0143 struct armada_crtc *dcrtc;
0144 struct armada_regs *regs;
0145 u32 cfg, cfg_mask, val;
0146 unsigned int idx;
0147
0148 DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);
0149
0150 if (!new_state->fb || WARN_ON(!new_state->crtc))
0151 return;
0152
0153 DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n",
0154 plane->base.id, plane->name,
0155 new_state->crtc->base.id, new_state->crtc->name,
0156 new_state->fb->base.id,
0157 old_state->visible, new_state->visible);
0158
0159 dcrtc = drm_to_armada_crtc(new_state->crtc);
0160 regs = dcrtc->regs + dcrtc->regs_idx;
0161
0162 idx = 0;
0163 if (!old_state->visible && new_state->visible) {
0164 val = CFG_PDWN64x66;
0165 if (drm_fb_to_armada_fb(new_state->fb)->fmt > CFG_420)
0166 val |= CFG_PDWN256x24;
0167 armada_reg_queue_mod(regs, idx, 0, val, LCD_SPU_SRAM_PARA1);
0168 }
0169 val = armada_src_hw(new_state);
0170 if (armada_src_hw(old_state) != val)
0171 armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_HPXL_VLN);
0172 val = armada_dst_yx(new_state);
0173 if (armada_dst_yx(old_state) != val)
0174 armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_OVSA_HPXL_VLN);
0175 val = armada_dst_hw(new_state);
0176 if (armada_dst_hw(old_state) != val)
0177 armada_reg_queue_set(regs, idx, val, LCD_SPU_GZM_HPXL_VLN);
0178 if (old_state->src.x1 != new_state->src.x1 ||
0179 old_state->src.y1 != new_state->src.y1 ||
0180 old_state->fb != new_state->fb ||
0181 new_state->crtc->state->mode_changed) {
0182 armada_reg_queue_set(regs, idx, armada_addr(new_state, 0, 0),
0183 LCD_CFG_GRA_START_ADDR0);
0184 armada_reg_queue_set(regs, idx, armada_addr(new_state, 1, 0),
0185 LCD_CFG_GRA_START_ADDR1);
0186 armada_reg_queue_mod(regs, idx, armada_pitch(new_state, 0),
0187 0xffff,
0188 LCD_CFG_GRA_PITCH);
0189 }
0190 if (old_state->fb != new_state->fb ||
0191 new_state->crtc->state->mode_changed) {
0192 cfg = CFG_GRA_FMT(drm_fb_to_armada_fb(new_state->fb)->fmt) |
0193 CFG_GRA_MOD(drm_fb_to_armada_fb(new_state->fb)->mod);
0194 if (drm_fb_to_armada_fb(new_state->fb)->fmt > CFG_420)
0195 cfg |= CFG_PALETTE_ENA;
0196 if (new_state->visible)
0197 cfg |= CFG_GRA_ENA;
0198 if (to_armada_plane_state(new_state)->interlace)
0199 cfg |= CFG_GRA_FTOGGLE;
0200 cfg_mask = CFG_GRAFORMAT |
0201 CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV |
0202 CFG_SWAPYU | CFG_YUV2RGB) |
0203 CFG_PALETTE_ENA | CFG_GRA_FTOGGLE |
0204 CFG_GRA_ENA;
0205 } else if (old_state->visible != new_state->visible) {
0206 cfg = new_state->visible ? CFG_GRA_ENA : 0;
0207 cfg_mask = CFG_GRA_ENA;
0208 } else {
0209 cfg = cfg_mask = 0;
0210 }
0211 if (drm_rect_width(&old_state->src) != drm_rect_width(&new_state->src) ||
0212 drm_rect_width(&old_state->dst) != drm_rect_width(&new_state->dst)) {
0213 cfg_mask |= CFG_GRA_HSMOOTH;
0214 if (drm_rect_width(&new_state->src) >> 16 !=
0215 drm_rect_width(&new_state->dst))
0216 cfg |= CFG_GRA_HSMOOTH;
0217 }
0218
0219 if (cfg_mask)
0220 armada_reg_queue_mod(regs, idx, cfg, cfg_mask,
0221 LCD_SPU_DMA_CTRL0);
0222
0223 dcrtc->regs_idx += idx;
0224 }
0225
0226 static void armada_drm_primary_plane_atomic_disable(struct drm_plane *plane,
0227 struct drm_atomic_state *state)
0228 {
0229 struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
0230 plane);
0231 struct armada_crtc *dcrtc;
0232 struct armada_regs *regs;
0233 unsigned int idx = 0;
0234
0235 DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);
0236
0237 if (!old_state->crtc)
0238 return;
0239
0240 DRM_DEBUG_KMS("[PLANE:%d:%s] was on [CRTC:%d:%s] with [FB:%d]\n",
0241 plane->base.id, plane->name,
0242 old_state->crtc->base.id, old_state->crtc->name,
0243 old_state->fb->base.id);
0244
0245 dcrtc = drm_to_armada_crtc(old_state->crtc);
0246 regs = dcrtc->regs + dcrtc->regs_idx;
0247
0248
0249 armada_reg_queue_mod(regs, idx, 0, CFG_GRA_ENA, LCD_SPU_DMA_CTRL0);
0250 armada_reg_queue_mod(regs, idx, CFG_PDWN256x32 | CFG_PDWN256x24 |
0251 CFG_PDWN32x32 | CFG_PDWN64x66,
0252 0, LCD_SPU_SRAM_PARA1);
0253
0254 dcrtc->regs_idx += idx;
0255 }
0256
0257 static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs = {
0258 .atomic_check = armada_drm_plane_atomic_check,
0259 .atomic_update = armada_drm_primary_plane_atomic_update,
0260 .atomic_disable = armada_drm_primary_plane_atomic_disable,
0261 };
0262
0263 void armada_plane_reset(struct drm_plane *plane)
0264 {
0265 struct armada_plane_state *st;
0266 if (plane->state)
0267 __drm_atomic_helper_plane_destroy_state(plane->state);
0268 kfree(plane->state);
0269 st = kzalloc(sizeof(*st), GFP_KERNEL);
0270 if (st)
0271 __drm_atomic_helper_plane_reset(plane, &st->base);
0272 }
0273
0274 struct drm_plane_state *armada_plane_duplicate_state(struct drm_plane *plane)
0275 {
0276 struct armada_plane_state *st;
0277
0278 if (WARN_ON(!plane->state))
0279 return NULL;
0280
0281 st = kmemdup(plane->state, sizeof(*st), GFP_KERNEL);
0282 if (st)
0283 __drm_atomic_helper_plane_duplicate_state(plane, &st->base);
0284
0285 return &st->base;
0286 }
0287
0288 static const struct drm_plane_funcs armada_primary_plane_funcs = {
0289 .update_plane = drm_atomic_helper_update_plane,
0290 .disable_plane = drm_atomic_helper_disable_plane,
0291 .destroy = drm_primary_helper_destroy,
0292 .reset = armada_plane_reset,
0293 .atomic_duplicate_state = armada_plane_duplicate_state,
0294 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
0295 };
0296
0297 int armada_drm_primary_plane_init(struct drm_device *drm,
0298 struct drm_plane *primary)
0299 {
0300 int ret;
0301
0302 drm_plane_helper_add(primary, &armada_primary_plane_helper_funcs);
0303
0304 ret = drm_universal_plane_init(drm, primary, 0,
0305 &armada_primary_plane_funcs,
0306 armada_primary_formats,
0307 ARRAY_SIZE(armada_primary_formats),
0308 NULL,
0309 DRM_PLANE_TYPE_PRIMARY, NULL);
0310
0311 return ret;
0312 }