static struct drm_framebuffer * rockchip_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd) { struct drm_framebuffer *fb; struct drm_gem_object *objs[ROCKCHIP_MAX_FB_BUFFER]; struct drm_gem_object *obj; unsigned int hsub; unsigned int vsub; int num_planes; int ret; int i; hsub = drm_format_horz_chroma_subsampling(mode_cmd->pixel_format); vsub = drm_format_vert_chroma_subsampling(mode_cmd->pixel_format); num_planes = min(drm_format_num_planes(mode_cmd->pixel_format), ROCKCHIP_MAX_FB_BUFFER); for (i = 0; i < num_planes; i++) { unsigned int width = mode_cmd->width / (i ? hsub : 1); unsigned int height = mode_cmd->height / (i ? vsub : 1); unsigned int min_size; obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]); if (!obj) { DRM_DEV_ERROR(dev->dev, "Failed to lookup GEM object\n"); ret = -ENXIO; goto err_gem_object_unreference; } min_size = (height - 1) * mode_cmd->pitches[i] + mode_cmd->offsets[i] + width * drm_format_plane_cpp(mode_cmd->pixel_format, i); if (obj->size < min_size) { drm_gem_object_put_unlocked(obj); ret = -EINVAL; goto err_gem_object_unreference; } objs[i] = obj; } fb = rockchip_fb_alloc(dev, mode_cmd, objs, i); if (IS_ERR(fb)) { ret = PTR_ERR(fb); goto err_gem_object_unreference; } return fb; err_gem_object_unreference: for (i--; i >= 0; i--) drm_gem_object_put_unlocked(objs[i]); return ERR_PTR(ret); }
/** * drm_format_plane_width - width of the plane given the first plane * @width: width of the first plane * @format: pixel format * @plane: plane index * * Returns: * The width of @plane, given that the width of the first plane is @width. */ int drm_format_plane_width(int width, uint32_t format, int plane) { if (plane >= drm_format_num_planes(format)) return 0; if (plane == 0) return width; return width / drm_format_horz_chroma_subsampling(format); }
struct drm_framebuffer *tegra_fb_create(struct drm_device *drm, struct drm_file *file, const struct drm_mode_fb_cmd2 *cmd) { unsigned int hsub, vsub, i; struct tegra_bo *planes[4]; struct drm_gem_object *gem; struct tegra_fb *fb; int err; hsub = drm_format_horz_chroma_subsampling(cmd->pixel_format); vsub = drm_format_vert_chroma_subsampling(cmd->pixel_format); for (i = 0; i < drm_format_num_planes(cmd->pixel_format); i++) { unsigned int width = cmd->width / (i ? hsub : 1); unsigned int height = cmd->height / (i ? vsub : 1); unsigned int size, bpp; gem = drm_gem_object_lookup(file, cmd->handles[i]); if (!gem) { err = -ENXIO; goto unreference; } bpp = drm_format_plane_cpp(cmd->pixel_format, i); size = (height - 1) * cmd->pitches[i] + width * bpp + cmd->offsets[i]; if (gem->size < size) { err = -EINVAL; goto unreference; } planes[i] = to_tegra_bo(gem); } fb = tegra_fb_alloc(drm, cmd, planes, i); if (IS_ERR(fb)) { err = PTR_ERR(fb); goto unreference; } return &fb->base; unreference: while (i--) drm_gem_object_put_unlocked(&planes[i]->gem); return ERR_PTR(err); }
struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev, struct drm_file *file, struct drm_mode_fb_cmd2 *cmd) { unsigned int hsub, vsub, i; struct mtk_drm_fb *mtk_fb; struct drm_gem_object *gem[MAX_FB_OBJ]; int err; hsub = drm_format_horz_chroma_subsampling(cmd->pixel_format); vsub = drm_format_vert_chroma_subsampling(cmd->pixel_format); for (i = 0; i < drm_format_num_planes(cmd->pixel_format); i++) { unsigned int width = cmd->width / (i ? hsub : 1); unsigned int height = cmd->height / (i ? vsub : 1); unsigned int size, bpp; gem[i] = drm_gem_object_lookup(dev, file, cmd->handles[i]); if (!gem[i]) { err = -ENOENT; goto unreference; } bpp = drm_format_plane_cpp(cmd->pixel_format, i); size = (height - 1) * cmd->pitches[i] + width * bpp; size += cmd->offsets[i]; if (gem[i]->size < size) { err = -EINVAL; goto unreference; } } mtk_fb = mtk_drm_framebuffer_init(dev, cmd, gem); return &mtk_fb->base; unreference: while (i--) drm_gem_object_unreference_unlocked(gem[i]); return ERR_PTR(err); }
/* NOTE: looks like if horizontal decimation is used (if we supported that) * then the width used to calculate SMP block requirements is the post- * decimated width. Ie. SMP buffering sits downstream of decimation (which * presumably happens during the dma from scanout buffer). */ static int request_smp_blocks(struct drm_plane *plane, uint32_t format, uint32_t nplanes, uint32_t width) { struct drm_device *dev = plane->dev; struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); struct mdp5_kms *mdp5_kms = get_kms(plane); enum mdp5_pipe pipe = mdp5_plane->pipe; int i, hsub, nlines, nblks, ret; hsub = drm_format_horz_chroma_subsampling(format); /* different if BWC (compressed framebuffer?) enabled: */ nlines = 2; for (i = 0, nblks = 0; i < nplanes; i++) { int n, fetch_stride, cpp; cpp = drm_format_plane_cpp(format, i); fetch_stride = width * cpp / (i ? hsub : 1); n = DIV_ROUND_UP(fetch_stride * nlines, SMP_BLK_SIZE); /* for hw rev v1.00 */ if (mdp5_kms->rev == 0) n = roundup_pow_of_two(n); DBG("%s[%d]: request %d SMP blocks", mdp5_plane->name, i, n); ret = mdp5_smp_request(mdp5_kms, pipe2client(pipe, i), n); if (ret) { dev_err(dev->dev, "Could not allocate %d SMP blocks: %d\n", n, ret); return ret; } nblks += n; } /* in success case, return total # of blocks allocated: */ return nblks; }
/* mode set a plane */ int xilinx_drm_plane_mode_set(struct drm_plane *base_plane, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) { struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane); struct drm_gem_cma_object *obj; size_t offset; unsigned int hsub, vsub, i; DRM_DEBUG_KMS("plane->id: %d\n", plane->id); if (fb->pixel_format != plane->format) { DRM_ERROR("unsupported pixel format %08x\n", fb->pixel_format); return -EINVAL; } /* configure cresample */ if (plane->cresample) xilinx_cresample_configure(plane->cresample, crtc_w, crtc_h); /* configure rgb2yuv */ if (plane->rgb2yuv) xilinx_rgb2yuv_configure(plane->rgb2yuv, crtc_w, crtc_h); DRM_DEBUG_KMS("h: %d(%d), v: %d(%d)\n", src_w, crtc_x, src_h, crtc_y); DRM_DEBUG_KMS("bpp: %d\n", fb->bits_per_pixel / 8); hsub = drm_format_horz_chroma_subsampling(fb->pixel_format); vsub = drm_format_vert_chroma_subsampling(fb->pixel_format); for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) { unsigned int width = src_w / (i ? hsub : 1); unsigned int height = src_h / (i ? vsub : 1); unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, i); obj = xilinx_drm_fb_get_gem_obj(fb, i); if (!obj) { DRM_ERROR("failed to get a gem obj for fb\n"); return -EINVAL; } plane->dma[i].xt.numf = height; plane->dma[i].sgl[0].size = width * cpp; plane->dma[i].sgl[0].icg = fb->pitches[i] - plane->dma[i].sgl[0].size; offset = src_x * cpp + src_y * fb->pitches[i]; offset += fb->offsets[i]; plane->dma[i].xt.src_start = obj->paddr + offset; plane->dma[i].xt.frame_size = 1; plane->dma[i].xt.dir = DMA_MEM_TO_DEV; plane->dma[i].xt.src_sgl = true; plane->dma[i].xt.dst_sgl = false; plane->dma[i].is_active = true; } for (; i < MAX_NUM_SUB_PLANES; i++) plane->dma[i].is_active = false; /* set OSD dimensions */ if (plane->manager->osd) { xilinx_osd_disable_rue(plane->manager->osd); xilinx_osd_layer_set_dimension(plane->osd_layer, crtc_x, crtc_y, src_w, src_h); xilinx_osd_enable_rue(plane->manager->osd); } if (plane->manager->dp_sub) { int ret; ret = xilinx_drm_dp_sub_layer_check_size(plane->manager->dp_sub, plane->dp_layer, src_w, src_h); if (ret) return ret; } return 0; }
struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos) { struct msm_drm_private *priv = dev->dev_private; struct msm_kms *kms = priv->kms; struct msm_framebuffer *msm_fb = NULL; struct drm_framebuffer *fb; const struct msm_format *format; int ret, i, n; unsigned int hsub, vsub; DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%4.4s)", dev, mode_cmd, mode_cmd->width, mode_cmd->height, (char *)&mode_cmd->pixel_format); n = drm_format_num_planes(mode_cmd->pixel_format); hsub = drm_format_horz_chroma_subsampling(mode_cmd->pixel_format); vsub = drm_format_vert_chroma_subsampling(mode_cmd->pixel_format); format = kms->funcs->get_format(kms, mode_cmd->pixel_format); if (!format) { dev_err(dev->dev, "unsupported pixel format: %4.4s\n", (char *)&mode_cmd->pixel_format); ret = -EINVAL; goto fail; } msm_fb = kzalloc(sizeof(*msm_fb), GFP_KERNEL); if (!msm_fb) { ret = -ENOMEM; goto fail; } fb = &msm_fb->base; msm_fb->format = format; if (n > ARRAY_SIZE(msm_fb->planes)) { ret = -EINVAL; goto fail; } for (i = 0; i < n; i++) { unsigned int width = mode_cmd->width / (i ? hsub : 1); unsigned int height = mode_cmd->height / (i ? vsub : 1); unsigned int min_size; min_size = (height - 1) * mode_cmd->pitches[i] + width * drm_format_plane_cpp(mode_cmd->pixel_format, i) + mode_cmd->offsets[i]; if (bos[i]->size < min_size) { ret = -EINVAL; goto fail; } msm_fb->planes[i] = bos[i]; } drm_helper_mode_fill_fb_struct(fb, mode_cmd); ret = drm_framebuffer_init(dev, fb, &msm_framebuffer_funcs); if (ret) { dev_err(dev->dev, "framebuffer init failed: %d\n", ret); goto fail; } DBG("create: FB ID: %d (%p)", fb->base.id, fb); return fb; fail: kfree(msm_fb); return ERR_PTR(ret); }