From: <ai...@ke...> - 2008-07-25 22:46:55
|
linux-core/drm_crtc.c | 77 ++++++++++++ linux-core/drm_crtc.h | 14 +- linux-core/drm_crtc_helper.c | 3 linux-core/drm_drv.c | 5 linux-core/drm_lock.c | 21 ++- linux-core/drm_modes.c | 4 linux-core/intel_crt.c | 4 linux-core/intel_display.c | 1 linux-core/intel_tv.c | 2 linux-core/nouveau_bios.c | 51 +++++++- linux-core/nv50_connector.c | 54 +++++++- linux-core/nv50_connector.h | 7 - linux-core/nv50_crtc.c | 12 + linux-core/nv50_crtc.h | 4 linux-core/nv50_dac.c | 42 ++++++ linux-core/nv50_display.c | 2 linux-core/nv50_display.h | 2 linux-core/nv50_kms_wrapper.c | 253 +++++++++++++++++++++++++++++++++++------- linux-core/nv50_kms_wrapper.h | 2 linux-core/nv50_output.h | 2 shared-core/drm.h | 10 + shared-core/nouveau_drm.h | 20 ++- shared-core/nouveau_drv.h | 4 shared-core/nouveau_fifo.c | 1 shared-core/nouveau_mem.c | 82 ++++++++++++- shared-core/nouveau_object.c | 6 26 files changed, 584 insertions(+), 101 deletions(-) New commits: commit 31da9492a4129f5255e949836c51e9dfbfb270c4 Merge: 11d3075... 7fd7ba8... Author: Dave Airlie <ai...@li...> Date: Sat Jul 26 08:46:38 2008 +1000 Merge remote branch 'origin/modesetting-101' into modesetting-gem commit 7fd7ba87f35aa4881e99b95bab4151b3f9db9b8e Author: Dave Airlie <ai...@re...> Date: Fri Jul 25 13:30:08 2008 +1000 drm: don't set the signal blocker on the master process. this lets us debug the X server through xkb startup. Not sure what the correct answer is, probably X needs to drop the lock when execing stuff, with input hotplug it can get xkb stuff at any time I believe. diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index 6bbf144..6e90e97 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -107,14 +107,19 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) ret ? "interrupted" : "has lock"); if (ret) return ret; - sigemptyset(&dev->sigmask); - sigaddset(&dev->sigmask, SIGSTOP); - sigaddset(&dev->sigmask, SIGTSTP); - sigaddset(&dev->sigmask, SIGTTIN); - sigaddset(&dev->sigmask, SIGTTOU); - dev->sigdata.context = lock->context; - dev->sigdata.lock = master->lock.hw_lock; - block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); + /* don't set the block all signals on the master process for now + * really probably not the correct answer but lets us debug xkb + * xserver for now */ + if (!file_priv->is_master) { + sigemptyset(&dev->sigmask); + sigaddset(&dev->sigmask, SIGSTOP); + sigaddset(&dev->sigmask, SIGTSTP); + sigaddset(&dev->sigmask, SIGTTIN); + sigaddset(&dev->sigmask, SIGTTOU); + dev->sigdata.context = lock->context; + dev->sigdata.lock = master->lock.hw_lock; + block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); + } if (dev->driver->dma_ready && (lock->flags & _DRM_LOCK_READY)) dev->driver->dma_ready(dev); commit 66723c09f5e4d60f1c746d112b065bacc1cfa89f Author: Dave Airlie <ai...@li...> Date: Sat Jul 26 08:43:59 2008 +1000 modesetting: pass file priv to cursor diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 91bff1f..7ee3321 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1445,7 +1445,7 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, if (req->flags & DRM_MODE_CURSOR_BO) { /* Turn of the cursor if handle is 0 */ if (crtc->funcs->cursor_set) { - ret = crtc->funcs->cursor_set(crtc, req->handle, req->width, req->height); + ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, req->width, req->height); } else { DRM_ERROR("crtc does not support cursor\n"); ret = -EFAULT; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 117b721..bfccdeb 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -299,8 +299,8 @@ struct drm_crtc_funcs { void (*restore)(struct drm_crtc *crtc); /* resume? */ /* cursor controls */ - int (*cursor_set)(struct drm_crtc *crtc, uint32_t buffer_handle, - uint32_t width, uint32_t height); + int (*cursor_set)(struct drm_crtc *crtc, struct drm_file *file_priv, + uint32_t handle, uint32_t width, uint32_t height); int (*cursor_move)(struct drm_crtc *crtc, int x, int y); /* Set gamma on the CRTC */ diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 29aae16..b8077bd 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -972,6 +972,7 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) } static int intel_crtc_cursor_set(struct drm_crtc *crtc, + struct drm_file *file_priv, uint32_t handle, uint32_t width, uint32_t height) { diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 1c4b52d..77271c1 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -236,8 +236,10 @@ static const struct drm_mode_config_funcs nv50_kms_mode_funcs = { * CRTC functions. */ -static int nv50_kms_crtc_cursor_set(struct drm_crtc *drm_crtc, uint32_t buffer_handle, - uint32_t width, uint32_t height) +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 nv50_crtc *crtc = to_nv50_crtc(drm_crtc); struct nv50_display *display = nv50_get_display(crtc->dev); commit 2be292f6ea8df96afc1454f30918b1b391fba2ba Author: Dave Airlie <ai...@li...> Date: Sat Jul 26 08:43:01 2008 +1000 nv50: remove TRUE/FALSE diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c index c4ca7e7..f56aa33 100644 --- a/linux-core/nv50_crtc.c +++ b/linux-core/nv50_crtc.c @@ -127,7 +127,7 @@ static int nv50_crtc_execute_mode(struct nv50_crtc *crtc) OUT_MODE(NV50_CRTC0_SCALE_CENTER_OFFSET + offset, NV50_CRTC_SCALE_CENTER_OFFSET_VAL(0,0)); /* Maybe move this as well? */ - crtc->blank(crtc, FALSE); + crtc->blank(crtc, false); return 0; } diff --git a/linux-core/nv50_display.c b/linux-core/nv50_display.c index b68c4e2..eeaa0e6 100644 --- a/linux-core/nv50_display.c +++ b/linux-core/nv50_display.c @@ -171,7 +171,7 @@ static int nv50_display_disable(struct nv50_display *display) /* disable clock change interrupts. */ NV_WRITE(NV50_PDISPLAY_SUPERVISOR_INTR, NV_READ(NV50_PDISPLAY_SUPERVISOR_INTR) & ~0x70); - display->init_done = FALSE; + display->init_done = false; return 0; } diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 355d25d..1c4b52d 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -950,11 +950,11 @@ static enum drm_connector_status nv50_kms_connector_detect(struct drm_connector i2c_detect = connector->i2c_detect(connector); if (load_detect == 1) { - nv50_kms_connector_set_digital(drm_connector, 0, TRUE); /* analog, forced */ + nv50_kms_connector_set_digital(drm_connector, 0, true); /* analog, forced */ } else if (hpd_detect == 1 && load_detect == 0) { - nv50_kms_connector_set_digital(drm_connector, 1, TRUE); /* digital, forced */ + nv50_kms_connector_set_digital(drm_connector, 1, true); /* digital, forced */ } else { - nv50_kms_connector_set_digital(drm_connector, -1, TRUE); /* unknown, forced */ + nv50_kms_connector_set_digital(drm_connector, -1, true); /* unknown, forced */ } if (hpd_detect == 1 || load_detect == 1 || i2c_detect == 1) commit 11d30750873260fe19498d90831f07079dfad5d8 Author: Dave Airlie <ai...@li...> Date: Sat Jul 26 08:41:01 2008 +1000 modesetting: pass file_priv into cursor set functions diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 91bff1f..7ee3321 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1445,7 +1445,7 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, if (req->flags & DRM_MODE_CURSOR_BO) { /* Turn of the cursor if handle is 0 */ if (crtc->funcs->cursor_set) { - ret = crtc->funcs->cursor_set(crtc, req->handle, req->width, req->height); + ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, req->width, req->height); } else { DRM_ERROR("crtc does not support cursor\n"); ret = -EFAULT; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 117b721..bfccdeb 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -299,8 +299,8 @@ struct drm_crtc_funcs { void (*restore)(struct drm_crtc *crtc); /* resume? */ /* cursor controls */ - int (*cursor_set)(struct drm_crtc *crtc, uint32_t buffer_handle, - uint32_t width, uint32_t height); + int (*cursor_set)(struct drm_crtc *crtc, struct drm_file *file_priv, + uint32_t handle, uint32_t width, uint32_t height); int (*cursor_move)(struct drm_crtc *crtc, int x, int y); /* Set gamma on the CRTC */ diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index a761b61..0236bbc 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -975,6 +975,7 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) } static int intel_crtc_cursor_set(struct drm_crtc *crtc, + struct drm_file *file_priv, uint32_t handle, uint32_t width, uint32_t height) { diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 355d25d..694b726 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -236,8 +236,10 @@ static const struct drm_mode_config_funcs nv50_kms_mode_funcs = { * CRTC functions. */ -static int nv50_kms_crtc_cursor_set(struct drm_crtc *drm_crtc, uint32_t buffer_handle, - uint32_t width, uint32_t height) +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 nv50_crtc *crtc = to_nv50_crtc(drm_crtc); struct nv50_display *display = nv50_get_display(crtc->dev); commit fb05c4d621084d7a3fb3dd52d7d9c888eac852d0 Merge: 2556341... 5342845... Author: Dave Airlie <ai...@li...> Date: Sat Jul 26 08:38:59 2008 +1000 Merge remote branch 'origin/modesetting-101' into modesetting-gem commit 53428453758621da70d9608c9baec58b4b9383ec Author: Dave Airlie <ai...@re...> Date: Thu Jul 24 15:22:44 2008 +1000 drm: use correct mode destructor diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index 4ee0030..d4cda0b 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -398,7 +398,7 @@ void drm_mode_prune_invalid(struct drm_device *dev, drm_mode_debug_printmodeline(mode); DRM_DEBUG("Not using %s mode %d\n", mode->name, mode->status); } - kfree(mode); + drm_mode_destroy(dev, mode); } } } @@ -556,7 +556,7 @@ void drm_mode_connector_list_update(struct drm_connector *connector) /* if equal delete the probed mode */ mode->status = pmode->status; list_del(&pmode->head); - kfree(pmode); + drm_mode_destroy(connector->dev, pmode); break; } } commit 4d5b9f484885ac01457f0a8c39b24ca4aac34b5a Author: Maarten Maathuis <mad...@gm...> Date: Mon Jul 21 16:57:25 2008 +0200 NV50: Don't create a "native" mode for LVDS when there is none. diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 8b27f80..355d25d 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -1079,6 +1079,10 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u NV50_DEBUG("No valid modes on %s\n", drm_get_connector_name(drm_connector)); + /* Making up native modes for LVDS is a bad idea. */ + if (drm_connector->connector_type == DRM_MODE_CONNECTOR_LVDS) + return; + /* Should we do this here ??? * When no valid EDID modes are available we end up * here and bailed in the past, now we add a standard commit 147ef45873868a0df9216dac0370ada1ed835590 Author: Maarten Maathuis <mad...@gm...> Date: Mon Jul 21 16:40:55 2008 +0200 NV50: don't fail on LVDS by default diff --git a/linux-core/nouveau_bios.c b/linux-core/nouveau_bios.c index 370d652..faa2b2b 100644 --- a/linux-core/nouveau_bios.c +++ b/linux-core/nouveau_bios.c @@ -341,11 +341,12 @@ parse_dcb_entry(struct drm_device *dev, int index, uint8_t dcb_version, uint16_t entry->lvdsconf.use_power_scripts = true; } if (conf & mask) { - DRM_ERROR( - "Unknown LVDS configuration bits, please report\n"); - /* cause output setting to fail, so message is seen */ - dev_priv->dcb_table.entries = 0; - return false; + if (dcb_version < 0x40) { /* we know g80 cards have unknown bits */ + DRM_ERROR("Unknown LVDS configuration bits, please report\n"); + /* cause output setting to fail, so message is seen */ + dev_priv->dcb_table.entries = 0; + return false; + } } break; } commit 03f8208ab0a3ea77a8b30dd1c3fe2b62892f9d8c Author: Maarten Maathuis <mad...@gm...> Date: Mon Jul 21 14:50:07 2008 +0200 NV50: Use bios table for load pattern when possible. diff --git a/linux-core/nouveau_bios.c b/linux-core/nouveau_bios.c index 3e7fe23..370d652 100644 --- a/linux-core/nouveau_bios.c +++ b/linux-core/nouveau_bios.c @@ -128,6 +128,39 @@ struct bit_entry { uint16_t offset; }; +static int parse_bit_A_tbl_entry(struct drm_device *dev, struct bios *bios, struct bit_entry *bitentry) +{ + /* Parses the load detect value table. + * + * Starting at bitentry->offset: + * + * offset + 0 (16 bits): table pointer + */ + + uint16_t load_table_pointer; + + if (bitentry->length != 3) { + DRM_ERROR("Do not understand BIT loadval table\n"); + return 0; + } + + load_table_pointer = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset]))); + + if (load_table_pointer == 0x0) { + DRM_ERROR("Pointer to loadval table invalid\n"); + return 0; + } + + /* Some kind of signature */ + if (bios->data[load_table_pointer] != 16 || bios->data[load_table_pointer + 1] != 4 || + bios->data[load_table_pointer + 2] != 4 || bios->data[load_table_pointer + 3] != 2) + return 0; + + bios->dactestval = le32_to_cpu(*((uint32_t *)&bios->data[load_table_pointer + 4])) & 0x3FF; + + return 1; +} + static int parse_bit_C_tbl_entry(struct drm_device *dev, struct bios *bios, struct bit_entry *bitentry) { /* offset + 8 (16 bits): PLL limits table pointer @@ -136,7 +169,7 @@ static int parse_bit_C_tbl_entry(struct drm_device *dev, struct bios *bios, stru */ if (bitentry->length < 10) { - DRM_ERROR( "Do not understand BIT C table\n"); + DRM_ERROR("Do not understand BIT C table\n"); return 0; } @@ -149,7 +182,7 @@ static void parse_bit_structure(struct drm_device *dev, struct bios *bios, const { int entries = bios->data[bitoffset + 4]; /* parse i first, I next (which needs C & M before it), and L before D */ - char parseorder[] = "iCMILDT"; + char parseorder[] = "iCMILDTA"; struct bit_entry bitentry; int i, j, offset; @@ -164,6 +197,9 @@ static void parse_bit_structure(struct drm_device *dev, struct bios *bios, const continue; switch (bitentry.id[0]) { + case 'A': + parse_bit_A_tbl_entry(dev, bios, &bitentry); + break; case 'C': parse_bit_C_tbl_entry(dev, bios, &bitentry); break; diff --git a/linux-core/nv50_connector.c b/linux-core/nv50_connector.c index 6e5fb91..34706ba 100644 --- a/linux-core/nv50_connector.c +++ b/linux-core/nv50_connector.c @@ -79,7 +79,6 @@ static struct nv50_output *nv50_connector_to_output(struct nv50_connector *conne static int nv50_connector_hpd_detect(struct nv50_connector *connector) { struct drm_nouveau_private *dev_priv = connector->dev->dev_private; - struct nv50_output *output = NULL; bool present = 0; uint32_t reg = 0; diff --git a/linux-core/nv50_dac.c b/linux-core/nv50_dac.c index 3f00716..5dddb46 100644 --- a/linux-core/nv50_dac.c +++ b/linux-core/nv50_dac.c @@ -146,7 +146,14 @@ static int nv50_dac_detect(struct nv50_output *output) NV_WRITE(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or), 0x00150000 | NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_PENDING); while (NV_READ(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or)) & NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_PENDING); - load_pattern = 340; /* TODO: use a bios table for this */ + /* Use bios provided value if possible. */ + if (dev_priv->bios.dactestval) { + load_pattern = dev_priv->bios.dactestval; + NV50_DEBUG("Using bios provided load_pattern of %d\n", load_pattern); + } else { + load_pattern = 340; + NV50_DEBUG("Using default load_pattern of %d\n", load_pattern); + } NV_WRITE(NV50_PDISPLAY_DAC_REGS_LOAD_CTRL(or), NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_ACTIVE | load_pattern); udelay(10000); /* give it some time to process */ commit d00644c27ddc7023ea0e442c7be6b67d9d0da047 Author: Maarten Maathuis <mad...@gm...> Date: Mon Jul 21 14:29:13 2008 +0200 NV50: Do detect with hpd and load detect if possible. - Appropriate error messages when an unknown situation is encountered are included. - Fallback to i2c will occur when needed. diff --git a/linux-core/nv50_connector.c b/linux-core/nv50_connector.c index 309f450..6e5fb91 100644 --- a/linux-core/nv50_connector.c +++ b/linux-core/nv50_connector.c @@ -76,7 +76,45 @@ static struct nv50_output *nv50_connector_to_output(struct nv50_connector *conne return NULL; } -static bool nv50_connector_detect(struct nv50_connector *connector) +static int nv50_connector_hpd_detect(struct nv50_connector *connector) +{ + struct drm_nouveau_private *dev_priv = connector->dev->dev_private; + struct nv50_output *output = NULL; + bool present = 0; + uint32_t reg = 0; + + /* Assume connected for the moment. */ + if (connector->type == CONNECTOR_LVDS) { + NV50_DEBUG("LVDS is defaulting to connected for the moment.\n"); + return 1; + } + + /* No i2c port, no idea what to do for hotplug. */ + if (connector->i2c_chan->index == 15) { + DRM_ERROR("You have a non-LVDS SOR with no i2c port, please report\n"); + return -EINVAL; + } + + if (connector->i2c_chan->index > 3) { + DRM_ERROR("You have an unusual configuration, index is %d\n", connector->i2c_chan->index); + DRM_ERROR("Please report.\n"); + return -EINVAL; + } + + /* Check hotplug pins. */ + reg = NV_READ(NV50_PCONNECTOR_HOTPLUG_STATE); + if (reg & (NV50_PCONNECTOR_HOTPLUG_STATE_PIN_CONNECTED_I2C0 << (4 * connector->i2c_chan->index))) + present = 1; + + if (present) + NV50_DEBUG("Hotplug detect returned positive for bus %d\n", connector->bus); + else + NV50_DEBUG("Hotplug detect returned negative for bus %d\n", connector->bus); + + return present; +} + +static int nv50_connector_i2c_detect(struct nv50_connector *connector) { /* kindly borrrowed from the intel driver, hope it works. */ uint8_t out_buf[] = { 0x0, 0x0}; @@ -97,13 +135,11 @@ static bool nv50_connector_detect(struct nv50_connector *connector) } }; - NV50_DEBUG("\n"); - if (!connector->i2c_chan) - return false; + return -EINVAL; ret = i2c_transfer(&connector->i2c_chan->adapter, msgs, 2); - DRM_INFO("I2C detect returned %d\n", ret); + NV50_DEBUG("I2C detect returned %d\n", ret); if (ret == 2) return true; @@ -195,7 +231,8 @@ int nv50_connector_create(struct drm_device *dev, int bus, int i2c_index, int ty connector->i2c_chan = nv50_i2c_channel_create(dev, i2c_index); /* set function pointers */ - connector->detect = nv50_connector_detect; + connector->hpd_detect = nv50_connector_hpd_detect; + connector->i2c_detect = nv50_connector_i2c_detect; connector->destroy = nv50_connector_destroy; connector->to_output = nv50_connector_to_output; diff --git a/linux-core/nv50_connector.h b/linux-core/nv50_connector.h index aac9445..fa7316e 100644 --- a/linux-core/nv50_connector.h +++ b/linux-core/nv50_connector.h @@ -51,7 +51,8 @@ struct nv50_connector { bool use_dithering; - bool (*detect) (struct nv50_connector *connector); + int (*hpd_detect) (struct nv50_connector *connector); + int (*i2c_detect) (struct nv50_connector *connector); int (*destroy) (struct nv50_connector *connector); struct nv50_output *(*to_output) (struct nv50_connector *connector, bool digital); }; diff --git a/linux-core/nv50_dac.c b/linux-core/nv50_dac.c index ca4bb5e..3f00716 100644 --- a/linux-core/nv50_dac.c +++ b/linux-core/nv50_dac.c @@ -133,6 +133,39 @@ static int nv50_dac_set_power_mode(struct nv50_output *output, int mode) return 0; } +static int nv50_dac_detect(struct nv50_output *output) +{ + struct drm_nouveau_private *dev_priv = output->dev->dev_private; + int or = nv50_output_or_offset(output); + bool present = 0; + uint32_t dpms_state, load_pattern, load_state; + + NV_WRITE(NV50_PDISPLAY_DAC_REGS_CLK_CTRL1(or), 0x00000001); + dpms_state = NV_READ(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or)); + + NV_WRITE(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or), 0x00150000 | NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_PENDING); + while (NV_READ(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or)) & NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_PENDING); + + load_pattern = 340; /* TODO: use a bios table for this */ + + NV_WRITE(NV50_PDISPLAY_DAC_REGS_LOAD_CTRL(or), NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_ACTIVE | load_pattern); + udelay(10000); /* give it some time to process */ + load_state = NV_READ(NV50_PDISPLAY_DAC_REGS_LOAD_CTRL(or)); + + NV_WRITE(NV50_PDISPLAY_DAC_REGS_LOAD_CTRL(or), 0); + NV_WRITE(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or), dpms_state); + + if ((load_state & NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_PRESENT) == NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_PRESENT) + present = 1; + + if (present) + NV50_DEBUG("Load was detected on output with or %d\n", or); + else + NV50_DEBUG("Load was not detected on output with or %d\n", or); + + return present; +} + static int nv50_dac_destroy(struct nv50_output *output) { struct drm_device *dev = output->dev; @@ -210,7 +243,7 @@ int nv50_dac_create(struct drm_device *dev, int dcb_entry) output->execute_mode = nv50_dac_execute_mode; output->set_clock_mode = nv50_dac_set_clock_mode; output->set_power_mode = nv50_dac_set_power_mode; - output->detect = NULL; /* TODO */ + output->detect = nv50_dac_detect; output->destroy = nv50_dac_destroy; return 0; diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 67836f3..8b27f80 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -386,7 +386,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) /* 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_is_digital(drm_connector)); + output = connector->to_output(connector, nv50_kms_connector_get_digital(drm_connector)); if (!output) { DRM_ERROR("No output\n"); goto out; @@ -458,7 +458,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) goto out; } - output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector)); + output = connector->to_output(connector, nv50_kms_connector_get_digital(drm_connector)); if (!output) { DRM_ERROR("No output\n"); goto out; @@ -835,7 +835,9 @@ static int nv50_kms_encoders_init(struct drm_device *dev) * Connector functions */ -bool nv50_kms_connector_is_digital(struct drm_connector *drm_connector) + +/* These 2 functions wrap the connector properties that deal with multiple encoders per connector. */ +bool nv50_kms_connector_get_digital(struct drm_connector *drm_connector) { struct drm_device *dev = drm_connector->dev; @@ -892,6 +894,33 @@ bool nv50_kms_connector_is_digital(struct drm_connector *drm_connector) return false; } +static void nv50_kms_connector_set_digital(struct drm_connector *drm_connector, int digital, bool force) +{ + struct drm_device *dev = drm_connector->dev; + + if (drm_connector->connector_type == DRM_MODE_CONNECTOR_DVII) { + uint64_t cur_value, new_value; + + int rval = drm_connector_property_get_value(drm_connector, dev->mode_config.dvi_i_subconnector_property, &cur_value); + if (rval) { + DRM_ERROR("Unable to find subconnector property\n"); + return; + } + + /* Only set when unknown or when forced to do so. */ + if (cur_value != DRM_MODE_SUBCONNECTOR_Unknown && !force) + return; + + if (digital == 1) + new_value = DRM_MODE_SUBCONNECTOR_DVID; + else if (digital == 0) + new_value = DRM_MODE_SUBCONNECTOR_DVIA; + else + new_value = DRM_MODE_SUBCONNECTOR_Unknown; + drm_connector_property_set_value(drm_connector, dev->mode_config.dvi_i_subconnector_property, new_value); + } +} + void nv50_kms_connector_detect_all(struct drm_device *dev) { struct drm_connector *drm_connector = NULL; @@ -903,16 +932,32 @@ void nv50_kms_connector_detect_all(struct drm_device *dev) static enum drm_connector_status nv50_kms_connector_detect(struct drm_connector *drm_connector) { - struct nv50_connector *connector = to_nv50_connector(drm_connector); struct drm_device *dev = drm_connector->dev; - bool connected; - int old_status; + struct nv50_connector *connector = to_nv50_connector(drm_connector); + struct nv50_output *output = NULL; + int hpd_detect = 0, load_detect = 0, i2c_detect = 0; + int old_status = drm_connector->status; - connected = connector->detect(connector); + /* hotplug detect */ + hpd_detect = connector->hpd_detect(connector); - old_status = drm_connector->status; + /* load detect */ + output = connector->to_output(connector, FALSE); /* analog */ + if (output && output->detect) + load_detect = output->detect(output); - if (connected) + if (hpd_detect < 0 || load_detect < 0) /* did an error occur? */ + i2c_detect = connector->i2c_detect(connector); + + if (load_detect == 1) { + nv50_kms_connector_set_digital(drm_connector, 0, TRUE); /* analog, forced */ + } else if (hpd_detect == 1 && load_detect == 0) { + nv50_kms_connector_set_digital(drm_connector, 1, TRUE); /* digital, forced */ + } else { + nv50_kms_connector_set_digital(drm_connector, -1, TRUE); /* unknown, forced */ + } + + if (hpd_detect == 1 || load_detect == 1 || i2c_detect == 1) drm_connector->status = connector_status_connected; else drm_connector->status = connector_status_disconnected; @@ -956,7 +1001,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u struct nv50_connector *connector = to_nv50_connector(drm_connector); struct drm_device *dev = drm_connector->dev; int rval = 0; - bool connected; + bool connected = false; struct drm_display_mode *mode, *t; struct edid *edid = NULL; @@ -965,16 +1010,13 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u list_for_each_entry_safe(mode, t, &drm_connector->modes, head) mode->status = MODE_UNVERIFIED; - connected = connector->detect(connector); + if (nv50_kms_connector_detect(drm_connector) == connector_status_connected) + connected = true; if (connected) - drm_connector->status = connector_status_connected; + NV50_DEBUG("%s is connected\n", drm_get_connector_name(drm_connector)); else - drm_connector->status = connector_status_disconnected; - - if (!connected) { NV50_DEBUG("%s is disconnected\n", drm_get_connector_name(drm_connector)); - } /* Not all connnectors have an i2c channel. */ if (connected && connector->i2c_chan) @@ -986,16 +1028,8 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u if (edid) { rval = drm_add_edid_modes(drm_connector, edid); - /* 2 encoders per connector */ - /* eventually do this based on load detect and hot plug detect */ - if (drm_connector->connector_type == DRM_MODE_CONNECTOR_DVII) { - uint64_t subtype = 0; - if (edid->digital) - subtype = DRM_MODE_SUBCONNECTOR_DVID; - else - subtype = DRM_MODE_SUBCONNECTOR_DVIA; - drm_connector_property_set_value(drm_connector, dev->mode_config.dvi_i_subconnector_property, subtype); - } + /* Only update when relevant and when detect couldn't determine type. */ + nv50_kms_connector_set_digital(drm_connector, edid->digital ? 1 : 0, FALSE); kfree(edid); } @@ -1009,7 +1043,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u list_for_each_entry_safe(mode, t, &drm_connector->modes, head) { if (mode->status == MODE_OK) { struct nouveau_hw_mode *hw_mode = nv50_kms_to_hw_mode(mode); - struct nv50_output *output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector)); + struct nv50_output *output = connector->to_output(connector, nv50_kms_connector_get_digital(drm_connector)); mode->status = output->validate_mode(output, hw_mode); /* find native mode, TODO: also check if we actually found one */ @@ -1025,7 +1059,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u list_for_each_entry_safe(mode, t, &drm_connector->modes, head) { if (mode->status == MODE_OK) { struct nouveau_hw_mode *hw_mode = nv50_kms_to_hw_mode(mode); - struct nv50_output *output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector)); + struct nv50_output *output = connector->to_output(connector, nv50_kms_connector_get_digital(drm_connector)); mode->status = output->validate_mode(output, hw_mode); kfree(hw_mode); @@ -1057,7 +1091,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u /* also add it as native mode */ hw_mode = nv50_kms_to_hw_mode(mode); - output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector)); + output = connector->to_output(connector, nv50_kms_connector_get_digital(drm_connector)); if (hw_mode) *output->native_mode = *hw_mode; diff --git a/linux-core/nv50_kms_wrapper.h b/linux-core/nv50_kms_wrapper.h index 5ac6652..6038480 100644 --- a/linux-core/nv50_kms_wrapper.h +++ b/linux-core/nv50_kms_wrapper.h @@ -87,7 +87,7 @@ struct nv50_kms_priv { struct nv50_kms_priv *nv50_get_kms_priv(struct drm_device *dev); void nv50_kms_connector_detect_all(struct drm_device *dev); -bool nv50_kms_connector_is_digital(struct drm_connector *drm_connector); +bool nv50_kms_connector_get_digital(struct drm_connector *drm_connector); int nv50_kms_init(struct drm_device *dev); int nv50_kms_destroy(struct drm_device *dev); diff --git a/linux-core/nv50_output.h b/linux-core/nv50_output.h index a5faf05..ac6d714 100644 --- a/linux-core/nv50_output.h +++ b/linux-core/nv50_output.h @@ -51,7 +51,7 @@ struct nv50_output { int (*set_clock_mode) (struct nv50_output *output); /* this is not a normal modeset call, it is a direct register write, so it's executed immediately */ int (*set_power_mode) (struct nv50_output *output, int mode); - bool (*detect) (struct nv50_output *output); + int (*detect) (struct nv50_output *output); int (*destroy) (struct nv50_output *output); }; commit 685bca02fe6b7406bb157a1a4e0f147b47ba28f8 Author: Maarten Maathuis <mad...@gm...> Date: Sun Jul 20 15:40:40 2008 +0200 NV50: delay changing gpu<->non-gpu scaling modes until next modeset diff --git a/linux-core/nv50_connector.c b/linux-core/nv50_connector.c index be133de..309f450 100644 --- a/linux-core/nv50_connector.c +++ b/linux-core/nv50_connector.c @@ -185,9 +185,9 @@ int nv50_connector_create(struct drm_device *dev, int bus, int i2c_index, int ty /* some reasonable defaults */ if (type == CONNECTOR_DVI_D || type == CONNECTOR_DVI_I || type == CONNECTOR_LVDS) - connector->scaling_mode = SCALE_FULLSCREEN; + connector->requested_scaling_mode = SCALE_FULLSCREEN; else - connector->scaling_mode = SCALE_NON_GPU; + connector->requested_scaling_mode = SCALE_NON_GPU; connector->use_dithering = false; diff --git a/linux-core/nv50_connector.h b/linux-core/nv50_connector.h index 02b1561..aac9445 100644 --- a/linux-core/nv50_connector.h +++ b/linux-core/nv50_connector.h @@ -47,7 +47,8 @@ struct nv50_connector { struct nv50_i2c_channel *i2c_chan; struct nv50_output *output; - int scaling_mode; + int requested_scaling_mode; + bool use_dithering; bool (*detect) (struct nv50_connector *connector); diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c index ffb976f..c4ca7e7 100644 --- a/linux-core/nv50_crtc.c +++ b/linux-core/nv50_crtc.c @@ -255,7 +255,7 @@ static int nv50_crtc_set_scale(struct nv50_crtc *crtc) NV50_DEBUG("\n"); - switch (crtc->scaling_mode) { + switch (crtc->requested_scaling_mode) { case SCALE_ASPECT: nv50_crtc_calc_scale(crtc, &outX, &outY); break; @@ -283,6 +283,9 @@ static int nv50_crtc_set_scale(struct nv50_crtc *crtc) OUT_MODE(NV50_CRTC0_SCALE_RES1 + offset, outY << 16 | outX); OUT_MODE(NV50_CRTC0_SCALE_RES2 + offset, outY << 16 | outX); + /* processed */ + crtc->scaling_mode = crtc->requested_scaling_mode; + return 0; } @@ -492,6 +495,9 @@ int nv50_crtc_create(struct drm_device *dev, int 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; diff --git a/linux-core/nv50_crtc.h b/linux-core/nv50_crtc.h index 8235c9d..b4b8358 100644 --- a/linux-core/nv50_crtc.h +++ b/linux-core/nv50_crtc.h @@ -46,6 +46,10 @@ struct nv50_crtc { bool use_native_mode; bool use_dithering; + + /* Changing scaling modes requires a modeset sometimes. */ + /* We need to know the currently active hw mode, as well as the requested one by the user. */ + int requested_scaling_mode; int scaling_mode; struct nv50_cursor *cursor; diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 6e0805f..67836f3 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -635,12 +635,12 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) if (connector->output != output) continue; - crtc->scaling_mode = connector->scaling_mode; + crtc->requested_scaling_mode = connector->requested_scaling_mode; crtc->use_dithering = connector->use_dithering; break; } - if (crtc->scaling_mode == SCALE_NON_GPU) + if (crtc->requested_scaling_mode == SCALE_NON_GPU) crtc->use_native_mode = false; else crtc->use_native_mode = true; @@ -1086,6 +1086,7 @@ static int nv50_kms_connector_set_property(struct drm_connector *drm_connector, struct drm_device *dev = drm_connector->dev; struct nv50_connector *connector = to_nv50_connector(drm_connector); int rval = 0; + bool delay_change = false; /* DPMS */ if (property == dev->mode_config.dpms_property && drm_connector->encoder) { @@ -1123,7 +1124,7 @@ static int nv50_kms_connector_set_property(struct drm_connector *drm_connector, if (connector->type == CONNECTOR_LVDS && internal_value == SCALE_NON_GPU) return -EINVAL; - connector->scaling_mode = internal_value; + connector->requested_scaling_mode = internal_value; if (drm_connector->encoder && drm_connector->encoder->crtc) crtc = to_nv50_crtc(drm_connector->encoder->crtc); @@ -1131,7 +1132,17 @@ static int nv50_kms_connector_set_property(struct drm_connector *drm_connector, if (!crtc) return 0; - crtc->scaling_mode = connector->scaling_mode; + crtc->requested_scaling_mode = connector->requested_scaling_mode; + + /* going from and to a gpu scaled regime requires a modesetting, so wait until next modeset */ + if (crtc->scaling_mode == SCALE_NON_GPU || internal_value == SCALE_NON_GPU) { + DRM_INFO("Moving from or to a non-gpu scaled mode, this will be processed upon next modeset."); + delay_change = true; + } + + if (delay_change) + return 0; + rval = crtc->set_scale(crtc); if (rval) return rval; @@ -1194,7 +1205,7 @@ static int nv50_kms_get_scaling_mode(struct drm_connector *drm_connector) connector = to_nv50_connector(drm_connector); - switch (connector->scaling_mode) { + switch (connector->requested_scaling_mode) { case SCALE_NON_GPU: drm_mode = DRM_MODE_SCALE_NON_GPU; break; commit e51cd78cac24df15e32e23d8db73614524e6ff0d Author: Maarten Maathuis <mad...@gm...> Date: Sun Jul 20 14:58:46 2008 +0200 modesetting-101: Only store property value when set_property was successful. diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index c984209..91bff1f 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -2184,12 +2184,12 @@ int drm_mode_connector_property_set_ioctl(struct drm_device *dev, } } - /* store the property value */ - drm_connector_property_set_value(connector, property, out_resp->value); - if (connector->funcs->set_property) ret = connector->funcs->set_property(connector, property, out_resp->value); + /* store the property value if succesful */ + if (!ret) + drm_connector_property_set_value(connector, property, out_resp->value); out: mutex_unlock(&dev->mode_config.mutex); return ret; commit f1e4785d4cf04b679948602ffbbef2043ce81ec0 Author: Maarten Maathuis <mad...@gm...> Date: Sun Jul 20 14:55:59 2008 +0200 NV50: LVDS always needs some kind of gpu scaling diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 009972c..6e0805f 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -1119,6 +1119,10 @@ static int nv50_kms_connector_set_property(struct drm_connector *drm_connector, break; } + /* LVDS always needs gpu scaling */ + if (connector->type == CONNECTOR_LVDS && internal_value == SCALE_NON_GPU) + return -EINVAL; + connector->scaling_mode = internal_value; if (drm_connector->encoder && drm_connector->encoder->crtc) commit 3ef1d05001a9e28ed52536de7e020323d8d34d83 Author: Maarten Maathuis <mad...@gm...> Date: Sun Jul 20 14:51:22 2008 +0200 modesetting-101: set_property should return an int, not a bool diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index d88c614..117b721 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -375,7 +375,7 @@ struct drm_connector_funcs { void (*restore)(struct drm_connector *connector); enum drm_connector_status (*detect)(struct drm_connector *connector); void (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height); - bool (*set_property)(struct drm_connector *connector, struct drm_property *property, + int (*set_property)(struct drm_connector *connector, struct drm_property *property, uint64_t val); void (*destroy)(struct drm_connector *connector); }; diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index 1b2b5b7..8e1b833 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -210,7 +210,7 @@ static int intel_crt_get_modes(struct drm_connector *connector) return intel_ddc_get_modes(intel_output); } -static bool intel_crt_set_property(struct drm_connector *connector, +static int intel_crt_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t value) { @@ -219,7 +219,7 @@ static bool intel_crt_set_property(struct drm_connector *connector, if (property == dev->mode_config.dpms_property && connector->encoder) intel_crt_dpms(connector->encoder, (uint32_t)(value & 0xf)); - return true; + return 0; } /* diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index 389487b..29cfc03 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -1560,7 +1560,7 @@ intel_tv_destroy (struct drm_connector *connector) } -static bool +static int intel_tv_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t val) { diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index b0d6434..009972c 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -1079,21 +1079,21 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u } } -static bool nv50_kms_connector_set_property(struct drm_connector *drm_connector, +static int nv50_kms_connector_set_property(struct drm_connector *drm_connector, struct drm_property *property, uint64_t value) { struct drm_device *dev = drm_connector->dev; struct nv50_connector *connector = to_nv50_connector(drm_connector); + int rval = 0; /* DPMS */ if (property == dev->mode_config.dpms_property && drm_connector->encoder) { struct nv50_output *output = to_nv50_output(drm_connector->encoder); - if (!output->set_power_mode(output, (int) value)) - return true; - else - return false; + rval = output->set_power_mode(output, (int) value); + + return rval; } /* Scaling mode */ @@ -1101,7 +1101,6 @@ static bool nv50_kms_connector_set_property(struct drm_connector *drm_connector, struct nv50_crtc *crtc = NULL; struct nv50_display *display = nv50_get_display(dev); int internal_value = 0; - int rval = 0; switch (value) { case DRM_MODE_SCALE_NON_GPU: @@ -1126,24 +1125,23 @@ static bool nv50_kms_connector_set_property(struct drm_connector *drm_connector, crtc = to_nv50_crtc(drm_connector->encoder->crtc); if (!crtc) - return true; + return 0; crtc->scaling_mode = connector->scaling_mode; rval = crtc->set_scale(crtc); if (rval) - return false; + return rval; /* process command buffer */ display->update(display); - return true; + return 0; } /* Dithering */ if (property == dev->mode_config.dithering_mode_property) { struct nv50_crtc *crtc = NULL; struct nv50_display *display = nv50_get_display(dev); - int rval = 0; if (value == DRM_MODE_DITHERING_ON) connector->use_dithering = true; @@ -1154,21 +1152,21 @@ static bool nv50_kms_connector_set_property(struct drm_connector *drm_connector, crtc = to_nv50_crtc(drm_connector->encoder->crtc); if (!crtc) - return true; + return 0; /* update hw state */ crtc->use_dithering = connector->use_dithering; rval = crtc->set_dither(crtc); if (rval) - return false; + return rval; /* process command buffer */ display->update(display); - return true; + return 0; } - return false; + return -EINVAL; } static const struct drm_connector_funcs nv50_kms_connector_funcs = { commit 65803e53a696347e38d7f6c2c8dc186c6764ff03 Author: Maarten Maathuis <mad...@gm...> Date: Sun Jul 20 13:49:18 2008 +0200 modesetting-101: implement optional scaling and dithering properties diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index fc8d1fe..c984209 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -60,6 +60,26 @@ char *drm_get_dpms_name(int val) return "unknown"; } +/* + * Optional properties + */ +static struct drm_prop_enum_list drm_scaling_mode_enum_list[] = +{ + { DRM_MODE_SCALE_NON_GPU, "Non-GPU" }, + { DRM_MODE_SCALE_FULLSCREEN, "Fullscreen" }, + { DRM_MODE_SCALE_NO_SCALE, "No scale" }, + { DRM_MODE_SCALE_ASPECT, "Aspect" }, +}; + +static struct drm_prop_enum_list drm_dithering_mode_enum_list[] = +{ + { DRM_MODE_DITHERING_OFF, "Off" }, + { DRM_MODE_DITHERING_ON, "On" }, +}; + +/* + * Non-global properties, but "required" for certain connectors. + */ static struct drm_prop_enum_list drm_select_subconnector_enum_list[] = { { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ @@ -102,6 +122,9 @@ char *drm_get_subconnector_name(int val) return "unknown"; } +/* + * Connector and encoder types. + */ static struct drm_prop_enum_list drm_connector_enum_list[] = { { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, { DRM_MODE_CONNECTOR_VGA, "VGA" }, @@ -647,6 +670,52 @@ int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes, EXPORT_SYMBOL(drm_mode_create_tv_properties); /** + * drm_mode_create_scaling_mode_property - create scaling mode property + * @dev: DRM device + * + * Called by a driver the first time it's needed, must be attached to desired connectors. + */ +int drm_mode_create_scaling_mode_property(struct drm_device *dev) +{ + int i; + + if (dev->mode_config.scaling_mode_property) /* already done */ + return 0; + + dev->mode_config.scaling_mode_property = + drm_property_create(dev, DRM_MODE_PROP_ENUM, + "scaling mode", ARRAY_SIZE(drm_scaling_mode_enum_list)); + for (i = 0; i < ARRAY_SIZE(drm_scaling_mode_enum_list); i++) + drm_property_add_enum(dev->mode_config.scaling_mode_property, i, drm_scaling_mode_enum_list[i].type, drm_scaling_mode_enum_list[i].name); + + return 0; +} +EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); + +/** + * drm_mode_create_dithering_property - create dithering property + * @dev: DRM device + * + * Called by a driver the first time it's needed, must be attached to desired connectors. + */ +int drm_mode_create_dithering_property(struct drm_device *dev) +{ + int i; + + if (dev->mode_config.dithering_mode_property) /* already done */ + return 0; + + dev->mode_config.dithering_mode_property = + drm_property_create(dev, DRM_MODE_PROP_ENUM, + "dithering", ARRAY_SIZE(drm_dithering_mode_enum_list)); + for (i = 0; i < ARRAY_SIZE(drm_dithering_mode_enum_list); i++) + drm_property_add_enum(dev->mode_config.dithering_mode_property, i, drm_dithering_mode_enum_list[i].type, drm_dithering_mode_enum_list[i].name); + + return 0; +} +EXPORT_SYMBOL(drm_mode_create_dithering_property); + +/** * drm_mode_config_init - initialize DRM mode_configuration structure * @dev: DRM device * diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index d4bb879..d88c614 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -536,7 +536,7 @@ struct drm_mode_config { struct drm_property *edid_property; struct drm_property *dpms_property; - /* optional properties */ + /* DVI-I properties */ struct drm_property *dvi_i_subconnector_property; struct drm_property *dvi_i_select_subconnector_property; @@ -549,6 +549,10 @@ struct drm_mode_config { struct drm_property *tv_top_margin_property; struct drm_property *tv_bottom_margin_property; + /* Optional properties */ + struct drm_property *scaling_mode_property; + struct drm_property *dithering_mode_property; + /* hotplug */ uint32_t hotplug_counter; }; @@ -650,6 +654,8 @@ extern int drm_property_add_enum(struct drm_property *property, int index, extern int drm_mode_create_dvi_i_properties(struct drm_device *dev); extern int drm_mode_create_tv_properties(struct drm_device *dev, int num_formats, char *formats[]); +extern int drm_mode_create_scaling_mode_property(struct drm_device *dev); +extern int drm_mode_create_dithering_property(struct drm_device *dev); extern char *drm_get_encoder_name(struct drm_encoder *encoder); extern int drm_mode_connector_attach_encoder(struct drm_connector *connector, diff --git a/linux-core/nv50_connector.c b/linux-core/nv50_connector.c index ac5194c..be133de 100644 --- a/linux-core/nv50_connector.c +++ b/linux-core/nv50_connector.c @@ -187,7 +187,9 @@ int nv50_connector_create(struct drm_device *dev, int bus, int i2c_index, int ty if (type == CONNECTOR_DVI_D || type == CONNECTOR_DVI_I || type == CONNECTOR_LVDS) connector->scaling_mode = SCALE_FULLSCREEN; else - connector->scaling_mode = SCALE_PANEL; + connector->scaling_mode = SCALE_NON_GPU; + + connector->use_dithering = false; if (i2c_index < 0xf) connector->i2c_chan = nv50_i2c_channel_create(dev, i2c_index); diff --git a/linux-core/nv50_connector.h b/linux-core/nv50_connector.h index ebd6eac..02b1561 100644 --- a/linux-core/nv50_connector.h +++ b/linux-core/nv50_connector.h @@ -48,6 +48,7 @@ struct nv50_connector { struct nv50_output *output; int scaling_mode; + bool use_dithering; bool (*detect) (struct nv50_connector *connector); int (*destroy) (struct nv50_connector *connector); diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c index 6c3d404..ffb976f 100644 --- a/linux-core/nv50_crtc.c +++ b/linux-core/nv50_crtc.c @@ -264,7 +264,7 @@ static int nv50_crtc_set_scale(struct nv50_crtc *crtc) outY = crtc->native_mode->vdisplay; break; case SCALE_NOSCALE: - case SCALE_PANEL: + case SCALE_NON_GPU: default: outX = crtc->mode->hdisplay; outY = crtc->mode->vdisplay; diff --git a/linux-core/nv50_display.h b/linux-core/nv50_display.h index f20e67d..3c2ee1c 100644 --- a/linux-core/nv50_display.h +++ b/linux-core/nv50_display.h @@ -68,7 +68,7 @@ struct nv50_display { }; enum scaling_modes { - SCALE_PANEL, + SCALE_NON_GPU, SCALE_FULLSCREEN, SCALE_ASPECT, SCALE_NOSCALE, diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index a7966e9..b0d6434 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -636,10 +636,11 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) continue; crtc->scaling_mode = connector->scaling_mode; + crtc->use_dithering = connector->use_dithering; break; } - if (crtc->scaling_mode == SCALE_PANEL) + if (crtc->scaling_mode == SCALE_NON_GPU) crtc->use_native_mode = false; else crtc->use_native_mode = true; @@ -1078,14 +1079,16 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u } } -static bool nv50_kms_connector_set_property(struct drm_connector *connector, +static bool nv50_kms_connector_set_property(struct drm_connector *drm_connector, struct drm_property *property, uint64_t value) { - struct drm_device *dev = connector->dev; + struct drm_device *dev = drm_connector->dev; + struct nv50_connector *connector = to_nv50_connector(drm_connector); - if (property == dev->mode_config.dpms_property && connector->encoder) { - struct nv50_output *output = to_nv50_output(connector->encoder); + /* DPMS */ + if (property == dev->mode_config.dpms_property && drm_connector->encoder) { + struct nv50_output *output = to_nv50_output(drm_connector->encoder); if (!output->set_power_mode(output, (int) value)) return true; @@ -1093,6 +1096,78 @@ static bool nv50_kms_connector_set_property(struct drm_connector *connector, return false; } + /* Scaling mode */ + if (property == dev->mode_config.scaling_mode_property) { + struct nv50_crtc *crtc = NULL; + struct nv50_display *display = nv50_get_display(dev); + int internal_value = 0; + int rval = 0; + + switch (value) { + case DRM_MODE_SCALE_NON_GPU: + internal_value = SCALE_NON_GPU; + break; + case DRM_MODE_SCALE_FULLSCREEN: + internal_value = SCALE_FULLSCREEN; + break; + case DRM_MODE_SCALE_NO_SCALE: + internal_value = SCALE_NOSCALE; + break; + case DRM_MODE_SCALE_ASPECT: + internal_value = SCALE_ASPECT; + break; + default: + break; + } + + connector->scaling_mode = internal_value; + + if (drm_connector->encoder && drm_connector->encoder->crtc) + crtc = to_nv50_crtc(drm_connector->encoder->crtc); + + if (!crtc) + return true; + + crtc->scaling_mode = connector->scaling_mode; + rval = crtc->set_scale(crtc); + if (rval) + return false; + + /* process command buffer */ + display->update(display); + + return true; + } + + /* Dithering */ + if (property == dev->mode_config.dithering_mode_property) { + struct nv50_crtc *crtc = NULL; + struct nv50_display *display = nv50_get_display(dev); + int rval = 0; + + if (value == DRM_MODE_DITHERING_ON) + connector->use_dithering = true; + else + connector->use_dithering = false; + + if (drm_connector->encoder && drm_connector->encoder->crtc) + crtc = to_nv50_crtc(drm_connector->encoder->crtc); + + if (!crtc) + return true; + + /* update hw state */ + crtc->use_dithering = connector->use_dithering; + rval = crtc->set_dither(crtc); + if (rval) + return false; + + /* process command buffer */ + display->update(display); + + return true; + } + return false; } @@ -1105,12 +1180,48 @@ static const struct drm_connector_funcs nv50_kms_connector_funcs = { .set_property = nv50_kms_connector_set_property }; +static int nv50_kms_get_scaling_mode(struct drm_connector *drm_connector) +{ + struct nv50_connector *connector = NULL; + int drm_mode = 0; + + if (!drm_connector) { + DRM_ERROR("drm_connector is NULL\n"); + return 0; + } + + connector = to_nv50_connector(drm_connector); + + switch (connector->scaling_mode) { + case SCALE_NON_GPU: + drm_mode = DRM_MODE_SCALE_NON_GPU; + break; + case SCALE_FULLSCREEN: + drm_mode = DRM_MODE_SCALE_FULLSCREEN; + break; + case SCALE_NOSCALE: + drm_mode = DRM_MODE_SCALE_NO_SCALE; + break; + case SCALE_ASPECT: + drm_mode = DRM_MODE_SCALE_ASPECT; + break; + default: + break; + } + + return drm_mode; +} + static int nv50_kms_connectors_init(struct drm_device *dev) { struct nv50_display *display = nv50_get_display(dev); struct nv50_connector *connector = NULL; int i; + /* Initialise some optional connector properties. */ + drm_mode_create_scaling_mode_property(dev); + drm_mode_create_dithering_property(dev); + list_for_each_entry(connector, &display->connectors, item) { struct drm_connector *drm_connector = to_nv50_kms_connector(connector); uint32_t type = DRM_MODE_CONNECTOR_Unknown; @@ -1154,6 +1265,13 @@ static int nv50_kms_connectors_init(struct drm_device *dev) drm_connector_attach_property(drm_connector, dev->mode_config.dvi_i_select_subconnector_property, 0); } + /* If supported in the future, it will have to use the scalers internally and not expose them. */ + if (type != DRM_MODE_CONNECTOR_SVIDEO) { + drm_connector_attach_property(drm_connector, dev->mode_config.scaling_mode_property, nv50_kms_get_scaling_mode(drm_connector)); + } + + drm_connector_attach_property(drm_connector, dev->mode_config.dithering_mode_property, connector->use_dithering ? DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF); + /* attach encoders, possibilities are analog + digital */ for (i = 0; i < 2; i++) { struct drm_encoder *drm_encoder = NULL; diff --git a/shared-core/drm.h b/shared-core/drm.h index 2e4d2a9..4119064 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1034,6 +1034,16 @@ struct drm_mm_info_arg { #define DRM_MODE_DPMS_SUSPEND 2 #define DRM_MODE_DPMS_OFF 3 +/* Scaling mode options */ +#define DRM_MODE_SCALE_NON_GPU 0 +#define DRM_MODE_SCALE_FULLSCREEN 1 +#define DRM_MODE_SCALE_NO_SCALE 2 +#define DRM_MODE_SCALE_ASPECT 3 + +/* Dithering mode options */ +#define DRM_MODE_DITHERING_OFF 0 +#define DRM_MODE_DITHERING_ON 1 + struct drm_mode_modeinfo { unsigned int clock; unsigned short hdisplay, hsync_start, hsync_end, htotal, hskew; commit e2ffee839ed7ae6c55a0a8c6bb8ee872ae8a2a70 Author: Maarten Maathuis <mad...@gm...> Date: Sun Jul 20 00:09:06 2008 +0200 drm: As a workaround don't tear down sg with a modesetting driver. - This allows me to maintain a useful prototype driver. diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index deb8eb9..4e7c531 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -242,7 +242,10 @@ int drm_lastclose(struct drm_device * dev) dev->agp->acquired = 0; dev->agp->enabled = 0; } - if (drm_core_check_feature(dev, DRIVER_SG) && dev->sg) { + + /* You're supposed to have a real memory manager for modesetting, but this'll suffice as a temporary workaround. */ + /* This assumes sgdma is inited at load time. */ + if (drm_core_check_feature(dev, DRIVER_SG) && !drm_core_check_feature(dev, DRIVER_MODESET) && dev->sg) { drm_sg_cleanup(dev->sg); dev->sg = NULL; } commit 0ef097b598433a5756df2bd6a72deba1f0e1d1c7 Author: Ben Skeggs <sk...@ni...> Date: Mon Jun 23 01:24:11 2008 +1000 nv50: use same dma object for fb/tt access We depend on the VM fully now for memory protection, separate DMA objects for VRAM and GART are unneccesary. However, until the next interface break (soon) a client can't depend on the objects being the same and must still call NV_OBJ_SET_DMA_* methods appropriately. diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index db207e7..375463b 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -806,6 +806,7 @@ int nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) { + struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_mem_alloc *alloc = data; struct mem_block *block; @@ -822,10 +823,15 @@ nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data, alloc->offset=block->start; alloc->flags=block->flags; + if (dev_priv->card_type >= NV_50 && alloc->flags & NOUVEAU_MEM_FB) + alloc->offset += 512*1024*1024; + return 0; } -int nouveau_ioctl_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv) +int +nouveau_ioctl_mem_free(struct drm_device *dev, void *data, + struct drm_file *file_priv) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_mem_free *memfree = data; @@ -833,6 +839,9 @@ int nouveau_ioctl_mem_free(struct drm_device *dev, void *data, struct drm_file * NOUVEAU_CHECK_INITIALISED_WITH_RETURN; + if (dev_priv->card_type >= NV_50 && memfree->flags & NOUVEAU_MEM_FB) + memfree->offset -= 512*1024*1024; + block=NULL; if (memfree->flags & NOUVEAU_MEM_FB) block = find_block(dev_priv->fb_heap, memfree->offset); diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index 5664bfc..894e733 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -1036,8 +1036,7 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, /* VRAM ctxdma */ if (dev_priv->card_type >= NV_50) { ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, - 512*1024*1024, - dev_priv->fb_available_size, + 0, 0x100000000ULL, NV_DMA_ACCESS_RW, NV_DMA_TARGET_AGP, &vram); if (ret) { @@ -1059,6 +1058,9 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, } /* TT memory ctxdma */ + if (dev_priv->card_type >= NV_50) { + tt = vram; + } else if (dev_priv->gart_info.type != NOUVEAU_GART_NONE) { ret = nouveau_gpuobj_gart_dma_new(chan, 0, dev_priv->gart_info.aper_size, commit 4872ac9c6204c3f212fd622ed292f6fc245020bf Author: Ben Skeggs <sk...@gm...> Date: Wed Jun 25 04:39:32 2008 +1000 nouveau: interface changes for nv5x 3d diff --git a/shared-core/nouveau_drm.h b/shared-core/nouveau_drm.h index bbb51bc..4b5869a 100644 --- a/shared-core/nouveau_drm.h +++ b/shared-core/nouveau_drm.h @@ -25,7 +25,7 @@ #ifndef __NOUVEAU_DRM_H__ #define __NOUVEAU_DRM_H__ -#define NOUVEAU_DRM_HEADER_PATCHLEVEL 10 +#define NOUVEAU_DRM_HEADER_PATCHLEVEL 11 struct drm_nouveau_channel_alloc { uint32_t fb_ctxdma_handle; @@ -85,10 +85,12 @@ struct drm_nouveau_gpuobj_free { #define NOUVEAU_MEM_PINNED 0x00000040 #define NOUVEAU_MEM_USER_BACKED 0x00000080 #define NOUVEAU_MEM_MAPPED 0x00000100 -#define NOUVEAU_MEM_INSTANCE 0x00000200 /* internal */ -#define NOUVEAU_MEM_NOTIFIER 0x00000400 /* internal */ -#define NOUVEAU_MEM_NOVM 0x00000800 /* internal */ -#define NOUVEAU_MEM_USER 0x00001000 /* internal */ +#define NOUVEAU_MEM_TILE 0x00000200 +#define NOUVEAU_MEM_TILE_ZETA 0x00000400 +#define NOUVEAU_MEM_INSTANCE 0x01000000 /* internal */ +#define NOUVEAU_MEM_NOTIFIER 0x02000000 /* internal */ +#define NOUVEAU_MEM_NOVM 0x04000000 /* internal */ +#define NOUVEAU_MEM_USER 0x08000000 /* internal */ #define NOUVEAU_MEM_INTERNAL (NOUVEAU_MEM_INSTANCE | \ NOUVEAU_MEM_NOTIFIER | \ NOUVEAU_MEM_NOVM | \ @@ -107,6 +109,13 @@ struct drm_nouveau_mem_free { int flags; }; +struct drm_nouveau_mem_tile { + uint64_t offset; + uint64_t delta; + uint64_t size; + int flags; +}; + /* FIXME : maybe unify {GET,SET}PARAMs */ #define NOUVEAU_GETPARAM_PCI_VENDOR 3 #define NOUVEAU_GETPARAM_PCI_DEVICE 4 @@ -168,5 +177,6 @@ struct drm_nouveau_sarea { #define DRM_NOUVEAU_GPUOBJ_FREE 0x07 #define DRM_NOUVEAU_MEM_ALLOC 0x08 #define DRM_NOUVEAU_MEM_FREE 0x09 +#define DRM_NOUVEAU_MEM_TILE 0x0a #endif /* __NOUVEAU_DRM_H__ */ diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index 33e2a5b..03fe2ba 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -34,7 +34,7 @@ #define DRIVER_MAJOR 0 #define DRIVER_MINOR 0 -#define DRIVER_PATCHLEVEL 10 +#define DRIVER_PATCHLEVEL 11 #define NOUVEAU_FAMILY 0x0000FFFF #define NOUVEAU_FLAGS 0xFFFF0000 @@ -385,6 +385,8 @@ extern int nouveau_ioctl_mem_alloc(struct drm_device *, void *data, struct drm_file *); extern int nouveau_ioctl_mem_free(struct drm_device *, void *data, ... [truncated message content] |