From c020c9a8ca569cec19a147c9cd44fe6c3c9cdcee Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 29 Jul 2010 21:01:45 +1000 Subject: drm/nv50: use custom i2c algo for dp auxch This makes it easier to see how this is working, and lets us transfer the EDID in blocks of 16 bytes. The primary reason for this change is because debug logs are rather hard to read with the hundreds of single-byte auxch transactions that occur. Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index 33742b1..8a1b188 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -572,47 +572,64 @@ out: return ret ? ret : (stat & NV50_AUXCH_STAT_REPLY); } -int -nouveau_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, - uint8_t write_byte, uint8_t *read_byte) +static int +nouveau_dp_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { - struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; - struct nouveau_i2c_chan *auxch = (struct nouveau_i2c_chan *)adapter; + struct nouveau_i2c_chan *auxch = (struct nouveau_i2c_chan *)adap; struct drm_device *dev = auxch->dev; - int ret = 0, cmd, addr = algo_data->address; - uint8_t *buf; - - if (mode == MODE_I2C_READ) { - cmd = AUX_I2C_READ; - buf = read_byte; - } else { - cmd = (mode & MODE_I2C_READ) ? AUX_I2C_READ : AUX_I2C_WRITE; - buf = &write_byte; - } + struct i2c_msg *msg = msgs; + int ret, mcnt = num; - if (!(mode & MODE_I2C_STOP)) - cmd |= AUX_I2C_MOT; + while (mcnt--) { + u8 remaining = msg->len; + u8 *ptr = msg->buf; - if (mode & MODE_I2C_START) - return 1; + while (remaining) { + u8 cnt = (remaining > 16) ? 16 : remaining; + u8 cmd; - for (;;) { - ret = nouveau_dp_auxch(auxch, cmd, addr, buf, 1); - if (ret < 0) - return ret; - - switch (ret & NV50_AUXCH_STAT_REPLY_I2C) { - case NV50_AUXCH_STAT_REPLY_I2C_ACK: - return 1; - case NV50_AUXCH_STAT_REPLY_I2C_NACK: - return -EREMOTEIO; - case NV50_AUXCH_STAT_REPLY_I2C_DEFER: - udelay(100); - break; - default: - NV_ERROR(dev, "invalid auxch status: 0x%08x\n", ret); - return -EREMOTEIO; + if (msg->flags & I2C_M_RD) + cmd = AUX_I2C_READ; + else + cmd = AUX_I2C_WRITE; + + if (mcnt || remaining > 16) + cmd |= AUX_I2C_MOT; + + ret = nouveau_dp_auxch(auxch, cmd, msg->addr, ptr, cnt); + if (ret < 0) + return ret; + + switch (ret & NV50_AUXCH_STAT_REPLY_I2C) { + case NV50_AUXCH_STAT_REPLY_I2C_ACK: + break; + case NV50_AUXCH_STAT_REPLY_I2C_NACK: + return -EREMOTEIO; + case NV50_AUXCH_STAT_REPLY_I2C_DEFER: + udelay(100); + continue; + default: + NV_ERROR(dev, "bad auxch reply: 0x%08x\n", ret); + return -EREMOTEIO; + } + + ptr += cnt; + remaining -= cnt; } + + msg++; } + + return num; +} + +static u32 +nouveau_dp_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } +const struct i2c_algorithm nouveau_dp_i2c_algo = { + .master_xfer = nouveau_dp_i2c_xfer, + .functionality = nouveau_dp_i2c_func +}; diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c index cb0cb34..9df711f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.c +++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c @@ -174,26 +174,26 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index) switch (entry->port_type) { case 0: - i2c->algo.bit.setsda = nv04_i2c_setsda; - i2c->algo.bit.setscl = nv04_i2c_setscl; - i2c->algo.bit.getsda = nv04_i2c_getsda; - i2c->algo.bit.getscl = nv04_i2c_getscl; + i2c->bit.setsda = nv04_i2c_setsda; + i2c->bit.setscl = nv04_i2c_setscl; + i2c->bit.getsda = nv04_i2c_getsda; + i2c->bit.getscl = nv04_i2c_getscl; i2c->rd = entry->read; i2c->wr = entry->write; break; case 4: - i2c->algo.bit.setsda = nv4e_i2c_setsda; - i2c->algo.bit.setscl = nv4e_i2c_setscl; - i2c->algo.bit.getsda = nv4e_i2c_getsda; - i2c->algo.bit.getscl = nv4e_i2c_getscl; + i2c->bit.setsda = nv4e_i2c_setsda; + i2c->bit.setscl = nv4e_i2c_setscl; + i2c->bit.getsda = nv4e_i2c_getsda; + i2c->bit.getscl = nv4e_i2c_getscl; i2c->rd = 0x600800 + entry->read; i2c->wr = 0x600800 + entry->write; break; case 5: - i2c->algo.bit.setsda = nv50_i2c_setsda; - i2c->algo.bit.setscl = nv50_i2c_setscl; - i2c->algo.bit.getsda = nv50_i2c_getsda; - i2c->algo.bit.getscl = nv50_i2c_getscl; + i2c->bit.setsda = nv50_i2c_setsda; + i2c->bit.setscl = nv50_i2c_setscl; + i2c->bit.getsda = nv50_i2c_getsda; + i2c->bit.getscl = nv50_i2c_getscl; i2c->rd = nv50_i2c_port[entry->read]; i2c->wr = i2c->rd; break; @@ -216,17 +216,14 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index) i2c_set_adapdata(&i2c->adapter, i2c); if (entry->port_type < 6) { - i2c->adapter.algo_data = &i2c->algo.bit; - i2c->algo.bit.udelay = 40; - i2c->algo.bit.timeout = usecs_to_jiffies(5000); - i2c->algo.bit.data = i2c; + i2c->adapter.algo_data = &i2c->bit; + i2c->bit.udelay = 40; + i2c->bit.timeout = usecs_to_jiffies(5000); + i2c->bit.data = i2c; ret = i2c_bit_add_bus(&i2c->adapter); } else { - i2c->adapter.algo_data = &i2c->algo.dp; - i2c->algo.dp.running = false; - i2c->algo.dp.address = 0; - i2c->algo.dp.aux_ch = nouveau_dp_i2c_aux_ch; - ret = i2c_dp_aux_add_bus(&i2c->adapter); + i2c->adapter.algo = &nouveau_dp_i2c_algo; + ret = i2c_add_adapter(&i2c->adapter); } if (ret) { diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.h b/drivers/gpu/drm/nouveau/nouveau_i2c.h index 6dd2f87..f71cb32 100644 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.h +++ b/drivers/gpu/drm/nouveau/nouveau_i2c.h @@ -33,10 +33,7 @@ struct dcb_i2c_entry; struct nouveau_i2c_chan { struct i2c_adapter adapter; struct drm_device *dev; - union { - struct i2c_algo_bit_data bit; - struct i2c_algo_dp_aux_data dp; - } algo; + struct i2c_algo_bit_data bit; unsigned rd; unsigned wr; unsigned data; @@ -49,7 +46,6 @@ 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); +extern const struct i2c_algorithm nouveau_dp_i2c_algo; #endif /* __NOUVEAU_I2C_H__ */ -- cgit v0.10.2 From 0d3470d218949dc1307313647c70154c7452a68b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 2 Aug 2010 16:28:19 +1000 Subject: drm/nouveau: remove unused ttm bo list Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 3ca8343..84f8518 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -51,9 +51,6 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo) if (nvbo->tile) nv10_mem_expire_tiling(dev, nvbo->tile, NULL); - spin_lock(&dev_priv->ttm.bo_list_lock); - list_del(&nvbo->head); - spin_unlock(&dev_priv->ttm.bo_list_lock); kfree(nvbo); } @@ -166,9 +163,6 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, } nvbo->channel = NULL; - spin_lock(&dev_priv->ttm.bo_list_lock); - list_add_tail(&nvbo->head, &dev_priv->ttm.bo_list); - spin_unlock(&dev_priv->ttm.bo_list_lock); *pnvbo = nvbo; return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index e15db15..db10809 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -536,8 +536,6 @@ struct drm_nouveau_private { struct drm_global_reference mem_global_ref; struct ttm_bo_global_ref bo_global_ref; struct ttm_bo_device bdev; - spinlock_t bo_list_lock; - struct list_head bo_list; atomic_t validate_sequence; } ttm; diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index a9f36ab..1f80dc6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -459,8 +459,6 @@ nouveau_mem_init(struct drm_device *dev) return ret; } - INIT_LIST_HEAD(&dev_priv->ttm.bo_list); - spin_lock_init(&dev_priv->ttm.bo_list_lock); spin_lock_init(&dev_priv->tile.lock); dev_priv->fb_available_size = dev_priv->vram_size; -- cgit v0.10.2 From 2b495268fc596fd474d2a2cbbc711d8bb1e11e88 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Fri, 30 Jul 2010 13:57:54 +0200 Subject: drm/nouveau: Fix AGP reset when AGP FW is already enabled on init. Previously nouveau_mem_reset_agp() was only disabling AGP fast writes when coming back from suspend. However, the "locked out of the card because of FW" problem can also be reproduced on init if you unload/reload nouveau.ko several times. This patch makes the AGP code reset FW on init. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 1f80dc6..47e5ad9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -351,7 +351,7 @@ nouveau_mem_reset_agp(struct drm_device *dev) /* First of all, disable fast writes, otherwise if it's * already enabled in the AGP bridge and we disable the card's * AGP controller we might be locking ourselves out of it. */ - if (dev->agp->acquired) { + if (nv_rd32(dev, NV04_PBUS_PCI_NV_19) & PCI_AGP_COMMAND_FW) { struct drm_agp_info info; struct drm_agp_mode mode; @@ -359,7 +359,7 @@ nouveau_mem_reset_agp(struct drm_device *dev) if (ret) return ret; - mode.mode = info.mode & ~0x10; + mode.mode = info.mode & ~PCI_AGP_COMMAND_FW; ret = drm_agp_enable(dev, mode); if (ret) return ret; @@ -405,6 +405,8 @@ nouveau_mem_init_agp(struct drm_device *dev) } } + nouveau_mem_reset_agp(dev); + ret = drm_agp_info(dev, &info); if (ret) { NV_ERROR(dev, "Unable to get AGP info: %d\n", ret); @@ -492,7 +494,6 @@ nouveau_mem_init(struct drm_device *dev) /* GART */ #if !defined(__powerpc__) && !defined(__ia64__) if (drm_device_is_agp(dev) && dev->agp && !nouveau_noagp) { - nouveau_mem_reset_agp(dev); ret = nouveau_mem_init_agp(dev); if (ret) NV_ERROR(dev, "Error initialising AGP: %d\n", ret); -- cgit v0.10.2 From a0d069ea2c7b81a453d258c7f60e1f61a3fcbd9f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 30 Jul 2010 17:04:32 +0200 Subject: drm/nouveau: unwind on load errors nouveau_load() just returned directly if there was an error instead of releasing resources. Signed-off-by: Dan Carpenter Reviewed-by: Marcin Slusarz Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index ee3729e..cf16bfb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -739,8 +739,10 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) int ret; dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); - if (!dev_priv) - return -ENOMEM; + if (!dev_priv) { + ret = -ENOMEM; + goto err_out; + } dev->dev_private = dev_priv; dev_priv->dev = dev; @@ -750,8 +752,10 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) dev->pci_vendor, dev->pci_device, dev->pdev->class); dev_priv->wq = create_workqueue("nouveau"); - if (!dev_priv->wq) - return -EINVAL; + if (!dev_priv->wq) { + ret = -EINVAL; + goto err_priv; + } /* resource 0 is mmio regs */ /* resource 1 is linear FB */ @@ -764,7 +768,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) if (!dev_priv->mmio) { NV_ERROR(dev, "Unable to initialize the mmio mapping. " "Please report your setup to " DRIVER_EMAIL "\n"); - return -EINVAL; + ret = -EINVAL; + goto err_wq; } NV_DEBUG(dev, "regs mapped ok at 0x%llx\n", (unsigned long long)mmio_start_offs); @@ -812,7 +817,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) break; default: NV_INFO(dev, "Unsupported chipset 0x%08x\n", reg0); - return -EINVAL; + ret = -EINVAL; + goto err_mmio; } NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n", @@ -820,7 +826,7 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) ret = nouveau_remove_conflicting_drivers(dev); if (ret) - return ret; + goto err_mmio; /* Map PRAMIN BAR, or on older cards, the aperture withing BAR0 */ if (dev_priv->card_type >= NV_40) { @@ -834,7 +840,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) dev_priv->ramin_size); if (!dev_priv->ramin) { NV_ERROR(dev, "Failed to PRAMIN BAR"); - return -ENOMEM; + ret = -ENOMEM; + goto err_mmio; } } else { dev_priv->ramin_size = 1 * 1024 * 1024; @@ -842,7 +849,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) dev_priv->ramin_size); if (!dev_priv->ramin) { NV_ERROR(dev, "Failed to map BAR0 PRAMIN.\n"); - return -ENOMEM; + ret = -ENOMEM; + goto err_mmio; } } @@ -857,9 +865,21 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) /* For kernel modesetting, init card now and bring up fbcon */ ret = nouveau_card_init(dev); if (ret) - return ret; + goto err_ramin; return 0; + +err_ramin: + iounmap(dev_priv->ramin); +err_mmio: + iounmap(dev_priv->mmio); +err_wq: + destroy_workqueue(dev_priv->wq); +err_priv: + kfree(dev_priv); + dev->dev_private = NULL; +err_out: + return ret; } void nouveau_lastclose(struct drm_device *dev) -- cgit v0.10.2 From 0bf9b0e0ce9140c200c0db67a0c71983f07e1a65 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Wed, 4 Aug 2010 05:10:57 +0200 Subject: drm/nouveau: Don't pass misaligned offsets to io_mapping_map_atomic_wc(). Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 7369b5e..6603528 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -2083,9 +2083,10 @@ peek_fb(struct drm_device *dev, struct io_mapping *fb, uint32_t val = 0; if (off < pci_resource_len(dev->pdev, 1)) { - uint32_t __iomem *p = io_mapping_map_atomic_wc(fb, off, KM_USER0); + uint32_t __iomem *p = + io_mapping_map_atomic_wc(fb, off & PAGE_MASK, KM_USER0); - val = ioread32(p); + val = ioread32(p + (off & ~PAGE_MASK)); io_mapping_unmap_atomic(p, KM_USER0); } @@ -2098,9 +2099,10 @@ poke_fb(struct drm_device *dev, struct io_mapping *fb, uint32_t off, uint32_t val) { if (off < pci_resource_len(dev->pdev, 1)) { - uint32_t __iomem *p = io_mapping_map_atomic_wc(fb, off, KM_USER0); + uint32_t __iomem *p = + io_mapping_map_atomic_wc(fb, off & PAGE_MASK, KM_USER0); - iowrite32(val, p); + iowrite32(val, p + (off & ~PAGE_MASK)); wmb(); io_mapping_unmap_atomic(p, KM_USER0); -- cgit v0.10.2 From 3c9b25349e8fd6e29c4e8298dc08fb052f45a18b Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Wed, 4 Aug 2010 05:15:11 +0200 Subject: drm/nouveau: Fix the INIT_CONFIGURE_PREINIT BIOS opcode. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 6603528..c608b0b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -2595,7 +2595,7 @@ init_configure_preinit(struct nvbios *bios, uint16_t offset, /* no iexec->execute check by design */ uint32_t straps = bios_rd32(bios, NV_PEXTDEV_BOOT_0); - uint8_t cr3c = ((straps << 2) & 0xf0) | (straps & (1 << 6)); + uint8_t cr3c = ((straps << 2) & 0xf0) | (straps & 0x40) >> 6; if (bios->major_version > 2) return 0; -- cgit v0.10.2 From 308dcebac7cb9e6dcf8972a178c535b795952931 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Wed, 4 Aug 2010 04:41:55 +0200 Subject: drm/nouveau: Ack the context switch interrupt before switching contexts. Leaving the IRQ unack'ed while switching contexts makes the switch fail randomly on some nv1x. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index 53360f1..0a4a617 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -586,11 +586,11 @@ nouveau_pgraph_irq_handler(struct drm_device *dev) } if (status & NV_PGRAPH_INTR_CONTEXT_SWITCH) { - nouveau_pgraph_intr_context_switch(dev); - status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH); + + nouveau_pgraph_intr_context_switch(dev); } if (status) { -- cgit v0.10.2 From d2f4e89254b5816925a207a221e6b26100357eea Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Wed, 4 Aug 2010 04:54:08 +0200 Subject: drm/nv10: Fix up switching of NV10TCL_DMA_VTXBUF. Not very nice, but I don't think there's a simpler workaround. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h index 9c1056c..21a6e45 100644 --- a/drivers/gpu/drm/nouveau/nouveau_reg.h +++ b/drivers/gpu/drm/nouveau/nouveau_reg.h @@ -220,28 +220,21 @@ # define NV_PGRAPH_INTR_ERROR (1<<20) #define NV10_PGRAPH_CTX_CONTROL 0x00400144 #define NV10_PGRAPH_CTX_USER 0x00400148 -#define NV10_PGRAPH_CTX_SWITCH1 0x0040014C -#define NV10_PGRAPH_CTX_SWITCH2 0x00400150 -#define NV10_PGRAPH_CTX_SWITCH3 0x00400154 -#define NV10_PGRAPH_CTX_SWITCH4 0x00400158 -#define NV10_PGRAPH_CTX_SWITCH5 0x0040015C +#define NV10_PGRAPH_CTX_SWITCH(i) (0x0040014C + 0x4*(i)) #define NV04_PGRAPH_CTX_SWITCH1 0x00400160 -#define NV10_PGRAPH_CTX_CACHE1 0x00400160 +#define NV10_PGRAPH_CTX_CACHE(i, j) (0x00400160 \ + + 0x4*(i) + 0x20*(j)) #define NV04_PGRAPH_CTX_SWITCH2 0x00400164 #define NV04_PGRAPH_CTX_SWITCH3 0x00400168 #define NV04_PGRAPH_CTX_SWITCH4 0x0040016C #define NV04_PGRAPH_CTX_CONTROL 0x00400170 #define NV04_PGRAPH_CTX_USER 0x00400174 #define NV04_PGRAPH_CTX_CACHE1 0x00400180 -#define NV10_PGRAPH_CTX_CACHE2 0x00400180 #define NV03_PGRAPH_CTX_CONTROL 0x00400190 #define NV03_PGRAPH_CTX_USER 0x00400194 #define NV04_PGRAPH_CTX_CACHE2 0x004001A0 -#define NV10_PGRAPH_CTX_CACHE3 0x004001A0 #define NV04_PGRAPH_CTX_CACHE3 0x004001C0 -#define NV10_PGRAPH_CTX_CACHE4 0x004001C0 #define NV04_PGRAPH_CTX_CACHE4 0x004001E0 -#define NV10_PGRAPH_CTX_CACHE5 0x004001E0 #define NV40_PGRAPH_CTXCTL_0304 0x00400304 #define NV40_PGRAPH_CTXCTL_0304_XFER_CTX 0x00000001 #define NV40_PGRAPH_CTXCTL_UCODE_STAT 0x00400308 @@ -356,9 +349,12 @@ #define NV04_PGRAPH_FFINTFC_ST2 0x00400754 #define NV10_PGRAPH_RDI_DATA 0x00400754 #define NV04_PGRAPH_DMA_PITCH 0x00400760 -#define NV10_PGRAPH_FFINTFC_ST2 0x00400764 +#define NV10_PGRAPH_FFINTFC_FIFO_PTR 0x00400760 #define NV04_PGRAPH_DVD_COLORFMT 0x00400764 +#define NV10_PGRAPH_FFINTFC_ST2 0x00400764 #define NV04_PGRAPH_SCALED_FORMAT 0x00400768 +#define NV10_PGRAPH_FFINTFC_ST2_DL 0x00400768 +#define NV10_PGRAPH_FFINTFC_ST2_DH 0x0040076c #define NV10_PGRAPH_DMA_PITCH 0x00400770 #define NV10_PGRAPH_DVD_COLORFMT 0x00400774 #define NV10_PGRAPH_SCALED_FORMAT 0x00400778 diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c index fcf2cdd..b2f6a57 100644 --- a/drivers/gpu/drm/nouveau/nv10_graph.c +++ b/drivers/gpu/drm/nouveau/nv10_graph.c @@ -43,51 +43,51 @@ struct pipe_state { }; static int nv10_graph_ctx_regs[] = { - NV10_PGRAPH_CTX_SWITCH1, - NV10_PGRAPH_CTX_SWITCH2, - NV10_PGRAPH_CTX_SWITCH3, - NV10_PGRAPH_CTX_SWITCH4, - NV10_PGRAPH_CTX_SWITCH5, - NV10_PGRAPH_CTX_CACHE1, /* 8 values from 0x400160 to 0x40017c */ - NV10_PGRAPH_CTX_CACHE2, /* 8 values from 0x400180 to 0x40019c */ - NV10_PGRAPH_CTX_CACHE3, /* 8 values from 0x4001a0 to 0x4001bc */ - NV10_PGRAPH_CTX_CACHE4, /* 8 values from 0x4001c0 to 0x4001dc */ - NV10_PGRAPH_CTX_CACHE5, /* 8 values from 0x4001e0 to 0x4001fc */ - 0x00400164, - 0x00400184, - 0x004001a4, - 0x004001c4, - 0x004001e4, - 0x00400168, - 0x00400188, - 0x004001a8, - 0x004001c8, - 0x004001e8, - 0x0040016c, - 0x0040018c, - 0x004001ac, - 0x004001cc, - 0x004001ec, - 0x00400170, - 0x00400190, - 0x004001b0, - 0x004001d0, - 0x004001f0, - 0x00400174, - 0x00400194, - 0x004001b4, - 0x004001d4, - 0x004001f4, - 0x00400178, - 0x00400198, - 0x004001b8, - 0x004001d8, - 0x004001f8, - 0x0040017c, - 0x0040019c, - 0x004001bc, - 0x004001dc, - 0x004001fc, + NV10_PGRAPH_CTX_SWITCH(0), + NV10_PGRAPH_CTX_SWITCH(1), + NV10_PGRAPH_CTX_SWITCH(2), + NV10_PGRAPH_CTX_SWITCH(3), + NV10_PGRAPH_CTX_SWITCH(4), + NV10_PGRAPH_CTX_CACHE(0, 0), + NV10_PGRAPH_CTX_CACHE(0, 1), + NV10_PGRAPH_CTX_CACHE(0, 2), + NV10_PGRAPH_CTX_CACHE(0, 3), + NV10_PGRAPH_CTX_CACHE(0, 4), + NV10_PGRAPH_CTX_CACHE(1, 0), + NV10_PGRAPH_CTX_CACHE(1, 1), + NV10_PGRAPH_CTX_CACHE(1, 2), + NV10_PGRAPH_CTX_CACHE(1, 3), + NV10_PGRAPH_CTX_CACHE(1, 4), + NV10_PGRAPH_CTX_CACHE(2, 0), + NV10_PGRAPH_CTX_CACHE(2, 1), + NV10_PGRAPH_CTX_CACHE(2, 2), + NV10_PGRAPH_CTX_CACHE(2, 3), + NV10_PGRAPH_CTX_CACHE(2, 4), + NV10_PGRAPH_CTX_CACHE(3, 0), + NV10_PGRAPH_CTX_CACHE(3, 1), + NV10_PGRAPH_CTX_CACHE(3, 2), + NV10_PGRAPH_CTX_CACHE(3, 3), + NV10_PGRAPH_CTX_CACHE(3, 4), + NV10_PGRAPH_CTX_CACHE(4, 0), + NV10_PGRAPH_CTX_CACHE(4, 1), + NV10_PGRAPH_CTX_CACHE(4, 2), + NV10_PGRAPH_CTX_CACHE(4, 3), + NV10_PGRAPH_CTX_CACHE(4, 4), + NV10_PGRAPH_CTX_CACHE(5, 0), + NV10_PGRAPH_CTX_CACHE(5, 1), + NV10_PGRAPH_CTX_CACHE(5, 2), + NV10_PGRAPH_CTX_CACHE(5, 3), + NV10_PGRAPH_CTX_CACHE(5, 4), + NV10_PGRAPH_CTX_CACHE(6, 0), + NV10_PGRAPH_CTX_CACHE(6, 1), + NV10_PGRAPH_CTX_CACHE(6, 2), + NV10_PGRAPH_CTX_CACHE(6, 3), + NV10_PGRAPH_CTX_CACHE(6, 4), + NV10_PGRAPH_CTX_CACHE(7, 0), + NV10_PGRAPH_CTX_CACHE(7, 1), + NV10_PGRAPH_CTX_CACHE(7, 2), + NV10_PGRAPH_CTX_CACHE(7, 3), + NV10_PGRAPH_CTX_CACHE(7, 4), NV10_PGRAPH_CTX_USER, NV04_PGRAPH_DMA_START_0, NV04_PGRAPH_DMA_START_1, @@ -653,6 +653,78 @@ static int nv17_graph_ctx_regs_find_offset(struct drm_device *dev, int reg) return -1; } +static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan, + uint32_t inst) +{ + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + uint32_t st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4]; + uint32_t ctx_user, ctx_switch[5]; + int i, subchan = -1; + + /* NV10TCL_DMA_VTXBUF (method 0x18c) modifies hidden state + * that cannot be restored via MMIO. Do it through the FIFO + * instead. + */ + + /* Look for a celsius object */ + for (i = 0; i < 8; i++) { + int class = nv_rd32(dev, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff; + + if (class == 0x56 || class == 0x96 || class == 0x99) { + subchan = i; + break; + } + } + + if (subchan < 0 || !inst) + return; + + /* Save the current ctx object */ + ctx_user = nv_rd32(dev, NV10_PGRAPH_CTX_USER); + for (i = 0; i < 5; i++) + ctx_switch[i] = nv_rd32(dev, NV10_PGRAPH_CTX_SWITCH(i)); + + /* Save the FIFO state */ + st2 = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2); + st2_dl = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2_DL); + st2_dh = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2_DH); + fifo_ptr = nv_rd32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR); + + for (i = 0; i < ARRAY_SIZE(fifo); i++) + fifo[i] = nv_rd32(dev, 0x4007a0 + 4 * i); + + /* Switch to the celsius subchannel */ + for (i = 0; i < 5; i++) + nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(i), + nv_rd32(dev, NV10_PGRAPH_CTX_CACHE(subchan, i))); + nv_mask(dev, NV10_PGRAPH_CTX_USER, 0xe000, subchan << 13); + + /* Inject NV10TCL_DMA_VTXBUF */ + nv_wr32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR, 0); + nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2, + 0x2c000000 | chan->id << 20 | subchan << 16 | 0x18c); + nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, inst); + nv_mask(dev, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000); + pgraph->fifo_access(dev, true); + pgraph->fifo_access(dev, false); + + /* Restore the FIFO state */ + for (i = 0; i < ARRAY_SIZE(fifo); i++) + nv_wr32(dev, 0x4007a0 + 4 * i, fifo[i]); + + nv_wr32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR, fifo_ptr); + nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2, st2); + nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, st2_dl); + nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DH, st2_dh); + + /* Restore the current ctx object */ + for (i = 0; i < 5; i++) + nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(i), ctx_switch[i]); + nv_wr32(dev, NV10_PGRAPH_CTX_USER, ctx_user); +} + int nv10_graph_load_context(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; @@ -670,6 +742,8 @@ int nv10_graph_load_context(struct nouveau_channel *chan) } nv10_graph_load_pipe(chan); + nv10_graph_load_dma_vtxbuf(chan, (nv_rd32(dev, NV10_PGRAPH_GLOBALSTATE1) + & 0xffff)); nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10010100); tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER); @@ -856,11 +930,12 @@ int nv10_graph_init(struct drm_device *dev) for (i = 0; i < NV10_PFB_TILE__SIZE; i++) nv10_graph_set_region_tiling(dev, i, 0, 0, 0); - nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH1, 0x00000000); - nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH2, 0x00000000); - nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH3, 0x00000000); - nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH4, 0x00000000); - nv_wr32(dev, NV10_PGRAPH_STATE , 0xFFFFFFFF); + nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000); + nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000); + nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000); + nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(3), 0x00000000); + nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(4), 0x00000000); + nv_wr32(dev, NV10_PGRAPH_STATE, 0xFFFFFFFF); tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff; tmp |= (dev_priv->engine.fifo.channels - 1) << 24; -- cgit v0.10.2 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 diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index c608b0b..e86f46c 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 024458a..fd14dfd 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 734e926..b1b22ba 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 db10809..9e17d88 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 a1a0d48..7c82d68 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 7855b35..7b61368 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 1c20c08..08c7e07 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 3311f3a..9871570 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 94e299c..4e73c44 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 v0.10.2 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 diff --git a/drivers/gpu/drm/nouveau/nv04_tv.c b/drivers/gpu/drm/nouveau/nv04_tv.c index 4e73c44..0b5d012 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 v0.10.2 From 2d14e35c950b00bddeba770278f2fe4dfd4355b2 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sun, 25 Jul 2010 19:13:43 +0200 Subject: drm/nv30: Workaround dual TMDS brain damage. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c index 9871570..a5dcf768 100644 --- a/drivers/gpu/drm/nouveau/nv04_dfp.c +++ b/drivers/gpu/drm/nouveau/nv04_dfp.c @@ -146,6 +146,36 @@ void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode) } } +static struct drm_encoder *get_tmds_slave(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; + struct drm_encoder *slave; + + if (dcb->type != OUTPUT_TMDS || dcb->location == DCB_LOC_ON_CHIP) + return NULL; + + /* Some BIOSes (e.g. the one in a Quadro FX1000) report several + * TMDS transmitters at the same I2C address, in the same I2C + * bus. This can still work because in that case one of them is + * always hard-wired to a reasonable configuration using straps, + * and the other one needs to be programmed. + * + * I don't think there's a way to know which is which, even the + * blob programs the one exposed via I2C for *both* heads, so + * let's do the same. + */ + list_for_each_entry(slave, &dev->mode_config.encoder_list, head) { + struct dcb_entry *slave_dcb = nouveau_encoder(slave)->dcb; + + if (slave_dcb->type == OUTPUT_TMDS && get_slave_funcs(slave) && + slave_dcb->tmdsconf.slave_addr == dcb->tmdsconf.slave_addr) + return slave; + } + + return NULL; +} + static bool nv04_dfp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -432,9 +462,9 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) 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); + if (get_tmds_slave(encoder)) + get_slave_funcs(get_tmds_slave(encoder))->mode_set( + encoder, &nv_encoder->mode, &nv_encoder->mode); helper->dpms(encoder, DRM_MODE_DPMS_ON); @@ -581,7 +611,8 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder) }; int type; - if (!nv_gf4_disp_arch(dev) || !i2c) + if (!nv_gf4_disp_arch(dev) || !i2c || + get_tmds_slave(encoder)) return; type = nouveau_i2c_identify(dev, "TMDS transmitter", info, 2); -- cgit v0.10.2 From 4b223eefe43d201c323d120a01dbd0dcbba64e6d Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 3 Aug 2010 10:00:56 +1000 Subject: drm/nvc0: starting point for GF100 support, everything stubbed Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index 2405d5e..e9b06e4 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -12,12 +12,12 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ nouveau_dp.o \ nv04_timer.o \ nv04_mc.o nv40_mc.o nv50_mc.o \ - nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o \ - nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \ + nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o nvc0_fb.o \ + nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o nvc0_fifo.o \ nv04_graph.o nv10_graph.o nv20_graph.o \ - nv40_graph.o nv50_graph.o \ + nv40_graph.o nv50_graph.o nvc0_graph.o \ nv40_grctx.o nv50_grctx.o \ - nv04_instmem.o nv50_instmem.o \ + nv04_instmem.o nv50_instmem.o nvc0_instmem.o \ nv50_crtc.o nv50_dac.o nv50_sor.o \ nv50_cursor.o nv50_display.o nv50_fbcon.o \ nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \ diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 9e17d88..e424bf7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -509,6 +509,7 @@ enum nouveau_card_type { NV_30 = 0x30, NV_40 = 0x40, NV_50 = 0x50, + NV_C0 = 0xc0, }; struct drm_nouveau_private { @@ -929,6 +930,10 @@ extern void nv40_fb_set_region_tiling(struct drm_device *, int, uint32_t, extern int nv50_fb_init(struct drm_device *); extern void nv50_fb_takedown(struct drm_device *); +/* nvc0_fb.c */ +extern int nvc0_fb_init(struct drm_device *); +extern void nvc0_fb_takedown(struct drm_device *); + /* nv04_fifo.c */ extern int nv04_fifo_init(struct drm_device *); extern void nv04_fifo_disable(struct drm_device *); @@ -966,6 +971,20 @@ extern void nv50_fifo_destroy_context(struct nouveau_channel *); extern int nv50_fifo_load_context(struct nouveau_channel *); extern int nv50_fifo_unload_context(struct drm_device *); +/* nvc0_fifo.c */ +extern int nvc0_fifo_init(struct drm_device *); +extern void nvc0_fifo_takedown(struct drm_device *); +extern void nvc0_fifo_disable(struct drm_device *); +extern void nvc0_fifo_enable(struct drm_device *); +extern bool nvc0_fifo_reassign(struct drm_device *, bool); +extern bool nvc0_fifo_cache_flush(struct drm_device *); +extern bool nvc0_fifo_cache_pull(struct drm_device *, bool); +extern int nvc0_fifo_channel_id(struct drm_device *); +extern int nvc0_fifo_create_context(struct nouveau_channel *); +extern void nvc0_fifo_destroy_context(struct nouveau_channel *); +extern int nvc0_fifo_load_context(struct nouveau_channel *); +extern int nvc0_fifo_unload_context(struct drm_device *); + /* nv04_graph.c */ extern struct nouveau_pgraph_object_class nv04_graph_grclass[]; extern int nv04_graph_init(struct drm_device *); @@ -1030,6 +1049,16 @@ extern int nv50_graph_unload_context(struct drm_device *); extern void nv50_graph_context_switch(struct drm_device *); extern int nv50_grctx_init(struct nouveau_grctx *); +/* nvc0_graph.c */ +extern int nvc0_graph_init(struct drm_device *); +extern void nvc0_graph_takedown(struct drm_device *); +extern void nvc0_graph_fifo_access(struct drm_device *, bool); +extern struct nouveau_channel *nvc0_graph_channel(struct drm_device *); +extern int nvc0_graph_create_context(struct nouveau_channel *); +extern void nvc0_graph_destroy_context(struct nouveau_channel *); +extern int nvc0_graph_load_context(struct nouveau_channel *); +extern int nvc0_graph_unload_context(struct drm_device *); + /* nv04_instmem.c */ extern int nv04_instmem_init(struct drm_device *); extern void nv04_instmem_takedown(struct drm_device *); @@ -1056,6 +1085,18 @@ extern void nv50_instmem_flush(struct drm_device *); extern void nv84_instmem_flush(struct drm_device *); extern void nv50_vm_flush(struct drm_device *, int engine); +/* nvc0_instmem.c */ +extern int nvc0_instmem_init(struct drm_device *); +extern void nvc0_instmem_takedown(struct drm_device *); +extern int nvc0_instmem_suspend(struct drm_device *); +extern void nvc0_instmem_resume(struct drm_device *); +extern int nvc0_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, + uint32_t *size); +extern void nvc0_instmem_clear(struct drm_device *, struct nouveau_gpuobj *); +extern int nvc0_instmem_bind(struct drm_device *, struct nouveau_gpuobj *); +extern int nvc0_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *); +extern void nvc0_instmem_flush(struct drm_device *); + /* nv04_mc.c */ extern int nv04_mc_init(struct drm_device *); extern void nv04_mc_takedown(struct drm_device *); diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 2fb2444..11f13fc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -280,6 +280,8 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, if (dev_priv->channel && !nouveau_nofbaccel) { switch (dev_priv->card_type) { + case NV_C0: + break; case NV_50: nv50_fbcon_accel_init(info); info->fbops = &nv50_fbcon_ops; diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c index 9df711f..0bd407c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.c +++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c @@ -163,7 +163,7 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index) if (entry->chan) return -EEXIST; - if (dev_priv->card_type == NV_50 && entry->read >= NV50_I2C_PORTS) { + if (dev_priv->card_type == NV_C0 && entry->read >= NV50_I2C_PORTS) { NV_ERROR(dev, "unknown i2c port %d\n", entry->read); return -EINVAL; } diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index 0a4a617..794b0ee 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -49,7 +49,7 @@ nouveau_irq_preinstall(struct drm_device *dev) /* Master disable */ nv_wr32(dev, NV03_PMC_INTR_EN_0, 0); - if (dev_priv->card_type == NV_50) { + if (dev_priv->card_type >= NV_50) { INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh); INIT_WORK(&dev_priv->hpd_work, nv50_display_irq_hotplug_bh); INIT_LIST_HEAD(&dev_priv->vbl_waiting); diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index cf16bfb..989322b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -359,6 +359,54 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->gpio.set = nv50_gpio_set; engine->gpio.irq_enable = nv50_gpio_irq_enable; break; + case 0xC0: + engine->instmem.init = nvc0_instmem_init; + engine->instmem.takedown = nvc0_instmem_takedown; + engine->instmem.suspend = nvc0_instmem_suspend; + engine->instmem.resume = nvc0_instmem_resume; + engine->instmem.populate = nvc0_instmem_populate; + engine->instmem.clear = nvc0_instmem_clear; + engine->instmem.bind = nvc0_instmem_bind; + engine->instmem.unbind = nvc0_instmem_unbind; + engine->instmem.flush = nvc0_instmem_flush; + engine->mc.init = nv50_mc_init; + engine->mc.takedown = nv50_mc_takedown; + engine->timer.init = nv04_timer_init; + engine->timer.read = nv04_timer_read; + engine->timer.takedown = nv04_timer_takedown; + engine->fb.init = nvc0_fb_init; + engine->fb.takedown = nvc0_fb_takedown; + engine->graph.grclass = NULL; //nvc0_graph_grclass; + engine->graph.init = nvc0_graph_init; + engine->graph.takedown = nvc0_graph_takedown; + engine->graph.fifo_access = nvc0_graph_fifo_access; + engine->graph.channel = nvc0_graph_channel; + engine->graph.create_context = nvc0_graph_create_context; + engine->graph.destroy_context = nvc0_graph_destroy_context; + engine->graph.load_context = nvc0_graph_load_context; + engine->graph.unload_context = nvc0_graph_unload_context; + engine->fifo.channels = 128; + engine->fifo.init = nvc0_fifo_init; + engine->fifo.takedown = nvc0_fifo_takedown; + engine->fifo.disable = nvc0_fifo_disable; + engine->fifo.enable = nvc0_fifo_enable; + engine->fifo.reassign = nvc0_fifo_reassign; + engine->fifo.channel_id = nvc0_fifo_channel_id; + engine->fifo.create_context = nvc0_fifo_create_context; + engine->fifo.destroy_context = nvc0_fifo_destroy_context; + engine->fifo.load_context = nvc0_fifo_load_context; + engine->fifo.unload_context = nvc0_fifo_unload_context; + engine->display.early_init = nv50_display_early_init; + engine->display.late_takedown = nv50_display_late_takedown; + engine->display.create = nv50_display_create; + engine->display.init = nv50_display_init; + engine->display.destroy = nv50_display_destroy; + engine->gpio.init = nv50_gpio_init; + engine->gpio.takedown = nouveau_stub_takedown; + engine->gpio.get = nv50_gpio_get; + engine->gpio.set = nv50_gpio_set; + engine->gpio.irq_enable = nv50_gpio_irq_enable; + break; default: NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset); return 1; @@ -815,6 +863,9 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) case 0xa0: dev_priv->card_type = NV_50; break; + case 0xc0: + dev_priv->card_type = NV_C0; + break; default: NV_INFO(dev, "Unsupported chipset 0x%08x\n", reg0); ret = -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvc0_fb.c b/drivers/gpu/drm/nouveau/nvc0_fb.c new file mode 100644 index 0000000..26a9960 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvc0_fb.c @@ -0,0 +1,38 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "drmP.h" + +#include "nouveau_drv.h" + +int +nvc0_fb_init(struct drm_device *dev) +{ + return 0; +} + +void +nvc0_fb_takedown(struct drm_device *dev) +{ +} diff --git a/drivers/gpu/drm/nouveau/nvc0_fifo.c b/drivers/gpu/drm/nouveau/nvc0_fifo.c new file mode 100644 index 0000000..d643758 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvc0_fifo.c @@ -0,0 +1,96 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "drmP.h" + +#include "nouveau_drv.h" + +void +nvc0_fifo_disable(struct drm_device *dev) +{ +} + +void +nvc0_fifo_enable(struct drm_device *dev) +{ +} + +bool +nvc0_fifo_reassign(struct drm_device *dev, bool enable) +{ + return false; +} + +bool +nvc0_fifo_cache_flush(struct drm_device *dev) +{ + return true; +} + +bool +nvc0_fifo_cache_pull(struct drm_device *dev, bool enable) +{ + return false; +} + +int +nvc0_fifo_channel_id(struct drm_device *dev) +{ + return 127; +} + +int +nvc0_fifo_create_context(struct nouveau_channel *chan) +{ + return 0; +} + +void +nvc0_fifo_destroy_context(struct nouveau_channel *chan) +{ +} + +int +nvc0_fifo_load_context(struct nouveau_channel *chan) +{ + return 0; +} + +int +nvc0_fifo_unload_context(struct drm_device *dev) +{ + return 0; +} + +void +nvc0_fifo_takedown(struct drm_device *dev) +{ +} + +int +nvc0_fifo_init(struct drm_device *dev) +{ + return 0; +} + diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c new file mode 100644 index 0000000..717a517 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvc0_graph.c @@ -0,0 +1,75 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "drmP.h" + +#include "nouveau_drv.h" + +void +nvc0_graph_fifo_access(struct drm_device *dev, bool enabled) +{ +} + +struct nouveau_channel * +nvc0_graph_channel(struct drm_device *dev) +{ + return NULL; +} + +int +nvc0_graph_create_context(struct nouveau_channel *chan) +{ + return 0; +} + +void +nvc0_graph_destroy_context(struct nouveau_channel *chan) +{ +} + +int +nvc0_graph_load_context(struct nouveau_channel *chan) +{ + return 0; +} + +int +nvc0_graph_unload_context(struct drm_device *dev) +{ + return 0; +} + +void +nvc0_graph_takedown(struct drm_device *dev) +{ +} + +int +nvc0_graph_init(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + dev_priv->engine.graph.accel_blocked = true; + return 0; +} + diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c new file mode 100644 index 0000000..c6ffc16 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvc0_instmem.c @@ -0,0 +1,79 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "drmP.h" + +#include "nouveau_drv.h" + +int +nvc0_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, + uint32_t *size) +{ + return 0; +} + +void +nvc0_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) +{ +} + +int +nvc0_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) +{ + return 0; +} + +int +nvc0_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) +{ + return 0; +} + +void +nvc0_instmem_flush(struct drm_device *dev) +{ +} + +int +nvc0_instmem_suspend(struct drm_device *dev) +{ + return 0; +} + +void +nvc0_instmem_resume(struct drm_device *dev) +{ +} + +int +nvc0_instmem_init(struct drm_device *dev) +{ + return 0; +} + +void +nvc0_instmem_takedown(struct drm_device *dev) +{ +} + -- cgit v0.10.2 From 080feda59c6133ad5edcfa06e8e3d775dd0240a2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 4 Aug 2010 13:40:50 +1000 Subject: drm/nvc0: allow INIT_GPIO Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index e86f46c..274e9b6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -3142,7 +3142,7 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c }; int i; - if (dev_priv->card_type != NV_50) { + if (dev_priv->card_type < NV_50) { NV_ERROR(bios->dev, "INIT_GPIO on unsupported chipset\n"); return 1; } -- cgit v0.10.2 From c556d989038a6eba1411acf39163eb660e0a13bc Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 4 Aug 2010 13:44:41 +1000 Subject: drm/nvc0: implement memory detection Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 47e5ad9..9689d414 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -320,7 +320,8 @@ nouveau_mem_detect(struct drm_device *dev) if (dev_priv->card_type < NV_50) { dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA); dev_priv->vram_size &= NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK; - } else { + } else + if (dev_priv->card_type < NV_C0) { dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA); dev_priv->vram_size |= (dev_priv->vram_size & 0xff) << 32; dev_priv->vram_size &= 0xffffffff00ll; @@ -328,6 +329,9 @@ nouveau_mem_detect(struct drm_device *dev) dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10); dev_priv->vram_sys_base <<= 12; } + } else { + dev_priv->vram_size = nv_rd32(dev, 0x10f20c) << 20; + dev_priv->vram_size *= nv_rd32(dev, 0x121c74); } NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20)); -- cgit v0.10.2 From 68b83a939cf8ed5466d11b7e9bfaa1dd22c11469 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 4 Aug 2010 15:45:33 +1000 Subject: drm/nvc0: rudimentary instmem support Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c index c6ffc16..e2a0bb8 100644 --- a/drivers/gpu/drm/nouveau/nvc0_instmem.c +++ b/drivers/gpu/drm/nouveau/nvc0_instmem.c @@ -30,29 +30,112 @@ int nvc0_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, uint32_t *size) { + int ret; + + *size = ALIGN(*size, 4096); + if (*size == 0) + return -EINVAL; + + ret = nouveau_bo_new(dev, NULL, *size, 0, TTM_PL_FLAG_VRAM, 0, 0x0000, + true, false, &gpuobj->im_backing); + if (ret) { + NV_ERROR(dev, "error getting PRAMIN backing pages: %d\n", ret); + return ret; + } + + ret = nouveau_bo_pin(gpuobj->im_backing, TTM_PL_FLAG_VRAM); + if (ret) { + NV_ERROR(dev, "error pinning PRAMIN backing VRAM: %d\n", ret); + nouveau_bo_ref(NULL, &gpuobj->im_backing); + return ret; + } + + gpuobj->im_backing_start = gpuobj->im_backing->bo.mem.mm_node->start; + gpuobj->im_backing_start <<= PAGE_SHIFT; return 0; } void nvc0_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) { + struct drm_nouveau_private *dev_priv = dev->dev_private; + + if (gpuobj && gpuobj->im_backing) { + if (gpuobj->im_bound) + dev_priv->engine.instmem.unbind(dev, gpuobj); + nouveau_bo_unpin(gpuobj->im_backing); + nouveau_bo_ref(NULL, &gpuobj->im_backing); + gpuobj->im_backing = NULL; + } } int nvc0_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) { + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t pte, pte_end; + uint64_t vram; + + if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound) + return -EINVAL; + + NV_DEBUG(dev, "st=0x%lx sz=0x%lx\n", + gpuobj->im_pramin->start, gpuobj->im_pramin->size); + + pte = gpuobj->im_pramin->start >> 12; + pte_end = (gpuobj->im_pramin->size >> 12) + pte; + vram = gpuobj->im_backing_start; + + NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n", + gpuobj->im_pramin->start, pte, pte_end); + NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start); + + while (pte < pte_end) { + nv_wr32(dev, 0x702000 + (pte * 8), (vram >> 8) | 1); + nv_wr32(dev, 0x702004 + (pte * 8), 0); + vram += 4096; + pte++; + } + dev_priv->engine.instmem.flush(dev); + + if (1) { + u32 chan = nv_rd32(dev, 0x1700) << 16; + nv_wr32(dev, 0x100cb8, (chan + 0x1000) >> 8); + nv_wr32(dev, 0x100cbc, 0x80000005); + } + + gpuobj->im_bound = 1; return 0; } int nvc0_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) { + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t pte, pte_end; + + if (gpuobj->im_bound == 0) + return -EINVAL; + + pte = gpuobj->im_pramin->start >> 12; + pte_end = (gpuobj->im_pramin->size >> 12) + pte; + while (pte < pte_end) { + nv_wr32(dev, 0x702000 + (pte * 8), 0); + nv_wr32(dev, 0x702004 + (pte * 8), 0); + pte++; + } + dev_priv->engine.instmem.flush(dev); + + gpuobj->im_bound = 0; return 0; } void nvc0_instmem_flush(struct drm_device *dev) { + nv_wr32(dev, 0x070000, 1); + if (!nv_wait(0x070000, 0x00000001, 0x00000000)) + NV_ERROR(dev, "PRAMIN flush timeout\n"); } int @@ -69,6 +152,54 @@ nvc0_instmem_resume(struct drm_device *dev) int nvc0_instmem_init(struct drm_device *dev) { + struct drm_nouveau_private *dev_priv = dev->dev_private; + u64 chan, pgt3, imem, lim3 = dev_priv->ramin_size - 1; + int ret, i; + + dev_priv->ramin_rsvd_vram = 1 * 1024 * 1024; + chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram; + imem = 4096 + 4096 + 32768; + + nv_wr32(dev, 0x001700, chan >> 16); + + /* channel setup */ + nv_wr32(dev, 0x700200, lower_32_bits(chan + 0x1000)); + nv_wr32(dev, 0x700204, upper_32_bits(chan + 0x1000)); + nv_wr32(dev, 0x700208, lower_32_bits(lim3)); + nv_wr32(dev, 0x70020c, upper_32_bits(lim3)); + + /* point pgd -> pgt */ + nv_wr32(dev, 0x701000, 0); + nv_wr32(dev, 0x701004, ((chan + 0x2000) >> 8) | 1); + + /* point pgt -> physical vram for channel */ + pgt3 = 0x2000; + for (i = 0; i < dev_priv->ramin_rsvd_vram; i += 4096, pgt3 += 8) { + nv_wr32(dev, 0x700000 + pgt3, ((chan + i) >> 8) | 1); + nv_wr32(dev, 0x700004 + pgt3, 0); + } + + /* clear rest of pgt */ + for (; i < dev_priv->ramin_size; i += 4096, pgt3 += 8) { + nv_wr32(dev, 0x700000 + pgt3, 0); + nv_wr32(dev, 0x700004 + pgt3, 0); + } + + /* point bar3 at the channel */ + nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12)); + + /* Global PRAMIN heap */ + ret = drm_mm_init(&dev_priv->ramin_heap, imem, + dev_priv->ramin_size - imem); + if (ret) { + NV_ERROR(dev, "Failed to init RAMIN heap\n"); + return -ENOMEM; + } + + /*XXX: incorrect, but needed to make hash func "work" */ + dev_priv->ramht_offset = 0x10000; + dev_priv->ramht_bits = 9; + dev_priv->ramht_size = (1 << dev_priv->ramht_bits); return 0; } -- cgit v0.10.2 From 0165d15dba2cec6ae2e6eb9c4eb6f2a5b38d4944 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 4 Aug 2010 17:24:57 +1000 Subject: drm/nvc0: fix evo dma object so we display something Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index f13ad0d..612fa6d 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -76,7 +76,10 @@ nv50_evo_dmaobj_new(struct nouveau_channel *evo, uint32_t class, uint32_t name, nv_wo32(dev, obj, 2, offset); nv_wo32(dev, obj, 3, 0x00000000); nv_wo32(dev, obj, 4, 0x00000000); - nv_wo32(dev, obj, 5, 0x00010000); + if (dev_priv->card_type < NV_C0) + nv_wo32(dev, obj, 5, 0x00010000); + else + nv_wo32(dev, obj, 5, 0x00020000); dev_priv->engine.instmem.flush(dev); return 0; -- cgit v0.10.2 From 1ac7b528a0e924308cfedea5d71b78c31c23b851 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 4 Aug 2010 22:08:03 +1000 Subject: drm/nvc0: implement crtc pll setting Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 274e9b6..e0997d6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -4828,7 +4828,7 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims pll_lim->min_p = record[12]; pll_lim->max_p = record[13]; /* where did this go to?? */ - if (limit_match == 0x00614100 || limit_match == 0x00614900) + if ((entry[0] & 0xf0) == 0x80) pll_lim->refclk = 27000; else pll_lim->refclk = 100000; diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c index 5d11ea1..a438e56 100644 --- a/drivers/gpu/drm/nouveau/nv50_crtc.c +++ b/drivers/gpu/drm/nouveau/nv50_crtc.c @@ -264,11 +264,16 @@ nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, int scaling_mode, bool update) int nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk) { - uint32_t reg = NV50_PDISPLAY_CRTC_CLK_CTRL1(head); + struct drm_nouveau_private *dev_priv = dev->dev_private; struct pll_lims pll; - uint32_t reg1, reg2; + uint32_t reg, reg1, reg2; int ret, N1, M1, N2, M2, P; + if (dev_priv->chipset < NV_C0) + reg = NV50_PDISPLAY_CRTC_CLK_CTRL1(head); + else + reg = 0x614140 + (head * 0x800); + ret = get_pll_limits(dev, reg, &pll); if (ret) return ret; @@ -286,7 +291,8 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk) nv_wr32(dev, reg, 0x10000611); nv_wr32(dev, reg + 4, reg1 | (M1 << 16) | N1); nv_wr32(dev, reg + 8, reg2 | (P << 28) | (M2 << 16) | N2); - } else { + } else + if (dev_priv->chipset < NV_C0) { ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P); if (ret <= 0) return 0; @@ -298,6 +304,17 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk) nv_wr32(dev, reg, 0x50000610); nv_wr32(dev, reg + 4, reg1 | (P << 16) | (M1 << 8) | N1); nv_wr32(dev, reg + 8, N2); + } else { + ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P); + if (ret <= 0) + return 0; + + NV_DEBUG(dev, "pclk %d out %d N %d fN 0x%04x M %d P %d\n", + pclk, ret, N1, N2, M1, P); + + nv_mask(dev, reg + 0x0c, 0x00000000, 0x00000100); + nv_wr32(dev, reg + 0x04, (P << 16) | (N1 << 8) | M1); + nv_wr32(dev, reg + 0x10, N2 << 16); } return 0; -- cgit v0.10.2 From e3a1924f3e5aeabdb1a1ae1a87b4097e48b7f2c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= Date: Fri, 2 Jul 2010 19:33:01 +0000 Subject: drm/nouveau: implement init table op 0x57, INIT_LTIME MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ben Skeggs Signed-off-by: Marcin Koƛcielnicki diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index e0997d6..6dd00ff 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -1928,6 +1928,31 @@ init_condition_time(struct nvbios *bios, uint16_t offset, } static int +init_ltime(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) +{ + /* + * INIT_LTIME opcode: 0x57 ('V') + * + * offset (8 bit): opcode + * offset + 1 (16 bit): time + * + * Sleep for "time" miliseconds. + */ + + unsigned time = ROM16(bios->data[offset + 1]); + + if (!iexec->execute) + return 3; + + BIOSLOG(bios, "0x%04X: Sleeping for 0x%04X miliseconds\n", + offset, time); + + msleep(time); + + return 3; +} + +static int init_zm_reg_sequence(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) { @@ -3518,6 +3543,7 @@ static struct init_tbl_entry itbl_entry[] = { { "INIT_ZM_CR" , 0x53, init_zm_cr }, { "INIT_ZM_CR_GROUP" , 0x54, init_zm_cr_group }, { "INIT_CONDITION_TIME" , 0x56, init_condition_time }, + { "INIT_LTIME" , 0x57, init_ltime }, { "INIT_ZM_REG_SEQUENCE" , 0x58, init_zm_reg_sequence }, /* INIT_INDIRECT_REG (0x5A, 7, 0, 0) removed due to no example of use */ { "INIT_SUB_DIRECT" , 0x5B, init_sub_direct }, -- cgit v0.10.2 From b715d64028ea90bcb67b3823ae1cc908a4ae0bc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= Date: Sun, 4 Jul 2010 02:47:16 +0000 Subject: drm/nouveau: implement init table opcodex 0x5e and 0x9a MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ben Skeggs Signed-off-by: Marcin Koƛcielnicki diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 6dd00ff..8f1f162 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -2020,6 +2020,64 @@ init_sub_direct(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) } static int +init_i2c_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) +{ + /* + * INIT_I2C_IF opcode: 0x5E ('^') + * + * offset (8 bit): opcode + * offset + 1 (8 bit): DCB I2C table entry index + * offset + 2 (8 bit): I2C slave address + * offset + 3 (8 bit): I2C register + * offset + 4 (8 bit): mask + * offset + 5 (8 bit): data + * + * Read the register given by "I2C register" on the device addressed + * by "I2C slave address" on the I2C bus given by "DCB I2C table + * entry index". Compare the result AND "mask" to "data". + * If they're not equal, skip subsequent opcodes until condition is + * inverted (INIT_NOT), or we hit INIT_RESUME + */ + + uint8_t i2c_index = bios->data[offset + 1]; + uint8_t i2c_address = bios->data[offset + 2] >> 1; + uint8_t reg = bios->data[offset + 3]; + uint8_t mask = bios->data[offset + 4]; + uint8_t data = bios->data[offset + 5]; + struct nouveau_i2c_chan *chan; + union i2c_smbus_data val; + int ret; + + /* no execute check by design */ + + BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X\n", + offset, i2c_index, i2c_address); + + chan = init_i2c_device_find(bios->dev, i2c_index); + if (!chan) + return -ENODEV; + + ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0, + I2C_SMBUS_READ, reg, + I2C_SMBUS_BYTE_DATA, &val); + if (ret < 0) { + BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: [no device], " + "Mask: 0x%02X, Data: 0x%02X\n", + offset, reg, mask, data); + iexec->execute = 0; + return 6; + } + + BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: 0x%02X, " + "Mask: 0x%02X, Data: 0x%02X\n", + offset, reg, val.byte, mask, data); + + iexec->execute = ((val.byte & mask) == data); + + return 6; +} + +static int init_copy_nv_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) { /* @@ -3517,6 +3575,69 @@ init_zm_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) return len; } +static int +init_i2c_long_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) +{ + /* + * INIT_I2C_LONG_IF opcode: 0x9A ('') + * + * offset (8 bit): opcode + * offset + 1 (8 bit): DCB I2C table entry index + * offset + 2 (8 bit): I2C slave address + * offset + 3 (16 bit): I2C register + * offset + 5 (8 bit): mask + * offset + 6 (8 bit): data + * + * Read the register given by "I2C register" on the device addressed + * by "I2C slave address" on the I2C bus given by "DCB I2C table + * entry index". Compare the result AND "mask" to "data". + * If they're not equal, skip subsequent opcodes until condition is + * inverted (INIT_NOT), or we hit INIT_RESUME + */ + + uint8_t i2c_index = bios->data[offset + 1]; + uint8_t i2c_address = bios->data[offset + 2] >> 1; + uint8_t reglo = bios->data[offset + 3]; + uint8_t reghi = bios->data[offset + 4]; + uint8_t mask = bios->data[offset + 5]; + uint8_t data = bios->data[offset + 6]; + struct nouveau_i2c_chan *chan; + uint8_t buf0[2] = { reghi, reglo }; + uint8_t buf1[1]; + struct i2c_msg msg[2] = { + { i2c_address, 0, 1, buf0 }, + { i2c_address, I2C_M_RD, 1, buf1 }, + }; + int ret; + + /* no execute check by design */ + + BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X\n", + offset, i2c_index, i2c_address); + + chan = init_i2c_device_find(bios->dev, i2c_index); + if (!chan) + return -ENODEV; + + + ret = i2c_transfer(&chan->adapter, msg, 2); + if (ret < 0) { + BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X:0x%02X, Value: [no device], " + "Mask: 0x%02X, Data: 0x%02X\n", + offset, reghi, reglo, mask, data); + iexec->execute = 0; + return 7; + } + + BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X:0x%02X, Value: 0x%02X, " + "Mask: 0x%02X, Data: 0x%02X\n", + offset, reghi, reglo, buf1[0], mask, data); + + iexec->execute = ((buf1[0] & mask) == data); + + return 7; +} + static struct init_tbl_entry itbl_entry[] = { /* command name , id , length , offset , mult , command handler */ /* INIT_PROG (0x31, 15, 10, 4) removed due to no example of use */ @@ -3547,6 +3668,7 @@ static struct init_tbl_entry itbl_entry[] = { { "INIT_ZM_REG_SEQUENCE" , 0x58, init_zm_reg_sequence }, /* INIT_INDIRECT_REG (0x5A, 7, 0, 0) removed due to no example of use */ { "INIT_SUB_DIRECT" , 0x5B, init_sub_direct }, + { "INIT_I2C_IF" , 0x5E, init_i2c_if }, { "INIT_COPY_NV_REG" , 0x5F, init_copy_nv_reg }, { "INIT_ZM_INDEX_IO" , 0x62, init_zm_index_io }, { "INIT_COMPUTE_MEM" , 0x63, init_compute_mem }, @@ -3580,6 +3702,7 @@ static struct init_tbl_entry itbl_entry[] = { { "INIT_97" , 0x97, init_97 }, { "INIT_AUXCH" , 0x98, init_auxch }, { "INIT_ZM_AUXCH" , 0x99, init_zm_auxch }, + { "INIT_I2C_LONG_IF" , 0x9A, init_i2c_long_if }, { NULL , 0 , NULL } }; -- cgit v0.10.2 From 147cad0936f3c59ec5678fe47319e44e3ea44d87 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 4 Aug 2010 22:48:34 +1000 Subject: drm/nvc0: backup bar3 channel on suspend Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c index e2a0bb8..e74bd45 100644 --- a/drivers/gpu/drm/nouveau/nvc0_instmem.c +++ b/drivers/gpu/drm/nouveau/nvc0_instmem.c @@ -141,12 +141,34 @@ nvc0_instmem_flush(struct drm_device *dev) int nvc0_instmem_suspend(struct drm_device *dev) { + struct drm_nouveau_private *dev_priv = dev->dev_private; + int i; + + dev_priv->susres.ramin_copy = vmalloc(65536); + if (!dev_priv->susres.ramin_copy) + return -ENOMEM; + + for (i = 0x700000; i < 0x710000; i += 4) + dev_priv->susres.ramin_copy[i/4] = nv_rd32(dev, i); return 0; } void nvc0_instmem_resume(struct drm_device *dev) { + struct drm_nouveau_private *dev_priv = dev->dev_private; + u64 chan; + int i; + + chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram; + nv_wr32(dev, 0x001700, chan >> 16); + + for (i = 0x700000; i < 0x710000; i += 4) + nv_wr32(dev, i, dev_priv->susres.ramin_copy[i/4]); + vfree(dev_priv->susres.ramin_copy); + dev_priv->susres.ramin_copy = NULL; + + nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12)); } int -- cgit v0.10.2 From 54bf67dee9551f7fd45540a9dec3e5144323c877 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 4 Aug 2010 23:09:30 +1000 Subject: drm/nouveau: reduce severity of some "error" messages There's some known configurations where the lack of these tables/scripts is perfectly normal, reduce visibilty of complaint messages to debug. Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 8f1f162..a8aef93 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -4561,7 +4561,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, bios->display.script_table_ptr, table[2], table[3], table[0] >= 0x21); if (!otable) { - NV_ERROR(dev, "Couldn't find matching output script table\n"); + NV_DEBUG_KMS(dev, "failed to match any output table\n"); return 1; } @@ -4618,7 +4618,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, if (script) script = clkcmptable(bios, script, pxclk); if (!script) { - NV_ERROR(dev, "clock script 0 not found\n"); + NV_DEBUG_KMS(dev, "clock script 0 not found\n"); return 1; } -- cgit v0.10.2 From 1849719ef86e29def631a473e496507a4e052c06 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Tue, 3 Aug 2010 15:34:53 +0200 Subject: drm/nouveau: Init dcb->or on cards that have no usable DCB table. We need a valid OR value because there're a few nv17 cards with DCB v1.4. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index a8aef93..8464d20 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -6003,7 +6003,7 @@ static void fabricate_vga_output(struct dcb_table *dcb, int i2c, int heads) entry->i2c_index = i2c; entry->heads = heads; entry->location = DCB_LOC_ON_CHIP; - /* "or" mostly unused in early gen crt modesetting, 0 is fine */ + entry->or = 1; } static void fabricate_dvi_i_output(struct dcb_table *dcb, bool twoHeads) -- cgit v0.10.2 From c93ebb4021ff1fdffe78be89a4bd30bc7cbc75e6 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Thu, 5 Aug 2010 22:57:08 +0200 Subject: drm/i2c/ch7006: Don't use POWER_LEVEL_FULL_POWER_OFF on early chip versions. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c index 833b35f..08792a7 100644 --- a/drivers/gpu/drm/i2c/ch7006_drv.c +++ b/drivers/gpu/drm/i2c/ch7006_drv.c @@ -470,6 +470,7 @@ static int ch7006_encoder_init(struct i2c_client *client, priv->hmargin = 50; priv->vmargin = 50; priv->last_dpms = -1; + priv->chip_version = ch7006_read(client, CH7006_VERSION_ID); if (ch7006_tv_norm) { for (i = 0; i < NUM_TV_NORMS; i++) { diff --git a/drivers/gpu/drm/i2c/ch7006_mode.c b/drivers/gpu/drm/i2c/ch7006_mode.c index e447dfb..c860f24 100644 --- a/drivers/gpu/drm/i2c/ch7006_mode.c +++ b/drivers/gpu/drm/i2c/ch7006_mode.c @@ -316,7 +316,10 @@ void ch7006_setup_power_state(struct drm_encoder *encoder) } } else { - *power |= bitfs(CH7006_POWER_LEVEL, FULL_POWER_OFF); + if (priv->chip_version >= 0x20) + *power |= bitfs(CH7006_POWER_LEVEL, FULL_POWER_OFF); + else + *power |= bitfs(CH7006_POWER_LEVEL, POWER_OFF); } } diff --git a/drivers/gpu/drm/i2c/ch7006_priv.h b/drivers/gpu/drm/i2c/ch7006_priv.h index 1c6d2e3..17667b7 100644 --- a/drivers/gpu/drm/i2c/ch7006_priv.h +++ b/drivers/gpu/drm/i2c/ch7006_priv.h @@ -95,6 +95,7 @@ struct ch7006_priv { int flicker; int scale; + int chip_version; int last_dpms; }; -- cgit v0.10.2 From 0746b5da53af533e3e525aeea47d1020c8f99c67 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Thu, 5 Aug 2010 22:58:42 +0200 Subject: drm/nv04: Fix up SGRAM density detection. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 8464d20..6df8b3f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -2250,7 +2250,7 @@ nv04_init_compute_mem(struct nvbios *bios) NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_4MB); - } else if (peek_fb(dev, fb, 0) == patt) { + } else if (peek_fb(dev, fb, 0) != patt) { if (read_back_fb(dev, fb, 0x800000, patt)) bios_md32(bios, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, -- cgit v0.10.2 From 4d1defd724485bb4cbecdcccf5c3fee5cd6a0d41 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Fri, 6 Aug 2010 20:32:25 +0200 Subject: drm/nv30: Fix PFB init for nv31. Fixes a regression introduced by 58bbb63720c8997e0136fe1884101e7ca40d68fd (fdo bug 29324). Reported-by: Johannes Obermayr Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nv30_fb.c b/drivers/gpu/drm/nouveau/nv30_fb.c index 9d35c8b..4a3f2f0 100644 --- a/drivers/gpu/drm/nouveau/nv30_fb.c +++ b/drivers/gpu/drm/nouveau/nv30_fb.c @@ -30,15 +30,25 @@ #include "nouveau_drm.h" static int -calc_ref(int b, int l, int i) +calc_bias(struct drm_device *dev, int k, int i, int j) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + int b = (dev_priv->chipset > 0x30 ? + nv_rd32(dev, 0x122c + 0x10 * k + 0x4 * j) >> (4 * (i ^ 1)) : + 0) & 0xf; + + return 2 * (b & 0x8 ? b - 0x10 : b); +} + +static int +calc_ref(struct drm_device *dev, int l, int k, int i) { int j, x = 0; for (j = 0; j < 4; j++) { - int n = (b >> (8 * j) & 0xf); - int m = (l >> (8 * i) & 0xff) + 2 * (n & 0x8 ? n - 0x10 : n); + int m = (l >> (8 * i) & 0xff) + calc_bias(dev, k, i, j); - x |= (0x80 | (m & 0x1f)) << (8 * j); + x |= (0x80 | clamp(m, 0, 0x1f)) << (8 * j); } return x; @@ -63,18 +73,16 @@ nv30_fb_init(struct drm_device *dev) dev_priv->chipset == 0x35) { /* Related to ROP count */ int n = (dev_priv->chipset == 0x31 ? 2 : 4); - int b = (dev_priv->chipset > 0x30 ? - nv_rd32(dev, 0x122c) & 0xf : 0); int l = nv_rd32(dev, 0x1003d0); for (i = 0; i < n; i++) { for (j = 0; j < 3; j++) nv_wr32(dev, 0x10037c + 0xc * i + 0x4 * j, - calc_ref(b, l, j)); + calc_ref(dev, l, 0, j)); for (j = 0; j < 2; j++) nv_wr32(dev, 0x1003ac + 0x8 * i + 0x4 * j, - calc_ref(b, l, j)); + calc_ref(dev, l, 1, j)); } } -- cgit v0.10.2 From 27d50fcc9ac7a39a4ab3107a619ee60ed05c6de8 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sun, 8 Aug 2010 17:09:06 +0200 Subject: drm/nouveau: Fix DCB TMDS config parsing. Thinko caused by 43bda05428a3d2021f3c12220073e0251c65df8b. Signed-off-by: Francisco Jerez diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 6df8b3f..0b69a96 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -6131,12 +6131,12 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, } break; case OUTPUT_TMDS: - if (dcb->version >= 0x22) - entry->tmdsconf.slave_addr = (conf & 0x00000070) >> 4; + if (dcb->version >= 0x40) + entry->tmdsconf.sor.link = (conf & 0x00000030) >> 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; + else if (dcb->version >= 0x22) + entry->tmdsconf.slave_addr = (conf & 0x00000070) >> 4; break; case 0xe: -- cgit v0.10.2 From 2dc5d2ec0599bd96729f8a9b00d44b56e15d765d Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 9 Aug 2010 15:18:44 +1000 Subject: drm/nvc0: fix typo in PRAMIN flush Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c index e74bd45..3ab3cdc 100644 --- a/drivers/gpu/drm/nouveau/nvc0_instmem.c +++ b/drivers/gpu/drm/nouveau/nvc0_instmem.c @@ -134,7 +134,7 @@ void nvc0_instmem_flush(struct drm_device *dev) { nv_wr32(dev, 0x070000, 1); - if (!nv_wait(0x070000, 0x00000001, 0x00000000)) + if (!nv_wait(0x070000, 0x00000002, 0x00000000)) NV_ERROR(dev, "PRAMIN flush timeout\n"); } -- cgit v0.10.2