diff --git a/nvkm/subdev/fb/nv50.c b/nvkm/subdev/fb/nv50.c index 4150b0d..bdaf2d0 100644 --- a/nvkm/subdev/fb/nv50.c +++ b/nvkm/subdev/fb/nv50.c @@ -259,6 +259,40 @@ nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, nv_warn(priv, "failed 0x100c08 page alloc\n"); } + if ((nv_device(priv)->chipset == 0xaa || nv_device(priv)->chipset == 0xac) + && !nv_rd32(priv, 0x100c14)) { + priv->r100c18_page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (priv->r100c18_page) { + priv->r100c18 = dma_map_page(nv_device_base(device), + priv->r100c18_page, 0, PAGE_SIZE, + DMA_BIDIRECTIONAL); + if (dma_mapping_error(nv_device_base(device), priv->r100c18)) + return -EFAULT; + } else { + nv_warn(priv, "failed 0x100c18 page alloc\n"); + } + priv->r100c1c_page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (priv->r100c1c_page) { + priv->r100c1c = dma_map_page(nv_device_base(device), + priv->r100c1c_page, 0, PAGE_SIZE, + DMA_BIDIRECTIONAL); + if (dma_mapping_error(nv_device_base(device), priv->r100c1c)) + return -EFAULT; + } else { + nv_warn(priv, "failed 0x100c1c page alloc\n"); + } + priv->r100c24_page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (priv->r100c24_page) { + priv->r100c24 = dma_map_page(nv_device_base(device), + priv->r100c24_page, 0, PAGE_SIZE, + DMA_BIDIRECTIONAL); + if (dma_mapping_error(nv_device_base(device), priv->r100c24)) + return -EFAULT; + } else { + nv_warn(priv, "failed 0x100c24 page alloc\n"); + } + } + nv_subdev(priv)->intr = nv50_fb_intr; return 0; } @@ -274,6 +308,21 @@ nv50_fb_dtor(struct nouveau_object *object) DMA_BIDIRECTIONAL); __free_page(priv->r100c08_page); } + if (priv->r100c18_page) { + dma_unmap_page(nv_device_base(device), priv->r100c18, PAGE_SIZE, + DMA_BIDIRECTIONAL); + __free_page(priv->r100c18_page); + } + if (priv->r100c1c_page) { + dma_unmap_page(nv_device_base(device), priv->r100c1c, PAGE_SIZE, + DMA_BIDIRECTIONAL); + __free_page(priv->r100c1c_page); + } + if (priv->r100c24_page) { + dma_unmap_page(nv_device_base(device), priv->r100c24, PAGE_SIZE, + DMA_BIDIRECTIONAL); + __free_page(priv->r100c24_page); + } nouveau_fb_destroy(&priv->base); } @@ -295,6 +344,19 @@ nv50_fb_init(struct nouveau_object *object) */ nv_wr32(priv, 0x100c08, priv->r100c08 >> 8); + /* Enable NISO poller for various clients and set their associated + * read address, only for MCP77/78 and MCP79/7A. (fd#25701) + */ + if ((nv_device(priv)->chipset == 0xaa || nv_device(priv)->chipset == 0xac) + && !nv_rd32(priv, 0x100c14)) { + nv_wr32(priv, 0x100c18, priv->r100c18 >> 8); + nv_mask(priv, 0x100c14, 0x00000000, 0x00000001); + nv_wr32(priv, 0x100c1c, priv->r100c1c >> 8); + nv_mask(priv, 0x100c14, 0x00000000, 0x00000002); + nv_wr32(priv, 0x100c24, priv->r100c24 >> 8); + nv_mask(priv, 0x100c14, 0x00000000, 0x00010000); + } + /* This is needed to get meaningful information from 100c90 * on traps. No idea what these values mean exactly. */ nv_wr32(priv, 0x100c90, impl->trap); diff --git a/nvkm/subdev/fb/nv50.h b/nvkm/subdev/fb/nv50.h index c5e5a88..e673e5a 100644 --- a/nvkm/subdev/fb/nv50.h +++ b/nvkm/subdev/fb/nv50.h @@ -6,7 +6,13 @@ struct nv50_fb_priv { struct nouveau_fb base; struct page *r100c08_page; + struct page *r100c18_page; + struct page *r100c1c_page; + struct page *r100c24_page; dma_addr_t r100c08; + dma_addr_t r100c18; + dma_addr_t r100c1c; + dma_addr_t r100c24; }; int nv50_fb_ctor(struct nouveau_object *, struct nouveau_object *,