231 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright 2015 Freescale Semiconductor, Inc.4 *5 * Freescale DCU drm device driver6 */7 8#include <linux/regmap.h>9 10#include <drm/drm_atomic.h>11#include <drm/drm_atomic_helper.h>12#include <drm/drm_crtc.h>13#include <drm/drm_fb_dma_helper.h>14#include <drm/drm_fourcc.h>15#include <drm/drm_framebuffer.h>16#include <drm/drm_gem_dma_helper.h>17#include <drm/drm_plane_helper.h>18#include <drm/drm_probe_helper.h>19 20#include "fsl_dcu_drm_drv.h"21#include "fsl_dcu_drm_plane.h"22 23static int fsl_dcu_drm_plane_index(struct drm_plane *plane)24{25 struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;26 unsigned int total_layer = fsl_dev->soc->total_layer;27 unsigned int index;28 29 index = drm_plane_index(plane);30 if (index < total_layer)31 return total_layer - index - 1;32 33 dev_err(fsl_dev->dev, "No more layer left\n");34 return -EINVAL;35}36 37static int fsl_dcu_drm_plane_atomic_check(struct drm_plane *plane,38 struct drm_atomic_state *state)39{40 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,41 plane);42 struct drm_framebuffer *fb = new_plane_state->fb;43 44 if (!new_plane_state->fb || !new_plane_state->crtc)45 return 0;46 47 switch (fb->format->format) {48 case DRM_FORMAT_RGB565:49 case DRM_FORMAT_RGB888:50 case DRM_FORMAT_XRGB8888:51 case DRM_FORMAT_ARGB8888:52 case DRM_FORMAT_XRGB4444:53 case DRM_FORMAT_ARGB4444:54 case DRM_FORMAT_XRGB1555:55 case DRM_FORMAT_ARGB1555:56 case DRM_FORMAT_YUV422:57 return 0;58 default:59 return -EINVAL;60 }61}62 63static void fsl_dcu_drm_plane_atomic_disable(struct drm_plane *plane,64 struct drm_atomic_state *state)65{66 struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;67 unsigned int value;68 int index;69 70 index = fsl_dcu_drm_plane_index(plane);71 if (index < 0)72 return;73 74 regmap_read(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4), &value);75 value &= ~DCU_LAYER_EN;76 regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4), value);77}78 79static void fsl_dcu_drm_plane_atomic_update(struct drm_plane *plane,80 struct drm_atomic_state *state)81 82{83 struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;84 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,85 plane);86 struct drm_framebuffer *fb = plane->state->fb;87 struct drm_gem_dma_object *gem;88 unsigned int alpha = DCU_LAYER_AB_NONE, bpp;89 int index;90 91 if (!fb)92 return;93 94 index = fsl_dcu_drm_plane_index(plane);95 if (index < 0)96 return;97 98 gem = drm_fb_dma_get_gem_obj(fb, 0);99 100 switch (fb->format->format) {101 case DRM_FORMAT_RGB565:102 bpp = FSL_DCU_RGB565;103 break;104 case DRM_FORMAT_RGB888:105 bpp = FSL_DCU_RGB888;106 break;107 case DRM_FORMAT_ARGB8888:108 alpha = DCU_LAYER_AB_WHOLE_FRAME;109 fallthrough;110 case DRM_FORMAT_XRGB8888:111 bpp = FSL_DCU_ARGB8888;112 break;113 case DRM_FORMAT_ARGB4444:114 alpha = DCU_LAYER_AB_WHOLE_FRAME;115 fallthrough;116 case DRM_FORMAT_XRGB4444:117 bpp = FSL_DCU_ARGB4444;118 break;119 case DRM_FORMAT_ARGB1555:120 alpha = DCU_LAYER_AB_WHOLE_FRAME;121 fallthrough;122 case DRM_FORMAT_XRGB1555:123 bpp = FSL_DCU_ARGB1555;124 break;125 case DRM_FORMAT_YUV422:126 bpp = FSL_DCU_YUV422;127 break;128 default:129 return;130 }131 132 regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 1),133 DCU_LAYER_HEIGHT(new_state->crtc_h) |134 DCU_LAYER_WIDTH(new_state->crtc_w));135 regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 2),136 DCU_LAYER_POSY(new_state->crtc_y) |137 DCU_LAYER_POSX(new_state->crtc_x));138 regmap_write(fsl_dev->regmap,139 DCU_CTRLDESCLN(index, 3), gem->dma_addr);140 regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4),141 DCU_LAYER_EN |142 DCU_LAYER_TRANS(0xff) |143 DCU_LAYER_BPP(bpp) |144 alpha);145 regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 5),146 DCU_LAYER_CKMAX_R(0xFF) |147 DCU_LAYER_CKMAX_G(0xFF) |148 DCU_LAYER_CKMAX_B(0xFF));149 regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 6),150 DCU_LAYER_CKMIN_R(0) |151 DCU_LAYER_CKMIN_G(0) |152 DCU_LAYER_CKMIN_B(0));153 regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 7), 0);154 regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 8),155 DCU_LAYER_FG_FCOLOR(0));156 regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 9),157 DCU_LAYER_BG_BCOLOR(0));158 159 if (!strcmp(fsl_dev->soc->name, "ls1021a")) {160 regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 10),161 DCU_LAYER_POST_SKIP(0) |162 DCU_LAYER_PRE_SKIP(0));163 }164 165 return;166}167 168static const struct drm_plane_helper_funcs fsl_dcu_drm_plane_helper_funcs = {169 .atomic_check = fsl_dcu_drm_plane_atomic_check,170 .atomic_disable = fsl_dcu_drm_plane_atomic_disable,171 .atomic_update = fsl_dcu_drm_plane_atomic_update,172};173 174static const struct drm_plane_funcs fsl_dcu_drm_plane_funcs = {175 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,176 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,177 .destroy = drm_plane_helper_destroy,178 .disable_plane = drm_atomic_helper_disable_plane,179 .reset = drm_atomic_helper_plane_reset,180 .update_plane = drm_atomic_helper_update_plane,181};182 183static const u32 fsl_dcu_drm_plane_formats[] = {184 DRM_FORMAT_RGB565,185 DRM_FORMAT_RGB888,186 DRM_FORMAT_XRGB8888,187 DRM_FORMAT_ARGB8888,188 DRM_FORMAT_XRGB4444,189 DRM_FORMAT_ARGB4444,190 DRM_FORMAT_XRGB1555,191 DRM_FORMAT_ARGB1555,192 DRM_FORMAT_YUV422,193};194 195void fsl_dcu_drm_init_planes(struct drm_device *dev)196{197 struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;198 int i, j;199 200 for (i = 0; i < fsl_dev->soc->total_layer; i++) {201 for (j = 1; j <= fsl_dev->soc->layer_regs; j++)202 regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(i, j), 0);203 }204}205 206struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device *dev)207{208 struct drm_plane *primary;209 int ret;210 211 primary = kzalloc(sizeof(*primary), GFP_KERNEL);212 if (!primary) {213 DRM_DEBUG_KMS("Failed to allocate primary plane\n");214 return NULL;215 }216 217 /* possible_crtc's will be filled in later by crtc_init */218 ret = drm_universal_plane_init(dev, primary, 0,219 &fsl_dcu_drm_plane_funcs,220 fsl_dcu_drm_plane_formats,221 ARRAY_SIZE(fsl_dcu_drm_plane_formats),222 NULL, DRM_PLANE_TYPE_PRIMARY, NULL);223 if (ret) {224 kfree(primary);225 primary = NULL;226 }227 drm_plane_helper_add(primary, &fsl_dcu_drm_plane_helper_funcs);228 229 return primary;230}231