From ef42af67cea6cf414d0e345304b9f0b3d2abc03d Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 3 Feb 2009 16:16:06 +1000 Subject: [PATCH] nv50/kms: merge nv50_kms_crtc and nv50_crtc --- linux-core/nv50_crtc.c | 591 ++++++++++++++++++++++++++++++---- linux-core/nv50_crtc.h | 5 +- linux-core/nv50_cursor.c | 16 +- linux-core/nv50_display.c | 2 +- linux-core/nv50_kms_wrapper.c | 578 +-------------------------------- linux-core/nv50_kms_wrapper.h | 14 +- linux-core/nv50_lut.c | 2 +- shared-core/nouveau_drv.h | 5 - 8 files changed, 551 insertions(+), 662 deletions(-) diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c index c95482c9..122d16ac 100644 --- a/linux-core/nv50_crtc.c +++ b/linux-core/nv50_crtc.c @@ -28,6 +28,9 @@ #include "nv50_cursor.h" #include "nv50_lut.h" #include "nv50_fb.h" +#include "nv50_kms_wrapper.h" +extern struct nouveau_hw_mode *nv50_kms_to_hw_mode(struct drm_display_mode *); +extern void nv50_kms_mirror_routing(struct drm_device *dev); static int nv50_crtc_validate_mode(struct nv50_crtc *crtc, struct nouveau_hw_mode *mode) { @@ -67,7 +70,7 @@ static int nv50_crtc_set_mode(struct nv50_crtc *crtc, struct nouveau_hw_mode *mo static int nv50_crtc_execute_mode(struct nv50_crtc *crtc) { - struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + struct drm_nouveau_private *dev_priv = crtc->base.dev->dev_private; struct nouveau_hw_mode *hw_mode; uint32_t hsync_dur, vsync_dur, hsync_start_to_end, vsync_start_to_end; uint32_t hunk1, vunk1, vunk2a, vunk2b; @@ -134,7 +137,7 @@ static int nv50_crtc_execute_mode(struct nv50_crtc *crtc) static int nv50_crtc_set_fb(struct nv50_crtc *crtc) { - struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + struct drm_nouveau_private *dev_priv = crtc->base.dev->dev_private; uint32_t offset = crtc->index * 0x400; NV50_DEBUG("\n"); @@ -167,7 +170,7 @@ static int nv50_crtc_set_fb(struct nv50_crtc *crtc) static int nv50_crtc_blank(struct nv50_crtc *crtc, bool blanked) { - struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + struct drm_nouveau_private *dev_priv = crtc->base.dev->dev_private; struct nouveau_gem_object *ngem = nouveau_gem_object(crtc->fb->gem); if (!ngem || !ngem->bo) { DRM_ERROR("no ngem/bo %p %p\n", ngem, ngem ? ngem->bo : NULL); @@ -226,7 +229,7 @@ static int nv50_crtc_blank(struct nv50_crtc *crtc, bool blanked) static int nv50_crtc_set_dither(struct nv50_crtc *crtc) { - struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + struct drm_nouveau_private *dev_priv = crtc->base.dev->dev_private; uint32_t offset = crtc->index * 0x400; NV50_DEBUG("\n"); @@ -256,7 +259,7 @@ static void nv50_crtc_calc_scale(struct nv50_crtc *crtc, uint32_t *outX, uint32_ static int nv50_crtc_set_scale(struct nv50_crtc *crtc) { - struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + struct drm_nouveau_private *dev_priv = crtc->base.dev->dev_private; uint32_t offset = crtc->index * 0x400; uint32_t outX, outY; @@ -320,7 +323,7 @@ static int nv50_crtc_calc_clock(struct nv50_crtc *crtc, clk = hw_mode->clock; /* These are in the g80 bios tables, at least in mine. */ - if (!get_pll_limits(crtc->dev, NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1(crtc->index), &limits)) + if (!get_pll_limits(crtc->base.dev, NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1(crtc->index), &limits)) return -EINVAL; minvco1 = limits.vco1.minfreq, maxvco1 = limits.vco1.maxfreq; @@ -402,7 +405,7 @@ static int nv50_crtc_calc_clock(struct nv50_crtc *crtc, static int nv50_crtc_set_clock(struct nv50_crtc *crtc) { - struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + struct drm_nouveau_private *dev_priv = crtc->base.dev->dev_private; uint32_t pll_reg = NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1(crtc->index); @@ -435,7 +438,7 @@ static int nv50_crtc_set_clock(struct nv50_crtc *crtc) static int nv50_crtc_set_clock_mode(struct nv50_crtc *crtc) { - struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + struct drm_nouveau_private *dev_priv = crtc->base.dev->dev_private; NV50_DEBUG("\n"); @@ -445,16 +448,16 @@ static int nv50_crtc_set_clock_mode(struct nv50_crtc *crtc) return 0; } -static int nv50_crtc_destroy(struct nv50_crtc *crtc) +static void nv50_crtc_destroy(struct drm_crtc *drm_crtc) { - struct drm_device *dev = crtc->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv50_display *display = nv50_get_display(dev); + struct nv50_crtc *crtc = to_nv50_crtc(drm_crtc); NV50_DEBUG("\n"); - if (!display || !crtc) - return -EINVAL; + if (!crtc) + return; + + drm_crtc_cleanup(&crtc->base); list_del(&crtc->item); @@ -464,56 +467,539 @@ static int nv50_crtc_destroy(struct nv50_crtc *crtc) kfree(crtc->mode); kfree(crtc->native_mode); - - if (dev_priv->free_crtc) - dev_priv->free_crtc(crtc); - - return 0; + kfree(crtc); } -int nv50_crtc_create(struct drm_device *dev, int index) +static int nv50_kms_crtc_cursor_set(struct drm_crtc *drm_crtc, + struct drm_file *file_priv, + uint32_t buffer_handle, + uint32_t width, uint32_t height) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv50_crtc *crtc = NULL; + struct drm_device *dev = drm_crtc->dev; + struct nv50_crtc *crtc = to_nv50_crtc(drm_crtc); + struct nv50_display *display = nv50_get_display(crtc->base.dev); + struct drm_gem_object *gem = NULL; + int ret = 0; + + if (width != 64 || height != 64) + return -EINVAL; + + if (buffer_handle) { + gem = drm_gem_object_lookup(dev, file_priv, buffer_handle); + if (!gem) + return -EINVAL; + + ret = nouveau_gem_pin(gem, NOUVEAU_GEM_DOMAIN_VRAM); + if (ret) { + mutex_lock(&dev->struct_mutex); + drm_gem_object_unreference(gem); + mutex_unlock(&dev->struct_mutex); + return ret; + } + + crtc->cursor->set_bo(crtc, gem); + crtc->cursor->set_offset(crtc); + ret = crtc->cursor->show(crtc); + } else { + crtc->cursor->set_bo(crtc, NULL); + crtc->cursor->hide(crtc); + } + + display->update(display); + return ret; +} + +static int nv50_kms_crtc_cursor_move(struct drm_crtc *drm_crtc, int x, int y) +{ + struct nv50_crtc *crtc = to_nv50_crtc(drm_crtc); + + return crtc->cursor->set_pos(crtc, x, y); +} + +void nv50_kms_crtc_gamma_set(struct drm_crtc *drm_crtc, u16 *r, u16 *g, u16 *b, + uint32_t size) +{ + struct nv50_crtc *crtc = to_nv50_crtc(drm_crtc); + + if (size != 256) + return; + + crtc->lut->set(crtc, (uint16_t *)r, (uint16_t *)g, (uint16_t *)b); +} + +int nv50_kms_crtc_set_config(struct drm_mode_set *set) +{ + int rval = 0, i; + uint32_t crtc_mask = 0; + struct drm_device *dev = NULL; + struct drm_nouveau_private *dev_priv = NULL; struct nv50_display *display = NULL; - int rval = 0; + struct drm_connector *drm_connector = NULL; + struct drm_encoder *drm_encoder = NULL; + struct drm_crtc *drm_crtc = NULL; + + struct nv50_crtc *crtc = NULL; + struct nv50_output *output = NULL; + struct nv50_connector *connector = NULL; + struct nouveau_hw_mode *hw_mode = NULL; + struct nv50_fb_info fb_info; + + bool blank = false; + bool switch_fb = false; + bool modeset = false; NV50_DEBUG("\n"); - /* This allows the public layer to do it's thing. */ - if (dev_priv->alloc_crtc) - crtc = dev_priv->alloc_crtc(dev); + /* + * Supported operations: + * - Switch mode. + * - Switch framebuffer. + * - Blank screen. + */ + /* Sanity checking */ + if (!set) { + DRM_ERROR("Sanity check failed\n"); + goto out; + } + + if (!set->crtc) { + DRM_ERROR("Sanity check failed\n"); + goto out; + } + + if (set->mode) { + if (set->fb) { + if (!drm_mode_equal(set->mode, &set->crtc->mode)) + modeset = true; + + if (set->fb != set->crtc->fb) + switch_fb = true; + + if (set->x != set->crtc->x || set->y != set->crtc->y) + switch_fb = true; + } + } else { + blank = true; + } + + if (!set->connectors && !blank) { + DRM_ERROR("Sanity check failed\n"); + goto out; + } + + /* Basic variable setting */ + dev = set->crtc->dev; + dev_priv = dev->dev_private; + display = nv50_get_display(dev); + crtc = to_nv50_crtc(set->crtc); + + /** + * Wiring up the encoders and connectors. + */ + + /* for switch_fb we verify if any important changes happened */ + if (!blank) { + /* Mode validation */ + hw_mode = nv50_kms_to_hw_mode(set->mode); + + rval = crtc->validate_mode(crtc, hw_mode); + + if (rval != MODE_OK) { + DRM_ERROR("Mode not ok\n"); + goto out; + } + + for (i = 0; i < set->num_connectors; i++) { + drm_connector = set->connectors[i]; + if (!drm_connector) { + DRM_ERROR("No connector\n"); + goto out; + } + connector = to_nv50_connector(drm_connector); + + /* This is to ensure it knows the connector subtype. */ + drm_connector->funcs->fill_modes(drm_connector, 0, 0); + + output = connector->to_output(connector, nv50_kms_connector_get_digital(drm_connector)); + if (!output) { + DRM_ERROR("No output\n"); + goto out; + } + + rval = output->validate_mode(output, hw_mode); + if (rval != MODE_OK) { + DRM_ERROR("Mode not ok\n"); + goto out; + } + + /* verify if any "sneaky" changes happened */ + if (output != connector->output) + modeset = true; + + if (output->crtc != crtc) + modeset = true; + } + } + + /* Now we verified if anything changed, fail if nothing has. */ + if (!modeset && !switch_fb && !blank) + DRM_INFO("A seemingly empty modeset encountered, this could be a bug.\n"); + + /* Validation done, move on to cleaning of existing structures. */ + if (modeset) { + /* find encoders that use this crtc. */ + list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) { + if (drm_encoder->crtc == set->crtc) { + /* find the connector that goes with it */ + list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) { + if (drm_connector->encoder == drm_encoder) { + drm_connector->encoder = NULL; + break; + } + } + drm_encoder->crtc = NULL; + } + } + + /* now find if our desired encoders or connectors are in use already. */ + for (i = 0; i < set->num_connectors; i++) { + drm_connector = set->connectors[i]; + if (!drm_connector) { + DRM_ERROR("No connector\n"); + goto out; + } + + if (!drm_connector->encoder) + continue; + + drm_encoder = drm_connector->encoder; + drm_connector->encoder = NULL; + + if (!drm_encoder->crtc) + continue; + + drm_crtc = drm_encoder->crtc; + drm_encoder->crtc = NULL; + + drm_crtc->enabled = false; + } + + /* Time to wire up the public encoder, the private one will be handled later. */ + for (i = 0; i < set->num_connectors; i++) { + drm_connector = set->connectors[i]; + if (!drm_connector) { + DRM_ERROR("No connector\n"); + goto out; + } + + output = connector->to_output(connector, nv50_kms_connector_get_digital(drm_connector)); + if (!output) { + DRM_ERROR("No output\n"); + goto out; + } + + output->base.crtc = set->crtc; + set->crtc->enabled = true; + drm_connector->encoder = &output->base; + } + } + + /** + * Disable crtc. + */ + + if (blank) { + crtc = to_nv50_crtc(set->crtc); + + set->crtc->enabled = false; + + /* disconnect encoders and connectors */ + for (i = 0; i < set->num_connectors; i++) { + drm_connector = set->connectors[i]; + + if (!drm_connector->encoder) + continue; + + drm_connector->encoder->crtc = NULL; + drm_connector->encoder = NULL; + } + } + + /** + * All state should now be updated, now onto the real work. + */ + + /* mirror everything to the private structs */ + nv50_kms_mirror_routing(dev); + + /** + * Bind framebuffer. + */ + + if (switch_fb) { + crtc = to_nv50_crtc(set->crtc); + + /* set framebuffer */ + set->crtc->fb = set->fb; + + /* set private framebuffer */ + crtc = to_nv50_crtc(set->crtc); + fb_info.gem = nv50_framebuffer(set->fb)->gem; + fb_info.width = set->fb->width; + fb_info.height = set->fb->height; + fb_info.depth = set->fb->depth; + fb_info.bpp = set->fb->bits_per_pixel; + fb_info.pitch = set->fb->pitch; + fb_info.x = set->x; + fb_info.y = set->y; + + rval = crtc->fb->bind(crtc, &fb_info); + if (rval != 0) { + DRM_ERROR("fb_bind failed\n"); + goto out; + } + } + + /* this is !cursor_show */ + if (!crtc->cursor->enabled) { + rval = crtc->cursor->enable(crtc); + if (rval != 0) { + DRM_ERROR("cursor_enable failed\n"); + goto out; + } + } + + /** + * Blanking. + */ + + if (blank) { + crtc = to_nv50_crtc(set->crtc); + + rval = crtc->blank(crtc, true); + if (rval != 0) { + DRM_ERROR("blanking failed\n"); + goto out; + } + + /* detach any outputs that are currently unused */ + list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) { + if (!drm_encoder->crtc) { + output = to_nv50_output(drm_encoder); + + rval = output->execute_mode(output, true); + if (rval != 0) { + DRM_ERROR("detaching output failed\n"); + goto out; + } + } + } + } + + /** + * Change framebuffer, without changing mode. + */ + + if (switch_fb && !modeset && !blank) { + crtc = to_nv50_crtc(set->crtc); + + rval = crtc->set_fb(crtc); + if (rval != 0) { + DRM_ERROR("set_fb failed\n"); + goto out; + } + + /* this also sets the fb offset */ + rval = crtc->blank(crtc, false); + if (rval != 0) { + DRM_ERROR("unblanking failed\n"); + goto out; + } + } + + /** + * Normal modesetting. + */ + + if (modeset) { + crtc = to_nv50_crtc(set->crtc); + + /* disconnect unused outputs */ + list_for_each_entry(output, &display->outputs, item) { + if (output->crtc) { + crtc_mask |= 1 << output->crtc->index; + } else { + rval = output->execute_mode(output, true); + if (rval != 0) { + DRM_ERROR("detaching output failed\n"); + goto out; + } + } + } + + /* blank any unused crtcs */ + list_for_each_entry(crtc, &display->crtcs, item) { + if (!(crtc_mask & (1 << crtc->index))) + crtc->blank(crtc, true); + } + + crtc = to_nv50_crtc(set->crtc); + + rval = crtc->set_mode(crtc, hw_mode); + if (rval != 0) { + DRM_ERROR("crtc mode set failed\n"); + goto out; + } + + /* find native mode. */ + list_for_each_entry(output, &display->outputs, item) { + if (output->crtc != crtc) + continue; + + *crtc->native_mode = *output->native_mode; + list_for_each_entry(connector, &display->connectors, item) { + if (connector->output != output) + continue; + + crtc->requested_scaling_mode = connector->requested_scaling_mode; + crtc->use_dithering = connector->use_dithering; + break; + } + + if (crtc->requested_scaling_mode == SCALE_NON_GPU) + crtc->use_native_mode = false; + else + crtc->use_native_mode = true; + + break; /* no use in finding more than one mode */ + } + + rval = crtc->execute_mode(crtc); + if (rval != 0) { + DRM_ERROR("crtc execute mode failed\n"); + goto out; + } + + list_for_each_entry(output, &display->outputs, item) { + if (output->crtc != crtc) + continue; + + rval = output->execute_mode(output, false); + if (rval != 0) { + DRM_ERROR("output execute mode failed\n"); + goto out; + } + } + + rval = crtc->set_scale(crtc); + if (rval != 0) { + DRM_ERROR("crtc set scale failed\n"); + goto out; + } + + /* next line changes crtc, so putting it here is important */ + display->last_crtc = crtc->index; + } + + /* always reset dpms, regardless if any other modesetting is done. */ + if (!blank) { + /* this is executed immediately */ + list_for_each_entry(output, &display->outputs, item) { + if (output->crtc != crtc) + continue; + + rval = output->set_power_mode(output, DRM_MODE_DPMS_ON); + if (rval != 0) { + DRM_ERROR("output set power mode failed\n"); + goto out; + } + } + + /* update dpms state to DPMSModeOn */ + for (i = 0; i < set->num_connectors; i++) { + drm_connector = set->connectors[i]; + if (!drm_connector) { + DRM_ERROR("No connector\n"); + goto out; + } + + rval = drm_connector_property_set_value(drm_connector, + dev->mode_config.dpms_property, + DRM_MODE_DPMS_ON); + if (rval != 0) { + DRM_ERROR("failed to update dpms state\n"); + goto out; + } + } + } + + display->update(display); + + /* Update the current mode, now that all has gone well. */ + if (modeset) { + set->crtc->mode = *(set->mode); + set->crtc->x = set->x; + set->crtc->y = set->y; + } + + kfree(hw_mode); + + return 0; + +out: + kfree(hw_mode); + + if (rval != 0) + return rval; + else + return -EINVAL; +} + +static const struct drm_crtc_funcs nv50_kms_crtc_funcs = { + .save = NULL, + .restore = NULL, + .cursor_set = nv50_kms_crtc_cursor_set, + .cursor_move = nv50_kms_crtc_cursor_move, + .gamma_set = nv50_kms_crtc_gamma_set, + .set_config = nv50_kms_crtc_set_config, + .destroy = nv50_crtc_destroy, +}; + +int nv50_crtc_create(struct drm_device *dev, int index) +{ + struct nv50_crtc *crtc = NULL; + struct nv50_display *display = NULL; + + NV50_DEBUG("\n"); + + display = nv50_get_display(dev); + if (!display) + return -EINVAL; + + crtc = kzalloc(sizeof(*crtc), GFP_KERNEL); if (!crtc) return -ENOMEM; - crtc->dev = dev; + crtc->mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); + if (!crtc->mode) { + kfree(crtc); + return -ENOMEM; + } - display = nv50_get_display(dev); - if (!display) { - rval = -EINVAL; - goto out; + crtc->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); + if (!crtc->native_mode) { + kfree(crtc->mode); + kfree(crtc); + return -ENOMEM; } list_add_tail(&crtc->item, &display->crtcs); crtc->index = index; - - crtc->mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); - crtc->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); - crtc->requested_scaling_mode = SCALE_INVALID; crtc->scaling_mode = SCALE_INVALID; - if (!crtc->mode || !crtc->native_mode) { - rval = -ENOMEM; - goto out; - } - - nv50_fb_create(crtc); - nv50_lut_create(crtc); - nv50_cursor_create(crtc); - /* set function pointers */ crtc->validate_mode = nv50_crtc_validate_mode; crtc->set_mode = nv50_crtc_set_mode; @@ -524,17 +1010,12 @@ int nv50_crtc_create(struct drm_device *dev, int index) crtc->set_scale = nv50_crtc_set_scale; crtc->set_clock = nv50_crtc_set_clock; crtc->set_clock_mode = nv50_crtc_set_clock_mode; - crtc->destroy = nv50_crtc_destroy; + drm_crtc_init(dev, &crtc->base, &nv50_kms_crtc_funcs); + drm_mode_crtc_set_gamma_size(&crtc->base, 256); + + nv50_fb_create(crtc); + nv50_lut_create(crtc); + nv50_cursor_create(crtc); return 0; - -out: - if (crtc->mode) - kfree(crtc->mode); - if (crtc->native_mode) - kfree(crtc->native_mode); - if (dev_priv->free_crtc) - dev_priv->free_crtc(crtc); - - return rval; } diff --git a/linux-core/nv50_crtc.h b/linux-core/nv50_crtc.h index b4b83584..11b343ed 100644 --- a/linux-core/nv50_crtc.h +++ b/linux-core/nv50_crtc.h @@ -34,11 +34,12 @@ struct nv50_lut; struct nv50_fb; struct nv50_crtc { + struct drm_crtc base; struct list_head item; - struct drm_device *dev; +/* struct drm_device *dev; IN BASE */ int index; - bool enabled; +/* bool enabled; IN BASE */ bool blanked; struct nouveau_hw_mode *mode; diff --git a/linux-core/nv50_cursor.c b/linux-core/nv50_cursor.c index 15dbd34b..5657a269 100644 --- a/linux-core/nv50_cursor.c +++ b/linux-core/nv50_cursor.c @@ -30,7 +30,7 @@ static int nv50_cursor_enable(struct nv50_crtc *crtc) { - struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + struct drm_nouveau_private *dev_priv = crtc->base.dev->dev_private; NV50_DEBUG("\n"); @@ -48,7 +48,7 @@ static int nv50_cursor_enable(struct nv50_crtc *crtc) static int nv50_cursor_disable(struct nv50_crtc *crtc) { - struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + struct drm_nouveau_private *dev_priv = crtc->base.dev->dev_private; NV50_DEBUG("\n"); @@ -63,7 +63,7 @@ static int nv50_cursor_disable(struct nv50_crtc *crtc) /* Calling update or changing the stored cursor state is left to the higher level ioctl's. */ static int nv50_cursor_show(struct nv50_crtc *crtc) { - struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + struct drm_nouveau_private *dev_priv = crtc->base.dev->dev_private; uint32_t offset = crtc->index * 0x400; NV50_DEBUG("\n"); @@ -83,7 +83,7 @@ static int nv50_cursor_show(struct nv50_crtc *crtc) static int nv50_cursor_hide(struct nv50_crtc *crtc) { - struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + struct drm_nouveau_private *dev_priv = crtc->base.dev->dev_private; uint32_t offset = crtc->index * 0x400; NV50_DEBUG("\n"); @@ -96,7 +96,7 @@ static int nv50_cursor_hide(struct nv50_crtc *crtc) static int nv50_cursor_set_pos(struct nv50_crtc *crtc, int x, int y) { - struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + struct drm_nouveau_private *dev_priv = crtc->base.dev->dev_private; NV_WRITE(NV50_HW_CURSOR_POS(crtc->index), ((y & 0xFFFF) << 16) | (x & 0xFFFF)); /* Needed to make the cursor move. */ @@ -107,7 +107,7 @@ static int nv50_cursor_set_pos(struct nv50_crtc *crtc, int x, int y) static int nv50_cursor_set_offset(struct nv50_crtc *crtc) { - struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + struct drm_nouveau_private *dev_priv = crtc->base.dev->dev_private; struct nouveau_gem_object *ngem = nouveau_gem_object(crtc->cursor->gem); NV50_DEBUG("\n"); @@ -128,9 +128,9 @@ nv50_cursor_set_bo(struct nv50_crtc *crtc, struct drm_gem_object *gem) struct nv50_cursor *cursor = crtc->cursor; if (cursor->gem) { - mutex_lock(&crtc->dev->struct_mutex); + mutex_lock(&crtc->base.dev->struct_mutex); drm_gem_object_unreference(cursor->gem); - mutex_unlock(&crtc->dev->struct_mutex); + mutex_unlock(&crtc->base.dev->struct_mutex); cursor->gem = NULL; } diff --git a/linux-core/nv50_display.c b/linux-core/nv50_display.c index f50e6d6c..2cd5b619 100644 --- a/linux-core/nv50_display.c +++ b/linux-core/nv50_display.c @@ -150,7 +150,7 @@ static int nv50_display_disable(struct nv50_display *display) /* Almost like ack'ing a vblank interrupt, maybe in the spirit of cleaning up? */ list_for_each_entry(crtc, &display->crtcs, item) { - if (crtc->enabled) { + if (crtc->base.enabled) { uint32_t mask; if (crtc->index == 1) diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index b47d1227..d60fc5cc 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -39,32 +39,6 @@ struct nv50_kms_priv *nv50_get_kms_priv(struct drm_device *dev) return dev_priv->kms_priv; } -/* - * Allocation functions. - */ - -static void *nv50_kms_alloc_crtc(struct drm_device *dev) -{ - struct nv50_kms_priv *kms_priv = nv50_get_kms_priv(dev); - struct nv50_kms_crtc *crtc = kzalloc(sizeof(struct nv50_kms_crtc), GFP_KERNEL); - - if (!crtc) - return NULL; - - list_add_tail(&crtc->item, &kms_priv->crtcs); - - return &(crtc->priv); -} - -static void nv50_kms_free_crtc(void *crtc) -{ - struct nv50_kms_crtc *kms_crtc = from_nv50_crtc(crtc); - - list_del(&kms_crtc->item); - - kfree(kms_crtc); -} - /* * Mode conversion functions. */ @@ -102,14 +76,13 @@ struct nouveau_hw_mode *nv50_kms_to_hw_mode(struct drm_display_mode *mode) * State mirroring functions. */ -static void nv50_kms_mirror_routing(struct drm_device *dev) +void nv50_kms_mirror_routing(struct drm_device *dev) { struct nv50_display *display = nv50_get_display(dev); struct nv50_crtc *crtc = NULL; struct nv50_output *output = NULL; struct nv50_connector *connector = NULL; struct drm_connector *drm_connector = NULL; - struct drm_crtc *drm_crtc = NULL; /* Wipe all previous connections. */ list_for_each_entry(connector, &display->connectors, item) { @@ -136,13 +109,6 @@ static void nv50_kms_mirror_routing(struct drm_device *dev) } } } - - /* mirror crtc active state */ - list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) { - crtc = to_nv50_crtc(drm_crtc); - - crtc->enabled = drm_crtc->enabled; - } } /* @@ -215,538 +181,6 @@ static const struct drm_mode_config_funcs nv50_kms_mode_funcs = { .fb_changed = nv50_kms_fb_changed, }; -/* - * CRTC functions. - */ - -static int nv50_kms_crtc_cursor_set(struct drm_crtc *drm_crtc, - struct drm_file *file_priv, - uint32_t buffer_handle, - uint32_t width, uint32_t height) -{ - struct drm_device *dev = drm_crtc->dev; - struct nv50_crtc *crtc = to_nv50_crtc(drm_crtc); - struct nv50_display *display = nv50_get_display(crtc->dev); - struct drm_gem_object *gem = NULL; - int ret = 0; - - if (width != 64 || height != 64) - return -EINVAL; - - if (buffer_handle) { - gem = drm_gem_object_lookup(dev, file_priv, buffer_handle); - if (!gem) - return -EINVAL; - - ret = nouveau_gem_pin(gem, NOUVEAU_GEM_DOMAIN_VRAM); - if (ret) { - mutex_lock(&dev->struct_mutex); - drm_gem_object_unreference(gem); - mutex_unlock(&dev->struct_mutex); - return ret; - } - - crtc->cursor->set_bo(crtc, gem); - crtc->cursor->set_offset(crtc); - ret = crtc->cursor->show(crtc); - } else { - crtc->cursor->set_bo(crtc, NULL); - crtc->cursor->hide(crtc); - } - - display->update(display); - return ret; -} - -static int nv50_kms_crtc_cursor_move(struct drm_crtc *drm_crtc, int x, int y) -{ - struct nv50_crtc *crtc = to_nv50_crtc(drm_crtc); - - return crtc->cursor->set_pos(crtc, x, y); -} - -void nv50_kms_crtc_gamma_set(struct drm_crtc *drm_crtc, u16 *r, u16 *g, u16 *b, - uint32_t size) -{ - struct nv50_crtc *crtc = to_nv50_crtc(drm_crtc); - - if (size != 256) - return; - - crtc->lut->set(crtc, (uint16_t *)r, (uint16_t *)g, (uint16_t *)b); -} - -int nv50_kms_crtc_set_config(struct drm_mode_set *set) -{ - int rval = 0, i; - uint32_t crtc_mask = 0; - struct drm_device *dev = NULL; - struct drm_nouveau_private *dev_priv = NULL; - struct nv50_display *display = NULL; - struct drm_connector *drm_connector = NULL; - struct drm_encoder *drm_encoder = NULL; - struct drm_crtc *drm_crtc = NULL; - - struct nv50_crtc *crtc = NULL; - struct nv50_output *output = NULL; - struct nv50_connector *connector = NULL; - struct nouveau_hw_mode *hw_mode = NULL; - struct nv50_fb_info fb_info; - - bool blank = false; - bool switch_fb = false; - bool modeset = false; - - NV50_DEBUG("\n"); - - /* - * Supported operations: - * - Switch mode. - * - Switch framebuffer. - * - Blank screen. - */ - - /* Sanity checking */ - if (!set) { - DRM_ERROR("Sanity check failed\n"); - goto out; - } - - if (!set->crtc) { - DRM_ERROR("Sanity check failed\n"); - goto out; - } - - if (set->mode) { - if (set->fb) { - if (!drm_mode_equal(set->mode, &set->crtc->mode)) - modeset = true; - - if (set->fb != set->crtc->fb) - switch_fb = true; - - if (set->x != set->crtc->x || set->y != set->crtc->y) - switch_fb = true; - } - } else { - blank = true; - } - - if (!set->connectors && !blank) { - DRM_ERROR("Sanity check failed\n"); - goto out; - } - - /* Basic variable setting */ - dev = set->crtc->dev; - dev_priv = dev->dev_private; - display = nv50_get_display(dev); - crtc = to_nv50_crtc(set->crtc); - - /** - * Wiring up the encoders and connectors. - */ - - /* for switch_fb we verify if any important changes happened */ - if (!blank) { - /* Mode validation */ - hw_mode = nv50_kms_to_hw_mode(set->mode); - - rval = crtc->validate_mode(crtc, hw_mode); - - if (rval != MODE_OK) { - DRM_ERROR("Mode not ok\n"); - goto out; - } - - for (i = 0; i < set->num_connectors; i++) { - drm_connector = set->connectors[i]; - if (!drm_connector) { - DRM_ERROR("No connector\n"); - goto out; - } - connector = to_nv50_connector(drm_connector); - - /* This is to ensure it knows the connector subtype. */ - drm_connector->funcs->fill_modes(drm_connector, 0, 0); - - output = connector->to_output(connector, nv50_kms_connector_get_digital(drm_connector)); - if (!output) { - DRM_ERROR("No output\n"); - goto out; - } - - rval = output->validate_mode(output, hw_mode); - if (rval != MODE_OK) { - DRM_ERROR("Mode not ok\n"); - goto out; - } - - /* verify if any "sneaky" changes happened */ - if (output != connector->output) - modeset = true; - - if (output->crtc != crtc) - modeset = true; - } - } - - /* Now we verified if anything changed, fail if nothing has. */ - if (!modeset && !switch_fb && !blank) - DRM_INFO("A seemingly empty modeset encountered, this could be a bug.\n"); - - /* Validation done, move on to cleaning of existing structures. */ - if (modeset) { - /* find encoders that use this crtc. */ - list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) { - if (drm_encoder->crtc == set->crtc) { - /* find the connector that goes with it */ - list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) { - if (drm_connector->encoder == drm_encoder) { - drm_connector->encoder = NULL; - break; - } - } - drm_encoder->crtc = NULL; - } - } - - /* now find if our desired encoders or connectors are in use already. */ - for (i = 0; i < set->num_connectors; i++) { - drm_connector = set->connectors[i]; - if (!drm_connector) { - DRM_ERROR("No connector\n"); - goto out; - } - - if (!drm_connector->encoder) - continue; - - drm_encoder = drm_connector->encoder; - drm_connector->encoder = NULL; - - if (!drm_encoder->crtc) - continue; - - drm_crtc = drm_encoder->crtc; - drm_encoder->crtc = NULL; - - drm_crtc->enabled = false; - } - - /* Time to wire up the public encoder, the private one will be handled later. */ - for (i = 0; i < set->num_connectors; i++) { - drm_connector = set->connectors[i]; - if (!drm_connector) { - DRM_ERROR("No connector\n"); - goto out; - } - - output = connector->to_output(connector, nv50_kms_connector_get_digital(drm_connector)); - if (!output) { - DRM_ERROR("No output\n"); - goto out; - } - - output->base.crtc = set->crtc; - set->crtc->enabled = true; - drm_connector->encoder = &output->base; - } - } - - /** - * Disable crtc. - */ - - if (blank) { - crtc = to_nv50_crtc(set->crtc); - - set->crtc->enabled = false; - - /* disconnect encoders and connectors */ - for (i = 0; i < set->num_connectors; i++) { - drm_connector = set->connectors[i]; - - if (!drm_connector->encoder) - continue; - - drm_connector->encoder->crtc = NULL; - drm_connector->encoder = NULL; - } - } - - /** - * All state should now be updated, now onto the real work. - */ - - /* mirror everything to the private structs */ - nv50_kms_mirror_routing(dev); - - /** - * Bind framebuffer. - */ - - if (switch_fb) { - crtc = to_nv50_crtc(set->crtc); - - /* set framebuffer */ - set->crtc->fb = set->fb; - - /* set private framebuffer */ - crtc = to_nv50_crtc(set->crtc); - fb_info.gem = nv50_framebuffer(set->fb)->gem; - fb_info.width = set->fb->width; - fb_info.height = set->fb->height; - fb_info.depth = set->fb->depth; - fb_info.bpp = set->fb->bits_per_pixel; - fb_info.pitch = set->fb->pitch; - fb_info.x = set->x; - fb_info.y = set->y; - - rval = crtc->fb->bind(crtc, &fb_info); - if (rval != 0) { - DRM_ERROR("fb_bind failed\n"); - goto out; - } - } - - /* this is !cursor_show */ - if (!crtc->cursor->enabled) { - rval = crtc->cursor->enable(crtc); - if (rval != 0) { - DRM_ERROR("cursor_enable failed\n"); - goto out; - } - } - - /** - * Blanking. - */ - - if (blank) { - crtc = to_nv50_crtc(set->crtc); - - rval = crtc->blank(crtc, true); - if (rval != 0) { - DRM_ERROR("blanking failed\n"); - goto out; - } - - /* detach any outputs that are currently unused */ - list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) { - if (!drm_encoder->crtc) { - output = to_nv50_output(drm_encoder); - - rval = output->execute_mode(output, true); - if (rval != 0) { - DRM_ERROR("detaching output failed\n"); - goto out; - } - } - } - } - - /** - * Change framebuffer, without changing mode. - */ - - if (switch_fb && !modeset && !blank) { - crtc = to_nv50_crtc(set->crtc); - - rval = crtc->set_fb(crtc); - if (rval != 0) { - DRM_ERROR("set_fb failed\n"); - goto out; - } - - /* this also sets the fb offset */ - rval = crtc->blank(crtc, false); - if (rval != 0) { - DRM_ERROR("unblanking failed\n"); - goto out; - } - } - - /** - * Normal modesetting. - */ - - if (modeset) { - crtc = to_nv50_crtc(set->crtc); - - /* disconnect unused outputs */ - list_for_each_entry(output, &display->outputs, item) { - if (output->crtc) { - crtc_mask |= 1 << output->crtc->index; - } else { - rval = output->execute_mode(output, true); - if (rval != 0) { - DRM_ERROR("detaching output failed\n"); - goto out; - } - } - } - - /* blank any unused crtcs */ - list_for_each_entry(crtc, &display->crtcs, item) { - if (!(crtc_mask & (1 << crtc->index))) - crtc->blank(crtc, true); - } - - crtc = to_nv50_crtc(set->crtc); - - rval = crtc->set_mode(crtc, hw_mode); - if (rval != 0) { - DRM_ERROR("crtc mode set failed\n"); - goto out; - } - - /* find native mode. */ - list_for_each_entry(output, &display->outputs, item) { - if (output->crtc != crtc) - continue; - - *crtc->native_mode = *output->native_mode; - list_for_each_entry(connector, &display->connectors, item) { - if (connector->output != output) - continue; - - crtc->requested_scaling_mode = connector->requested_scaling_mode; - crtc->use_dithering = connector->use_dithering; - break; - } - - if (crtc->requested_scaling_mode == SCALE_NON_GPU) - crtc->use_native_mode = false; - else - crtc->use_native_mode = true; - - break; /* no use in finding more than one mode */ - } - - rval = crtc->execute_mode(crtc); - if (rval != 0) { - DRM_ERROR("crtc execute mode failed\n"); - goto out; - } - - list_for_each_entry(output, &display->outputs, item) { - if (output->crtc != crtc) - continue; - - rval = output->execute_mode(output, false); - if (rval != 0) { - DRM_ERROR("output execute mode failed\n"); - goto out; - } - } - - rval = crtc->set_scale(crtc); - if (rval != 0) { - DRM_ERROR("crtc set scale failed\n"); - goto out; - } - - /* next line changes crtc, so putting it here is important */ - display->last_crtc = crtc->index; - } - - /* always reset dpms, regardless if any other modesetting is done. */ - if (!blank) { - /* this is executed immediately */ - list_for_each_entry(output, &display->outputs, item) { - if (output->crtc != crtc) - continue; - - rval = output->set_power_mode(output, DRM_MODE_DPMS_ON); - if (rval != 0) { - DRM_ERROR("output set power mode failed\n"); - goto out; - } - } - - /* update dpms state to DPMSModeOn */ - for (i = 0; i < set->num_connectors; i++) { - drm_connector = set->connectors[i]; - if (!drm_connector) { - DRM_ERROR("No connector\n"); - goto out; - } - - rval = drm_connector_property_set_value(drm_connector, - dev->mode_config.dpms_property, - DRM_MODE_DPMS_ON); - if (rval != 0) { - DRM_ERROR("failed to update dpms state\n"); - goto out; - } - } - } - - display->update(display); - - /* Update the current mode, now that all has gone well. */ - if (modeset) { - set->crtc->mode = *(set->mode); - set->crtc->x = set->x; - set->crtc->y = set->y; - } - - kfree(hw_mode); - - return 0; - -out: - kfree(hw_mode); - - if (rval != 0) - return rval; - else - return -EINVAL; -} - -static void nv50_kms_crtc_destroy(struct drm_crtc *drm_crtc) -{ - struct nv50_crtc *crtc = to_nv50_crtc(drm_crtc); - - drm_crtc_cleanup(drm_crtc); - - /* this will even destroy the public structure. */ - crtc->destroy(crtc); -} - -static const struct drm_crtc_funcs nv50_kms_crtc_funcs = { - .save = NULL, - .restore = NULL, - .cursor_set = nv50_kms_crtc_cursor_set, - .cursor_move = nv50_kms_crtc_cursor_move, - .gamma_set = nv50_kms_crtc_gamma_set, - .set_config = nv50_kms_crtc_set_config, - .destroy = nv50_kms_crtc_destroy, -}; - -static int nv50_kms_crtcs_init(struct drm_device *dev) -{ - struct nv50_display *display = nv50_get_display(dev); - struct nv50_crtc *crtc = NULL; - - /* - * This may look a bit confusing, but: - * The internal structure is already allocated and so is the public one. - * Just a matter of getting to the memory and register it. - */ - list_for_each_entry(crtc, &display->crtcs, item) { - struct drm_crtc *drm_crtc = to_nv50_kms_crtc(crtc); - - drm_crtc_init(dev, drm_crtc, &nv50_kms_crtc_funcs); - - /* init lut storage */ - drm_mode_crtc_set_gamma_size(drm_crtc, 256); - } - - return 0; -} - /* * Main functions */ @@ -763,11 +197,6 @@ int nv50_kms_init(struct drm_device *dev) dev_priv->kms_priv = kms_priv; - /* function pointers */ - /* an allocation interface that deals with the outside world, without polluting the core. */ - dev_priv->alloc_crtc = nv50_kms_alloc_crtc; - dev_priv->free_crtc = nv50_kms_free_crtc; - /* bios is needed for tables. */ rval = nouveau_parse_bios(dev); if (rval != 0) @@ -809,11 +238,6 @@ int nv50_kms_init(struct drm_device *dev) if (rval != 0) goto out; - /* init external layer */ - rval = nv50_kms_crtcs_init(dev); - if (rval != 0) - goto out; - /* init now, this'll kill the textmode */ rval = display->init(display); if (rval != 0) diff --git a/linux-core/nv50_kms_wrapper.h b/linux-core/nv50_kms_wrapper.h index 5680d4be..01da2377 100644 --- a/linux-core/nv50_kms_wrapper.h +++ b/linux-core/nv50_kms_wrapper.h @@ -43,23 +43,11 @@ /* Link internal modesetting structure to interface. */ -struct nv50_kms_crtc { - struct list_head item; - - struct nv50_crtc priv; - struct drm_crtc pub; -}; - struct nv50_kms_priv { struct list_head crtcs; }; -/* Get private functions. */ -#define from_nv50_kms_crtc(x) container_of(x, struct nv50_kms_crtc, pub) -#define from_nv50_crtc(x) container_of(x, struct nv50_kms_crtc, priv) - -#define to_nv50_crtc(x) (&(from_nv50_kms_crtc(x)->priv)) -#define to_nv50_kms_crtc(x) (&(from_nv50_crtc(x)->pub)) +#define to_nv50_crtc(x) container_of((x), struct nv50_crtc, base) #define to_nv50_output(x) container_of((x), struct nv50_output, base) #define to_nv50_connector(x) container_of((x), struct nv50_connector, base) diff --git a/linux-core/nv50_lut.c b/linux-core/nv50_lut.c index b47691ff..1cd7be71 100644 --- a/linux-core/nv50_lut.c +++ b/linux-core/nv50_lut.c @@ -31,7 +31,7 @@ static int nv50_lut_alloc(struct nv50_crtc *crtc) { - struct drm_device *dev = crtc->dev; + struct drm_device *dev = crtc->base.dev; int ret; NV50_DEBUG("\n"); diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index 9531f46f..f0b068fb 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -341,11 +341,6 @@ struct drm_nouveau_private { void *display_priv; /* internal modesetting */ void *kms_priv; /* related to public interface */ - /* Hook these up to the "public interface" to accomodate a certain allocation style. */ - /* This is to avoid polluting the internal interface. */ - void *(*alloc_crtc) (struct drm_device *dev); - void (*free_crtc) (void *crtc); - struct bios bios; struct {