This looks like the meatiest patch, with lots of support for new
hardware. Gotta love the StudlyCaps...
---
drivers/char/drm/Kconfig | 7
drivers/char/drm/Makefile | 2
drivers/char/drm/drm_pciids.h | 9
drivers/char/drm/via_chrome9_3d_reg.h | 395 +++++++++++
drivers/char/drm/via_chrome9_dma.c | 1147 ++++++++++++++++++++++++++++++++++
drivers/char/drm/via_chrome9_dma.h | 68 ++
drivers/char/drm/via_chrome9_drm.c | 993 +++++++++++++++++++++++++++++
drivers/char/drm/via_chrome9_drm.h | 423 ++++++++++++
drivers/char/drm/via_chrome9_drv.c | 153 ++++
drivers/char/drm/via_chrome9_drv.h | 145 ++++
drivers/char/drm/via_chrome9_mm.c | 388 +++++++++++
drivers/char/drm/via_chrome9_mm.h | 67 +
12 files changed, 3796 insertions(+), 1 deletion(-)
--- a/drivers/char/drm/drm_pciids.h
+++ b/drivers/char/drm/drm_pciids.h
@@ -339,10 +339,17 @@
{0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3344, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
- {0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_DX9_0}, \
{0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_PRO_GROUP_A}, \
{0, 0, 0}
+
+#define via_chrome9DRV_PCI_IDS \
+ {0x1106, 0x3225, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_CHROME9_DX9_0}, \
+ {0x1106, 0x3371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x1106, 0x1122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_CHROME9_PCIE_GROUP},\
+ {0, 0, 0}
+
#define i810_PCI_IDS \
{0x8086, 0x7121, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x8086, 0x7123, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
--- a/drivers/char/drm/Kconfig
+++ b/drivers/char/drm/Kconfig
@@ -99,6 +99,13 @@ config DRM_VIA
Choose this option if you have a Via unichrome or compatible video
chipset. If M is selected the module will be called via.
+config DRM_VIA_CHROME9
+ tristate "Via unichrome9 video cards"
+ depends on DRM
+ help
+ Choose this option if you have a Via unichrome9 or compatible video
+ chipset. If M is selected the module will be called via_chrome9.
+
config DRM_SAVAGE
tristate "Savage video cards"
depends on DRM
--- a/drivers/char/drm/Makefile
+++ b/drivers/char/drm/Makefile
@@ -18,6 +18,7 @@ radeon-objs := radeon_drv.o radeon_cp.o
sis-objs := sis_drv.o sis_mm.o
savage-objs := savage_drv.o savage_bci.o savage_state.o
via-objs := via_irq.o via_drv.o via_map.o via_mm.o via_dma.o via_verifier.o via_video.o via_dmablit.o
+via_chrome9-objs := via_chrome9_drv.o via_chrome9_drm.o via_chrome9_mm.o via_chrome9_dma.o
ifeq ($(CONFIG_COMPAT),y)
drm-objs += drm_ioc32.o
@@ -38,3 +39,4 @@ obj-$(CONFIG_DRM_I915) += i915.o
obj-$(CONFIG_DRM_SIS) += sis.o
obj-$(CONFIG_DRM_SAVAGE)+= savage.o
obj-$(CONFIG_DRM_VIA) +=via.o
+obj-$(CONFIG_DRM_VIA_CHROME9) += via_chrome9.o
--- /dev/null
+++ b/drivers/char/drm/via_chrome9_3d_reg.h
@@ -0,0 +1,395 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. 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, sub license,
+ * 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, 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.
+ */
+
+#ifndef VIA_CHROME9_3D_REG_H
+#define VIA_CHROME9_3D_REG_H
+#define GetMMIORegister(base, offset) \
+ (*(volatile unsigned int *)(void *)(((unsigned char *)(base)) + \
+ (offset)))
+#define SetMMIORegister(base, offset, val) \
+ (*(volatile unsigned int *)(void *)(((unsigned char *)(base)) + \
+ (offset)) = (val))
+
+#define GetMMIORegisterU8(base, offset) \
+ (*(volatile unsigned char *)(void *)(((unsigned char *)(base)) + \
+ (offset)))
+#define SetMMIORegisterU8(base, offset, val) \
+ (*(volatile unsigned char *)(void *)(((unsigned char *)(base)) + \
+ (offset)) = (val))
+
+#define BCI_SEND(bci, value) (*(bci)++ = (unsigned long)(value))
+#define BCI_SET_STREAM_REGISTER(bci_base, bci_index, reg_value) \
+do { \
+ unsigned long cmd; \
+ \
+ cmd = (0x90000000 \
+ | (1<<16) /* stream processor register */ \
+ | (bci_index & 0x3FFC)); /* MMIO register address */ \
+ BCI_SEND(bci_base, cmd); \
+ BCI_SEND(bci_base, reg_value); \
+ } while (0)
+
+/* Command Header Type */
+
+#define INV_AGPHeader0 0xFE000000
+#define INV_AGPHeader1 0xFE010000
+#define INV_AGPHeader2 0xFE020000
+#define INV_AGPHeader3 0xFE030000
+#define INV_AGPHeader4 0xFE040000
+#define INV_AGPHeader5 0xFE050000
+#define INV_AGPHeader6 0xFE060000
+#define INV_AGPHeader7 0xFE070000
+#define INV_AGPHeader82 0xFE820000
+#define INV_AGPHeader_MASK 0xFFFF0000
+
+/*send pause address of AGP ring command buffer via_chrome9 this IO port*/
+#define INV_REG_PCIPAUSE 0x294
+#define INV_REG_PCIPAUSE_ENABLE 0x4
+
+#define INV_CMDBUF_THRESHOLD (8)
+#define INV_QW_PAUSE_ALIGN 0x40
+
+/* Transmission IO Space*/
+#define INV_REG_CR_TRANS 0x041C
+#define INV_REG_CR_BEGIN 0x0420
+#define INV_REG_CR_END 0x0438
+
+#define INV_REG_3D_TRANS 0x043C
+#define INV_REG_3D_BEGIN 0x0440
+#define INV_REG_3D_END 0x06FC
+#define INV_REG_23D_WAIT 0x326C
+/*3D / 2D ID Control (Only For Group A)*/
+#define INV_REG_2D3D_ID_CTRL 0x060
+
+
+/* Engine Status */
+
+#define INV_RB_ENG_STATUS 0x0400
+#define INV_ENG_BUSY_HQV0 0x00040000
+#define INV_ENG_BUSY_HQV1 0x00020000
+#define INV_ENG_BUSY_CR 0x00000010
+#define INV_ENG_BUSY_MPEG 0x00000008
+#define INV_ENG_BUSY_VQ 0x00000004
+#define INV_ENG_BUSY_2D 0x00000002
+#define INV_ENG_BUSY_3D 0x00001FE1
+#define INV_ENG_BUSY_ALL \
+ (INV_ENG_BUSY_2D | INV_ENG_BUSY_3D | INV_ENG_BUSY_CR)
+
+/* Command Queue Status*/
+#define INV_RB_VQ_STATUS 0x0448
+#define INV_VQ_FULL 0x40000000
+
+/* AGP command buffer pointer current position*/
+#define INV_RB_AGPCMD_CURRADDR 0x043C
+
+/* AGP command buffer status*/
+#define INV_RB_AGPCMD_STATUS 0x0444
+#define INV_AGPCMD_InPause 0x80000000
+
+/*AGP command buffer pause address*/
+#define INV_RB_AGPCMD_PAUSEADDR 0x045C
+
+/*AGP command buffer jump address*/
+#define INV_RB_AGPCMD_JUMPADDR 0x0460
+
+/*AGP command buffer start address*/
+#define INV_RB_AGPCMD_STARTADDR 0x0464
+
+
+/* Constants */
+#define NUMBER_OF_EVENT_TAGS 1024
+#define NUMBER_OF_APERTURES_CLB 16
+
+/* Register definition */
+#define HW_SHADOW_ADDR 0x8520
+#define HW_GARTTABLE_ADDR 0x8540
+
+#define INV_HSWFlag_DBGMASK 0x00000FFF
+#define INV_HSWFlag_ENCODEMASK 0x007FFFF0
+#define INV_HSWFlag_ADDRSHFT 8
+#define INV_HSWFlag_DECODEMASK \
+ (INV_HSWFlag_ENCODEMASK << INV_HSWFlag_ADDRSHFT)
+#define INV_HSWFlag_ADDR_ENCODE(x) 0xCC000000
+#define INV_HSWFlag_ADDR_DECODE(x) \
+ (((unsigned int)x & INV_HSWFlag_DECODEMASK) >> INV_HSWFlag_ADDRSHFT)
+
+
+#define INV_SubA_HAGPBstL 0x60000000
+#define INV_SubA_HAGPBstH 0x61000000
+#define INV_SubA_HAGPBendL 0x62000000
+#define INV_SubA_HAGPBendH 0x63000000
+#define INV_SubA_HAGPBpL 0x64000000
+#define INV_SubA_HAGPBpID 0x65000000
+#define INV_HAGPBpID_PAUSE 0x00000000
+#define INV_HAGPBpID_JUMP 0x00000100
+#define INV_HAGPBpID_STOP 0x00000200
+
+#define INV_HAGPBpH_MASK 0x000000FF
+#define INV_HAGPBpH_SHFT 0
+
+#define INV_SubA_HAGPBjumpL 0x66000000
+#define INV_SubA_HAGPBjumpH 0x67000000
+#define INV_HAGPBjumpH_MASK 0x000000FF
+#define INV_HAGPBjumpH_SHFT 0
+
+#define INV_SubA_HFthRCM 0x68000000
+#define INV_HFthRCM_MASK 0x003F0000
+#define INV_HFthRCM_SHFT 16
+#define INV_HFthRCM_8 0x00080000
+#define INV_HFthRCM_10 0x000A0000
+#define INV_HFthRCM_18 0x00120000
+#define INV_HFthRCM_24 0x00180000
+#define INV_HFthRCM_32 0x00200000
+
+#define INV_HAGPBClear 0x00000008
+
+#define INV_HRSTTrig_RestoreAGP 0x00000004
+#define INV_HRSTTrig_RestoreAll 0x00000002
+#define INV_HAGPBTrig 0x00000001
+
+#define INV_ParaSubType_MASK 0xff000000
+#define INV_ParaType_MASK 0x00ff0000
+#define INV_ParaOS_MASK 0x0000ff00
+#define INV_ParaAdr_MASK 0x000000ff
+#define INV_ParaSubType_SHIFT 24
+#define INV_ParaType_SHIFT 16
+#define INV_ParaOS_SHIFT 8
+#define INV_ParaAdr_SHIFT 0
+
+#define INV_ParaType_Vdata 0x00000000
+#define INV_ParaType_Attr 0x00010000
+#define INV_ParaType_Tex 0x00020000
+#define INV_ParaType_Pal 0x00030000
+#define INV_ParaType_FVF 0x00040000
+#define INV_ParaType_PreCR 0x00100000
+#define INV_ParaType_CR 0x00110000
+#define INV_ParaType_Cfg 0x00fe0000
+#define INV_ParaType_Dummy 0x00300000
+
+#define INV_HWBasL_MASK 0x00FFFFFF
+#define INV_HWBasH_MASK 0xFF000000
+#define INV_HWBasH_SHFT 24
+#define INV_HWBasL(x) ((unsigned int)(x) & INV_HWBasL_MASK)
+#define INV_HWBasH(x) ((unsigned int)(x) >> INV_HWBasH_SHFT)
+#define INV_HWBas256(x) ((unsigned int)(x) >> 8)
+#define INV_HWPit32(x) ((unsigned int)(x) >> 5)
+
+/* Read Back Register Setting */
+#define INV_SubA_HSetRBGID 0x02000000
+#define INV_HSetRBGID_CR 0x00000000
+#define INV_HSetRBGID_FE 0x00000001
+#define INV_HSetRBGID_PE 0x00000002
+#define INV_HSetRBGID_RC 0x00000003
+#define INV_HSetRBGID_PS 0x00000004
+#define INV_HSetRBGID_XE 0x00000005
+#define INV_HSetRBGID_BE 0x00000006
+
+
+struct drm_clb_event_tag_info {
+ unsigned int *linear_address;
+ unsigned int *event_tag_linear_address;
+ int usage[NUMBER_OF_EVENT_TAGS];
+ unsigned int pid[NUMBER_OF_EVENT_TAGS];
+};
+
+static inline int IS_AGPHEADER_INV(unsigned int data)
+{
+ switch (data & INV_AGPHeader_MASK) {
+ case INV_AGPHeader0:
+ case INV_AGPHeader1:
+ case INV_AGPHeader2:
+ case INV_AGPHeader3:
+ case INV_AGPHeader4:
+ case INV_AGPHeader5:
+ case INV_AGPHeader6:
+ case INV_AGPHeader7:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+/* Header0: 2D */
+#define ADDCmdHeader0_INVI(pCmd, dwCount) \
+{ \
+ /* 4 unsigned int align, insert NULL Command for padding */ \
+ while (((unsigned long *)(pCmd)) & 0xF) { \
+ *(pCmd)++ = 0xCC000000; \
+ } \
+ *(pCmd)++ = INV_AGPHeader0; \
+ *(pCmd)++ = (dwCount); \
+ *(pCmd)++ = 0; \
+ *(pCmd)++ = (unsigned int)INV_HSWFlag_ADDR_ENCODE(pCmd); \
+}
+
+/* Header1: 2D */
+#define ADDCmdHeader1_INVI(pCmd, dwAddr, dwCount) \
+{ \
+ /* 4 unsigned int align, insert NULL Command for padding */ \
+ while (((unsigned long *)(pCmd)) & 0xF) { \
+ *(pCmd)++ = 0xCC000000; \
+ } \
+ *(pCmd)++ = INV_AGPHeader1 | (dwAddr); \
+ *(pCmd)++ = (dwCount); \
+ *(pCmd)++ = 0; \
+ *(pCmd)++ = (unsigned int)INV_HSWFlag_ADDR_ENCODE(pCmd); \
+}
+
+/* Header2: CR/3D */
+#define ADDCmdHeader2_INVI(pCmd, dwAddr, dwType) \
+{ \
+ /* 4 unsigned int align, insert NULL Command for padding */ \
+ while (((unsigned int)(pCmd)) & 0xF) { \
+ *(pCmd)++ = 0xCC000000; \
+ } \
+ *(pCmd)++ = INV_AGPHeader2 | ((dwAddr)+4); \
+ *(pCmd)++ = (dwAddr); \
+ *(pCmd)++ = (dwType); \
+ *(pCmd)++ = (unsigned int)INV_HSWFlag_ADDR_ENCODE(pCmd); \
+}
+
+/* Header2: CR/3D with SW Flag */
+#define ADDCmdHeader2_SWFlag_INVI(pCmd, dwAddr, dwType, dwSWFlag) \
+{ \
+ /* 4 unsigned int align, insert NULL Command for padding */ \
+ while (((unsigned long *)(pCmd)) & 0xF) { \
+ *(pCmd)++ = 0xCC000000; \
+ } \
+ *(pCmd)++ = INV_AGPHeader2 | ((dwAddr)+4); \
+ *(pCmd)++ = (dwAddr); \
+ *(pCmd)++ = (dwType); \
+ *(pCmd)++ = (dwSWFlag); \
+}
+
+
+/* Header3: 3D */
+#define ADDCmdHeader3_INVI(pCmd, dwType, dwStart, dwCount) \
+{ \
+ /* 4 unsigned int align, insert NULL Command for padding */ \
+ while (((unsigned long *)(pCmd)) & 0xF) { \
+ *(pCmd)++ = 0xCC000000; \
+ } \
+ *(pCmd)++ = INV_AGPHeader3 | INV_REG_3D_TRANS; \
+ *(pCmd)++ = (dwCount); \
+ *(pCmd)++ = (dwType) | ((dwStart) & 0xFFFF); \
+ *(pCmd)++ = (unsigned int)INV_HSWFlag_ADDR_ENCODE(pCmd); \
+}
+
+/* Header3: 3D with SW Flag */
+#define ADDCmdHeader3_SWFlag_INVI(pCmd, dwType, dwStart, dwSWFlag, dwCount) \
+{ \
+ /* 4 unsigned int align, insert NULL Command for padding */ \
+ while (((unsigned long *)(pCmd)) & 0xF) { \
+ *(pCmd)++ = 0xCC000000; \
+ } \
+ *(pCmd)++ = INV_AGPHeader3 | INV_REG_3D_TRANS; \
+ *(pCmd)++ = (dwCount); \
+ *(pCmd)++ = (dwType) | ((dwStart) & 0xFFFF); \
+ *(pCmd)++ = (dwSWFlag); \
+}
+
+/* Header4: DVD */
+#define ADDCmdHeader4_INVI(pCmd, dwAddr, dwCount, id) \
+{ \
+ /* 4 unsigned int align, insert NULL Command for padding */ \
+ while (((unsigned long *)(pCmd)) & 0xF) { \
+ *(pCmd)++ = 0xCC000000; \
+ } \
+ *(pCmd)++ = INV_AGPHeader4 | (dwAddr); \
+ *(pCmd)++ = (dwCount); \
+ *(pCmd)++ = (id); \
+ *(pCmd)++ = 0; \
+}
+
+/* Header5: DVD */
+#define ADDCmdHeader5_INVI(pCmd, dwQWcount, id) \
+{ \
+ /* 4 unsigned int align, insert NULL Command for padding */ \
+ while (((unsigned long *)(pCmd)) & 0xF) { \
+ *(pCmd)++ = 0xCC000000; \
+ } \
+ *(pCmd)++ = INV_AGPHeader5; \
+ *(pCmd)++ = (dwQWcount); \
+ *(pCmd)++ = (id); \
+ *(pCmd)++ = 0; \
+}
+
+/* Header6: DEBUG */
+#define ADDCmdHeader6_INVI(pCmd) \
+{ \
+ /* 4 unsigned int align, insert NULL Command for padding */ \
+ while (((unsigned long *)(pCmd)) & 0xF) { \
+ *(pCmd)++ = 0xCC000000; \
+ } \
+ *(pCmd)++ = INV_AGPHeader6; \
+ *(pCmd)++ = 0; \
+ *(pCmd)++ = 0; \
+ *(pCmd)++ = 0; \
+}
+
+/* Header7: DMA */
+#define ADDCmdHeader7_INVI(pCmd, dwQWcount, id) \
+{ \
+ /* 4 unsigned int align, insert NULL Command for padding */ \
+ while (((unsigned long *)(pCmd)) & 0xF) { \
+ *(pCmd)++ = 0xCC000000; \
+ } \
+ *(pCmd)++ = INV_AGPHeader7; \
+ *(pCmd)++ = (dwQWcount); \
+ *(pCmd)++ = (id); \
+ *(pCmd)++ = 0; \
+}
+
+/* Header82: Branch buffer */
+#define ADDCmdHeader82_INVI(pCmd, dwAddr, dwType); \
+{ \
+ /* 4 unsigned int align, insert NULL Command for padding */ \
+ while (((unsigned long *)(pCmd)) & 0xF) { \
+ *(pCmd)++ = 0xCC000000; \
+ } \
+ *(pCmd)++ = INV_AGPHeader82 | ((dwAddr)+4); \
+ *(pCmd)++ = (dwAddr); \
+ *(pCmd)++ = (dwType); \
+ *(pCmd)++ = 0xCC000000; \
+}
+
+
+#define ADD2DCmd_INVI(pCmd, dwAddr, dwCmd) \
+{ \
+ *(pCmd)++ = (dwAddr); \
+ *(pCmd)++ = (dwCmd); \
+}
+
+#define ADDCmdData_INVI(pCmd, dwCmd) *(pCmd)++ = (dwCmd)
+
+#define ADDCmdDataStream_INVI(pCmdBuf, pCmd, dwCount) \
+{ \
+ memcpy((pCmdBuf), (pCmd), ((dwCount)<<2)); \
+ (pCmdBuf) += (dwCount); \
+}
+
+#endif
--- /dev/null
+++ b/drivers/char/drm/via_chrome9_dma.c
@@ -0,0 +1,1147 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. 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, sub license,
+ * 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, 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.
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "via_chrome9_drm.h"
+#include "via_chrome9_drv.h"
+#include "via_chrome9_3d_reg.h"
+#include "via_chrome9_dma.h"
+
+#define NULLCOMMANDNUMBER 256
+unsigned int NULL_COMMAND_INV[4] =
+ { 0xCC000000, 0xCD000000, 0xCE000000, 0xCF000000 };
+
+void
+via_chrome9ke_assert(int a)
+{
+}
+
+unsigned int
+ProtectSizeValue(unsigned int size)
+{
+ unsigned int i;
+ for (i = 0; i < 8; i++)
+ if ((size > (1 << (i + 12)))
+ && (size <= (1 << (i + 13))))
+ return (i + 1);
+ return 0;
+}
+
+static unsigned int
+InitPCIEGART(struct drm_via_chrome9_private *dev_priv)
+{
+ unsigned int *pGARTTable;
+ unsigned int i, entries, GARTOffset;
+ unsigned char sr6a, sr6b, sr6c, sr6f, sr7b;
+
+ if (!dev_priv->pagetable_map.pagetable_size)
+ return 0;
+
+ entries = dev_priv->pagetable_map.pagetable_size / sizeof(unsigned int);
+
+ pGARTTable =
+ ioremap_nocache(dev_priv->fb_base_address +
+ dev_priv->pagetable_map.pagetable_offset,
+ dev_priv->pagetable_map.pagetable_size);
+ if (pGARTTable)
+ dev_priv->pagetable_map.pagetable_handle = pGARTTable;
+ else
+ return 0;
+
+ /*set gart table base */
+ GARTOffset = dev_priv->pagetable_map.pagetable_offset;
+
+ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c);
+ sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5);
+ sr6c &= (~0x80);
+ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c);
+
+ sr6a = (unsigned char) ((GARTOffset & 0xff000) >> 12);
+ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6a);
+ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6a);
+
+ sr6b = (unsigned char) ((GARTOffset & 0xff00000) >> 20);
+ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6b);
+ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6b);
+
+ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c);
+ sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5);
+ sr6c |= ((unsigned char) ((GARTOffset >> 28) & 0x01));
+ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c);
+
+ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x7b);
+ sr7b = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5);
+ sr7b &= (~0x0f);
+ sr7b |= ProtectSizeValue(dev_priv->pagetable_map.pagetable_size);
+ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr7b);
+
+ for (i = 0; i < entries; i++)
+ writel(0x80000000, pGARTTable + i);
+ /*flush */
+ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6f);
+ do {
+ sr6f = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5);
+ }
+ while (sr6f & 0x80)
+ ;
+
+ sr6f |= 0x80;
+ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6f);
+
+ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c);
+ sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5);
+ sr6c |= 0x80;
+ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c);
+
+ return 1;
+}
+
+
+static unsigned int *
+AllocAndBindPCIEMemory(struct drm_via_chrome9_private *dev_priv,
+ unsigned int size, unsigned int offset)
+{
+ unsigned int *addrlinear;
+ unsigned int *pGARTTable;
+ unsigned int entries, alignedoffset, i;
+ unsigned char sr6c, sr6f;
+
+ if (!size)
+ return NULL;
+
+ entries = (size + PAGE_SIZE - 1) / PAGE_SIZE;
+ alignedoffset = (offset + PAGE_SIZE - 1) / PAGE_SIZE;
+
+ if ((entries + alignedoffset) >
+ (dev_priv->pagetable_map.pagetable_size / sizeof(unsigned int)))
+ return NULL;
+
+ addrlinear =
+ __vmalloc(entries * PAGE_SIZE, GFP_KERNEL | __GFP_HIGHMEM,
+ PAGE_KERNEL_NOCACHE);
+
+ if (!addrlinear)
+ return NULL;
+
+ pGARTTable = dev_priv->pagetable_map.pagetable_handle;
+
+ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c);
+ sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5);
+ sr6c &= (~0x80);
+ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c);
+
+ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6f);
+ do {
+ sr6f = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5);
+ }
+ while (sr6f & 0x80)
+ ;
+
+ for (i = 0; i < entries; i++)
+ writel(page_to_pfn
+ (vmalloc_to_page((void *) addrlinear + PAGE_SIZE * i)) &
+ 0x3fffffff, pGARTTable + i + alignedoffset);
+
+ sr6f |= 0x80;
+ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6f);
+
+ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c);
+ sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5);
+ sr6c |= 0x80;
+ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c);
+
+ return addrlinear;
+
+}
+
+void
+SetAGPDoubleCmd_inv(struct drm_device *dev)
+{
+ /* we now don't use double buffer */
+ return;
+}
+
+void
+SetAGPRingCmdRegs_inv(struct drm_device *dev)
+{
+ struct drm_via_chrome9_private *dev_priv =
+ (struct drm_via_chrome9_private *) dev->dev_private;
+ struct drm_via_chrome9_DMA_manager *lpcmDMAManager =
+ (struct drm_via_chrome9_DMA_manager *) dev_priv->dma_manager;
+ unsigned int AGPBufLinearBase = 0, AGPBufPhysicalBase = 0;
+ unsigned long *pFree;
+ unsigned int dwStart, dwEnd, dwPause, AGPCurrAddr, AGPCurStat, CurrAGP;
+ unsigned int dwReg60, dwReg61, dwReg62, dwReg63,
+ dwReg64, dwReg65, dwJump;
+
+ lpcmDMAManager->pFree = lpcmDMAManager->pBeg;
+
+ AGPBufLinearBase = (unsigned int) lpcmDMAManager->addr_linear;
+ AGPBufPhysicalBase =
+ (dev_priv->chip_agp ==
+ CHIP_PCIE) ? 0 : (unsigned int) dev->agp->base +
+ lpcmDMAManager->pPhysical;
+ /*add shadow offset */
+
+ CurrAGP =
+ GetMMIORegister(dev_priv->mmio->handle, INV_RB_AGPCMD_CURRADDR);
+ AGPCurStat =
+ GetMMIORegister(dev_priv->mmio->handle, INV_RB_AGPCMD_STATUS);
+
+ if (AGPCurStat & INV_AGPCMD_InPause) {
+ AGPCurrAddr =
+ GetMMIORegister(dev_priv->mmio->handle,
+ INV_RB_AGPCMD_CURRADDR);
+ pFree = (unsigned long *) (AGPBufLinearBase + AGPCurrAddr -
+ AGPBufPhysicalBase);
+ ADDCmdHeader2_INVI(pFree, INV_REG_CR_TRANS, INV_ParaType_Dummy);
+ if (dev_priv->chip_sub_index == CHIP_H6S2)
+ do {
+ ADDCmdData_INVI(pFree, 0xCCCCCCC0);
+ ADDCmdData_INVI(pFree, 0xDDD00000);
+ }
+ while ((u32)((unsigned int) pFree) & 0x7f)
+ ;
+ /*for 8*128bit aligned */
+ else
+ do {
+ ADDCmdData_INVI(pFree, 0xCCCCCCC0);
+ ADDCmdData_INVI(pFree, 0xDDD00000);
+ }
+ while ((u32) ((unsigned int) pFree) & 0x1f)
+ ;
+ /*for 256bit aligned */
+ dwPause =
+ (u32) (((unsigned int) pFree) - AGPBufLinearBase +
+ AGPBufPhysicalBase - 16);
+
+ dwReg64 = INV_SubA_HAGPBpL | INV_HWBasL(dwPause);
+ dwReg65 =
+ INV_SubA_HAGPBpID | INV_HWBasH(dwPause) |
+ INV_HAGPBpID_STOP;
+
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS,
+ INV_ParaType_PreCR);
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN,
+ dwReg64);
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN,
+ dwReg65);
+
+ while ((GetMMIORegister
+ (dev_priv->mmio->handle,
+ INV_RB_ENG_STATUS) & INV_ENG_BUSY_ALL));
+ }
+ dwStart =
+ (u32) ((unsigned int) lpcmDMAManager->pBeg - AGPBufLinearBase +
+ AGPBufPhysicalBase);
+ dwEnd = (u32) ((unsigned int) lpcmDMAManager->pEnd - AGPBufLinearBase +
+ AGPBufPhysicalBase);
+
+ lpcmDMAManager->pFree = lpcmDMAManager->pBeg;
+ if (dev_priv->chip_sub_index == CHIP_H6S2) {
+ ADDCmdHeader2_INVI(lpcmDMAManager->pFree, INV_REG_CR_TRANS,
+ INV_ParaType_Dummy);
+ do {
+ ADDCmdData_INVI(lpcmDMAManager->pFree, 0xCCCCCCC0);
+ ADDCmdData_INVI(lpcmDMAManager->pFree, 0xDDD00000);
+ }
+ while ((u32)((unsigned long *) lpcmDMAManager->pFree) & 0x7f)
+ ;
+ }
+ dwJump = 0xFFFFFFF0;
+ dwPause =
+ (u32)(((unsigned int) lpcmDMAManager->pFree) -
+ 16 - AGPBufLinearBase + AGPBufPhysicalBase);
+
+ DRM_DEBUG("dwStart = %08x, dwEnd = %08x, dwPause = %08x\n", dwStart,
+ dwEnd, dwPause);
+
+ dwReg60 = INV_SubA_HAGPBstL | INV_HWBasL(dwStart);
+ dwReg61 = INV_SubA_HAGPBstH | INV_HWBasH(dwStart);
+ dwReg62 = INV_SubA_HAGPBendL | INV_HWBasL(dwEnd);
+ dwReg63 = INV_SubA_HAGPBendH | INV_HWBasH(dwEnd);
+ dwReg64 = INV_SubA_HAGPBpL | INV_HWBasL(dwPause);
+ dwReg65 = INV_SubA_HAGPBpID | INV_HWBasH(dwPause) | INV_HAGPBpID_PAUSE;
+
+ if (dev_priv->chip_sub_index == CHIP_H6S2)
+ dwReg60 |= 0x01;
+
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS,
+ INV_ParaType_PreCR);
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg60);
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg61);
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg62);
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg63);
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg64);
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg65);
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN,
+ INV_SubA_HAGPBjumpL | INV_HWBasL(dwJump));
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN,
+ INV_SubA_HAGPBjumpH | INV_HWBasH(dwJump));
+
+ /* Trigger AGP cycle */
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN,
+ INV_SubA_HFthRCM | INV_HFthRCM_10 | INV_HAGPBTrig);
+
+ /*for debug */
+ CurrAGP =
+ GetMMIORegister(dev_priv->mmio->handle, INV_RB_AGPCMD_CURRADDR);
+
+ lpcmDMAManager->pInUseBySW = lpcmDMAManager->pFree;
+}
+
+/* Do hw intialization and determine whether to use dma or mmio to
+talk with hw */
+int
+via_chrome9_hw_init(struct drm_device *dev,
+ struct drm_via_chrome9_init *init)
+{
+ struct drm_via_chrome9_private *dev_priv =
+ (struct drm_via_chrome9_private *) dev->dev_private;
+ unsigned retval = 0;
+ unsigned int *pGARTTable, *addrlinear = NULL;
+ int pages;
+ struct drm_clb_event_tag_info *event_tag_info;
+ struct drm_via_chrome9_DMA_manager *lpcmDMAManager = NULL;
+
+ if (init->chip_agp == CHIP_PCIE) {
+ dev_priv->pagetable_map.pagetable_offset =
+ init->garttable_offset;
+ dev_priv->pagetable_map.pagetable_size = init->garttable_size;
+ dev_priv->agp_size = init->agp_tex_size;
+ /*Henry :prepare for PCIE texture buffer */
+ } else {
+ dev_priv->pagetable_map.pagetable_offset = 0;
+ dev_priv->pagetable_map.pagetable_size = 0;
+ }
+
+ dev_priv->dma_manager =
+ kmalloc(sizeof(struct drm_via_chrome9_DMA_manager), GFP_KERNEL);
+ if (!dev_priv->dma_manager) {
+ DRM_ERROR("could not allocate system for dma_manager!\n");
+ return -ENOMEM;
+ }
+
+ lpcmDMAManager =
+ (struct drm_via_chrome9_DMA_manager *) dev_priv->dma_manager;
+ ((struct drm_via_chrome9_DMA_manager *)
+ dev_priv->dma_manager)->DMASize = init->DMA_size;
+ ((struct drm_via_chrome9_DMA_manager *)
+ dev_priv->dma_manager)->pPhysical = init->DMA_phys_address;
+
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, 0x00110000);
+ if (dev_priv->chip_sub_index == CHIP_H6S2) {
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN,
+ 0x06000000);
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN,
+ 0x07100000);
+ } else {
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN,
+ 0x02000000);
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN,
+ 0x03100000);
+ }
+
+ /* Specify fence command read back ID */
+ /* Default the read back ID is CR */
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS,
+ INV_ParaType_PreCR);
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN,
+ INV_SubA_HSetRBGID | INV_HSetRBGID_CR);
+
+ DRM_DEBUG("begin to init\n");
+
+ if (dev_priv->chip_sub_index == CHIP_H6S2) {
+ dev_priv->pcie_vmalloc_nocache = 0;
+ if (dev_priv->pagetable_map.pagetable_size)
+ retval = InitPCIEGART(dev_priv);
+
+ if (retval && dev_priv->drm_agp_type != DRM_AGP_DISABLED) {
+ addrlinear =
+ AllocAndBindPCIEMemory(dev_priv,
+ lpcmDMAManager->DMASize +
+ dev_priv->agp_size, 0);
+ if (addrlinear) {
+ dev_priv->pcie_vmalloc_nocache = (unsigned long)
+ addrlinear;
+ } else {
+ dev_priv->bci_buffer =
+ vmalloc(MAX_BCI_BUFFER_SIZE);
+ dev_priv->drm_agp_type = DRM_AGP_DISABLED;
+ }
+ } else {
+ dev_priv->bci_buffer = vmalloc(MAX_BCI_BUFFER_SIZE);
+ dev_priv->drm_agp_type = DRM_AGP_DISABLED;
+ }
+ } else {
+ if (dev_priv->drm_agp_type != DRM_AGP_DISABLED) {
+ pGARTTable = NULL;
+ addrlinear = (unsigned int *)
+ ioremap(dev->agp->base +
+ lpcmDMAManager->pPhysical,
+ lpcmDMAManager->DMASize);
+ dev_priv->bci_buffer = NULL;
+ } else {
+ dev_priv->bci_buffer = vmalloc(MAX_BCI_BUFFER_SIZE);
+ /*Homer, BCI path always use this block of memory8 */
+ }
+ }
+
+ /*till here we have known whether support dma or not */
+ pages = dev->sg->pages;
+ event_tag_info = vmalloc(sizeof(struct drm_clb_event_tag_info));
+ memset(event_tag_info, 0, sizeof(struct drm_clb_event_tag_info));
+ if (!event_tag_info)
+ return DRM_ERROR(" event_tag_info allocate error!");
+
+ /* aligned to 16k alignment */
+ event_tag_info->linear_address =
+ (int
+ *) (((unsigned int) dev_priv->shadow_map.shadow_handle +
+ 0x3fff) & 0xffffc000);
+ event_tag_info->event_tag_linear_address =
+ event_tag_info->linear_address + 3;
+ dev_priv->event_tag_info = (void *) event_tag_info;
+ dev_priv->max_apertures = NUMBER_OF_APERTURES_CLB;
+
+ /* Initialize DMA data structure */
+ lpcmDMAManager->DMASize /= sizeof(unsigned int);
+ lpcmDMAManager->pBeg = addrlinear;
+ lpcmDMAManager->pFree = lpcmDMAManager->pBeg;
+ lpcmDMAManager->pInUseBySW = lpcmDMAManager->pBeg;
+ lpcmDMAManager->pInUseByHW = lpcmDMAManager->pBeg;
+ lpcmDMAManager->LastIssuedEventTag = (unsigned int) (unsigned long *)
+ lpcmDMAManager->pBeg;
+ lpcmDMAManager->ppInUseByHW =
+ (unsigned int **) ((char *) (dev_priv->mmio->handle) +
+ INV_RB_AGPCMD_CURRADDR);
+ lpcmDMAManager->bDMAAgp = dev_priv->chip_agp;
+ lpcmDMAManager->addr_linear = (unsigned int *) addrlinear;
+
+ if (dev_priv->drm_agp_type == DRM_AGP_DOUBLE_BUFFER) {
+ lpcmDMAManager->MaxKickoffSize = lpcmDMAManager->DMASize >> 1;
+ lpcmDMAManager->pEnd =
+ lpcmDMAManager->addr_linear +
+ (lpcmDMAManager->DMASize >> 1) - 1;
+ SetAGPDoubleCmd_inv(dev);
+ if (dev_priv->chip_sub_index == CHIP_H6S2) {
+ DRM_INFO("DMA buffer initialized finished. ");
+ DRM_INFO("Use PCIE Double Buffer type!\n");
+ DRM_INFO("Total PCIE DMA buffer size = %8d bytes. \n",
+ lpcmDMAManager->DMASize << 2);
+ } else {
+ DRM_INFO("DMA buffer initialized finished. ");
+ DRM_INFO("Use AGP Double Buffer type!\n");
+ DRM_INFO("Total AGP DMA buffer size = %8d bytes. \n",
+ lpcmDMAManager->DMASize << 2);
+ }
+ } else if (dev_priv->drm_agp_type == DRM_AGP_RING_BUFFER) {
+ lpcmDMAManager->MaxKickoffSize = lpcmDMAManager->DMASize;
+ lpcmDMAManager->pEnd =
+ lpcmDMAManager->addr_linear + lpcmDMAManager->DMASize;
+ SetAGPRingCmdRegs_inv(dev);
+ if (dev_priv->chip_sub_index == CHIP_H6S2) {
+ DRM_INFO("DMA buffer initialized finished. \n");
+ DRM_INFO("Use PCIE Ring Buffer type!");
+ DRM_INFO("Total PCIE DMA buffer size = %8d bytes. \n",
+ lpcmDMAManager->DMASize << 2);
+ } else {
+ DRM_INFO("DMA buffer initialized finished. ");
+ DRM_INFO("Use AGP Ring Buffer type!\n");
+ DRM_INFO("Total AGP DMA buffer size = %8d bytes. \n",
+ lpcmDMAManager->DMASize << 2);
+ }
+ } else if (dev_priv->drm_agp_type == DRM_AGP_DISABLED) {
+ lpcmDMAManager->MaxKickoffSize = 0x0;
+ if (dev_priv->chip_sub_index == CHIP_H6S2)
+ DRM_INFO("PCIE init failed! Use PCI\n");
+ else
+ DRM_INFO("AGP init failed! Use PCI\n");
+ }
+ return 0;
+}
+
+static void
+kickoff_bci_inv(struct drm_via_chrome9_private *dev_priv,
+ struct drm_via_chrome9_flush *dma_info)
+{
+ u32 HdType, dwQWCount, i, dwCount, Addr1, Addr2, SWPointer,
+ SWPointerEnd;
+ unsigned long *pCmdData;
+ int result;
+
+ /*pCmdData = __s3gke_vmalloc(dma_info->cmd_size<<2); */
+ pCmdData = dev_priv->bci_buffer;
+
+ if (!pCmdData)
+ return;
+
+ result = copy_from_user((int *) pCmdData, dma_info->usermode_dma_buf,
+ dma_info->cmd_size << 2);
+
+ SWPointer = 0;
+ SWPointerEnd = (u32) dma_info->cmd_size;
+ while (SWPointer < SWPointerEnd) {
+ HdType = pCmdData[SWPointer] & INV_AGPHeader_MASK;
+ switch (HdType) {
+ case INV_AGPHeader0:
+ case INV_AGPHeader5:
+ dwQWCount = pCmdData[SWPointer + 1];
+ SWPointer += 4;
+
+ for (i = 0; i < dwQWCount; i++) {
+ SetMMIORegister(dev_priv->mmio->handle,
+ pCmdData[SWPointer],
+ pCmdData[SWPointer + 1]);
+ SWPointer += 2;
+ }
+ break;
+
+ case INV_AGPHeader1:
+ dwCount = pCmdData[SWPointer + 1];
+ Addr1 = 0x0;
+ SWPointer += 4; /* skip 128-bit. */
+
+ for (; dwCount > 0; dwCount--, SWPointer++,
+ Addr1 += 4) {
+ SetMMIORegister(dev_priv->hostBlt->handle,
+ Addr1, pCmdData[SWPointer]);
+ }
+ break;
+
+ case INV_AGPHeader4:
+ dwCount = pCmdData[SWPointer + 1];
+ Addr1 = pCmdData[SWPointer] & 0x0000FFFF;
+ SWPointer += 4; /* skip 128-bit. */
+
+ for (; dwCount > 0; dwCount--, SWPointer++)
+ SetMMIORegister(dev_priv->mmio->handle, Addr1,
+ pCmdData[SWPointer]);
+ break;
+
+ case INV_AGPHeader2:
+ Addr1 = pCmdData[SWPointer + 1] & 0xFFFF;
+ Addr2 = pCmdData[SWPointer] & 0xFFFF;
+
+ /* Write first data (either ParaType or whatever) to
+ Addr1 */
+ SetMMIORegister(dev_priv->mmio->handle, Addr1,
+ pCmdData[SWPointer + 2]);
+ SWPointer += 4;
+
+ /* The following data are all written to Addr2,
+ until another header is met */
+ while (!IS_AGPHEADER_INV(pCmdData[SWPointer])
+ && (SWPointer < SWPointerEnd)) {
+ SetMMIORegister(dev_priv->mmio->handle, Addr2,
+ pCmdData[SWPointer]);
+ SWPointer++;
+ }
+ break;
+
+ case INV_AGPHeader3:
+ Addr1 = pCmdData[SWPointer] & 0xFFFF;
+ Addr2 = Addr1 + 4;
+ dwCount = pCmdData[SWPointer + 1];
+
+ /* Write first data (either ParaType or whatever) to
+ Addr1 */
+ SetMMIORegister(dev_priv->mmio->handle, Addr1,
+ pCmdData[SWPointer + 2]);
+ SWPointer += 4;
+
+ for (i = 0; i < dwCount; i++) {
+ SetMMIORegister(dev_priv->mmio->handle, Addr2,
+ pCmdData[SWPointer]);
+ SWPointer++;
+ }
+ break;
+
+ case INV_AGPHeader6:
+ break;
+
+ case INV_AGPHeader7:
+ break;
+
+ default:
+ SWPointer += 4; /* Advance to next header */
+ }
+
+ SWPointer = (SWPointer + 3) & ~3;
+ }
+}
+
+void
+kickoff_dma_db_inv(struct drm_device *dev)
+{
+ struct drm_via_chrome9_private *dev_priv =
+ (struct drm_via_chrome9_private *) dev->dev_private;
+ struct drm_via_chrome9_DMA_manager *lpcmDMAManager =
+ dev_priv->dma_manager;
+
+ u32 BufferSize = (u32) (lpcmDMAManager->pFree - lpcmDMAManager->pBeg);
+
+ unsigned int AGPBufLinearBase =
+ (unsigned int) lpcmDMAManager->addr_linear;
+ unsigned int AGPBufPhysicalBase =
+ (unsigned int) dev->agp->base + lpcmDMAManager->pPhysical;
+ /*add shadow offset */
+
+ unsigned int dwStart, dwEnd, dwPause;
+ unsigned int dwReg60, dwReg61, dwReg62, dwReg63, dwReg64, dwReg65;
+ unsigned int CR_Status;
+
+ if (BufferSize == 0)
+ return;
+
+ /* 256-bit alignment of AGP pause address */
+ if ((u32) ((unsigned long *) lpcmDMAManager->pFree) & 0x1f) {
+ ADDCmdHeader2_INVI(lpcmDMAManager->pFree, INV_REG_CR_TRANS,
+ INV_ParaType_Dummy);
+ do {
+ ADDCmdData_INVI(lpcmDMAManager->pFree, 0xCCCCCCC0);
+ ADDCmdData_INVI(lpcmDMAManager->pFree, 0xDDD00000);
+ }
+ while (((unsigned int) lpcmDMAManager->pFree) & 0x1f)
+ ;
+ }
+
+ dwStart =
+ (u32) (unsigned long *)lpcmDMAManager->pBeg -
+ AGPBufLinearBase + AGPBufPhysicalBase;
+ dwEnd = (u32) (unsigned long *)lpcmDMAManager->pEnd -
+ AGPBufLinearBase + AGPBufPhysicalBase;
+ dwPause =
+ (u32)(unsigned long *)lpcmDMAManager->pFree -
+ AGPBufLinearBase + AGPBufPhysicalBase - 4;
+
+ dwReg60 = INV_SubA_HAGPBstL | INV_HWBasL(dwStart);
+ dwReg61 = INV_SubA_HAGPBstH | INV_HWBasH(dwStart);
+ dwReg62 = INV_SubA_HAGPBendL | INV_HWBasL(dwEnd);
+ dwReg63 = INV_SubA_HAGPBendH | INV_HWBasH(dwEnd);
+ dwReg64 = INV_SubA_HAGPBpL | INV_HWBasL(dwPause);
+ dwReg65 = INV_SubA_HAGPBpID | INV_HWBasH(dwPause) | INV_HAGPBpID_STOP;
+
+ /* wait CR idle */
+ CR_Status = GetMMIORegister(dev_priv->mmio->handle, INV_RB_ENG_STATUS);
+ while (CR_Status & INV_ENG_BUSY_CR)
+ CR_Status =
+ GetMMIORegister(dev_priv->mmio->handle,
+ INV_RB_ENG_STATUS);
+
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS,
+ INV_ParaType_PreCR);
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg60);
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg61);
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg62);
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg63);
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg64);
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg65);
+
+ /* Trigger AGP cycle */
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN,
+ INV_SubA_HFthRCM | INV_HFthRCM_10 | INV_HAGPBTrig);
+
+ if (lpcmDMAManager->pBeg == lpcmDMAManager->addr_linear) {
+ /* The second AGP command buffer */
+ lpcmDMAManager->pBeg =
+ lpcmDMAManager->addr_linear +
+ (lpcmDMAManager->DMASize >> 2);
+ lpcmDMAManager->pEnd =
+ lpcmDMAManager->addr_linear + lpcmDMAManager->DMASize;
+ lpcmDMAManager->pFree = lpcmDMAManager->pBeg;
+ } else {
+ /* The first AGP command buffer */
+ lpcmDMAManager->pBeg = lpcmDMAManager->addr_linear;
+ lpcmDMAManager->pEnd =
+ lpcmDMAManager->addr_linear +
+ (lpcmDMAManager->DMASize / 2) - 1;
+ lpcmDMAManager->pFree = lpcmDMAManager->pBeg;
+ }
+ CR_Status = GetMMIORegister(dev_priv->mmio->handle, INV_RB_ENG_STATUS);
+}
+
+
+void
+kickoff_dma_ring_inv(struct drm_device *dev)
+{
+ unsigned int dwPause, dwReg64, dwReg65;
+
+ struct drm_via_chrome9_private *dev_priv =
+ (struct drm_via_chrome9_private *) dev->dev_private;
+ struct drm_via_chrome9_DMA_manager *lpcmDMAManager =
+ dev_priv->dma_manager;
+
+ unsigned int AGPBufLinearBase =
+ (unsigned int) lpcmDMAManager->addr_linear;
+ unsigned int AGPBufPhysicalBase =
+ (dev_priv->chip_agp ==
+ CHIP_PCIE) ? 0 : (unsigned int) dev->agp->base +
+ lpcmDMAManager->pPhysical;
+ /*add shadow offset */
+
+ /* 256-bit alignment of AGP pause address */
+ if (dev_priv->chip_sub_index == CHIP_H6S2) {
+ if ((u32)
+ ((unsigned long *) lpcmDMAManager->pFree) & 0x7f) {
+ ADDCmdHeader2_INVI(lpcmDMAManager->pFree,
+ INV_REG_CR_TRANS,
+ INV_ParaType_Dummy);
+ do {
+ ADDCmdData_INVI(lpcmDMAManager->pFree,
+ 0xCCCCCCC0);
+ ADDCmdData_INVI(lpcmDMAManager->pFree,
+ 0xDDD00000);
+ }
+ while ((u32)((unsigned long *) lpcmDMAManager->pFree) &
+ 0x7f)
+ ;
+ }
+ } else {
+ if ((u32)
+ ((unsigned long *) lpcmDMAManager->pFree) & 0x1f) {
+ ADDCmdHeader2_INVI(lpcmDMAManager->pFree,
+ INV_REG_CR_TRANS,
+ INV_ParaType_Dummy);
+ do {
+ ADDCmdData_INVI(lpcmDMAManager->pFree,
+ 0xCCCCCCC0);
+ ADDCmdData_INVI(lpcmDMAManager->pFree,
+ 0xDDD00000);
+ }
+ while ((u32)((unsigned long *) lpcmDMAManager->pFree) &
+ 0x1f)
+ ;
+ }
+ }
+
+
+ dwPause = (u32) ((unsigned long *) lpcmDMAManager->pFree)
+ - AGPBufLinearBase + AGPBufPhysicalBase - 16;
+
+ dwReg64 = INV_SubA_HAGPBpL | INV_HWBasL(dwPause);
+ dwReg65 = INV_SubA_HAGPBpID | INV_HWBasH(dwPause) | INV_HAGPBpID_PAUSE;
+
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS,
+ INV_ParaType_PreCR);
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg64);
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg65);
+
+ lpcmDMAManager->pInUseBySW = lpcmDMAManager->pFree;
+}
+
+static int
+waitchipidle_inv(struct drm_via_chrome9_private *dev_priv)
+{
+ unsigned int count = 50000;
+ unsigned int eng_status;
+ unsigned int engine_busy;
+
+ do {
+ eng_status =
+ GetMMIORegister(dev_priv->mmio->handle,
+ INV_RB_ENG_STATUS);
+ engine_busy = eng_status & INV_ENG_BUSY_ALL;
+ count--;
+ }
+ while (engine_busy && count)
+ ;
+ if (count && engine_busy == 0)
+ return 0;
+ return -1;
+}
+
+void
+get_space_db_inv(struct drm_device *dev,
+ struct cmd_get_space *lpcmGetSpaceData)
+{
+ struct drm_via_chrome9_private *dev_priv =
+ (struct drm_via_chrome9_private *) dev->dev_private;
+ struct drm_via_chrome9_DMA_manager *lpcmDMAManager =
+ dev_priv->dma_manager;
+
+ unsigned int dwRequestSize = lpcmGetSpaceData->dwRequestSize;
+ if (dwRequestSize > lpcmDMAManager->MaxKickoffSize) {
+ DRM_INFO("too big DMA buffer request!!!\n");
+ via_chrome9ke_assert(0);
+ *lpcmGetSpaceData->pCmdData = (unsigned int) NULL;
+ return;
+ }
+
+ if ((lpcmDMAManager->pFree + dwRequestSize) >
+ (lpcmDMAManager->pEnd - INV_CMDBUF_THRESHOLD * 2))
+ kickoff_dma_db_inv(dev);
+
+ *lpcmGetSpaceData->pCmdData = (unsigned int) lpcmDMAManager->pFree;
+}
+
+void
+RewindRingAGP_inv(struct drm_device *dev)
+{
+ struct drm_via_chrome9_private *dev_priv =
+ (struct drm_via_chrome9_private *) dev->dev_private;
+ struct drm_via_chrome9_DMA_manager *lpcmDMAManager =
+ dev_priv->dma_manager;
+
+ unsigned int AGPBufLinearBase =
+ (unsigned int) lpcmDMAManager->addr_linear;
+ unsigned int AGPBufPhysicalBase =
+ (dev_priv->chip_agp ==
+ CHIP_PCIE) ? 0 : (unsigned int) dev->agp->base +
+ lpcmDMAManager->pPhysical;
+ /*add shadow offset */
+
+ unsigned int dwPause, dwJump;
+ unsigned int dwReg66, dwReg67;
+ unsigned int dwReg64, dwReg65;
+
+ ADDCmdHeader2_INVI(lpcmDMAManager->pFree, INV_REG_CR_TRANS,
+ INV_ParaType_Dummy);
+ ADDCmdData_INVI(lpcmDMAManager->pFree, 0xCCCCCCC7);
+ if (dev_priv->chip_sub_index == CHIP_H6S2)
+ while ((unsigned int) lpcmDMAManager->pFree & 0x7F)
+ ADDCmdData_INVI(lpcmDMAManager->pFree, 0xCCCCCCC7);
+ else
+ while ((unsigned int) lpcmDMAManager->pFree & 0x1F)
+ ADDCmdData_INVI(lpcmDMAManager->pFree, 0xCCCCCCC7);
+ dwJump = ((u32) ((unsigned long *) lpcmDMAManager->pFree))
+ - AGPBufLinearBase + AGPBufPhysicalBase - 16;
+
+ lpcmDMAManager->pFree = lpcmDMAManager->pBeg;
+
+ dwPause = ((u32) ((unsigned long *) lpcmDMAManager->pFree))
+ - AGPBufLinearBase + AGPBufPhysicalBase - 16;
+
+ dwReg64 = INV_SubA_HAGPBpL | INV_HWBasL(dwPause);
+ dwReg65 = INV_SubA_HAGPBpID | INV_HWBasH(dwPause) | INV_HAGPBpID_PAUSE;
+
+ dwReg66 = INV_SubA_HAGPBjumpL | INV_HWBasL(dwJump);
+ dwReg67 = INV_SubA_HAGPBjumpH | INV_HWBasH(dwJump);
+
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS,
+ INV_ParaType_PreCR);
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg66);
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg67);
+
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg64);
+ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg65);
+ lpcmDMAManager->pInUseBySW = lpcmDMAManager->pFree;
+}
+
+
+void
+get_space_ring_inv(struct drm_device *dev,
+ struct cmd_get_space *lpcmGetSpaceData)
+{
+ struct drm_via_chrome9_private *dev_priv =
+ (struct drm_via_chrome9_private *) dev->dev_private;
+ struct drm_via_chrome9_DMA_manager *lpcmDMAManager =
+ dev_priv->dma_manager;
+ unsigned int dwUnFlushed;
+ unsigned int dwRequestSize = lpcmGetSpaceData->dwRequestSize;
+
+ unsigned int AGPBufLinearBase =
+ (unsigned int) lpcmDMAManager->addr_linear;
+ unsigned int AGPBufPhysicalBase =
+ (dev_priv->chip_agp ==
+ CHIP_PCIE) ? 0 : (unsigned int) dev->agp->base +
+ lpcmDMAManager->pPhysical;
+ /*add shadow offset */
+ u32 BufStart, BufEnd, CurSW, CurHW, NextSW, BoundaryCheck;
+
+ dwUnFlushed =
+ (unsigned int) (lpcmDMAManager->pFree - lpcmDMAManager->pBeg);
+ /*default bEnableModuleSwitch is on for metro,is off for rest */
+ /*cmHW_Module_Switch is context-wide variable which is enough for 2d/3d
+ switch in a context. */
+ /*But we must keep the dma buffer being wrapped head and tail by 3d cmds
+ when it is kicked off to kernel mode. */
+ /*Get DMA Space (If requested, or no BCI space and BCI not forced. */
+
+ if (dwRequestSize > lpcmDMAManager->MaxKickoffSize) {
+ DRM_INFO("too big DMA buffer request!!!\n");
+ via_chrome9ke_assert(0);
+ *lpcmGetSpaceData->pCmdData = 0;
+ return;
+ }
+
+ if (dwUnFlushed + dwRequestSize > lpcmDMAManager->MaxKickoffSize)
+ kickoff_dma_ring_inv(dev);
+
+ BufStart =
+ (u32)((unsigned int) lpcmDMAManager->pBeg) - AGPBufLinearBase +
+ AGPBufPhysicalBase;
+ BufEnd = (u32)((unsigned int) lpcmDMAManager->pEnd) - AGPBufLinearBase +
+ AGPBufPhysicalBase;
+ dwRequestSize = lpcmGetSpaceData->dwRequestSize << 2;
+ NextSW = (u32) ((unsigned int) lpcmDMAManager->pFree) + dwRequestSize +
+ INV_CMDBUF_THRESHOLD * 8 - AGPBufLinearBase +
+ AGPBufPhysicalBase;
+
+ CurSW = (u32)((unsigned int) lpcmDMAManager->pFree) - AGPBufLinearBase +
+ AGPBufPhysicalBase;
+ CurHW = GetMMIORegister(dev_priv->mmio->handle, INV_RB_AGPCMD_CURRADDR);
+
+ if (NextSW >= BufEnd) {
+ kickoff_dma_ring_inv(dev);
+ CurSW = (u32) ((unsigned int) lpcmDMAManager->pFree) -
+ AGPBufLinearBase + AGPBufPhysicalBase;
+ /* make sure the last rewind is completed */
+ CurHW = GetMMIORegister(dev_priv->mmio->handle,
+ INV_RB_AGPCMD_CURRADDR);
+ while (CurHW > CurSW)
+ CurHW = GetMMIORegister(dev_priv->mmio->handle,
+ INV_RB_AGPCMD_CURRADDR);
+ /* Sometime the value read from HW is unreliable,
+ so need double confirm. */
+ CurHW = GetMMIORegister(dev_priv->mmio->handle,
+ INV_RB_AGPCMD_CURRADDR);
+ while (CurHW > CurSW)
+ CurHW = GetMMIORegister(dev_priv->mmio->handle,
+ INV_RB_AGPCMD_CURRADDR);
+ BoundaryCheck =
+ BufStart + dwRequestSize + INV_QW_PAUSE_ALIGN * 16;
+ if (BoundaryCheck >= BufEnd)
+ /* If an empty command buffer can't hold
+ the request data. */
+ via_chrome9ke_assert(0);
+ else {
+ /* We need to guarntee the new commands have no chance
+ to override the unexected commands or wait until there
+ is no unexecuted commands in agp buffer */
+ if (CurSW <= BoundaryCheck) {
+ CurHW = GetMMIORegister(dev_priv->mmio->handle,
+ INV_RB_AGPCMD_CURRADDR);
+ while (CurHW < CurSW)
+ CurHW = GetMMIORegister(
+ dev_priv->mmio->handle,
+ INV_RB_AGPCMD_CURRADDR);
+ /*Sometime the value read from HW is unreliable,
+ so need double confirm. */
+ CurHW = GetMMIORegister(dev_priv->mmio->handle,
+ INV_RB_AGPCMD_CURRADDR);
+ while (CurHW < CurSW) {
+ CurHW = GetMMIORegister(
+ dev_priv->mmio->handle,
+ INV_RB_AGPCMD_CURRADDR);
+ }
+ RewindRingAGP_inv(dev);
+ CurSW = (u32) ((unsigned long *)
+ lpcmDMAManager->pFree) -
+ AGPBufLinearBase + AGPBufPhysicalBase;
+ CurHW = GetMMIORegister(dev_priv->mmio->handle,
+ INV_RB_AGPCMD_CURRADDR);
+ /* Waiting until hw pointer jump to start
+ and hw pointer will */
+ /* equal to sw pointer */
+ while (CurHW != CurSW) {
+ CurHW = GetMMIORegister(
+ dev_priv->mmio->handle,
+ INV_RB_AGPCMD_CURRADDR);
+ }
+ } else {
+ CurHW = GetMMIORegister(dev_priv->mmio->handle,
+ INV_RB_AGPCMD_CURRADDR);
+
+ while (CurHW <= BoundaryCheck) {
+ CurHW = GetMMIORegister(
+ dev_priv->mmio->handle,
+ INV_RB_AGPCMD_CURRADDR);
+ }
+ CurHW = GetMMIORegister(dev_priv->mmio->handle,
+ INV_RB_AGPCMD_CURRADDR);
+ /* Sometime the value read from HW is
+ unreliable, so need double confirm. */
+ while (CurHW <= BoundaryCheck) {
+ CurHW = GetMMIORegister(
+ dev_priv->mmio->handle,
+ INV_RB_AGPCMD_CURRADDR);
+ }
+ RewindRingAGP_inv(dev);
+ }
+ }
+ } else {
+ /* no need to rewind Ensure unexecuted agp commands will
+ not be override by new
+ agp commands */
+ CurSW = (u32) ((unsigned int) lpcmDMAManager->pFree) -
+ AGPBufLinearBase + AGPBufPhysicalBase;
+ CurHW = GetMMIORegister(dev_priv->mmio->handle,
+ INV_RB_AGPCMD_CURRADDR);
+
+ while ((CurHW > CurSW) && (CurHW <= NextSW))
+ CurHW = GetMMIORegister(dev_priv->mmio->handle,
+ INV_RB_AGPCMD_CURRADDR);
+
+ /* Sometime the value read from HW is unreliable,
+ so need double confirm. */
+ CurHW = GetMMIORegister(dev_priv->mmio->handle,
+ INV_RB_AGPCMD_CURRADDR);
+ while ((CurHW > CurSW) && (CurHW <= NextSW))
+ CurHW = GetMMIORegister(dev_priv->mmio->handle,
+ INV_RB_AGPCMD_CURRADDR);
+ }
+ /*return the space handle */
+ *lpcmGetSpaceData->pCmdData = (unsigned int) lpcmDMAManager->pFree;
+}
+
+void
+release_space_inv(struct drm_device *dev,
+ struct cmd_release_space *lpcmReleaseSpaceData)
+{
+ struct drm_via_chrome9_private *dev_priv =
+ (struct drm_via_chrome9_private *) dev->dev_private;
+ struct drm_via_chrome9_DMA_manager *lpcmDMAManager =
+ dev_priv->dma_manager;
+ unsigned int dwReleaseSize = lpcmReleaseSpaceData->dwReleaseSize;
+ int i = 0;
+
+ lpcmDMAManager->pFree += dwReleaseSize;
+
+ /* aligned address */
+ while (((unsigned int) lpcmDMAManager->pFree) & 0xF) {
+ /* not in 4 unsigned ints (16 Bytes) align address,
+ insert NULL Commands */
+ *lpcmDMAManager->pFree++ = NULL_COMMAND_INV[i & 0x3];
+ i++;
+ }
+
+ if ((dev_priv->chip_sub_index == CHIP_H5)
+ && (dev_priv->drm_agp_type == DRM_AGP_RING_BUFFER)) {
+ ADDCmdHeader2_INVI(lpcmDMAManager->pFree, INV_REG_CR_TRANS,
+ INV_ParaType_Dummy);
+ for (i = 0; i < NULLCOMMANDNUMBER; i++)
+ ADDCmdData_INVI(lpcmDMAManager->pFree, 0xCC000000);
+ }
+}
+
+int
+via_chrome9_ioctl_flush(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_via_chrome9_flush *dma_info = data;
+ struct drm_via_chrome9_private *dev_priv =
+ (struct drm_via_chrome9_private *) dev->dev_private;
+ int ret = 0;
+ int result = 0;
+ struct cmd_get_space getspace;
+ struct cmd_release_space releasespace;
+ volatile unsigned long *pCmdData = NULL;
+
+ switch (dma_info->dma_cmd_type) {
+ /* Copy DMA buffer to BCI command buffer */
+ case flush_bci:
+ case flush_bci_and_wait:
+ if (dma_info->cmd_size <= 0)
+ return 0;
+ if (dma_info->cmd_size > MAX_BCI_BUFFER_SIZE) {
+ DRM_INFO("too big BCI space request!!!\n");
+ return 0;
+ }
+
+ kickoff_bci_inv(dev_priv, dma_info);
+ waitchipidle_inv(dev_priv);
+ break;
+ /* Use DRM DMA buffer manager to kick off DMA directly */
+ case dma_kickoff:
+ break;
+
+ /* Copy user mode DMA buffer to kernel DMA buffer,
+ then kick off DMA */
+ case flush_dma_buffer:
+ case flush_dma_and_wait:
+ if (dma_info->cmd_size <= 0)
+ return 0;
+
+ getspace.dwRequestSize = dma_info->cmd_size;
+ if ((dev_priv->chip_sub_index == CHIP_H5)
+ && (dev_priv->drm_agp_type == DRM_AGP_RING_BUFFER))
+ getspace.dwRequestSize += (NULLCOMMANDNUMBER + 4);
+ /*henry:Patch for VT3293 agp ring buffer stability */
+ getspace.pCmdData = (unsigned int *) &pCmdData;
+
+ if (dev_priv->drm_agp_type == DRM_AGP_DOUBLE_BUFFER)
+ get_space_db_inv(dev, &getspace);
+ else if (dev_priv->drm_agp_type == DRM_AGP_RING_BUFFER)
+ get_space_ring_inv(dev, &getspace);
+
+ if (pCmdData) {
+ /*copy data from userspace to kernel-dma-agp buffer */
+ result = copy_from_user((int *)
+ pCmdData,
+ dma_info->usermode_dma_buf,
+ dma_info->cmd_size << 2);
+ releasespace.dwReleaseSize = dma_info->cmd_size;
+ release_space_inv(dev, &releasespace);
+
+ if (dev_priv->drm_agp_type == DRM_AGP_DOUBLE_BUFFER)
+ kickoff_dma_db_inv(dev);
+ else if (dev_priv->drm_agp_type == DRM_AGP_RING_BUFFER)
+ kickoff_dma_ring_inv(dev);
+
+ if (dma_info->dma_cmd_type == flush_dma_and_wait)
+ waitchipidle_inv(dev_priv);
+ } else {
+ DRM_INFO("No enough DMA space");
+ ret = -ENOMEM;
+ }
+ break;
+
+ default:
+ DRM_INFO("Invalid DMA buffer type");
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+int
+via_chrome9_ioctl_free(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ return 0;
+}
+
+int
+via_chrome9_ioctl_wait_chip_idle(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_via_chrome9_private *dev_priv =
+ (struct drm_via_chrome9_private *) dev->dev_private;
+
+ waitchipidle_inv(dev_priv);
+ /* maybe_bug here, do we always return 0 */
+ return 0;
+}
+
+int
+via_chrome9_ioctl_flush_cache(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ return 0;
+}
--- /dev/null
+++ b/drivers/char/drm/via_chrome9_dma.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. 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, sub license,
+ * 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, 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.
+ */
+#ifndef _VIA_CHROME9_DMA_H_
+#define _VIA_CHROME9_DMA_H_
+
+#define MAX_BCI_BUFFER_SIZE 16*1024*1024
+
+enum cmd_request_type {
+ CM_REQUEST_BCI,
+ CM_REQUEST_DMA,
+ CM_REQUEST_RB,
+ CM_REQUEST_RB_FORCED_DMA,
+ CM_REQUEST_NOTAVAILABLE
+};
+
+struct cmd_get_space {
+ unsigned int dwRequestSize;
+ enum cmd_request_type hint;
+ volatile unsigned int *pCmdData;
+};
+
+struct cmd_release_space {
+ unsigned int dwReleaseSize;
+};
+
+extern int via_chrome9_hw_init(struct drm_device *dev,
+ struct drm_via_chrome9_init *init);
+extern int via_chrome9_ioctl_flush(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int via_chrome9_ioctl_free(struct drm_device *dev, void *data,
+ struct drm_file *file_prev);
+extern int via_chrome9_ioctl_wait_chip_idle(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+extern int via_chrome9_ioctl_flush_cache(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+extern int via_chrome9_ioctl_flush(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int via_chrome9_ioctl_free(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern unsigned int ProtectSizeValue(unsigned int size);
+extern void SetAGPDoubleCmd_inv(struct drm_device *dev);
+extern void SetAGPRingCmdRegs_inv(struct drm_device *dev);
+
+#endif
--- /dev/null
+++ b/drivers/char/drm/via_chrome9_drm.c
@@ -0,0 +1,993 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. 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, sub license,
+ * 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
+ * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, 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.
+ */
+#include "drmP.h"
+#include "via_chrome9_drm.h"
+#include "via_chrome9_drv.h"
+#include "via_chrome9_mm.h"
+#include "via_chrome9_dma.h"
+#include "via_chrome9_3d_reg.h"
+
+#define VIA_CHROME9DRM_VIDEO_STARTADDRESS_ALIGNMENT 10
+
+
+void __via_chrome9ke_udelay(unsigned long usecs)
+{
+ unsigned long start;
+ unsigned long stop;
+ unsigned long period;
+ unsigned long wait_period;
+ struct timespec tval;
+
+#ifdef NDELAY_LIMIT
+#define UDELAY_LIMIT (NDELAY_LIMIT/1000) /* supposed to be 10 msec */
+#else
+#define UDELAY_LIMIT (10000) /* 10 msec */
+#endif
+
+ if (usecs > UDELAY_LIMIT) {
+ start = jiffies;
+ tval.tv_sec = usecs / 1000000;
+ tval.tv_nsec = (usecs - tval.tv_sec * 1000000) * 1000;
+ wait_period = timespec_to_jiffies(&tval);
+ do {
+ stop = jiffies;
+
+ if (stop < start)
+ period = ((unsigned long)-1 - start) + stop + 1;
+ else
+ period = stop - start;
+
+ } while (period < wait_period);
+ } else
+ udelay(usecs); /* delay value might get checked once again */
+}
+
+int via_chrome9_ioctl_process_exit(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ return 0;
+}
+
+int via_chrome9_ioctl_restore_primary(struct drm_device *dev,
+ void *data, struct drm_file *file_priv)
+{
+ return 0;
+}
+
+void Initialize3DEngine(struct drm_via_chrome9_private *dev_priv)
+{
+ int i;
+ unsigned int StageOfTexture;
+
+ if (dev_priv->chip_sub_index == CHIP_H5 ||
+ dev_priv->chip_sub_index == CHIP_H5S1) {
+ SetMMIORegister(dev_priv->mmio->handle, 0x43C,
+ 0x00010000);
+
+ for (i = 0; i <= 0x8A; i++) {
+ SetMMIORegister(dev_priv->mmio->handle, 0x440,
+ (unsigned int) i << 24);
+ }
+
+ /* Initial Texture Stage Setting*/
+ for (StageOfTexture = 0; StageOfTexture < 0xf;
+ StageOfTexture++) {
+ SetMMIORegister(dev_priv->mmio->handle, 0x43C,
+ (0x00020000 | 0x00000000 |
+ (StageOfTexture & 0xf)<<24));
+ /* *((unsigned int volatile*)(pMapIOPort+HC_REG_TRANS_SET)) =
+ (0x00020000 | HC_ParaSubType_Tex0 | (StageOfTexture &
+ 0xf)<<24);*/
+ for (i = 0 ; i <= 0x30 ; i++) {
+ /* *((unsigned int volatile*)(pMapIOPort+
+ HC_REG_Hpara0)) = ((unsigned int) i << 24);*/
+ SetMMIORegister(dev_priv->mmio->handle,
+ 0x440, (unsigned int) i << 24);
+ }
+ }
+
+ /* Initial Texture Sampler Setting*/
+ for (StageOfTexture = 0; StageOfTexture < 0xf;
+ StageOfTexture++) {
+ SetMMIORegister(dev_priv->mmio->handle, 0x43C,
+ (0x00020000 | 0x00020000 |
+ (StageOfTexture & 0xf)<<24));
+ /* *((unsigned int volatile*)(pMapIOPort+
+ HC_REG_TRANS_SET)) = (0x00020000 | 0x00020000 |
+ ( StageOfTexture & 0xf)<<24);*/
+ for (i = 0 ; i <= 0x30 ; i++) {
+ /* *((unsigned int volatile*)(pMapIOPort+
+ HC_REG_Hpara0)) = ((unsigned int) i << 24);*/
+ SetMMIORegister(dev_priv->mmio->handle,
+ 0x440, (unsigned int) i << 24);
+ }
+ }
+
+ SetMMIORegister(dev_priv->mmio->handle, 0x43C,
+ (0x00020000 | 0xfe000000));
+ /* *((unsigned int volatile*)(pMapIOPort+HC_REG_TRANS_SET)) =
+ (0x00020000 | HC_P