diff options
| author | Ian Romanick <idr@us.ibm.com> | 2007-09-06 15:37:52 -0700 | 
|---|---|---|
| committer | Ian Romanick <idr@us.ibm.com> | 2007-09-06 15:37:52 -0700 | 
| commit | 54c96cbc46a21e05cf991d0e4a26da58bd87ce85 (patch) | |
| tree | 19bd9c681b3a07bebdb17964c392c28940367045 /linux-core | |
| parent | edf5a86a269690b0e42a5cee7d4ac3828b42ca3e (diff) | |
| parent | c597bd57eee3ea05a3b8c851615c7351d0b32fce (diff) | |
Merge branch 'xgi-0-0-2'
Diffstat (limited to 'linux-core')
| -rw-r--r-- | linux-core/Makefile | 8 | ||||
| -rw-r--r-- | linux-core/Makefile.kernel | 3 | ||||
| -rw-r--r-- | linux-core/xgi_cmdlist.c | 322 | ||||
| -rw-r--r-- | linux-core/xgi_cmdlist.h | 66 | ||||
| l--------- | linux-core/xgi_drm.h | 1 | ||||
| -rw-r--r-- | linux-core/xgi_drv.c | 428 | ||||
| -rw-r--r-- | linux-core/xgi_drv.h | 114 | ||||
| -rw-r--r-- | linux-core/xgi_fb.c | 123 | ||||
| -rw-r--r-- | linux-core/xgi_fence.c | 127 | ||||
| -rw-r--r-- | linux-core/xgi_misc.c | 477 | ||||
| -rw-r--r-- | linux-core/xgi_misc.h | 37 | ||||
| -rw-r--r-- | linux-core/xgi_pcie.c | 126 | ||||
| -rw-r--r-- | linux-core/xgi_regs.h | 169 | 
13 files changed, 2000 insertions, 1 deletions
| diff --git a/linux-core/Makefile b/linux-core/Makefile index 1758777c..55e25253 100644 --- a/linux-core/Makefile +++ b/linux-core/Makefile @@ -58,7 +58,7 @@ endif  # Modules for all architectures  MODULE_LIST := drm.o tdfx.o r128.o radeon.o mga.o sis.o savage.o via.o \ -               mach64.o nv.o nouveau.o +               mach64.o nv.o nouveau.o xgi.o  # Modules only for ix86 architectures  ifneq (,$(findstring 86,$(MACHINE))) @@ -91,6 +91,7 @@ MACH64HEADERS = mach64_drv.h mach64_drm.h $(DRMHEADERS)  NVHEADERS =     nv_drv.h $(DRMHEADERS)  FFBHEADERS = 	ffb_drv.h $(DRMHEADERS)  NOUVEAUHEADERS = nouveau_drv.h nouveau_drm.h nouveau_reg.h $(DRMHEADERS) +XGIHEADERS = xgi_cmdlist.h xgi_drv.h xgi_misc.h xgi_regs.h $(DRMHEADERS)  PROGS = dristat drmstat @@ -284,6 +285,7 @@ CONFIG_DRM_VIA := n  CONFIG_DRM_MACH64 := n  CONFIG_DRM_NV := n  CONFIG_DRM_NOUVEAU := n +CONFIG_DRM_XGI := n  # Enable module builds for the modules requested/supported. @@ -320,6 +322,9 @@ endif  ifneq (,$(findstring nouveau,$(DRM_MODULES)))  CONFIG_DRM_NOUVEAU := m  endif +ifneq (,$(findstring xgi,$(DRM_MODULES))) +CONFIG_DRM_XGI := m +endif  # These require AGP support @@ -347,6 +352,7 @@ $(via-objs):	$(VIAHEADERS)  $(mach64-objs): $(MACH64HEADERS)  $(nv-objs):     $(NVHEADERS)  $(nouveau-objs): $(NOUVEAUHEADERS) +$(xgi-objs):    $(XGIHEADERS)  endif diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 3d00cbe6..ac77941e 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -38,6 +38,8 @@ 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_fence.o via_buffer.o  mach64-objs := mach64_drv.o mach64_dma.o mach64_irq.o mach64_state.o  nv-objs := nv_drv.o +xgi-objs    := xgi_cmdlist.o xgi_drv.o xgi_fb.o xgi_misc.o xgi_pcie.o \ +		xgi_fence.o  ifeq ($(CONFIG_COMPAT),y)  drm-objs    += drm_ioc32.o @@ -62,3 +64,4 @@ obj-$(CONFIG_DRM_VIA)   += via.o  obj-$(CONFIG_DRM_MACH64)+= mach64.o  obj-$(CONFIG_DRM_NV)    += nv.o  obj-$(CONFIG_DRM_NOUVEAU) += nouveau.o +obj-$(CONFIG_DRM_XGI)   += xgi.o
\ No newline at end of file diff --git a/linux-core/xgi_cmdlist.c b/linux-core/xgi_cmdlist.c new file mode 100644 index 00000000..261f4e13 --- /dev/null +++ b/linux-core/xgi_cmdlist.c @@ -0,0 +1,322 @@ +/**************************************************************************** + * Copyright (C) 2003-2006 by XGI Technology, Taiwan. + * + * 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 on 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 NON-INFRINGEMENT.  IN NO EVENT SHALL + * XGI 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 "xgi_drv.h" +#include "xgi_regs.h" +#include "xgi_misc.h" +#include "xgi_cmdlist.h" + +static void xgi_emit_flush(struct xgi_info * info, bool stop); +static void xgi_emit_nop(struct xgi_info * info); +static unsigned int get_batch_command(enum xgi_batch_type type); +static void triggerHWCommandList(struct xgi_info * info); +static void xgi_cmdlist_reset(struct xgi_info * info); + + +/** + * Graphic engine register (2d/3d) acessing interface + */ +static inline void dwWriteReg(struct drm_map * map, u32 addr, u32 data) +{ +#ifdef XGI_MMIO_DEBUG +	DRM_INFO("mmio_map->handle = 0x%p, addr = 0x%x, data = 0x%x\n", +		 map->handle, addr, data); +#endif +	DRM_WRITE32(map, addr, data); +} + + +int xgi_cmdlist_initialize(struct xgi_info * info, size_t size, +			   struct drm_file * filp) +{ +	struct xgi_mem_alloc mem_alloc = { +		.location = XGI_MEMLOC_NON_LOCAL, +		.size = size, +	}; +	int err; + +	err = xgi_alloc(info, &mem_alloc, filp); +	if (err) { +		return err; +	} + +	info->cmdring.ptr = xgi_find_pcie_virt(info, mem_alloc.hw_addr); +	info->cmdring.size = mem_alloc.size; +	info->cmdring.ring_hw_base = mem_alloc.hw_addr; +	info->cmdring.last_ptr = NULL; +	info->cmdring.ring_offset = 0; + +	return 0; +} + + +/** + * get_batch_command - Get the command ID for the current begin type. + * @type: Type of the current batch + * + * See section 3.2.2 "Begin" (page 15) of the 3D SPG. + *  + * This function assumes that @type is on the range [0,3]. + */ +unsigned int get_batch_command(enum xgi_batch_type type) +{ +	static const unsigned int ports[4] = { +		0x30 >> 2, 0x40 >> 2, 0x50 >> 2, 0x20 >> 2 +	}; +	 +	return ports[type]; +} + + +int xgi_submit_cmdlist(struct drm_device * dev, void * data, +		       struct drm_file * filp) +{ +	struct xgi_info *const info = dev->dev_private; +	const struct xgi_cmd_info *const pCmdInfo = +		(struct xgi_cmd_info *) data; +	const unsigned int cmd = get_batch_command(pCmdInfo->type); +	u32 begin[4]; + + +	begin[0] = (cmd << 24) | BEGIN_VALID_MASK +		| (BEGIN_BEGIN_IDENTIFICATION_MASK & info->next_sequence); +	begin[1] = BEGIN_LINK_ENABLE_MASK | pCmdInfo->size; +	begin[2] = pCmdInfo->hw_addr >> 4; +	begin[3] = 0; + +	if (info->cmdring.last_ptr == NULL) { +		const unsigned int portOffset = BASE_3D_ENG + (cmd << 2); + + +		/* Enable PCI Trigger Mode +		 */ +		dwWriteReg(info->mmio_map, +			   BASE_3D_ENG + M2REG_AUTO_LINK_SETTING_ADDRESS, +			   (M2REG_AUTO_LINK_SETTING_ADDRESS << 22) | +			   M2REG_CLEAR_COUNTERS_MASK | 0x08 | +			   M2REG_PCI_TRIGGER_MODE_MASK); + +		dwWriteReg(info->mmio_map, +			   BASE_3D_ENG + M2REG_AUTO_LINK_SETTING_ADDRESS, +			   (M2REG_AUTO_LINK_SETTING_ADDRESS << 22) | 0x08 | +			   M2REG_PCI_TRIGGER_MODE_MASK); + + +		/* Send PCI begin command +		 */ +		dwWriteReg(info->mmio_map, portOffset,      begin[0]); +		dwWriteReg(info->mmio_map, portOffset +  4, begin[1]); +		dwWriteReg(info->mmio_map, portOffset +  8, begin[2]); +		dwWriteReg(info->mmio_map, portOffset + 12, begin[3]); +	} else { +		DRM_DEBUG("info->cmdring.last_ptr != NULL\n"); + +		if (pCmdInfo->type == BTYPE_3D) { +			xgi_emit_flush(info, FALSE); +		} + +		info->cmdring.last_ptr[1] = begin[1]; +		info->cmdring.last_ptr[2] = begin[2]; +		info->cmdring.last_ptr[3] = begin[3]; +		DRM_WRITEMEMORYBARRIER(); +		info->cmdring.last_ptr[0] = begin[0]; + +		triggerHWCommandList(info); +	} + +	info->cmdring.last_ptr = xgi_find_pcie_virt(info, pCmdInfo->hw_addr); +	drm_fence_flush_old(info->dev, 0, info->next_sequence); +	return 0; +} + + +/* +    state:      0 - console +                1 - graphic +                2 - fb +                3 - logout +*/ +int xgi_state_change(struct xgi_info * info, unsigned int to,  +		     unsigned int from) +{ +#define STATE_CONSOLE   0 +#define STATE_GRAPHIC   1 +#define STATE_FBTERM    2 +#define STATE_LOGOUT    3 +#define STATE_REBOOT    4 +#define STATE_SHUTDOWN  5 + +	if ((from == STATE_GRAPHIC) && (to == STATE_CONSOLE)) { +		DRM_INFO("Leaving graphical mode (probably VT switch)\n"); +	} else if ((from == STATE_CONSOLE) && (to == STATE_GRAPHIC)) { +		DRM_INFO("Entering graphical mode (probably VT switch)\n"); +		xgi_cmdlist_reset(info); +	} else if ((from == STATE_GRAPHIC) +		   && ((to == STATE_LOGOUT) +		       || (to == STATE_REBOOT) +		       || (to == STATE_SHUTDOWN))) { +		DRM_INFO("Leaving graphical mode (probably X shutting down)\n"); +	} else { +		DRM_ERROR("Invalid state change.\n"); +		return -EINVAL; +	} + +	return 0; +} + + +int xgi_state_change_ioctl(struct drm_device * dev, void * data, +			   struct drm_file * filp) +{ +	struct xgi_state_info *const state = +		(struct xgi_state_info *) data; +	struct xgi_info *info = dev->dev_private; + + +	return xgi_state_change(info, state->_toState, state->_fromState); +} + + +void xgi_cmdlist_reset(struct xgi_info * info) +{ +	info->cmdring.last_ptr = NULL; +	info->cmdring.ring_offset = 0; +} + + +void xgi_cmdlist_cleanup(struct xgi_info * info) +{ +	if (info->cmdring.ring_hw_base != 0) { +		/* If command lists have been issued, terminate the command +		 * list chain with a flush command. +		 */ +		if (info->cmdring.last_ptr != NULL) { +			xgi_emit_flush(info, FALSE); +			xgi_emit_nop(info); +		} + +		xgi_waitfor_pci_idle(info); +		 +		(void) memset(&info->cmdring, 0, sizeof(info->cmdring)); +	} +} + +static void triggerHWCommandList(struct xgi_info * info) +{ +	static unsigned int s_triggerID = 1; + +	dwWriteReg(info->mmio_map, +		   BASE_3D_ENG + M2REG_PCI_TRIGGER_REGISTER_ADDRESS, +		   0x05000000 + (0x0ffff & s_triggerID++)); +} + + +/** + * Emit a flush to the CRTL command stream. + * @info XGI info structure + * + * This function assumes info->cmdring.ptr is non-NULL. + */ +void xgi_emit_flush(struct xgi_info * info, bool stop) +{ +	const u32 flush_command[8] = { +		((0x10 << 24)  +		 | (BEGIN_BEGIN_IDENTIFICATION_MASK & info->next_sequence)), +		BEGIN_LINK_ENABLE_MASK | (0x00004), +		0x00000000, 0x00000000, + +		/* Flush the 2D engine with the default 32 clock delay. +		 */ +		M2REG_FLUSH_ENGINE_COMMAND | M2REG_FLUSH_2D_ENGINE_MASK, +		M2REG_FLUSH_ENGINE_COMMAND | M2REG_FLUSH_2D_ENGINE_MASK, +		M2REG_FLUSH_ENGINE_COMMAND | M2REG_FLUSH_2D_ENGINE_MASK, +		M2REG_FLUSH_ENGINE_COMMAND | M2REG_FLUSH_2D_ENGINE_MASK, +	}; +	const unsigned int flush_size = sizeof(flush_command); +	u32 *batch_addr; +	u32 hw_addr; + +	/* check buf is large enough to contain a new flush batch */ +	if ((info->cmdring.ring_offset + flush_size) >= info->cmdring.size) { +		info->cmdring.ring_offset = 0; +	} + +	hw_addr = info->cmdring.ring_hw_base  +		+ info->cmdring.ring_offset; +	batch_addr = info->cmdring.ptr  +		+ (info->cmdring.ring_offset / 4); + +	(void) memcpy(batch_addr, flush_command, flush_size); + +	if (stop) { +		*batch_addr |= BEGIN_STOP_STORE_CURRENT_POINTER_MASK; +	} + +	info->cmdring.last_ptr[1] = BEGIN_LINK_ENABLE_MASK | (flush_size / 4); +	info->cmdring.last_ptr[2] = hw_addr >> 4; +	info->cmdring.last_ptr[3] = 0; +	DRM_WRITEMEMORYBARRIER(); +	info->cmdring.last_ptr[0] = (get_batch_command(BTYPE_CTRL) << 24)  +		| (BEGIN_VALID_MASK); + +	triggerHWCommandList(info); + +	info->cmdring.ring_offset += flush_size; +	info->cmdring.last_ptr = batch_addr; +} + + +/** + * Emit an empty command to the CRTL command stream. + * @info XGI info structure + * + * This function assumes info->cmdring.ptr is non-NULL.  In addition, since + * this function emits a command that does not have linkage information, + * it sets info->cmdring.ptr to NULL. + */ +void xgi_emit_nop(struct xgi_info * info) +{ +	info->cmdring.last_ptr[1] = BEGIN_LINK_ENABLE_MASK  +		| (BEGIN_BEGIN_IDENTIFICATION_MASK & info->next_sequence); +	info->cmdring.last_ptr[2] = 0; +	info->cmdring.last_ptr[3] = 0; +	DRM_WRITEMEMORYBARRIER(); +	info->cmdring.last_ptr[0] = (get_batch_command(BTYPE_CTRL) << 24)  +		| (BEGIN_VALID_MASK); + +	triggerHWCommandList(info); + +	info->cmdring.last_ptr = NULL; +} + + +void xgi_emit_irq(struct xgi_info * info) +{ +	if (info->cmdring.last_ptr == NULL) +		return; + +	xgi_emit_flush(info, TRUE); +} diff --git a/linux-core/xgi_cmdlist.h b/linux-core/xgi_cmdlist.h new file mode 100644 index 00000000..f6f1c1ef --- /dev/null +++ b/linux-core/xgi_cmdlist.h @@ -0,0 +1,66 @@ +/**************************************************************************** + * Copyright (C) 2003-2006 by XGI Technology, Taiwan. + * + * 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 on 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 NON-INFRINGEMENT.  IN NO EVENT SHALL + * XGI 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 _XGI_CMDLIST_H_ +#define _XGI_CMDLIST_H_ + +struct xgi_cmdring_info { +	/** +	 * Kernel space pointer to the base of the command ring. +	 */ +	u32 * ptr; + +	/** +	 * Size, in bytes, of the command ring. +	 */ +	unsigned int size; + +	/** +	 * Base address of the command ring from the hardware's PoV. +	 */ +	unsigned int ring_hw_base; + +	u32 * last_ptr; + +	/** +	 * Offset, in bytes, from the start of the ring to the next available +	 * location to store a command. +	 */ +	unsigned int ring_offset; +}; + +struct xgi_info; +extern int xgi_cmdlist_initialize(struct xgi_info * info, size_t size, +	struct drm_file * filp); + +extern int xgi_state_change(struct xgi_info * info, unsigned int to, +	unsigned int from); + +extern void xgi_cmdlist_cleanup(struct xgi_info * info); + +extern void xgi_emit_irq(struct xgi_info * info); + +#endif				/* _XGI_CMDLIST_H_ */ diff --git a/linux-core/xgi_drm.h b/linux-core/xgi_drm.h new file mode 120000 index 00000000..677586d7 --- /dev/null +++ b/linux-core/xgi_drm.h @@ -0,0 +1 @@ +../shared-core/xgi_drm.h
\ No newline at end of file diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c new file mode 100644 index 00000000..84547f62 --- /dev/null +++ b/linux-core/xgi_drv.c @@ -0,0 +1,428 @@ +/**************************************************************************** + * Copyright (C) 2003-2006 by XGI Technology, Taiwan. + * + * 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 on 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 NON-INFRINGEMENT.  IN NO EVENT SHALL + * XGI 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 "xgi_drv.h" +#include "xgi_regs.h" +#include "xgi_misc.h" +#include "xgi_cmdlist.h" + +#include "drm_pciids.h" + +static struct pci_device_id pciidlist[] = { +	xgi_PCI_IDS +}; + +static struct drm_fence_driver xgi_fence_driver = { +	.num_classes = 1, +	.wrap_diff = BEGIN_BEGIN_IDENTIFICATION_MASK, +	.flush_diff = BEGIN_BEGIN_IDENTIFICATION_MASK - 1, +	.sequence_mask = BEGIN_BEGIN_IDENTIFICATION_MASK, +	.lazy_capable = 1, +	.emit = xgi_fence_emit_sequence, +	.poke_flush = xgi_poke_flush, +	.has_irq = xgi_fence_has_irq +}; + +static int xgi_bootstrap(struct drm_device *, void *, struct drm_file *); + +static struct drm_ioctl_desc xgi_ioctls[] = { +	DRM_IOCTL_DEF(DRM_XGI_BOOTSTRAP, xgi_bootstrap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), +	DRM_IOCTL_DEF(DRM_XGI_ALLOC, xgi_alloc_ioctl, DRM_AUTH), +	DRM_IOCTL_DEF(DRM_XGI_FREE, xgi_free_ioctl, DRM_AUTH), +	DRM_IOCTL_DEF(DRM_XGI_SUBMIT_CMDLIST, xgi_submit_cmdlist, DRM_AUTH), +	DRM_IOCTL_DEF(DRM_XGI_STATE_CHANGE, xgi_state_change_ioctl, DRM_AUTH|DRM_MASTER), +}; + +static const int xgi_max_ioctl = DRM_ARRAY_SIZE(xgi_ioctls); + +static int probe(struct pci_dev *pdev, const struct pci_device_id *ent); +static int xgi_driver_load(struct drm_device *dev, unsigned long flags); +static int xgi_driver_unload(struct drm_device *dev); +static void xgi_driver_lastclose(struct drm_device * dev); +static void xgi_reclaim_buffers_locked(struct drm_device * dev, +	struct drm_file * filp); +static irqreturn_t xgi_kern_isr(DRM_IRQ_ARGS); + + +static struct drm_driver driver = { +	.driver_features = +		DRIVER_PCI_DMA | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | +		DRIVER_IRQ_SHARED | DRIVER_SG, +	.dev_priv_size = sizeof(struct xgi_info), +	.load = xgi_driver_load, +	.unload = xgi_driver_unload, +	.lastclose = xgi_driver_lastclose, +	.dma_quiescent = NULL, +	.irq_preinstall = NULL, +	.irq_postinstall = NULL, +	.irq_uninstall = NULL, +	.irq_handler = xgi_kern_isr, +	.reclaim_buffers = drm_core_reclaim_buffers, +	.reclaim_buffers_idlelocked = xgi_reclaim_buffers_locked, +	.get_map_ofs = drm_core_get_map_ofs, +	.get_reg_ofs = drm_core_get_reg_ofs, +	.ioctls = xgi_ioctls, +	.dma_ioctl = NULL, + +	.fops = { +		.owner = THIS_MODULE, +		.open = drm_open, +		.release = drm_release, +		.ioctl = drm_ioctl, +		.mmap = drm_mmap, +		.poll = drm_poll, +		.fasync = drm_fasync, +	}, + +	.pci_driver = { +		.name = DRIVER_NAME, +		.id_table = pciidlist, +		.probe = probe, +		.remove = __devexit_p(drm_cleanup_pci), +	}, + +	.fence_driver = &xgi_fence_driver, + +	.name = DRIVER_NAME, +	.desc = DRIVER_DESC, +	.date = DRIVER_DATE, +	.major = DRIVER_MAJOR, +	.minor = DRIVER_MINOR, +	.patchlevel = DRIVER_PATCHLEVEL, + +}; + +static int probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ +	return drm_get_dev(pdev, ent, &driver); +} + + +static int __init xgi_init(void) +{ +	driver.num_ioctls = xgi_max_ioctl; +	return drm_init(&driver, pciidlist); +} + +static void __exit xgi_exit(void) +{ +	drm_exit(&driver); +} + +module_init(xgi_init); +module_exit(xgi_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL and additional rights"); + + +void xgi_engine_init(struct xgi_info * info) +{ +	u8 temp; + + +	OUT3C5B(info->mmio_map, 0x11, 0x92); + +	/* -------> copy from OT2D +	 * PCI Retry Control Register. +	 * disable PCI read retry & enable write retry in mem. (10xx xxxx)b +	 */ +	temp = IN3X5B(info->mmio_map, 0x55); +	OUT3X5B(info->mmio_map, 0x55, (temp & 0xbf) | 0x80); + +	xgi_enable_ge(info); + +	/* Enable linear addressing of the card. */ +	temp = IN3X5B(info->mmio_map, 0x21); +	OUT3X5B(info->mmio_map, 0x21, temp | 0x20); + +	/* Enable 32-bit internal data path */ +	temp = IN3X5B(info->mmio_map, 0x2A); +	OUT3X5B(info->mmio_map, 0x2A, temp | 0x40); + +	/* Enable PCI burst write ,disable burst read and enable MMIO. */ +	/* +	 * 0x3D4.39 Enable PCI burst write, disable burst read and enable MMIO. +	 * 7 ---- Pixel Data Format 1:  big endian 0:  little endian +	 * 6 5 4 3---- Memory Data with Big Endian Format, BE[3:0]#  with Big Endian Format +	 * 2 ---- PCI Burst Write Enable +	 * 1 ---- PCI Burst Read Enable +	 * 0 ---- MMIO Control +	 */ +	temp = IN3X5B(info->mmio_map, 0x39); +	OUT3X5B(info->mmio_map, 0x39, (temp | 0x05) & 0xfd); + +	/* enable GEIO decode */ +	/* temp = IN3X5B(info->mmio_map, 0x29); +	 * OUT3X5B(info->mmio_map, 0x29, temp | 0x08); +	 */ + +	/* Enable graphic engine I/O PCI retry function*/ +	/* temp = IN3X5B(info->mmio_map, 0x62); +	 * OUT3X5B(info->mmio_map, 0x62, temp | 0x50); +	 */ + +	/* protect all register except which protected by 3c5.0e.7 */ +        /* OUT3C5B(info->mmio_map, 0x11, 0x87); */ +} + + +int xgi_bootstrap(struct drm_device * dev, void * data, +		  struct drm_file * filp) +{ +	struct xgi_info *info = dev->dev_private; +	struct xgi_bootstrap * bs = (struct xgi_bootstrap *) data; +	struct drm_map_list *maplist; +	int err; + + +	DRM_SPININIT(&info->fence_lock, "fence lock"); +	info->next_sequence = 0; +	info->complete_sequence = 0; + +	if (info->mmio_map == NULL) { +		err = drm_addmap(dev, info->mmio.base, info->mmio.size, +				 _DRM_REGISTERS, _DRM_KERNEL, +				 &info->mmio_map); +		if (err) { +			DRM_ERROR("Unable to map MMIO region: %d\n", err); +			return err; +		} + +		xgi_enable_mmio(info); +		xgi_engine_init(info); +	} + + +	info->fb.size = IN3CFB(info->mmio_map, 0x54) * 8 * 1024 * 1024; + +	DRM_INFO("fb   base: 0x%lx, size: 0x%x (probed)\n", +		 (unsigned long) info->fb.base, info->fb.size); + + +	if ((info->fb.base == 0) || (info->fb.size == 0)) { +		DRM_ERROR("framebuffer appears to be wrong: 0x%lx 0x%x\n", +			  (unsigned long) info->fb.base, info->fb.size); +		return -EINVAL; +	} + + +	/* Init the resource manager */ +	if (!info->fb_heap_initialized) { +		err = xgi_fb_heap_init(info); +		if (err) { +			DRM_ERROR("Unable to initialize FB heap.\n"); +			return err; +		} +	} + + +	info->pcie.size = bs->gart.size; + +	/* Init the resource manager */ +	if (!info->pcie_heap_initialized) { +		err = xgi_pcie_heap_init(info); +		if (err) { +			DRM_ERROR("Unable to initialize GART heap.\n"); +			return err; +		} + +		/* Alloc 1M bytes for cmdbuffer which is flush2D batch array */ +		err = xgi_cmdlist_initialize(info, 0x100000, filp); +		if (err) { +			DRM_ERROR("xgi_cmdlist_initialize() failed\n"); +			return err; +		} +	} + + +	if (info->pcie_map == NULL) { +		err = drm_addmap(info->dev, 0, info->pcie.size, +				 _DRM_SCATTER_GATHER, _DRM_LOCKED, +				 & info->pcie_map); +		if (err) { +			DRM_ERROR("Could not add map for GART backing " +				  "store.\n"); +			return err; +		} +	} + + +	maplist = drm_find_matching_map(dev, info->pcie_map); +	if (maplist == NULL) { +		DRM_ERROR("Could not find GART backing store map.\n"); +		return -EINVAL; +	} + +	bs->gart = *info->pcie_map; +	bs->gart.handle = (void *)(unsigned long) maplist->user_token; +	return 0; +} + + +void xgi_driver_lastclose(struct drm_device * dev) +{ +	struct xgi_info * info = dev->dev_private; + +	if (info != NULL) { +		if (info->mmio_map != NULL) { +			xgi_cmdlist_cleanup(info); +			xgi_disable_ge(info); +			xgi_disable_mmio(info); +		} + +		/* The core DRM lastclose routine will destroy all of our +		 * mappings for us.  NULL out the pointers here so that +		 * xgi_bootstrap can do the right thing. +		 */ +		info->pcie_map = NULL; +		info->mmio_map = NULL; +		info->fb_map = NULL; + +		if (info->pcie_heap_initialized) { +			drm_ati_pcigart_cleanup(dev, &info->gart_info); +		} + +		if (info->fb_heap_initialized +		    || info->pcie_heap_initialized) { +			drm_sman_cleanup(&info->sman); + +			info->fb_heap_initialized = FALSE; +			info->pcie_heap_initialized = FALSE; +		} +	} +} + + +void xgi_reclaim_buffers_locked(struct drm_device * dev, +				struct drm_file * filp) +{ +	struct xgi_info * info = dev->dev_private; + +	mutex_lock(&info->dev->struct_mutex); +	if (drm_sman_owner_clean(&info->sman, (unsigned long) filp)) { +		mutex_unlock(&info->dev->struct_mutex); +		return; +	} + +	if (dev->driver->dma_quiescent) { +		dev->driver->dma_quiescent(dev); +	} + +	drm_sman_owner_cleanup(&info->sman, (unsigned long) filp); +	mutex_unlock(&info->dev->struct_mutex); +	return; +} + + +/* + * driver receives an interrupt if someone waiting, then hand it off. + */ +irqreturn_t xgi_kern_isr(DRM_IRQ_ARGS) +{ +	struct drm_device *dev = (struct drm_device *) arg; +	struct xgi_info *info = dev->dev_private; +	const u32 irq_bits = DRM_READ32(info->mmio_map, +					(0x2800  +					 + M2REG_AUTO_LINK_STATUS_ADDRESS)) +		& (M2REG_ACTIVE_TIMER_INTERRUPT_MASK +		   | M2REG_ACTIVE_INTERRUPT_0_MASK +		   | M2REG_ACTIVE_INTERRUPT_2_MASK +		   | M2REG_ACTIVE_INTERRUPT_3_MASK); + + +	if (irq_bits != 0) { +		DRM_WRITE32(info->mmio_map,  +			    0x2800 + M2REG_AUTO_LINK_SETTING_ADDRESS, +			    M2REG_AUTO_LINK_SETTING_COMMAND | irq_bits); +		xgi_fence_handler(dev); +		return IRQ_HANDLED; +	} else { +		return IRQ_NONE; +	} +} + + +int xgi_driver_load(struct drm_device *dev, unsigned long flags) +{ +	struct xgi_info *info = drm_alloc(sizeof(*info), DRM_MEM_DRIVER); +	int err; + +	if (!info) +		return -ENOMEM; + +	(void) memset(info, 0, sizeof(*info)); +	dev->dev_private = info; +	info->dev = dev; + +	info->mmio.base = drm_get_resource_start(dev, 1); +	info->mmio.size = drm_get_resource_len(dev, 1); + +	DRM_INFO("mmio base: 0x%lx, size: 0x%x\n", +		 (unsigned long) info->mmio.base, info->mmio.size); + + +	if ((info->mmio.base == 0) || (info->mmio.size == 0)) { +		DRM_ERROR("mmio appears to be wrong: 0x%lx 0x%x\n", +			  (unsigned long) info->mmio.base, info->mmio.size); +		err = -EINVAL; +		goto fail; +	} + + +	info->fb.base = drm_get_resource_start(dev, 0); +	info->fb.size = drm_get_resource_len(dev, 0); + +	DRM_INFO("fb   base: 0x%lx, size: 0x%x\n", +		 (unsigned long) info->fb.base, info->fb.size); + + +	err = drm_sman_init(&info->sman, 2, 12, 8); +	if (err) { +		goto fail; +	} + + +	return 0; +	 +fail: +	drm_free(info, sizeof(*info), DRM_MEM_DRIVER); +	return err; +} + +int xgi_driver_unload(struct drm_device *dev) +{ +	struct xgi_info * info = dev->dev_private; + +	drm_sman_takedown(&info->sman); +	drm_free(info, sizeof(*info), DRM_MEM_DRIVER); +	dev->dev_private = NULL; + +	return 0; +} diff --git a/linux-core/xgi_drv.h b/linux-core/xgi_drv.h new file mode 100644 index 00000000..88ade64d --- /dev/null +++ b/linux-core/xgi_drv.h @@ -0,0 +1,114 @@ +/**************************************************************************** + * Copyright (C) 2003-2006 by XGI Technology, Taiwan. + * + * 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 on 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 NON-INFRINGEMENT.  IN NO EVENT SHALL + * XGI 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 _XGI_DRV_H_ +#define _XGI_DRV_H_ + +#include "drmP.h" +#include "drm.h" +#include "drm_sman.h" + +#define DRIVER_AUTHOR		"Andrea Zhang <andrea_zhang@macrosynergy.com>" + +#define DRIVER_NAME		"xgi" +#define DRIVER_DESC		"XGI XP5 / XP10 / XG47" +#define DRIVER_DATE		"20070906" + +#define DRIVER_MAJOR		1 +#define DRIVER_MINOR		0 +#define DRIVER_PATCHLEVEL	0 + +#include "xgi_cmdlist.h" +#include "xgi_drm.h" + +struct xgi_aperture { +	dma_addr_t base; +	unsigned int size; +}; + +struct xgi_info { +	struct drm_device *dev; + +	bool bootstrap_done; + +	/* physical characteristics */ +	struct xgi_aperture mmio; +	struct xgi_aperture fb; +	struct xgi_aperture pcie; + +	struct drm_map *mmio_map; +	struct drm_map *pcie_map; +	struct drm_map *fb_map; + +	/* look up table parameters */ +	struct ati_pcigart_info gart_info; +	unsigned int lutPageSize; + +	struct drm_sman sman; +	bool fb_heap_initialized; +	bool pcie_heap_initialized; + +	struct xgi_cmdring_info cmdring; + +	DRM_SPINTYPE fence_lock; +	unsigned complete_sequence; +	unsigned next_sequence; +}; + +extern int xgi_fb_heap_init(struct xgi_info * info); + +extern int xgi_alloc(struct xgi_info * info, struct xgi_mem_alloc * alloc, +	struct drm_file * filp); + +extern int xgi_free(struct xgi_info * info, unsigned long index, +	struct drm_file * filp); + +extern int xgi_pcie_heap_init(struct xgi_info * info); + +extern void *xgi_find_pcie_virt(struct xgi_info * info, u32 address); + +extern void xgi_enable_mmio(struct xgi_info * info); +extern void xgi_disable_mmio(struct xgi_info * info); +extern void xgi_enable_ge(struct xgi_info * info); +extern void xgi_disable_ge(struct xgi_info * info); + +extern void xgi_poke_flush(struct drm_device * dev, uint32_t class); +extern int xgi_fence_emit_sequence(struct drm_device * dev, uint32_t class, +	uint32_t flags, uint32_t * sequence, uint32_t * native_type); +extern void xgi_fence_handler(struct drm_device * dev); +extern int xgi_fence_has_irq(struct drm_device *dev, uint32_t class, +	uint32_t flags); + +extern int xgi_alloc_ioctl(struct drm_device * dev, void * data, +	struct drm_file * filp); +extern int xgi_free_ioctl(struct drm_device * dev, void * data, +	struct drm_file * filp); +extern int xgi_submit_cmdlist(struct drm_device * dev, void * data, +	struct drm_file * filp); +extern int xgi_state_change_ioctl(struct drm_device * dev, void * data, +	struct drm_file * filp); + +#endif diff --git a/linux-core/xgi_fb.c b/linux-core/xgi_fb.c new file mode 100644 index 00000000..40f39fbc --- /dev/null +++ b/linux-core/xgi_fb.c @@ -0,0 +1,123 @@ +/**************************************************************************** + * Copyright (C) 2003-2006 by XGI Technology, Taiwan. + * + * 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 on 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 NON-INFRINGEMENT.  IN NO EVENT SHALL + * XGI 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 "xgi_drv.h" + +#define XGI_FB_HEAP_START 0x1000000 + +int xgi_alloc(struct xgi_info * info, struct xgi_mem_alloc * alloc, +	      struct drm_file * filp) +{ +	struct drm_memblock_item *block; +	const char *const mem_name = (alloc->location == XGI_MEMLOC_LOCAL)  +		? "on-card" : "GART"; + + +	if ((alloc->location != XGI_MEMLOC_LOCAL) +	    && (alloc->location != XGI_MEMLOC_NON_LOCAL)) { +		DRM_ERROR("Invalid memory pool (0x%08x) specified.\n", +			  alloc->location); +		return -EINVAL; +	} + +	if ((alloc->location == XGI_MEMLOC_LOCAL)  +	    ? !info->fb_heap_initialized : !info->pcie_heap_initialized) { +		DRM_ERROR("Attempt to allocate from uninitialized memory " +			  "pool (0x%08x).\n", alloc->location); +		return -EINVAL; +	} + +	mutex_lock(&info->dev->struct_mutex); +	block = drm_sman_alloc(&info->sman, alloc->location, alloc->size, +			       0, (unsigned long) filp); +	mutex_unlock(&info->dev->struct_mutex); + +	if (block == NULL) { +		alloc->size = 0; +		DRM_ERROR("%s memory allocation failed\n", mem_name); +		return -ENOMEM; +	} else { +		alloc->offset = (*block->mm->offset)(block->mm, +						     block->mm_info); +		alloc->hw_addr = alloc->offset; +		alloc->index = block->user_hash.key; + +		if (alloc->location == XGI_MEMLOC_NON_LOCAL) { +			alloc->hw_addr += info->pcie.base; +		} + +		DRM_DEBUG("%s memory allocation succeeded: 0x%x\n", +			  mem_name, alloc->offset); +	} + +	return 0; +} + + +int xgi_alloc_ioctl(struct drm_device * dev, void * data, +		    struct drm_file * filp) +{ +	struct xgi_info *info = dev->dev_private; + +	return xgi_alloc(info, (struct xgi_mem_alloc *) data, filp); +} + + +int xgi_free(struct xgi_info * info, unsigned long index, +	     struct drm_file * filp) +{ +	int err; + +	mutex_lock(&info->dev->struct_mutex); +	err = drm_sman_free_key(&info->sman, index); +	mutex_unlock(&info->dev->struct_mutex); + +	return err; +} + + +int xgi_free_ioctl(struct drm_device * dev, void * data, +		   struct drm_file * filp) +{ +	struct xgi_info *info = dev->dev_private; + +	return xgi_free(info, *(unsigned long *) data, filp); +} + + +int xgi_fb_heap_init(struct xgi_info * info) +{ +	int err; +	 +	mutex_lock(&info->dev->struct_mutex); +	err = drm_sman_set_range(&info->sman, XGI_MEMLOC_LOCAL, +				 XGI_FB_HEAP_START, +				 info->fb.size - XGI_FB_HEAP_START); +	mutex_unlock(&info->dev->struct_mutex); + +	info->fb_heap_initialized = (err == 0); +	return err; +} diff --git a/linux-core/xgi_fence.c b/linux-core/xgi_fence.c new file mode 100644 index 00000000..adedf300 --- /dev/null +++ b/linux-core/xgi_fence.c @@ -0,0 +1,127 @@ +/* + * (C) Copyright IBM Corporation 2007 + * 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 + * on 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 + * THE AUTHORS AND/OR THEIR 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. + * + * Authors: + *    Ian Romanick <idr@us.ibm.com> + */ + +#include "xgi_drv.h" +#include "xgi_regs.h" +#include "xgi_misc.h" +#include "xgi_cmdlist.h" + +static uint32_t xgi_do_flush(struct drm_device * dev, uint32_t class) +{ +	struct xgi_info * info = dev->dev_private; +	struct drm_fence_class_manager * fc = &dev->fm.class[class]; +	uint32_t pending_flush_types = 0; +	uint32_t signaled_flush_types = 0; + + +	if ((info == NULL) || (class != 0)) +		return 0; + +	DRM_SPINLOCK(&info->fence_lock); + +	pending_flush_types = fc->pending_flush | +		((fc->pending_exe_flush) ? DRM_FENCE_TYPE_EXE : 0); + +	if (pending_flush_types) { +		if (pending_flush_types & DRM_FENCE_TYPE_EXE) { +			const u32 begin_id = DRM_READ32(info->mmio_map, +							0x2820) +				& BEGIN_BEGIN_IDENTIFICATION_MASK; + +			if (begin_id != info->complete_sequence) { +				info->complete_sequence = begin_id; +				signaled_flush_types |= DRM_FENCE_TYPE_EXE; +			} +		} + +		if (signaled_flush_types) { +			drm_fence_handler(dev, 0, info->complete_sequence, +					  signaled_flush_types); +		} +	} + +	DRM_SPINUNLOCK(&info->fence_lock); + +	return fc->pending_flush | +		((fc->pending_exe_flush) ? DRM_FENCE_TYPE_EXE : 0); +} + + +int xgi_fence_emit_sequence(struct drm_device * dev, uint32_t class, +			    uint32_t flags, uint32_t * sequence,  +			    uint32_t * native_type) +{ +	struct xgi_info * info = dev->dev_private; + +	if ((info == NULL) || (class != 0)) +		return -EINVAL; + + +	DRM_SPINLOCK(&info->fence_lock); +	info->next_sequence++; +	if (info->next_sequence > BEGIN_BEGIN_IDENTIFICATION_MASK) { +		info->next_sequence = 1; +	} +	DRM_SPINUNLOCK(&info->fence_lock); + + +	xgi_emit_irq(info); + +	*sequence = (uint32_t) info->next_sequence; +	*native_type = DRM_FENCE_TYPE_EXE; + +	return 0; +} + + +void xgi_poke_flush(struct drm_device * dev, uint32_t class) +{ +	struct drm_fence_manager * fm = &dev->fm; +	unsigned long flags; + + +	write_lock_irqsave(&fm->lock, flags); +	xgi_do_flush(dev, class); +	write_unlock_irqrestore(&fm->lock, flags); +} + + +void xgi_fence_handler(struct drm_device * dev) +{ +	struct drm_fence_manager * fm = &dev->fm; + + +	write_lock(&fm->lock); +	xgi_do_flush(dev, 0); +	write_unlock(&fm->lock); +} + + +int xgi_fence_has_irq(struct drm_device *dev, uint32_t class, uint32_t flags) +{ +	return ((class == 0) && (flags == DRM_FENCE_TYPE_EXE)) ? 1 : 0; +} diff --git a/linux-core/xgi_misc.c b/linux-core/xgi_misc.c new file mode 100644 index 00000000..50a721c0 --- /dev/null +++ b/linux-core/xgi_misc.c @@ -0,0 +1,477 @@ +/**************************************************************************** + * Copyright (C) 2003-2006 by XGI Technology, Taiwan. + * + * 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 on 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 NON-INFRINGEMENT.  IN NO EVENT SHALL + * XGI 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 "xgi_drv.h" +#include "xgi_regs.h" + +#include <linux/delay.h> + +/* + * irq functions + */ +#define STALL_INTERRUPT_RESET_THRESHOLD 0xffff + +static unsigned int s_invalid_begin = 0; + +static bool xgi_validate_signal(struct drm_map * map) +{ +	if (DRM_READ32(map, 0x2800) & 0x001c0000) { +		u16 check; + +		/* Check Read back status */ +		DRM_WRITE8(map, 0x235c, 0x80); +		check = DRM_READ16(map, 0x2360); + +		if ((check & 0x3f) != ((check & 0x3f00) >> 8)) { +			return FALSE; +		} + +		/* Check RO channel */ +		DRM_WRITE8(map, 0x235c, 0x83); +		check = DRM_READ16(map, 0x2360); +		if ((check & 0x0f) != ((check & 0xf0) >> 4)) { +			return FALSE; +		} + +		/* Check RW channel */ +		DRM_WRITE8(map, 0x235c, 0x88); +		check = DRM_READ16(map, 0x2360); +		if ((check & 0x0f) != ((check & 0xf0) >> 4)) { +			return FALSE; +		} + +		/* Check RO channel outstanding */ +		DRM_WRITE8(map, 0x235c, 0x8f); +		check = DRM_READ16(map, 0x2360); +		if (0 != (check & 0x3ff)) { +			return FALSE; +		} + +		/* Check RW channel outstanding */ +		DRM_WRITE8(map, 0x235c, 0x90); +		check = DRM_READ16(map, 0x2360); +		if (0 != (check & 0x3ff)) { +			return FALSE; +		} + +		/* No pending PCIE request. GE stall. */ +	} + +	return TRUE; +} + + +static void xgi_ge_hang_reset(struct drm_map * map) +{ +	int time_out = 0xffff; + +	DRM_WRITE8(map, 0xb057, 8); +	while (0 != (DRM_READ32(map, 0x2800) & 0xf0000000)) { +		while (0 != ((--time_out) & 0xfff))  +			/* empty */ ; + +		if (0 == time_out) { +			u8 old_3ce; +			u8 old_3cf; +			u8 old_index; +			u8 old_36; + +			DRM_INFO("Can not reset back 0x%x!\n", +				 DRM_READ32(map, 0x2800)); + +			DRM_WRITE8(map, 0xb057, 0); + +			/* Have to use 3x5.36 to reset. */ +			/* Save and close dynamic gating */ + +			old_3ce = DRM_READ8(map, 0x3ce); +			DRM_WRITE8(map, 0x3ce, 0x2a); +			old_3cf = DRM_READ8(map, 0x3cf); +			DRM_WRITE8(map, 0x3cf, old_3cf & 0xfe); + +			/* Reset GE */ +			old_index = DRM_READ8(map, 0x3d4); +			DRM_WRITE8(map, 0x3d4, 0x36); +			old_36 = DRM_READ8(map, 0x3d5); +			DRM_WRITE8(map, 0x3d5, old_36 | 0x10); +			 +			while (0 != ((--time_out) & 0xfff))  +				/* empty */ ; + +			DRM_WRITE8(map, 0x3d5, old_36); +			DRM_WRITE8(map, 0x3d4, old_index); + +			/* Restore dynamic gating */ +			DRM_WRITE8(map, 0x3cf, old_3cf); +			DRM_WRITE8(map, 0x3ce, old_3ce); +			break; +		} +	} + +	DRM_WRITE8(map, 0xb057, 0); +} + +	 +bool xgi_ge_irq_handler(struct xgi_info * info) +{ +	const u32 int_status = DRM_READ32(info->mmio_map, 0x2810); +	bool is_support_auto_reset = FALSE; + +	/* Check GE on/off */ +	if (0 == (0xffffc0f0 & int_status)) { +		if (0 != (0x1000 & int_status)) { +			/* We got GE stall interrupt.  +			 */ +			DRM_WRITE32(info->mmio_map, 0x2810, +				    int_status | 0x04000000); + +			if (is_support_auto_reset) { +				static cycles_t last_tick; +				static unsigned continue_int_count = 0; + +				/* OE II is busy. */ + +				if (!xgi_validate_signal(info->mmio_map)) { +					/* Nothing but skip. */ +				} else if (0 == continue_int_count++) { +					last_tick = get_cycles(); +				} else { +					const cycles_t new_tick = get_cycles(); +					if ((new_tick - last_tick) > +					    STALL_INTERRUPT_RESET_THRESHOLD) { +						continue_int_count = 0; +					} else if (continue_int_count >= 3) { +						continue_int_count = 0; + +						/* GE Hung up, need reset. */ +						DRM_INFO("Reset GE!\n"); + +						xgi_ge_hang_reset(info->mmio_map); +					} +				} +			} +		} else if (0 != (0x1 & int_status)) { +			s_invalid_begin++; +			DRM_WRITE32(info->mmio_map, 0x2810, +				    (int_status & ~0x01) | 0x04000000); +		} + +		return TRUE; +	} + +	return FALSE; +} + +bool xgi_crt_irq_handler(struct xgi_info * info) +{ +	bool ret = FALSE; +	u8 save_3ce = DRM_READ8(info->mmio_map, 0x3ce); + +	/* CRT1 interrupt just happened +	 */ +	if (IN3CFB(info->mmio_map, 0x37) & 0x01) { +		u8 op3cf_3d; +		u8 op3cf_37; + +		/* What happened? +		 */ +		op3cf_37 = IN3CFB(info->mmio_map, 0x37); + +		/* Clear CRT interrupt +		 */ +		op3cf_3d = IN3CFB(info->mmio_map, 0x3d); +		OUT3CFB(info->mmio_map, 0x3d, (op3cf_3d | 0x04)); +		OUT3CFB(info->mmio_map, 0x3d, (op3cf_3d & ~0x04)); +		ret = TRUE; +	} +	DRM_WRITE8(info->mmio_map, 0x3ce, save_3ce); + +	return (ret); +} + +bool xgi_dvi_irq_handler(struct xgi_info * info) +{ +	bool ret = FALSE; +	const u8 save_3ce = DRM_READ8(info->mmio_map, 0x3ce); + +	/* DVI interrupt just happened +	 */ +	if (IN3CFB(info->mmio_map, 0x38) & 0x20) { +		const u8 save_3x4 = DRM_READ8(info->mmio_map, 0x3d4); +		u8 op3cf_39; +		u8 op3cf_37; +		u8 op3x5_5a; + +		/* What happened? +		 */ +		op3cf_37 = IN3CFB(info->mmio_map, 0x37); + +		/* Notify BIOS that DVI plug/unplug happened +		 */ +		op3x5_5a = IN3X5B(info->mmio_map, 0x5a); +		OUT3X5B(info->mmio_map, 0x5a, op3x5_5a & 0xf7); + +		DRM_WRITE8(info->mmio_map, 0x3d4, save_3x4); + +		/* Clear DVI interrupt +		 */ +		op3cf_39 = IN3CFB(info->mmio_map, 0x39); +		OUT3C5B(info->mmio_map, 0x39, (op3cf_39 & ~0x01)); +		OUT3C5B(info->mmio_map, 0x39, (op3cf_39 | 0x01)); + +		ret = TRUE; +	} +	DRM_WRITE8(info->mmio_map, 0x3ce, save_3ce); + +	return (ret); +} + + +static void dump_reg_header(unsigned regbase) +{ +	printk("\n=====xgi_dump_register========0x%x===============\n", +	       regbase); +	printk("    0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n"); +} + + +static void dump_indexed_reg(struct xgi_info * info, unsigned regbase) +{ +	unsigned i, j; +	u8 temp; + + +	dump_reg_header(regbase); +	for (i = 0; i < 0x10; i++) { +		printk("%1x ", i); + +		for (j = 0; j < 0x10; j++) { +			DRM_WRITE8(info->mmio_map, regbase - 1, +				   (i * 0x10) + j); +			temp = DRM_READ8(info->mmio_map, regbase); +			printk("%3x", temp); +		} +		printk("\n"); +	} +} + + +static void dump_reg(struct xgi_info * info, unsigned regbase, unsigned range) +{ +	unsigned i, j; + + +	dump_reg_header(regbase); +	for (i = 0; i < range; i++) { +		printk("%1x ", i); + +		for (j = 0; j < 0x10; j++) { +			u8 temp = DRM_READ8(info->mmio_map,  +					    regbase + (i * 0x10) + j); +			printk("%3x", temp); +		} +		printk("\n"); +	} +} + + +void xgi_dump_register(struct xgi_info * info) +{ +	dump_indexed_reg(info, 0x3c5); +	dump_indexed_reg(info, 0x3d5); +	dump_indexed_reg(info, 0x3cf); + +	dump_reg(info, 0xB000, 0x05); +	dump_reg(info, 0x2200, 0x0B); +	dump_reg(info, 0x2300, 0x07); +	dump_reg(info, 0x2400, 0x10); +	dump_reg(info, 0x2800, 0x10); +} + + +#define WHOLD_GE_STATUS             0x2800 + +/* Test everything except the "whole GE busy" bit, the "master engine busy" + * bit, and the reserved bits [26:21]. + */ +#define IDLE_MASK                   ~((1U<<31) | (1U<<28) | (0x3f<<21)) + +void xgi_waitfor_pci_idle(struct xgi_info * info) +{ +	unsigned int idleCount = 0; +	u32 old_status = 0; +	unsigned int same_count = 0; + +	while (idleCount < 5) { +		const u32 status = DRM_READ32(info->mmio_map, WHOLD_GE_STATUS)  +			& IDLE_MASK; + +		if (status == old_status) { +			same_count++; + +			if ((same_count % 100) == 0) { +				DRM_ERROR("GE status stuck at 0x%08x for %u iterations!\n", +					  old_status, same_count); +			} +		} else { +			old_status = status; +			same_count = 0; +		} + +		if (status != 0) { +			msleep(1); +			idleCount = 0; +		} else { +			idleCount++; +		} +	} +} + + +void xgi_enable_mmio(struct xgi_info * info) +{ +	u8 protect = 0; +	u8 temp; + +	/* Unprotect registers */ +	DRM_WRITE8(info->mmio_map, 0x3C4, 0x11); +	protect = DRM_READ8(info->mmio_map, 0x3C5); +	DRM_WRITE8(info->mmio_map, 0x3C5, 0x92); + +	DRM_WRITE8(info->mmio_map, 0x3D4, 0x3A); +	temp = DRM_READ8(info->mmio_map, 0x3D5); +	DRM_WRITE8(info->mmio_map, 0x3D5, temp | 0x20); + +	/* Enable MMIO */ +	DRM_WRITE8(info->mmio_map, 0x3D4, 0x39); +	temp = DRM_READ8(info->mmio_map, 0x3D5); +	DRM_WRITE8(info->mmio_map, 0x3D5, temp | 0x01); + +	/* Protect registers */ +	OUT3C5B(info->mmio_map, 0x11, protect); +} + + +void xgi_disable_mmio(struct xgi_info * info) +{ +	u8 protect = 0; +	u8 temp; + +	/* Unprotect registers */ +	DRM_WRITE8(info->mmio_map, 0x3C4, 0x11); +	protect = DRM_READ8(info->mmio_map, 0x3C5); +	DRM_WRITE8(info->mmio_map, 0x3C5, 0x92); + +	/* Disable MMIO access */ +	DRM_WRITE8(info->mmio_map, 0x3D4, 0x39); +	temp = DRM_READ8(info->mmio_map, 0x3D5); +	DRM_WRITE8(info->mmio_map, 0x3D5, temp & 0xFE); + +	/* Protect registers */ +	OUT3C5B(info->mmio_map, 0x11, protect); +} + + +void xgi_enable_ge(struct xgi_info * info) +{ +	u8 bOld3cf2a; +	int wait = 0; + +	OUT3C5B(info->mmio_map, 0x11, 0x92); + +	/* Save and close dynamic gating +	 */ +	bOld3cf2a = IN3CFB(info->mmio_map, XGI_MISC_CTRL); +	OUT3CFB(info->mmio_map, XGI_MISC_CTRL, bOld3cf2a & ~EN_GEPWM); + +	/* Enable 2D and 3D GE +	 */ +	OUT3X5B(info->mmio_map, XGI_GE_CNTL, (GE_ENABLE | GE_ENABLE_3D)); +	wait = 10; +	while (wait--) { +		DRM_READ8(info->mmio_map, 0x36); +	} + +	/* Reset both 3D and 2D engine +	 */ +	OUT3X5B(info->mmio_map, XGI_GE_CNTL, +		(GE_ENABLE | GE_RESET | GE_ENABLE_3D)); +	wait = 10; +	while (wait--) { +		DRM_READ8(info->mmio_map, 0x36); +	} + +	OUT3X5B(info->mmio_map, XGI_GE_CNTL, (GE_ENABLE | GE_ENABLE_3D)); +	wait = 10; +	while (wait--) { +		DRM_READ8(info->mmio_map, 0x36); +	} + +	/* Enable 2D engine only +	 */ +	OUT3X5B(info->mmio_map, XGI_GE_CNTL, GE_ENABLE); + +	/* Enable 2D+3D engine +	 */ +	OUT3X5B(info->mmio_map, XGI_GE_CNTL, (GE_ENABLE | GE_ENABLE_3D)); + +	/* Restore dynamic gating +	 */ +	OUT3CFB(info->mmio_map, XGI_MISC_CTRL, bOld3cf2a); +} + + +void xgi_disable_ge(struct xgi_info * info) +{ +	int wait = 0; + +	OUT3X5B(info->mmio_map, XGI_GE_CNTL, (GE_ENABLE | GE_ENABLE_3D)); + +	wait = 10; +	while (wait--) { +		DRM_READ8(info->mmio_map, 0x36); +	} + +	/* Reset both 3D and 2D engine +	 */ +	OUT3X5B(info->mmio_map, XGI_GE_CNTL, +		(GE_ENABLE | GE_RESET | GE_ENABLE_3D)); + +	wait = 10; +	while (wait--) { +		DRM_READ8(info->mmio_map, 0x36); +	} +	OUT3X5B(info->mmio_map, XGI_GE_CNTL, (GE_ENABLE | GE_ENABLE_3D)); + +	wait = 10; +	while (wait--) { +		DRM_READ8(info->mmio_map, 0x36); +	} + +	/* Disable 2D engine and 3D engine. +	 */ +	OUT3X5B(info->mmio_map, XGI_GE_CNTL, 0); +} diff --git a/linux-core/xgi_misc.h b/linux-core/xgi_misc.h new file mode 100644 index 00000000..af19a11a --- /dev/null +++ b/linux-core/xgi_misc.h @@ -0,0 +1,37 @@ +/**************************************************************************** + * Copyright (C) 2003-2006 by XGI Technology, Taiwan.			 + * + * 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 on 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 NON-INFRINGEMENT.  IN NO EVENT SHALL + * XGI 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 _XGI_MISC_H_ +#define _XGI_MISC_H_ + +extern void xgi_dump_register(struct xgi_info * info); + +extern bool xgi_ge_irq_handler(struct xgi_info * info); +extern bool xgi_crt_irq_handler(struct xgi_info * info); +extern bool xgi_dvi_irq_handler(struct xgi_info * info); +extern void xgi_waitfor_pci_idle(struct xgi_info * info); + +#endif diff --git a/linux-core/xgi_pcie.c b/linux-core/xgi_pcie.c new file mode 100644 index 00000000..a7d3ea24 --- /dev/null +++ b/linux-core/xgi_pcie.c @@ -0,0 +1,126 @@ +/**************************************************************************** + * Copyright (C) 2003-2006 by XGI Technology, Taiwan. + * + * 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 on 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 NON-INFRINGEMENT.  IN NO EVENT SHALL + * XGI 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 "xgi_drv.h" +#include "xgi_regs.h" +#include "xgi_misc.h" + +void xgi_gart_flush(struct drm_device *dev) +{ +	struct xgi_info *const info = dev->dev_private; +	u8 temp; + +	DRM_MEMORYBARRIER(); + +	/* Set GART in SFB */ +	temp = DRM_READ8(info->mmio_map, 0xB00C); +	DRM_WRITE8(info->mmio_map, 0xB00C, temp & ~0x02); + +	/* Set GART base address to HW */ +	DRM_WRITE32(info->mmio_map, 0xB034, info->gart_info.bus_addr); + +	/* Flush GART table. */ +	DRM_WRITE8(info->mmio_map, 0xB03F, 0x40); +	DRM_WRITE8(info->mmio_map, 0xB03F, 0x00); +} + + +int xgi_pcie_heap_init(struct xgi_info * info) +{ +	u8 temp = 0; +	int err; +	struct drm_scatter_gather request; + +	/* Get current FB aperture size */ +	temp = IN3X5B(info->mmio_map, 0x27); +	DRM_INFO("In3x5(0x27): 0x%x \n", temp); + +	if (temp & 0x01) {	/* 256MB; Jong 06/05/2006; 0x10000000 */ +		info->pcie.base = 256 * 1024 * 1024; +	} else {		/* 128MB; Jong 06/05/2006; 0x08000000 */ +		info->pcie.base = 128 * 1024 * 1024; +	} + + +	DRM_INFO("info->pcie.base: 0x%lx\n", (unsigned long) info->pcie.base); + +	/* Get current lookup table page size */ +	temp = DRM_READ8(info->mmio_map, 0xB00C); +	if (temp & 0x04) {	/* 8KB */ +		info->lutPageSize = 8 * 1024; +	} else {		/* 4KB */ +		info->lutPageSize = 4 * 1024; +	} + +	DRM_INFO("info->lutPageSize: 0x%x \n", info->lutPageSize); + + +	request.size = info->pcie.size; +	err = drm_sg_alloc(info->dev, & request); +	if (err) { +		DRM_ERROR("cannot allocate PCIE GART backing store!  " +			  "size = %d\n", info->pcie.size); +		return err; +	} + +	info->gart_info.gart_table_location = DRM_ATI_GART_MAIN; +	info->gart_info.gart_reg_if = DRM_ATI_GART_PCI; +	info->gart_info.table_size = info->dev->sg->pages * sizeof(u32); + +	if (!drm_ati_pcigart_init(info->dev, &info->gart_info)) { +		DRM_ERROR("failed to init PCI GART!\n"); +		return -ENOMEM; +	} + + +	xgi_gart_flush(info->dev); + +	mutex_lock(&info->dev->struct_mutex); +	err = drm_sman_set_range(&info->sman, XGI_MEMLOC_NON_LOCAL, +				 0, info->pcie.size); +	mutex_unlock(&info->dev->struct_mutex); +	if (err) { +		drm_ati_pcigart_cleanup(info->dev, &info->gart_info); +	} + +	info->pcie_heap_initialized = (err == 0); +	return err; +} + + +/** + * xgi_find_pcie_virt + * @address: GE HW address + * + * Returns CPU virtual address.  Assumes the CPU VAddr is continuous in not + * the same block + */ +void *xgi_find_pcie_virt(struct xgi_info * info, u32 address) +{ +	const unsigned long offset = address - info->pcie.base; + +	return ((u8 *) info->dev->sg->virtual) + offset; +} diff --git a/linux-core/xgi_regs.h b/linux-core/xgi_regs.h new file mode 100644 index 00000000..5c0100a0 --- /dev/null +++ b/linux-core/xgi_regs.h @@ -0,0 +1,169 @@ +/**************************************************************************** + * Copyright (C) 2003-2006 by XGI Technology, Taiwan. + * + * 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 on 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 NON-INFRINGEMENT.  IN NO EVENT SHALL + * XGI 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 _XGI_REGS_H_ +#define _XGI_REGS_H_ + +#include "drmP.h" +#include "drm.h" + +#define MAKE_MASK(bits)  ((1U << (bits)) - 1) + +#define ONE_BIT_MASK        MAKE_MASK(1) +#define TWENTY_BIT_MASK     MAKE_MASK(20) +#define TWENTYONE_BIT_MASK  MAKE_MASK(21) +#define TWENTYTWO_BIT_MASK  MAKE_MASK(22) + + +/* Port 0x3d4/0x3d5, index 0x2a */ +#define XGI_INTERFACE_SEL 0x2a +#define DUAL_64BIT        (1U<<7) +#define INTERNAL_32BIT    (1U<<6) +#define EN_SEP_WR         (1U<<5) +#define POWER_DOWN_SEL    (1U<<4) +/*#define RESERVED_3      (1U<<3) */ +#define SUBS_MCLK_PCICLK  (1U<<2) +#define MEM_SIZE_MASK     (3<<0) +#define MEM_SIZE_32MB     (0<<0) +#define MEM_SIZE_64MB     (1<<0) +#define MEM_SIZE_128MB    (2<<0) +#define MEM_SIZE_256MB    (3<<0) + +/* Port 0x3d4/0x3d5, index 0x36 */ +#define XGI_GE_CNTL 0x36 +#define GE_ENABLE        (1U<<7) +/*#define RESERVED_6     (1U<<6) */ +/*#define RESERVED_5     (1U<<5) */ +#define GE_RESET         (1U<<4) +/*#define RESERVED_3     (1U<<3) */ +#define GE_ENABLE_3D     (1U<<2) +/*#define RESERVED_1     (1U<<1) */ +/*#define RESERVED_0     (1U<<0) */ + +/* Port 0x3ce/0x3cf, index 0x2a */ +#define XGI_MISC_CTRL 0x2a +#define MOTION_VID_SUSPEND   (1U<<7) +#define DVI_CRTC_TIMING_SEL  (1U<<6) +#define LCD_SEL_CTL_NEW      (1U<<5) +#define LCD_SEL_EXT_DELYCTRL (1U<<4) +#define REG_LCDDPARST        (1U<<3) +#define LCD2DPAOFF           (1U<<2) +/*#define RESERVED_1         (1U<<1) */ +#define EN_GEPWM             (1U<<0)  /* Enable GE power management */ + + +#define BASE_3D_ENG 0x2800 + +#define M2REG_FLUSH_ENGINE_ADDRESS 0x000 +#define M2REG_FLUSH_ENGINE_COMMAND 0x00 +#define M2REG_FLUSH_FLIP_ENGINE_MASK              (ONE_BIT_MASK<<21) +#define M2REG_FLUSH_2D_ENGINE_MASK                (ONE_BIT_MASK<<20) +#define M2REG_FLUSH_3D_ENGINE_MASK                TWENTY_BIT_MASK + +#define M2REG_RESET_ADDRESS 0x004 +#define M2REG_RESET_COMMAND 0x01 +#define M2REG_RESET_STATUS2_MASK                  (ONE_BIT_MASK<<10) +#define M2REG_RESET_STATUS1_MASK                  (ONE_BIT_MASK<<9) +#define M2REG_RESET_STATUS0_MASK                  (ONE_BIT_MASK<<8) +#define M2REG_RESET_3DENG_MASK                    (ONE_BIT_MASK<<4) +#define M2REG_RESET_2DENG_MASK                    (ONE_BIT_MASK<<2) + +/* Write register */ +#define M2REG_AUTO_LINK_SETTING_ADDRESS 0x010 +#define M2REG_AUTO_LINK_SETTING_COMMAND 0x04 +#define M2REG_CLEAR_TIMER_INTERRUPT_MASK          (ONE_BIT_MASK<<11) +#define M2REG_CLEAR_INTERRUPT_3_MASK              (ONE_BIT_MASK<<10) +#define M2REG_CLEAR_INTERRUPT_2_MASK              (ONE_BIT_MASK<<9) +#define M2REG_CLEAR_INTERRUPT_0_MASK              (ONE_BIT_MASK<<8) +#define M2REG_CLEAR_COUNTERS_MASK                 (ONE_BIT_MASK<<4) +#define M2REG_PCI_TRIGGER_MODE_MASK               (ONE_BIT_MASK<<1) +#define M2REG_INVALID_LIST_AUTO_INTERRUPT_MASK    (ONE_BIT_MASK<<0) + +/* Read register */ +#define M2REG_AUTO_LINK_STATUS_ADDRESS 0x010 +#define M2REG_AUTO_LINK_STATUS_COMMAND 0x04 +#define M2REG_ACTIVE_TIMER_INTERRUPT_MASK          (ONE_BIT_MASK<<11) +#define M2REG_ACTIVE_INTERRUPT_3_MASK              (ONE_BIT_MASK<<10) +#define M2REG_ACTIVE_INTERRUPT_2_MASK              (ONE_BIT_MASK<<9) +#define M2REG_ACTIVE_INTERRUPT_0_MASK              (ONE_BIT_MASK<<8) +#define M2REG_INVALID_LIST_AUTO_INTERRUPTED_MODE_MASK    (ONE_BIT_MASK<<0) + +#define     M2REG_PCI_TRIGGER_REGISTER_ADDRESS 0x014 +#define     M2REG_PCI_TRIGGER_REGISTER_COMMAND 0x05 + + +/** + * Begin instruction, double-word 0 + */ +#define BEGIN_STOP_STORE_CURRENT_POINTER_MASK   (ONE_BIT_MASK<<22) +#define BEGIN_VALID_MASK                        (ONE_BIT_MASK<<20) +#define BEGIN_BEGIN_IDENTIFICATION_MASK         TWENTY_BIT_MASK + +/** + * Begin instruction, double-word 1 + */ +#define BEGIN_LINK_ENABLE_MASK                  (ONE_BIT_MASK<<31) +#define BEGIN_COMMAND_LIST_LENGTH_MASK          TWENTYTWO_BIT_MASK + + +/* Hardware access functions */ +static inline void OUT3C5B(struct drm_map * map, u8 index, u8 data) +{ +	DRM_WRITE8(map, 0x3C4, index); +	DRM_WRITE8(map, 0x3C5, data); +} + +static inline void OUT3X5B(struct drm_map * map, u8 index, u8 data) +{ +	DRM_WRITE8(map, 0x3D4, index); +	DRM_WRITE8(map, 0x3D5, data); +} + +static inline void OUT3CFB(struct drm_map * map, u8 index, u8 data) +{ +	DRM_WRITE8(map, 0x3CE, index); +	DRM_WRITE8(map, 0x3CF, data); +} + +static inline u8 IN3C5B(struct drm_map * map, u8 index) +{ +	DRM_WRITE8(map, 0x3C4, index); +	return DRM_READ8(map, 0x3C5); +} + +static inline u8 IN3X5B(struct drm_map * map, u8 index) +{ +	DRM_WRITE8(map, 0x3D4, index); +	return DRM_READ8(map, 0x3D5); +} + +static inline u8 IN3CFB(struct drm_map * map, u8 index) +{ +	DRM_WRITE8(map, 0x3CE, index); +	return DRM_READ8(map, 0x3CF); +} + +#endif | 
