Commit d30645ae authored by Dave Airlie's avatar Dave Airlie

Merge branch 'drm-nouveau-next' of...

Merge branch 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6 into drm-next

Nothing major ready for merging yet, so mostly bug fixes below, in addition to VP3 enablement from Ilia.

* 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6:
  drm/nouveau: fix command submission to use vmalloc for big allocations
  drm/nouveau/bios/therm: handle vbioses with duplicate entries (mostly nva5)
  drm/nouveau: use MSI interrupts
  drm/nv50-/kms: assume analog display connected if load on any pin
  drm/nv50/disp: prevent false output detection on the original nv50
  drm/nouveau/i2c: pass the function pointers in at creation time
  drm/nouveau/therm: survive to suspend/resume cycles
  drm/nouveau/timer: add a way to cancel alarms
  drm/nouveau/timer: restore the time on resume
  drm/nouveau/fan: restore pwm value on resume when in manual/auto mode
  drm/nouveau/therm: Set the correct pwm_mode upon resume
  drm/nouveau: require contiguous bo for framebuffer
  drm/nv50-/disp: use the number of dac, sor, pior rather than hardcoded values
  drm/nouveau: remove duplicate copy of nv44_graph_class
  drm/nouveau/vdec: implement support for VP3 engines
  drm/nouveau/core: get rid of math.h, replace log2i with order_base_2
