0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <drm/drm_atomic.h>
0011 #include <drm/drm_atomic_helper.h>
0012 #include <drm/drm_crtc.h>
0013 #include <drm/drm_device.h>
0014 #include <drm/drm_fb_cma_helper.h>
0015 #include <drm/drm_framebuffer.h>
0016 #include <drm/drm_gem_cma_helper.h>
0017 #include <drm/drm_gem_framebuffer_helper.h>
0018 #include <drm/drm_managed.h>
0019 #include <drm/drm_probe_helper.h>
0020 #include <drm/drm_vblank.h>
0021
0022 #include <linux/device.h>
0023 #include <linux/dma-buf.h>
0024 #include <linux/of_graph.h>
0025 #include <linux/of_platform.h>
0026 #include <linux/wait.h>
0027
0028 #include "rcar_du_crtc.h"
0029 #include "rcar_du_drv.h"
0030 #include "rcar_du_encoder.h"
0031 #include "rcar_du_kms.h"
0032 #include "rcar_du_regs.h"
0033 #include "rcar_du_vsp.h"
0034 #include "rcar_du_writeback.h"
0035
0036
0037
0038
0039
0040 static const struct rcar_du_format_info rcar_du_format_infos[] = {
0041 {
0042 .fourcc = DRM_FORMAT_RGB565,
0043 .v4l2 = V4L2_PIX_FMT_RGB565,
0044 .bpp = 16,
0045 .planes = 1,
0046 .hsub = 1,
0047 .pnmr = PnMR_SPIM_TP | PnMR_DDDF_16BPP,
0048 .edf = PnDDCR4_EDF_NONE,
0049 }, {
0050 .fourcc = DRM_FORMAT_ARGB1555,
0051 .v4l2 = V4L2_PIX_FMT_ARGB555,
0052 .bpp = 16,
0053 .planes = 1,
0054 .hsub = 1,
0055 .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_ARGB,
0056 .edf = PnDDCR4_EDF_NONE,
0057 }, {
0058 .fourcc = DRM_FORMAT_XRGB1555,
0059 .v4l2 = V4L2_PIX_FMT_XRGB555,
0060 .bpp = 16,
0061 .planes = 1,
0062 .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_ARGB,
0063 .edf = PnDDCR4_EDF_NONE,
0064 }, {
0065 .fourcc = DRM_FORMAT_XRGB8888,
0066 .v4l2 = V4L2_PIX_FMT_XBGR32,
0067 .bpp = 32,
0068 .planes = 1,
0069 .hsub = 1,
0070 .pnmr = PnMR_SPIM_TP | PnMR_DDDF_16BPP,
0071 .edf = PnDDCR4_EDF_RGB888,
0072 }, {
0073 .fourcc = DRM_FORMAT_ARGB8888,
0074 .v4l2 = V4L2_PIX_FMT_ABGR32,
0075 .bpp = 32,
0076 .planes = 1,
0077 .hsub = 1,
0078 .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_16BPP,
0079 .edf = PnDDCR4_EDF_ARGB8888,
0080 }, {
0081 .fourcc = DRM_FORMAT_UYVY,
0082 .v4l2 = V4L2_PIX_FMT_UYVY,
0083 .bpp = 16,
0084 .planes = 1,
0085 .hsub = 2,
0086 .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
0087 .edf = PnDDCR4_EDF_NONE,
0088 }, {
0089 .fourcc = DRM_FORMAT_YUYV,
0090 .v4l2 = V4L2_PIX_FMT_YUYV,
0091 .bpp = 16,
0092 .planes = 1,
0093 .hsub = 2,
0094 .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
0095 .edf = PnDDCR4_EDF_NONE,
0096 }, {
0097 .fourcc = DRM_FORMAT_NV12,
0098 .v4l2 = V4L2_PIX_FMT_NV12M,
0099 .bpp = 12,
0100 .planes = 2,
0101 .hsub = 2,
0102 .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
0103 .edf = PnDDCR4_EDF_NONE,
0104 }, {
0105 .fourcc = DRM_FORMAT_NV21,
0106 .v4l2 = V4L2_PIX_FMT_NV21M,
0107 .bpp = 12,
0108 .planes = 2,
0109 .hsub = 2,
0110 .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
0111 .edf = PnDDCR4_EDF_NONE,
0112 }, {
0113 .fourcc = DRM_FORMAT_NV16,
0114 .v4l2 = V4L2_PIX_FMT_NV16M,
0115 .bpp = 16,
0116 .planes = 2,
0117 .hsub = 2,
0118 .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
0119 .edf = PnDDCR4_EDF_NONE,
0120 },
0121
0122
0123
0124
0125 {
0126 .fourcc = DRM_FORMAT_RGB332,
0127 .v4l2 = V4L2_PIX_FMT_RGB332,
0128 .bpp = 8,
0129 .planes = 1,
0130 .hsub = 1,
0131 }, {
0132 .fourcc = DRM_FORMAT_ARGB4444,
0133 .v4l2 = V4L2_PIX_FMT_ARGB444,
0134 .bpp = 16,
0135 .planes = 1,
0136 .hsub = 1,
0137 }, {
0138 .fourcc = DRM_FORMAT_XRGB4444,
0139 .v4l2 = V4L2_PIX_FMT_XRGB444,
0140 .bpp = 16,
0141 .planes = 1,
0142 .hsub = 1,
0143 }, {
0144 .fourcc = DRM_FORMAT_RGBA4444,
0145 .v4l2 = V4L2_PIX_FMT_RGBA444,
0146 .bpp = 16,
0147 .planes = 1,
0148 .hsub = 1,
0149 }, {
0150 .fourcc = DRM_FORMAT_RGBX4444,
0151 .v4l2 = V4L2_PIX_FMT_RGBX444,
0152 .bpp = 16,
0153 .planes = 1,
0154 .hsub = 1,
0155 }, {
0156 .fourcc = DRM_FORMAT_ABGR4444,
0157 .v4l2 = V4L2_PIX_FMT_ABGR444,
0158 .bpp = 16,
0159 .planes = 1,
0160 .hsub = 1,
0161 }, {
0162 .fourcc = DRM_FORMAT_XBGR4444,
0163 .v4l2 = V4L2_PIX_FMT_XBGR444,
0164 .bpp = 16,
0165 .planes = 1,
0166 .hsub = 1,
0167 }, {
0168 .fourcc = DRM_FORMAT_BGRA4444,
0169 .v4l2 = V4L2_PIX_FMT_BGRA444,
0170 .bpp = 16,
0171 .planes = 1,
0172 .hsub = 1,
0173 }, {
0174 .fourcc = DRM_FORMAT_BGRX4444,
0175 .v4l2 = V4L2_PIX_FMT_BGRX444,
0176 .bpp = 16,
0177 .planes = 1,
0178 .hsub = 1,
0179 }, {
0180 .fourcc = DRM_FORMAT_RGBA5551,
0181 .v4l2 = V4L2_PIX_FMT_RGBA555,
0182 .bpp = 16,
0183 .planes = 1,
0184 .hsub = 1,
0185 }, {
0186 .fourcc = DRM_FORMAT_RGBX5551,
0187 .v4l2 = V4L2_PIX_FMT_RGBX555,
0188 .bpp = 16,
0189 .planes = 1,
0190 .hsub = 1,
0191 }, {
0192 .fourcc = DRM_FORMAT_ABGR1555,
0193 .v4l2 = V4L2_PIX_FMT_ABGR555,
0194 .bpp = 16,
0195 .planes = 1,
0196 .hsub = 1,
0197 }, {
0198 .fourcc = DRM_FORMAT_XBGR1555,
0199 .v4l2 = V4L2_PIX_FMT_XBGR555,
0200 .bpp = 16,
0201 .planes = 1,
0202 .hsub = 1,
0203 }, {
0204 .fourcc = DRM_FORMAT_BGRA5551,
0205 .v4l2 = V4L2_PIX_FMT_BGRA555,
0206 .bpp = 16,
0207 .planes = 1,
0208 .hsub = 1,
0209 }, {
0210 .fourcc = DRM_FORMAT_BGRX5551,
0211 .v4l2 = V4L2_PIX_FMT_BGRX555,
0212 .bpp = 16,
0213 .planes = 1,
0214 .hsub = 1,
0215 }, {
0216 .fourcc = DRM_FORMAT_BGR888,
0217 .v4l2 = V4L2_PIX_FMT_RGB24,
0218 .bpp = 24,
0219 .planes = 1,
0220 .hsub = 1,
0221 }, {
0222 .fourcc = DRM_FORMAT_RGB888,
0223 .v4l2 = V4L2_PIX_FMT_BGR24,
0224 .bpp = 24,
0225 .planes = 1,
0226 .hsub = 1,
0227 }, {
0228 .fourcc = DRM_FORMAT_RGBA8888,
0229 .v4l2 = V4L2_PIX_FMT_BGRA32,
0230 .bpp = 32,
0231 .planes = 1,
0232 .hsub = 1,
0233 }, {
0234 .fourcc = DRM_FORMAT_RGBX8888,
0235 .v4l2 = V4L2_PIX_FMT_BGRX32,
0236 .bpp = 32,
0237 .planes = 1,
0238 .hsub = 1,
0239 }, {
0240 .fourcc = DRM_FORMAT_ABGR8888,
0241 .v4l2 = V4L2_PIX_FMT_RGBA32,
0242 .bpp = 32,
0243 .planes = 1,
0244 .hsub = 1,
0245 }, {
0246 .fourcc = DRM_FORMAT_XBGR8888,
0247 .v4l2 = V4L2_PIX_FMT_RGBX32,
0248 .bpp = 32,
0249 .planes = 1,
0250 .hsub = 1,
0251 }, {
0252 .fourcc = DRM_FORMAT_BGRA8888,
0253 .v4l2 = V4L2_PIX_FMT_ARGB32,
0254 .bpp = 32,
0255 .planes = 1,
0256 .hsub = 1,
0257 }, {
0258 .fourcc = DRM_FORMAT_BGRX8888,
0259 .v4l2 = V4L2_PIX_FMT_XRGB32,
0260 .bpp = 32,
0261 .planes = 1,
0262 .hsub = 1,
0263 }, {
0264 .fourcc = DRM_FORMAT_YVYU,
0265 .v4l2 = V4L2_PIX_FMT_YVYU,
0266 .bpp = 16,
0267 .planes = 1,
0268 .hsub = 2,
0269 }, {
0270 .fourcc = DRM_FORMAT_NV61,
0271 .v4l2 = V4L2_PIX_FMT_NV61M,
0272 .bpp = 16,
0273 .planes = 2,
0274 .hsub = 2,
0275 }, {
0276 .fourcc = DRM_FORMAT_YUV420,
0277 .v4l2 = V4L2_PIX_FMT_YUV420M,
0278 .bpp = 12,
0279 .planes = 3,
0280 .hsub = 2,
0281 }, {
0282 .fourcc = DRM_FORMAT_YVU420,
0283 .v4l2 = V4L2_PIX_FMT_YVU420M,
0284 .bpp = 12,
0285 .planes = 3,
0286 .hsub = 2,
0287 }, {
0288 .fourcc = DRM_FORMAT_YUV422,
0289 .v4l2 = V4L2_PIX_FMT_YUV422M,
0290 .bpp = 16,
0291 .planes = 3,
0292 .hsub = 2,
0293 }, {
0294 .fourcc = DRM_FORMAT_YVU422,
0295 .v4l2 = V4L2_PIX_FMT_YVU422M,
0296 .bpp = 16,
0297 .planes = 3,
0298 .hsub = 2,
0299 }, {
0300 .fourcc = DRM_FORMAT_YUV444,
0301 .v4l2 = V4L2_PIX_FMT_YUV444M,
0302 .bpp = 24,
0303 .planes = 3,
0304 .hsub = 1,
0305 }, {
0306 .fourcc = DRM_FORMAT_YVU444,
0307 .v4l2 = V4L2_PIX_FMT_YVU444M,
0308 .bpp = 24,
0309 .planes = 3,
0310 .hsub = 1,
0311 },
0312 };
0313
0314 const struct rcar_du_format_info *rcar_du_format_info(u32 fourcc)
0315 {
0316 unsigned int i;
0317
0318 for (i = 0; i < ARRAY_SIZE(rcar_du_format_infos); ++i) {
0319 if (rcar_du_format_infos[i].fourcc == fourcc)
0320 return &rcar_du_format_infos[i];
0321 }
0322
0323 return NULL;
0324 }
0325
0326
0327
0328
0329
0330 static const struct drm_gem_object_funcs rcar_du_gem_funcs = {
0331 .free = drm_gem_cma_object_free,
0332 .print_info = drm_gem_cma_object_print_info,
0333 .get_sg_table = drm_gem_cma_object_get_sg_table,
0334 .vmap = drm_gem_cma_object_vmap,
0335 .mmap = drm_gem_cma_object_mmap,
0336 .vm_ops = &drm_gem_cma_vm_ops,
0337 };
0338
0339 struct drm_gem_object *rcar_du_gem_prime_import_sg_table(struct drm_device *dev,
0340 struct dma_buf_attachment *attach,
0341 struct sg_table *sgt)
0342 {
0343 struct rcar_du_device *rcdu = to_rcar_du_device(dev);
0344 struct drm_gem_cma_object *cma_obj;
0345 struct drm_gem_object *gem_obj;
0346 int ret;
0347
0348 if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE))
0349 return drm_gem_cma_prime_import_sg_table(dev, attach, sgt);
0350
0351
0352 cma_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL);
0353 if (!cma_obj)
0354 return ERR_PTR(-ENOMEM);
0355
0356 gem_obj = &cma_obj->base;
0357 gem_obj->funcs = &rcar_du_gem_funcs;
0358
0359 drm_gem_private_object_init(dev, gem_obj, attach->dmabuf->size);
0360 cma_obj->map_noncoherent = false;
0361
0362 ret = drm_gem_create_mmap_offset(gem_obj);
0363 if (ret) {
0364 drm_gem_object_release(gem_obj);
0365 kfree(cma_obj);
0366 return ERR_PTR(ret);
0367 }
0368
0369 cma_obj->paddr = 0;
0370 cma_obj->sgt = sgt;
0371
0372 return gem_obj;
0373 }
0374
0375 int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev,
0376 struct drm_mode_create_dumb *args)
0377 {
0378 struct rcar_du_device *rcdu = to_rcar_du_device(dev);
0379 unsigned int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
0380 unsigned int align;
0381
0382
0383
0384
0385
0386 if (rcar_du_needs(rcdu, RCAR_DU_QUIRK_ALIGN_128B))
0387 align = 128;
0388 else
0389 align = 16 * args->bpp / 8;
0390
0391 args->pitch = roundup(min_pitch, align);
0392
0393 return drm_gem_cma_dumb_create_internal(file, dev, args);
0394 }
0395
0396 static struct drm_framebuffer *
0397 rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv,
0398 const struct drm_mode_fb_cmd2 *mode_cmd)
0399 {
0400 struct rcar_du_device *rcdu = to_rcar_du_device(dev);
0401 const struct rcar_du_format_info *format;
0402 unsigned int chroma_pitch;
0403 unsigned int max_pitch;
0404 unsigned int align;
0405 unsigned int i;
0406
0407 format = rcar_du_format_info(mode_cmd->pixel_format);
0408 if (format == NULL) {
0409 dev_dbg(dev->dev, "unsupported pixel format %08x\n",
0410 mode_cmd->pixel_format);
0411 return ERR_PTR(-EINVAL);
0412 }
0413
0414 if (rcdu->info->gen < 3) {
0415
0416
0417
0418
0419
0420 unsigned int bpp = format->planes == 1 ? format->bpp / 8 : 1;
0421
0422 max_pitch = 4095 * bpp;
0423
0424 if (rcar_du_needs(rcdu, RCAR_DU_QUIRK_ALIGN_128B))
0425 align = 128;
0426 else
0427 align = 16 * bpp;
0428 } else {
0429
0430
0431
0432
0433
0434 max_pitch = 65535;
0435 align = 1;
0436 }
0437
0438 if (mode_cmd->pitches[0] & (align - 1) ||
0439 mode_cmd->pitches[0] > max_pitch) {
0440 dev_dbg(dev->dev, "invalid pitch value %u\n",
0441 mode_cmd->pitches[0]);
0442 return ERR_PTR(-EINVAL);
0443 }
0444
0445
0446
0447
0448
0449
0450 chroma_pitch = mode_cmd->pitches[0] / format->hsub;
0451 if (format->planes == 2)
0452 chroma_pitch *= 2;
0453
0454 for (i = 1; i < format->planes; ++i) {
0455 if (mode_cmd->pitches[i] != chroma_pitch) {
0456 dev_dbg(dev->dev,
0457 "luma and chroma pitches are not compatible\n");
0458 return ERR_PTR(-EINVAL);
0459 }
0460 }
0461
0462 return drm_gem_fb_create(dev, file_priv, mode_cmd);
0463 }
0464
0465
0466
0467
0468
0469 static int rcar_du_atomic_check(struct drm_device *dev,
0470 struct drm_atomic_state *state)
0471 {
0472 struct rcar_du_device *rcdu = to_rcar_du_device(dev);
0473 int ret;
0474
0475 ret = drm_atomic_helper_check(dev, state);
0476 if (ret)
0477 return ret;
0478
0479 if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE))
0480 return 0;
0481
0482 return rcar_du_atomic_check_planes(dev, state);
0483 }
0484
0485 static void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state)
0486 {
0487 struct drm_device *dev = old_state->dev;
0488 struct rcar_du_device *rcdu = to_rcar_du_device(dev);
0489 struct drm_crtc_state *crtc_state;
0490 struct drm_crtc *crtc;
0491 unsigned int i;
0492
0493
0494
0495
0496
0497 rcdu->dpad1_source = -1;
0498
0499 for_each_new_crtc_in_state(old_state, crtc, crtc_state, i) {
0500 struct rcar_du_crtc_state *rcrtc_state =
0501 to_rcar_crtc_state(crtc_state);
0502 struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
0503
0504 if (rcrtc_state->outputs & BIT(RCAR_DU_OUTPUT_DPAD0))
0505 rcdu->dpad0_source = rcrtc->index;
0506
0507 if (rcrtc_state->outputs & BIT(RCAR_DU_OUTPUT_DPAD1))
0508 rcdu->dpad1_source = rcrtc->index;
0509 }
0510
0511
0512 drm_atomic_helper_commit_modeset_disables(dev, old_state);
0513 drm_atomic_helper_commit_planes(dev, old_state,
0514 DRM_PLANE_COMMIT_ACTIVE_ONLY);
0515 drm_atomic_helper_commit_modeset_enables(dev, old_state);
0516
0517 drm_atomic_helper_commit_hw_done(old_state);
0518 drm_atomic_helper_wait_for_flip_done(dev, old_state);
0519
0520 drm_atomic_helper_cleanup_planes(dev, old_state);
0521 }
0522
0523
0524
0525
0526
0527 static const struct drm_mode_config_helper_funcs rcar_du_mode_config_helper = {
0528 .atomic_commit_tail = rcar_du_atomic_commit_tail,
0529 };
0530
0531 static const struct drm_mode_config_funcs rcar_du_mode_config_funcs = {
0532 .fb_create = rcar_du_fb_create,
0533 .atomic_check = rcar_du_atomic_check,
0534 .atomic_commit = drm_atomic_helper_commit,
0535 };
0536
0537 static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
0538 enum rcar_du_output output,
0539 struct of_endpoint *ep)
0540 {
0541 struct device_node *entity;
0542 int ret;
0543
0544
0545 entity = of_graph_get_remote_port_parent(ep->local_node);
0546 if (!entity) {
0547 dev_dbg(rcdu->dev, "unconnected endpoint %pOF, skipping\n",
0548 ep->local_node);
0549 return -ENODEV;
0550 }
0551
0552 if (!of_device_is_available(entity)) {
0553 dev_dbg(rcdu->dev,
0554 "connected entity %pOF is disabled, skipping\n",
0555 entity);
0556 of_node_put(entity);
0557 return -ENODEV;
0558 }
0559
0560 ret = rcar_du_encoder_init(rcdu, output, entity);
0561 if (ret && ret != -EPROBE_DEFER && ret != -ENOLINK)
0562 dev_warn(rcdu->dev,
0563 "failed to initialize encoder %pOF on output %s (%d), skipping\n",
0564 entity, rcar_du_output_name(output), ret);
0565
0566 of_node_put(entity);
0567
0568 return ret;
0569 }
0570
0571 static int rcar_du_encoders_init(struct rcar_du_device *rcdu)
0572 {
0573 struct device_node *np = rcdu->dev->of_node;
0574 struct device_node *ep_node;
0575 unsigned int num_encoders = 0;
0576
0577
0578
0579
0580
0581 for_each_endpoint_of_node(np, ep_node) {
0582 enum rcar_du_output output;
0583 struct of_endpoint ep;
0584 unsigned int i;
0585 int ret;
0586
0587 ret = of_graph_parse_endpoint(ep_node, &ep);
0588 if (ret < 0) {
0589 of_node_put(ep_node);
0590 return ret;
0591 }
0592
0593
0594 for (i = 0; i < RCAR_DU_OUTPUT_MAX; ++i) {
0595 if (rcdu->info->routes[i].possible_crtcs &&
0596 rcdu->info->routes[i].port == ep.port) {
0597 output = i;
0598 break;
0599 }
0600 }
0601
0602 if (i == RCAR_DU_OUTPUT_MAX) {
0603 dev_warn(rcdu->dev,
0604 "port %u references unexisting output, skipping\n",
0605 ep.port);
0606 continue;
0607 }
0608
0609
0610 ret = rcar_du_encoders_init_one(rcdu, output, &ep);
0611 if (ret < 0) {
0612 if (ret == -EPROBE_DEFER) {
0613 of_node_put(ep_node);
0614 return ret;
0615 }
0616
0617 continue;
0618 }
0619
0620 num_encoders++;
0621 }
0622
0623 return num_encoders;
0624 }
0625
0626 static int rcar_du_properties_init(struct rcar_du_device *rcdu)
0627 {
0628
0629
0630
0631
0632
0633 rcdu->props.colorkey =
0634 drm_property_create_range(&rcdu->ddev, 0, "colorkey",
0635 0, 0x01ffffff);
0636 if (rcdu->props.colorkey == NULL)
0637 return -ENOMEM;
0638
0639 return 0;
0640 }
0641
0642 static int rcar_du_vsps_init(struct rcar_du_device *rcdu)
0643 {
0644 const struct device_node *np = rcdu->dev->of_node;
0645 const char *vsps_prop_name = "renesas,vsps";
0646 struct of_phandle_args args;
0647 struct {
0648 struct device_node *np;
0649 unsigned int crtcs_mask;
0650 } vsps[RCAR_DU_MAX_VSPS] = { { NULL, }, };
0651 unsigned int vsps_count = 0;
0652 unsigned int cells;
0653 unsigned int i;
0654 int ret;
0655
0656
0657
0658
0659
0660
0661 ret = of_property_count_u32_elems(np, vsps_prop_name);
0662 if (ret < 0) {
0663
0664 vsps_prop_name = "vsps";
0665 ret = of_property_count_u32_elems(np, vsps_prop_name);
0666 }
0667 cells = ret / rcdu->num_crtcs - 1;
0668 if (cells > 1)
0669 return -EINVAL;
0670
0671 for (i = 0; i < rcdu->num_crtcs; ++i) {
0672 unsigned int j;
0673
0674 ret = of_parse_phandle_with_fixed_args(np, vsps_prop_name,
0675 cells, i, &args);
0676 if (ret < 0)
0677 goto error;
0678
0679
0680
0681
0682
0683 for (j = 0; j < vsps_count; ++j) {
0684 if (vsps[j].np == args.np)
0685 break;
0686 }
0687
0688 if (j < vsps_count)
0689 of_node_put(args.np);
0690 else
0691 vsps[vsps_count++].np = args.np;
0692
0693 vsps[j].crtcs_mask |= BIT(i);
0694
0695
0696
0697
0698
0699
0700 rcdu->crtcs[i].vsp = &rcdu->vsps[j];
0701 rcdu->crtcs[i].vsp_pipe = cells >= 1 ? args.args[0] : 0;
0702 }
0703
0704
0705
0706
0707
0708 for (i = 0; i < vsps_count; ++i) {
0709 struct rcar_du_vsp *vsp = &rcdu->vsps[i];
0710
0711 vsp->index = i;
0712 vsp->dev = rcdu;
0713
0714 ret = rcar_du_vsp_init(vsp, vsps[i].np, vsps[i].crtcs_mask);
0715 if (ret < 0)
0716 goto error;
0717 }
0718
0719 return 0;
0720
0721 error:
0722 for (i = 0; i < ARRAY_SIZE(vsps); ++i)
0723 of_node_put(vsps[i].np);
0724
0725 return ret;
0726 }
0727
0728 static int rcar_du_cmm_init(struct rcar_du_device *rcdu)
0729 {
0730 const struct device_node *np = rcdu->dev->of_node;
0731 unsigned int i;
0732 int cells;
0733
0734 cells = of_property_count_u32_elems(np, "renesas,cmms");
0735 if (cells == -EINVAL)
0736 return 0;
0737
0738 if (cells > rcdu->num_crtcs) {
0739 dev_err(rcdu->dev,
0740 "Invalid number of entries in 'renesas,cmms'\n");
0741 return -EINVAL;
0742 }
0743
0744 for (i = 0; i < cells; ++i) {
0745 struct platform_device *pdev;
0746 struct device_link *link;
0747 struct device_node *cmm;
0748 int ret;
0749
0750 cmm = of_parse_phandle(np, "renesas,cmms", i);
0751 if (!cmm) {
0752 dev_err(rcdu->dev,
0753 "Failed to parse 'renesas,cmms' property\n");
0754 return -EINVAL;
0755 }
0756
0757 if (!of_device_is_available(cmm)) {
0758
0759 of_node_put(cmm);
0760 continue;
0761 }
0762
0763 pdev = of_find_device_by_node(cmm);
0764 if (!pdev) {
0765 dev_err(rcdu->dev, "No device found for CMM%u\n", i);
0766 of_node_put(cmm);
0767 return -EINVAL;
0768 }
0769
0770 of_node_put(cmm);
0771
0772
0773
0774
0775
0776 ret = rcar_cmm_init(pdev);
0777 if (ret) {
0778 platform_device_put(pdev);
0779 return ret == -ENODEV ? 0 : ret;
0780 }
0781
0782 rcdu->cmms[i] = pdev;
0783
0784
0785
0786
0787
0788 link = device_link_add(rcdu->dev, &pdev->dev, DL_FLAG_STATELESS);
0789 if (!link) {
0790 dev_err(rcdu->dev,
0791 "Failed to create device link to CMM%u\n", i);
0792 return -EINVAL;
0793 }
0794 }
0795
0796 return 0;
0797 }
0798
0799 static void rcar_du_modeset_cleanup(struct drm_device *dev, void *res)
0800 {
0801 struct rcar_du_device *rcdu = to_rcar_du_device(dev);
0802 unsigned int i;
0803
0804 for (i = 0; i < ARRAY_SIZE(rcdu->cmms); ++i)
0805 platform_device_put(rcdu->cmms[i]);
0806 }
0807
0808 int rcar_du_modeset_init(struct rcar_du_device *rcdu)
0809 {
0810 static const unsigned int mmio_offsets[] = {
0811 DU0_REG_OFFSET, DU2_REG_OFFSET
0812 };
0813
0814 struct drm_device *dev = &rcdu->ddev;
0815 struct drm_encoder *encoder;
0816 unsigned int dpad0_sources;
0817 unsigned int num_encoders;
0818 unsigned int num_groups;
0819 unsigned int swindex;
0820 unsigned int hwindex;
0821 unsigned int i;
0822 int ret;
0823
0824 ret = drmm_mode_config_init(dev);
0825 if (ret)
0826 return ret;
0827
0828 ret = drmm_add_action(&rcdu->ddev, rcar_du_modeset_cleanup, NULL);
0829 if (ret)
0830 return ret;
0831
0832 dev->mode_config.min_width = 0;
0833 dev->mode_config.min_height = 0;
0834 dev->mode_config.normalize_zpos = true;
0835 dev->mode_config.funcs = &rcar_du_mode_config_funcs;
0836 dev->mode_config.helper_private = &rcar_du_mode_config_helper;
0837
0838 if (rcdu->info->gen < 3) {
0839 dev->mode_config.max_width = 4095;
0840 dev->mode_config.max_height = 2047;
0841 } else {
0842
0843
0844
0845
0846 dev->mode_config.max_width = 8190;
0847 dev->mode_config.max_height = 8190;
0848 }
0849
0850 rcdu->num_crtcs = hweight8(rcdu->info->channels_mask);
0851
0852 ret = rcar_du_properties_init(rcdu);
0853 if (ret < 0)
0854 return ret;
0855
0856
0857
0858
0859
0860 ret = drm_vblank_init(dev, rcdu->num_crtcs);
0861 if (ret < 0)
0862 return ret;
0863
0864
0865 num_groups = DIV_ROUND_UP(rcdu->num_crtcs, 2);
0866
0867 for (i = 0; i < num_groups; ++i) {
0868 struct rcar_du_group *rgrp = &rcdu->groups[i];
0869
0870 mutex_init(&rgrp->lock);
0871
0872 rgrp->dev = rcdu;
0873 rgrp->mmio_offset = mmio_offsets[i];
0874 rgrp->index = i;
0875
0876 rgrp->channels_mask = (rcdu->info->channels_mask >> (2 * i))
0877 & GENMASK(1, 0);
0878 rgrp->num_crtcs = hweight8(rgrp->channels_mask);
0879
0880
0881
0882
0883
0884
0885
0886 rgrp->dptsr_planes = rgrp->num_crtcs > 1
0887 ? (rcdu->info->gen >= 3 ? 0x04 : 0xf0)
0888 : 0;
0889
0890 if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) {
0891 ret = rcar_du_planes_init(rgrp);
0892 if (ret < 0)
0893 return ret;
0894 }
0895 }
0896
0897
0898 if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) {
0899 ret = rcar_du_vsps_init(rcdu);
0900 if (ret < 0)
0901 return ret;
0902 }
0903
0904
0905 ret = rcar_du_cmm_init(rcdu);
0906 if (ret)
0907 return ret;
0908
0909
0910 for (swindex = 0, hwindex = 0; swindex < rcdu->num_crtcs; ++hwindex) {
0911 struct rcar_du_group *rgrp;
0912
0913
0914 if (!(rcdu->info->channels_mask & BIT(hwindex)))
0915 continue;
0916
0917 rgrp = &rcdu->groups[hwindex / 2];
0918
0919 ret = rcar_du_crtc_create(rgrp, swindex++, hwindex);
0920 if (ret < 0)
0921 return ret;
0922 }
0923
0924
0925 ret = rcar_du_encoders_init(rcdu);
0926 if (ret < 0)
0927 return ret;
0928
0929 if (ret == 0) {
0930 dev_err(rcdu->dev, "error: no encoder could be initialized\n");
0931 return -EINVAL;
0932 }
0933
0934 num_encoders = ret;
0935
0936
0937
0938
0939
0940
0941 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
0942 struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
0943 const struct rcar_du_output_routing *route =
0944 &rcdu->info->routes[renc->output];
0945
0946 encoder->possible_crtcs = route->possible_crtcs;
0947 encoder->possible_clones = (1 << num_encoders) - 1;
0948 }
0949
0950
0951 if (rcdu->info->gen >= 3) {
0952 for (i = 0; i < rcdu->num_crtcs; ++i) {
0953 struct rcar_du_crtc *rcrtc = &rcdu->crtcs[i];
0954
0955 ret = rcar_du_writeback_init(rcdu, rcrtc);
0956 if (ret < 0)
0957 return ret;
0958 }
0959 }
0960
0961
0962
0963
0964
0965
0966
0967
0968
0969 dpad0_sources = rcdu->info->routes[RCAR_DU_OUTPUT_DPAD0].possible_crtcs;
0970 rcdu->dpad0_source = ffs(dpad0_sources) - 1;
0971
0972 drm_mode_config_reset(dev);
0973
0974 drm_kms_helper_poll_init(dev);
0975
0976 return 0;
0977 }