Merge branch 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6 into drm-core-next
* 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6: drm/nouveau/gr: disable fifo access and idle before suspend ctx unload drm/nouveau: pass flag to engine fini() method on suspend drm/nouveau: replace nv04_graph_fifo_access() use with direct reg bashing drm/nv40/gr: rewrite/split context takedown functions drm/nouveau: detect disabled device in irq handler and return IRQ_NONE drm/nouveau: ignore connector type when deciding digital/analog on DVI-I drm/nouveau: Add a quirk for Gigabyte NX86T drm/nouveau: do not leak in nv20_graph_create drm/nv50/dp: fix hack to work for macbooks booted via EFI
This commit is contained in:
commit
603f2e6d37
|
@ -5966,6 +5966,12 @@ apply_dcb_connector_quirks(struct nvbios *bios, int idx)
|
||||||
if (cte->type == DCB_CONNECTOR_HDMI_1)
|
if (cte->type == DCB_CONNECTOR_HDMI_1)
|
||||||
cte->type = DCB_CONNECTOR_DVI_I;
|
cte->type = DCB_CONNECTOR_DVI_I;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Gigabyte GV-NX86T512H */
|
||||||
|
if (nv_match_device(dev, 0x0402, 0x1458, 0x3455)) {
|
||||||
|
if (cte->type == DCB_CONNECTOR_HDMI_1)
|
||||||
|
cte->type = DCB_CONNECTOR_DVI_I;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const u8 hpd_gpio[16] = {
|
static const u8 hpd_gpio[16] = {
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
static void nouveau_connector_hotplug(void *, int);
|
static void nouveau_connector_hotplug(void *, int);
|
||||||
|
|
||||||
static struct nouveau_encoder *
|
static struct nouveau_encoder *
|
||||||
find_encoder_by_type(struct drm_connector *connector, int type)
|
find_encoder(struct drm_connector *connector, int type)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = connector->dev;
|
struct drm_device *dev = connector->dev;
|
||||||
struct nouveau_encoder *nv_encoder;
|
struct nouveau_encoder *nv_encoder;
|
||||||
|
@ -170,8 +170,8 @@ nouveau_connector_of_detect(struct drm_connector *connector)
|
||||||
struct device_node *cn, *dn = pci_device_to_OF_node(dev->pdev);
|
struct device_node *cn, *dn = pci_device_to_OF_node(dev->pdev);
|
||||||
|
|
||||||
if (!dn ||
|
if (!dn ||
|
||||||
!((nv_encoder = find_encoder_by_type(connector, OUTPUT_TMDS)) ||
|
!((nv_encoder = find_encoder(connector, OUTPUT_TMDS)) ||
|
||||||
(nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG))))
|
(nv_encoder = find_encoder(connector, OUTPUT_ANALOG))))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
for_each_child_of_node(dn, cn) {
|
for_each_child_of_node(dn, cn) {
|
||||||
|
@ -233,6 +233,7 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
|
||||||
struct drm_device *dev = connector->dev;
|
struct drm_device *dev = connector->dev;
|
||||||
struct nouveau_connector *nv_connector = nouveau_connector(connector);
|
struct nouveau_connector *nv_connector = nouveau_connector(connector);
|
||||||
struct nouveau_encoder *nv_encoder = NULL;
|
struct nouveau_encoder *nv_encoder = NULL;
|
||||||
|
struct nouveau_encoder *nv_partner;
|
||||||
struct nouveau_i2c_chan *i2c;
|
struct nouveau_i2c_chan *i2c;
|
||||||
int type;
|
int type;
|
||||||
|
|
||||||
|
@ -266,19 +267,22 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
|
||||||
* same i2c channel so the value returned from ddc_detect
|
* same i2c channel so the value returned from ddc_detect
|
||||||
* isn't necessarily correct.
|
* isn't necessarily correct.
|
||||||
*/
|
*/
|
||||||
if (nv_connector->dcb->type == DCB_CONNECTOR_DVI_I) {
|
nv_partner = NULL;
|
||||||
|
if (nv_encoder->dcb->type == OUTPUT_TMDS)
|
||||||
|
nv_partner = find_encoder(connector, OUTPUT_ANALOG);
|
||||||
|
if (nv_encoder->dcb->type == OUTPUT_ANALOG)
|
||||||
|
nv_partner = find_encoder(connector, OUTPUT_TMDS);
|
||||||
|
|
||||||
|
if (nv_partner && ((nv_encoder->dcb->type == OUTPUT_ANALOG &&
|
||||||
|
nv_partner->dcb->type == OUTPUT_TMDS) ||
|
||||||
|
(nv_encoder->dcb->type == OUTPUT_TMDS &&
|
||||||
|
nv_partner->dcb->type == OUTPUT_ANALOG))) {
|
||||||
if (nv_connector->edid->input & DRM_EDID_INPUT_DIGITAL)
|
if (nv_connector->edid->input & DRM_EDID_INPUT_DIGITAL)
|
||||||
type = OUTPUT_TMDS;
|
type = OUTPUT_TMDS;
|
||||||
else
|
else
|
||||||
type = OUTPUT_ANALOG;
|
type = OUTPUT_ANALOG;
|
||||||
|
|
||||||
nv_encoder = find_encoder_by_type(connector, type);
|
nv_encoder = find_encoder(connector, type);
|
||||||
if (!nv_encoder) {
|
|
||||||
NV_ERROR(dev, "Detected %d encoder on %s, "
|
|
||||||
"but no object!\n", type,
|
|
||||||
drm_get_connector_name(connector));
|
|
||||||
return connector_status_disconnected;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nouveau_connector_set_encoder(connector, nv_encoder);
|
nouveau_connector_set_encoder(connector, nv_encoder);
|
||||||
|
@ -292,9 +296,9 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
|
||||||
}
|
}
|
||||||
|
|
||||||
detect_analog:
|
detect_analog:
|
||||||
nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG);
|
nv_encoder = find_encoder(connector, OUTPUT_ANALOG);
|
||||||
if (!nv_encoder && !nouveau_tv_disable)
|
if (!nv_encoder && !nouveau_tv_disable)
|
||||||
nv_encoder = find_encoder_by_type(connector, OUTPUT_TV);
|
nv_encoder = find_encoder(connector, OUTPUT_TV);
|
||||||
if (nv_encoder && force) {
|
if (nv_encoder && force) {
|
||||||
struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
|
struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
|
||||||
struct drm_encoder_helper_funcs *helper =
|
struct drm_encoder_helper_funcs *helper =
|
||||||
|
@ -327,7 +331,7 @@ nouveau_connector_detect_lvds(struct drm_connector *connector, bool force)
|
||||||
nv_connector->edid = NULL;
|
nv_connector->edid = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
nv_encoder = find_encoder_by_type(connector, OUTPUT_LVDS);
|
nv_encoder = find_encoder(connector, OUTPUT_LVDS);
|
||||||
if (!nv_encoder)
|
if (!nv_encoder)
|
||||||
return connector_status_disconnected;
|
return connector_status_disconnected;
|
||||||
|
|
||||||
|
@ -405,7 +409,7 @@ nouveau_connector_force(struct drm_connector *connector)
|
||||||
} else
|
} else
|
||||||
type = OUTPUT_ANY;
|
type = OUTPUT_ANY;
|
||||||
|
|
||||||
nv_encoder = find_encoder_by_type(connector, type);
|
nv_encoder = find_encoder(connector, type);
|
||||||
if (!nv_encoder) {
|
if (!nv_encoder) {
|
||||||
NV_ERROR(connector->dev, "can't find encoder to force %s on!\n",
|
NV_ERROR(connector->dev, "can't find encoder to force %s on!\n",
|
||||||
drm_get_connector_name(connector));
|
drm_get_connector_name(connector));
|
||||||
|
|
|
@ -214,10 +214,13 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
|
||||||
pfifo->unload_context(dev);
|
pfifo->unload_context(dev);
|
||||||
|
|
||||||
for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {
|
for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {
|
||||||
if (dev_priv->eng[e]) {
|
if (!dev_priv->eng[e])
|
||||||
ret = dev_priv->eng[e]->fini(dev, e);
|
continue;
|
||||||
if (ret)
|
|
||||||
goto out_abort;
|
ret = dev_priv->eng[e]->fini(dev, e, true);
|
||||||
|
if (ret) {
|
||||||
|
NV_ERROR(dev, "... engine %d failed: %d\n", i, ret);
|
||||||
|
goto out_abort;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -312,7 +312,7 @@ struct nouveau_channel {
|
||||||
struct nouveau_exec_engine {
|
struct nouveau_exec_engine {
|
||||||
void (*destroy)(struct drm_device *, int engine);
|
void (*destroy)(struct drm_device *, int engine);
|
||||||
int (*init)(struct drm_device *, int engine);
|
int (*init)(struct drm_device *, int engine);
|
||||||
int (*fini)(struct drm_device *, int engine);
|
int (*fini)(struct drm_device *, int engine, bool suspend);
|
||||||
int (*context_new)(struct nouveau_channel *, int engine);
|
int (*context_new)(struct nouveau_channel *, int engine);
|
||||||
void (*context_del)(struct nouveau_channel *, int engine);
|
void (*context_del)(struct nouveau_channel *, int engine);
|
||||||
int (*object_new)(struct nouveau_channel *, int engine,
|
int (*object_new)(struct nouveau_channel *, int engine,
|
||||||
|
@ -1142,7 +1142,6 @@ extern int nvc0_fifo_unload_context(struct drm_device *);
|
||||||
|
|
||||||
/* nv04_graph.c */
|
/* nv04_graph.c */
|
||||||
extern int nv04_graph_create(struct drm_device *);
|
extern int nv04_graph_create(struct drm_device *);
|
||||||
extern void nv04_graph_fifo_access(struct drm_device *, bool);
|
|
||||||
extern int nv04_graph_object_new(struct nouveau_channel *, int, u32, u16);
|
extern int nv04_graph_object_new(struct nouveau_channel *, int, u32, u16);
|
||||||
extern int nv04_graph_mthd_page_flip(struct nouveau_channel *chan,
|
extern int nv04_graph_mthd_page_flip(struct nouveau_channel *chan,
|
||||||
u32 class, u32 mthd, u32 data);
|
u32 class, u32 mthd, u32 data);
|
||||||
|
|
|
@ -79,7 +79,7 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
stat = nv_rd32(dev, NV03_PMC_INTR_0);
|
stat = nv_rd32(dev, NV03_PMC_INTR_0);
|
||||||
if (!stat)
|
if (stat == 0 || stat == ~0)
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
|
|
||||||
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
|
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
|
||||||
|
|
|
@ -694,7 +694,7 @@ out_engine:
|
||||||
for (e = e - 1; e >= 0; e--) {
|
for (e = e - 1; e >= 0; e--) {
|
||||||
if (!dev_priv->eng[e])
|
if (!dev_priv->eng[e])
|
||||||
continue;
|
continue;
|
||||||
dev_priv->eng[e]->fini(dev, e);
|
dev_priv->eng[e]->fini(dev, e, false);
|
||||||
dev_priv->eng[e]->destroy(dev,e );
|
dev_priv->eng[e]->destroy(dev,e );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -746,7 +746,7 @@ static void nouveau_card_takedown(struct drm_device *dev)
|
||||||
engine->fifo.takedown(dev);
|
engine->fifo.takedown(dev);
|
||||||
for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {
|
for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {
|
||||||
if (dev_priv->eng[e]) {
|
if (dev_priv->eng[e]) {
|
||||||
dev_priv->eng[e]->fini(dev, e);
|
dev_priv->eng[e]->fini(dev, e, false);
|
||||||
dev_priv->eng[e]->destroy(dev,e );
|
dev_priv->eng[e]->destroy(dev,e );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -450,13 +450,13 @@ nv04_graph_context_del(struct nouveau_channel *chan, int engine)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
|
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
|
||||||
nv04_graph_fifo_access(dev, false);
|
nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
|
||||||
|
|
||||||
/* Unload the context if it's the currently active one */
|
/* Unload the context if it's the currently active one */
|
||||||
if (nv04_graph_channel(dev) == chan)
|
if (nv04_graph_channel(dev) == chan)
|
||||||
nv04_graph_unload_context(dev);
|
nv04_graph_unload_context(dev);
|
||||||
|
|
||||||
nv04_graph_fifo_access(dev, true);
|
nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
|
||||||
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
|
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
|
||||||
|
|
||||||
/* Free the context resources */
|
/* Free the context resources */
|
||||||
|
@ -538,24 +538,18 @@ nv04_graph_init(struct drm_device *dev, int engine)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
nv04_graph_fini(struct drm_device *dev, int engine)
|
nv04_graph_fini(struct drm_device *dev, int engine, bool suspend)
|
||||||
{
|
{
|
||||||
|
nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
|
||||||
|
if (!nv_wait(dev, NV04_PGRAPH_STATUS, ~0, 0) && suspend) {
|
||||||
|
nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
nv04_graph_unload_context(dev);
|
nv04_graph_unload_context(dev);
|
||||||
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
|
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
nv04_graph_fifo_access(struct drm_device *dev, bool enabled)
|
|
||||||
{
|
|
||||||
if (enabled)
|
|
||||||
nv_wr32(dev, NV04_PGRAPH_FIFO,
|
|
||||||
nv_rd32(dev, NV04_PGRAPH_FIFO) | 1);
|
|
||||||
else
|
|
||||||
nv_wr32(dev, NV04_PGRAPH_FIFO,
|
|
||||||
nv_rd32(dev, NV04_PGRAPH_FIFO) & ~1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
nv04_graph_mthd_set_ref(struct nouveau_channel *chan,
|
nv04_graph_mthd_set_ref(struct nouveau_channel *chan,
|
||||||
u32 class, u32 mthd, u32 data)
|
u32 class, u32 mthd, u32 data)
|
||||||
|
|
|
@ -708,8 +708,8 @@ static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
|
||||||
0x2c000000 | chan->id << 20 | subchan << 16 | 0x18c);
|
0x2c000000 | chan->id << 20 | subchan << 16 | 0x18c);
|
||||||
nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, inst);
|
nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, inst);
|
||||||
nv_mask(dev, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000);
|
nv_mask(dev, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000);
|
||||||
nv04_graph_fifo_access(dev, true);
|
nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
|
||||||
nv04_graph_fifo_access(dev, false);
|
nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
|
||||||
|
|
||||||
/* Restore the FIFO state */
|
/* Restore the FIFO state */
|
||||||
for (i = 0; i < ARRAY_SIZE(fifo); i++)
|
for (i = 0; i < ARRAY_SIZE(fifo); i++)
|
||||||
|
@ -879,13 +879,13 @@ nv10_graph_context_del(struct nouveau_channel *chan, int engine)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
|
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
|
||||||
nv04_graph_fifo_access(dev, false);
|
nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
|
||||||
|
|
||||||
/* Unload the context if it's the currently active one */
|
/* Unload the context if it's the currently active one */
|
||||||
if (nv10_graph_channel(dev) == chan)
|
if (nv10_graph_channel(dev) == chan)
|
||||||
nv10_graph_unload_context(dev);
|
nv10_graph_unload_context(dev);
|
||||||
|
|
||||||
nv04_graph_fifo_access(dev, true);
|
nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
|
||||||
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
|
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
|
||||||
|
|
||||||
/* Free the context resources */
|
/* Free the context resources */
|
||||||
|
@ -957,8 +957,13 @@ nv10_graph_init(struct drm_device *dev, int engine)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
nv10_graph_fini(struct drm_device *dev, int engine)
|
nv10_graph_fini(struct drm_device *dev, int engine, bool suspend)
|
||||||
{
|
{
|
||||||
|
nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
|
||||||
|
if (!nv_wait(dev, NV04_PGRAPH_STATUS, ~0, 0) && suspend) {
|
||||||
|
nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
nv10_graph_unload_context(dev);
|
nv10_graph_unload_context(dev);
|
||||||
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
|
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -454,13 +454,13 @@ nv20_graph_context_del(struct nouveau_channel *chan, int engine)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
|
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
|
||||||
nv04_graph_fifo_access(dev, false);
|
nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
|
||||||
|
|
||||||
/* Unload the context if it's the currently active one */
|
/* Unload the context if it's the currently active one */
|
||||||
if (nv10_graph_channel(dev) == chan)
|
if (nv10_graph_channel(dev) == chan)
|
||||||
nv20_graph_unload_context(dev);
|
nv20_graph_unload_context(dev);
|
||||||
|
|
||||||
nv04_graph_fifo_access(dev, true);
|
nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
|
||||||
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
|
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
|
||||||
|
|
||||||
/* Free the context resources */
|
/* Free the context resources */
|
||||||
|
@ -654,8 +654,13 @@ nv30_graph_init(struct drm_device *dev, int engine)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
nv20_graph_fini(struct drm_device *dev, int engine)
|
nv20_graph_fini(struct drm_device *dev, int engine, bool suspend)
|
||||||
{
|
{
|
||||||
|
nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
|
||||||
|
if (!nv_wait(dev, NV04_PGRAPH_STATUS, ~0, 0) && suspend) {
|
||||||
|
nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
nv20_graph_unload_context(dev);
|
nv20_graph_unload_context(dev);
|
||||||
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
|
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -753,6 +758,7 @@ nv20_graph_create(struct drm_device *dev)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
NV_ERROR(dev, "PGRAPH: unknown chipset\n");
|
NV_ERROR(dev, "PGRAPH: unknown chipset\n");
|
||||||
|
kfree(pgraph);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -774,6 +780,7 @@ nv20_graph_create(struct drm_device *dev)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
NV_ERROR(dev, "PGRAPH: unknown chipset\n");
|
NV_ERROR(dev, "PGRAPH: unknown chipset\n");
|
||||||
|
kfree(pgraph);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,89 +35,6 @@ struct nv40_graph_engine {
|
||||||
u32 grctx_size;
|
u32 grctx_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct nouveau_channel *
|
|
||||||
nv40_graph_channel(struct drm_device *dev)
|
|
||||||
{
|
|
||||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
||||||
struct nouveau_gpuobj *grctx;
|
|
||||||
uint32_t inst;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
inst = nv_rd32(dev, NV40_PGRAPH_CTXCTL_CUR);
|
|
||||||
if (!(inst & NV40_PGRAPH_CTXCTL_CUR_LOADED))
|
|
||||||
return NULL;
|
|
||||||
inst = (inst & NV40_PGRAPH_CTXCTL_CUR_INSTANCE) << 4;
|
|
||||||
|
|
||||||
for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
|
|
||||||
if (!dev_priv->channels.ptr[i])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
grctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_GR];
|
|
||||||
if (grctx && grctx->pinst == inst)
|
|
||||||
return dev_priv->channels.ptr[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
nv40_graph_transfer_context(struct drm_device *dev, uint32_t inst, int save)
|
|
||||||
{
|
|
||||||
uint32_t old_cp, tv = 1000, tmp;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
old_cp = nv_rd32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER);
|
|
||||||
nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
|
|
||||||
|
|
||||||
tmp = nv_rd32(dev, NV40_PGRAPH_CTXCTL_0310);
|
|
||||||
tmp |= save ? NV40_PGRAPH_CTXCTL_0310_XFER_SAVE :
|
|
||||||
NV40_PGRAPH_CTXCTL_0310_XFER_LOAD;
|
|
||||||
nv_wr32(dev, NV40_PGRAPH_CTXCTL_0310, tmp);
|
|
||||||
|
|
||||||
tmp = nv_rd32(dev, NV40_PGRAPH_CTXCTL_0304);
|
|
||||||
tmp |= NV40_PGRAPH_CTXCTL_0304_XFER_CTX;
|
|
||||||
nv_wr32(dev, NV40_PGRAPH_CTXCTL_0304, tmp);
|
|
||||||
|
|
||||||
nouveau_wait_for_idle(dev);
|
|
||||||
|
|
||||||
for (i = 0; i < tv; i++) {
|
|
||||||
if (nv_rd32(dev, NV40_PGRAPH_CTXCTL_030C) == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, old_cp);
|
|
||||||
|
|
||||||
if (i == tv) {
|
|
||||||
uint32_t ucstat = nv_rd32(dev, NV40_PGRAPH_CTXCTL_UCODE_STAT);
|
|
||||||
NV_ERROR(dev, "Failed: Instance=0x%08x Save=%d\n", inst, save);
|
|
||||||
NV_ERROR(dev, "IP: 0x%02x, Opcode: 0x%08x\n",
|
|
||||||
ucstat >> NV40_PGRAPH_CTXCTL_UCODE_STAT_IP_SHIFT,
|
|
||||||
ucstat & NV40_PGRAPH_CTXCTL_UCODE_STAT_OP_MASK);
|
|
||||||
NV_ERROR(dev, "0x40030C = 0x%08x\n",
|
|
||||||
nv_rd32(dev, NV40_PGRAPH_CTXCTL_030C));
|
|
||||||
return -EBUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
nv40_graph_unload_context(struct drm_device *dev)
|
|
||||||
{
|
|
||||||
uint32_t inst;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
inst = nv_rd32(dev, NV40_PGRAPH_CTXCTL_CUR);
|
|
||||||
if (!(inst & NV40_PGRAPH_CTXCTL_CUR_LOADED))
|
|
||||||
return 0;
|
|
||||||
inst &= NV40_PGRAPH_CTXCTL_CUR_INSTANCE;
|
|
||||||
|
|
||||||
ret = nv40_graph_transfer_context(dev, inst, 1);
|
|
||||||
|
|
||||||
nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, inst);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
nv40_graph_context_new(struct nouveau_channel *chan, int engine)
|
nv40_graph_context_new(struct nouveau_channel *chan, int engine)
|
||||||
{
|
{
|
||||||
|
@ -163,16 +80,16 @@ nv40_graph_context_del(struct nouveau_channel *chan, int engine)
|
||||||
struct nouveau_gpuobj *grctx = chan->engctx[engine];
|
struct nouveau_gpuobj *grctx = chan->engctx[engine];
|
||||||
struct drm_device *dev = chan->dev;
|
struct drm_device *dev = chan->dev;
|
||||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||||
|
u32 inst = 0x01000000 | (grctx->pinst >> 4);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
|
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
|
||||||
nv04_graph_fifo_access(dev, false);
|
nv_mask(dev, 0x400720, 0x00000000, 0x00000001);
|
||||||
|
if (nv_rd32(dev, 0x40032c) == inst)
|
||||||
/* Unload the context if it's the currently active one */
|
nv_mask(dev, 0x40032c, 0x01000000, 0x00000000);
|
||||||
if (nv40_graph_channel(dev) == chan)
|
if (nv_rd32(dev, 0x400330) == inst)
|
||||||
nv40_graph_unload_context(dev);
|
nv_mask(dev, 0x400330, 0x01000000, 0x00000000);
|
||||||
|
nv_mask(dev, 0x400720, 0x00000001, 0x00000001);
|
||||||
nv04_graph_fifo_access(dev, true);
|
|
||||||
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
|
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
|
||||||
|
|
||||||
/* Free the context resources */
|
/* Free the context resources */
|
||||||
|
@ -429,9 +346,20 @@ nv40_graph_init(struct drm_device *dev, int engine)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
nv40_graph_fini(struct drm_device *dev, int engine)
|
nv40_graph_fini(struct drm_device *dev, int engine, bool suspend)
|
||||||
{
|
{
|
||||||
nv40_graph_unload_context(dev);
|
u32 inst = nv_rd32(dev, 0x40032c);
|
||||||
|
if (inst & 0x01000000) {
|
||||||
|
nv_wr32(dev, 0x400720, 0x00000000);
|
||||||
|
nv_wr32(dev, 0x400784, inst);
|
||||||
|
nv_mask(dev, 0x400310, 0x00000020, 0x00000020);
|
||||||
|
nv_mask(dev, 0x400304, 0x00000001, 0x00000001);
|
||||||
|
if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000)) {
|
||||||
|
u32 insn = nv_rd32(dev, 0x400308);
|
||||||
|
NV_ERROR(dev, "PGRAPH: ctxprog timeout 0x%08x\n", insn);
|
||||||
|
}
|
||||||
|
nv_mask(dev, 0x40032c, 0x01000000, 0x00000000);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -137,7 +137,7 @@ nv40_mpeg_init(struct drm_device *dev, int engine)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
nv40_mpeg_fini(struct drm_device *dev, int engine)
|
nv40_mpeg_fini(struct drm_device *dev, int engine, bool suspend)
|
||||||
{
|
{
|
||||||
/*XXX: context save? */
|
/*XXX: context save? */
|
||||||
nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
|
nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
|
||||||
|
|
|
@ -125,7 +125,6 @@ static void
|
||||||
nv50_graph_init_reset(struct drm_device *dev)
|
nv50_graph_init_reset(struct drm_device *dev)
|
||||||
{
|
{
|
||||||
uint32_t pmc_e = NV_PMC_ENABLE_PGRAPH | (1 << 21);
|
uint32_t pmc_e = NV_PMC_ENABLE_PGRAPH | (1 << 21);
|
||||||
|
|
||||||
NV_DEBUG(dev, "\n");
|
NV_DEBUG(dev, "\n");
|
||||||
|
|
||||||
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & ~pmc_e);
|
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & ~pmc_e);
|
||||||
|
@ -255,9 +254,13 @@ nv50_graph_init(struct drm_device *dev, int engine)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
nv50_graph_fini(struct drm_device *dev, int engine)
|
nv50_graph_fini(struct drm_device *dev, int engine, bool suspend)
|
||||||
{
|
{
|
||||||
NV_DEBUG(dev, "\n");
|
nv_mask(dev, 0x400500, 0x00010001, 0x00000000);
|
||||||
|
if (!nv_wait(dev, 0x400700, ~0, 0) && suspend) {
|
||||||
|
nv_mask(dev, 0x400500, 0x00010001, 0x00010001);
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
nv50_graph_unload_context(dev);
|
nv50_graph_unload_context(dev);
|
||||||
nv_wr32(dev, 0x40013c, 0x00000000);
|
nv_wr32(dev, 0x40013c, 0x00000000);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -160,7 +160,7 @@ nv50_mpeg_init(struct drm_device *dev, int engine)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
nv50_mpeg_fini(struct drm_device *dev, int engine)
|
nv50_mpeg_fini(struct drm_device *dev, int engine, bool suspend)
|
||||||
{
|
{
|
||||||
/*XXX: context save for s/r */
|
/*XXX: context save for s/r */
|
||||||
nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
|
nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
|
||||||
|
|
|
@ -318,6 +318,8 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_entry *entry)
|
||||||
uint32_t tmp;
|
uint32_t tmp;
|
||||||
|
|
||||||
tmp = nv_rd32(dev, 0x61c700 + (or * 0x800));
|
tmp = nv_rd32(dev, 0x61c700 + (or * 0x800));
|
||||||
|
if (!tmp)
|
||||||
|
tmp = nv_rd32(dev, 0x610798 + (or * 8));
|
||||||
|
|
||||||
switch ((tmp & 0x00000f00) >> 8) {
|
switch ((tmp & 0x00000f00) >> 8) {
|
||||||
case 8:
|
case 8:
|
||||||
|
|
|
@ -138,7 +138,7 @@ nv84_crypt_isr(struct drm_device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
nv84_crypt_fini(struct drm_device *dev, int engine)
|
nv84_crypt_fini(struct drm_device *dev, int engine, bool suspend)
|
||||||
{
|
{
|
||||||
nv_wr32(dev, 0x102140, 0x00000000);
|
nv_wr32(dev, 0x102140, 0x00000000);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -140,7 +140,7 @@ nva3_copy_init(struct drm_device *dev, int engine)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
nva3_copy_fini(struct drm_device *dev, int engine)
|
nva3_copy_fini(struct drm_device *dev, int engine, bool suspend)
|
||||||
{
|
{
|
||||||
nv_mask(dev, 0x104048, 0x00000003, 0x00000000);
|
nv_mask(dev, 0x104048, 0x00000003, 0x00000000);
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,7 @@ nvc0_copy_init(struct drm_device *dev, int engine)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
nvc0_copy_fini(struct drm_device *dev, int engine)
|
nvc0_copy_fini(struct drm_device *dev, int engine, bool suspend)
|
||||||
{
|
{
|
||||||
struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
|
struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
|
||||||
|
|
||||||
|
|
|
@ -304,7 +304,7 @@ nvc0_graph_object_new(struct nouveau_channel *chan, int engine,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
nvc0_graph_fini(struct drm_device *dev, int engine)
|
nvc0_graph_fini(struct drm_device *dev, int engine, bool suspend)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue