45,10 → 45,167 |
#include "i915_drv.h" |
|
|
struct fb_info *framebuffer_alloc(size_t size, struct device *dev) |
{ |
#define BYTES_PER_LONG (BITS_PER_LONG/8) |
#define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG)) |
int fb_info_size = sizeof(struct fb_info); |
struct fb_info *info; |
char *p; |
|
if (size) |
fb_info_size += PADDING; |
|
p = kzalloc(fb_info_size + size, GFP_KERNEL); |
|
if (!p) |
return NULL; |
|
info = (struct fb_info *) p; |
|
if (size) |
info->par = p + fb_info_size; |
|
return info; |
#undef PADDING |
#undef BYTES_PER_LONG |
} |
|
|
static struct fb_ops intelfb_ops = { |
// .owner = THIS_MODULE, |
.fb_check_var = drm_fb_helper_check_var, |
.fb_set_par = drm_fb_helper_set_par, |
// .fb_fillrect = cfb_fillrect, |
// .fb_copyarea = cfb_copyarea, |
// .fb_imageblit = cfb_imageblit, |
// .fb_pan_display = drm_fb_helper_pan_display, |
.fb_blank = drm_fb_helper_blank, |
// .fb_setcmap = drm_fb_helper_setcmap, |
// .fb_debug_enter = drm_fb_helper_debug_enter, |
// .fb_debug_leave = drm_fb_helper_debug_leave, |
}; |
|
static int intelfb_create(struct intel_fbdev *ifbdev, |
struct drm_fb_helper_surface_size *sizes) |
{ |
struct drm_device *dev = ifbdev->helper.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct fb_info *info; |
struct drm_framebuffer *fb; |
struct drm_mode_fb_cmd mode_cmd; |
struct drm_i915_gem_object *obj; |
struct device *device = &dev->pdev->dev; |
int size, ret; |
|
/* we don't do packed 24bpp */ |
if (sizes->surface_bpp == 24) |
sizes->surface_bpp = 32; |
|
mode_cmd.width = sizes->surface_width; |
mode_cmd.height = sizes->surface_height; |
|
mode_cmd.bpp = sizes->surface_bpp; |
mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 7) / 8), 64); |
mode_cmd.depth = sizes->surface_depth; |
|
size = mode_cmd.pitch * mode_cmd.height; |
size = ALIGN(size, PAGE_SIZE); |
obj = i915_gem_alloc_object(dev, size); |
if (!obj) { |
DRM_ERROR("failed to allocate framebuffer\n"); |
ret = -ENOMEM; |
goto out; |
} |
|
mutex_lock(&dev->struct_mutex); |
|
/* Flush everything out, we'll be doing GTT only from now on */ |
ret = intel_pin_and_fence_fb_obj(dev, obj, false); |
if (ret) { |
DRM_ERROR("failed to pin fb: %d\n", ret); |
goto out_unref; |
} |
|
info = framebuffer_alloc(0, device); |
if (!info) { |
ret = -ENOMEM; |
goto out_unpin; |
} |
|
info->par = ifbdev; |
|
ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj); |
if (ret) |
goto out_unpin; |
|
fb = &ifbdev->ifb.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; |
|
/* 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->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; |
|
info->fix.smem_start = dev->mode_config.fb_base + obj->gtt_offset; |
info->fix.smem_len = size; |
|
info->screen_size = size; |
|
// memset(info->screen_base, 0, size); |
|
drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); |
drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height); |
|
DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n", |
fb->width, fb->height, |
obj->gtt_offset, obj); |
|
|
mutex_unlock(&dev->struct_mutex); |
// vga_switcheroo_client_fb_set(dev->pdev, info); |
return 0; |
|
out_unpin: |
// i915_gem_object_unpin(obj); |
out_unref: |
// drm_gem_object_unreference(&obj->base); |
mutex_unlock(&dev->struct_mutex); |
out: |
return ret; |
} |
static int intel_fb_find_or_create_single(struct drm_fb_helper *helper, |
struct drm_fb_helper_surface_size *sizes) |
{ |
struct intel_fbdev *ifbdev = (struct intel_fbdev *)helper; |
int new_fb = 0; |
int ret; |
|
if (!helper->fb) { |
ret = intelfb_create(ifbdev, sizes); |
if (ret) |
return ret; |
new_fb = 1; |
} |
return new_fb; |
} |
|
static struct drm_fb_helper_funcs intel_fb_helper_funcs = { |
.gamma_set = intel_crtc_fb_gamma_set, |
.gamma_get = intel_crtc_fb_gamma_get, |
// .fb_probe = intel_fb_find_or_create_single, |
.fb_probe = intel_fb_find_or_create_single, |
}; |
|
|