/*
* Copyright (C) 2008 Maarten Maathuis.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#define NOUVEAU_DMA_DEBUG (nouveau_reg_debug & NOUVEAU_REG_DEBUG_EVO)
#include "nv50_display.h"
#include "nouveau_crtc.h"
#include "nouveau_encoder.h"
#include "nouveau_connector.h"
#include "nouveau_fb.h"
#include "nouveau_fbcon.h"
#include "nouveau_ramht.h"
#include "drm_crtc_helper.h"
static void nv50_display_isr(struct drm_device *);
static void nv50_display_bh(unsigned long);
static inline int
nv50_sor_nr(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
if (dev_priv->chipset < 0x90 ||
dev_priv->chipset == 0x92 ||
dev_priv->chipset == 0xa0)
return 2;
return 4;
}
u32
nv50_display_active_crtcs(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
u32 mask = 0;
int i;
if (dev_priv->chipset < 0x90 ||
dev_priv->chipset == 0x92 ||
dev_priv->chipset == 0xa0) {
for (i = 0; i < 2; i++)
mask |= nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_C(i));
} else {
for (i = 0; i < 4; i++)
mask |= nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_C(i));
}
for (i = 0; i < 3; i++)
mask |= nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_C(i));
return mask & 3;
}
static int
evo_icmd(struct drm_device *dev, int ch, u32 mthd, u32 data)
{
int ret = 0;
nv_mask(dev, 0x610300 + (ch * 0x08), 0x00000001, 0x00000001);
nv_wr32(dev, 0x610304 + (ch * 0x08), data);
nv_wr32(dev, 0x610300 + (ch * 0x08), 0x80000001 | mthd);
if (!nv_wait(dev, 0x610300 + (ch * 0x08), 0x80000000, 0x00000000))
ret = -EBUSY;
if (ret || (nouveau_reg_debug & NOUVEAU_REG_DEBUG_EVO))
NV_INFO(dev, "EvoPIO: %d 0x%04x 0x%08x\n", ch, mthd, data);
nv_mask(dev, 0x610300 + (ch * 0x08), 0x00000001, 0x00000000);
return ret;
}
int
nv50_display_early_init(struct drm_device *dev)
{
u32 ctrl = nv_rd32(dev, 0x610200);
int i;
/* check if master evo channel is already active, a good a sign as any
* that the display engine is in a weird state (hibernate/kexec), if
* it is, do our best to reset the display engine...
*/
if ((ctrl & 0x00000003) == 0x00000003) {
NV_INFO(dev, "PDISP: EVO(0) 0x%08x, resetting...\n", ctrl);
/* deactivate both heads first, PDISP will disappear forever
* (well, until you power cycle) on some boards as soon as
* PMC_ENABLE is hit unless they are..
*/
for (i = 0; i < 2; i++) {
evo_icmd(dev, 0, 0x0880 + (i * 0x400), 0x05000000);
evo_icmd(dev, 0, 0x089c + (i * 0x400), 0);
evo_icmd(dev, 0, 0x0840 + (i * 0x400), 0);
evo_icmd(dev, 0, 0x0844 + (i * 0x400), 0);
evo_icmd(dev, 0, 0x085c + (i * 0x400), 0);
evo_icmd(dev, 0, 0x0874 + (i * 0x400),