0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/regmap.h>
0009
0010 #include <drm/drm_atomic.h>
0011 #include <drm/drm_atomic_helper.h>
0012 #include <drm/drm_crtc.h>
0013 #include <drm/drm_fb_cma_helper.h>
0014 #include <drm/drm_fourcc.h>
0015 #include <drm/drm_framebuffer.h>
0016 #include <drm/drm_gem_cma_helper.h>
0017 #include <drm/drm_plane_helper.h>
0018 #include <drm/drm_probe_helper.h>
0019
0020 #include "fsl_dcu_drm_drv.h"
0021 #include "fsl_dcu_drm_plane.h"
0022
0023 static int fsl_dcu_drm_plane_index(struct drm_plane *plane)
0024 {
0025 struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;
0026 unsigned int total_layer = fsl_dev->soc->total_layer;
0027 unsigned int index;
0028
0029 index = drm_plane_index(plane);
0030 if (index < total_layer)
0031 return total_layer - index - 1;
0032
0033 dev_err(fsl_dev->dev, "No more layer left\n");
0034 return -EINVAL;
0035 }
0036
0037 static int fsl_dcu_drm_plane_atomic_check(struct drm_plane *plane,
0038 struct drm_atomic_state *state)
0039 {
0040 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
0041 plane);
0042 struct drm_framebuffer *fb = new_plane_state->fb;
0043
0044 if (!new_plane_state->fb || !new_plane_state->crtc)
0045 return 0;
0046
0047 switch (fb->format->format) {
0048 case DRM_FORMAT_RGB565:
0049 case DRM_FORMAT_RGB888:
0050 case DRM_FORMAT_XRGB8888:
0051 case DRM_FORMAT_ARGB8888:
0052 case DRM_FORMAT_XRGB4444:
0053 case DRM_FORMAT_ARGB4444:
0054 case DRM_FORMAT_XRGB1555:
0055 case DRM_FORMAT_ARGB1555:
0056 case DRM_FORMAT_YUV422:
0057 return 0;
0058 default:
0059 return -EINVAL;
0060 }
0061 }
0062
0063 static void fsl_dcu_drm_plane_atomic_disable(struct drm_plane *plane,
0064 struct drm_atomic_state *state)
0065 {
0066 struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;
0067 unsigned int value;
0068 int index;
0069
0070 index = fsl_dcu_drm_plane_index(plane);
0071 if (index < 0)
0072 return;
0073
0074 regmap_read(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4), &value);
0075 value &= ~DCU_LAYER_EN;
0076 regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4), value);
0077 }
0078
0079 static void fsl_dcu_drm_plane_atomic_update(struct drm_plane *plane,
0080 struct drm_atomic_state *state)
0081
0082 {
0083 struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;
0084 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
0085 plane);
0086 struct drm_framebuffer *fb = plane->state->fb;
0087 struct drm_gem_cma_object *gem;
0088 unsigned int alpha = DCU_LAYER_AB_NONE, bpp;
0089 int index;
0090
0091 if (!fb)
0092 return;
0093
0094 index = fsl_dcu_drm_plane_index(plane);
0095 if (index < 0)
0096 return;
0097
0098 gem = drm_fb_cma_get_gem_obj(fb, 0);
0099
0100 switch (fb->format->format) {
0101 case DRM_FORMAT_RGB565:
0102 bpp = FSL_DCU_RGB565;
0103 break;
0104 case DRM_FORMAT_RGB888:
0105 bpp = FSL_DCU_RGB888;
0106 break;
0107 case DRM_FORMAT_ARGB8888:
0108 alpha = DCU_LAYER_AB_WHOLE_FRAME;
0109 fallthrough;
0110 case DRM_FORMAT_XRGB8888:
0111 bpp = FSL_DCU_ARGB8888;
0112 break;
0113 case DRM_FORMAT_ARGB4444:
0114 alpha = DCU_LAYER_AB_WHOLE_FRAME;
0115 fallthrough;
0116 case DRM_FORMAT_XRGB4444:
0117 bpp = FSL_DCU_ARGB4444;
0118 break;
0119 case DRM_FORMAT_ARGB1555:
0120 alpha = DCU_LAYER_AB_WHOLE_FRAME;
0121 fallthrough;
0122 case DRM_FORMAT_XRGB1555:
0123 bpp = FSL_DCU_ARGB1555;
0124 break;
0125 case DRM_FORMAT_YUV422:
0126 bpp = FSL_DCU_YUV422;
0127 break;
0128 default:
0129 return;
0130 }
0131
0132 regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 1),
0133 DCU_LAYER_HEIGHT(new_state->crtc_h) |
0134 DCU_LAYER_WIDTH(new_state->crtc_w));
0135 regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 2),
0136 DCU_LAYER_POSY(new_state->crtc_y) |
0137 DCU_LAYER_POSX(new_state->crtc_x));
0138 regmap_write(fsl_dev->regmap,
0139 DCU_CTRLDESCLN(index, 3), gem->paddr);
0140 regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4),
0141 DCU_LAYER_EN |
0142 DCU_LAYER_TRANS(0xff) |
0143 DCU_LAYER_BPP(bpp) |
0144 alpha);
0145 regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 5),
0146 DCU_LAYER_CKMAX_R(0xFF) |
0147 DCU_LAYER_CKMAX_G(0xFF) |
0148 DCU_LAYER_CKMAX_B(0xFF));
0149 regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 6),
0150 DCU_LAYER_CKMIN_R(0) |
0151 DCU_LAYER_CKMIN_G(0) |
0152 DCU_LAYER_CKMIN_B(0));
0153 regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 7), 0);
0154 regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 8),
0155 DCU_LAYER_FG_FCOLOR(0));
0156 regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 9),
0157 DCU_LAYER_BG_BCOLOR(0));
0158
0159 if (!strcmp(fsl_dev->soc->name, "ls1021a")) {
0160 regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 10),
0161 DCU_LAYER_POST_SKIP(0) |
0162 DCU_LAYER_PRE_SKIP(0));
0163 }
0164
0165 return;
0166 }
0167
0168 static const struct drm_plane_helper_funcs fsl_dcu_drm_plane_helper_funcs = {
0169 .atomic_check = fsl_dcu_drm_plane_atomic_check,
0170 .atomic_disable = fsl_dcu_drm_plane_atomic_disable,
0171 .atomic_update = fsl_dcu_drm_plane_atomic_update,
0172 };
0173
0174 static void fsl_dcu_drm_plane_destroy(struct drm_plane *plane)
0175 {
0176 drm_plane_cleanup(plane);
0177 kfree(plane);
0178 }
0179
0180 static const struct drm_plane_funcs fsl_dcu_drm_plane_funcs = {
0181 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
0182 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
0183 .destroy = fsl_dcu_drm_plane_destroy,
0184 .disable_plane = drm_atomic_helper_disable_plane,
0185 .reset = drm_atomic_helper_plane_reset,
0186 .update_plane = drm_atomic_helper_update_plane,
0187 };
0188
0189 static const u32 fsl_dcu_drm_plane_formats[] = {
0190 DRM_FORMAT_RGB565,
0191 DRM_FORMAT_RGB888,
0192 DRM_FORMAT_XRGB8888,
0193 DRM_FORMAT_ARGB8888,
0194 DRM_FORMAT_XRGB4444,
0195 DRM_FORMAT_ARGB4444,
0196 DRM_FORMAT_XRGB1555,
0197 DRM_FORMAT_ARGB1555,
0198 DRM_FORMAT_YUV422,
0199 };
0200
0201 void fsl_dcu_drm_init_planes(struct drm_device *dev)
0202 {
0203 struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
0204 int i, j;
0205
0206 for (i = 0; i < fsl_dev->soc->total_layer; i++) {
0207 for (j = 1; j <= fsl_dev->soc->layer_regs; j++)
0208 regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(i, j), 0);
0209 }
0210 }
0211
0212 struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device *dev)
0213 {
0214 struct drm_plane *primary;
0215 int ret;
0216
0217 primary = kzalloc(sizeof(*primary), GFP_KERNEL);
0218 if (!primary) {
0219 DRM_DEBUG_KMS("Failed to allocate primary plane\n");
0220 return NULL;
0221 }
0222
0223
0224 ret = drm_universal_plane_init(dev, primary, 0,
0225 &fsl_dcu_drm_plane_funcs,
0226 fsl_dcu_drm_plane_formats,
0227 ARRAY_SIZE(fsl_dcu_drm_plane_formats),
0228 NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
0229 if (ret) {
0230 kfree(primary);
0231 primary = NULL;
0232 }
0233 drm_plane_helper_add(primary, &fsl_dcu_drm_plane_helper_funcs);
0234
0235 return primary;
0236 }