summaryrefslogtreecommitdiff
path: root/linux-core
diff options
context:
space:
mode:
Diffstat (limited to 'linux-core')
-rw-r--r--linux-core/drmP.h4
-rw-r--r--linux-core/drm_crtc.c1
-rw-r--r--linux-core/drm_crtc.h9
-rw-r--r--linux-core/drm_crtc_helper.c123
-rw-r--r--linux-core/drm_crtc_helper.h3
-rw-r--r--linux-core/i915_drv.c8
-rw-r--r--linux-core/intel_display.c21
-rw-r--r--linux-core/intel_drv.h8
-rw-r--r--linux-core/intel_fb.c692
9 files changed, 524 insertions, 345 deletions
diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index 6e627cd9..5b2d7829 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -742,10 +742,6 @@ struct drm_driver {
void (*set_version) (struct drm_device *dev,
struct drm_set_version *sv);
- /* FB routines, if present */
- int (*fb_probe)(struct drm_device *dev, struct drm_crtc *crtc, struct drm_connector *connector);
- int (*fb_resize)(struct drm_device *dev, struct drm_crtc *crtc);
-
/* Master routines */
int (*master_create)(struct drm_device *dev, struct drm_master *master);
void (*master_destroy)(struct drm_device *dev, struct drm_master *master);
diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c
index 7a049da8..d49834b9 100644
--- a/linux-core/drm_crtc.c
+++ b/linux-core/drm_crtc.c
@@ -562,6 +562,7 @@ void drm_mode_config_init(struct drm_device *dev)
{
mutex_init(&dev->mode_config.mutex);
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.connector_list);
INIT_LIST_HEAD(&dev->mode_config.encoder_list);
diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h
index f3953692..043b4a57 100644
--- a/linux-core/drm_crtc.h
+++ b/linux-core/drm_crtc.h
@@ -498,8 +498,9 @@ struct drm_connector {
*
* This is used to set modes.
*/
-struct drm_mode_set
-{
+struct drm_mode_set {
+ struct list_head head;
+
struct drm_framebuffer *fb;
struct drm_crtc *crtc;
struct drm_display_mode *mode;
@@ -523,6 +524,7 @@ struct drm_mode_set
struct drm_mode_config_funcs {
bool (*resize_fb)(struct drm_device *dev, struct drm_framebuffer *fb);
struct drm_framebuffer *(*fb_create)(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd *mode_cmd);
+ void (*fb_changed)(struct drm_device *dev);
};
struct drm_mode_group {
@@ -554,6 +556,9 @@ struct drm_mode_config {
struct list_head property_list;
+ /* in-kernel framebuffers - hung of filp_head in drm_framebuffer */
+ struct list_head fb_kernel_list;
+
/* currently in use generation id */
int current_generation;
diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c
index 4083d6b7..777820d7 100644
--- a/linux-core/drm_crtc_helper.c
+++ b/linux-core/drm_crtc_helper.c
@@ -67,6 +67,7 @@ void drm_helper_probe_single_connector_modes(struct drm_connector *connector, ui
struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
int ret;
+ DRM_DEBUG("%s\n", drm_get_connector_name(connector));
/* set all modes to the unverified state */
list_for_each_entry_safe(mode, t, &connector->modes, head)
mode->status = MODE_UNVERIFIED;
@@ -186,8 +187,11 @@ void drm_helper_disable_unused_functions(struct drm_device *dev)
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
- if (!crtc->enabled)
+ crtc->enabled = drm_helper_crtc_in_use(crtc);
+ if (!crtc->enabled) {
crtc_funcs->dpms(crtc, DPMSModeOff);
+ crtc->fb = NULL;
+ }
}
}
EXPORT_SYMBOL(drm_helper_disable_unused_functions);
@@ -209,6 +213,7 @@ static void drm_pick_crtcs (struct drm_device *dev)
struct drm_connector_helper_funcs *connector_funcs;
int found;
+ DRM_DEBUG("\n");
/* clean out all the encoder/crtc combos */
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
encoder->crtc = NULL;
@@ -496,6 +501,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
crtc_funcs = set->crtc->helper_private;
DRM_DEBUG("crtc: %p fb: %p connectors: %p num_connectors: %i (x, y) (%i, %i)\n", set->crtc, set->fb, set->connectors, set->num_connectors, set->x, set->y);
+
dev = set->crtc->dev;
/* save previous config */
@@ -514,8 +520,13 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
/* We should be able to check here if the fb has the same properties
* and then just flip_or_move it */
- if (set->crtc->fb != set->fb)
- flip_or_move = true;
+ if (set->crtc->fb != set->fb) {
+ /* if we have no fb then its a change not a flip */
+ if (set->crtc->fb == NULL)
+ changed = true;
+ else
+ flip_or_move = true;
+ }
if (set->x != set->crtc->x || set->y != set->crtc->y)
flip_or_move = true;
@@ -532,7 +543,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
save_encoders[count++] = connector->encoder;
- new_encoder = NULL;
+ new_encoder = connector->encoder;
for (ro = 0; ro < set->num_connectors; ro++) {
if (set->connectors[ro] == connector) {
new_encoder = connector_funcs->best_encoder(connector);
@@ -626,6 +637,22 @@ fail_no_encoder:
}
EXPORT_SYMBOL(drm_crtc_helper_set_config);
+bool drm_helper_plugged_event(struct drm_device *dev)
+{
+ DRM_DEBUG("\n");
+
+ drm_helper_probe_connector_modes(dev, dev->mode_config.max_width, dev->mode_config.max_height);
+
+ drm_pick_crtcs(dev);
+
+ /* alert the driver fb layer */
+ dev->mode_config.funcs->fb_changed(dev);
+
+ drm_helper_disable_unused_functions(dev);
+
+ drm_sysfs_hotplug_event(dev);
+ return true;
+}
/**
* drm_initial_config - setup a sane initial connector configuration
* @dev: DRM device
@@ -643,45 +670,9 @@ EXPORT_SYMBOL(drm_crtc_helper_set_config);
*/
bool drm_helper_initial_config(struct drm_device *dev, bool can_grow)
{
- struct drm_connector *connector;
int ret = false;
- mutex_lock(&dev->mode_config.mutex);
-
- drm_helper_probe_connector_modes(dev, 2048, 2048);
-
- drm_pick_crtcs(dev);
-
- /* This is a little screwy, as we've already walked the connectors
- * above, but it's a little bit of magic too. There's the potential
- * for things not to get setup above if an existing device gets
- * re-assigned thus confusing the hardware. By walking the connectors
- * this fixes up their crtc's.
- */
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-
- struct drm_encoder *encoder = connector->encoder;
- struct drm_crtc *crtc;
-
- if (!encoder)
- continue;
-
- crtc = connector->encoder->crtc;
-
- /* can't setup the connector if there's no assigned mode */
- if (!crtc || !crtc->desired_mode)
- continue;
-
- dev->driver->fb_probe(dev, crtc, connector);
-
- /* and needs an attached fb */
- if (crtc->fb)
- drm_crtc_helper_set_mode(crtc, crtc->desired_mode, 0, 0);
- }
-
- drm_helper_disable_unused_functions(dev);
-
- mutex_unlock(&dev->mode_config.mutex);
+ drm_helper_plugged_event(dev);
return ret;
}
EXPORT_SYMBOL(drm_helper_initial_config);
@@ -699,62 +690,16 @@ EXPORT_SYMBOL(drm_helper_initial_config);
* RETURNS:
* Zero on success, errno on failure.
*/
-int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *connector,
- bool connected)
+int drm_helper_hotplug_stage_two(struct drm_device *dev)
{
- int has_config = 0;
-
dev->mode_config.hotplug_counter++;
- /* We might want to do something more here */
- if (!connected) {
- DRM_DEBUG("not connected\n");
- return 0;
- }
-
- if (connector->encoder) {
- if (connector->encoder->crtc && connector->encoder->crtc->desired_mode) {
- DRM_DEBUG("drm thinks that the connector already has a config\n");
- has_config = 1;
- }
- }
-
- drm_helper_probe_connector_modes(dev, 2048, 2048);
-
- if (!has_config)
- drm_pick_crtcs(dev);
-
- if (!connector->encoder) {
- DRM_DEBUG("could not find a desired mode or crtc for connector\n");
- return 1;
- }
-
- if (!connector->encoder->crtc || !connector->encoder->crtc->desired_mode) {
- DRM_DEBUG("could not find a desired mode or crtc for connector\n");
- return 1;
- }
-
- /* We should really check if there is a fb using this crtc */
- if (!has_config)
- dev->driver->fb_probe(dev, connector->encoder->crtc, connector);
- else {
- dev->driver->fb_resize(dev, connector->encoder->crtc);
-
-#if 0
- if (!drm_crtc_set_mode(connector->encoder->crtc, connector->encoder->crtc->desired_mode, 0, 0))
- DRM_ERROR("failed to set mode after hotplug\n");
-#endif
- }
-
- drm_sysfs_hotplug_event(dev);
-
- drm_helper_disable_unused_functions(dev);
+ drm_helper_plugged_event(dev);
return 0;
}
EXPORT_SYMBOL(drm_helper_hotplug_stage_two);
-
int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
struct drm_mode_fb_cmd *mode_cmd)
{
diff --git a/linux-core/drm_crtc_helper.h b/linux-core/drm_crtc_helper.h
index 7b7f23dc..45a67f98 100644
--- a/linux-core/drm_crtc_helper.h
+++ b/linux-core/drm_crtc_helper.h
@@ -65,8 +65,7 @@ struct drm_connector_helper_funcs {
extern void 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 int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *connector,
- bool connected);
+extern int drm_helper_hotplug_stage_two(struct drm_device *dev);
extern bool drm_helper_initial_config(struct drm_device *dev, bool can_grow);
extern int drm_crtc_helper_set_config(struct drm_mode_set *set);
extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,
diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c
index 2aac4926..f755dcd4 100644
--- a/linux-core/i915_drv.c
+++ b/linux-core/i915_drv.c
@@ -42,6 +42,12 @@ static struct pci_device_id pciidlist[] = {
unsigned int i915_modeset = 0;
module_param_named(modeset, i915_modeset, int, 0400);
+unsigned int i915_fbpercrtc = 0;
+module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400);
+
+unsigned int i915_rightof = 1;
+module_param_named(i915_rightof, i915_rightof, int, 0400);
+
#ifdef I915_HAVE_FENCE
extern struct drm_fence_driver i915_fence_driver;
#endif
@@ -588,8 +594,6 @@ static struct drm_driver driver = {
.reclaim_buffers = drm_core_reclaim_buffers,
.get_map_ofs = drm_core_get_map_ofs,
.get_reg_ofs = drm_core_get_reg_ofs,
- .fb_probe = intelfb_probe,
- .fb_resize = intelfb_resize,
.master_create = i915_master_create,
.master_destroy = i915_master_destroy,
.ioctls = i915_ioctls,
diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c
index 6493af16..0081b5be 100644
--- a/linux-core/intel_display.c
+++ b/linux-core/intel_display.c
@@ -1167,13 +1167,10 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output,
}
/*
- * If we didn't find an unused CRTC, use the first available one
- * that can drive this connector.
+ * If we didn't find an unused CRTC, don't use any.
*/
if (!crtc) {
- crtc = supported_crtc;
- if (!crtc)
- return NULL;
+ return NULL;
}
encoder->crtc = crtc;
@@ -1366,7 +1363,7 @@ void intel_crtc_init(struct drm_device *dev, int pipe)
struct intel_crtc *intel_crtc;
int i;
- intel_crtc = kzalloc(sizeof(struct intel_crtc), GFP_KERNEL);
+ intel_crtc = kzalloc(sizeof(struct intel_crtc) + (INTELFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL);
if (intel_crtc == NULL)
return;
@@ -1383,6 +1380,16 @@ void intel_crtc_init(struct drm_device *dev, int pipe)
intel_crtc->cursor_addr = 0;
intel_crtc->dpms_mode = DPMSModeOff;
drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
+
+ intel_crtc->mode_set.crtc = &intel_crtc->base;
+ intel_crtc->mode_set.connectors = (struct drm_connector **)(intel_crtc + 1);
+ intel_crtc->mode_set.num_connectors = 0;
+
+ if (i915_fbpercrtc) {
+
+
+
+ }
}
struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe)
@@ -1513,6 +1520,7 @@ struct drm_framebuffer *intel_user_framebuffer_create(struct drm_device *dev,
static const struct drm_mode_config_funcs intel_mode_funcs = {
.resize_fb = NULL,
.fb_create = intel_user_framebuffer_create,
+ .fb_changed = intelfb_probe,
};
void intel_modeset_init(struct drm_device *dev)
@@ -1554,6 +1562,7 @@ void intel_modeset_init(struct drm_device *dev)
intel_setup_outputs(dev);
+ /* setup fbs */
//drm_initial_config(dev, false);
}
diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h
index 46f0fbec..1008e271 100644
--- a/linux-core/intel_drv.h
+++ b/linux-core/intel_drv.h
@@ -20,6 +20,8 @@
/* The i830->i865 use multiple DVOs with multiple i2cs */
/* the i915, i945 have a single sDVO i2c bus - which is different */
#define MAX_OUTPUTS 6
+/* maximum connectors per crtcs in the mode set */
+#define INTELFB_CONN_LIMIT 4
#define INTEL_I2C_BUS_DVO 1
#define INTEL_I2C_BUS_SDVO 2
@@ -52,6 +54,7 @@ struct intel_framebuffer {
struct drm_bo_kmap_obj kmap;
};
+
struct intel_output {
struct drm_connector base;
@@ -70,6 +73,9 @@ struct intel_crtc {
uint32_t cursor_addr;
u8 lut_r[256], lut_g[256], lut_b[256];
int dpms_mode;
+ struct intel_framebuffer *fbdev_fb;
+ /* a mode_set for fbdev users on this crtc */
+ struct drm_mode_set mode_set;
};
#define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
@@ -108,7 +114,7 @@ extern void intel_release_load_detect_pipe(struct intel_output *intel_output,
extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB);
extern int intel_sdvo_supports_hotplug(struct drm_connector *connector);
extern void intel_sdvo_set_hotplug(struct drm_connector *connector, int enable);
-extern int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_connector *connector);
+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 intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c
index 1107cbfb..85a173e1 100644
--- a/linux-core/intel_fb.c
+++ b/linux-core/intel_fb.c
@@ -47,14 +47,11 @@
struct intelfb_par {
struct drm_device *dev;
-/*
- struct drm_crtc *crtc;
- struct drm_display_mode *fb_mode;
- struct drm_framebuffer *fb;
-*/
struct drm_display_mode *our_mode;
- struct drm_mode_set set;
- struct drm_connector *hack;
+ struct intel_framebuffer *intel_fb;
+ int crtc_count;
+ /* crtc currently bound to this */
+ uint32_t crtc_ids[2];
};
/*
static int
@@ -73,38 +70,52 @@ static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
struct fb_info *info)
{
struct intelfb_par *par = info->par;
- struct drm_framebuffer *fb = par->set.fb;
- struct drm_crtc *crtc = par->set.crtc;
+ struct drm_device *dev = par->dev;
+ struct drm_crtc *crtc;
+ int i;
- if (regno > 255)
- return 1;
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct drm_mode_set *modeset = &intel_crtc->mode_set;
+ struct drm_framebuffer *fb = modeset->fb;
- if (fb->depth == 8) {
- intel_crtc_fb_gamma_set(crtc, red, green, blue, regno);
- return 0;
- }
+ for (i = 0; i < par->crtc_count; i++)
+ if (crtc->base.id == par->crtc_ids[i])
+ break;
- if (regno < 16) {
- switch (fb->depth) {
- case 15:
- fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) |
- ((green & 0xf800) >> 6) |
- ((blue & 0xf800) >> 11);
- break;
- case 16:
- fb->pseudo_palette[regno] = (red & 0xf800) |
- ((green & 0xfc00) >> 5) |
- ((blue & 0xf800) >> 11);
- break;
- case 24:
- case 32:
- fb->pseudo_palette[regno] = ((red & 0xff00) << 8) |
- (green & 0xff00) |
- ((blue & 0xff00) >> 8);
- break;
+ if (i == par->crtc_count)
+ continue;
+
+
+ if (regno > 255)
+ return 1;
+
+ if (fb->depth == 8) {
+ intel_crtc_fb_gamma_set(crtc, red, green, blue, regno);
+ return 0;
}
- }
+ if (regno < 16) {
+ switch (fb->depth) {
+ case 15:
+ fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) |
+ ((green & 0xf800) >> 6) |
+ ((blue & 0xf800) >> 11);
+ break;
+ case 16:
+ fb->pseudo_palette[regno] = (red & 0xf800) |
+ ((green & 0xfc00) >> 5) |
+ ((blue & 0xf800) >> 11);
+ break;
+ case 24:
+ case 32:
+ fb->pseudo_palette[regno] = ((red & 0xff00) << 8) |
+ (green & 0xff00) |
+ ((blue & 0xff00) >> 8);
+ break;
+ }
+ }
+ }
return 0;
}
@@ -112,12 +123,11 @@ static int intelfb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct intelfb_par *par = info->par;
- /*struct drm_device *dev = par->dev;*/
- struct drm_framebuffer *fb = par->set.fb;
- /*struct drm_connector *connector;*/
- int depth/*, found = 0*/;
+ struct intel_framebuffer *intel_fb = par->intel_fb;
+ struct drm_framebuffer *fb = &intel_fb->base;
+ int depth;
- if (!var->pixclock)
+ if (var->pixclock == -1 || !var->pixclock)
return -EINVAL;
/* Need to resize the fb object !!! */
@@ -194,31 +204,6 @@ static int intelfb_check_var(struct fb_var_screeninfo *var,
return -EINVAL;
}
-#if 0
- /* Here we walk the connector mode list and look for modes. If we haven't
- * got it, then bail. Not very nice, so this is disabled.
- * In the set_par code, we create our mode based on the incoming
- * parameters. Nicer, but may not be desired by some.
- */
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- if (connector->crtc == par->crtc)
- break;
- }
-
- list_for_each_entry(drm_mode, &connector->modes, head) {
- if (drm_mode->hdisplay == var->xres &&
- drm_mode->vdisplay == var->yres &&
- (((PICOS2KHZ(var->pixclock))/1000) >= ((drm_mode->clock/1000)-1)) &&
- (((PICOS2KHZ(var->pixclock))/1000) <= ((drm_mode->clock/1000)+1))) {
- found = 1;
- break;
- }
- }
-
- if (!found)
- return -EINVAL;
-#endif
-
return 0;
}
@@ -227,123 +212,132 @@ static int intelfb_check_var(struct fb_var_screeninfo *var,
static int intelfb_set_par(struct fb_info *info)
{
struct intelfb_par *par = info->par;
- struct drm_framebuffer *fb = par->set.fb;
struct drm_device *dev = par->dev;
- struct drm_display_mode *drm_mode, *search_mode;
- struct drm_connector *connector = NULL;
struct fb_var_screeninfo *var = &info->var;
- int found = 0;
+ int i;
- DRM_DEBUG("\n");
+ DRM_DEBUG("%d %d\n", var->xres, var->pixclock);
- switch (var->bits_per_pixel) {
- case 16:
- fb->depth = (var->green.length == 6) ? 16 : 15;
- break;
- case 32:
- fb->depth = (var->transp.length > 0) ? 32 : 24;
- break;
- default:
- fb->depth = var->bits_per_pixel;
- break;
- }
- fb->bits_per_pixel = var->bits_per_pixel;
+ if (var->pixclock != -1) {
- info->fix.line_length = fb->pitch;
- info->fix.smem_len = info->fix.line_length * fb->height;
- info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
-
- info->screen_size = info->fix.smem_len; /* ??? */
-
- /* create a drm mode */
- drm_mode = drm_mode_create(dev);
- drm_mode->hdisplay = var->xres;
- drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin;
- drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len;
- drm_mode->htotal = drm_mode->hsync_end + var->left_margin;
- drm_mode->vdisplay = var->yres;
- drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin;
- drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len;
- drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin;
- drm_mode->clock = PICOS2KHZ(var->pixclock);
- drm_mode->vrefresh = drm_mode_vrefresh(drm_mode);
- drm_mode->flags = 0;
- drm_mode->flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC;
- drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC;
-
- drm_mode_set_name(drm_mode);
- drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V);
-
- found = 0;
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- if (connector->encoder &&
- connector->encoder->crtc == par->set.crtc){
- found = 1;
- break;
- }
- }
+ DRM_ERROR("PIXEL CLCOK SET\n");
+#if 0
+ struct intel_framebuffer *intel_fb = par->intel_fb;
+ struct drm_framebuffer *fb = &intel_fb->base;
+ struct drm_display_mode *drm_mode, *search_mode;
+ struct drm_connector *connector = NULL;
+ struct drm_device *dev = par->dev;
- /* no connector bound, bail */
- if (!found)
- return -EINVAL;
+ int found = 0;
- found = 0;
- drm_mode_debug_printmodeline(drm_mode);
- list_for_each_entry(search_mode, &connector->modes, head) {
- drm_mode_debug_printmodeline(search_mode);
- if (drm_mode_equal(drm_mode, search_mode)) {
- drm_mode_destroy(dev, drm_mode);
- drm_mode = search_mode;
- found = 1;
+ switch (var->bits_per_pixel) {
+ case 16:
+ fb->depth = (var->green.length == 6) ? 16 : 15;
+ break;
+ case 32:
+ fb->depth = (var->transp.length > 0) ? 32 : 24;
+ break;
+ default:
+ fb->depth = var->bits_per_pixel;
break;
}
- }
-
- /* If we didn't find a matching mode that exists on our connector,
- * create a new attachment for the incoming user specified mode
- */
- if (!found) {
- if (par->our_mode) {
- /* this also destroys the mode */
- drm_mode_detachmode_crtc(dev, par->our_mode);
+
+ fb->bits_per_pixel = var->bits_per_pixel;
+
+ info->fix.line_length = fb->pitch;
+ info->fix.smem_len = info->fix.line_length * fb->height;
+ info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+
+ info->screen_size = info->fix.smem_len; /* ??? */
+ /* reuse desired mode if possible */
+ /* create a drm mode */
+ drm_mode = drm_mode_create(dev);
+ drm_mode->hdisplay = var->xres;
+ drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin;
+ drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len;
+ drm_mode->htotal = drm_mode->hsync_end + var->left_margin;
+ drm_mode->vdisplay = var->yres;
+ drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin;
+ drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len;
+ drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin;
+ drm_mode->clock = PICOS2KHZ(var->pixclock);
+ drm_mode->vrefresh = drm_mode_vrefresh(drm_mode);
+ drm_mode->flags = 0;
+ drm_mode->flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC;
+ drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC;
+
+ drm_mode_set_name(drm_mode);
+ drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V);
+
+ found = 0;
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ if (connector->encoder &&
+ connector->encoder->crtc == par->set.crtc){
+ found = 1;
+ break;
+ }
}
-
- par->set.mode = drm_mode;
- par->our_mode = drm_mode;
+
+ /* no connector bound, bail */
+ if (!found)
+ return -EINVAL;
+
+ found = 0;
drm_mode_debug_printmodeline(drm_mode);
- /* attach mode */
- drm_mode_attachmode_crtc(dev, par->set.crtc, par->set.mode);
+ list_for_each_entry(search_mode, &connector->modes, head) {
+ drm_mode_debug_printmodeline(search_mode);
+ if (drm_mode_equal(drm_mode, search_mode)) {
+ drm_mode_destroy(dev, drm_mode);
+ drm_mode = search_mode;
+ found = 1;
+ break;
+ }
+ }
+
+ /* If we didn't find a matching mode that exists on our connector,
+ * create a new attachment for the incoming user specified mode
+ */
+ if (!found) {
+ if (par->our_mode) {
+ /* this also destroys the mode */
+ drm_mode_detachmode_crtc(dev, par->our_mode);
+ }
+
+ par->set.mode = drm_mode;
+ par->our_mode = drm_mode;
+ drm_mode_debug_printmodeline(drm_mode);
+ /* attach mode */
+ drm_mode_attachmode_crtc(dev, par->set.crtc, par->set.mode);
+ } else {
+ par->set.mode = drm_mode;
+ if (par->our_mode)
+ drm_mode_detachmode_crtc(dev, par->our_mode);
+ par->our_mode = NULL;
+ }
+ return par->set.crtc->funcs->set_config(&par->set);
+#endif
+ return -EINVAL;
} else {
- par->set.mode = drm_mode;
- if (par->our_mode)
- drm_mode_detachmode_crtc(dev, par->our_mode);
- par->our_mode = NULL;
- }
+ struct drm_crtc *crtc;
+ int ret;
-#if 0
- /* re-attach fb */
- if (!par->crtc->fb) {
- par->crtc->fb = par->fb;
- changed = 1;
- }
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- if (par->crtc->x != var->xoffset || par->crtc->y != var->yoffset)
- changed = 1;
-
- drm_mode_debug_printmodeline(drm_mode);
- drm_mode_debug_printmodeline(&par->crtc->mode);
- if (!drm_mode_equal(drm_mode, &par->crtc->mode))
- changed = 1;
-
- if (changed)
- if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset))
- return -EINVAL;
+ for (i = 0; i < par->crtc_count; i++)
+ if (crtc->base.id == par->crtc_ids[i])
+ break;
- return 0;
-#else
- return par->set.crtc->funcs->set_config(&par->set);
-#endif
+ if (i == par->crtc_count)
+ continue;
+
+ ret = crtc->funcs->set_config(&intel_crtc->mode_set);
+ if (ret)
+ return ret;
+ }
+ return 0;
+ }
}
#if 0
@@ -495,17 +489,36 @@ static int intelfb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct intelfb_par *par = info->par;
- int ret;
- DRM_DEBUG("\n");
-
- par->set.x = var->xoffset;
- par->set.y = var->yoffset;
+ struct drm_device *dev = par->dev;
+ struct drm_mode_set *modeset;
+ struct drm_crtc *crtc;
+ struct intel_crtc *intel_crtc;
+ int ret = 0;
+ int i;
+
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+
+ for (i = 0; i < par->crtc_count; i++)
+ if (crtc->base.id == par->crtc_ids[i])
+ break;
- ret = par->set.crtc->funcs->set_config(&par->set);
+ if (i == par->crtc_count)
+ continue;
- if (!ret) {
- info->var.xoffset = var->xoffset;
- info->var.yoffset = var->yoffset;
+ intel_crtc = to_intel_crtc(crtc);
+ modeset = &intel_crtc->mode_set;
+
+ modeset->x = var->xoffset;
+ modeset->y = var->yoffset;
+
+ if (modeset->num_connectors) {
+ ret = crtc->funcs->set_config(modeset);
+
+ if (!ret) {
+ info->var.xoffset = var->xoffset;
+ info->var.yoffset = var->yoffset;
+ }
+ }
}
return ret;
@@ -567,29 +580,21 @@ int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc)
}
EXPORT_SYMBOL(intelfb_resize);
-int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_connector *connector)
+int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height,
+ uint32_t surface_width, uint32_t surface_height,
+ struct intel_framebuffer **intel_fb_p)
{
struct fb_info *info;
struct intelfb_par *par;
- struct device *device = &dev->pdev->dev;
struct drm_framebuffer *fb;
struct intel_framebuffer *intel_fb;
- struct drm_display_mode *mode = crtc->desired_mode;
struct drm_mode_fb_cmd mode_cmd;
-
struct drm_buffer_object *fbo = NULL;
+ struct device *device = &dev->pdev->dev;
int ret;
- info = framebuffer_alloc(sizeof(struct intelfb_par), device);
- if (!info){
- return -EINVAL;
- }
-
- if (!connector)
- return -EINVAL;
-
- mode_cmd.width = 2048;/* crtc->desired_mode->hdisplay; */
- mode_cmd.height = 2048;/* crtc->desired_mode->vdisplay; */
+ mode_cmd.width = surface_width;/* crtc->desired_mode->hdisplay; */
+ mode_cmd.height = surface_height;/* crtc->desired_mode->vdisplay; */
mode_cmd.bpp = 32;
mode_cmd.pitch = mode_cmd.width * ((mode_cmd.bpp + 1) / 8);
@@ -606,43 +611,31 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn
&fbo);
if (ret || !fbo) {
printk(KERN_ERR "failed to allocate framebuffer\n");
- framebuffer_release(info);
return -EINVAL;
}
fb = intel_user_framebuffer_create(dev, NULL, &mode_cmd);
if (!fb) {
- framebuffer_release(info);
drm_bo_usage_deref_unlocked(&fbo);
DRM_ERROR("failed to allocate fb.\n");
return -EINVAL;
}
+ list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list);
+
intel_fb = to_intel_framebuffer(fb);
+ *intel_fb_p = intel_fb;
intel_fb->bo = fbo;
- crtc->fb = fb;
-
- /* To allow resizeing without swapping buffers */
- printk("allocated %dx%d fb: 0x%08lx, bo %p\n", intel_fb->base.width,
- intel_fb->base.height, intel_fb->bo->offset, fbo);
+ info = framebuffer_alloc(sizeof(struct intelfb_par), device);
+ if (!info)
+ return -EINVAL;
- fb->fbdev = info;
-
par = info->par;
- par->dev = dev;
- par->set.crtc = crtc;
- par->set.fb = fb;
- par->hack = connector;
- par->set.connectors = &par->hack;
- par->set.num_connectors = 1;
-
- info->fbops = &intelfb_ops;
-
- strcpy(info->fix.id, "intelfb");
+ strcpy(info->fix.id, "inteldrmfb");
info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fix.visual = FB_VISUAL_TRUECOLOR;
info->fix.type_aux = 0;
@@ -651,14 +644,10 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn
info->fix.ywrapstep = 0;
info->fix.accel = FB_ACCEL_I830;
info->fix.type_aux = 0;
-
- if (IS_I9XX(dev)) {
- info->fix.mmio_start = pci_resource_start(dev->pdev, 0);
- info->fix.mmio_len = pci_resource_len(dev->pdev, 0);
- } else {
- info->fix.mmio_start = pci_resource_start(dev->pdev, 1);
- info->fix.mmio_len = pci_resource_len(dev->pdev, 1);
- }
+
+ info->flags = FBINFO_DEFAULT;
+
+ info->fbops = &intelfb_ops;
info->fix.line_length = fb->pitch;
info->fix.smem_start = intel_fb->bo->offset + dev->mode_config.fb_base;
@@ -672,6 +661,9 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn
info->screen_base = intel_fb->kmap.virtual;
info->screen_size = info->fix.smem_len; /* FIXME */
+
+ memset(intel_fb->kmap.virtual, 0, info->screen_size);
+
info->pseudo_palette = fb->pseudo_palette;
info->var.xres_virtual = fb->width;
info->var.yres_virtual = fb->height;
@@ -682,28 +674,16 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn
info->var.height = -1;
info->var.width = -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 = KHZ2PICOS(mode->clock);
+ info->var.xres = fb_width;
+ info->var.yres = fb_height;
- if (mode->flags & V_PHSYNC)
- info->var.sync |= FB_SYNC_HOR_HIGH_ACT;
-
- if (mode->flags & V_PVSYNC)
- info->var.sync |= FB_SYNC_VERT_HIGH_ACT;
-
- if (mode->flags & V_INTERLACE)
- info->var.vmode = FB_VMODE_INTERLACED;
- else if (mode->flags & V_DBLSCAN)
- info->var.vmode = FB_VMODE_DOUBLE;
- else
- info->var.vmode = FB_VMODE_NONINTERLACED;
+ if (IS_I9XX(dev)) {
+ info->fix.mmio_start = pci_resource_start(dev->pdev, 0);
+ info->fix.mmio_len = pci_resource_len(dev->pdev, 0);
+ } else {
+ info->fix.mmio_start = pci_resource_start(dev->pdev, 1);
+ info->fix.mmio_len = pci_resource_len(dev->pdev, 1);
+ }
info->pixmap.size = 64*1024;
info->pixmap.buf_align = 8;
@@ -767,13 +747,247 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn
break;
}
- if (register_framebuffer(info) < 0)
- return -EINVAL;
+ fb->fbdev = info;
+
+ par->intel_fb = intel_fb;
+ par->dev = dev;
+
+ /* To allow resizeing without swapping buffers */
+ printk("allocated %dx%d fb: 0x%08lx, bo %p\n", intel_fb->base.width,
+ intel_fb->base.height, intel_fb->bo->offset, fbo);
+
+ return 0;
+}
+
+static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc *crtc)
+{
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct intel_framebuffer *intel_fb;
+ struct drm_framebuffer *fb;
+ struct drm_connector *connector;
+ struct fb_info *info;
+ struct intelfb_par *par;
+ struct drm_mode_set *modeset;
+ unsigned int width, height;
+ int new_fb = 0;
+ int ret, i, conn_count;
+
+ if (!drm_helper_crtc_in_use(crtc))
+ return 0;
+
+ if (!crtc->desired_mode)
+ return 0;
+
+ width = crtc->desired_mode->hdisplay;
+ height = crtc->desired_mode->vdisplay;
+
+ /* is there an fb bound to this crtc already */
+ if (!intel_crtc->mode_set.fb) {
+ ret = intelfb_create(dev, width, height, width, height, &intel_fb);
+ if (ret)
+ return -EINVAL;
+ new_fb = 1;
+ } else {
+ fb = intel_crtc->mode_set.fb;
+ intel_fb = to_intel_framebuffer(fb);
+ if ((intel_fb->base.width < width) || (intel_fb->base.height < height))
+ return -EINVAL;
+ }
+
+ info = intel_fb->base.fbdev;
+ par = info->par;
+
+ modeset = &intel_crtc->mode_set;
+ modeset->fb = &intel_fb->base;
+ conn_count = 0;
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ if (connector->encoder)
+ if (connector->encoder->crtc == modeset->crtc) {
+ modeset->connectors[conn_count] = connector;
+ conn_count++;
+ if (conn_count > INTELFB_CONN_LIMIT)
+ BUG();
+ }
+ }
+
+ for (i = conn_count; i < INTELFB_CONN_LIMIT; i++)
+ modeset->connectors[i] = NULL;
+
+ par->crtc_ids[0] = crtc->base.id;
+
+ modeset->num_connectors = conn_count;
+ if (modeset->mode != modeset->crtc->desired_mode)
+ modeset->mode = modeset->crtc->desired_mode;
+
+ par->crtc_count = 1;
+
+ if (new_fb) {
+ info->var.pixclock = -1;
+ if (register_framebuffer(info) < 0)
+ return -EINVAL;
+ } else
+ intelfb_set_par(info);
+
+ printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
+ info->fix.id);
+ return 0;
+}
+
+static int intelfb_multi_fb_probe(struct drm_device *dev)
+{
+
+ struct drm_crtc *crtc;
+ int ret = 0;
+
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ ret = intelfb_multi_fb_probe_crtc(dev, crtc);
+ if (ret)
+ return ret;
+ }
+ return ret;
+}
+
+static int intelfb_single_fb_probe(struct drm_device *dev)
+{
+ struct drm_crtc *crtc;
+ struct drm_connector *connector;
+ unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1;
+ unsigned int surface_width = 0, surface_height = 0;
+ int new_fb = 0;
+ int crtc_count = 0;
+ int ret, i, conn_count = 0;
+ struct intel_framebuffer *intel_fb;
+ struct fb_info *info;
+ struct intelfb_par *par;
+ struct drm_mode_set *modeset;
+
+ DRM_DEBUG("\n");
+ /* first up get a count of crtcs now in use and new min/maxes width/heights */
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ if (drm_helper_crtc_in_use(crtc)) {
+ if (crtc->desired_mode) {
+ if (crtc->desired_mode->hdisplay < fb_width)
+ fb_width = crtc->desired_mode->hdisplay;
+
+ if (crtc->desired_mode->vdisplay < fb_height)
+ fb_height = crtc->desired_mode->vdisplay;
+
+ if (crtc->desired_mode->hdisplay > surface_width)
+ surface_width = crtc->desired_mode->hdisplay;
+
+ if (crtc->desired_mode->vdisplay > surface_height)
+ surface_height = crtc->desired_mode->vdisplay;
+
+ }
+ crtc_count++;
+ }
+ }
+
+ if (crtc_count == 0 || fb_width == -1 || fb_height == -1) {
+ /* hmm everyone went away - assume VGA cable just fell out
+ and will come back later. */
+ return 0;
+ }
+
+ /* do we have an fb already? */
+ if (list_empty(&dev->mode_config.fb_kernel_list)) {
+ /* create an fb if we don't have one */
+ ret = intelfb_create(dev, fb_width, fb_height, surface_width, surface_height, &intel_fb);
+ if (ret)
+ return -EINVAL;
+ new_fb = 1;
+ } else {
+ struct drm_framebuffer *fb;
+ fb = list_first_entry(&dev->mode_config.fb_kernel_list, struct drm_framebuffer, filp_head);
+ intel_fb = to_intel_framebuffer(fb);
+
+ /* if someone hotplugs something bigger than we have already allocated, we are pwned.
+ As really we can't resize an fbdev that is in the wild currently due to fbdev
+ not really being designed for the lower layers moving stuff around under it.
+ - so in the grand style of things - punt. */
+ if ((fb->width < surface_width) || (fb->height < surface_height)) {
+ DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
+ return -EINVAL;
+ }
+ }
+
+ info = intel_fb->base.fbdev;
+ par = info->par;
+
+ crtc_count = 0;
+ /* okay we need to setup new connector sets in the crtcs */
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ modeset = &intel_crtc->mode_set;
+ modeset->fb = &intel_fb->base;
+ conn_count = 0;
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ if (connector->encoder)
+ if(connector->encoder->crtc == modeset->crtc) {
+ modeset->connectors[conn_count] = connector;
+ conn_count++;
+ if (conn_count > INTELFB_CONN_LIMIT)
+ BUG();
+ }
+ }
+
+ for (i = conn_count; i < INTELFB_CONN_LIMIT; i++)
+ modeset->connectors[i] = NULL;
+
+ par->crtc_ids[crtc_count++] = crtc->base.id;
+
+ modeset->num_connectors = conn_count;
+ if (modeset->mode != modeset->crtc->desired_mode)
+ modeset->mode = modeset->crtc->desired_mode;
+ }
+ par->crtc_count = crtc_count;
+ if (new_fb) {
+ info->var.pixclock = -1;
+ if (register_framebuffer(info) < 0)
+ return -EINVAL;
+ } else
+ intelfb_set_par(info);
+
printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
- info->fix.id);
+ info->fix.id);
return 0;
}
+
+int intelfb_probe(struct drm_device *dev)
+{
+ int ret;
+
+ DRM_DEBUG("\n");
+
+ /* something has changed in the lower levels of hell - deal with it
+ here */
+
+ /* two modes : a) 1 fb to rule all crtcs.
+ b) one fb per crtc.
+ two actions 1) new connected device
+ 2) device removed.
+ case a/1 : if the fb surface isn't big enough - resize the surface fb.
+ if the fb size isn't big enough - resize fb into surface.
+ if everything big enough configure the new crtc/etc.
+ case a/2 : undo the configuration
+ possibly resize down the fb to fit the new configuration.
+ case b/1 : see if it is on a new crtc - setup a new fb and add it.
+ case b/2 : teardown the new fb.
+ */
+
+ /* mode a first */
+ /* search for an fb */
+ if (i915_fbpercrtc == 1) {
+ ret = intelfb_multi_fb_probe(dev);
+ } else {
+ ret = intelfb_single_fb_probe(dev);
+ }
+
+fail:
+ /* TODO */
+ return ret;
+}
EXPORT_SYMBOL(intelfb_probe);
int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb)