14b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs/*
2310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs * Copyright 2011 Red Hat Inc.
34b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs *
44b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs * Permission is hereby granted, free of charge, to any person obtaining a
54b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs * copy of this software and associated documentation files (the "Software"),
64b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs * to deal in the Software without restriction, including without limitation
74b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs * the rights to use, copy, modify, merge, publish, distribute, sublicense,
84b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs * and/or sell copies of the Software, and to permit persons to whom the
94b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs * Software is furnished to do so, subject to the following conditions:
104b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs *
114b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs * The above copyright notice and this permission notice shall be included in
124b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs * all copies or substantial portions of the Software.
134b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs *
144b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
154b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
164b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
174b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
184b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
194b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
204b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs * OTHER DEALINGS IN THE SOFTWARE.
214b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs *
224b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs * Authors: Ben Skeggs
234b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs */
244b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs
254b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs#include "drmP.h"
26310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs#include "drm.h"
274b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs#include "nouveau_drv.h"
28310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs#include "nouveau_drm.h"
29310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs
30310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggsstruct nvc0_fb_priv {
31310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	struct page *r100c10_page;
32310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	dma_addr_t r100c10;
33310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs};
34310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs
35a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggsstatic inline void
36a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggsnvc0_mfb_subp_isr(struct drm_device *dev, int unit, int subp)
37a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggs{
38a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggs	u32 subp_base = 0x141000 + (unit * 0x2000) + (subp * 0x400);
39a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggs	u32 stat = nv_rd32(dev, subp_base + 0x020);
40a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggs
41a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggs	if (stat) {
42a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggs		NV_INFO(dev, "PMFB%d_SUBP%d: 0x%08x\n", unit, subp, stat);
43a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggs		nv_wr32(dev, subp_base + 0x020, stat);
44a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggs	}
45a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggs}
46a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggs
47a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggsstatic void
48a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggsnvc0_mfb_isr(struct drm_device *dev)
49a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggs{
50a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggs	u32 units = nv_rd32(dev, 0x00017c);
51a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggs	while (units) {
52a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggs		u32 subp, unit = ffs(units) - 1;
53a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggs		for (subp = 0; subp < 2; subp++)
54a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggs			nvc0_mfb_subp_isr(dev, unit, subp);
55a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggs		units &= ~(1 << unit);
56a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggs	}
57ffc6a4e49e5bc117aac13ed752cfc018c163e2acChristoph Bumiller
58ffc6a4e49e5bc117aac13ed752cfc018c163e2acChristoph Bumiller	/* we do something horribly wrong and upset PMFB a lot, so mask off
59ffc6a4e49e5bc117aac13ed752cfc018c163e2acChristoph Bumiller	 * interrupts from it after the first one until it's fixed
60ffc6a4e49e5bc117aac13ed752cfc018c163e2acChristoph Bumiller	 */
61ffc6a4e49e5bc117aac13ed752cfc018c163e2acChristoph Bumiller	nv_mask(dev, 0x000640, 0x02000000, 0x00000000);
62a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggs}
63a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggs
64310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggsstatic void
65310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggsnvc0_fb_destroy(struct drm_device *dev)
66310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs{
67310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	struct drm_nouveau_private *dev_priv = dev->dev_private;
68310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
69310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	struct nvc0_fb_priv *priv = pfb->priv;
70310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs
71a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggs	nouveau_irq_unregister(dev, 25);
72a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggs
73310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	if (priv->r100c10_page) {
74310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs		pci_unmap_page(dev->pdev, priv->r100c10, PAGE_SIZE,
75310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs			       PCI_DMA_BIDIRECTIONAL);
76310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs		__free_page(priv->r100c10_page);
77310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	}
78310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs
79310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	kfree(priv);
80310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	pfb->priv = NULL;
81310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs}
82310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs
83310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggsstatic int
84310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggsnvc0_fb_create(struct drm_device *dev)
85310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs{
86310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	struct drm_nouveau_private *dev_priv = dev->dev_private;
87310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
88310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	struct nvc0_fb_priv *priv;
89310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs
90310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
91310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	if (!priv)
92310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs		return -ENOMEM;
93310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	pfb->priv = priv;
94310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs
95310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	priv->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
96310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	if (!priv->r100c10_page) {
97310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs		nvc0_fb_destroy(dev);
98310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs		return -ENOMEM;
99310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	}
100310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs
101310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	priv->r100c10 = pci_map_page(dev->pdev, priv->r100c10_page, 0,
102310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs				     PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
103310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	if (pci_dma_mapping_error(dev->pdev, priv->r100c10)) {
104310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs		nvc0_fb_destroy(dev);
105310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs		return -EFAULT;
106310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	}
107310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs
108a14845121c1e9cfe302d23ca4ffcfc62cf8e1033Ben Skeggs	nouveau_irq_register(dev, 25, nvc0_mfb_isr);
109310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	return 0;
110310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs}
1114b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs
1124b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggsint
1134b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggsnvc0_fb_init(struct drm_device *dev)
1144b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs{
115310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	struct drm_nouveau_private *dev_priv = dev->dev_private;
116310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	struct nvc0_fb_priv *priv;
117310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	int ret;
118310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs
119310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	if (!dev_priv->engine.fb.priv) {
120310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs		ret = nvc0_fb_create(dev);
121310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs		if (ret)
122310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs			return ret;
123310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	}
124310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	priv = dev_priv->engine.fb.priv;
125310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs
126310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	nv_wr32(dev, 0x100c10, priv->r100c10 >> 8);
1274b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs	return 0;
1284b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs}
1294b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs
1304b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggsvoid
1314b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggsnvc0_fb_takedown(struct drm_device *dev)
1324b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs{
133310ff414b32e66d832307bedd99ba75908e4e36dBen Skeggs	nvc0_fb_destroy(dev);
1344b223eefe43d201c323d120a01dbd0dcbba64e6dBen Skeggs}
135