summaryrefslogtreecommitdiff
path: root/shared-core
diff options
context:
space:
mode:
Diffstat (limited to 'shared-core')
-rw-r--r--shared-core/drm.h86
-rw-r--r--shared-core/nouveau_dma.h5
-rw-r--r--shared-core/nouveau_drm.h4
-rw-r--r--shared-core/nouveau_drv.h28
-rw-r--r--shared-core/nouveau_irq.c80
-rw-r--r--shared-core/nouveau_mem.c95
-rw-r--r--shared-core/nouveau_notifier.c2
-rw-r--r--shared-core/nouveau_object.c2
-rw-r--r--shared-core/nouveau_reg.h238
-rw-r--r--shared-core/nouveau_state.c57
-rw-r--r--shared-core/nv50_fifo.c4
11 files changed, 546 insertions, 55 deletions
diff --git a/shared-core/drm.h b/shared-core/drm.h
index 382e3fa1..017c012b 100644
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@ -1034,6 +1034,30 @@ struct drm_gem_open {
#define DRM_MODE_TYPE_USERDEF (1<<5)
#define DRM_MODE_TYPE_DRIVER (1<<6)
+/* Video mode flags */
+/* bit compatible with the xorg definitions. */
+#define DRM_MODE_FLAG_PHSYNC (1<<0)
+#define DRM_MODE_FLAG_NHSYNC (1<<1)
+#define DRM_MODE_FLAG_PVSYNC (1<<2)
+#define DRM_MODE_FLAG_NVSYNC (1<<3)
+#define DRM_MODE_FLAG_INTERLACE (1<<4)
+#define DRM_MODE_FLAG_DBLSCAN (1<<5)
+#define DRM_MODE_FLAG_CSYNC (1<<6)
+#define DRM_MODE_FLAG_PCSYNC (1<<7)
+#define DRM_MODE_FLAG_NCSYNC (1<<8)
+#define DRM_MODE_FLAG_HSKEW (1<<9) /* hskew provided */
+#define DRM_MODE_FLAG_BCAST (1<<10)
+#define DRM_MODE_FLAG_PIXMUX (1<<11)
+#define DRM_MODE_FLAG_DBLCLK (1<<12)
+#define DRM_MODE_FLAG_CLKDIV2 (1<<13)
+
+/* DPMS flags */
+/* bit compatible with the xorg definitions. */
+#define DRM_MODE_DPMS_ON 0
+#define DRM_MODE_DPMS_STANDBY 1
+#define DRM_MODE_DPMS_SUSPEND 2
+#define DRM_MODE_DPMS_OFF 3
+
struct drm_mode_modeinfo {
unsigned int clock;
unsigned short hdisplay, hsync_start, hsync_end, htotal, hskew;
@@ -1057,47 +1081,63 @@ struct drm_mode_card_res {
int count_encoders;
int min_width, max_width;
int min_height, max_height;
- uint32_t generation;
};
struct drm_mode_crtc {
uint64_t set_connectors_ptr;
+ int count_connectors;
unsigned int crtc_id; /**< Id */
unsigned int fb_id; /**< Id of framebuffer */
int x, y; /**< Position on the frameuffer */
- uint32_t generation;
-
- int count_connectors;
- unsigned int connectors; /**< Connectors that are connected */
-
- int count_possibles;
- unsigned int possibles; /**< Connectors that can be connected */
uint32_t gamma_size;
int mode_valid;
struct drm_mode_modeinfo mode;
};
-struct drm_mode_get_encoder {
-
- uint32_t generation;
-
- uint32_t encoder_type;
- uint32_t encoder_id;
-
- unsigned int crtc; /**< Id of crtc */
- uint32_t crtcs;
- uint32_t clones;
-};
-
#define DRM_MODE_ENCODER_NONE 0
#define DRM_MODE_ENCODER_DAC 1
#define DRM_MODE_ENCODER_TMDS 2
#define DRM_MODE_ENCODER_LVDS 3
#define DRM_MODE_ENCODER_TVDAC 4
+struct drm_mode_get_encoder {
+
+ unsigned int encoder_type;
+ unsigned int encoder_id;
+
+ unsigned int crtc_id; /**< Id of crtc */
+
+ uint32_t possible_crtcs;
+ uint32_t possible_clones;
+};
+
+/* This is for connectors with multiple signal types. */
+/* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */
+#define DRM_MODE_SUBCONNECTOR_Automatic 0
+#define DRM_MODE_SUBCONNECTOR_Unknown 0
+#define DRM_MODE_SUBCONNECTOR_DVID 3
+#define DRM_MODE_SUBCONNECTOR_DVIA 4
+#define DRM_MODE_SUBCONNECTOR_Composite 5
+#define DRM_MODE_SUBCONNECTOR_SVIDEO 6
+#define DRM_MODE_SUBCONNECTOR_Component 8
+
+#define DRM_MODE_CONNECTOR_Unknown 0
+#define DRM_MODE_CONNECTOR_VGA 1
+#define DRM_MODE_CONNECTOR_DVII 2
+#define DRM_MODE_CONNECTOR_DVID 3
+#define DRM_MODE_CONNECTOR_DVIA 4
+#define DRM_MODE_CONNECTOR_Composite 5
+#define DRM_MODE_CONNECTOR_SVIDEO 6
+#define DRM_MODE_CONNECTOR_LVDS 7
+#define DRM_MODE_CONNECTOR_Component 8
+#define DRM_MODE_CONNECTOR_9PinDIN 9
+#define DRM_MODE_CONNECTOR_DisplayPort 10
+#define DRM_MODE_CONNECTOR_HDMIA 11
+#define DRM_MODE_CONNECTOR_HDMIB 12
+
struct drm_mode_get_connector {
uint64_t encoders_ptr;
@@ -1109,13 +1149,11 @@ struct drm_mode_get_connector {
int count_props;
int count_encoders;
- unsigned int encoder; /**< Current Encoder */
- unsigned int connector; /**< Id */
+ unsigned int encoder_id; /**< Current Encoder */
+ unsigned int connector_id; /**< Id */
unsigned int connector_type;
unsigned int connector_type_id;
- uint32_t generation;
-
unsigned int connection;
unsigned int mm_width, mm_height; /**< HxW in millimeters */
unsigned int subpixel;
diff --git a/shared-core/nouveau_dma.h b/shared-core/nouveau_dma.h
index ce3c58cb..07652c2b 100644
--- a/shared-core/nouveau_dma.h
+++ b/shared-core/nouveau_dma.h
@@ -93,4 +93,9 @@ typedef enum {
} \
} while(0)
+/* This should allow easy switching to a real fifo in the future. */
+#define OUT_MODE(mthd, val) do { \
+ nv50_display_command(dev_priv, mthd, val); \
+} while(0)
+
#endif
diff --git a/shared-core/nouveau_drm.h b/shared-core/nouveau_drm.h
index cf762052..bbb51bc4 100644
--- a/shared-core/nouveau_drm.h
+++ b/shared-core/nouveau_drm.h
@@ -88,9 +88,11 @@ struct drm_nouveau_gpuobj_free {
#define NOUVEAU_MEM_INSTANCE 0x00000200 /* internal */
#define NOUVEAU_MEM_NOTIFIER 0x00000400 /* internal */
#define NOUVEAU_MEM_NOVM 0x00000800 /* internal */
+#define NOUVEAU_MEM_USER 0x00001000 /* internal */
#define NOUVEAU_MEM_INTERNAL (NOUVEAU_MEM_INSTANCE | \
NOUVEAU_MEM_NOTIFIER | \
- NOUVEAU_MEM_NOVM)
+ NOUVEAU_MEM_NOVM | \
+ NOUVEAU_MEM_USER)
struct drm_nouveau_mem_alloc {
int flags;
diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h
index a51e552c..33e2a5b6 100644
--- a/shared-core/nouveau_drv.h
+++ b/shared-core/nouveau_drv.h
@@ -41,6 +41,9 @@
#include "nouveau_drm.h"
#include "nouveau_reg.h"
+#include "nouveau_bios.h"
+
+#define MAX_NUM_DCB_ENTRIES 16
struct mem_block {
struct mem_block *next;
@@ -310,6 +313,28 @@ struct drm_nouveau_private {
struct nouveau_config config;
struct list_head gpuobj_list;
+
+ void *display_priv; /* internal modesetting */
+ void *kms_priv; /* related to public interface */
+
+ /* Hook these up to the "public interface" to accomodate a certain allocation style. */
+ /* This is to avoid polluting the internal interface. */
+ void *(*alloc_crtc) (struct drm_device *dev);
+ void *(*alloc_output) (struct drm_device *dev);
+ void *(*alloc_connector) (struct drm_device *dev);
+
+ void (*free_crtc) (void *crtc);
+ void (*free_output) (void *output);
+ void (*free_connector) (void *connector);
+
+ struct bios bios;
+
+ struct {
+ int entries;
+ struct dcb_entry entry[MAX_NUM_DCB_ENTRIES];
+ unsigned char i2c_read[MAX_NUM_DCB_ENTRIES];
+ unsigned char i2c_write[MAX_NUM_DCB_ENTRIES];
+ } dcb_table;
};
#define NOUVEAU_CHECK_INITIALISED_WITH_RETURN do { \
@@ -350,9 +375,10 @@ extern int nouveau_mem_init_heap(struct mem_block **, uint64_t start,
uint64_t size);
extern struct mem_block *nouveau_mem_alloc_block(struct mem_block *,
uint64_t size, int align2,
- struct drm_file *);
+ struct drm_file *, int tail);
extern void nouveau_mem_takedown(struct mem_block **heap);
extern void nouveau_mem_free_block(struct mem_block *);
+extern struct mem_block* find_block_by_handle(struct mem_block *heap, drm_handle_t handle);
extern uint64_t nouveau_mem_fb_amount(struct drm_device *);
extern void nouveau_mem_release(struct drm_file *, struct mem_block *heap);
extern int nouveau_ioctl_mem_alloc(struct drm_device *, void *data,
diff --git a/shared-core/nouveau_irq.c b/shared-core/nouveau_irq.c
index 2a3d8a0b..4c46da8d 100644
--- a/shared-core/nouveau_irq.c
+++ b/shared-core/nouveau_irq.c
@@ -37,6 +37,11 @@
#include "nouveau_reg.h"
#include "nouveau_swmthd.h"
+/* needed for interrupt based vpll changes */
+#include "nv50_display.h"
+#include "nv50_crtc.h"
+#include "nv50_output.h"
+
void
nouveau_irq_preinstall(struct drm_device *dev)
{
@@ -503,11 +508,82 @@ static void
nouveau_nv50_display_irq_handler(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t val = NV_READ(NV50_DISPLAY_SUPERVISOR);
+ uint32_t val = NV_READ(NV50_PDISPLAY_SUPERVISOR);
DRM_INFO("NV50_DISPLAY_INTR - 0x%08X\n", val);
- NV_WRITE(NV50_DISPLAY_SUPERVISOR, val);
+ /* vblank interrupts */
+ if (val & NV50_PDISPLAY_SUPERVISOR_CRTCn) {
+ NV_WRITE(NV50_PDISPLAY_SUPERVISOR, val & NV50_PDISPLAY_SUPERVISOR_CRTCn);
+ val &= ~NV50_PDISPLAY_SUPERVISOR_CRTCn;
+ }
+
+ /* clock setting amongst other things. */
+ if (val & NV50_PDISPLAY_SUPERVISOR_CLK_MASK) {
+ uint32_t state = (val & NV50_PDISPLAY_SUPERVISOR_CLK_MASK) >> NV50_PDISPLAY_SUPERVISOR_CLK_MASK__SHIFT;
+
+ NV50_DEBUG("state %d\n", state);
+
+ /* Set pll */
+ if (state == 2) {
+ struct nv50_display *display = nv50_get_display(dev);
+ struct nv50_output *output = NULL;
+ struct nv50_crtc *crtc = NULL;
+ int crtc_index;
+
+ uint32_t unk30 = NV_READ(NV50_PDISPLAY_UNK30_CTRL);
+
+ for (crtc_index = 0; crtc_index < 2; crtc_index++) {
+ bool clock_change = false;
+ bool clock_ack = false;
+
+ if (crtc_index == 0 && (unk30 & NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK0))
+ clock_change = true;
+
+ if (crtc_index == 1 && (unk30 & NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK1))
+ clock_change = true;
+
+ if (clock_change)
+ clock_ack = true;
+
+ if (display->last_crtc == crtc_index)
+ clock_ack = true;
+
+ list_for_each_entry(crtc, &display->crtcs, item) {
+ if (crtc->index == crtc_index)
+ break;
+ }
+
+ if (clock_change)
+ crtc->set_clock(crtc);
+
+ NV50_DEBUG("index %d clock_change %d clock_ack %d\n", crtc_index, clock_change, clock_ack);
+
+ if (!clock_ack)
+ continue;
+
+ crtc->set_clock_mode(crtc);
+
+ list_for_each_entry(output, &display->outputs, item) {
+ if (!output->crtc)
+ continue;
+
+ if (output->crtc == crtc)
+ output->set_clock_mode(output);
+ }
+ }
+ }
+
+ NV_WRITE(NV50_PDISPLAY_UNK30_CTRL, NV50_PDISPLAY_UNK30_CTRL_PENDING);
+ NV_WRITE(NV50_PDISPLAY_SUPERVISOR, val & NV50_PDISPLAY_SUPERVISOR_CLK_MASK);
+
+ val &= ~NV50_PDISPLAY_SUPERVISOR_CLK_MASK;
+ }
+
+ if (val)
+ DRM_ERROR("unsupported NV50_DISPLAY_INTR - 0x%08X\n", val);
+
+ NV_WRITE(NV50_PDISPLAY_SUPERVISOR, val);
}
static void
diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c
index 2cf8807d..861d699f 100644
--- a/shared-core/nouveau_mem.c
+++ b/shared-core/nouveau_mem.c
@@ -34,9 +34,12 @@
#include "drm.h"
#include "drm_sarea.h"
#include "nouveau_drv.h"
+#include "nv50_kms_wrapper.h"
-static struct mem_block *split_block(struct mem_block *p, uint64_t start, uint64_t size,
- struct drm_file *file_priv)
+
+static struct mem_block *
+split_block(struct mem_block *p, uint64_t start, uint64_t size,
+ struct drm_file *file_priv)
{
/* Maybe cut off the start of an existing block */
if (start > p->start) {
@@ -77,10 +80,9 @@ out:
return p;
}
-struct mem_block *nouveau_mem_alloc_block(struct mem_block *heap,
- uint64_t size,
- int align2,
- struct drm_file *file_priv)
+struct mem_block *
+nouveau_mem_alloc_block(struct mem_block *heap, uint64_t size,
+ int align2, struct drm_file *file_priv, int tail)
{
struct mem_block *p;
uint64_t mask = (1 << align2) - 1;
@@ -88,10 +90,22 @@ struct mem_block *nouveau_mem_alloc_block(struct mem_block *heap,
if (!heap)
return NULL;
- list_for_each(p, heap) {
- uint64_t start = (p->start + mask) & ~mask;
- if (p->file_priv == 0 && start + size <= p->start + p->size)
- return split_block(p, start, size, file_priv);
+ if (tail) {
+ list_for_each_prev(p, heap) {
+ uint64_t start = ((p->start + p->size) - size) & ~mask;
+
+ if (p->file_priv == 0 && start >= p->start &&
+ start + size <= p->start + p->size)
+ return split_block(p, start, size, file_priv);
+ }
+ } else {
+ list_for_each(p, heap) {
+ uint64_t start = (p->start + mask) & ~mask;
+
+ if (p->file_priv == 0 &&
+ start + size <= p->start + p->size)
+ return split_block(p, start, size, file_priv);
+ }
}
return NULL;
@@ -108,6 +122,17 @@ static struct mem_block *find_block(struct mem_block *heap, uint64_t start)
return NULL;
}
+struct mem_block *find_block_by_handle(struct mem_block *heap, drm_handle_t handle)
+{
+ struct mem_block *p;
+
+ list_for_each(p, heap)
+ if (p->map_handle == handle)
+ return p;
+
+ return NULL;
+}
+
void nouveau_mem_free_block(struct mem_block *p)
{
p->file_priv = NULL;
@@ -563,13 +588,13 @@ int nouveau_mem_init(struct drm_device *dev)
return 0;
}
-struct mem_block* nouveau_mem_alloc(struct drm_device *dev, int alignment,
- uint64_t size, int flags,
- struct drm_file *file_priv)
+struct mem_block *
+nouveau_mem_alloc(struct drm_device *dev, int alignment, uint64_t size,
+ int flags, struct drm_file *file_priv)
{
- struct mem_block *block;
- int type;
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct mem_block *block;
+ int type, tail = !(flags & NOUVEAU_MEM_USER);
/*
* Make things easier on ourselves: all allocations are page-aligned.
@@ -600,14 +625,14 @@ struct mem_block* nouveau_mem_alloc(struct drm_device *dev, int alignment,
#define NOUVEAU_MEM_ALLOC_AGP {\
type=NOUVEAU_MEM_AGP;\
block = nouveau_mem_alloc_block(dev_priv->agp_heap, size,\
- alignment, file_priv); \
+ alignment, file_priv, tail); \
if (block) goto alloc_ok;\
}
#define NOUVEAU_MEM_ALLOC_PCI {\
type = NOUVEAU_MEM_PCI;\
block = nouveau_mem_alloc_block(dev_priv->pci_heap, size, \
- alignment, file_priv); \
+ alignment, file_priv, tail); \
if ( block ) goto alloc_ok;\
}
@@ -616,11 +641,11 @@ struct mem_block* nouveau_mem_alloc(struct drm_device *dev, int alignment,
if (!(flags&NOUVEAU_MEM_MAPPED)) {\
block = nouveau_mem_alloc_block(dev_priv->fb_nomap_heap,\
size, alignment, \
- file_priv); \
+ file_priv, tail); \
if (block) goto alloc_ok;\
}\
block = nouveau_mem_alloc_block(dev_priv->fb_heap, size,\
- alignment, file_priv);\
+ alignment, file_priv, tail);\
if (block) goto alloc_ok;\
}
@@ -707,6 +732,30 @@ void nouveau_mem_free(struct drm_device* dev, struct mem_block* block)
DRM_DEBUG("freeing 0x%llx type=0x%08x\n", block->start, block->flags);
+ /* Check if the deallocations cause problems for our modesetting system. */
+ if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+ if (dev_priv->card_type >= NV_50) {
+ struct nv50_crtc *crtc = NULL;
+ struct nv50_display *display = nv50_get_display(dev);
+
+ list_for_each_entry(crtc, &display->crtcs, item) {
+ if (crtc->fb->block == block) {
+ crtc->fb->block = NULL;
+
+ if (!crtc->blanked)
+ crtc->blank(crtc, true);
+ }
+
+ if (crtc->cursor->block == block) {
+ crtc->cursor->block = NULL;
+
+ if (crtc->cursor->visible)
+ crtc->cursor->hide(crtc);
+ }
+ }
+ }
+ }
+
if (block->flags&NOUVEAU_MEM_MAPPED)
drm_rmmap(dev, block->map);
@@ -738,7 +787,9 @@ out_free:
* Ioctls
*/
-int nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv)
+int
+nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
struct drm_nouveau_mem_alloc *alloc = data;
struct mem_block *block;
@@ -748,8 +799,8 @@ int nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data, struct drm_file
if (alloc->flags & NOUVEAU_MEM_INTERNAL)
return -EINVAL;
- block=nouveau_mem_alloc(dev, alloc->alignment, alloc->size,
- alloc->flags, file_priv);
+ block = nouveau_mem_alloc(dev, alloc->alignment, alloc->size,
+ alloc->flags | NOUVEAU_MEM_USER, file_priv);
if (!block)
return -ENOMEM;
alloc->map_handle=block->map_handle;
diff --git a/shared-core/nouveau_notifier.c b/shared-core/nouveau_notifier.c
index 82c8ab7d..edece4da 100644
--- a/shared-core/nouveau_notifier.c
+++ b/shared-core/nouveau_notifier.c
@@ -94,7 +94,7 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
}
mem = nouveau_mem_alloc_block(chan->notifier_heap, count*32, 0,
- (struct drm_file *)-2);
+ (struct drm_file *)-2, 0);
if (!mem) {
DRM_ERROR("Channel %d notifier block full\n", chan->id);
return -ENOMEM;
diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c
index 09f9027a..5664bfc8 100644
--- a/shared-core/nouveau_object.c
+++ b/shared-core/nouveau_object.c
@@ -248,7 +248,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
/* Allocate a chunk of the PRAMIN aperture */
gpuobj->im_pramin = nouveau_mem_alloc_block(pramin, size,
drm_order(align),
- (struct drm_file *)-2);
+ (struct drm_file *)-2, 0);
if (!gpuobj->im_pramin) {
nouveau_gpuobj_del(dev, &gpuobj);
return -ENOMEM;
diff --git a/shared-core/nouveau_reg.h b/shared-core/nouveau_reg.h
index 1ae0177c..6ed23e26 100644
--- a/shared-core/nouveau_reg.h
+++ b/shared-core/nouveau_reg.h
@@ -116,6 +116,9 @@
#define NV04_PBUS_PCI_NV_1 0x00001804
#define NV04_PBUS_PCI_NV_19 0x0000184C
+#define NV04_PBUS_PCI_NV_20 0x00001850
+# define NV04_PBUS_PCI_NV_20_ROM_SHADOW_DISABLED (0 << 0)
+# define NV04_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED (1 << 0)
#define NV04_PTIMER_INTR_0 0x00009100
#define NV04_PTIMER_INTR_EN_0 0x00009140
@@ -542,6 +545,8 @@
/* This name is a partial guess. */
#define NV50_DISPLAY_SUPERVISOR 0x00610024
+#define NV04_PRAMIN 0x00700000
+
/* Fifo commands. These are not regs, neither masks */
#define NV03_FIFO_CMD_JUMP 0x20000000
#define NV03_FIFO_CMD_JUMP_OFFSET_MASK 0x1ffffffc
@@ -591,3 +596,236 @@
#define NV40_RAMFC_UNK_48 0x48
#define NV40_RAMFC_UNK_4C 0x4C
#define NV40_RAMFC_UNK_50 0x50
+
+/* This is a partial import from rules-ng, a few things may be duplicated.
+ * Eventually we should completely import everything from rules-ng.
+ * For the moment check rules-ng for docs.
+ */
+
+#define NV50_PMC 0x00000000
+#define NV50_PMC__LEN 0x1
+#define NV50_PMC__ESIZE 0x2000
+# define NV50_PMC_BOOT_0 0x00000000
+# define NV50_PMC_BOOT_0_REVISION 0x000000ff
+# define NV50_PMC_BOOT_0_REVISION__SHIFT 0
+# define NV50_PMC_BOOT_0_ARCH 0x0ff00000
+# define NV50_PMC_BOOT_0_ARCH__SHIFT 20
+# define NV50_PMC_INTR_0 0x00000100
+# define NV50_PMC_INTR_0_PFIFO (1<<8)
+# define NV50_PMC_INTR_0_PGRAPH (1<<12)
+# define NV50_PMC_INTR_0_PTIMER (1<<20)
+# define NV50_PMC_INTR_0_HOTPLUG (1<<21)
+# define NV50_PMC_INTR_0_DISPLAY (1<<26)
+# define NV50_PMC_INTR_EN_0 0x00000140
+# define NV50_PMC_INTR_EN_0_MASTER (1<<0)
+# define NV50_PMC_INTR_EN_0_MASTER_DISABLED (0<<0)
+# define NV50_PMC_INTR_EN_0_MASTER_ENABLED (1<<0)
+# define NV50_PMC_ENABLE 0x00000200
+# define NV50_PMC_ENABLE_PFIFO (1<<8)
+# define NV50_PMC_ENABLE_PGRAPH (1<<12)
+
+#define NV50_PCONNECTOR 0x0000e000
+#define NV50_PCONNECTOR__LEN 0x1
+#define NV50_PCONNECTOR__ESIZE 0x1000
+# define NV50_PCONNECTOR_HOTPLUG_INTR 0x0000e050
+# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C0 (1<<0)
+# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C1 (1<<1)
+# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C2 (1<<2)
+# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C3 (1<<3)
+# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C0 (1<<16)
+# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C1 (1<<17)
+# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C2 (1<<18)
+# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C3 (1<<19)
+# define NV50_PCONNECTOR_HOTPLUG_CTRL 0x0000e054
+# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C0 (1<<0)
+# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C1 (1<<1)
+# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C2 (1<<2)
+# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C3 (1<<3)
+# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C0 (1<<16)
+# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C1 (1<<17)
+# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C2 (1<<18)
+# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C3 (1<<19)
+# define NV50_PCONNECTOR_HOTPLUG_STATE 0x0000e104
+# define NV50_PCONNECTOR_HOTPLUG_STATE_PIN_CONNECTED_I2C0 (1<<2)
+# define NV50_PCONNECTOR_HOTPLUG_STATE_PIN_CONNECTED_I2C1 (1<<6)
+# define NV50_PCONNECTOR_HOTPLUG_STATE_PIN_CONNECTED_I2C2 (1<<10)
+# define NV50_PCONNECTOR_HOTPLUG_STATE_PIN_CONNECTED_I2C3 (1<<14)
+# define NV50_PCONNECTOR_I2C_PORT_0 0x0000e138
+# define NV50_PCONNECTOR_I2C_PORT_1 0x0000e150
+# define NV50_PCONNECTOR_I2C_PORT_2 0x0000e168
+# define NV50_PCONNECTOR_I2C_PORT_3 0x0000e180
+# define NV50_PCONNECTOR_I2C_PORT_4 0x0000e240
+# define NV50_PCONNECTOR_I2C_PORT_5 0x0000e258
+
+#define NV50_PBUS 0x00088000
+#define NV50_PBUS__LEN 0x1
+#define NV50_PBUS__ESIZE 0x1000
+# define NV50_PBUS_PCI_ID 0x00088000
+# define NV50_PBUS_PCI_ID_VENDOR_ID 0x0000ffff
+# define NV50_PBUS_PCI_ID_VENDOR_ID__SHIFT 0
+# define NV50_PBUS_PCI_ID_DEVICE_ID 0xffff0000
+# define NV50_PBUS_PCI_ID_DEVICE_ID__SHIFT 16
+
+#define NV50_PFB 0x00100000
+#define NV50_PFB__LEN 0x1
+#define NV50_PFB__ESIZE 0x1000
+
+#define NV50_PEXTDEV 0x00101000
+#define NV50_PEXTDEV__LEN 0x1
+#define NV50_PEXTDEV__ESIZE 0x1000
+
+#define NV50_PROM 0x00300000
+#define NV50_PROM__LEN 0x1
+#define NV50_PROM__ESIZE 0x10000
+
+#define NV50_PGRAPH 0x00400000
+#define NV50_PGRAPH__LEN 0x1
+#define NV50_PGRAPH__ESIZE 0x10000
+
+#define NV50_PDISPLAY 0x00610000
+#define NV50_PDISPLAY__LEN 0x1
+#define NV50_PDISPLAY__ESIZE 0x10000
+# define NV50_PDISPLAY_SUPERVISOR 0x00610024
+# define NV50_PDISPLAY_SUPERVISOR_CRTCn 0x0000000c
+# define NV50_PDISPLAY_SUPERVISOR_CRTCn__SHIFT 2
+# define NV50_PDISPLAY_SUPERVISOR_CRTC0 (1<<2)
+# define NV50_PDISPLAY_SUPERVISOR_CRTC1 (1<<3)
+# define NV50_PDISPLAY_SUPERVISOR_CLK_MASK 0x00000070
+# define NV50_PDISPLAY_SUPERVISOR_CLK_MASK__SHIFT 4
+# define NV50_PDISPLAY_SUPERVISOR_CLK_UPDATE (1<<5)
+# define NV50_PDISPLAY_SUPERVISOR_INTR 0x0061002c
+# define NV50_PDISPLAY_SUPERVISOR_INTR_VBLANK_CRTC0 (1<<2)
+# define NV50_PDISPLAY_SUPERVISOR_INTR_VBLANK_CRTC1 (1<<3)
+# define NV50_PDISPLAY_SUPERVISOR_INTR_UNK1 (1<<4)
+# define NV50_PDISPLAY_SUPERVISOR_INTR_CLK_UPDATE (1<<5)
+# define NV50_PDISPLAY_SUPERVISOR_INTR_UNK4 (1<<6)
+# define NV50_PDISPLAY_UNK30_CTRL 0x00610030
+# define NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK0 (1<<9)
+# define NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK1 (1<<10)
+# define NV50_PDISPLAY_UNK30_CTRL_PENDING (1<<31)
+# define NV50_PDISPLAY_UNK50_CTRL 0x00610050
+# define NV50_PDISPLAY_UNK50_CTRL_CRTC0_ACTIVE (1<<1)
+# define NV50_PDISPLAY_UNK50_CTRL_CRTC0_ACTIVE_MASK 0x00000003
+# define NV50_PDISPLAY_UNK50_CTRL_CRTC0_ACTIVE_MASK__SHIFT 0
+# define NV50_PDISPLAY_UNK50_CTRL_CRTC1_ACTIVE (1<<9)
+# define NV50_PDISPLAY_UNK50_CTRL_CRTC1_ACTIVE_MASK 0x00000300
+# define NV50_PDISPLAY_UNK50_CTRL_CRTC1_ACTIVE_MASK__SHIFT 8
+# define NV50_PDISPLAY_UNK200_CTRL 0x00610200
+# define NV50_PDISPLAY_CURSOR 0x00610270
+# define NV50_PDISPLAY_CURSOR__LEN 0x2
+# define NV50_PDISPLAY_CURSOR__ESIZE 0x10
+# define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i) (0x00610270+(i)*0x10)
+# define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_ON (1<<0)
+# define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_MASK 0x00030000
+# define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_MASK__SHIFT 16
+# define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_ACTIVE (1<<16)
+
+# define NV50_PDISPLAY_CTRL_STATE 0x00610300
+# define NV50_PDISPLAY_CTRL_STATE_ENABLE (1<<0)
+# define NV50_PDISPLAY_CTRL_STATE_PENDING (1<<31)
+# define NV50_PDISPLAY_CTRL_VAL 0x00610304
+# define NV50_PDISPLAY_UNK_380 0x00610380
+# define NV50_PDISPLAY_RAM_AMOUNT 0x00610384
+# define NV50_PDISPLAY_UNK_388 0x00610388
+# define NV50_PDISPLAY_UNK_38C 0x0061038c
+# define NV50_PDISPLAY_CRTC_VAL 0x00610a00
+# define NV50_PDISPLAY_CRTC_VAL__LEN 0x2
+# define NV50_PDISPLAY_CRTC_VAL_UNK_900(i,j) (0x00610a18+(i)*0x540+(j)*0x4)
+# define NV50_PDISPLAY_CRTC_VAL_CLUT_MODE(i,j) (0x00610a24+(i)*0x540+(j)*0x4)
+# define NV50_PDISPLAY_CRTC_VAL_INTERLACE(i,j) (0x00610a48+(i)*0x540+(j)*0x4)
+# define NV50_PDISPLAY_CRTC_VAL_SCALE_CTRL(i,j) (0x00610a50+(i)*0x540+(j)*0x4)
+# define NV50_PDISPLAY_CRTC_VAL_CURSOR_CTRL(i,j) (0x00610a58+(i)*0x540+(j)*0x4)
+# define NV50_PDISPLAY_CRTC_VAL_UNK_904(i,j) (0x00610ab8+(i)*0x540+(j)*0x4)
+# define NV50_PDISPLAY_CRTC_VAL_DEPTH(i,j) (0x00610ac8+(i)*0x540+(j)*0x4)
+# define NV50_PDISPLAY_CRTC_VAL_CLOCK(i,j) (0x00610ad0+(i)*0x540+(j)*0x4)
+# define NV50_PDISPLAY_CRTC_VAL_COLOR_CTRL(i,j) (0x00610ae0+(i)*0x540+(j)*0x4)
+# define NV50_PDISPLAY_CRTC_VAL_SYNC_START_TO_BLANK_END(i,j) (0x00610ae8+(i)*0x540+(j)*0x4)
+# define NV50_PDISPLAY_CRTC_VAL_MODE_UNK1(i,j) (0x00610af0+(i)*0x540+(j)*0x4)
+# define NV50_PDISPLAY_CRTC_VAL_DISPLAY_TOTAL(i,j) (0x00610af8+(i)*0x540+(j)*0x4)
+# define NV50_PDISPLAY_CRTC_VAL_SYNC_DURATION(i,j) (0x00610b00+(i)*0x540+(j)*0x4)
+# define NV50_PDISPLAY_CRTC_VAL_MODE_UNK2(i,j) (0x00610b08+(i)*0x540+(j)*0x4)
+# define NV50_PDISPLAY_CRTC_VAL_UNK_828(i,j) (0x00610b10+(i)*0x540+(j)*0x4)
+# define NV50_PDISPLAY_CRTC_VAL_FB_SIZE(i,j) (0x00610b18+(i)*0x540+(j)*0x4)
+# define NV50_PDISPLAY_CRTC_VAL_FB_PITCH(i,j) (0x00610b20+(i)*0x540+(j)*0x4)
+# define NV50_PDISPLAY_CRTC_VAL_FB_PITCH_LINEAR_FB (1<<20)
+# define NV50_PDISPLAY_CRTC_VAL_FB_POS(i,j) (0x00610b28+(i)*0x540+(j)*0x4)
+# define NV50_PDISPLAY_CRTC_VAL_SCALE_CENTER_OFFSET(i,j) (0x00610b38+(i)*0x540+(j)*0x4)
+# define NV50_PDISPLAY_CRTC_VAL_REAL_RES(i,j) (0x00610b40+(i)*0x540+(j)*0x4)
+# define NV50_PDISPLAY_CRTC_VAL_SCALE_RES1(i,j) (0x00610b48+(i)*0x540+(j)*0x4)
+# define NV50_PDISPLAY_CRTC_VAL_SCALE_RES2(i,j) (0x00610b50+(i)*0x540+(j)*0x4)
+
+
+# define NV50_PDISPLAY_DAC_VAL_MODE_CTRL(i,j) (0x00610b58+(i)*0x8+(j)*0x4)
+
+
+# define NV50_PDISPLAY_SOR_VAL_MODE_CTRL(i,j) (0x00610b70+(i)*0x8+(j)*0x4)
+
+
+# define NV50_PDISPLAY_DAC_VAL_MODE_CTRL2(i,j) (0x00610bdc+(i)*0x8+(j)*0x4)
+
+
+# define NV50_PDISPLAY_CRTC_CLK 0x00614000
+# define NV50_PDISPLAY_CRTC_CLK__LEN 0x2
+# define NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1(i) (0x00614100+(i)*0x800)
+# define NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1_CONNECTED 0x00000600
+# define NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1_CONNECTED__SHIFT 9
+# define NV50_PDISPLAY_CRTC_CLK_VPLL_A(i) (0x00614104+(i)*0x800)
+# define NV50_PDISPLAY_CRTC_CLK_VPLL_B(i) (0x00614108+(i)*0x800)
+# define NV50_PDISPLAY_CRTC_CLK_CLK_CTRL2(i) (0x00614200+(i)*0x800)
+
+# define NV50_PDISPLAY_DAC_CLK 0x00614000
+# define NV50_PDISPLAY_DAC_CLK__LEN 0x3
+# define NV50_PDISPLAY_DAC_CLK_CLK_CTRL2(i) (0x00614280+(i)*0x800)
+
+# define NV50_PDISPLAY_SOR_CLK 0x00614000
+# define NV50_PDISPLAY_SOR_CLK__LEN 0x3
+# define NV50_PDISPLAY_SOR_CLK_CLK_CTRL2(i) (0x00614300+(i)*0x800)
+
+# define NV50_PDISPLAY_DAC_REGS 0x0061a000
+# define NV50_PDISPLAY_DAC_REGS__LEN 0x3
+# define NV50_PDISPLAY_DAC_REGS__ESIZE 0x800
+# define NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(i) (0x0061a004+(i)*0x800)
+# define NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_HSYNC_OFF (1<<0)
+# define NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_VSYNC_OFF (1<<2)
+# define NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_BLANKED (1<<4)
+# define NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_OFF (1<<6)
+# define NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_PENDING (1<<31)
+# define NV50_PDISPLAY_DAC_REGS_LOAD_CTRL(i) (0x0061a00c+(i)*0x800)
+# define NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_ACTIVE (1<<20)
+# define NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_PRESENT 0x38000000
+# define NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_PRESENT__SHIFT 29
+# define NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_DONE (1<<31)
+# define NV50_PDISPLAY_DAC_REGS_CLK_CTRL1(i) (0x0061a010+(i)*0x800)
+# define NV50_PDISPLAY_DAC_REGS_CLK_CTRL1_CONNECTED 0x00000600
+# define NV50_PDISPLAY_DAC_REGS_CLK_CTRL1_CONNECTED__SHIFT 9
+
+# define NV50_PDISPLAY_SOR_REGS 0x0061c000
+# define NV50_PDISPLAY_SOR_REGS__LEN 0x2
+# define NV50_PDISPLAY_SOR_REGS__ESIZE 0x800
+# define NV50_PDISPLAY_SOR_REGS_DPMS_CTRL(i) (0x0061c004+(i)*0x800)
+# define NV50_PDISPLAY_SOR_REGS_DPMS_CTRL_ON (1<<0)
+# define NV50_PDISPLAY_SOR_REGS_DPMS_CTRL_PENDING (1<<31)
+# define NV50_PDISPLAY_SOR_REGS_CLK_CTRL1(i) (0x0061c008+(i)*0x800)
+# define NV50_PDISPLAY_SOR_REGS_CLK_CTRL1_CONNECTED 0x00000600
+# define NV50_PDISPLAY_SOR_REGS_CLK_CTRL1_CONNECTED__SHIFT 9
+# define NV50_PDISPLAY_SOR_REGS_UNK_00C(i) (0x0061c00c+(i)*0x800)
+# define NV50_PDISPLAY_SOR_REGS_UNK_010(i) (0x0061c010+(i)*0x800)
+# define NV50_PDISPLAY_SOR_REGS_UNK_014(i) (0x0061c014+(i)*0x800)
+# define NV50_PDISPLAY_SOR_REGS_UNK_018(i) (0x0061c018+(i)*0x800)
+# define NV50_PDISPLAY_SOR_REGS_DPMS_STATE(i) (0x0061c030+(i)*0x800)
+# define NV50_PDISPLAY_SOR_REGS_DPMS_STATE_ACTIVE 0x00030000
+# define NV50_PDISPLAY_SOR_REGS_DPMS_STATE_ACTIVE__SHIFT 16
+# define NV50_PDISPLAY_SOR_REGS_DPMS_STATE_BLANKED (1<<19)
+# define NV50_PDISPLAY_SOR_REGS_DPMS_STATE_WAIT (1<<28)
+
+
+#define NV50_UNK640000 0x00640000
+#define NV50_UNK640000__LEN 0x6
+#define NV50_UNK640000__ESIZE 0x1000
+# define NV50_UNK640000_UNK_000(i) (0x00640000+(i)*0x1000)
+
+#define NV50_HW_CURSOR 0x00647000
+#define NV50_HW_CURSOR__LEN 0x2
+#define NV50_HW_CURSOR__ESIZE 0x1000
+# define NV50_HW_CURSOR_POS_CTRL(i) (0x00647080+(i)*0x1000)
+# define NV50_HW_CURSOR_POS(i) (0x00647084+(i)*0x1000)
diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c
index d9c6efe7..3baae6ad 100644
--- a/shared-core/nouveau_state.c
+++ b/shared-core/nouveau_state.c
@@ -27,6 +27,8 @@
#include "drm_sarea.h"
#include "nouveau_drv.h"
#include "nouveau_drm.h"
+#include "nv50_kms_wrapper.h"
+#include "nv50_fbcon.h"
static int nouveau_init_card_mappings(struct drm_device *dev)
{
@@ -362,6 +364,14 @@ nouveau_card_init(struct drm_device *dev)
if (ret) return ret;
dev_priv->init_state = NOUVEAU_CARD_INIT_DONE;
+
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
+ if (dev_priv->card_type >= NV_50) {
+ nv50_kms_init(dev);
+ //nv50_kms_connector_detect_all(dev);
+ nv50_fbcon_init(dev);
+ }
+
return 0;
}
@@ -410,8 +420,7 @@ void nouveau_preclose(struct drm_device *dev, struct drm_file *file_priv)
nouveau_mem_release(file_priv,dev_priv->pci_heap);
}
-/* first module load, setup the mmio/fb mapping */
-int nouveau_firstopen(struct drm_device *dev)
+int nouveau_setup_mappings(struct drm_device *dev)
{
#if defined(__powerpc__)
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -457,6 +466,16 @@ int nouveau_firstopen(struct drm_device *dev)
return 0;
}
+/* first module load, setup the mmio/fb mapping */
+/* KMS: we need mmio at load time, not when the first drm client opens. */
+int nouveau_firstopen(struct drm_device *dev)
+{
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
+ return 0;
+
+ return nouveau_setup_mappings(dev);
+}
+
#define NV40_CHIPSET_MASK 0x00000baf
#define NV44_CHIPSET_MASK 0x00005450
@@ -540,6 +559,10 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
return -EINVAL;
}
+ /* For those who think they want to be funny. */
+ if (dev_priv->card_type < NV_50)
+ dev->driver->driver_features &= ~DRIVER_MODESET;
+
/* Special flags */
if (dev->pci_device == 0x01a0) {
dev_priv->flags |= NV_NFORCE;
@@ -549,10 +572,23 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
dev->dev_private = (void *)dev_priv;
+ /* init card now, otherwise bad things happen */
+ if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+ int rval = 0;
+
+ rval = nouveau_setup_mappings(dev);
+ if (rval != 0)
+ return rval;
+
+ rval = nouveau_card_init(dev);
+ if (rval != 0)
+ return rval;
+ }
+
return 0;
}
-void nouveau_lastclose(struct drm_device *dev)
+void nouveau_close(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -568,8 +604,23 @@ void nouveau_lastclose(struct drm_device *dev)
}
}
+/* KMS: we need mmio at load time, not when the first drm client opens. */
+void nouveau_lastclose(struct drm_device *dev)
+{
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
+ return;
+
+ nouveau_close(dev);
+}
+
int nouveau_unload(struct drm_device *dev)
{
+ if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+ nv50_kms_destroy(dev);
+ nv50_fbcon_destroy(dev);
+ nouveau_close(dev);
+ }
+
drm_free(dev->dev_private, sizeof(*dev->dev_private), DRM_MEM_DRIVER);
dev->dev_private = NULL;
return 0;
diff --git a/shared-core/nv50_fifo.c b/shared-core/nv50_fifo.c
index edf4edbf..d6810666 100644
--- a/shared-core/nv50_fifo.c
+++ b/shared-core/nv50_fifo.c
@@ -289,6 +289,7 @@ void
nv50_fifo_destroy_context(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
DRM_DEBUG("ch%d\n", chan->id);
@@ -298,6 +299,9 @@ nv50_fifo_destroy_context(struct nouveau_channel *chan)
if (chan->id == 0)
nv50_fifo_channel_disable(dev, 127, 0);
+ if ((NV_READ(NV03_PFIFO_CACHE1_PUSH1) & 0xffff) == chan->id)
+ NV_WRITE(NV03_PFIFO_CACHE1_PUSH1, 127);
+
nouveau_gpuobj_ref_del(dev, &chan->ramfc);
}