/* create extra planes */ int xilinx_drm_plane_create_planes(struct xilinx_drm_plane_manager *manager, unsigned int possible_crtcs) { struct xilinx_drm_plane *plane; int i; int err_ret; xilinx_drm_plane_create_property(manager); /* find if there any available plane, and create if available */ for (i = 0; i < manager->num_planes; i++) { if (manager->planes[i]) continue; plane = xilinx_drm_plane_create(manager, possible_crtcs, false); if (IS_ERR(plane)) { DRM_ERROR("failed to allocate a plane\n"); err_ret = PTR_ERR(plane); goto err_out; } xilinx_drm_plane_attach_property(&plane->base); manager->planes[i] = plane; } return 0; err_out: xilinx_drm_plane_destroy_planes(manager); return err_ret; }
/* destroy crtc */ void xilinx_drm_crtc_destroy(struct drm_crtc *base_crtc) { struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc); /* make sure crtc is off */ xilinx_drm_crtc_dpms(base_crtc, DRM_MODE_DPMS_OFF); drm_crtc_cleanup(base_crtc); clk_disable_unprepare(crtc->pixel_clock); xilinx_drm_plane_destroy_planes(crtc->plane_manager); xilinx_drm_plane_destroy_private(crtc->plane_manager, crtc->priv_plane); xilinx_drm_plane_remove_manager(crtc->plane_manager); }
/* create crtc */ struct drm_crtc *xilinx_drm_crtc_create(struct drm_device *drm) { struct xilinx_drm_crtc *crtc; struct device_node *sub_node; int possible_crtcs = 1; int ret; crtc = devm_kzalloc(drm->dev, sizeof(*crtc), GFP_KERNEL); if (!crtc) return ERR_PTR(-ENOMEM); /* probe chroma resampler and enable */ sub_node = of_parse_phandle(drm->dev->of_node, "cresample", 0); if (sub_node) { crtc->cresample = xilinx_cresample_probe(drm->dev, sub_node); of_node_put(sub_node); if (IS_ERR(crtc->cresample)) { DRM_ERROR("failed to probe a cresample\n"); return ERR_CAST(crtc->cresample); } } /* probe color space converter and enable */ sub_node = of_parse_phandle(drm->dev->of_node, "rgb2yuv", 0); if (sub_node) { crtc->rgb2yuv = xilinx_rgb2yuv_probe(drm->dev, sub_node); of_node_put(sub_node); if (IS_ERR(crtc->rgb2yuv)) { DRM_ERROR("failed to probe a rgb2yuv\n"); return ERR_CAST(crtc->rgb2yuv); } } /* probe a plane manager */ crtc->plane_manager = xilinx_drm_plane_probe_manager(drm); if (IS_ERR(crtc->plane_manager)) { DRM_ERROR("failed to probe a plane manager\n"); return ERR_CAST(crtc->plane_manager); } /* create a private plane. there's only one crtc now */ crtc->priv_plane = xilinx_drm_plane_create_private(crtc->plane_manager, possible_crtcs); if (IS_ERR(crtc->priv_plane)) { DRM_ERROR("failed to create a private plane for crtc\n"); ret = PTR_ERR(crtc->priv_plane); goto err_plane; } /* create extra planes */ xilinx_drm_plane_create_planes(crtc->plane_manager, possible_crtcs); crtc->pixel_clock = devm_clk_get(drm->dev, NULL); if (IS_ERR(crtc->pixel_clock)) { DRM_DEBUG_KMS("failed to get pixel clock\n"); ret = -EPROBE_DEFER; goto err_out; } ret = clk_prepare_enable(crtc->pixel_clock); if (ret) { DRM_DEBUG_KMS("failed to prepare/enable clock\n"); goto err_out; } sub_node = of_parse_phandle(drm->dev->of_node, "vtc", 0); if (!sub_node) { DRM_ERROR("failed to get a video timing controller node\n"); ret = -ENODEV; goto err_out; } crtc->vtc = xilinx_vtc_probe(drm->dev, sub_node); of_node_put(sub_node); if (IS_ERR(crtc->vtc)) { DRM_ERROR("failed to probe video timing controller\n"); ret = PTR_ERR(crtc->vtc); goto err_out; } crtc->dpms = DRM_MODE_DPMS_OFF; /* initialize drm crtc */ ret = drm_crtc_init(drm, &crtc->base, &xilinx_drm_crtc_funcs); if (ret) { DRM_ERROR("failed to initialize crtc\n"); goto err_out; } drm_crtc_helper_add(&crtc->base, &xilinx_drm_crtc_helper_funcs); xilinx_drm_crtc_attach_property(&crtc->base); return &crtc->base; err_out: xilinx_drm_plane_destroy_planes(crtc->plane_manager); xilinx_drm_plane_destroy_private(crtc->plane_manager, crtc->priv_plane); err_plane: xilinx_drm_plane_remove_manager(crtc->plane_manager); return ERR_PTR(ret); }