parents ef25bd84 c859074e
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
#include <core/object.h> #include <core/object.h>
#include <core/ramht.h> #include <core/ramht.h>
#include <core/math.h>
#include <subdev/bar.h> #include <subdev/bar.h>
...@@ -104,6 +103,6 @@ nouveau_ramht_new(struct nouveau_object *parent, struct nouveau_object *pargpu, ...@@ -104,6 +103,6 @@ nouveau_ramht_new(struct nouveau_object *parent, struct nouveau_object *pargpu,
if (ret) if (ret)
return ret; return ret;
ramht->bits = log2i(nv_gpuobj(ramht)->size >> 3); ramht->bits = order_base_2(nv_gpuobj(ramht)->size >> 3);
return 0; return 0;
} }
...@@ -19,16 +19,14 @@ ...@@ -19,16 +19,14 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE. * OTHER DEALINGS IN THE SOFTWARE.
* *
* Authors: Ben Skeggs * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin
*/ */
#include <core/engctx.h> #include <engine/falcon.h>
#include <core/class.h>
#include <engine/bsp.h> #include <engine/bsp.h>
struct nv98_bsp_priv { struct nv98_bsp_priv {
struct nouveau_engine base; struct nouveau_falcon base;
}; };
/******************************************************************************* /*******************************************************************************
...@@ -37,30 +35,48 @@ struct nv98_bsp_priv { ...@@ -37,30 +35,48 @@ struct nv98_bsp_priv {
static struct nouveau_oclass static struct nouveau_oclass
nv98_bsp_sclass[] = { nv98_bsp_sclass[] = {
{ 0x88b1, &nouveau_object_ofuncs },
{ 0x85b1, &nouveau_object_ofuncs },
{ 0x86b1, &nouveau_object_ofuncs },
{}, {},
}; };
/******************************************************************************* /*******************************************************************************
* BSP context * PBSP context
******************************************************************************/ ******************************************************************************/
static struct nouveau_oclass static struct nouveau_oclass
nv98_bsp_cclass = { nv98_bsp_cclass = {
.handle = NV_ENGCTX(BSP, 0x98), .handle = NV_ENGCTX(BSP, 0x98),
.ofuncs = &(struct nouveau_ofuncs) { .ofuncs = &(struct nouveau_ofuncs) {
.ctor = _nouveau_engctx_ctor, .ctor = _nouveau_falcon_context_ctor,
.dtor = _nouveau_engctx_dtor, .dtor = _nouveau_falcon_context_dtor,
.init = _nouveau_engctx_init, .init = _nouveau_falcon_context_init,
.fini = _nouveau_engctx_fini, .fini = _nouveau_falcon_context_fini,
.rd32 = _nouveau_engctx_rd32, .rd32 = _nouveau_falcon_context_rd32,
.wr32 = _nouveau_engctx_wr32, .wr32 = _nouveau_falcon_context_wr32,
}, },
}; };
/******************************************************************************* /*******************************************************************************
* BSP engine/subdev functions * PBSP engine/subdev functions
******************************************************************************/ ******************************************************************************/
static int
nv98_bsp_init(struct nouveau_object *object)
{
struct nv98_bsp_priv *priv = (void *)object;
int ret;
ret = nouveau_falcon_init(&priv->base);
if (ret)
return ret;
nv_wr32(priv, 0x084010, 0x0000ffd2);
nv_wr32(priv, 0x08401c, 0x0000fff2);
return 0;
}
static int static int
nv98_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, nv98_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_oclass *oclass, void *data, u32 size,
...@@ -69,7 +85,7 @@ nv98_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -69,7 +85,7 @@ nv98_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv98_bsp_priv *priv; struct nv98_bsp_priv *priv;
int ret; int ret;
ret = nouveau_engine_create(parent, engine, oclass, true, ret = nouveau_falcon_create(parent, engine, oclass, 0x084000, true,
"PBSP", "bsp", &priv); "PBSP", "bsp", &priv);
*pobject = nv_object(priv); *pobject = nv_object(priv);
if (ret) if (ret)
...@@ -86,8 +102,10 @@ nv98_bsp_oclass = { ...@@ -86,8 +102,10 @@ nv98_bsp_oclass = {
.handle = NV_ENGINE(BSP, 0x98), .handle = NV_ENGINE(BSP, 0x98),
.ofuncs = &(struct nouveau_ofuncs) { .ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv98_bsp_ctor, .ctor = nv98_bsp_ctor,
.dtor = _nouveau_engine_dtor, .dtor = _nouveau_falcon_dtor,
.init = _nouveau_engine_init, .init = nv98_bsp_init,
.fini = _nouveau_engine_fini, .fini = _nouveau_falcon_fini,
.rd32 = _nouveau_falcon_rd32,
.wr32 = _nouveau_falcon_wr32,
}, },
}; };
...@@ -49,18 +49,23 @@ int ...@@ -49,18 +49,23 @@ int
nv50_dac_sense(struct nv50_disp_priv *priv, int or, u32 loadval) nv50_dac_sense(struct nv50_disp_priv *priv, int or, u32 loadval)
{ {
const u32 doff = (or * 0x800); const u32 doff = (or * 0x800);
int load = -EINVAL;
nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80150000); nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80150000);
nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000); nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
nv_wr32(priv, 0x61a00c + doff, 0x00100000 | loadval); nv_wr32(priv, 0x61a00c + doff, 0x00100000 | loadval);
mdelay(9); mdelay(9);
udelay(500); udelay(500);
nv_wr32(priv, 0x61a00c + doff, 0x80000000); loadval = nv_mask(priv, 0x61a00c + doff, 0xffffffff, 0x00000000);
load = (nv_rd32(priv, 0x61a00c + doff) & 0x38000000) >> 27;
nv_wr32(priv, 0x61a00c + doff, 0x00000000);
nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80550000); nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80550000);
nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000); nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
return load;
nv_debug(priv, "DAC%d sense: 0x%08x\n", or, loadval);
if (!(loadval & 0x80000000))
return -ETIMEDOUT;
return (loadval & 0x38000000) >> 27;
} }
int int
......
...@@ -628,7 +628,7 @@ nv50_disp_base_init(struct nouveau_object *object) ...@@ -628,7 +628,7 @@ nv50_disp_base_init(struct nouveau_object *object)
} }
/* ... PIOR caps */ /* ... PIOR caps */
for (i = 0; i < 3; i++) { for (i = 0; i < priv->pior.nr; i++) {
tmp = nv_rd32(priv, 0x61e000 + (i * 0x800)); tmp = nv_rd32(priv, 0x61e000 + (i * 0x800));
nv_wr32(priv, 0x6101f0 + (i * 0x04), tmp); nv_wr32(priv, 0x6101f0 + (i * 0x04), tmp);
} }
...@@ -834,10 +834,11 @@ exec_script(struct nv50_disp_priv *priv, int head, int id) ...@@ -834,10 +834,11 @@ exec_script(struct nv50_disp_priv *priv, int head, int id)
u8 ver, hdr, cnt, len; u8 ver, hdr, cnt, len;
u16 data; u16 data;
u32 ctrl = 0x00000000; u32 ctrl = 0x00000000;
u32 reg;
int i; int i;
/* DAC */ /* DAC */
for (i = 0; !(ctrl & (1 << head)) && i < 3; i++) for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++)
ctrl = nv_rd32(priv, 0x610b5c + (i * 8)); ctrl = nv_rd32(priv, 0x610b5c + (i * 8));
/* SOR */ /* SOR */
...@@ -845,19 +846,18 @@ exec_script(struct nv50_disp_priv *priv, int head, int id) ...@@ -845,19 +846,18 @@ exec_script(struct nv50_disp_priv *priv, int head, int id)
if (nv_device(priv)->chipset < 0x90 || if (nv_device(priv)->chipset < 0x90 ||
nv_device(priv)->chipset == 0x92 || nv_device(priv)->chipset == 0x92 ||
nv_device(priv)->chipset == 0xa0) { nv_device(priv)->chipset == 0xa0) {
for (i = 0; !(ctrl & (1 << head)) && i < 2; i++) reg = 0x610b74;
ctrl = nv_rd32(priv, 0x610b74 + (i * 8));
i += 4;
} else { } else {
for (i = 0; !(ctrl & (1 << head)) && i < 4; i++) reg = 0x610798;
ctrl = nv_rd32(priv, 0x610798 + (i * 8));
i += 4;
} }
for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++)
ctrl = nv_rd32(priv, reg + (i * 8));
i += 4;
} }
/* PIOR */ /* PIOR */
if (!(ctrl & (1 << head))) { if (!(ctrl & (1 << head))) {
for (i = 0; !(ctrl & (1 << head)) && i < 3; i++) for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++)
ctrl = nv_rd32(priv, 0x610b84 + (i * 8)); ctrl = nv_rd32(priv, 0x610b84 + (i * 8));
i += 8; i += 8;
} }
...@@ -893,10 +893,11 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, ...@@ -893,10 +893,11 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk,
u8 ver, hdr, cnt, len; u8 ver, hdr, cnt, len;
u32 ctrl = 0x00000000; u32 ctrl = 0x00000000;
u32 data, conf = ~0; u32 data, conf = ~0;
u32 reg;
int i; int i;
/* DAC */ /* DAC */
for (i = 0; !(ctrl & (1 << head)) && i < 3; i++) for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++)
ctrl = nv_rd32(priv, 0x610b58 + (i * 8)); ctrl = nv_rd32(priv, 0x610b58 + (i * 8));
/* SOR */ /* SOR */
...@@ -904,19 +905,18 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, ...@@ -904,19 +905,18 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk,
if (nv_device(priv)->chipset < 0x90 || if (nv_device(priv)->chipset < 0x90 ||
nv_device(priv)->chipset == 0x92 || nv_device(priv)->chipset == 0x92 ||
nv_device(priv)->chipset == 0xa0) { nv_device(priv)->chipset == 0xa0) {
for (i = 0; !(ctrl & (1 << head)) && i < 2; i++) reg = 0x610b70;
ctrl = nv_rd32(priv, 0x610b70 + (i * 8));
i += 4;
} else { } else {
for (i = 0; !(ctrl & (1 << head)) && i < 4; i++) reg = 0x610794;
ctrl = nv_rd32(priv, 0x610794 + (i * 8));
i += 4;
} }
for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++)
ctrl = nv_rd32(priv, reg + (i * 8));
i += 4;
} }
/* PIOR */ /* PIOR */
if (!(ctrl & (1 << head))) { if (!(ctrl & (1 << head))) {
for (i = 0; !(ctrl & (1 << head)) && i < 3; i++) for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++)
ctrl = nv_rd32(priv, 0x610b80 + (i * 8)); ctrl = nv_rd32(priv, 0x610b80 + (i * 8));
i += 8; i += 8;
} }
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#include <core/engctx.h> #include <core/engctx.h>
#include <core/ramht.h> #include <core/ramht.h>
#include <core/class.h> #include <core/class.h>
#include <core/math.h>
#include <subdev/timer.h> #include <subdev/timer.h>
#include <subdev/bar.h> #include <subdev/bar.h>
...@@ -278,7 +277,7 @@ nv50_fifo_chan_ctor_ind(struct nouveau_object *parent, ...@@ -278,7 +277,7 @@ nv50_fifo_chan_ctor_ind(struct nouveau_object *parent,
return ret; return ret;
ioffset = args->ioffset; ioffset = args->ioffset;
ilength = log2i(args->ilength / 8); ilength = order_base_2(args->ilength / 8);
nv_wo32(base->ramfc, 0x3c, 0x403f6078); nv_wo32(base->ramfc, 0x3c, 0x403f6078);
nv_wo32(base->ramfc, 0x44, 0x01003fff); nv_wo32(base->ramfc, 0x44, 0x01003fff);
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#include <core/ramht.h> #include <core/ramht.h>
#include <core/event.h> #include <core/event.h>
#include <core/class.h> #include <core/class.h>
#include <core/math.h>
#include <subdev/timer.h> #include <subdev/timer.h>
#include <subdev/bar.h> #include <subdev/bar.h>
...@@ -57,6 +56,7 @@ nv84_fifo_context_attach(struct nouveau_object *parent, ...@@ -57,6 +56,7 @@ nv84_fifo_context_attach(struct nouveau_object *parent,
case NVDEV_ENGINE_SW : return 0; case NVDEV_ENGINE_SW : return 0;
case NVDEV_ENGINE_GR : addr = 0x0020; break; case NVDEV_ENGINE_GR : addr = 0x0020; break;
case NVDEV_ENGINE_VP : addr = 0x0040; break; case NVDEV_ENGINE_VP : addr = 0x0040; break;
case NVDEV_ENGINE_PPP :
case NVDEV_ENGINE_MPEG : addr = 0x0060; break; case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
case NVDEV_ENGINE_BSP : addr = 0x0080; break; case NVDEV_ENGINE_BSP : addr = 0x0080; break;
case NVDEV_ENGINE_CRYPT: addr = 0x00a0; break; case NVDEV_ENGINE_CRYPT: addr = 0x00a0; break;
...@@ -92,6 +92,7 @@ nv84_fifo_context_detach(struct nouveau_object *parent, bool suspend, ...@@ -92,6 +92,7 @@ nv84_fifo_context_detach(struct nouveau_object *parent, bool suspend,
case NVDEV_ENGINE_SW : return 0; case NVDEV_ENGINE_SW : return 0;
case NVDEV_ENGINE_GR : engn = 0; addr = 0x0020; break; case NVDEV_ENGINE_GR : engn = 0; addr = 0x0020; break;
case NVDEV_ENGINE_VP : engn = 3; addr = 0x0040; break; case NVDEV_ENGINE_VP : engn = 3; addr = 0x0040; break;
case NVDEV_ENGINE_PPP :
case NVDEV_ENGINE_MPEG : engn = 1; addr = 0x0060; break; case NVDEV_ENGINE_MPEG : engn = 1; addr = 0x0060; break;
case NVDEV_ENGINE_BSP : engn = 5; addr = 0x0080; break; case NVDEV_ENGINE_BSP : engn = 5; addr = 0x0080; break;
case NVDEV_ENGINE_CRYPT: engn = 4; addr = 0x00a0; break; case NVDEV_ENGINE_CRYPT: engn = 4; addr = 0x00a0; break;
...@@ -258,7 +259,7 @@ nv84_fifo_chan_ctor_ind(struct nouveau_object *parent, ...@@ -258,7 +259,7 @@ nv84_fifo_chan_ctor_ind(struct nouveau_object *parent,
nv_parent(chan)->object_detach = nv50_fifo_object_detach; nv_parent(chan)->object_detach = nv50_fifo_object_detach;
ioffset = args->ioffset; ioffset = args->ioffset;
ilength = log2i(args->ilength / 8); ilength = order_base_2(args->ilength / 8);
nv_wo32(base->ramfc, 0x3c, 0x403f6078); nv_wo32(base->ramfc, 0x3c, 0x403f6078);
nv_wo32(base->ramfc, 0x44, 0x01003fff); nv_wo32(base->ramfc, 0x44, 0x01003fff);
......
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
#include <core/engctx.h> #include <core/engctx.h>
#include <core/event.h> #include <core/event.h>
#include <core/class.h> #include <core/class.h>
#include <core/math.h>
#include <core/enum.h> #include <core/enum.h>
#include <subdev/timer.h> #include <subdev/timer.h>
...@@ -200,7 +199,7 @@ nvc0_fifo_chan_ctor(struct nouveau_object *parent, ...@@ -200,7 +199,7 @@ nvc0_fifo_chan_ctor(struct nouveau_object *parent,
usermem = chan->base.chid * 0x1000; usermem = chan->base.chid * 0x1000;
ioffset = args->ioffset; ioffset = args->ioffset;
ilength = log2i(args->ilength / 8); ilength = order_base_2(args->ilength / 8);
for (i = 0; i < 0x1000; i += 4) for (i = 0; i < 0x1000; i += 4)
nv_wo32(priv->user.mem, usermem + i, 0x00000000); nv_wo32(priv->user.mem, usermem + i, 0x00000000);
......
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
#include <core/engctx.h> #include <core/engctx.h>
#include <core/event.h> #include <core/event.h>
#include <core/class.h> #include <core/class.h>
#include <core/math.h>
#include <core/enum.h> #include <core/enum.h>
#include <subdev/timer.h> #include <subdev/timer.h>
...@@ -240,7 +239,7 @@ nve0_fifo_chan_ctor(struct nouveau_object *parent, ...@@ -240,7 +239,7 @@ nve0_fifo_chan_ctor(struct nouveau_object *parent,
usermem = chan->base.chid * 0x200; usermem = chan->base.chid * 0x200;
ioffset = args->ioffset; ioffset = args->ioffset;
ilength = log2i(args->ilength / 8); ilength = order_base_2(args->ilength / 8);
for (i = 0; i < 0x200; i += 4) for (i = 0; i < 0x200; i += 4)
nv_wo32(priv->user.mem, usermem + i, 0x00000000); nv_wo32(priv->user.mem, usermem + i, 0x00000000);
......
#ifndef __NV40_GRAPH_H__ #ifndef __NV40_GRAPH_H__
#define __NV40_GRAPH_H__ #define __NV40_GRAPH_H__
#include <core/device.h>
#include <core/gpuobj.h>
/* returns 1 if device is one of the nv4x using the 0x4497 object class, /* returns 1 if device is one of the nv4x using the 0x4497 object class,
* helpful to determine a number of other hardware features * helpful to determine a number of other hardware features
*/ */
......
...@@ -19,21 +19,14 @@ ...@@ -19,21 +19,14 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE. * OTHER DEALINGS IN THE SOFTWARE.
* *
* Authors: Ben Skeggs * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin
*/ */
#include <core/engine.h> #include <engine/falcon.h>
#include <core/engctx.h>
#include <core/class.h>
#include <engine/ppp.h> #include <engine/ppp.h>
struct nv98_ppp_priv { struct nv98_ppp_priv {
struct nouveau_engine base; struct nouveau_falcon base;
};
struct nv98_ppp_chan {
struct nouveau_engctx base;
}; };
/******************************************************************************* /*******************************************************************************
...@@ -42,6 +35,8 @@ struct nv98_ppp_chan { ...@@ -42,6 +35,8 @@ struct nv98_ppp_chan {
static struct nouveau_oclass static struct nouveau_oclass
nv98_ppp_sclass[] = { nv98_ppp_sclass[] = {
{ 0x88b3, &nouveau_object_ofuncs },
{ 0x85b3, &nouveau_object_ofuncs },
{}, {},
}; };
...@@ -53,12 +48,12 @@ static struct nouveau_oclass ...@@ -53,12 +48,12 @@ static struct nouveau_oclass
nv98_ppp_cclass = { nv98_ppp_cclass = {
.handle = NV_ENGCTX(PPP, 0x98), .handle = NV_ENGCTX(PPP, 0x98),
.ofuncs = &(struct nouveau_ofuncs) { .ofuncs = &(struct nouveau_ofuncs) {
.ctor = _nouveau_engctx_ctor, .ctor = _nouveau_falcon_context_ctor,
.dtor = _nouveau_engctx_dtor, .dtor = _nouveau_falcon_context_dtor,
.init = _nouveau_engctx_init, .init = _nouveau_falcon_context_init,
.fini = _nouveau_engctx_fini, .fini = _nouveau_falcon_context_fini,
.rd32 = _nouveau_engctx_rd32, .rd32 = _nouveau_falcon_context_rd32,
.wr32 = _nouveau_engctx_wr32, .wr32 = _nouveau_falcon_context_wr32,
}, },
}; };
...@@ -66,6 +61,21 @@ nv98_ppp_cclass = { ...@@ -66,6 +61,21 @@ nv98_ppp_cclass = {
* PPPP engine/subdev functions * PPPP engine/subdev functions
******************************************************************************/ ******************************************************************************/
static int
nv98_ppp_init(struct nouveau_object *object)
{
struct nv98_ppp_priv *priv = (void *)object;
int ret;
ret = nouveau_falcon_init(&priv->base);
if (ret)
return ret;
nv_wr32(priv, 0x086010, 0x0000ffd2);
nv_wr32(priv, 0x08601c, 0x0000fff2);
return 0;
}
static int static int
nv98_ppp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, nv98_ppp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_oclass *oclass, void *data, u32 size,
...@@ -74,7 +84,7 @@ nv98_ppp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -74,7 +84,7 @@ nv98_ppp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv98_ppp_priv *priv; struct nv98_ppp_priv *priv;
int ret; int ret;
ret = nouveau_engine_create(parent, engine, oclass, true, ret = nouveau_falcon_create(parent, engine, oclass, 0x086000, true,
"PPPP", "ppp", &priv); "PPPP", "ppp", &priv);
*pobject = nv_object(priv); *pobject = nv_object(priv);
if (ret) if (ret)
...@@ -91,8 +101,10 @@ nv98_ppp_oclass = { ...@@ -91,8 +101,10 @@ nv98_ppp_oclass = {
.handle = NV_ENGINE(PPP, 0x98), .handle = NV_ENGINE(PPP, 0x98),
.ofuncs = &(struct nouveau_ofuncs) { .ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv98_ppp_ctor, .ctor = nv98_ppp_ctor,
.dtor = _nouveau_engine_dtor, .dtor = _nouveau_falcon_dtor,
.init = _nouveau_engine_init, .init = nv98_ppp_init,
.fini = _nouveau_engine_fini, .fini = _nouveau_falcon_fini,
.rd32 = _nouveau_falcon_rd32,
.wr32 = _nouveau_falcon_wr32,
}, },
}; };
...@@ -19,16 +19,14 @@ ...@@ -19,16 +19,14 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE. * OTHER DEALINGS IN THE SOFTWARE.
* *
* Authors: Ben Skeggs * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin
*/ */
#include <core/engctx.h> #include <engine/falcon.h>
#include <core/class.h>
#include <engine/vp.h> #include <engine/vp.h>
struct nv98_vp_priv { struct nv98_vp_priv {
struct nouveau_engine base; struct nouveau_falcon base;
}; };
/******************************************************************************* /*******************************************************************************
...@@ -37,6 +35,8 @@ struct nv98_vp_priv { ...@@ -37,6 +35,8 @@ struct nv98_vp_priv {
static struct nouveau_oclass static struct nouveau_oclass
nv98_vp_sclass[] = { nv98_vp_sclass[] = {
{ 0x88b2, &nouveau_object_ofuncs },
{ 0x85b2, &nouveau_object_ofuncs },
{}, {},
}; };
...@@ -48,12 +48,12 @@ static struct nouveau_oclass ...@@ -48,12 +48,12 @@ static struct nouveau_oclass
nv98_vp_cclass = { nv98_vp_cclass = {
.handle = NV_ENGCTX(VP, 0x98), .handle = NV_ENGCTX(VP, 0x98),
.ofuncs = &(struct nouveau_ofuncs) { .ofuncs = &(struct nouveau_ofuncs) {
.ctor = _nouveau_engctx_ctor, .ctor = _nouveau_falcon_context_ctor,
.dtor = _nouveau_engctx_dtor, .dtor = _nouveau_falcon_context_dtor,
.init = _nouveau_engctx_init, .init = _nouveau_falcon_context_init,
.fini = _nouveau_engctx_fini, .fini = _nouveau_falcon_context_fini,
.rd32 = _nouveau_engctx_rd32, .rd32 = _nouveau_falcon_context_rd32,
.wr32 = _nouveau_engctx_wr32, .wr32 = _nouveau_falcon_context_wr32,
}, },
}; };
...@@ -61,6 +61,21 @@ nv98_vp_cclass = { ...@@ -61,6 +61,21 @@ nv98_vp_cclass = {
* PVP engine/subdev functions * PVP engine/subdev functions
******************************************************************************/ ******************************************************************************/
static int
nv98_vp_init(struct nouveau_object *object)
{
struct nv98_vp_priv *priv = (void *)object;
int ret;
ret = nouveau_falcon_init(&priv->base);
if (ret)
return ret;
nv_wr32(priv, 0x085010, 0x0000ffd2);
nv_wr32(priv, 0x08501c, 0x0000fff2);
return 0;
}
static int static int
nv98_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, nv98_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_oclass *oclass, void *data, u32 size,
...@@ -69,7 +84,7 @@ nv98_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -69,7 +84,7 @@ nv98_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv98_vp_priv *priv; struct nv98_vp_priv *priv;
int ret; int ret;
ret = nouveau_engine_create(parent, engine, oclass, true, ret = nouveau_falcon_create(parent, engine, oclass, 0x085000, true,
"PVP", "vp", &priv); "PVP", "vp", &priv);
*pobject = nv_object(priv); *pobject = nv_object(priv);
if (ret) if (ret)
...@@ -86,8 +101,10 @@ nv98_vp_oclass = { ...@@ -86,8 +101,10 @@ nv98_vp_oclass = {
.handle = NV_ENGINE(VP, 0x98), .handle = NV_ENGINE(VP, 0x98),
.ofuncs = &(struct nouveau_ofuncs) { .ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv98_vp_ctor, .ctor = nv98_vp_ctor,
.dtor = _nouveau_engine_dtor, .dtor = _nouveau_falcon_dtor,
.init = _nouveau_engine_init, .init = nv98_vp_init,
.fini = _nouveau_engine_fini, .fini = _nouveau_falcon_fini,
.rd32 = _nouveau_falcon_rd32,
.wr32 = _nouveau_falcon_wr32,
}, },
}; };
#ifndef __NOUVEAU_MATH_H__
#define __NOUVEAU_MATH_H__
static inline int
log2i(u64 base)
{
u64 temp = base >> 1;
int log2;
for (log2 = 0; temp; log2++, temp >>= 1) {
}
return (base & (base - 1)) ? log2 + 1: log2;
}
#endif
...@@ -39,8 +39,8 @@ struct nouveau_i2c_func { ...@@ -39,8 +39,8 @@ struct nouveau_i2c_func {
int (*drv_ctl)(struct nouveau_i2c_port *, int lane, int sw, int pe); int (*drv_ctl)(struct nouveau_i2c_port *, int lane, int sw, int pe);
}; };
#define nouveau_i2c_port_create(p,e,o,i,a,d) \ #define nouveau_i2c_port_create(p,e,o,i,a,f,d) \
nouveau_i2c_port_create_((p), (e), (o), (i), (a), \ nouveau_i2c_port_create_((p), (e), (o), (i), (a), (f), \
sizeof(**d), (void **)d) sizeof(**d), (void **)d)
#define nouveau_i2c_port_destroy(p) ({ \ #define nouveau_i2c_port_destroy(p) ({ \
struct nouveau_i2c_port *port = (p); \ struct nouveau_i2c_port *port = (p); \
...@@ -53,7 +53,9 @@ struct nouveau_i2c_func { ...@@ -53,7 +53,9 @@ struct nouveau_i2c_func {
int nouveau_i2c_port_create_(struct nouveau_object *, struct nouveau_object *, int nouveau_i2c_port_create_(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, u8, struct nouveau_oclass *, u8,
const struct i2c_algorithm *, int, void **); const struct i2c_algorithm *,
const struct nouveau_i2c_func *,
int, void **);
void _nouveau_i2c_port_dtor(struct nouveau_object *); void _nouveau_i2c_port_dtor(struct nouveau_object *);
#define _nouveau_i2c_port_init nouveau_object_init #define _nouveau_i2c_port_init nouveau_object_init
#define _nouveau_i2c_port_fini nouveau_object_fini #define _nouveau_i2c_port_fini nouveau_object_fini
......
...@@ -12,6 +12,7 @@ struct nouveau_mc_intr { ...@@ -12,6 +12,7 @@ struct nouveau_mc_intr {
struct nouveau_mc { struct nouveau_mc {
struct nouveau_subdev base; struct nouveau_subdev base;
const struct nouveau_mc_intr *intr_map; const struct nouveau_mc_intr *intr_map;
bool use_msi;
}; };
static inline struct nouveau_mc * static inline struct nouveau_mc *
......
...@@ -22,6 +22,7 @@ bool nouveau_timer_wait_eq(void *, u64 nsec, u32 addr, u32 mask, u32 data); ...@@ -22,6 +22,7 @@ bool nouveau_timer_wait_eq(void *, u64 nsec, u32 addr, u32 mask, u32 data);
bool nouveau_timer_wait_ne(void *, u64 nsec, u32 addr, u32 mask, u32 data); bool nouveau_timer_wait_ne(void *, u64 nsec, u32 addr, u32 mask, u32 data);
bool nouveau_timer_wait_cb(void *, u64 nsec, bool (*func)(void *), void *data); bool nouveau_timer_wait_cb(void *, u64 nsec, bool (*func)(void *), void *data);
void nouveau_timer_alarm(void *, u32 nsec, struct nouveau_alarm *); void nouveau_timer_alarm(void *, u32 nsec, struct nouveau_alarm *);
void nouveau_timer_alarm_cancel(void *, struct nouveau_alarm *);
#define NV_WAIT_DEFAULT 2000000000ULL #define NV_WAIT_DEFAULT 2000000000ULL
#define nv_wait(o,a,m,v) \ #define nv_wait(o,a,m,v) \
...@@ -35,6 +36,7 @@ struct nouveau_timer { ...@@ -35,6 +36,7 @@ struct nouveau_timer {
struct nouveau_subdev base; struct nouveau_subdev base;
u64 (*read)(struct nouveau_timer *); u64 (*read)(struct nouveau_timer *);
void (*alarm)(struct nouveau_timer *, u64 time, struct nouveau_alarm *); void (*alarm)(struct nouveau_timer *, u64 time, struct nouveau_alarm *);
void (*alarm_cancel)(struct nouveau_timer *, struct nouveau_alarm *);
}; };
static inline struct nouveau_timer * static inline struct nouveau_timer *
......
...@@ -13,11 +13,13 @@ ...@@ -13,11 +13,13 @@
#include <linux/i2c-algo-bit.h> #include <linux/i2c-algo-bit.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/io-mapping.h> #include <linux/io-mapping.h>
#include <linux/vmalloc.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/vmalloc.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/log2.h>
#include <linux/pm_runtime.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
......
...@@ -184,7 +184,8 @@ nvbios_therm_fan_parse(struct nouveau_bios *bios, ...@@ -184,7 +184,8 @@ nvbios_therm_fan_parse(struct nouveau_bios *bios,
cur_trip->fan_duty = value; cur_trip->fan_duty = value;
break; break;
case 0x26: case 0x26:
fan->pwm_freq = value; if (!fan->pwm_freq)
fan->pwm_freq = value;
break; break;
case 0x3b: case 0x3b:
fan->bump_period = value; fan->bump_period = value;
......
...@@ -118,7 +118,8 @@ anx9805_aux_chan_ctor(struct nouveau_object *parent, ...@@ -118,7 +118,8 @@ anx9805_aux_chan_ctor(struct nouveau_object *parent,
int ret; int ret;
ret = nouveau_i2c_port_create(parent, engine, oclass, index, ret = nouveau_i2c_port_create(parent, engine, oclass, index,
&nouveau_i2c_aux_algo, &chan); &nouveau_i2c_aux_algo, &anx9805_aux_func,
&chan);
*pobject = nv_object(chan); *pobject = nv_object(chan);
if (ret) if (ret)
return ret; return ret;
...@@ -140,8 +141,6 @@ anx9805_aux_chan_ctor(struct nouveau_object *parent, ...@@ -140,8 +141,6 @@ anx9805_aux_chan_ctor(struct nouveau_object *parent,
struct i2c_algo_bit_data *algo = mast->adapter.algo_data; struct i2c_algo_bit_data *algo = mast->adapter.algo_data;
algo->udelay = max(algo->udelay, 40); algo->udelay = max(algo->udelay, 40);
} }
chan->base.func = &anx9805_aux_func;
return 0; return 0;
} }
...@@ -234,7 +233,8 @@ anx9805_ddc_port_ctor(struct nouveau_object *parent, ...@@ -234,7 +233,8 @@ anx9805_ddc_port_ctor(struct nouveau_object *parent,
int ret; int ret;
ret = nouveau_i2c_port_create(parent, engine, oclass, index, ret = nouveau_i2c_port_create(parent, engine, oclass, index,
&anx9805_i2c_algo, &port); &anx9805_i2c_algo, &anx9805_i2c_func,
&port);
*pobject = nv_object(port); *pobject = nv_object(port);
if (ret) if (ret)
return ret; return ret;
...@@ -256,8 +256,6 @@ anx9805_ddc_port_ctor(struct nouveau_object *parent, ...@@ -256,8 +256,6 @@ anx9805_ddc_port_ctor(struct nouveau_object *parent,
struct i2c_algo_bit_data *algo = mast->adapter.algo_data; struct i2c_algo_bit_data *algo = mast->adapter.algo_data;
algo->udelay = max(algo->udelay, 40); algo->udelay = max(algo->udelay, 40);
} }
port->base.func = &anx9805_i2c_func;
return 0; return 0;
} }
......
...@@ -95,6 +95,7 @@ nouveau_i2c_port_create_(struct nouveau_object *parent, ...@@ -95,6 +95,7 @@ nouveau_i2c_port_create_(struct nouveau_object *parent,
struct nouveau_object *engine, struct nouveau_object *engine,
struct nouveau_oclass *oclass, u8 index, struct nouveau_oclass *oclass, u8 index,
const struct i2c_algorithm *algo, const struct i2c_algorithm *algo,
const struct nouveau_i2c_func *func,
int size, void **pobject) int size, void **pobject)
{ {
struct nouveau_device *device = nv_device(parent); struct nouveau_device *device = nv_device(parent);
...@@ -112,6 +113,7 @@ nouveau_i2c_port_create_(struct nouveau_object *parent, ...@@ -112,6 +113,7 @@ nouveau_i2c_port_create_(struct nouveau_object *parent,
port->adapter.owner = THIS_MODULE; port->adapter.owner = THIS_MODULE;
port->adapter.dev.parent = &device->pdev->dev; port->adapter.dev.parent = &device->pdev->dev;
port->index = index; port->index = index;
port->func = func;
i2c_set_adapdata(&port->adapter, i2c); i2c_set_adapdata(&port->adapter, i2c);
if ( algo == &nouveau_i2c_bit_algo && if ( algo == &nouveau_i2c_bit_algo &&
......
...@@ -91,12 +91,12 @@ nv04_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -91,12 +91,12 @@ nv04_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
int ret; int ret;
ret = nouveau_i2c_port_create(parent, engine, oclass, index, ret = nouveau_i2c_port_create(parent, engine, oclass, index,
&nouveau_i2c_bit_algo, &port); &nouveau_i2c_bit_algo, &nv04_i2c_func,
&port);
*pobject = nv_object(port); *pobject = nv_object(port);
if (ret) if (ret)
return ret; return ret;
port->base.func = &nv04_i2c_func;
port->drive = info->drive; port->drive = info->drive;
port->sense = info->sense; port->sense = info->sense;
return 0; return 0;
......
...@@ -84,12 +84,12 @@ nv4e_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -84,12 +84,12 @@ nv4e_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
int ret; int ret;
ret = nouveau_i2c_port_create(parent, engine, oclass, index, ret = nouveau_i2c_port_create(parent, engine, oclass, index,
&nouveau_i2c_bit_algo, &port); &nouveau_i2c_bit_algo, &nv4e_i2c_func,
&port);
*pobject = nv_object(port); *pobject = nv_object(port);
if (ret) if (ret)
return ret; return ret;
port->base.func = &nv4e_i2c_func;
port->addr = 0x600800 + info->drive; port->addr = 0x600800 + info->drive;
return 0; return 0;
} }
......
...@@ -85,7 +85,8 @@ nv50_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -85,7 +85,8 @@ nv50_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
int ret; int ret;
ret = nouveau_i2c_port_create(parent, engine, oclass, index, ret = nouveau_i2c_port_create(parent, engine, oclass, index,
&nouveau_i2c_bit_algo, &port); &nouveau_i2c_bit_algo, &nv50_i2c_func,
&port);
*pobject = nv_object(port); *pobject = nv_object(port);
if (ret) if (ret)
return ret; return ret;
...@@ -93,7 +94,6 @@ nv50_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -93,7 +94,6 @@ nv50_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (info->drive >= nv50_i2c_addr_nr) if (info->drive >= nv50_i2c_addr_nr)
return -EINVAL; return -EINVAL;
port->base.func = &nv50_i2c_func;
port->state = 0x00000007; port->state = 0x00000007;
port->addr = nv50_i2c_addr[info->drive]; port->addr = nv50_i2c_addr[info->drive];
return 0; return 0;
......
...@@ -186,7 +186,8 @@ nv94_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -186,7 +186,8 @@ nv94_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
int ret; int ret;
ret = nouveau_i2c_port_create(parent, engine, oclass, index, ret = nouveau_i2c_port_create(parent, engine, oclass, index,
&nouveau_i2c_bit_algo, &port); &nouveau_i2c_bit_algo, &nv94_i2c_func,
&port);
*pobject = nv_object(port); *pobject = nv_object(port);
if (ret) if (ret)
return ret; return ret;
...@@ -194,7 +195,6 @@ nv94_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -194,7 +195,6 @@ nv94_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (info->drive >= nv50_i2c_addr_nr) if (info->drive >= nv50_i2c_addr_nr)
return -EINVAL; return -EINVAL;
port->base.func = &nv94_i2c_func;
port->state = 7; port->state = 7;
port->addr = nv50_i2c_addr[info->drive]; port->addr = nv50_i2c_addr[info->drive];
if (info->share != DCB_I2C_UNUSED) { if (info->share != DCB_I2C_UNUSED) {
...@@ -221,12 +221,12 @@ nv94_aux_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -221,12 +221,12 @@ nv94_aux_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
int ret; int ret;
ret = nouveau_i2c_port_create(parent, engine, oclass, index, ret = nouveau_i2c_port_create(parent, engine, oclass, index,
&nouveau_i2c_aux_algo, &port); &nouveau_i2c_aux_algo, &nv94_aux_func,
&port);
*pobject = nv_object(port); *pobject = nv_object(port);
if (ret) if (ret)
return ret; return ret;
port->base.func = &nv94_aux_func;
port->addr = info->drive; port->addr = info->drive;
if (info->share != DCB_I2C_UNUSED) { if (info->share != DCB_I2C_UNUSED) {
port->ctrl = 0x00e500 + (info->drive * 0x50); port->ctrl = 0x00e500 + (info->drive * 0x50);
......
...@@ -60,12 +60,12 @@ nvd0_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -60,12 +60,12 @@ nvd0_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
int ret; int ret;
ret = nouveau_i2c_port_create(parent, engine, oclass, index, ret = nouveau_i2c_port_create(parent, engine, oclass, index,
&nouveau_i2c_bit_algo, &port); &nouveau_i2c_bit_algo, &nvd0_i2c_func,
&port);
*pobject = nv_object(port); *pobject = nv_object(port);
if (ret) if (ret)
return ret; return ret;
port->base.func = &nvd0_i2c_func;
port->state = 0x00000007; port->state = 0x00000007;
port->addr = 0x00d014 + (info->drive * 0x20); port->addr = 0x00d014 + (info->drive * 0x20);
if (info->share != DCB_I2C_UNUSED) { if (info->share != DCB_I2C_UNUSED) {
......
...@@ -22,15 +22,9 @@ ...@@ -22,15 +22,9 @@
* Authors: Ben Skeggs * Authors: Ben Skeggs
*/ */
#include "nv04.h" #include <engine/graph/nv40.h>
static inline int #include "nv04.h"
nv44_graph_class(struct nv04_instmem_priv *priv)
{
if ((nv_device(priv)->chipset & 0xf0) == 0x60)
return 1;
return !(0x0baf & (1 << (nv_device(priv)->chipset & 0x0f)));
}
static int static int
nv40_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine, nv40_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
*/ */
#include <subdev/mc.h> #include <subdev/mc.h>
#include <linux/pm_runtime.h> #include <core/option.h>
static irqreturn_t static irqreturn_t
nouveau_mc_intr(int irq, void *arg) nouveau_mc_intr(int irq, void *arg)
...@@ -47,6 +47,9 @@ nouveau_mc_intr(int irq, void *arg) ...@@ -47,6 +47,9 @@ nouveau_mc_intr(int irq, void *arg)
map++; map++;
} }
if (pmc->use_msi)
nv_wr08(pmc->base.base.parent, 0x00088068, 0xff);
if (intr) { if (intr) {
nv_error(pmc, "unknown intr 0x%08x\n", stat); nv_error(pmc, "unknown intr 0x%08x\n", stat);
} }
...@@ -81,6 +84,8 @@ _nouveau_mc_dtor(struct nouveau_object *object) ...@@ -81,6 +84,8 @@ _nouveau_mc_dtor(struct nouveau_object *object)
struct nouveau_device *device = nv_device(object); struct nouveau_device *device = nv_device(object);
struct nouveau_mc *pmc = (void *)object; struct nouveau_mc *pmc = (void *)object;
free_irq(device->pdev->irq, pmc); free_irq(device->pdev->irq, pmc);
if (pmc->use_msi)
pci_disable_msi(device->pdev);
nouveau_subdev_destroy(&pmc->base); nouveau_subdev_destroy(&pmc->base);
} }
...@@ -102,6 +107,23 @@ nouveau_mc_create_(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -102,6 +107,23 @@ nouveau_mc_create_(struct nouveau_object *parent, struct nouveau_object *engine,
pmc->intr_map = intr_map; pmc->intr_map = intr_map;
switch (device->pdev->device & 0x0ff0) {
case 0x00f0: /* BR02? */
case 0x02e0: /* BR02? */
pmc->use_msi = false;
break;
default:
pmc->use_msi = nouveau_boolopt(device->cfgopt, "NvMSI", true);
if (pmc->use_msi) {
pmc->use_msi = pci_enable_msi(device->pdev) == 0;
if (pmc->use_msi) {
nv_info(pmc, "MSI interrupts enabled\n");
nv_wr08(device, 0x00088068, 0xff);
}
}
break;
}
ret = request_irq(device->pdev->irq, nouveau_mc_intr, ret = request_irq(device->pdev->irq, nouveau_mc_intr,
IRQF_SHARED, "nouveau", pmc); IRQF_SHARED, "nouveau", pmc);
if (ret < 0) if (ret < 0)
......
...@@ -35,6 +35,7 @@ nv98_mc_intr[] = { ...@@ -35,6 +35,7 @@ nv98_mc_intr[] = {
{ 0x00001000, NVDEV_ENGINE_GR }, { 0x00001000, NVDEV_ENGINE_GR },
{ 0x00004000, NVDEV_ENGINE_CRYPT }, /* NV84:NVA3 */ { 0x00004000, NVDEV_ENGINE_CRYPT }, /* NV84:NVA3 */
{ 0x00008000, NVDEV_ENGINE_BSP }, { 0x00008000, NVDEV_ENGINE_BSP },
{ 0x00020000, NVDEV_ENGINE_VP },
{ 0x00080000, NVDEV_SUBDEV_THERM }, /* NVA3:NVC0 */ { 0x00080000, NVDEV_SUBDEV_THERM }, /* NVA3:NVC0 */
{ 0x00100000, NVDEV_SUBDEV_TIMER }, { 0x00100000, NVDEV_SUBDEV_TIMER },
{ 0x00200000, NVDEV_SUBDEV_GPIO }, { 0x00200000, NVDEV_SUBDEV_GPIO },
...@@ -42,7 +43,7 @@ nv98_mc_intr[] = { ...@@ -42,7 +43,7 @@ nv98_mc_intr[] = {
{ 0x04000000, NVDEV_ENGINE_DISP }, { 0x04000000, NVDEV_ENGINE_DISP },
{ 0x10000000, NVDEV_SUBDEV_BUS }, { 0x10000000, NVDEV_SUBDEV_BUS },
{ 0x80000000, NVDEV_ENGINE_SW }, { 0x80000000, NVDEV_ENGINE_SW },
{ 0x0040d101, NVDEV_SUBDEV_FB }, { 0x0042d101, NVDEV_SUBDEV_FB },
{}, {},
}; };
......
...@@ -95,12 +95,14 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode) ...@@ -95,12 +95,14 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode)
int duty; int duty;
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
nv_debug(therm, "FAN speed check\n");
if (mode < 0) if (mode < 0)
mode = priv->mode; mode = priv->mode;
priv->mode = mode; priv->mode = mode;
switch (mode) { switch (mode) {
case NOUVEAU_THERM_CTRL_MANUAL: case NOUVEAU_THERM_CTRL_MANUAL:
ptimer->alarm_cancel(ptimer, &priv->alarm);
duty = nouveau_therm_fan_get(therm); duty = nouveau_therm_fan_get(therm);
if (duty < 0) if (duty < 0)
duty = 100; duty = 100;
...@@ -113,6 +115,7 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode) ...@@ -113,6 +115,7 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode)
break; break;
case NOUVEAU_THERM_CTRL_NONE: case NOUVEAU_THERM_CTRL_NONE:
default: default:
ptimer->alarm_cancel(ptimer, &priv->alarm);
goto done; goto done;
} }
...@@ -122,6 +125,8 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode) ...@@ -122,6 +125,8 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode)
done: done:
if (list_empty(&priv->alarm.head) && (mode == NOUVEAU_THERM_CTRL_AUTO)) if (list_empty(&priv->alarm.head) && (mode == NOUVEAU_THERM_CTRL_AUTO))
ptimer->alarm(ptimer, 1000000000ULL, &priv->alarm); ptimer->alarm(ptimer, 1000000000ULL, &priv->alarm);
else if (!list_empty(&priv->alarm.head))
nv_debug(therm, "therm fan alarm list is not empty\n");
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
} }
...@@ -267,9 +272,15 @@ _nouveau_therm_init(struct nouveau_object *object) ...@@ -267,9 +272,15 @@ _nouveau_therm_init(struct nouveau_object *object)
if (ret) if (ret)
return ret; return ret;
if (priv->suspend >= 0) if (priv->suspend >= 0) {
nouveau_therm_fan_mode(therm, priv->mode); /* restore the pwm value only when on manual or auto mode */
priv->sensor.program_alarms(therm); if (priv->suspend > 0)
nouveau_therm_fan_set(therm, true, priv->fan->percent);
nouveau_therm_fan_mode(therm, priv->suspend);
}
nouveau_therm_sensor_init(therm);
nouveau_therm_fan_init(therm);
return 0; return 0;
} }
...@@ -279,6 +290,8 @@ _nouveau_therm_fini(struct nouveau_object *object, bool suspend) ...@@ -279,6 +290,8 @@ _nouveau_therm_fini(struct nouveau_object *object, bool suspend)
struct nouveau_therm *therm = (void *)object; struct nouveau_therm *therm = (void *)object;
struct nouveau_therm_priv *priv = (void *)therm; struct nouveau_therm_priv *priv = (void *)therm;
nouveau_therm_fan_fini(therm, suspend);
nouveau_therm_sensor_fini(therm, suspend);
if (suspend) { if (suspend) {
priv->suspend = priv->mode; priv->suspend = priv->mode;
priv->mode = NOUVEAU_THERM_CTRL_NONE; priv->mode = NOUVEAU_THERM_CTRL_NONE;
......
...@@ -203,6 +203,23 @@ nouveau_therm_fan_safety_checks(struct nouveau_therm *therm) ...@@ -203,6 +203,23 @@ nouveau_therm_fan_safety_checks(struct nouveau_therm *therm)
priv->fan->bios.min_duty = priv->fan->bios.max_duty; priv->fan->bios.min_duty = priv->fan->bios.max_duty;
} }
int
nouveau_therm_fan_init(struct nouveau_therm *therm)
{
return 0;
}
int
nouveau_therm_fan_fini(struct nouveau_therm *therm, bool suspend)
{
struct nouveau_therm_priv *priv = (void *)therm;
struct nouveau_timer *ptimer = nouveau_timer(therm);
if (suspend)
ptimer->alarm_cancel(ptimer, &priv->fan->alarm);
return 0;
}
int int
nouveau_therm_fan_ctor(struct nouveau_therm *therm) nouveau_therm_fan_ctor(struct nouveau_therm *therm)
{ {
...@@ -234,6 +251,9 @@ nouveau_therm_fan_ctor(struct nouveau_therm *therm) ...@@ -234,6 +251,9 @@ nouveau_therm_fan_ctor(struct nouveau_therm *therm)
nv_info(therm, "FAN control: %s\n", priv->fan->type); nv_info(therm, "FAN control: %s\n", priv->fan->type);
/* read the current speed, it is useful when resuming */
priv->fan->percent = nouveau_therm_fan_get(therm);
/* attempt to detect a tachometer connection */ /* attempt to detect a tachometer connection */
ret = gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &priv->fan->tach); ret = gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &priv->fan->tach);
if (ret) if (ret)
......
...@@ -113,6 +113,8 @@ void nouveau_therm_ic_ctor(struct nouveau_therm *therm); ...@@ -113,6 +113,8 @@ void nouveau_therm_ic_ctor(struct nouveau_therm *therm);
int nouveau_therm_sensor_ctor(struct nouveau_therm *therm); int nouveau_therm_sensor_ctor(struct nouveau_therm *therm);
int nouveau_therm_fan_ctor(struct nouveau_therm *therm); int nouveau_therm_fan_ctor(struct nouveau_therm *therm);
int nouveau_therm_fan_init(struct nouveau_therm *therm);
int nouveau_therm_fan_fini(struct nouveau_therm *therm, bool suspend);
int nouveau_therm_fan_get(struct nouveau_therm *therm); int nouveau_therm_fan_get(struct nouveau_therm *therm);
int nouveau_therm_fan_set(struct nouveau_therm *therm, bool now, int percent); int nouveau_therm_fan_set(struct nouveau_therm *therm, bool now, int percent);
int nouveau_therm_fan_user_get(struct nouveau_therm *therm); int nouveau_therm_fan_user_get(struct nouveau_therm *therm);
...@@ -122,6 +124,8 @@ int nouveau_therm_fan_sense(struct nouveau_therm *therm); ...@@ -122,6 +124,8 @@ int nouveau_therm_fan_sense(struct nouveau_therm *therm);
int nouveau_therm_preinit(struct nouveau_therm *); int nouveau_therm_preinit(struct nouveau_therm *);
int nouveau_therm_sensor_init(struct nouveau_therm *therm);
int nouveau_therm_sensor_fini(struct nouveau_therm *therm, bool suspend);
void nouveau_therm_sensor_preinit(struct nouveau_therm *); void nouveau_therm_sensor_preinit(struct nouveau_therm *);
void nouveau_therm_sensor_set_threshold_state(struct nouveau_therm *therm, void nouveau_therm_sensor_set_threshold_state(struct nouveau_therm *therm,
enum nouveau_therm_thrs thrs, enum nouveau_therm_thrs thrs,
......
...@@ -180,6 +180,8 @@ alarm_timer_callback(struct nouveau_alarm *alarm) ...@@ -180,6 +180,8 @@ alarm_timer_callback(struct nouveau_alarm *alarm)
spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags); spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags);
nv_debug(therm, "polling the internal temperature\n");
nouveau_therm_threshold_hyst_polling(therm, &sensor->thrs_fan_boost, nouveau_therm_threshold_hyst_polling(therm, &sensor->thrs_fan_boost,
NOUVEAU_THERM_THRS_FANBOOST); NOUVEAU_THERM_THRS_FANBOOST);
...@@ -216,6 +218,25 @@ nouveau_therm_program_alarms_polling(struct nouveau_therm *therm) ...@@ -216,6 +218,25 @@ nouveau_therm_program_alarms_polling(struct nouveau_therm *therm)
alarm_timer_callback(&priv->sensor.therm_poll_alarm); alarm_timer_callback(&priv->sensor.therm_poll_alarm);
} }
int
nouveau_therm_sensor_init(struct nouveau_therm *therm)
{
struct nouveau_therm_priv *priv = (void *)therm;
priv->sensor.program_alarms(therm);
return 0;
}
int
nouveau_therm_sensor_fini(struct nouveau_therm *therm, bool suspend)
{
struct nouveau_therm_priv *priv = (void *)therm;
struct nouveau_timer *ptimer = nouveau_timer(therm);
if (suspend)
ptimer->alarm_cancel(ptimer, &priv->sensor.therm_poll_alarm);
return 0;
}
void void
nouveau_therm_sensor_preinit(struct nouveau_therm *therm) nouveau_therm_sensor_preinit(struct nouveau_therm *therm)
{ {
......
...@@ -85,3 +85,10 @@ nouveau_timer_alarm(void *obj, u32 nsec, struct nouveau_alarm *alarm) ...@@ -85,3 +85,10 @@ nouveau_timer_alarm(void *obj, u32 nsec, struct nouveau_alarm *alarm)
struct nouveau_timer *ptimer = nouveau_timer(obj); struct nouveau_timer *ptimer = nouveau_timer(obj);
ptimer->alarm(ptimer, nsec, alarm); ptimer->alarm(ptimer, nsec, alarm);
} }
void
nouveau_timer_alarm_cancel(void *obj, struct nouveau_alarm *alarm)
{
struct nouveau_timer *ptimer = nouveau_timer(obj);
ptimer->alarm_cancel(ptimer, alarm);
}
...@@ -36,6 +36,7 @@ struct nv04_timer_priv { ...@@ -36,6 +36,7 @@ struct nv04_timer_priv {
struct nouveau_timer base; struct nouveau_timer base;
struct list_head alarms; struct list_head alarms;
spinlock_t lock; spinlock_t lock;
u64 suspend_time;
}; };
static u64 static u64
...@@ -112,6 +113,25 @@ nv04_timer_alarm(struct nouveau_timer *ptimer, u64 time, ...@@ -112,6 +113,25 @@ nv04_timer_alarm(struct nouveau_timer *ptimer, u64 time,
nv04_timer_alarm_trigger(ptimer); nv04_timer_alarm_trigger(ptimer);
} }
static void
nv04_timer_alarm_cancel(struct nouveau_timer *ptimer,
struct nouveau_alarm *alarm)
{
struct nv04_timer_priv *priv = (void *)ptimer;
unsigned long flags;
/* avoid deleting an entry while the alarm intr is running */
spin_lock_irqsave(&priv->lock, flags);
/* delete the alarm from the list */
list_del(&alarm->head);
/* reset the head so as list_empty returns 1 */
INIT_LIST_HEAD(&alarm->head);
spin_unlock_irqrestore(&priv->lock, flags);
}
static void static void
nv04_timer_intr(struct nouveau_subdev *subdev) nv04_timer_intr(struct nouveau_subdev *subdev)
{ {
...@@ -146,6 +166,8 @@ nv04_timer_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -146,6 +166,8 @@ nv04_timer_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->base.base.intr = nv04_timer_intr; priv->base.base.intr = nv04_timer_intr;
priv->base.read = nv04_timer_read; priv->base.read = nv04_timer_read;
priv->base.alarm = nv04_timer_alarm; priv->base.alarm = nv04_timer_alarm;
priv->base.alarm_cancel = nv04_timer_alarm_cancel;
priv->suspend_time = 0;
INIT_LIST_HEAD(&priv->alarms); INIT_LIST_HEAD(&priv->alarms);
spin_lock_init(&priv->lock); spin_lock_init(&priv->lock);
...@@ -164,7 +186,7 @@ nv04_timer_init(struct nouveau_object *object) ...@@ -164,7 +186,7 @@ nv04_timer_init(struct nouveau_object *object)
{ {
struct nouveau_device *device = nv_device(object); struct nouveau_device *device = nv_device(object);
struct nv04_timer_priv *priv = (void *)object; struct nv04_timer_priv *priv = (void *)object;
u32 m = 1, f, n, d; u32 m = 1, f, n, d, lo, hi;
int ret; int ret;
ret = nouveau_timer_init(&priv->base); ret = nouveau_timer_init(&priv->base);
...@@ -221,16 +243,25 @@ nv04_timer_init(struct nouveau_object *object) ...@@ -221,16 +243,25 @@ nv04_timer_init(struct nouveau_object *object)
d >>= 1; d >>= 1;
} }
/* restore the time before suspend */
lo = priv->suspend_time;
hi = (priv->suspend_time >> 32);
nv_debug(priv, "input frequency : %dHz\n", f); nv_debug(priv, "input frequency : %dHz\n", f);
nv_debug(priv, "input multiplier: %d\n", m); nv_debug(priv, "input multiplier: %d\n", m);
nv_debug(priv, "numerator : 0x%08x\n", n); nv_debug(priv, "numerator : 0x%08x\n", n);
nv_debug(priv, "denominator : 0x%08x\n", d); nv_debug(priv, "denominator : 0x%08x\n", d);
nv_debug(priv, "timer frequency : %dHz\n", (f * m) * d / n); nv_debug(priv, "timer frequency : %dHz\n", (f * m) * d / n);
nv_debug(priv, "time low : 0x%08x\n", lo);
nv_debug(priv, "time high : 0x%08x\n", hi);
nv_wr32(priv, NV04_PTIMER_NUMERATOR, n); nv_wr32(priv, NV04_PTIMER_NUMERATOR, n);
nv_wr32(priv, NV04_PTIMER_DENOMINATOR, d); nv_wr32(priv, NV04_PTIMER_DENOMINATOR, d);
nv_wr32(priv, NV04_PTIMER_INTR_0, 0xffffffff); nv_wr32(priv, NV04_PTIMER_INTR_0, 0xffffffff);
nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000); nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000);
nv_wr32(priv, NV04_PTIMER_TIME_1, hi);
nv_wr32(priv, NV04_PTIMER_TIME_0, lo);
return 0; return 0;
} }
...@@ -238,6 +269,8 @@ static int ...@@ -238,6 +269,8 @@ static int
nv04_timer_fini(struct nouveau_object *object, bool suspend) nv04_timer_fini(struct nouveau_object *object, bool suspend)
{ {
struct nv04_timer_priv *priv = (void *)object; struct nv04_timer_priv *priv = (void *)object;
if (suspend)
priv->suspend_time = nv04_timer_read(&priv->base);
nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000); nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000);
return nouveau_timer_fini(&priv->base, suspend); return nouveau_timer_fini(&priv->base, suspend);
} }
......
...@@ -174,6 +174,7 @@ nv50_vm_flush(struct nouveau_vm *vm) ...@@ -174,6 +174,7 @@ nv50_vm_flush(struct nouveau_vm *vm)
case NVDEV_ENGINE_GR : vme = 0x00; break; case NVDEV_ENGINE_GR : vme = 0x00; break;
case NVDEV_ENGINE_VP : vme = 0x01; break; case NVDEV_ENGINE_VP : vme = 0x01; break;
case NVDEV_SUBDEV_BAR : vme = 0x06; break; case NVDEV_SUBDEV_BAR : vme = 0x06; break;
case NVDEV_ENGINE_PPP :
case NVDEV_ENGINE_MPEG : vme = 0x08; break; case NVDEV_ENGINE_MPEG : vme = 0x08; break;
case NVDEV_ENGINE_BSP : vme = 0x09; break; case NVDEV_ENGINE_BSP : vme = 0x09; break;
case NVDEV_ENGINE_CRYPT: vme = 0x0a; break; case NVDEV_ENGINE_CRYPT: vme = 0x0a; break;
......
...@@ -107,6 +107,11 @@ nouveau_framebuffer_init(struct drm_device *dev, ...@@ -107,6 +107,11 @@ nouveau_framebuffer_init(struct drm_device *dev,
return -EINVAL; return -EINVAL;
} }
if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG) {
NV_ERROR(drm, "framebuffer requires contiguous bo\n");
return -EINVAL;
}
if (nv_device(drm->device)->chipset == 0x50) if (nv_device(drm->device)->chipset == 0x50)
nv_fb->r_format |= (tile_flags << 8); nv_fb->r_format |= (tile_flags << 8);
......
...@@ -579,18 +579,31 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan, ...@@ -579,18 +579,31 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan,
return 0; return 0;
} }
static inline void
u_free(void *addr)
{
if (!is_vmalloc_addr(addr))
kfree(addr);
else
vfree(addr);
}
static inline void * static inline void *
u_memcpya(uint64_t user, unsigned nmemb, unsigned size) u_memcpya(uint64_t user, unsigned nmemb, unsigned size)
{ {
void *mem; void *mem;
void __user *userptr = (void __force __user *)(uintptr_t)user; void __user *userptr = (void __force __user *)(uintptr_t)user;
mem = kmalloc(nmemb * size, GFP_KERNEL); size *= nmemb;
mem = kmalloc(size, GFP_KERNEL | __GFP_NOWARN);
if (!mem)
mem = vmalloc(size);
if (!mem) if (!mem)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
if (DRM_COPY_FROM_USER(mem, userptr, nmemb * size)) { if (DRM_COPY_FROM_USER(mem, userptr, size)) {
kfree(mem); u_free(mem);
return ERR_PTR(-EFAULT); return ERR_PTR(-EFAULT);
} }
...@@ -676,7 +689,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, ...@@ -676,7 +689,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli,
nouveau_bo_wr32(nvbo, r->reloc_bo_offset >> 2, data); nouveau_bo_wr32(nvbo, r->reloc_bo_offset >> 2, data);
} }
kfree(reloc); u_free(reloc);
return ret; return ret;
} }
...@@ -738,7 +751,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, ...@@ -738,7 +751,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
bo = u_memcpya(req->buffers, req->nr_buffers, sizeof(*bo)); bo = u_memcpya(req->buffers, req->nr_buffers, sizeof(*bo));
if (IS_ERR(bo)) { if (IS_ERR(bo)) {
kfree(push); u_free(push);
return nouveau_abi16_put(abi16, PTR_ERR(bo)); return nouveau_abi16_put(abi16, PTR_ERR(bo));
} }
...@@ -849,8 +862,8 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, ...@@ -849,8 +862,8 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
nouveau_fence_unref(&fence); nouveau_fence_unref(&fence);
out_prevalid: out_prevalid:
kfree(bo); u_free(bo);
kfree(push); u_free(push);
out_next: out_next:
if (chan->dma.ib_max) { if (chan->dma.ib_max) {
......
...@@ -1583,7 +1583,7 @@ nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) ...@@ -1583,7 +1583,7 @@ nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
load = 340; load = 340;
ret = nv_exec(disp->core, NV50_DISP_DAC_LOAD + or, &load, sizeof(load)); ret = nv_exec(disp->core, NV50_DISP_DAC_LOAD + or, &load, sizeof(load));
if (ret || load != 7) if (ret || !load)
return connector_status_disconnected; return connector_status_disconnected;
return connector_status_connected; return connector_status_connected;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment