Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2012 Russell King
0004  *  Rewritten from the dovefb driver, and Armada510 manuals.
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     /* Disable plane and power down most RAMs and FIFOs */
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 }