struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos) { struct omap_framebuffer *omap_fb; struct drm_framebuffer *fb = NULL; const struct format *format = NULL; int ret, i, n = drm_format_num_planes(mode_cmd->pixel_format); 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); for (i = 0; i < ARRAY_SIZE(formats); i++) { if (formats[i].pixel_format == mode_cmd->pixel_format) { format = &formats[i]; break; } } if (!format) { dev_err(dev->dev, "unsupported pixel format: %4.4s\n", (char *)&mode_cmd->pixel_format); ret = -EINVAL; goto fail; } omap_fb = kzalloc(sizeof(*omap_fb), GFP_KERNEL); if (!omap_fb) { ret = -ENOMEM; goto fail; } fb = &omap_fb->base; omap_fb->format = format; for (i = 0; i < n; i++) { struct plane *plane = &omap_fb->planes[i]; int size, pitch = mode_cmd->pitches[i]; if (pitch < (mode_cmd->width * format->planes[i].stride_bpp)) { dev_err(dev->dev, "provided buffer pitch is too small! %d < %d\n", pitch, mode_cmd->width * format->planes[i].stride_bpp); ret = -EINVAL; goto fail; } size = pitch * mode_cmd->height / format->planes[i].sub_y; if (size > (omap_gem_mmap_size(bos[i]) - mode_cmd->offsets[i])) { dev_err(dev->dev, "provided buffer object is too small! %d < %d\n", bos[i]->size - mode_cmd->offsets[i], size); ret = -EINVAL; goto fail; } plane->bo = bos[i]; plane->offset = mode_cmd->offsets[i]; plane->pitch = pitch; plane->paddr = 0; } drm_helper_mode_fill_fb_struct(fb, mode_cmd); ret = drm_framebuffer_init(dev, fb, &omap_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: if (fb) omap_framebuffer_destroy(fb); return ERR_PTR(ret); }
struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, struct drm_mode_fb_cmd *mode_cmd, struct drm_gem_object *bo) { struct omap_framebuffer *omap_fb; struct drm_framebuffer *fb = NULL; int size, ret; DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%d)", dev, mode_cmd, mode_cmd->width, mode_cmd->height, mode_cmd->bpp); /* in case someone tries to feed us a completely bogus stride: */ mode_cmd->pitch = align_pitch(mode_cmd->pitch, mode_cmd->width, mode_cmd->bpp); omap_fb = kzalloc(sizeof(*omap_fb), GFP_KERNEL); if (!omap_fb) { dev_err(dev->dev, "could not allocate fb\n"); goto fail; } fb = &omap_fb->base; ret = drm_framebuffer_init(dev, fb, &omap_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); size = PAGE_ALIGN(mode_cmd->pitch * mode_cmd->height); if (bo) { DBG("using existing %d byte buffer (needed %d)", bo->size, size); if (size > bo->size) { dev_err(dev->dev, "provided buffer object is too small!\n"); goto fail; } } else { /* for convenience of all the various callers who don't want * to be bothered to allocate their own buffer.. */ union omap_gem_size gsize = { .bytes = size, }; DBG("allocating %d bytes for fb %d", size, dev->primary->index); bo = omap_gem_new(dev, gsize, OMAP_BO_SCANOUT | OMAP_BO_WC); if (!bo) { dev_err(dev->dev, "failed to allocate buffer object\n"); goto fail; } } omap_fb->bo = bo; omap_fb->size = size; if (omap_gem_get_paddr(bo, &omap_fb->paddr, true)) { dev_err(dev->dev, "could not map (paddr)!\n"); goto fail; } drm_helper_mode_fill_fb_struct(fb, mode_cmd); return fb; fail: if (fb) { omap_framebuffer_destroy(fb); } return NULL; }