Commit 7fff400b authored by Dave Airlie's avatar Dave Airlie

Merge branch 'drm-fbdev-cleanup' into drm-core-next

* drm-fbdev-cleanup:
  drm/fb: remove drm_fb_helper_setcolreg
  drm/kms/fb: use slow work mechanism for normal hotplug also.
  drm/kms/fb: add polling support for when nothing is connected.
  drm/kms/fb: provide a 1024x768 fbcon if no outputs found.
  drm/kms/fb: separate fbdev connector list from core drm connectors
  drm/kms/fb: move to using fb helper crtc grouping instead of core crtc list
  drm/fb: fix fbdev object model + cleanup properly.

Conflicts:
	drivers/gpu/drm/i915/i915_drv.h
	drivers/gpu/drm/nouveau/nouveau_drv.h
parents 0bcb1d84 b1f20198
...@@ -23,6 +23,7 @@ config DRM_KMS_HELPER ...@@ -23,6 +23,7 @@ config DRM_KMS_HELPER
depends on DRM depends on DRM
select FB select FB
select FRAMEBUFFER_CONSOLE if !EMBEDDED select FRAMEBUFFER_CONSOLE if !EMBEDDED
select SLOW_WORK
help help
FB and CRTC helpers for KMS drivers. FB and CRTC helpers for KMS drivers.
......
...@@ -495,7 +495,6 @@ void drm_connector_cleanup(struct drm_connector *connector) ...@@ -495,7 +495,6 @@ void drm_connector_cleanup(struct drm_connector *connector)
list_for_each_entry_safe(mode, t, &connector->user_modes, head) list_for_each_entry_safe(mode, t, &connector->user_modes, head)
drm_mode_remove(connector, mode); drm_mode_remove(connector, mode);
kfree(connector->fb_helper_private);
mutex_lock(&dev->mode_config.mutex); mutex_lock(&dev->mode_config.mutex);
drm_mode_object_put(dev, &connector->base); drm_mode_object_put(dev, &connector->base);
list_del(&connector->head); list_del(&connector->head);
...@@ -859,7 +858,6 @@ void drm_mode_config_init(struct drm_device *dev) ...@@ -859,7 +858,6 @@ void drm_mode_config_init(struct drm_device *dev)
mutex_init(&dev->mode_config.mutex); mutex_init(&dev->mode_config.mutex);
mutex_init(&dev->mode_config.idr_mutex); mutex_init(&dev->mode_config.idr_mutex);
INIT_LIST_HEAD(&dev->mode_config.fb_list); INIT_LIST_HEAD(&dev->mode_config.fb_list);
INIT_LIST_HEAD(&dev->mode_config.fb_kernel_list);
INIT_LIST_HEAD(&dev->mode_config.crtc_list); INIT_LIST_HEAD(&dev->mode_config.crtc_list);
INIT_LIST_HEAD(&dev->mode_config.connector_list); INIT_LIST_HEAD(&dev->mode_config.connector_list);
INIT_LIST_HEAD(&dev->mode_config.encoder_list); INIT_LIST_HEAD(&dev->mode_config.encoder_list);
......
This diff is collapsed.
This diff is collapsed.
...@@ -1492,7 +1492,7 @@ static int i915_load_modeset_init(struct drm_device *dev, ...@@ -1492,7 +1492,7 @@ static int i915_load_modeset_init(struct drm_device *dev,
I915_WRITE(INSTPM, (1 << 5) | (1 << 21)); I915_WRITE(INSTPM, (1 << 5) | (1 << 21));
drm_helper_initial_config(dev); intel_fbdev_init(dev);
return 0; return 0;
......
...@@ -226,6 +226,8 @@ enum intel_pch { ...@@ -226,6 +226,8 @@ enum intel_pch {
PCH_CPT, /* Cougarpoint PCH */ PCH_CPT, /* Cougarpoint PCH */
}; };
struct intel_fbdev;
typedef struct drm_i915_private { typedef struct drm_i915_private {
struct drm_device *dev; struct drm_device *dev;
...@@ -638,6 +640,9 @@ typedef struct drm_i915_private { ...@@ -638,6 +640,9 @@ typedef struct drm_i915_private {
u8 max_delay; u8 max_delay;
enum no_fbc_reason no_fbc_reason; enum no_fbc_reason no_fbc_reason;
/* list of fbdev register on this device */
struct intel_fbdev *fbdev;
} drm_i915_private_t; } drm_i915_private_t;
/** driver private structure attached to each drm_gem_object */ /** driver private structure attached to each drm_gem_object */
......
...@@ -271,6 +271,7 @@ static void i915_hotplug_work_func(struct work_struct *work) ...@@ -271,6 +271,7 @@ static void i915_hotplug_work_func(struct work_struct *work)
} }
} }
/* Just fire off a uevent and let userspace tell us what to do */ /* Just fire off a uevent and let userspace tell us what to do */
intelfb_hotplug(dev, false);
drm_sysfs_hotplug_event(dev); drm_sysfs_hotplug_event(dev);
} }
......
...@@ -4889,10 +4889,6 @@ static void intel_setup_outputs(struct drm_device *dev) ...@@ -4889,10 +4889,6 @@ static void intel_setup_outputs(struct drm_device *dev)
static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb) static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
{ {
struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
struct drm_device *dev = fb->dev;
if (fb->fbdev)
intelfb_remove(dev, fb);
drm_framebuffer_cleanup(fb); drm_framebuffer_cleanup(fb);
drm_gem_object_unreference_unlocked(intel_fb->obj); drm_gem_object_unreference_unlocked(intel_fb->obj);
...@@ -4915,18 +4911,13 @@ static const struct drm_framebuffer_funcs intel_fb_funcs = { ...@@ -4915,18 +4911,13 @@ static const struct drm_framebuffer_funcs intel_fb_funcs = {
.create_handle = intel_user_framebuffer_create_handle, .create_handle = intel_user_framebuffer_create_handle,
}; };
int intel_framebuffer_create(struct drm_device *dev, int intel_framebuffer_init(struct drm_device *dev,
struct drm_mode_fb_cmd *mode_cmd, struct intel_framebuffer *intel_fb,
struct drm_framebuffer **fb, struct drm_mode_fb_cmd *mode_cmd,
struct drm_gem_object *obj) struct drm_gem_object *obj)
{ {
struct intel_framebuffer *intel_fb;
int ret; int ret;
intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
if (!intel_fb)
return -ENOMEM;
ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs); ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs);
if (ret) { if (ret) {
DRM_ERROR("framebuffer init failed %d\n", ret); DRM_ERROR("framebuffer init failed %d\n", ret);
...@@ -4934,40 +4925,40 @@ int intel_framebuffer_create(struct drm_device *dev, ...@@ -4934,40 +4925,40 @@ int intel_framebuffer_create(struct drm_device *dev,
} }
drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd); drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd);
intel_fb->obj = obj; intel_fb->obj = obj;
*fb = &intel_fb->base;
return 0; return 0;
} }
static struct drm_framebuffer * static struct drm_framebuffer *
intel_user_framebuffer_create(struct drm_device *dev, intel_user_framebuffer_create(struct drm_device *dev,
struct drm_file *filp, struct drm_file *filp,
struct drm_mode_fb_cmd *mode_cmd) struct drm_mode_fb_cmd *mode_cmd)
{ {
struct drm_gem_object *obj; struct drm_gem_object *obj;
struct drm_framebuffer *fb; struct intel_framebuffer *intel_fb;
int ret; int ret;
obj = drm_gem_object_lookup(dev, filp, mode_cmd->handle); obj = drm_gem_object_lookup(dev, filp, mode_cmd->handle);
if (!obj) if (!obj)
return NULL; return NULL;
ret = intel_framebuffer_create(dev, mode_cmd, &fb, obj); intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
if (!intel_fb)
return NULL;
ret = intel_framebuffer_init(dev, intel_fb,
mode_cmd, obj);
if (ret) { if (ret) {
drm_gem_object_unreference_unlocked(obj); drm_gem_object_unreference_unlocked(obj);
kfree(intel_fb);
return NULL; return NULL;
} }
return fb; return &intel_fb->base;
} }
static const struct drm_mode_config_funcs intel_mode_funcs = { static const struct drm_mode_config_funcs intel_mode_funcs = {
.fb_create = intel_user_framebuffer_create, .fb_create = intel_user_framebuffer_create,
.fb_changed = intelfb_probe,
}; };
static struct drm_gem_object * static struct drm_gem_object *
...@@ -5355,6 +5346,8 @@ void intel_modeset_cleanup(struct drm_device *dev) ...@@ -5355,6 +5346,8 @@ void intel_modeset_cleanup(struct drm_device *dev)
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
intel_fbdev_fini(dev);
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
/* Skip inactive CRTCs */ /* Skip inactive CRTCs */
if (!crtc->fb) if (!crtc->fb)
......
...@@ -206,9 +206,6 @@ extern void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder, ...@@ -206,9 +206,6 @@ extern void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB); extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB);
extern int intel_sdvo_supports_hotplug(struct drm_connector *connector); extern int intel_sdvo_supports_hotplug(struct drm_connector *connector);
extern void intel_sdvo_set_hotplug(struct drm_connector *connector, int enable); extern void intel_sdvo_set_hotplug(struct drm_connector *connector, int enable);
extern int intelfb_probe(struct drm_device *dev);
extern int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
extern int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc);
extern void intelfb_restore(void); extern void intelfb_restore(void);
extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
u16 blue, int regno); u16 blue, int regno);
...@@ -218,10 +215,12 @@ extern void intel_init_clock_gating(struct drm_device *dev); ...@@ -218,10 +215,12 @@ extern void intel_init_clock_gating(struct drm_device *dev);
extern void ironlake_enable_drps(struct drm_device *dev); extern void ironlake_enable_drps(struct drm_device *dev);
extern void ironlake_disable_drps(struct drm_device *dev); extern void ironlake_disable_drps(struct drm_device *dev);
extern int intel_framebuffer_create(struct drm_device *dev, extern int intel_framebuffer_init(struct drm_device *dev,
struct drm_mode_fb_cmd *mode_cmd, struct intel_framebuffer *ifb,
struct drm_framebuffer **fb, struct drm_mode_fb_cmd *mode_cmd,
struct drm_gem_object *obj); struct drm_gem_object *obj);
extern int intel_fbdev_init(struct drm_device *dev);
extern void intel_fbdev_fini(struct drm_device *dev);
extern void intel_prepare_page_flip(struct drm_device *dev, int plane); extern void intel_prepare_page_flip(struct drm_device *dev, int plane);
extern void intel_finish_page_flip(struct drm_device *dev, int pipe); extern void intel_finish_page_flip(struct drm_device *dev, int pipe);
...@@ -235,4 +234,6 @@ extern int intel_overlay_put_image(struct drm_device *dev, void *data, ...@@ -235,4 +234,6 @@ extern int intel_overlay_put_image(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
extern int intel_overlay_attrs(struct drm_device *dev, void *data, extern int intel_overlay_attrs(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
void intelfb_hotplug(struct drm_device *dev, bool polled);
#endif /* __INTEL_DRV_H__ */ #endif /* __INTEL_DRV_H__ */
...@@ -44,9 +44,10 @@ ...@@ -44,9 +44,10 @@
#include "i915_drm.h" #include "i915_drm.h"
#include "i915_drv.h" #include "i915_drv.h"
struct intelfb_par { struct intel_fbdev {
struct drm_fb_helper helper; struct drm_fb_helper helper;
struct intel_framebuffer *intel_fb; struct intel_framebuffer ifb;
struct list_head fbdev_list;
struct drm_display_mode *our_mode; struct drm_display_mode *our_mode;
}; };
...@@ -54,7 +55,6 @@ static struct fb_ops intelfb_ops = { ...@@ -54,7 +55,6 @@ static struct fb_ops intelfb_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.fb_check_var = drm_fb_helper_check_var, .fb_check_var = drm_fb_helper_check_var,
.fb_set_par = drm_fb_helper_set_par, .fb_set_par = drm_fb_helper_set_par,
.fb_setcolreg = drm_fb_helper_setcolreg,
.fb_fillrect = cfb_fillrect, .fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea, .fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit, .fb_imageblit = cfb_imageblit,
...@@ -63,62 +63,12 @@ static struct fb_ops intelfb_ops = { ...@@ -63,62 +63,12 @@ static struct fb_ops intelfb_ops = {
.fb_setcmap = drm_fb_helper_setcmap, .fb_setcmap = drm_fb_helper_setcmap,
}; };
static struct drm_fb_helper_funcs intel_fb_helper_funcs = { static int intelfb_create(struct intel_fbdev *ifbdev,
.gamma_set = intel_crtc_fb_gamma_set, struct drm_fb_helper_surface_size *sizes)
.gamma_get = intel_crtc_fb_gamma_get,
};
/**
* Currently it is assumed that the old framebuffer is reused.
*
* LOCKING
* caller should hold the mode config lock.
*
*/
int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc)
{
struct fb_info *info;
struct drm_framebuffer *fb;
struct drm_display_mode *mode = crtc->desired_mode;
fb = crtc->fb;
if (!fb)
return 1;
info = fb->fbdev;
if (!info)
return 1;
if (!mode)
return 1;
info->var.xres = mode->hdisplay;
info->var.right_margin = mode->hsync_start - mode->hdisplay;
info->var.hsync_len = mode->hsync_end - mode->hsync_start;
info->var.left_margin = mode->htotal - mode->hsync_end;
info->var.yres = mode->vdisplay;
info->var.lower_margin = mode->vsync_start - mode->vdisplay;
info->var.vsync_len = mode->vsync_end - mode->vsync_start;
info->var.upper_margin = mode->vtotal - mode->vsync_end;
info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100;
/* avoid overflow */
info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh;
return 0;
}
EXPORT_SYMBOL(intelfb_resize);
static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
uint32_t fb_height, uint32_t surface_width,
uint32_t surface_height,
uint32_t surface_depth, uint32_t surface_bpp,
struct drm_framebuffer **fb_p)
{ {
struct drm_device *dev = ifbdev->helper.dev;
struct fb_info *info; struct fb_info *info;
struct intelfb_par *par;
struct drm_framebuffer *fb; struct drm_framebuffer *fb;
struct intel_framebuffer *intel_fb;
struct drm_mode_fb_cmd mode_cmd; struct drm_mode_fb_cmd mode_cmd;
struct drm_gem_object *fbo = NULL; struct drm_gem_object *fbo = NULL;
struct drm_i915_gem_object *obj_priv; struct drm_i915_gem_object *obj_priv;
...@@ -126,15 +76,15 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width, ...@@ -126,15 +76,15 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
int size, ret, mmio_bar = IS_I9XX(dev) ? 0 : 1; int size, ret, mmio_bar = IS_I9XX(dev) ? 0 : 1;
/* we don't do packed 24bpp */ /* we don't do packed 24bpp */
if (surface_bpp == 24) if (sizes->surface_bpp == 24)
surface_bpp = 32; sizes->surface_bpp = 32;
mode_cmd.width = surface_width; mode_cmd.width = sizes->surface_width;
mode_cmd.height = surface_height; mode_cmd.height = sizes->surface_height;
mode_cmd.bpp = surface_bpp; mode_cmd.bpp = sizes->surface_bpp;
mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 1) / 8), 64); mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 1) / 8), 64);
mode_cmd.depth = surface_depth; mode_cmd.depth = sizes->surface_depth;
size = mode_cmd.pitch * mode_cmd.height; size = mode_cmd.pitch * mode_cmd.height;
size = ALIGN(size, PAGE_SIZE); size = ALIGN(size, PAGE_SIZE);
...@@ -157,39 +107,26 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width, ...@@ -157,39 +107,26 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
/* Flush everything out, we'll be doing GTT only from now on */ /* Flush everything out, we'll be doing GTT only from now on */
i915_gem_object_set_to_gtt_domain(fbo, 1); i915_gem_object_set_to_gtt_domain(fbo, 1);
ret = intel_framebuffer_create(dev, &mode_cmd, &fb, fbo); info = framebuffer_alloc(0, device);
if (ret) {
DRM_ERROR("failed to allocate fb.\n");
goto out_unpin;
}
list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list);
intel_fb = to_intel_framebuffer(fb);
*fb_p = fb;
info = framebuffer_alloc(sizeof(struct intelfb_par), device);
if (!info) { if (!info) {
ret = -ENOMEM; ret = -ENOMEM;
goto out_unpin; goto out_unpin;
} }
par = info->par; info->par = ifbdev;
par->helper.funcs = &intel_fb_helper_funcs; intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, fbo);
par->helper.dev = dev;
ret = drm_fb_helper_init_crtc_count(&par->helper, 2, fb = &ifbdev->ifb.base;
INTELFB_CONN_LIMIT);
if (ret) ifbdev->helper.fb = fb;
goto out_unref; ifbdev->helper.fbdev = info;
strcpy(info->fix.id, "inteldrmfb"); strcpy(info->fix.id, "inteldrmfb");
info->flags = FBINFO_DEFAULT; info->flags = FBINFO_DEFAULT;
info->fbops = &intelfb_ops; info->fbops = &intelfb_ops;
/* setup aperture base/size for vesafb takeover */ /* setup aperture base/size for vesafb takeover */
info->aperture_base = dev->mode_config.fb_base; info->aperture_base = dev->mode_config.fb_base;
if (IS_I9XX(dev)) if (IS_I9XX(dev))
...@@ -208,12 +145,18 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width, ...@@ -208,12 +145,18 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
ret = -ENOSPC; ret = -ENOSPC;
goto out_unpin; goto out_unpin;
} }
ret = fb_alloc_cmap(&info->cmap, 256, 0);
if (ret) {
ret = -ENOMEM;
goto out_unpin;
}
info->screen_size = size; info->screen_size = size;
// memset(info->screen_base, 0, size); // memset(info->screen_base, 0, size);
drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); drm_fb_helper_fill_fix(info, fb->pitch, fb->depth);
drm_fb_helper_fill_var(info, fb, fb_width, fb_height); drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height);
/* FIXME: we really shouldn't expose mmio space at all */ /* FIXME: we really shouldn't expose mmio space at all */
info->fix.mmio_start = pci_resource_start(dev->pdev, mmio_bar); info->fix.mmio_start = pci_resource_start(dev->pdev, mmio_bar);
...@@ -225,14 +168,10 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width, ...@@ -225,14 +168,10 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
info->pixmap.flags = FB_PIXMAP_SYSTEM; info->pixmap.flags = FB_PIXMAP_SYSTEM;
info->pixmap.scan_align = 1; info->pixmap.scan_align = 1;
fb->fbdev = info;
par->intel_fb = intel_fb;
/* To allow resizeing without swapping buffers */
DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n", DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n",
intel_fb->base.width, intel_fb->base.height, fb->width, fb->height,
obj_priv->gtt_offset, fbo); obj_priv->gtt_offset, fbo);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
vga_switcheroo_client_fb_set(dev->pdev, info); vga_switcheroo_client_fb_set(dev->pdev, info);
...@@ -247,35 +186,86 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width, ...@@ -247,35 +186,86 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
return ret; return ret;
} }
int intelfb_probe(struct drm_device *dev) 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; int ret;
DRM_DEBUG_KMS("\n"); if (!helper->fb) {
ret = drm_fb_helper_single_fb_probe(dev, 32, intelfb_create); ret = intelfb_create(ifbdev, sizes);
return ret; if (ret)
return ret;
new_fb = 1;
}
return new_fb;
} }
EXPORT_SYMBOL(intelfb_probe);
int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) void intelfb_hotplug(struct drm_device *dev, bool polled)
{ {
struct fb_info *info; drm_i915_private_t *dev_priv = dev->dev_private;
drm_helper_fb_hpd_irq_event(&dev_priv->fbdev->helper);
}
if (!fb) static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
return -EINVAL; .gamma_set = intel_crtc_fb_gamma_set,
.gamma_get = intel_crtc_fb_gamma_get,
.fb_probe = intel_fb_find_or_create_single,
};
info = fb->fbdev; int intel_fbdev_destroy(struct drm_device *dev,
struct intel_fbdev *ifbdev)
{
struct fb_info *info;
struct intel_framebuffer *ifb = &ifbdev->ifb;
if (info) { if (ifbdev->helper.fbdev) {
struct intelfb_par *par = info->par; info = ifbdev->helper.fbdev;
unregister_framebuffer(info); unregister_framebuffer(info);
iounmap(info->screen_base); iounmap(info->screen_base);
if (info->par) if (info->cmap.len)
drm_fb_helper_free(&par->helper); fb_dealloc_cmap(&info->cmap);
framebuffer_release(info); framebuffer_release(info);
} }
drm_fb_helper_fini(&ifbdev->helper);
drm_framebuffer_cleanup(&ifb->base);
if (ifb->obj)
drm_gem_object_unreference_unlocked(ifb->obj);
return 0;
}
int intel_fbdev_init(struct drm_device *dev)
{
struct intel_fbdev *ifbdev;
drm_i915_private_t *dev_priv = dev->dev_private;
ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL);
if (!ifbdev)
return -ENOMEM;
dev_priv->fbdev = ifbdev;
ifbdev->helper.funcs = &intel_fb_helper_funcs;
drm_fb_helper_init(dev, &ifbdev->helper, 2,
INTELFB_CONN_LIMIT, false);
drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
drm_fb_helper_initial_config(&ifbdev->helper, 32);
return 0; return 0;
} }
EXPORT_SYMBOL(intelfb_remove);
void intel_fbdev_fini(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
if (!dev_priv->fbdev)
return;
intel_fbdev_destroy(dev, dev_priv->fbdev);
kfree(dev_priv->fbdev);
dev_priv->fbdev = NULL;
}
MODULE_LICENSE("GPL and additional rights"); MODULE_LICENSE("GPL and additional rights");
...@@ -34,10 +34,6 @@ static void ...@@ -34,10 +34,6 @@ static void
nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb) nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb)
{ {
struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb); struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb);
struct drm_device *dev = drm_fb->dev;
if (drm_fb->fbdev)
nouveau_fbcon_remove(dev, drm_fb);
if (fb->nvbo) if (fb->nvbo)
drm_gem_object_unreference_unlocked(fb->nvbo->gem); drm_gem_object_unreference_unlocked(fb->nvbo->gem);
...@@ -61,27 +57,20 @@ static const struct drm_framebuffer_funcs nouveau_framebuffer_funcs = { ...@@ -61,27 +57,20 @@ static const struct drm_framebuffer_funcs nouveau_framebuffer_funcs = {
.create_handle = nouveau_user_framebuffer_create_handle, .create_handle = nouveau_user_framebuffer_create_handle,
}; };
struct drm_framebuffer * int
nouveau_framebuffer_create(struct drm_device *dev, struct nouveau_bo *nvbo, nouveau_framebuffer_init(struct drm_device *dev, struct nouveau_framebuffer *nouveau_fb,
struct drm_mode_fb_cmd *mode_cmd) struct drm_mode_fb_cmd *mode_cmd, struct nouveau_bo *nvbo)
{ {
struct nouveau_framebuffer *fb;
int ret; int ret;
fb = kzalloc(sizeof(struct nouveau_framebuffer), GFP_KERNEL); ret = drm_framebuffer_init(dev, &nouveau_fb->base, &nouveau_framebuffer_funcs);
if (!fb)
return NULL;
ret = drm_framebuffer_init(dev, &fb->base, &nouveau_framebuffer_funcs);
if (ret) { if (ret) {
kfree(fb); return ret;
return NULL;
} }
drm_helper_mode_fill_fb_struct(&fb->base, mode_cmd); drm_helper_mode_fill_fb_struct(&nouveau_fb->base, mode_cmd);
nouveau_fb->nvbo = nvbo;
fb->nvbo = nvbo; return 0;
return &fb->base;
} }
static struct drm_framebuffer * static struct drm_framebuffer *
...@@ -89,24 +78,28 @@ nouveau_user_framebuffer_create(struct drm_device *dev, ...@@ -89,24 +78,28 @@ nouveau_user_framebuffer_create(struct drm_device *dev,
struct drm_file *file_priv, struct drm_file *file_priv,
struct drm_mode_fb_cmd *mode_cmd) struct drm_mode_fb_cmd *mode_cmd)
{ {
struct drm_framebuffer *fb; struct nouveau_framebuffer *nouveau_fb;
struct drm_gem_object *gem; struct drm_gem_object *gem;
int ret;
gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle); gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle);
if (!gem) if (!gem)
return NULL; return NULL;
fb = nouveau_framebuffer_create(dev, nouveau_gem_object(gem), mode_cmd); nouveau_fb = kzalloc(sizeof(struct nouveau_framebuffer), GFP_KERNEL);
if (!fb) { if (!nouveau_fb)
return NULL;
ret = nouveau_framebuffer_init(dev, nouveau_fb, mode_cmd, nouveau_gem_object(gem));
if (ret) {
drm_gem_object_unreference(gem); drm_gem_object_unreference(gem);
return NULL; return NULL;
} }
return fb; return &nouveau_fb->base;
} }
const struct drm_mode_config_funcs nouveau_mode_config_funcs = { const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
.fb_create = nouveau_user_framebuffer_create, .fb_create = nouveau_user_framebuffer_create,
.fb_changed = nouveau_fbcon_probe,
}; };
...@@ -153,7 +153,6 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state) ...@@ -153,7 +153,6 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
struct nouveau_channel *chan; struct nouveau_channel *chan;
struct drm_crtc *crtc; struct drm_crtc *crtc;
uint32_t fbdev_flags;
int ret, i; int ret, i;
if (!drm_core_check_feature(dev, DRIVER_MODESET)) if (!drm_core_check_feature(dev, DRIVER_MODESET))
...@@ -163,8 +162,7 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state) ...@@ -163,8 +162,7 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
return 0; return 0;
NV_INFO(dev, "Disabling fbcon acceleration...\n"); NV_INFO(dev, "Disabling fbcon acceleration...\n");
fbdev_flags = dev_priv->fbdev_info->flags; nouveau_fbcon_save_disable_accel(dev);
dev_priv->fbdev_info->flags |= FBINFO_HWACCEL_DISABLED;
NV_INFO(dev, "Unpinning framebuffer(s)...\n"); NV_INFO(dev, "Unpinning framebuffer(s)...\n");
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
...@@ -230,9 +228,9 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state) ...@@ -230,9 +228,9 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
} }
acquire_console_sem(); acquire_console_sem();
fb_set_suspend(dev_priv->fbdev_info, 1); nouveau_fbcon_set_suspend(dev, 1);
release_console_sem(); release_console_sem();
dev_priv->fbdev_info->flags = fbdev_flags; nouveau_fbcon_restore_accel(dev);
return 0; return 0;
out_abort: out_abort:
...@@ -250,14 +248,12 @@ nouveau_pci_resume(struct pci_dev *pdev) ...@@ -250,14 +248,12 @@ nouveau_pci_resume(struct pci_dev *pdev)
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_engine *engine = &dev_priv->engine; struct nouveau_engine *engine = &dev_priv->engine;
struct drm_crtc *crtc; struct drm_crtc *crtc;
uint32_t fbdev_flags;
int ret, i; int ret, i;
if (!drm_core_check_feature(dev, DRIVER_MODESET)) if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -ENODEV; return -ENODEV;
fbdev_flags = dev_priv->fbdev_info->flags; nouveau_fbcon_save_disable_accel(dev);
dev_priv->fbdev_info->flags |= FBINFO_HWACCEL_DISABLED;
NV_INFO(dev, "We're back, enabling device...\n"); NV_INFO(dev, "We're back, enabling device...\n");
pci_set_power_state(pdev, PCI_D0); pci_set_power_state(pdev, PCI_D0);
...@@ -332,13 +328,14 @@ nouveau_pci_resume(struct pci_dev *pdev) ...@@ -332,13 +328,14 @@ nouveau_pci_resume(struct pci_dev *pdev)
} }
acquire_console_sem(); acquire_console_sem();
fb_set_suspend(dev_priv->fbdev_info, 0); nouveau_fbcon_set_suspend(dev, 0);
release_console_sem(); release_console_sem();
nouveau_fbcon_zfill(dev); nouveau_fbcon_zfill_all(dev);
drm_helper_resume_force_mode(dev); drm_helper_resume_force_mode(dev);
dev_priv->fbdev_info->flags = fbdev_flags;
nouveau_fbcon_restore_accel(dev);
return 0; return 0;
} }
......
...@@ -535,6 +535,7 @@ struct drm_nouveau_private { ...@@ -535,6 +535,7 @@ struct drm_nouveau_private {
struct fb_info *fbdev_info; struct fb_info *fbdev_info;
int fifo_alloc_count;
struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR]; struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR];
struct nouveau_engine engine; struct nouveau_engine engine;
...@@ -621,6 +622,8 @@ struct drm_nouveau_private { ...@@ -621,6 +622,8 @@ struct drm_nouveau_private {
struct { struct {
struct dentry *channel_root; struct dentry *channel_root;
} debugfs; } debugfs;
struct nouveau_fbdev *nfbdev;
}; };
static inline struct drm_nouveau_private * static inline struct drm_nouveau_private *
......
...@@ -40,8 +40,6 @@ nouveau_framebuffer(struct drm_framebuffer *fb) ...@@ -40,8 +40,6 @@ nouveau_framebuffer(struct drm_framebuffer *fb)
extern const struct drm_mode_config_funcs nouveau_mode_config_funcs; extern const struct drm_mode_config_funcs nouveau_mode_config_funcs;
struct drm_framebuffer * int nouveau_framebuffer_init(struct drm_device *dev, struct nouveau_framebuffer *nouveau_fb,
nouveau_framebuffer_create(struct drm_device *, struct nouveau_bo *, struct drm_mode_fb_cmd *mode_cmd, struct nouveau_bo *nvbo);
struct drm_mode_fb_cmd *);
#endif /* __NOUVEAU_FB_H__ */ #endif /* __NOUVEAU_FB_H__ */
...@@ -52,8 +52,8 @@ ...@@ -52,8 +52,8 @@
static int static int
nouveau_fbcon_sync(struct fb_info *info) nouveau_fbcon_sync(struct fb_info *info)
{ {
struct nouveau_fbcon_par *par = info->par; struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = par->dev; struct drm_device *dev = nfbdev->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = dev_priv->channel; struct nouveau_channel *chan = dev_priv->channel;
int ret, i; int ret, i;
...@@ -97,7 +97,6 @@ static struct fb_ops nouveau_fbcon_ops = { ...@@ -97,7 +97,6 @@ static struct fb_ops nouveau_fbcon_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.fb_check_var = drm_fb_helper_check_var, .fb_check_var = drm_fb_helper_check_var,
.fb_set_par = drm_fb_helper_set_par, .fb_set_par = drm_fb_helper_set_par,
.fb_setcolreg = drm_fb_helper_setcolreg,
.fb_fillrect = cfb_fillrect, .fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea, .fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit, .fb_imageblit = cfb_imageblit,
...@@ -111,7 +110,6 @@ static struct fb_ops nv04_fbcon_ops = { ...@@ -111,7 +110,6 @@ static struct fb_ops nv04_fbcon_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.fb_check_var = drm_fb_helper_check_var, .fb_check_var = drm_fb_helper_check_var,
.fb_set_par = drm_fb_helper_set_par, .fb_set_par = drm_fb_helper_set_par,
.fb_setcolreg = drm_fb_helper_setcolreg,
.fb_fillrect = nv04_fbcon_fillrect, .fb_fillrect = nv04_fbcon_fillrect,
.fb_copyarea = nv04_fbcon_copyarea, .fb_copyarea = nv04_fbcon_copyarea,
.fb_imageblit = nv04_fbcon_imageblit, .fb_imageblit = nv04_fbcon_imageblit,
...@@ -125,7 +123,6 @@ static struct fb_ops nv50_fbcon_ops = { ...@@ -125,7 +123,6 @@ static struct fb_ops nv50_fbcon_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.fb_check_var = drm_fb_helper_check_var, .fb_check_var = drm_fb_helper_check_var,
.fb_set_par = drm_fb_helper_set_par, .fb_set_par = drm_fb_helper_set_par,
.fb_setcolreg = drm_fb_helper_setcolreg,
.fb_fillrect = nv50_fbcon_fillrect, .fb_fillrect = nv50_fbcon_fillrect,
.fb_copyarea = nv50_fbcon_copyarea, .fb_copyarea = nv50_fbcon_copyarea,
.fb_imageblit = nv50_fbcon_imageblit, .fb_imageblit = nv50_fbcon_imageblit,
...@@ -155,11 +152,6 @@ static void nouveau_fbcon_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, ...@@ -155,11 +152,6 @@ static void nouveau_fbcon_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
*blue = nv_crtc->lut.b[regno]; *blue = nv_crtc->lut.b[regno];
} }
static struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = {
.gamma_set = nouveau_fbcon_gamma_set,
.gamma_get = nouveau_fbcon_gamma_get
};
#if defined(__i386__) || defined(__x86_64__) #if defined(__i386__) || defined(__x86_64__)
static bool static bool
nouveau_fbcon_has_vesafb_or_efifb(struct drm_device *dev) nouveau_fbcon_has_vesafb_or_efifb(struct drm_device *dev)
...@@ -198,11 +190,10 @@ nouveau_fbcon_has_vesafb_or_efifb(struct drm_device *dev) ...@@ -198,11 +190,10 @@ nouveau_fbcon_has_vesafb_or_efifb(struct drm_device *dev)
} }
#endif #endif
void static void
nouveau_fbcon_zfill(struct drm_device *dev) nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbdev *nfbdev)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct fb_info *info = nfbdev->helper.fbdev;
struct fb_info *info = dev_priv->fbdev_info;
struct fb_fillrect rect; struct fb_fillrect rect;
/* Clear the entire fbcon. The drm will program every connector /* Clear the entire fbcon. The drm will program every connector
...@@ -218,14 +209,12 @@ nouveau_fbcon_zfill(struct drm_device *dev) ...@@ -218,14 +209,12 @@ nouveau_fbcon_zfill(struct drm_device *dev)
} }
static int static int
nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
uint32_t fb_height, uint32_t surface_width, struct drm_fb_helper_surface_size *sizes)
uint32_t surface_height, uint32_t surface_depth,
uint32_t surface_bpp, struct drm_framebuffer **pfb)
{ {
struct drm_device *dev = nfbdev->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct fb_info *info; struct fb_info *info;
struct nouveau_fbcon_par *par;
struct drm_framebuffer *fb; struct drm_framebuffer *fb;
struct nouveau_framebuffer *nouveau_fb; struct nouveau_framebuffer *nouveau_fb;
struct nouveau_bo *nvbo; struct nouveau_bo *nvbo;
...@@ -233,13 +222,13 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, ...@@ -233,13 +222,13 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
struct device *device = &dev->pdev->dev; struct device *device = &dev->pdev->dev;
int size, ret; int size, ret;
mode_cmd.width = surface_width; mode_cmd.width = sizes->surface_width;
mode_cmd.height = surface_height; mode_cmd.height = sizes->surface_height;
mode_cmd.bpp = surface_bpp; mode_cmd.bpp = sizes->surface_bpp;
mode_cmd.pitch = mode_cmd.width * (mode_cmd.bpp >> 3); mode_cmd.pitch = mode_cmd.width * (mode_cmd.bpp >> 3);
mode_cmd.pitch = roundup(mode_cmd.pitch, 256); mode_cmd.pitch = roundup(mode_cmd.pitch, 256);
mode_cmd.depth = surface_depth; mode_cmd.depth = sizes->surface_depth;
size = mode_cmd.pitch * mode_cmd.height; size = mode_cmd.pitch * mode_cmd.height;
size = roundup(size, PAGE_SIZE); size = roundup(size, PAGE_SIZE);
...@@ -268,31 +257,28 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, ...@@ -268,31 +257,28 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
fb = nouveau_framebuffer_create(dev, nvbo, &mode_cmd); info = framebuffer_alloc(0, device);
if (!fb) { if (!info) {
ret = -ENOMEM; ret = -ENOMEM;
NV_ERROR(dev, "failed to allocate fb.\n");
goto out_unref; goto out_unref;
} }
list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list); ret = fb_alloc_cmap(&info->cmap, 256, 0);
if (ret) {
nouveau_fb = nouveau_framebuffer(fb);
*pfb = fb;
info = framebuffer_alloc(sizeof(struct nouveau_fbcon_par), device);
if (!info) {
ret = -ENOMEM; ret = -ENOMEM;
goto out_unref; goto out_unref;
} }
par = info->par; info->par = nfbdev;
par->helper.funcs = &nouveau_fbcon_helper_funcs;
par->helper.dev = dev; nouveau_framebuffer_init(dev, &nfbdev->nouveau_fb, &mode_cmd, nvbo);
ret = drm_fb_helper_init_crtc_count(&par->helper, 2, 4);
if (ret) nouveau_fb = &nfbdev->nouveau_fb;
goto out_unref; fb = &nouveau_fb->base;
dev_priv->fbdev_info = info;
/* setup helper */
nfbdev->helper.fb = fb;
nfbdev->helper.fbdev = info;
strcpy(info->fix.id, "nouveaufb"); strcpy(info->fix.id, "nouveaufb");
if (nouveau_nofbaccel) if (nouveau_nofbaccel)
...@@ -310,7 +296,7 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, ...@@ -310,7 +296,7 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
info->screen_size = size; info->screen_size = size;
drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); drm_fb_helper_fill_fix(info, fb->pitch, fb->depth);
drm_fb_helper_fill_var(info, fb, fb_width, fb_height); drm_fb_helper_fill_var(info, &nfbdev->helper, sizes->fb_width, sizes->fb_height);
/* FIXME: we really shouldn't expose mmio space at all */ /* FIXME: we really shouldn't expose mmio space at all */
info->fix.mmio_start = pci_resource_start(dev->pdev, 1); info->fix.mmio_start = pci_resource_start(dev->pdev, 1);
...@@ -343,11 +329,6 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, ...@@ -343,11 +329,6 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
info->pixmap.flags = FB_PIXMAP_SYSTEM; info->pixmap.flags = FB_PIXMAP_SYSTEM;
info->pixmap.scan_align = 1; info->pixmap.scan_align = 1;
fb->fbdev = info;
par->nouveau_fb = nouveau_fb;
par->dev = dev;
if (dev_priv->channel && !nouveau_nofbaccel) { if (dev_priv->channel && !nouveau_nofbaccel) {
switch (dev_priv->card_type) { switch (dev_priv->card_type) {
case NV_50: case NV_50:
...@@ -361,7 +342,7 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, ...@@ -361,7 +342,7 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
}; };
} }
nouveau_fbcon_zfill(dev); nouveau_fbcon_zfill(dev, nfbdev);
/* To allow resizeing without swapping buffers */ /* To allow resizeing without swapping buffers */
NV_INFO(dev, "allocated %dx%d fb: 0x%lx, bo %p\n", NV_INFO(dev, "allocated %dx%d fb: 0x%lx, bo %p\n",
...@@ -379,44 +360,129 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, ...@@ -379,44 +360,129 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
return ret; return ret;
} }
int static int
nouveau_fbcon_probe(struct drm_device *dev) nouveau_fbcon_find_or_create_single(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes)
{ {
NV_DEBUG_KMS(dev, "\n"); struct nouveau_fbdev *nfbdev = (struct nouveau_fbdev *)helper;
int new_fb = 0;
int ret;
if (!helper->fb) {
ret = nouveau_fbcon_create(nfbdev, sizes);
if (ret)
return ret;
new_fb = 1;
}
return new_fb;
}
return drm_fb_helper_single_fb_probe(dev, 32, nouveau_fbcon_create); void nouveau_fbcon_hotplug(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
drm_helper_fb_hpd_irq_event(&dev_priv->nfbdev->helper);
}
static void nouveau_fbcon_output_status_changed(struct drm_fb_helper *fb_helper)
{
drm_helper_fb_hotplug_event(fb_helper, true);
} }
int int
nouveau_fbcon_remove(struct drm_device *dev, struct drm_framebuffer *fb) nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *nfbdev)
{ {
struct nouveau_framebuffer *nouveau_fb = nouveau_framebuffer(fb); struct nouveau_framebuffer *nouveau_fb = &nfbdev->nouveau_fb;
struct fb_info *info; struct fb_info *info;
if (!fb) if (nfbdev->helper.fbdev) {
return -EINVAL; info = nfbdev->helper.fbdev;
info = fb->fbdev;
if (info) {
struct nouveau_fbcon_par *par = info->par;
unregister_framebuffer(info); unregister_framebuffer(info);
if (info->cmap.len)
fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);
}
if (nouveau_fb->nvbo) {
nouveau_bo_unmap(nouveau_fb->nvbo); nouveau_bo_unmap(nouveau_fb->nvbo);
drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem); drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem);
nouveau_fb->nvbo = NULL; nouveau_fb->nvbo = NULL;
if (par)
drm_fb_helper_free(&par->helper);
framebuffer_release(info);
} }
drm_fb_helper_fini(&nfbdev->helper);
drm_framebuffer_cleanup(&nouveau_fb->base);
return 0; return 0;
} }
void nouveau_fbcon_gpu_lockup(struct fb_info *info) void nouveau_fbcon_gpu_lockup(struct fb_info *info)
{ {
struct nouveau_fbcon_par *par = info->par; struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = par->dev; struct drm_device *dev = nfbdev->dev;
NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); NV_ERROR(dev, "GPU lockup - switching to software fbcon\n");
info->flags |= FBINFO_HWACCEL_DISABLED; info->flags |= FBINFO_HWACCEL_DISABLED;
} }
static struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = {
.gamma_set = nouveau_fbcon_gamma_set,
.gamma_get = nouveau_fbcon_gamma_get,
.fb_probe = nouveau_fbcon_find_or_create_single,
.fb_output_status_changed = nouveau_fbcon_output_status_changed,
};
int nouveau_fbcon_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_fbdev *nfbdev;
nfbdev = kzalloc(sizeof(struct nouveau_fbdev), GFP_KERNEL);
if (!nfbdev)
return -ENOMEM;
nfbdev->dev = dev;
dev_priv->nfbdev = nfbdev;
nfbdev->helper.funcs = &nouveau_fbcon_helper_funcs;
drm_fb_helper_init(dev, &nfbdev->helper,
2, 4, true);
drm_fb_helper_single_add_all_connectors(&nfbdev->helper);
drm_fb_helper_initial_config(&nfbdev->helper, 32);
return 0;
}
void nouveau_fbcon_fini(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
if (!dev_priv->nfbdev)
return;
nouveau_fbcon_destroy(dev, dev_priv->nfbdev);
kfree(dev_priv->nfbdev);
dev_priv->nfbdev = NULL;
}
void nouveau_fbcon_save_disable_accel(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
dev_priv->nfbdev->saved_flags = dev_priv->nfbdev->helper.fbdev->flags;
dev_priv->nfbdev->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED;
}
void nouveau_fbcon_restore_accel(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
dev_priv->nfbdev->helper.fbdev->flags = dev_priv->nfbdev->saved_flags;
}
void nouveau_fbcon_set_suspend(struct drm_device *dev, int state)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
fb_set_suspend(dev_priv->nfbdev->helper.fbdev, state);
}
void nouveau_fbcon_zfill_all(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
nouveau_fbcon_zfill(dev, dev_priv->nfbdev);
}
...@@ -29,16 +29,16 @@ ...@@ -29,16 +29,16 @@
#include "drm_fb_helper.h" #include "drm_fb_helper.h"
struct nouveau_fbcon_par { #include "nouveau_fb.h"
struct nouveau_fbdev {
struct drm_fb_helper helper; struct drm_fb_helper helper;
struct nouveau_framebuffer nouveau_fb;
struct list_head fbdev_list;
struct drm_device *dev; struct drm_device *dev;
struct nouveau_framebuffer *nouveau_fb; unsigned int saved_flags;
}; };
int nouveau_fbcon_probe(struct drm_device *dev);
int nouveau_fbcon_remove(struct drm_device *dev, struct drm_framebuffer *fb);
void nouveau_fbcon_restore(void); void nouveau_fbcon_restore(void);
void nouveau_fbcon_zfill(struct drm_device *dev);
void nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); void nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
void nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); void nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
...@@ -50,5 +50,14 @@ void nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); ...@@ -50,5 +50,14 @@ void nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
int nv50_fbcon_accel_init(struct fb_info *info); int nv50_fbcon_accel_init(struct fb_info *info);
void nouveau_fbcon_gpu_lockup(struct fb_info *info); void nouveau_fbcon_gpu_lockup(struct fb_info *info);
int nouveau_fbcon_init(struct drm_device *dev);
void nouveau_fbcon_fini(struct drm_device *dev);
void nouveau_fbcon_set_suspend(struct drm_device *dev, int state);
void nouveau_fbcon_zfill_all(struct drm_device *dev);
void nouveau_fbcon_save_disable_accel(struct drm_device *dev);
void nouveau_fbcon_restore_accel(struct drm_device *dev);
void nouveau_fbcon_hotplug(struct drm_device *dev);
#endif /* __NV50_FBCON_H__ */ #endif /* __NV50_FBCON_H__ */
...@@ -1204,7 +1204,7 @@ nouveau_irq_handler(DRM_IRQ_ARGS) ...@@ -1204,7 +1204,7 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
{ {
struct drm_device *dev = (struct drm_device *)arg; struct drm_device *dev = (struct drm_device *)arg;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t status, fbdev_flags = 0; uint32_t status;
unsigned long flags; unsigned long flags;
status = nv_rd32(dev, NV03_PMC_INTR_0); status = nv_rd32(dev, NV03_PMC_INTR_0);
...@@ -1213,11 +1213,6 @@ nouveau_irq_handler(DRM_IRQ_ARGS) ...@@ -1213,11 +1213,6 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
spin_lock_irqsave(&dev_priv->context_switch_lock, flags); spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
if (dev_priv->fbdev_info) {
fbdev_flags = dev_priv->fbdev_info->flags;
dev_priv->fbdev_info->flags |= FBINFO_HWACCEL_DISABLED;
}
if (status & NV_PMC_INTR_0_PFIFO_PENDING) { if (status & NV_PMC_INTR_0_PFIFO_PENDING) {
nouveau_fifo_irq_handler(dev); nouveau_fifo_irq_handler(dev);
status &= ~NV_PMC_INTR_0_PFIFO_PENDING; status &= ~NV_PMC_INTR_0_PFIFO_PENDING;
...@@ -1247,9 +1242,6 @@ nouveau_irq_handler(DRM_IRQ_ARGS) ...@@ -1247,9 +1242,6 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
if (status) if (status)
NV_ERROR(dev, "Unhandled PMC INTR status bits 0x%08x\n", status); NV_ERROR(dev, "Unhandled PMC INTR status bits 0x%08x\n", status);
if (dev_priv->fbdev_info)
dev_priv->fbdev_info->flags = fbdev_flags;
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
return IRQ_HANDLED; return IRQ_HANDLED;
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "nouveau_drv.h" #include "nouveau_drv.h"
#include "nouveau_drm.h" #include "nouveau_drm.h"
#include "nouveau_fbcon.h"
#include "nv50_display.h" #include "nv50_display.h"
static void nouveau_stub_takedown(struct drm_device *dev) {} static void nouveau_stub_takedown(struct drm_device *dev) {}
...@@ -516,7 +517,7 @@ nouveau_card_init(struct drm_device *dev) ...@@ -516,7 +517,7 @@ nouveau_card_init(struct drm_device *dev)
dev_priv->init_state = NOUVEAU_CARD_INIT_DONE; dev_priv->init_state = NOUVEAU_CARD_INIT_DONE;
if (drm_core_check_feature(dev, DRIVER_MODESET)) if (drm_core_check_feature(dev, DRIVER_MODESET))
drm_helper_initial_config(dev); nouveau_fbcon_init(dev);
return 0; return 0;
...@@ -563,6 +564,7 @@ static void nouveau_card_takedown(struct drm_device *dev) ...@@ -563,6 +564,7 @@ static void nouveau_card_takedown(struct drm_device *dev)
NV_DEBUG(dev, "prev state = %d\n", dev_priv->init_state); NV_DEBUG(dev, "prev state = %d\n", dev_priv->init_state);
if (dev_priv->init_state != NOUVEAU_CARD_INIT_DOWN) { if (dev_priv->init_state != NOUVEAU_CARD_INIT_DOWN) {
nouveau_backlight_exit(dev); nouveau_backlight_exit(dev);
if (dev_priv->channel) { if (dev_priv->channel) {
...@@ -794,6 +796,7 @@ int nouveau_unload(struct drm_device *dev) ...@@ -794,6 +796,7 @@ int nouveau_unload(struct drm_device *dev)
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
if (drm_core_check_feature(dev, DRIVER_MODESET)) { if (drm_core_check_feature(dev, DRIVER_MODESET)) {
nouveau_fbcon_fini(dev);
if (dev_priv->card_type >= NV_50) if (dev_priv->card_type >= NV_50)
nv50_display_destroy(dev); nv50_display_destroy(dev);
else else
......
...@@ -30,8 +30,8 @@ ...@@ -30,8 +30,8 @@
void void
nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
{ {
struct nouveau_fbcon_par *par = info->par; struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = par->dev; struct drm_device *dev = nfbdev->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = dev_priv->channel; struct nouveau_channel *chan = dev_priv->channel;
...@@ -57,8 +57,8 @@ nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) ...@@ -57,8 +57,8 @@ nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
void void
nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{ {
struct nouveau_fbcon_par *par = info->par; struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = par->dev; struct drm_device *dev = nfbdev->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = dev_priv->channel; struct nouveau_channel *chan = dev_priv->channel;
...@@ -91,8 +91,8 @@ nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) ...@@ -91,8 +91,8 @@ nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
void void
nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
{ {
struct nouveau_fbcon_par *par = info->par; struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = par->dev; struct drm_device *dev = nfbdev->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = dev_priv->channel; struct nouveau_channel *chan = dev_priv->channel;
uint32_t fg; uint32_t fg;
...@@ -179,8 +179,8 @@ nv04_fbcon_grobj_new(struct drm_device *dev, int class, uint32_t handle) ...@@ -179,8 +179,8 @@ nv04_fbcon_grobj_new(struct drm_device *dev, int class, uint32_t handle)
int int
nv04_fbcon_accel_init(struct fb_info *info) nv04_fbcon_accel_init(struct fb_info *info)
{ {
struct nouveau_fbcon_par *par = info->par; struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = par->dev; struct drm_device *dev = nfbdev->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = dev_priv->channel; struct nouveau_channel *chan = dev_priv->channel;
const int sub = NvSubCtxSurf2D; const int sub = NvSubCtxSurf2D;
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "nouveau_encoder.h" #include "nouveau_encoder.h"
#include "nouveau_connector.h" #include "nouveau_connector.h"
#include "nouveau_fb.h" #include "nouveau_fb.h"
#include "nouveau_fbcon.h"
#include "drm_crtc_helper.h" #include "drm_crtc_helper.h"
static void static void
...@@ -945,6 +946,8 @@ nv50_display_irq_hotplug_bh(struct work_struct *work) ...@@ -945,6 +946,8 @@ nv50_display_irq_hotplug_bh(struct work_struct *work)
nv_wr32(dev, 0xe054, nv_rd32(dev, 0xe054)); nv_wr32(dev, 0xe054, nv_rd32(dev, 0xe054));
if (dev_priv->chipset >= 0x90) if (dev_priv->chipset >= 0x90)
nv_wr32(dev, 0xe074, nv_rd32(dev, 0xe074)); nv_wr32(dev, 0xe074, nv_rd32(dev, 0xe074));
nouveau_fbcon_hotplug(dev);
} }
void void
......
...@@ -6,8 +6,8 @@ ...@@ -6,8 +6,8 @@
void void
nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{ {
struct nouveau_fbcon_par *par = info->par; struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = par->dev; struct drm_device *dev = nfbdev->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = dev_priv->channel; struct nouveau_channel *chan = dev_priv->channel;
...@@ -49,8 +49,8 @@ nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) ...@@ -49,8 +49,8 @@ nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
void void
nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
{ {
struct nouveau_fbcon_par *par = info->par; struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = par->dev; struct drm_device *dev = nfbdev->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = dev_priv->channel; struct nouveau_channel *chan = dev_priv->channel;
...@@ -84,8 +84,8 @@ nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) ...@@ -84,8 +84,8 @@ nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
void void
nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
{ {
struct nouveau_fbcon_par *par = info->par; struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = par->dev; struct drm_device *dev = nfbdev->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = dev_priv->channel; struct nouveau_channel *chan = dev_priv->channel;
uint32_t width, dwords, *data = (uint32_t *)image->data; uint32_t width, dwords, *data = (uint32_t *)image->data;
...@@ -152,8 +152,8 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) ...@@ -152,8 +152,8 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
int int
nv50_fbcon_accel_init(struct fb_info *info) nv50_fbcon_accel_init(struct fb_info *info)
{ {
struct nouveau_fbcon_par *par = info->par; struct nouveau_fbdev *nfbdev = info->par;
struct drm_device *dev = par->dev; struct drm_device *dev = nfbdev->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = dev_priv->channel; struct nouveau_channel *chan = dev_priv->channel;
struct nouveau_gpuobj *eng2d = NULL; struct nouveau_gpuobj *eng2d = NULL;
......
...@@ -938,9 +938,6 @@ struct radeon_device { ...@@ -938,9 +938,6 @@ struct radeon_device {
bool is_atom_bios; bool is_atom_bios;
uint16_t bios_header_start; uint16_t bios_header_start;
struct radeon_bo *stollen_vga_memory; struct radeon_bo *stollen_vga_memory;
struct fb_info *fbdev_info;
struct radeon_bo *fbdev_rbo;
struct radeon_framebuffer *fbdev_rfb;
/* Register mmio */ /* Register mmio */
resource_size_t rmmio_base; resource_size_t rmmio_base;
resource_size_t rmmio_size; resource_size_t rmmio_size;
......
...@@ -1041,7 +1041,6 @@ radeon_add_atom_connector(struct drm_device *dev, ...@@ -1041,7 +1041,6 @@ radeon_add_atom_connector(struct drm_device *dev,
struct radeon_connector_atom_dig *radeon_dig_connector; struct radeon_connector_atom_dig *radeon_dig_connector;
uint32_t subpixel_order = SubPixelNone; uint32_t subpixel_order = SubPixelNone;
bool shared_ddc = false; bool shared_ddc = false;
int ret;
/* fixme - tv/cv/din */ /* fixme - tv/cv/din */
if (connector_type == DRM_MODE_CONNECTOR_Unknown) if (connector_type == DRM_MODE_CONNECTOR_Unknown)
...@@ -1076,9 +1075,7 @@ radeon_add_atom_connector(struct drm_device *dev, ...@@ -1076,9 +1075,7 @@ radeon_add_atom_connector(struct drm_device *dev,
switch (connector_type) { switch (connector_type) {
case DRM_MODE_CONNECTOR_VGA: case DRM_MODE_CONNECTOR_VGA:
drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
ret = drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
if (ret)
goto failed;
if (i2c_bus->valid) { if (i2c_bus->valid) {
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA"); radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA");
if (!radeon_connector->ddc_bus) if (!radeon_connector->ddc_bus)
...@@ -1091,9 +1088,7 @@ radeon_add_atom_connector(struct drm_device *dev, ...@@ -1091,9 +1088,7 @@ radeon_add_atom_connector(struct drm_device *dev,
break; break;
case DRM_MODE_CONNECTOR_DVIA: case DRM_MODE_CONNECTOR_DVIA:
drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
ret = drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
if (ret)
goto failed;
if (i2c_bus->valid) { if (i2c_bus->valid) {
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI"); radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
if (!radeon_connector->ddc_bus) if (!radeon_connector->ddc_bus)
...@@ -1113,9 +1108,7 @@ radeon_add_atom_connector(struct drm_device *dev, ...@@ -1113,9 +1108,7 @@ radeon_add_atom_connector(struct drm_device *dev,
radeon_dig_connector->igp_lane_info = igp_lane_info; radeon_dig_connector->igp_lane_info = igp_lane_info;
radeon_connector->con_priv = radeon_dig_connector; radeon_connector->con_priv = radeon_dig_connector;
drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
ret = drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
if (ret)
goto failed;
if (i2c_bus->valid) { if (i2c_bus->valid) {
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI"); radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
if (!radeon_connector->ddc_bus) if (!radeon_connector->ddc_bus)
...@@ -1141,9 +1134,7 @@ radeon_add_atom_connector(struct drm_device *dev, ...@@ -1141,9 +1134,7 @@ radeon_add_atom_connector(struct drm_device *dev,
radeon_dig_connector->igp_lane_info = igp_lane_info; radeon_dig_connector->igp_lane_info = igp_lane_info;
radeon_connector->con_priv = radeon_dig_connector; radeon_connector->con_priv = radeon_dig_connector;
drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
ret = drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
if (ret)
goto failed;
if (i2c_bus->valid) { if (i2c_bus->valid) {
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "HDMI"); radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "HDMI");
if (!radeon_connector->ddc_bus) if (!radeon_connector->ddc_bus)
...@@ -1163,9 +1154,7 @@ radeon_add_atom_connector(struct drm_device *dev, ...@@ -1163,9 +1154,7 @@ radeon_add_atom_connector(struct drm_device *dev,
radeon_dig_connector->igp_lane_info = igp_lane_info; radeon_dig_connector->igp_lane_info = igp_lane_info;
radeon_connector->con_priv = radeon_dig_connector; radeon_connector->con_priv = radeon_dig_connector;
drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type); drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);
ret = drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs); drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
if (ret)
goto failed;
if (i2c_bus->valid) { if (i2c_bus->valid) {
/* add DP i2c bus */ /* add DP i2c bus */
if (connector_type == DRM_MODE_CONNECTOR_eDP) if (connector_type == DRM_MODE_CONNECTOR_eDP)
...@@ -1191,9 +1180,7 @@ radeon_add_atom_connector(struct drm_device *dev, ...@@ -1191,9 +1180,7 @@ radeon_add_atom_connector(struct drm_device *dev,
case DRM_MODE_CONNECTOR_9PinDIN: case DRM_MODE_CONNECTOR_9PinDIN:
if (radeon_tv == 1) { if (radeon_tv == 1) {
drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type); drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type);
ret = drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs); drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
if (ret)
goto failed;
radeon_connector->dac_load_detect = true; radeon_connector->dac_load_detect = true;
drm_connector_attach_property(&radeon_connector->base, drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.load_detect_property, rdev->mode_info.load_detect_property,
...@@ -1211,9 +1198,7 @@ radeon_add_atom_connector(struct drm_device *dev, ...@@ -1211,9 +1198,7 @@ radeon_add_atom_connector(struct drm_device *dev,
radeon_dig_connector->igp_lane_info = igp_lane_info; radeon_dig_connector->igp_lane_info = igp_lane_info;
radeon_connector->con_priv = radeon_dig_connector; radeon_connector->con_priv = radeon_dig_connector;
drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type); drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
ret = drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs); drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
if (ret)
goto failed;
if (i2c_bus->valid) { if (i2c_bus->valid) {
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS"); radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS");
if (!radeon_connector->ddc_bus) if (!radeon_connector->ddc_bus)
...@@ -1250,7 +1235,6 @@ radeon_add_legacy_connector(struct drm_device *dev, ...@@ -1250,7 +1235,6 @@ radeon_add_legacy_connector(struct drm_device *dev,
struct drm_connector *connector; struct drm_connector *connector;
struct radeon_connector *radeon_connector; struct radeon_connector *radeon_connector;
uint32_t subpixel_order = SubPixelNone; uint32_t subpixel_order = SubPixelNone;
int ret;
/* fixme - tv/cv/din */ /* fixme - tv/cv/din */
if (connector_type == DRM_MODE_CONNECTOR_Unknown) if (connector_type == DRM_MODE_CONNECTOR_Unknown)
...@@ -1278,9 +1262,7 @@ radeon_add_legacy_connector(struct drm_device *dev, ...@@ -1278,9 +1262,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
switch (connector_type) { switch (connector_type) {
case DRM_MODE_CONNECTOR_VGA: case DRM_MODE_CONNECTOR_VGA:
drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
ret = drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
if (ret)
goto failed;
if (i2c_bus->valid) { if (i2c_bus->valid) {
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA"); radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA");
if (!radeon_connector->ddc_bus) if (!radeon_connector->ddc_bus)
...@@ -1293,9 +1275,7 @@ radeon_add_legacy_connector(struct drm_device *dev, ...@@ -1293,9 +1275,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
break; break;
case DRM_MODE_CONNECTOR_DVIA: case DRM_MODE_CONNECTOR_DVIA:
drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
ret = drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
if (ret)
goto failed;
if (i2c_bus->valid) { if (i2c_bus->valid) {
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI"); radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
if (!radeon_connector->ddc_bus) if (!radeon_connector->ddc_bus)
...@@ -1309,9 +1289,7 @@ radeon_add_legacy_connector(struct drm_device *dev, ...@@ -1309,9 +1289,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
case DRM_MODE_CONNECTOR_DVII: case DRM_MODE_CONNECTOR_DVII:
case DRM_MODE_CONNECTOR_DVID: case DRM_MODE_CONNECTOR_DVID:
drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
ret = drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
if (ret)
goto failed;
if (i2c_bus->valid) { if (i2c_bus->valid) {
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI"); radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
if (!radeon_connector->ddc_bus) if (!radeon_connector->ddc_bus)
...@@ -1328,9 +1306,7 @@ radeon_add_legacy_connector(struct drm_device *dev, ...@@ -1328,9 +1306,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
case DRM_MODE_CONNECTOR_9PinDIN: case DRM_MODE_CONNECTOR_9PinDIN:
if (radeon_tv == 1) { if (radeon_tv == 1) {
drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type); drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type);
ret = drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs); drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
if (ret)
goto failed;
radeon_connector->dac_load_detect = true; radeon_connector->dac_load_detect = true;
/* RS400,RC410,RS480 chipset seems to report a lot /* RS400,RC410,RS480 chipset seems to report a lot
* of false positive on load detect, we haven't yet * of false positive on load detect, we haven't yet
...@@ -1349,9 +1325,7 @@ radeon_add_legacy_connector(struct drm_device *dev, ...@@ -1349,9 +1325,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
break; break;
case DRM_MODE_CONNECTOR_LVDS: case DRM_MODE_CONNECTOR_LVDS:
drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type); drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
ret = drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs); drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
if (ret)
goto failed;
if (i2c_bus->valid) { if (i2c_bus->valid) {
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS"); radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS");
if (!radeon_connector->ddc_bus) if (!radeon_connector->ddc_bus)
......
...@@ -730,9 +730,10 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) ...@@ -730,9 +730,10 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)
continue; continue;
} }
robj = rfb->obj->driver_private; robj = rfb->obj->driver_private;
if (robj != rdev->fbdev_rbo) { /* don't unpin kernel fb objects */
if (!radeon_fbdev_robj_is_fb(rdev, robj)) {
r = radeon_bo_reserve(robj, false); r = radeon_bo_reserve(robj, false);
if (unlikely(r == 0)) { if (r == 0) {
radeon_bo_unpin(robj); radeon_bo_unpin(robj);
radeon_bo_unreserve(robj); radeon_bo_unreserve(robj);
} }
...@@ -757,7 +758,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) ...@@ -757,7 +758,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)
pci_set_power_state(dev->pdev, PCI_D3hot); pci_set_power_state(dev->pdev, PCI_D3hot);
} }
acquire_console_sem(); acquire_console_sem();
fb_set_suspend(rdev->fbdev_info, 1); radeon_fbdev_set_suspend(rdev, 1);
release_console_sem(); release_console_sem();
return 0; return 0;
} }
...@@ -781,7 +782,7 @@ int radeon_resume_kms(struct drm_device *dev) ...@@ -781,7 +782,7 @@ int radeon_resume_kms(struct drm_device *dev)
radeon_agp_resume(rdev); radeon_agp_resume(rdev);
radeon_resume(rdev); radeon_resume(rdev);
radeon_restore_bios_scratch_regs(rdev); radeon_restore_bios_scratch_regs(rdev);
fb_set_suspend(rdev->fbdev_info, 0); radeon_fbdev_set_suspend(rdev, 0);
release_console_sem(); release_console_sem();
/* reset hpd state */ /* reset hpd state */
......
...@@ -831,10 +831,6 @@ void radeon_compute_pll(struct radeon_pll *pll, ...@@ -831,10 +831,6 @@ void radeon_compute_pll(struct radeon_pll *pll,
static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb) static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb)
{ {
struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb);
struct drm_device *dev = fb->dev;
if (fb->fbdev)
radeonfb_remove(dev, fb);
if (radeon_fb->obj) if (radeon_fb->obj)
drm_gem_object_unreference_unlocked(radeon_fb->obj); drm_gem_object_unreference_unlocked(radeon_fb->obj);
...@@ -856,21 +852,15 @@ static const struct drm_framebuffer_funcs radeon_fb_funcs = { ...@@ -856,21 +852,15 @@ static const struct drm_framebuffer_funcs radeon_fb_funcs = {
.create_handle = radeon_user_framebuffer_create_handle, .create_handle = radeon_user_framebuffer_create_handle,
}; };
struct drm_framebuffer * void
radeon_framebuffer_create(struct drm_device *dev, radeon_framebuffer_init(struct drm_device *dev,
struct drm_mode_fb_cmd *mode_cmd, struct radeon_framebuffer *rfb,
struct drm_gem_object *obj) struct drm_mode_fb_cmd *mode_cmd,
struct drm_gem_object *obj)
{ {
struct radeon_framebuffer *radeon_fb; rfb->obj = obj;
drm_framebuffer_init(dev, &rfb->base, &radeon_fb_funcs);
radeon_fb = kzalloc(sizeof(*radeon_fb), GFP_KERNEL); drm_helper_mode_fill_fb_struct(&rfb->base, mode_cmd);
if (radeon_fb == NULL) {
return NULL;
}
drm_framebuffer_init(dev, &radeon_fb->base, &radeon_fb_funcs);
drm_helper_mode_fill_fb_struct(&radeon_fb->base, mode_cmd);
radeon_fb->obj = obj;
return &radeon_fb->base;
} }
static struct drm_framebuffer * static struct drm_framebuffer *
...@@ -879,6 +869,7 @@ radeon_user_framebuffer_create(struct drm_device *dev, ...@@ -879,6 +869,7 @@ radeon_user_framebuffer_create(struct drm_device *dev,
struct drm_mode_fb_cmd *mode_cmd) struct drm_mode_fb_cmd *mode_cmd)
{ {
struct drm_gem_object *obj; struct drm_gem_object *obj;
struct radeon_framebuffer *radeon_fb;
obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle); obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle);
if (obj == NULL) { if (obj == NULL) {
...@@ -886,12 +877,19 @@ radeon_user_framebuffer_create(struct drm_device *dev, ...@@ -886,12 +877,19 @@ radeon_user_framebuffer_create(struct drm_device *dev,
"can't create framebuffer\n", mode_cmd->handle); "can't create framebuffer\n", mode_cmd->handle);
return NULL; return NULL;
} }
return radeon_framebuffer_create(dev, mode_cmd, obj);
radeon_fb = kzalloc(sizeof(*radeon_fb), GFP_KERNEL);
if (radeon_fb == NULL) {
return NULL;
}
radeon_framebuffer_init(dev, radeon_fb, mode_cmd, obj);
return &radeon_fb->base;
} }
static const struct drm_mode_config_funcs radeon_mode_funcs = { static const struct drm_mode_config_funcs radeon_mode_funcs = {
.fb_create = radeon_user_framebuffer_create, .fb_create = radeon_user_framebuffer_create,
.fb_changed = radeonfb_probe,
}; };
struct drm_prop_enum_list { struct drm_prop_enum_list {
...@@ -1031,12 +1029,14 @@ int radeon_modeset_init(struct radeon_device *rdev) ...@@ -1031,12 +1029,14 @@ int radeon_modeset_init(struct radeon_device *rdev)
} }
/* initialize hpd */ /* initialize hpd */
radeon_hpd_init(rdev); radeon_hpd_init(rdev);
drm_helper_initial_config(rdev->ddev);
radeon_fbdev_init(rdev);
return 0; return 0;
} }
void radeon_modeset_fini(struct radeon_device *rdev) void radeon_modeset_fini(struct radeon_device *rdev)
{ {
radeon_fbdev_fini(rdev);
kfree(rdev->mode_info.bios_hardcoded_edid); kfree(rdev->mode_info.bios_hardcoded_edid);
if (rdev->mode_info.mode_config_initialized) { if (rdev->mode_info.mode_config_initialized) {
......
This diff is collapsed.
...@@ -158,8 +158,7 @@ int radeon_gem_info_ioctl(struct drm_device *dev, void *data, ...@@ -158,8 +158,7 @@ int radeon_gem_info_ioctl(struct drm_device *dev, void *data,
args->vram_visible = rdev->mc.real_vram_size; args->vram_visible = rdev->mc.real_vram_size;
if (rdev->stollen_vga_memory) if (rdev->stollen_vga_memory)
args->vram_visible -= radeon_bo_size(rdev->stollen_vga_memory); args->vram_visible -= radeon_bo_size(rdev->stollen_vga_memory);
if (rdev->fbdev_rbo) args->vram_visible -= radeon_fbdev_total_size(rdev);
args->vram_visible -= radeon_bo_size(rdev->fbdev_rbo);
args->gart_size = rdev->mc.gtt_size - rdev->cp.ring_size - 4096 - args->gart_size = rdev->mc.gtt_size - rdev->cp.ring_size - 4096 -
RADEON_IB_POOL_SIZE*64*1024; RADEON_IB_POOL_SIZE*64*1024;
return 0; return 0;
......
...@@ -55,6 +55,8 @@ static void radeon_hotplug_work_func(struct work_struct *work) ...@@ -55,6 +55,8 @@ static void radeon_hotplug_work_func(struct work_struct *work)
radeon_connector_hotplug(connector); radeon_connector_hotplug(connector);
} }
/* Just fire off a uevent and let userspace tell us what to do */ /* Just fire off a uevent and let userspace tell us what to do */
radeonfb_hotplug(dev, false);
drm_sysfs_hotplug_event(dev); drm_sysfs_hotplug_event(dev);
} }
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <linux/i2c-algo-bit.h> #include <linux/i2c-algo-bit.h>
#include "radeon_fixed.h" #include "radeon_fixed.h"
struct radeon_bo;
struct radeon_device; struct radeon_device;
#define to_radeon_crtc(x) container_of(x, struct radeon_crtc, base) #define to_radeon_crtc(x) container_of(x, struct radeon_crtc, base)
...@@ -202,6 +203,8 @@ enum radeon_dvo_chip { ...@@ -202,6 +203,8 @@ enum radeon_dvo_chip {
DVO_SIL1178, DVO_SIL1178,
}; };
struct radeon_fbdev;
struct radeon_mode_info { struct radeon_mode_info {
struct atom_context *atom_context; struct atom_context *atom_context;
struct card_info *atom_card_info; struct card_info *atom_card_info;
...@@ -218,6 +221,9 @@ struct radeon_mode_info { ...@@ -218,6 +221,9 @@ struct radeon_mode_info {
struct drm_property *tmds_pll_property; struct drm_property *tmds_pll_property;
/* hardcoded DFP edid from BIOS */ /* hardcoded DFP edid from BIOS */
struct edid *bios_hardcoded_edid; struct edid *bios_hardcoded_edid;
/* pointer to fbdev info structure */
struct radeon_fbdev *rfbdev;
}; };
#define MAX_H_CODE_TIMING_LEN 32 #define MAX_H_CODE_TIMING_LEN 32
...@@ -532,11 +538,10 @@ extern void radeon_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, ...@@ -532,11 +538,10 @@ extern void radeon_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
u16 blue, int regno); u16 blue, int regno);
extern void radeon_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, extern void radeon_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
u16 *blue, int regno); u16 *blue, int regno);
struct drm_framebuffer *radeon_framebuffer_create(struct drm_device *dev, void radeon_framebuffer_init(struct drm_device *dev,
struct drm_mode_fb_cmd *mode_cmd, struct radeon_framebuffer *rfb,
struct drm_gem_object *obj); struct drm_mode_fb_cmd *mode_cmd,
struct drm_gem_object *obj);
int radeonfb_probe(struct drm_device *dev);
int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev); bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev);
...@@ -573,4 +578,12 @@ void radeon_legacy_tv_adjust_pll2(struct drm_encoder *encoder, ...@@ -573,4 +578,12 @@ void radeon_legacy_tv_adjust_pll2(struct drm_encoder *encoder,
void radeon_legacy_tv_mode_set(struct drm_encoder *encoder, void radeon_legacy_tv_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode); struct drm_display_mode *adjusted_mode);
/* fbdev layer */
int radeon_fbdev_init(struct radeon_device *rdev);
void radeon_fbdev_fini(struct radeon_device *rdev);
void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state);
int radeon_fbdev_total_size(struct radeon_device *rdev);
bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj);
void radeonfb_hotplug(struct drm_device *dev, bool polled);
#endif #endif
...@@ -752,14 +752,8 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, ...@@ -752,14 +752,8 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
return NULL; return NULL;
} }
static int vmw_kms_fb_changed(struct drm_device *dev)
{
return 0;
}
static struct drm_mode_config_funcs vmw_kms_funcs = { static struct drm_mode_config_funcs vmw_kms_funcs = {
.fb_create = vmw_kms_fb_create, .fb_create = vmw_kms_fb_create,
.fb_changed = vmw_kms_fb_changed,
}; };
int vmw_kms_init(struct vmw_private *dev_priv) int vmw_kms_init(struct vmw_private *dev_priv)
......
...@@ -271,8 +271,6 @@ struct drm_framebuffer { ...@@ -271,8 +271,6 @@ struct drm_framebuffer {
unsigned int depth; unsigned int depth;
int bits_per_pixel; int bits_per_pixel;
int flags; int flags;
struct fb_info *fbdev;
u32 pseudo_palette[17];
struct list_head filp_head; struct list_head filp_head;
/* if you are using the helper */ /* if you are using the helper */
void *helper_private; void *helper_private;
...@@ -369,9 +367,6 @@ struct drm_crtc_funcs { ...@@ -369,9 +367,6 @@ struct drm_crtc_funcs {
* @enabled: is this CRTC enabled? * @enabled: is this CRTC enabled?
* @x: x position on screen * @x: x position on screen
* @y: y position on screen * @y: y position on screen
* @desired_mode: new desired mode
* @desired_x: desired x for desired_mode
* @desired_y: desired y for desired_mode
* @funcs: CRTC control functions * @funcs: CRTC control functions
* *
* Each CRTC may have one or more connectors associated with it. This structure * Each CRTC may have one or more connectors associated with it. This structure
...@@ -391,8 +386,6 @@ struct drm_crtc { ...@@ -391,8 +386,6 @@ struct drm_crtc {
struct drm_display_mode mode; struct drm_display_mode mode;
int x, y; int x, y;
struct drm_display_mode *desired_mode;
int desired_x, desired_y;
const struct drm_crtc_funcs *funcs; const struct drm_crtc_funcs *funcs;
/* CRTC gamma size for reporting to userspace */ /* CRTC gamma size for reporting to userspace */
...@@ -521,7 +514,6 @@ struct drm_connector { ...@@ -521,7 +514,6 @@ struct drm_connector {
uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER]; uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER];
uint32_t force_encoder_id; uint32_t force_encoder_id;
struct drm_encoder *encoder; /* currently active encoder */ struct drm_encoder *encoder; /* currently active encoder */
void *fb_helper_private;
}; };
/** /**
...@@ -548,16 +540,9 @@ struct drm_mode_set { ...@@ -548,16 +540,9 @@ struct drm_mode_set {
/** /**
* struct drm_mode_config_funcs - configure CRTCs for a given screen layout * struct drm_mode_config_funcs - configure CRTCs for a given screen layout
* @resize: adjust CRTCs as necessary for the proposed layout
*
* Currently only a resize hook is available. DRM will call back into the
* driver with a new screen width and height. If the driver can't support
* the proposed size, it can return false. Otherwise it should adjust
* the CRTC<->connector mappings as needed and update its view of the screen.
*/ */
struct drm_mode_config_funcs { struct drm_mode_config_funcs {
struct drm_framebuffer *(*fb_create)(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd *mode_cmd); struct drm_framebuffer *(*fb_create)(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd *mode_cmd);
int (*fb_changed)(struct drm_device *dev);
}; };
struct drm_mode_group { struct drm_mode_group {
...@@ -590,9 +575,6 @@ struct drm_mode_config { ...@@ -590,9 +575,6 @@ struct drm_mode_config {
struct list_head property_list; struct list_head property_list;
/* in-kernel framebuffers - hung of filp_head in drm_framebuffer */
struct list_head fb_kernel_list;
int min_width, min_height; int min_width, min_height;
int max_width, max_height; int max_width, max_height;
struct drm_mode_config_funcs *funcs; struct drm_mode_config_funcs *funcs;
......
...@@ -39,7 +39,6 @@ ...@@ -39,7 +39,6 @@
#include <linux/fb.h> #include <linux/fb.h>
#include "drm_fb_helper.h"
struct drm_crtc_helper_funcs { struct drm_crtc_helper_funcs {
/* /*
* Control power levels on the CRTC. If the mode passed in is * Control power levels on the CRTC. If the mode passed in is
...@@ -96,8 +95,6 @@ struct drm_connector_helper_funcs { ...@@ -96,8 +95,6 @@ struct drm_connector_helper_funcs {
extern int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY); extern int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY);
extern void drm_helper_disable_unused_functions(struct drm_device *dev); extern void drm_helper_disable_unused_functions(struct drm_device *dev);
extern int drm_helper_hotplug_stage_two(struct drm_device *dev);
extern bool drm_helper_initial_config(struct drm_device *dev);
extern int drm_crtc_helper_set_config(struct drm_mode_set *set); extern int drm_crtc_helper_set_config(struct drm_mode_set *set);
extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
struct drm_display_mode *mode, struct drm_display_mode *mode,
...@@ -123,11 +120,10 @@ static inline void drm_encoder_helper_add(struct drm_encoder *encoder, ...@@ -123,11 +120,10 @@ static inline void drm_encoder_helper_add(struct drm_encoder *encoder,
encoder->helper_private = (void *)funcs; encoder->helper_private = (void *)funcs;
} }
static inline int drm_connector_helper_add(struct drm_connector *connector, static inline void drm_connector_helper_add(struct drm_connector *connector,
const struct drm_connector_helper_funcs *funcs) const struct drm_connector_helper_funcs *funcs)
{ {
connector->helper_private = (void *)funcs; connector->helper_private = (void *)funcs;
return drm_fb_helper_add_connector(connector);
} }
extern int drm_helper_resume_force_mode(struct drm_device *dev); extern int drm_helper_resume_force_mode(struct drm_device *dev);
......
...@@ -30,17 +30,14 @@ ...@@ -30,17 +30,14 @@
#ifndef DRM_FB_HELPER_H #ifndef DRM_FB_HELPER_H
#define DRM_FB_HELPER_H #define DRM_FB_HELPER_H
#include <linux/slow-work.h>
struct drm_fb_helper;
struct drm_fb_helper_crtc { struct drm_fb_helper_crtc {
uint32_t crtc_id; uint32_t crtc_id;
struct drm_mode_set mode_set; struct drm_mode_set mode_set;
}; struct drm_display_mode *desired_mode;
struct drm_fb_helper_funcs {
void (*gamma_set)(struct drm_crtc *crtc, u16 red, u16 green,
u16 blue, int regno);
void (*gamma_get)(struct drm_crtc *crtc, u16 *red, u16 *green,
u16 *blue, int regno);
}; };
/* mode specified on the command line */ /* mode specified on the command line */
...@@ -57,8 +54,31 @@ struct drm_fb_helper_cmdline_mode { ...@@ -57,8 +54,31 @@ struct drm_fb_helper_cmdline_mode {
bool margins; bool margins;
}; };
struct drm_fb_helper_surface_size {
u32 fb_width;
u32 fb_height;
u32 surface_width;
u32 surface_height;
u32 surface_bpp;
u32 surface_depth;
};
struct drm_fb_helper_funcs {
void (*gamma_set)(struct drm_crtc *crtc, u16 red, u16 green,
u16 blue, int regno);
void (*gamma_get)(struct drm_crtc *crtc, u16 *red, u16 *green,
u16 *blue, int regno);
int (*fb_probe)(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes);
void (*fb_output_status_changed)(struct drm_fb_helper *helper);
};
struct drm_fb_helper_connector { struct drm_fb_helper_connector {
struct drm_fb_helper_cmdline_mode cmdline_mode; struct drm_fb_helper_cmdline_mode cmdline_mode;
struct drm_connector *connector;
}; };
struct drm_fb_helper { struct drm_fb_helper {
...@@ -67,24 +87,28 @@ struct drm_fb_helper { ...@@ -67,24 +87,28 @@ struct drm_fb_helper {
struct drm_display_mode *mode; struct drm_display_mode *mode;
int crtc_count; int crtc_count;
struct drm_fb_helper_crtc *crtc_info; struct drm_fb_helper_crtc *crtc_info;
int connector_count;
struct drm_fb_helper_connector **connector_info;
struct drm_fb_helper_funcs *funcs; struct drm_fb_helper_funcs *funcs;
int conn_limit; int conn_limit;
struct fb_info *fbdev;
u32 pseudo_palette[17];
struct list_head kernel_fb_list; struct list_head kernel_fb_list;
struct delayed_slow_work output_status_change_slow_work;
bool poll_enabled;
/* we got a hotplug but fbdev wasn't running the console
delay until next set_par */
bool delayed_hotplug;
}; };
int drm_fb_helper_single_fb_probe(struct drm_device *dev, int drm_fb_helper_single_fb_probe(struct drm_fb_helper *helper,
int preferred_bpp, int preferred_bpp);
int (*fb_create)(struct drm_device *dev,
uint32_t fb_width, int drm_fb_helper_init(struct drm_device *dev,
uint32_t fb_height, struct drm_fb_helper *helper, int crtc_count,
uint32_t surface_width, int max_conn, bool polled);
uint32_t surface_height, void drm_fb_helper_fini(struct drm_fb_helper *helper);
uint32_t surface_depth,
uint32_t surface_bpp,
struct drm_framebuffer **fb_ptr));
int drm_fb_helper_init_crtc_count(struct drm_fb_helper *helper, int crtc_count,
int max_conn);
void drm_fb_helper_free(struct drm_fb_helper *helper);
int drm_fb_helper_blank(int blank, struct fb_info *info); int drm_fb_helper_blank(int blank, struct fb_info *info);
int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info); struct fb_info *info);
...@@ -99,13 +123,17 @@ int drm_fb_helper_setcolreg(unsigned regno, ...@@ -99,13 +123,17 @@ int drm_fb_helper_setcolreg(unsigned regno,
struct fb_info *info); struct fb_info *info);
void drm_fb_helper_restore(void); void drm_fb_helper_restore(void);
void drm_fb_helper_fill_var(struct fb_info *info, struct drm_framebuffer *fb, void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
uint32_t fb_width, uint32_t fb_height); uint32_t fb_width, uint32_t fb_height);
void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
uint32_t depth); uint32_t depth);
int drm_fb_helper_add_connector(struct drm_connector *connector);
int drm_fb_helper_parse_command_line(struct drm_device *dev);
int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info);
bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper,
bool polled);
bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel);
int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper);
void drm_helper_fb_hpd_irq_event(struct drm_fb_helper *fb_helper);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment