0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <drm/drm_crtc.h>
0011 #include <drm/drm_crtc_helper.h>
0012 #include <drm/drm_fb_cma_helper.h>
0013 #include <drm/drm_fourcc.h>
0014 #include <drm/drm_framebuffer.h>
0015 #include <drm/drm_gem_cma_helper.h>
0016
0017 #include "shmob_drm_drv.h"
0018 #include "shmob_drm_kms.h"
0019 #include "shmob_drm_plane.h"
0020 #include "shmob_drm_regs.h"
0021
0022 struct shmob_drm_plane {
0023 struct drm_plane plane;
0024 unsigned int index;
0025 unsigned int alpha;
0026
0027 const struct shmob_drm_format_info *format;
0028 unsigned long dma[2];
0029
0030 unsigned int src_x;
0031 unsigned int src_y;
0032 unsigned int crtc_x;
0033 unsigned int crtc_y;
0034 unsigned int crtc_w;
0035 unsigned int crtc_h;
0036 };
0037
0038 #define to_shmob_plane(p) container_of(p, struct shmob_drm_plane, plane)
0039
0040 static void shmob_drm_plane_compute_base(struct shmob_drm_plane *splane,
0041 struct drm_framebuffer *fb,
0042 int x, int y)
0043 {
0044 struct drm_gem_cma_object *gem;
0045 unsigned int bpp;
0046
0047 bpp = splane->format->yuv ? 8 : splane->format->bpp;
0048 gem = drm_fb_cma_get_gem_obj(fb, 0);
0049 splane->dma[0] = gem->paddr + fb->offsets[0]
0050 + y * fb->pitches[0] + x * bpp / 8;
0051
0052 if (splane->format->yuv) {
0053 bpp = splane->format->bpp - 8;
0054 gem = drm_fb_cma_get_gem_obj(fb, 1);
0055 splane->dma[1] = gem->paddr + fb->offsets[1]
0056 + y / (bpp == 4 ? 2 : 1) * fb->pitches[1]
0057 + x * (bpp == 16 ? 2 : 1);
0058 }
0059 }
0060
0061 static void __shmob_drm_plane_setup(struct shmob_drm_plane *splane,
0062 struct drm_framebuffer *fb)
0063 {
0064 struct shmob_drm_device *sdev = splane->plane.dev->dev_private;
0065 u32 format;
0066
0067
0068 format = LDBBSIFR_EN | (splane->alpha << LDBBSIFR_LAY_SHIFT);
0069
0070 switch (splane->format->fourcc) {
0071 case DRM_FORMAT_RGB565:
0072 case DRM_FORMAT_NV21:
0073 case DRM_FORMAT_NV61:
0074 case DRM_FORMAT_NV42:
0075 format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW;
0076 break;
0077 case DRM_FORMAT_RGB888:
0078 case DRM_FORMAT_NV12:
0079 case DRM_FORMAT_NV16:
0080 case DRM_FORMAT_NV24:
0081 format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW | LDBBSIFR_SWPB;
0082 break;
0083 case DRM_FORMAT_ARGB8888:
0084 default:
0085 format |= LDBBSIFR_SWPL;
0086 break;
0087 }
0088
0089 switch (splane->format->fourcc) {
0090 case DRM_FORMAT_RGB565:
0091 format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB16;
0092 break;
0093 case DRM_FORMAT_RGB888:
0094 format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB24;
0095 break;
0096 case DRM_FORMAT_ARGB8888:
0097 format |= LDBBSIFR_AL_PK | LDBBSIFR_RY | LDDFR_PKF_ARGB32;
0098 break;
0099 case DRM_FORMAT_NV12:
0100 case DRM_FORMAT_NV21:
0101 format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_420;
0102 break;
0103 case DRM_FORMAT_NV16:
0104 case DRM_FORMAT_NV61:
0105 format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_422;
0106 break;
0107 case DRM_FORMAT_NV24:
0108 case DRM_FORMAT_NV42:
0109 format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_444;
0110 break;
0111 }
0112
0113 #define plane_reg_dump(sdev, splane, reg) \
0114 dev_dbg(sdev->ddev->dev, "%s(%u): %s 0x%08x 0x%08x\n", __func__, \
0115 splane->index, #reg, \
0116 lcdc_read(sdev, reg(splane->index)), \
0117 lcdc_read(sdev, reg(splane->index) + LCDC_SIDE_B_OFFSET))
0118
0119 plane_reg_dump(sdev, splane, LDBnBSIFR);
0120 plane_reg_dump(sdev, splane, LDBnBSSZR);
0121 plane_reg_dump(sdev, splane, LDBnBLOCR);
0122 plane_reg_dump(sdev, splane, LDBnBSMWR);
0123 plane_reg_dump(sdev, splane, LDBnBSAYR);
0124 plane_reg_dump(sdev, splane, LDBnBSACR);
0125
0126 lcdc_write(sdev, LDBCR, LDBCR_UPC(splane->index));
0127 dev_dbg(sdev->ddev->dev, "%s(%u): %s 0x%08x\n", __func__, splane->index,
0128 "LDBCR", lcdc_read(sdev, LDBCR));
0129
0130 lcdc_write(sdev, LDBnBSIFR(splane->index), format);
0131
0132 lcdc_write(sdev, LDBnBSSZR(splane->index),
0133 (splane->crtc_h << LDBBSSZR_BVSS_SHIFT) |
0134 (splane->crtc_w << LDBBSSZR_BHSS_SHIFT));
0135 lcdc_write(sdev, LDBnBLOCR(splane->index),
0136 (splane->crtc_y << LDBBLOCR_CVLC_SHIFT) |
0137 (splane->crtc_x << LDBBLOCR_CHLC_SHIFT));
0138 lcdc_write(sdev, LDBnBSMWR(splane->index),
0139 fb->pitches[0] << LDBBSMWR_BSMW_SHIFT);
0140
0141 shmob_drm_plane_compute_base(splane, fb, splane->src_x, splane->src_y);
0142
0143 lcdc_write(sdev, LDBnBSAYR(splane->index), splane->dma[0]);
0144 if (splane->format->yuv)
0145 lcdc_write(sdev, LDBnBSACR(splane->index), splane->dma[1]);
0146
0147 lcdc_write(sdev, LDBCR,
0148 LDBCR_UPF(splane->index) | LDBCR_UPD(splane->index));
0149 dev_dbg(sdev->ddev->dev, "%s(%u): %s 0x%08x\n", __func__, splane->index,
0150 "LDBCR", lcdc_read(sdev, LDBCR));
0151
0152 plane_reg_dump(sdev, splane, LDBnBSIFR);
0153 plane_reg_dump(sdev, splane, LDBnBSSZR);
0154 plane_reg_dump(sdev, splane, LDBnBLOCR);
0155 plane_reg_dump(sdev, splane, LDBnBSMWR);
0156 plane_reg_dump(sdev, splane, LDBnBSAYR);
0157 plane_reg_dump(sdev, splane, LDBnBSACR);
0158 }
0159
0160 void shmob_drm_plane_setup(struct drm_plane *plane)
0161 {
0162 struct shmob_drm_plane *splane = to_shmob_plane(plane);
0163
0164 if (plane->fb == NULL)
0165 return;
0166
0167 __shmob_drm_plane_setup(splane, plane->fb);
0168 }
0169
0170 static int
0171 shmob_drm_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
0172 struct drm_framebuffer *fb, int crtc_x, int crtc_y,
0173 unsigned int crtc_w, unsigned int crtc_h,
0174 uint32_t src_x, uint32_t src_y,
0175 uint32_t src_w, uint32_t src_h,
0176 struct drm_modeset_acquire_ctx *ctx)
0177 {
0178 struct shmob_drm_plane *splane = to_shmob_plane(plane);
0179 struct shmob_drm_device *sdev = plane->dev->dev_private;
0180 const struct shmob_drm_format_info *format;
0181
0182 format = shmob_drm_format_info(fb->format->format);
0183 if (format == NULL) {
0184 dev_dbg(sdev->dev, "update_plane: unsupported format %08x\n",
0185 fb->format->format);
0186 return -EINVAL;
0187 }
0188
0189 if (src_w >> 16 != crtc_w || src_h >> 16 != crtc_h) {
0190 dev_dbg(sdev->dev, "%s: scaling not supported\n", __func__);
0191 return -EINVAL;
0192 }
0193
0194 splane->format = format;
0195
0196 splane->src_x = src_x >> 16;
0197 splane->src_y = src_y >> 16;
0198 splane->crtc_x = crtc_x;
0199 splane->crtc_y = crtc_y;
0200 splane->crtc_w = crtc_w;
0201 splane->crtc_h = crtc_h;
0202
0203 __shmob_drm_plane_setup(splane, fb);
0204 return 0;
0205 }
0206
0207 static int shmob_drm_plane_disable(struct drm_plane *plane,
0208 struct drm_modeset_acquire_ctx *ctx)
0209 {
0210 struct shmob_drm_plane *splane = to_shmob_plane(plane);
0211 struct shmob_drm_device *sdev = plane->dev->dev_private;
0212
0213 splane->format = NULL;
0214
0215 lcdc_write(sdev, LDBnBSIFR(splane->index), 0);
0216 return 0;
0217 }
0218
0219 static void shmob_drm_plane_destroy(struct drm_plane *plane)
0220 {
0221 drm_plane_force_disable(plane);
0222 drm_plane_cleanup(plane);
0223 }
0224
0225 static const struct drm_plane_funcs shmob_drm_plane_funcs = {
0226 .update_plane = shmob_drm_plane_update,
0227 .disable_plane = shmob_drm_plane_disable,
0228 .destroy = shmob_drm_plane_destroy,
0229 };
0230
0231 static const uint32_t formats[] = {
0232 DRM_FORMAT_RGB565,
0233 DRM_FORMAT_RGB888,
0234 DRM_FORMAT_ARGB8888,
0235 DRM_FORMAT_NV12,
0236 DRM_FORMAT_NV21,
0237 DRM_FORMAT_NV16,
0238 DRM_FORMAT_NV61,
0239 DRM_FORMAT_NV24,
0240 DRM_FORMAT_NV42,
0241 };
0242
0243 int shmob_drm_plane_create(struct shmob_drm_device *sdev, unsigned int index)
0244 {
0245 struct shmob_drm_plane *splane;
0246 int ret;
0247
0248 splane = devm_kzalloc(sdev->dev, sizeof(*splane), GFP_KERNEL);
0249 if (splane == NULL)
0250 return -ENOMEM;
0251
0252 splane->index = index;
0253 splane->alpha = 255;
0254
0255 ret = drm_plane_init(sdev->ddev, &splane->plane, 1,
0256 &shmob_drm_plane_funcs, formats,
0257 ARRAY_SIZE(formats), false);
0258
0259 return ret;
0260 }