From 8f1a60868f4594bc5576cca8952635f475e8bec6 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 28 Jun 2010 14:35:50 +1000 Subject: drm/nouveau: tidy connector/encoder creation a little Create connectors before encoders to avoid having to do another loop across encoder list whenever we create a new connector. This allows us to pass the connector to the encoder creation functions, and avoid using a create_resources() callback since we can now call it directly. This can also potentially modify the connector ordering on nv50. On cards where the DCB connector and encoder tables are in the same order, things will be unchanged. However, there's some cards where the ordering between the tables differ, and in one case, leads us to naming the connectors "wrongly". Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv04_tv.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/nouveau/nv04_tv.c') diff --git a/drivers/gpu/drm/nouveau/nv04_tv.c b/drivers/gpu/drm/nouveau/nv04_tv.c index c4e3404337d..84b5954a8ef 100644 --- a/drivers/gpu/drm/nouveau/nv04_tv.c +++ b/drivers/gpu/drm/nouveau/nv04_tv.c @@ -223,10 +223,12 @@ static void nv04_tv_destroy(struct drm_encoder *encoder) kfree(nv_encoder); } -int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry) +int +nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry) { struct nouveau_encoder *nv_encoder; struct drm_encoder *encoder; + struct drm_device *dev = connector->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct i2c_adapter *adap; struct drm_encoder_funcs *funcs = NULL; @@ -266,7 +268,7 @@ int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry) was_locked = NVLockVgaCrtcs(dev, false); - ret = drm_i2c_encoder_init(encoder->dev, to_encoder_slave(encoder), adap, + ret = drm_i2c_encoder_init(dev, to_encoder_slave(encoder), adap, &nv04_tv_encoder_info[type].board_info); NVLockVgaCrtcs(dev, was_locked); @@ -294,7 +296,9 @@ int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry) /* Set the slave encoder configuration */ sfuncs->set_config(encoder, nv04_tv_encoder_info[type].params); + sfuncs->create_resources(encoder, connector); + drm_mode_connector_attach_encoder(connector, encoder); return 0; fail: -- cgit v1.2.3-70-g09d2 From 6d416d80f720f71e2dfe903d672bcca071822538 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Mon, 19 Jul 2010 15:55:08 +0200 Subject: drm/nouveau: Add some generic I2C gadget detection code. Clean up and move the external TV encoder detection code to nouveau_i2c.c, it's also going to be useful for external TMDS and DDC detection. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 22 +----- drivers/gpu/drm/nouveau/nouveau_i2c.c | 34 ++++++++ drivers/gpu/drm/nouveau/nouveau_i2c.h | 3 + drivers/gpu/drm/nouveau/nv04_tv.c | 115 +++++++++------------------- 4 files changed, 75 insertions(+), 99 deletions(-) (limited to 'drivers/gpu/drm/nouveau/nv04_tv.c') diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 7f749d281df..27df0063131 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -139,26 +139,10 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, struct nouveau_encoder **pnv_encoder) { struct drm_device *dev = connector->dev; - uint8_t out_buf[] = { 0x0, 0x0}, buf[2]; int ret, flags, i; - struct i2c_msg msgs[] = { - { - .addr = 0x50, - .flags = 0, - .len = 1, - .buf = out_buf, - }, - { - .addr = 0x50, - .flags = I2C_M_RD, - .len = 1, - .buf = buf, - } - }; - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - struct nouveau_i2c_chan *i2c = NULL; + struct nouveau_i2c_chan *i2c; struct nouveau_encoder *nv_encoder; struct drm_mode_object *obj; int id; @@ -178,10 +162,10 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, continue; nouveau_connector_ddc_prepare(connector, &flags); - ret = i2c_transfer(&i2c->adapter, msgs, 2); + ret = nouveau_probe_i2c_addr(i2c, 0x50); nouveau_connector_ddc_finish(connector, flags); - if (ret == 2) { + if (ret) { *pnv_encoder = nv_encoder; return i2c; } diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c index 316a3c7e6eb..97ba89ef42a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.c +++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c @@ -278,3 +278,37 @@ nouveau_i2c_find(struct drm_device *dev, int index) return i2c->chan; } +bool +nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr) +{ + struct i2c_msg msg = { + .addr = addr, + .len = 0, + }; + + return i2c_transfer(&i2c->adapter, &msg, 1) == 1; +} + +int +nouveau_i2c_identify(struct drm_device *dev, const char *what, + struct i2c_board_info *info, int index) +{ + struct nouveau_i2c_chan *i2c = nouveau_i2c_find(dev, index); + int was_locked, i; + + was_locked = NVLockVgaCrtcs(dev, false); + NV_DEBUG(dev, "Probing %ss on I2C bus: %d\n", what, index); + + for (i = 0; info[i].addr; i++) { + if (nouveau_probe_i2c_addr(i2c, info[i].addr)) { + NV_INFO(dev, "Detected %s: %s\n", what, info[i].type); + goto out; + } + } + + NV_DEBUG(dev, "No devices found.\n"); +out: + NVLockVgaCrtcs(dev, was_locked); + + return info[i].addr ? i : -ENODEV; +} diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.h b/drivers/gpu/drm/nouveau/nouveau_i2c.h index c8eaf7a9fcb..6dd2f8713cd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.h +++ b/drivers/gpu/drm/nouveau/nouveau_i2c.h @@ -45,6 +45,9 @@ struct nouveau_i2c_chan { int nouveau_i2c_init(struct drm_device *, struct dcb_i2c_entry *, int index); void nouveau_i2c_fini(struct drm_device *, struct dcb_i2c_entry *); struct nouveau_i2c_chan *nouveau_i2c_find(struct drm_device *, int index); +bool nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr); +int nouveau_i2c_identify(struct drm_device *dev, const char *what, + struct i2c_board_info *info, int index); int nouveau_dp_i2c_aux_ch(struct i2c_adapter *, int mode, uint8_t write_byte, uint8_t *read_byte); diff --git a/drivers/gpu/drm/nouveau/nv04_tv.c b/drivers/gpu/drm/nouveau/nv04_tv.c index 84b5954a8ef..8de1eef3594 100644 --- a/drivers/gpu/drm/nouveau/nv04_tv.c +++ b/drivers/gpu/drm/nouveau/nv04_tv.c @@ -34,69 +34,26 @@ #include "i2c/ch7006.h" -static struct { - struct i2c_board_info board_info; - struct drm_encoder_funcs funcs; - struct drm_encoder_helper_funcs hfuncs; - void *params; - -} nv04_tv_encoder_info[] = { +static struct i2c_board_info nv04_tv_encoder_info[] = { { - .board_info = { I2C_BOARD_INFO("ch7006", 0x75) }, - .params = &(struct ch7006_encoder_params) { + I2C_BOARD_INFO("ch7006", 0x75), + .platform_data = &(struct ch7006_encoder_params) { CH7006_FORMAT_RGB24m12I, CH7006_CLOCK_MASTER, 0, 0, 0, CH7006_SYNC_SLAVE, CH7006_SYNC_SEPARATED, CH7006_POUT_3_3V, CH7006_ACTIVE_HSYNC - }, + } }, + { } }; -static bool probe_i2c_addr(struct i2c_adapter *adapter, int addr) -{ - struct i2c_msg msg = { - .addr = addr, - .len = 0, - }; - - return i2c_transfer(adapter, &msg, 1) == 1; -} - int nv04_tv_identify(struct drm_device *dev, int i2c_index) { - struct nouveau_i2c_chan *i2c; - bool was_locked; - int i, ret; - - NV_TRACE(dev, "Probing TV encoders on I2C bus: %d\n", i2c_index); - - i2c = nouveau_i2c_find(dev, i2c_index); - if (!i2c) - return -ENODEV; - - was_locked = NVLockVgaCrtcs(dev, false); - - for (i = 0; i < ARRAY_SIZE(nv04_tv_encoder_info); i++) { - if (probe_i2c_addr(&i2c->adapter, - nv04_tv_encoder_info[i].board_info.addr)) { - ret = i; - break; - } - } - - if (i < ARRAY_SIZE(nv04_tv_encoder_info)) { - NV_TRACE(dev, "Detected TV encoder: %s\n", - nv04_tv_encoder_info[i].board_info.type); - - } else { - NV_TRACE(dev, "No TV encoders found.\n"); - i = -ENODEV; - } - - NVLockVgaCrtcs(dev, was_locked); - return i; + return nouveau_i2c_identify(dev, "TV encoder", + nv04_tv_encoder_info, i2c_index); } + #define PLLSEL_TV_CRTC1_MASK \ (NV_PRAMDAC_PLL_COEFF_SELECT_TV_VSCLK1 \ | NV_PRAMDAC_PLL_COEFF_SELECT_TV_PCLK1) @@ -214,32 +171,33 @@ static void nv04_tv_commit(struct drm_encoder *encoder) static void nv04_tv_destroy(struct drm_encoder *encoder) { - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - to_encoder_slave(encoder)->slave_funcs->destroy(encoder); drm_encoder_cleanup(encoder); - kfree(nv_encoder); + kfree(encoder->helper_private); + kfree(nouveau_encoder(encoder)); } +static const struct drm_encoder_funcs nv04_tv_funcs = { + .destroy = nv04_tv_destroy, +}; + int nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry) { struct nouveau_encoder *nv_encoder; struct drm_encoder *encoder; struct drm_device *dev = connector->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct i2c_adapter *adap; - struct drm_encoder_funcs *funcs = NULL; - struct drm_encoder_helper_funcs *hfuncs = NULL; - struct drm_encoder_slave_funcs *sfuncs = NULL; - int i2c_index = entry->i2c_index; + struct drm_encoder_helper_funcs *hfuncs; + struct drm_encoder_slave_funcs *sfuncs; + struct nouveau_i2c_chan *i2c = + nouveau_i2c_find(dev, entry->i2c_index); int type, ret; bool was_locked; /* Ensure that we can talk to this encoder */ - type = nv04_tv_identify(dev, i2c_index); + type = nv04_tv_identify(dev, entry->i2c_index); if (type < 0) return type; @@ -248,41 +206,37 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry) if (!nv_encoder) return -ENOMEM; + hfuncs = kzalloc(sizeof(*hfuncs), GFP_KERNEL); + if (!hfuncs) { + ret = -ENOMEM; + goto fail_free; + } + /* Initialize the common members */ encoder = to_drm_encoder(nv_encoder); - funcs = &nv04_tv_encoder_info[type].funcs; - hfuncs = &nv04_tv_encoder_info[type].hfuncs; - - drm_encoder_init(dev, encoder, funcs, DRM_MODE_ENCODER_TVDAC); + drm_encoder_init(dev, encoder, &nv04_tv_funcs, DRM_MODE_ENCODER_TVDAC); drm_encoder_helper_add(encoder, hfuncs); encoder->possible_crtcs = entry->heads; encoder->possible_clones = 0; - nv_encoder->dcb = entry; nv_encoder->or = ffs(entry->or) - 1; /* Run the slave-specific initialization */ - adap = &dev_priv->vbios.dcb.i2c[i2c_index].chan->adapter; - was_locked = NVLockVgaCrtcs(dev, false); - ret = drm_i2c_encoder_init(dev, to_encoder_slave(encoder), adap, - &nv04_tv_encoder_info[type].board_info); + ret = drm_i2c_encoder_init(dev, to_encoder_slave(encoder), + &i2c->adapter, &nv04_tv_encoder_info[type]); NVLockVgaCrtcs(dev, was_locked); if (ret < 0) - goto fail; + goto fail_cleanup; /* Fill the function pointers */ sfuncs = to_encoder_slave(encoder)->slave_funcs; - *funcs = (struct drm_encoder_funcs) { - .destroy = nv04_tv_destroy, - }; - *hfuncs = (struct drm_encoder_helper_funcs) { .dpms = nv04_tv_dpms, .save = sfuncs->save, @@ -294,16 +248,17 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry) .detect = sfuncs->detect, }; - /* Set the slave encoder configuration */ - sfuncs->set_config(encoder, nv04_tv_encoder_info[type].params); + /* Attach it to the specified connector. */ + sfuncs->set_config(encoder, nv04_tv_encoder_info[type].platform_data); sfuncs->create_resources(encoder, connector); - drm_mode_connector_attach_encoder(connector, encoder); + return 0; -fail: +fail_cleanup: drm_encoder_cleanup(encoder); - + kfree(hfuncs); +fail_free: kfree(nv_encoder); return ret; } -- cgit v1.2.3-70-g09d2 From 03cd06ca9046190e8418749c2c8f636e2625556c Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Tue, 20 Jul 2010 03:08:25 +0200 Subject: drm/nouveau: No need to lock/unlock the VGA CRTC regs all the time. Locking only makes sense in the VBIOS parsing code as it's executed before CRTC init. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 11 +++---- drivers/gpu/drm/nouveau/nouveau_connector.c | 50 +++-------------------------- drivers/gpu/drm/nouveau/nouveau_drv.c | 5 ++- drivers/gpu/drm/nouveau/nv04_display.c | 36 +++++++-------------- drivers/gpu/drm/nouveau/nv04_tv.c | 6 ---- 5 files changed, 23 insertions(+), 85 deletions(-) (limited to 'drivers/gpu/drm/nouveau/nv04_tv.c') diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 665f0d64f2c..3b5523eff43 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -6607,7 +6607,6 @@ static bool nouveau_bios_posted(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - bool was_locked; unsigned htotal; if (dev_priv->chipset >= NV_50) { @@ -6617,13 +6616,14 @@ nouveau_bios_posted(struct drm_device *dev) return true; } - was_locked = NVLockVgaCrtcs(dev, false); + NVLockVgaCrtcs(dev, false); htotal = NVReadVgaCrtc(dev, 0, 0x06); htotal |= (NVReadVgaCrtc(dev, 0, 0x07) & 0x01) << 8; htotal |= (NVReadVgaCrtc(dev, 0, 0x07) & 0x20) << 4; htotal |= (NVReadVgaCrtc(dev, 0, 0x25) & 0x01) << 10; htotal |= (NVReadVgaCrtc(dev, 0, 0x41) & 0x01) << 11; - NVLockVgaCrtcs(dev, was_locked); + NVLockVgaCrtcs(dev, true); + return (htotal != 0); } @@ -6632,7 +6632,6 @@ nouveau_bios_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nvbios *bios = &dev_priv->vbios; - bool was_locked; int ret; if (!NVInitVBIOS(dev)) @@ -6667,14 +6666,14 @@ nouveau_bios_init(struct drm_device *dev) return ret; /* feature_byte on BMP is poor, but init always sets CR4B */ - was_locked = NVLockVgaCrtcs(dev, false); + NVLockVgaCrtcs(dev, false); if (bios->major_version < 5) bios->is_mobile = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_4B) & 0x40; /* all BIT systems need p_f_m_t for digital_min_front_porch */ if (bios->is_mobile || bios->major_version >= 5) ret = parse_fp_mode_table(dev, bios); - NVLockVgaCrtcs(dev, was_locked); + NVLockVgaCrtcs(dev, true); /* allow subsequent scripts to execute */ bios->execute = true; diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 27df0063131..734e92635e8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -102,44 +102,12 @@ nouveau_connector_destroy(struct drm_connector *drm_connector) kfree(drm_connector); } -static void -nouveau_connector_ddc_prepare(struct drm_connector *connector, int *flags) -{ - struct drm_nouveau_private *dev_priv = connector->dev->dev_private; - - if (dev_priv->card_type >= NV_50) - return; - - *flags = 0; - if (NVLockVgaCrtcs(dev_priv->dev, false)) - *flags |= 1; - if (nv_heads_tied(dev_priv->dev)) - *flags |= 2; - - if (*flags & 2) - NVSetOwner(dev_priv->dev, 0); /* necessary? */ -} - -static void -nouveau_connector_ddc_finish(struct drm_connector *connector, int flags) -{ - struct drm_nouveau_private *dev_priv = connector->dev->dev_private; - - if (dev_priv->card_type >= NV_50) - return; - - if (flags & 2) - NVSetOwner(dev_priv->dev, 4); - if (flags & 1) - NVLockVgaCrtcs(dev_priv->dev, true); -} - static struct nouveau_i2c_chan * nouveau_connector_ddc_detect(struct drm_connector *connector, struct nouveau_encoder **pnv_encoder) { struct drm_device *dev = connector->dev; - int ret, flags, i; + int i; for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { struct nouveau_i2c_chan *i2c; @@ -155,17 +123,9 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, if (!obj) continue; nv_encoder = nouveau_encoder(obj_to_encoder(obj)); + i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); - if (nv_encoder->dcb->i2c_index < 0xf) - i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); - if (!i2c) - continue; - - nouveau_connector_ddc_prepare(connector, &flags); - ret = nouveau_probe_i2c_addr(i2c, 0x50); - nouveau_connector_ddc_finish(connector, flags); - - if (ret) { + if (i2c && nouveau_probe_i2c_addr(i2c, 0x50)) { *pnv_encoder = nv_encoder; return i2c; } @@ -218,7 +178,7 @@ nouveau_connector_detect(struct drm_connector *connector) struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_encoder *nv_encoder = NULL; struct nouveau_i2c_chan *i2c; - int type, flags; + int type; /* Cleanup the previous EDID block. */ if (nv_connector->edid) { @@ -229,9 +189,7 @@ nouveau_connector_detect(struct drm_connector *connector) i2c = nouveau_connector_ddc_detect(connector, &nv_encoder); if (i2c) { - nouveau_connector_ddc_prepare(connector, &flags); nv_connector->edid = drm_get_edid(connector, &i2c->adapter); - nouveau_connector_ddc_finish(connector, flags); drm_mode_connector_update_edid_property(connector, nv_connector->edid); if (!nv_connector->edid) { diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index 6c8cd38fd11..e93fbcc56da 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -321,10 +321,9 @@ nouveau_pci_resume(struct pci_dev *pdev) NV_ERROR(dev, "Could not pin/map cursor.\n"); } - if (dev_priv->card_type < NV_50) { + if (dev_priv->card_type < NV_50) nv04_display_restore(dev); - NVLockVgaCrtcs(dev, false); - } else + else nv50_display_init(dev); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { diff --git a/drivers/gpu/drm/nouveau/nv04_display.c b/drivers/gpu/drm/nouveau/nv04_display.c index 93200da8f2d..c6df391ebb2 100644 --- a/drivers/gpu/drm/nouveau/nv04_display.c +++ b/drivers/gpu/drm/nouveau/nv04_display.c @@ -32,8 +32,6 @@ #include "nouveau_encoder.h" #include "nouveau_connector.h" -#define MULTIPLE_ENCODERS(e) (e & (e - 1)) - static void nv04_display_store_initial_head_owner(struct drm_device *dev) { @@ -41,7 +39,7 @@ nv04_display_store_initial_head_owner(struct drm_device *dev) if (dev_priv->chipset != 0x11) { dev_priv->crtc_owner = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_44); - goto ownerknown; + return; } /* reading CR44 is broken on nv11, so we attempt to infer it */ @@ -52,8 +50,6 @@ nv04_display_store_initial_head_owner(struct drm_device *dev) bool tvA = false; bool tvB = false; - NVLockVgaCrtcs(dev, false); - slaved_on_B = NVReadVgaCrtc(dev, 1, NV_CIO_CRE_PIXEL_INDEX) & 0x80; if (slaved_on_B) @@ -66,8 +62,6 @@ nv04_display_store_initial_head_owner(struct drm_device *dev) tvA = !(NVReadVgaCrtc(dev, 0, NV_CIO_CRE_LCD__INDEX) & MASK(NV_CIO_CRE_LCD_LCD_SELECT)); - NVLockVgaCrtcs(dev, true); - if (slaved_on_A && !tvA) dev_priv->crtc_owner = 0x0; else if (slaved_on_B && !tvB) @@ -79,12 +73,6 @@ nv04_display_store_initial_head_owner(struct drm_device *dev) else dev_priv->crtc_owner = 0x0; } - -ownerknown: - /* we need to ensure the heads are not tied henceforth, or reading any - * 8 bit reg on head B will fail - * setting a single arbitrary head solves that */ - NVSetOwner(dev, 0); } int @@ -99,8 +87,13 @@ nv04_display_create(struct drm_device *dev) NV_DEBUG_KMS(dev, "\n"); - if (nv_two_heads(dev)) + NVLockVgaCrtcs(dev, false); + + if (nv_two_heads(dev)) { nv04_display_store_initial_head_owner(dev); + NVSetOwner(dev, 0); + } + nouveau_hw_save_vga_fonts(dev, 1); drm_mode_config_init(dev); @@ -168,8 +161,6 @@ nv04_display_create(struct drm_device *dev) } /* Save previous state */ - NVLockVgaCrtcs(dev, false); - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) crtc->funcs->save(crtc); @@ -185,6 +176,7 @@ nv04_display_create(struct drm_device *dev) void nv04_display_destroy(struct drm_device *dev) { + struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_encoder *encoder; struct drm_crtc *crtc; @@ -200,8 +192,6 @@ nv04_display_destroy(struct drm_device *dev) } /* Restore state */ - NVLockVgaCrtcs(dev, false); - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { struct drm_encoder_helper_funcs *func = encoder->helper_private; @@ -214,12 +204,15 @@ nv04_display_destroy(struct drm_device *dev) drm_mode_config_cleanup(dev); nouveau_hw_save_vga_fonts(dev, 0); + + if (nv_two_heads(dev)) + NVSetOwner(dev, dev_priv->crtc_owner); + NVLockVgaCrtcs(dev, true); } void nv04_display_restore(struct drm_device *dev) { - struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_encoder *encoder; struct drm_crtc *crtc; @@ -241,10 +234,5 @@ nv04_display_restore(struct drm_device *dev) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) crtc->funcs->restore(crtc); - - if (nv_two_heads(dev)) - NVSetOwner(dev, dev_priv->crtc_owner); - - NVLockVgaCrtcs(dev, true); } diff --git a/drivers/gpu/drm/nouveau/nv04_tv.c b/drivers/gpu/drm/nouveau/nv04_tv.c index 8de1eef3594..94e299cef0b 100644 --- a/drivers/gpu/drm/nouveau/nv04_tv.c +++ b/drivers/gpu/drm/nouveau/nv04_tv.c @@ -194,7 +194,6 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry) struct nouveau_i2c_chan *i2c = nouveau_i2c_find(dev, entry->i2c_index); int type, ret; - bool was_locked; /* Ensure that we can talk to this encoder */ type = nv04_tv_identify(dev, entry->i2c_index); @@ -224,13 +223,8 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry) nv_encoder->or = ffs(entry->or) - 1; /* Run the slave-specific initialization */ - was_locked = NVLockVgaCrtcs(dev, false); - ret = drm_i2c_encoder_init(dev, to_encoder_slave(encoder), &i2c->adapter, &nv04_tv_encoder_info[type]); - - NVLockVgaCrtcs(dev, was_locked); - if (ret < 0) goto fail_cleanup; -- cgit v1.2.3-70-g09d2 From 4a9f822fe1a6ca5de7d8cdd5efbead3b9ab4283b Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Tue, 20 Jul 2010 16:48:08 +0200 Subject: drm/nv17-nv4x: Attempt to init some external TMDS transmitters. sil164 and friends are the most common, usually they just need to be poked once because a fixed configuration is enough for any modes and clocks, so they worked without this patch if the BIOS had done a good job on POST. Display couldn't survive a suspend/resume cycle though. Unfortunately, BIOS scripts are useless here. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 21 ++++++++++++++- drivers/gpu/drm/nouveau/nouveau_bios.h | 1 + drivers/gpu/drm/nouveau/nouveau_connector.c | 19 +++++-------- drivers/gpu/drm/nouveau/nouveau_drv.h | 2 +- drivers/gpu/drm/nouveau/nouveau_encoder.h | 6 +++++ drivers/gpu/drm/nouveau/nouveau_hw.c | 11 ++++++-- drivers/gpu/drm/nouveau/nv04_crtc.c | 3 +++ drivers/gpu/drm/nouveau/nv04_dfp.c | 42 +++++++++++++++++++++++++++++ drivers/gpu/drm/nouveau/nv04_tv.c | 9 +++---- 9 files changed, 93 insertions(+), 21 deletions(-) (limited to 'drivers/gpu/drm/nouveau/nv04_tv.c') diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index c608b0b29a3..e86f46cf883 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -5982,7 +5982,13 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, } break; case OUTPUT_TMDS: - entry->tmdsconf.sor.link = (conf & 0x00000030) >> 4; + if (dcb->version >= 0x22) + entry->tmdsconf.slave_addr = (conf & 0x00000070) >> 4; + else if (dcb->version >= 0x30) + entry->tmdsconf.slave_addr = (conf & 0x00000700) >> 8; + else if (dcb->version >= 0x40) + entry->tmdsconf.sor.link = (conf & 0x00000030) >> 4; + break; case 0xe: /* weird g80 mobile type that "nv" treats as a terminator */ @@ -6272,6 +6278,19 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads) dcb->i2c_table = &bios->data[i2ctabptr]; if (dcb->version >= 0x30) dcb->i2c_default_indices = dcb->i2c_table[4]; + + /* + * Parse the "management" I2C bus, used for hardware + * monitoring and some external TMDS transmitters. + */ + if (dcb->version >= 0x22) { + int idx = (dcb->version >= 0x40 ? + dcb->i2c_default_indices & 0xf : + 2); + + read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table, + idx, &dcb->i2c[idx]); + } } if (entries > DCB_MAX_NUM_ENTRIES) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h index 024458a8d06..fd14dfd3d78 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.h +++ b/drivers/gpu/drm/nouveau/nouveau_bios.h @@ -131,6 +131,7 @@ struct dcb_entry { } dpconf; struct { struct sor_conf sor; + int slave_addr; } tmdsconf; }; bool i2c_upper_default; diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 734e92635e8..b1b22baf142 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -37,12 +37,6 @@ #include "nouveau_connector.h" #include "nouveau_hw.h" -static inline struct drm_encoder_slave_funcs * -get_slave_funcs(struct nouveau_encoder *enc) -{ - return to_encoder_slave(to_drm_encoder(enc))->slave_funcs; -} - static struct nouveau_encoder * find_encoder_by_type(struct drm_connector *connector, int type) { @@ -360,6 +354,7 @@ nouveau_connector_set_property(struct drm_connector *connector, { struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; + struct drm_encoder *encoder = to_drm_encoder(nv_encoder); struct drm_device *dev = connector->dev; int ret; @@ -432,8 +427,8 @@ nouveau_connector_set_property(struct drm_connector *connector, } if (nv_encoder && nv_encoder->dcb->type == OUTPUT_TV) - return get_slave_funcs(nv_encoder)-> - set_property(to_drm_encoder(nv_encoder), connector, property, value); + return get_slave_funcs(encoder)->set_property( + encoder, connector, property, value); return -EINVAL; } @@ -545,6 +540,7 @@ nouveau_connector_get_modes(struct drm_connector *connector) struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; + struct drm_encoder *encoder = to_drm_encoder(nv_encoder); int ret = 0; /* destroy the native mode, the attached monitor could have changed. @@ -580,8 +576,7 @@ nouveau_connector_get_modes(struct drm_connector *connector) } if (nv_encoder->dcb->type == OUTPUT_TV) - ret = get_slave_funcs(nv_encoder)-> - get_modes(to_drm_encoder(nv_encoder), connector); + ret = get_slave_funcs(encoder)->get_modes(encoder, connector); if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS || nv_connector->dcb->type == DCB_CONNECTOR_eDP) @@ -597,6 +592,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector, struct drm_nouveau_private *dev_priv = connector->dev->dev_private; struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; + struct drm_encoder *encoder = to_drm_encoder(nv_encoder); unsigned min_clock = 25000, max_clock = min_clock; unsigned clock = mode->clock; @@ -623,8 +619,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector, max_clock = 350000; break; case OUTPUT_TV: - return get_slave_funcs(nv_encoder)-> - mode_valid(to_drm_encoder(nv_encoder), mode); + return get_slave_funcs(encoder)->mode_valid(encoder, mode); case OUTPUT_DP: if (nv_encoder->dp.link_bw == DP_LINK_BW_2_7) max_clock = nv_encoder->dp.link_nr * 270000; diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index db10809e913..9e17d88bc89 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -410,7 +410,7 @@ enum nv04_fp_display_regs { struct nv04_crtc_reg { unsigned char MiscOutReg; /* */ - uint8_t CRTC[0x9f]; + uint8_t CRTC[0xa0]; uint8_t CR58[0x10]; uint8_t Sequencer[5]; uint8_t Graphics[9]; diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index a1a0d48ae70..7c82d68bc15 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h @@ -71,6 +71,12 @@ static inline struct drm_encoder *to_drm_encoder(struct nouveau_encoder *enc) return &enc->base.base; } +static inline struct drm_encoder_slave_funcs * +get_slave_funcs(struct drm_encoder *enc) +{ + return to_encoder_slave(enc)->slave_funcs; +} + struct nouveau_connector * nouveau_encoder_connector_get(struct nouveau_encoder *encoder); int nv50_sor_create(struct drm_connector *, struct dcb_entry *); diff --git a/drivers/gpu/drm/nouveau/nouveau_hw.c b/drivers/gpu/drm/nouveau/nouveau_hw.c index 7855b35effc..7b613682e40 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hw.c +++ b/drivers/gpu/drm/nouveau/nouveau_hw.c @@ -865,8 +865,12 @@ nv_save_state_ext(struct drm_device *dev, int head, rd_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX); rd_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX); rd_cio_state(dev, head, regp, NV_CIO_CRE_21); - if (dev_priv->card_type >= NV_30) + + if (dev_priv->card_type >= NV_30) { rd_cio_state(dev, head, regp, NV_CIO_CRE_47); + rd_cio_state(dev, head, regp, 0x9f); + } + rd_cio_state(dev, head, regp, NV_CIO_CRE_49); rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX); rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR1_INDEX); @@ -971,8 +975,11 @@ nv_load_state_ext(struct drm_device *dev, int head, wr_cio_state(dev, head, regp, NV_CIO_CRE_ENH_INDEX); wr_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX); wr_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX); - if (dev_priv->card_type >= NV_30) + + if (dev_priv->card_type >= NV_30) { wr_cio_state(dev, head, regp, NV_CIO_CRE_47); + wr_cio_state(dev, head, regp, 0x9f); + } wr_cio_state(dev, head, regp, NV_CIO_CRE_49); wr_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX); diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c index 1c20c08ce67..08c7e073edc 100644 --- a/drivers/gpu/drm/nouveau/nv04_crtc.c +++ b/drivers/gpu/drm/nouveau/nv04_crtc.c @@ -542,6 +542,9 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode) * 1 << 30 on 0x60.830), for no apparent reason */ regp->CRTC[NV_CIO_CRE_59] = off_chip_digital; + if (dev_priv->card_type >= NV_30) + regp->CRTC[0x9f] = off_chip_digital ? 0x11 : 0x1; + regp->crtc_830 = mode->crtc_vdisplay - 3; regp->crtc_834 = mode->crtc_vdisplay - 1; diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c index 3311f3a8c81..9871570d2ff 100644 --- a/drivers/gpu/drm/nouveau/nv04_dfp.c +++ b/drivers/gpu/drm/nouveau/nv04_dfp.c @@ -34,6 +34,8 @@ #include "nouveau_hw.h" #include "nvreg.h" +#include "i2c/sil164.h" + #define FP_TG_CONTROL_ON (NV_PRAMDAC_FP_TG_CONTROL_DISPEN_POS | \ NV_PRAMDAC_FP_TG_CONTROL_HSYNC_POS | \ NV_PRAMDAC_FP_TG_CONTROL_VSYNC_POS) @@ -429,6 +431,11 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) else NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0x00100000); + /* Init external transmitters */ + if (get_slave_funcs(encoder)) + get_slave_funcs(encoder)->mode_set(encoder, &nv_encoder->mode, + &nv_encoder->mode); + helper->dpms(encoder, DRM_MODE_DPMS_ON); NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n", @@ -550,10 +557,41 @@ static void nv04_dfp_destroy(struct drm_encoder *encoder) NV_DEBUG_KMS(encoder->dev, "\n"); + if (get_slave_funcs(encoder)) + get_slave_funcs(encoder)->destroy(encoder); + drm_encoder_cleanup(encoder); kfree(nv_encoder); } +static void nv04_tmds_slave_init(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; + struct nouveau_i2c_chan *i2c = nouveau_i2c_find(dev, 2); + struct i2c_board_info info[] = { + { + .type = "sil164", + .addr = (dcb->tmdsconf.slave_addr == 0x7 ? 0x3a : 0x38), + .platform_data = &(struct sil164_encoder_params) { + SIL164_INPUT_EDGE_RISING + } + }, + { } + }; + int type; + + if (!nv_gf4_disp_arch(dev) || !i2c) + return; + + type = nouveau_i2c_identify(dev, "TMDS transmitter", info, 2); + if (type < 0) + return; + + drm_i2c_encoder_init(dev, to_encoder_slave(encoder), + &i2c->adapter, &info[type]); +} + static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = { .dpms = nv04_lvds_dpms, .save = nv04_dfp_save, @@ -616,6 +654,10 @@ nv04_dfp_create(struct drm_connector *connector, struct dcb_entry *entry) encoder->possible_crtcs = entry->heads; encoder->possible_clones = 0; + if (entry->type == OUTPUT_TMDS && + entry->location != DCB_LOC_ON_CHIP) + nv04_tmds_slave_init(encoder); + drm_mode_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/nouveau/nv04_tv.c b/drivers/gpu/drm/nouveau/nv04_tv.c index 94e299cef0b..4e73c4461a2 100644 --- a/drivers/gpu/drm/nouveau/nv04_tv.c +++ b/drivers/gpu/drm/nouveau/nv04_tv.c @@ -89,7 +89,7 @@ static void nv04_tv_dpms(struct drm_encoder *encoder, int mode) NVWriteRAMDAC(dev, 0, NV_PRAMDAC_PLL_COEFF_SELECT, state->pllsel); - to_encoder_slave(encoder)->slave_funcs->dpms(encoder, mode); + get_slave_funcs(encoder)->dpms(encoder, mode); } static void nv04_tv_bind(struct drm_device *dev, int head, bool bind) @@ -152,7 +152,7 @@ static void nv04_tv_mode_set(struct drm_encoder *encoder, regp->tv_vskew = 1; regp->tv_vsync_delay = 1; - to_encoder_slave(encoder)->slave_funcs->mode_set(encoder, mode, adjusted_mode); + get_slave_funcs(encoder)->mode_set(encoder, mode, adjusted_mode); } static void nv04_tv_commit(struct drm_encoder *encoder) @@ -171,8 +171,7 @@ static void nv04_tv_commit(struct drm_encoder *encoder) static void nv04_tv_destroy(struct drm_encoder *encoder) { - to_encoder_slave(encoder)->slave_funcs->destroy(encoder); - + get_slave_funcs(encoder)->destroy(encoder); drm_encoder_cleanup(encoder); kfree(encoder->helper_private); @@ -229,7 +228,7 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry) goto fail_cleanup; /* Fill the function pointers */ - sfuncs = to_encoder_slave(encoder)->slave_funcs; + sfuncs = get_slave_funcs(encoder); *hfuncs = (struct drm_encoder_helper_funcs) { .dpms = nv04_tv_dpms, -- cgit v1.2.3-70-g09d2 From bfe9dbcfc67e14eb679869afbc8ada2c4bcc4440 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Tue, 20 Jul 2010 17:16:33 +0200 Subject: drm/nouveau: No need to set slave TV encoder configs explicitly. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv04_tv.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/gpu/drm/nouveau/nv04_tv.c') diff --git a/drivers/gpu/drm/nouveau/nv04_tv.c b/drivers/gpu/drm/nouveau/nv04_tv.c index 4e73c4461a2..0b5d012d7c2 100644 --- a/drivers/gpu/drm/nouveau/nv04_tv.c +++ b/drivers/gpu/drm/nouveau/nv04_tv.c @@ -242,7 +242,6 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry) }; /* Attach it to the specified connector. */ - sfuncs->set_config(encoder, nv04_tv_encoder_info[type].platform_data); sfuncs->create_resources(encoder, connector); drm_mode_connector_attach_encoder(connector, encoder); -- cgit v1.2.3-70-g09d2