/* update which fb (if any) is pinned for scanout */ static int update_pin(struct drm_plane *plane, struct drm_framebuffer *fb) { struct omap_plane *omap_plane = to_omap_plane(plane); struct drm_framebuffer *pinned_fb = omap_plane->pinned_fb; if (pinned_fb != fb) { int ret; DBG("%p -> %p", pinned_fb, fb); if (fb) drm_framebuffer_reference(fb); ret = omap_framebuffer_replace(pinned_fb, fb, plane, unpin); if (pinned_fb) drm_framebuffer_unreference(pinned_fb); if (ret) { dev_err(plane->dev->dev, "could not swap %p -> %p\n", omap_plane->pinned_fb, fb); if (fb) drm_framebuffer_unreference(fb); omap_plane->pinned_fb = NULL; return ret; } omap_plane->pinned_fb = fb; } return 0; }
static int mdp4_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb) { struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); struct drm_plane *plane = mdp4_crtc->plane; struct drm_display_mode *mode = &crtc->mode; int ret; /* grab extra ref for update_scanout() */ drm_framebuffer_reference(crtc->primary->fb); ret = mdp4_plane_mode_set(plane, crtc, crtc->primary->fb, 0, 0, mode->hdisplay, mode->vdisplay, x << 16, y << 16, mode->hdisplay << 16, mode->vdisplay << 16); if (ret) { drm_framebuffer_unreference(crtc->primary->fb); return ret; } update_fb(crtc, crtc->primary->fb); update_scanout(crtc, crtc->primary->fb); return 0; }
static void mdp5_plane_destroy_state(struct drm_plane *plane, struct drm_plane_state *state) { if (state->fb) drm_framebuffer_unreference(state->fb); kfree(to_mdp5_plane_state(state)); }
static void armada_drm_unref_work(struct work_struct *work) { struct armada_private *priv = container_of(work, struct armada_private, fb_unref_work); struct drm_framebuffer *fb; while (kfifo_get(&priv->fb_unref, &fb)) drm_framebuffer_unreference(fb); }
static void unref_fb_worker(struct drm_flip_work *work, void *val) { struct mdp4_crtc *mdp4_crtc = container_of(work, struct mdp4_crtc, unref_fb_work); struct drm_device *dev = mdp4_crtc->base.dev; mutex_lock(&dev->mode_config.mutex); drm_framebuffer_unreference(val); mutex_unlock(&dev->mode_config.mutex); }
void evdi_painter_disconnect(struct evdi_device *evdi, struct drm_file *file) { struct evdi_painter *painter = evdi->painter; EVDI_CHECKPT(); painter_lock(painter); if (file != painter->drm_filp) { EVDI_WARN ("(dev=%d) An unknown connection to %p tries to close us", evdi->dev_index, file); EVDI_WARN(" - ignoring\n"); painter_unlock(painter); return; } if (painter->new_scanout_fb) { drm_framebuffer_unreference(&painter->new_scanout_fb->base); painter->new_scanout_fb = NULL; } if (painter->scanout_fb) { drm_framebuffer_unreference(&painter->scanout_fb->base); painter->scanout_fb = NULL; } painter->is_connected = false; EVDI_DEBUG("(dev=%d) Disconnected from %p\n", evdi->dev_index, painter->drm_filp); painter->drm_filp = NULL; evdi->dev_index = -1; memset(&painter->current_mode, '\0', sizeof(struct drm_display_mode)); painter->was_update_requested = false; painter_unlock(painter); drm_helper_hpd_irq_event(evdi->ddev); }
void evdi_set_new_scanout_buffer(struct evdi_device *evdi, struct evdi_framebuffer *efb) { struct evdi_painter *painter = evdi->painter; if (efb) drm_framebuffer_reference(&efb->base); if (painter->new_scanout_fb) drm_framebuffer_unreference(&painter->new_scanout_fb->base); painter->new_scanout_fb = efb; }
void evdi_flip_scanout_buffer(struct evdi_device *evdi) { struct evdi_painter *painter = evdi->painter; painter_lock(painter); if (painter->new_scanout_fb) drm_framebuffer_reference(&painter->new_scanout_fb->base); if (painter->scanout_fb) drm_framebuffer_unreference(&painter->scanout_fb->base); painter->scanout_fb = painter->new_scanout_fb; painter_unlock(painter); }
static void mdp5_plane_reset(struct drm_plane *plane) { struct mdp5_plane_state *mdp5_state; if (plane->state && plane->state->fb) drm_framebuffer_unreference(plane->state->fb); kfree(to_mdp5_plane_state(plane->state)); mdp5_state = kzalloc(sizeof(*mdp5_state), GFP_KERNEL); if (plane->type == DRM_PLANE_TYPE_PRIMARY) { mdp5_state->zpos = 0; } else { mdp5_state->zpos = 1 + drm_plane_index(plane); } plane->state = &mdp5_state->base; }
/** * drm_atomic_plane_set_property - set property on plane * @plane: the drm plane to set a property on * @state: the state object to update with the new property value * @property: the property to set * @val: the new property value * * Use this instead of calling plane->atomic_set_property directly. * This function handles generic/core properties and calls out to * driver's ->atomic_set_property() for driver properties. To ensure * consistent behavior you must call this function rather than the * driver hook directly. * * RETURNS: * Zero on success, error code on failure */ int drm_atomic_plane_set_property(struct drm_plane *plane, struct drm_plane_state *state, struct drm_property *property, uint64_t val) { struct drm_device *dev = plane->dev; struct drm_mode_config *config = &dev->mode_config; if (property == config->prop_fb_id) { struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, val); drm_atomic_set_fb_for_plane(state, fb); if (fb) drm_framebuffer_unreference(fb); } else if (property == config->prop_crtc_id) { struct drm_crtc *crtc = drm_crtc_find(dev, val); return drm_atomic_set_crtc_for_plane(state, crtc); } else if (property == config->prop_crtc_x) { state->crtc_x = U642I64(val); } else if (property == config->prop_crtc_y) { state->crtc_y = U642I64(val); } else if (property == config->prop_crtc_w) { state->crtc_w = val; } else if (property == config->prop_crtc_h) { state->crtc_h = val; } else if (property == config->prop_src_x) { state->src_x = val; } else if (property == config->prop_src_y) { state->src_y = val; } else if (property == config->prop_src_w) { state->src_w = val; } else if (property == config->prop_src_h) { state->src_h = val; } else if (property == config->rotation_property) { state->rotation = val; } else if (plane->funcs->atomic_set_property) { return plane->funcs->atomic_set_property(plane, state, property, val); } else { return -EINVAL; } return 0; }
static int omap_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, 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 omap_plane *omap_plane = to_omap_plane(plane); omap_plane->enabled = true; if (plane->fb) drm_framebuffer_unreference(plane->fb); drm_framebuffer_reference(fb); return omap_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, src_x, src_y, src_w, src_h, NULL, NULL); }
/** * _sde_connector_destroy_fb - clean up connector state's out_fb buffer * @c_conn: Pointer to sde connector structure * @c_state: Pointer to sde connector state structure */ static void _sde_connector_destroy_fb(struct sde_connector *c_conn, struct sde_connector_state *c_state) { if (!c_state || !c_state->out_fb) { SDE_ERROR("invalid state %pK\n", c_state); return; } msm_framebuffer_cleanup(c_state->out_fb, c_state->mmu_id); drm_framebuffer_unreference(c_state->out_fb); c_state->out_fb = NULL; if (c_conn) { c_state->property_values[CONNECTOR_PROP_OUT_FB] = msm_property_get_default(&c_conn->property_info, CONNECTOR_PROP_OUT_FB); } else { c_state->property_values[CONNECTOR_PROP_OUT_FB] = ~0; } }
static int intelfb_create(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { struct intel_fbdev *ifbdev = container_of(helper, struct intel_fbdev, helper); struct intel_framebuffer *intel_fb = ifbdev->fb; struct drm_device *dev = helper->dev; struct drm_i915_private *dev_priv = to_i915(dev); struct pci_dev *pdev = dev_priv->drm.pdev; struct i915_ggtt *ggtt = &dev_priv->ggtt; struct fb_info *info; struct drm_framebuffer *fb; struct i915_vma *vma; bool prealloc = false; void __iomem *vaddr; int ret; if (intel_fb && (sizes->fb_width > intel_fb->base.width || sizes->fb_height > intel_fb->base.height)) { DRM_DEBUG_KMS("BIOS fb too small (%dx%d), we require (%dx%d)," " releasing it\n", intel_fb->base.width, intel_fb->base.height, sizes->fb_width, sizes->fb_height); drm_framebuffer_unreference(&intel_fb->base); intel_fb = ifbdev->fb = NULL; } if (!intel_fb || WARN_ON(!intel_fb->obj)) { DRM_DEBUG_KMS("no BIOS fb, allocating a new one\n"); ret = intelfb_alloc(helper, sizes); if (ret) return ret; intel_fb = ifbdev->fb; } else { DRM_DEBUG_KMS("re-using BIOS fb\n"); prealloc = true; sizes->fb_width = intel_fb->base.width; sizes->fb_height = intel_fb->base.height; } mutex_lock(&dev->struct_mutex); /* Pin the GGTT vma for our access via info->screen_base. * This also validates that any existing fb inherited from the * BIOS is suitable for own access. */ vma = intel_pin_and_fence_fb_obj(&ifbdev->fb->base, DRM_ROTATE_0); if (IS_ERR(vma)) { ret = PTR_ERR(vma); goto out_unlock; } info = drm_fb_helper_alloc_fbi(helper); if (IS_ERR(info)) { DRM_ERROR("Failed to allocate fb_info\n"); ret = PTR_ERR(info); goto out_unpin; } info->par = helper; fb = &ifbdev->fb->base; ifbdev->helper.fb = fb; strcpy(info->fix.id, "inteldrmfb"); info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT; info->fbops = &intelfb_ops; /* setup aperture base/size for vesafb takeover */ info->apertures->ranges[0].base = dev->mode_config.fb_base; info->apertures->ranges[0].size = ggtt->mappable_end; info->fix.smem_start = dev->mode_config.fb_base + i915_ggtt_offset(vma); info->fix.smem_len = vma->node.size; vaddr = i915_vma_pin_iomap(vma); if (IS_ERR(vaddr)) { DRM_ERROR("Failed to remap framebuffer into virtual memory\n"); ret = PTR_ERR(vaddr); goto out_destroy_fbi; } info->screen_base = vaddr; info->screen_size = vma->node.size; /* This driver doesn't need a VT switch to restore the mode on resume */ info->skip_vt_switch = true; drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth); drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height); /* If the object is shmemfs backed, it will have given us zeroed pages. * If the object is stolen however, it will be full of whatever * garbage was left in there. */ if (intel_fb->obj->stolen && !prealloc) memset_io(info->screen_base, 0, info->screen_size); /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x\n", fb->width, fb->height, i915_ggtt_offset(vma)); ifbdev->vma = vma; mutex_unlock(&dev->struct_mutex); vga_switcheroo_client_fb_set(pdev, info); return 0; out_destroy_fbi: drm_fb_helper_release_fbi(helper); out_unpin: intel_unpin_fb_obj(&ifbdev->fb->base, DRM_ROTATE_0); out_unlock: mutex_unlock(&dev->struct_mutex); return ret; }
static int intelfb_create(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { struct intel_fbdev *ifbdev = container_of(helper, struct intel_fbdev, helper); struct intel_framebuffer *intel_fb = ifbdev->fb; struct drm_device *dev = helper->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct fb_info *info; struct drm_framebuffer *fb; struct drm_i915_gem_object *obj; int size, ret; bool prealloc = false; mutex_lock(&dev->struct_mutex); if (intel_fb && (sizes->fb_width > intel_fb->base.width || sizes->fb_height > intel_fb->base.height)) { DRM_DEBUG_KMS("BIOS fb too small (%dx%d), we require (%dx%d)," " releasing it\n", intel_fb->base.width, intel_fb->base.height, sizes->fb_width, sizes->fb_height); drm_framebuffer_unreference(&intel_fb->base); intel_fb = ifbdev->fb = NULL; } if (!intel_fb || WARN_ON(!intel_fb->obj)) { DRM_DEBUG_KMS("no BIOS fb, allocating a new one\n"); ret = intelfb_alloc(helper, sizes); if (ret) goto out_unlock; intel_fb = ifbdev->fb; } else { DRM_DEBUG_KMS("re-using BIOS fb\n"); prealloc = true; sizes->fb_width = intel_fb->base.width; sizes->fb_height = intel_fb->base.height; } obj = intel_fb->obj; size = obj->base.size; info = framebuffer_alloc(0, &dev->pdev->dev); if (!info) { ret = -ENOMEM; goto out_unpin; } info->par = helper; fb = &ifbdev->fb->base; ifbdev->helper.fb = fb; ifbdev->helper.fbdev = info; strcpy(info->fix.id, "inteldrmfb"); info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT; info->fbops = &intelfb_ops; ret = fb_alloc_cmap(&info->cmap, 256, 0); if (ret) { ret = -ENOMEM; goto out_unpin; } /* setup aperture base/size for vesafb takeover */ info->apertures = alloc_apertures(1); if (!info->apertures) { ret = -ENOMEM; goto out_unpin; } info->apertures->ranges[0].base = dev->mode_config.fb_base; info->apertures->ranges[0].size = dev_priv->gtt.mappable_end; info->fix.smem_start = dev->mode_config.fb_base + i915_gem_obj_ggtt_offset(obj); info->fix.smem_len = size; info->screen_base = ioremap_wc(dev_priv->gtt.mappable_base + i915_gem_obj_ggtt_offset(obj), size); if (!info->screen_base) { ret = -ENOSPC; goto out_unpin; } info->screen_size = size; /* This driver doesn't need a VT switch to restore the mode on resume */ info->skip_vt_switch = true; drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height); /* If the object is shmemfs backed, it will have given us zeroed pages. * If the object is stolen however, it will be full of whatever * garbage was left in there. */ if (ifbdev->fb->obj->stolen && !prealloc) memset_io(info->screen_base, 0, info->screen_size); /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width, fb->height, i915_gem_obj_ggtt_offset(obj), obj); mutex_unlock(&dev->struct_mutex); vga_switcheroo_client_fb_set(dev->pdev, info); return 0; out_unpin: i915_gem_object_ggtt_unpin(obj); drm_gem_object_unreference(&obj->base); out_unlock: mutex_unlock(&dev->struct_mutex); return ret; }
int vmw_present_readback_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct vmw_private *dev_priv = vmw_priv(dev); struct drm_vmw_present_readback_arg *arg = (struct drm_vmw_present_readback_arg *)data; struct drm_vmw_fence_rep __user *user_fence_rep = (struct drm_vmw_fence_rep __user *) (unsigned long)arg->fence_rep; struct vmw_master *vmaster = vmw_master(file_priv->master); struct drm_vmw_rect __user *clips_ptr; struct drm_vmw_rect *clips = NULL; struct drm_framebuffer *fb; struct vmw_framebuffer *vfb; uint32_t num_clips; int ret; num_clips = arg->num_clips; clips_ptr = (struct drm_vmw_rect *)(unsigned long)arg->clips_ptr; if (unlikely(num_clips == 0)) return 0; if (clips_ptr == NULL) { DRM_ERROR("Argument clips_ptr must be specified.\n"); ret = -EINVAL; goto out_clips; } clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL); if (clips == NULL) { DRM_ERROR("Failed to allocate clip rect list.\n"); ret = -ENOMEM; goto out_clips; } ret = copy_from_user(clips, clips_ptr, num_clips * sizeof(*clips)); if (ret) { DRM_ERROR("Failed to copy clip rects from userspace.\n"); ret = -EFAULT; goto out_no_copy; } drm_modeset_lock_all(dev); fb = drm_framebuffer_lookup(dev, arg->fb_id); if (!fb) { DRM_ERROR("Invalid framebuffer id.\n"); ret = -ENOENT; goto out_no_fb; } vfb = vmw_framebuffer_to_vfb(fb); if (!vfb->dmabuf) { DRM_ERROR("Framebuffer not dmabuf backed.\n"); ret = -EINVAL; goto out_no_ttm_lock; } ret = ttm_read_lock(&vmaster->lock, true); if (unlikely(ret != 0)) goto out_no_ttm_lock; ret = vmw_kms_readback(dev_priv, file_priv, vfb, user_fence_rep, clips, num_clips); ttm_read_unlock(&vmaster->lock); out_no_ttm_lock: drm_framebuffer_unreference(fb); out_no_fb: drm_modeset_unlock_all(dev); out_no_copy: kfree(clips); out_clips: return ret; }
int vmw_present_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; struct vmw_private *dev_priv = vmw_priv(dev); struct drm_vmw_present_arg *arg = (struct drm_vmw_present_arg *)data; struct vmw_surface *surface; struct vmw_master *vmaster = vmw_master(file_priv->master); struct drm_vmw_rect __user *clips_ptr; struct drm_vmw_rect *clips = NULL; struct drm_framebuffer *fb; struct vmw_framebuffer *vfb; struct vmw_resource *res; uint32_t num_clips; int ret; num_clips = arg->num_clips; clips_ptr = (struct drm_vmw_rect *)(unsigned long)arg->clips_ptr; if (unlikely(num_clips == 0)) return 0; if (clips_ptr == NULL) { DRM_ERROR("Variable clips_ptr must be specified.\n"); ret = -EINVAL; goto out_clips; } clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL); if (clips == NULL) { DRM_ERROR("Failed to allocate clip rect list.\n"); ret = -ENOMEM; goto out_clips; } ret = copy_from_user(clips, clips_ptr, num_clips * sizeof(*clips)); if (ret) { DRM_ERROR("Failed to copy clip rects from userspace.\n"); ret = -EFAULT; goto out_no_copy; } drm_modeset_lock_all(dev); fb = drm_framebuffer_lookup(dev, arg->fb_id); if (!fb) { DRM_ERROR("Invalid framebuffer id.\n"); ret = -ENOENT; goto out_no_fb; } vfb = vmw_framebuffer_to_vfb(fb); ret = ttm_read_lock(&vmaster->lock, true); if (unlikely(ret != 0)) goto out_no_ttm_lock; ret = vmw_user_resource_lookup_handle(dev_priv, tfile, arg->sid, user_surface_converter, &res); if (ret) goto out_no_surface; surface = vmw_res_to_srf(res); ret = vmw_kms_present(dev_priv, file_priv, vfb, surface, arg->sid, arg->dest_x, arg->dest_y, clips, num_clips); /* vmw_user_surface_lookup takes one ref so does new_fb */ vmw_surface_unreference(&surface); out_no_surface: ttm_read_unlock(&vmaster->lock); out_no_ttm_lock: drm_framebuffer_unreference(fb); out_no_fb: drm_modeset_unlock_all(dev); out_no_copy: kfree(clips); out_clips: return ret; }
static int mdp4_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, int x, int y, struct drm_framebuffer *old_fb) { struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); struct mdp4_kms *mdp4_kms = get_kms(crtc); enum mdp4_dma dma = mdp4_crtc->dma; int ret, ovlp = mdp4_crtc->ovlp; mode = adjusted_mode; DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", mdp4_crtc->name, mode->base.id, mode->name, mode->vrefresh, mode->clock, mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal, mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal, mode->type, mode->flags); /* grab extra ref for update_scanout() */ drm_framebuffer_reference(crtc->primary->fb); ret = mdp4_plane_mode_set(mdp4_crtc->plane, crtc, crtc->primary->fb, 0, 0, mode->hdisplay, mode->vdisplay, x << 16, y << 16, mode->hdisplay << 16, mode->vdisplay << 16); if (ret) { drm_framebuffer_unreference(crtc->primary->fb); dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n", mdp4_crtc->name, ret); return ret; } mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_SIZE(dma), MDP4_DMA_SRC_SIZE_WIDTH(mode->hdisplay) | MDP4_DMA_SRC_SIZE_HEIGHT(mode->vdisplay)); /* take data from pipe: */ mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_BASE(dma), 0); mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_STRIDE(dma), crtc->primary->fb->pitches[0]); mdp4_write(mdp4_kms, REG_MDP4_DMA_DST_SIZE(dma), MDP4_DMA_DST_SIZE_WIDTH(0) | MDP4_DMA_DST_SIZE_HEIGHT(0)); mdp4_write(mdp4_kms, REG_MDP4_OVLP_BASE(ovlp), 0); mdp4_write(mdp4_kms, REG_MDP4_OVLP_SIZE(ovlp), MDP4_OVLP_SIZE_WIDTH(mode->hdisplay) | MDP4_OVLP_SIZE_HEIGHT(mode->vdisplay)); mdp4_write(mdp4_kms, REG_MDP4_OVLP_STRIDE(ovlp), crtc->primary->fb->pitches[0]); mdp4_write(mdp4_kms, REG_MDP4_OVLP_CFG(ovlp), 1); if (dma == DMA_E) { mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(0), 0x00ff0000); mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(1), 0x00ff0000); mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(2), 0x00ff0000); } update_fb(crtc, crtc->primary->fb); update_scanout(crtc, crtc->primary->fb); return 0; }