From: 杜坤明 Date: Fri, 5 Nov 2010 12:13:19 +0000 (+0800) Subject: update vivant gpu(gc830) driver X-Git-Tag: firefly_0821_release~11032^2~7 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=7abcfd1c429f7f11628cbe6004bafe6a030027ea;p=firefly-linux-kernel-4.4.55.git update vivant gpu(gc830) driver --- diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig old mode 100644 new mode 100755 index ec496cc2be3f..34ee095555ab --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -130,5 +130,7 @@ source "drivers/staging/rk2818/rk2818_dsp/Kconfig" source "drivers/staging/rk2818/rk1000_control/Kconfig" source "drivers/staging/rk2818/rk2818_power/Kconfig" + +source "drivers/staging/rk29/vivante/Kconfig" endif # !STAGING_EXCLUDE_BUILD endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile old mode 100644 new mode 100755 index f34adae43390..5b2a508c7fcc --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -48,3 +48,4 @@ obj-$(CONFIG_RK2818_DSP) += rk2818/rk2818_dsp/ obj-$(CONFIG_RK1000_CONTROL) += rk2818/rk1000_control/ obj-$(CONFIG_RK1000_TVOUT) += rk2818/rk1000_tv/ obj-$(CONFIG_RK2818_POWER) += rk2818/rk2818_power/ +obj-$(CONFIG_VIVANTE) += rk29/vivante/ diff --git a/drivers/staging/rk29/vivante/Kbuild_ b/drivers/staging/rk29/vivante/Kbuild_ new file mode 100644 index 000000000000..ec0cc6c88a46 --- /dev/null +++ b/drivers/staging/rk29/vivante/Kbuild_ @@ -0,0 +1,171 @@ +############################################################################## +# +# Copyright (C) 2005 - 2010 by Vivante Corp. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the license, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +############################################################################## + + +# +# Linux build file for kernel HAL driver. +# + +include $(AQROOT)/config + +DRIVER_OUT_DIR = hal/driver +KERNEL_DIR ?= $(TOOL_DIR)/kernel + +OS_KERNEL_DIR := hal/os/linux/kernel +ARCH_KERNEL_DIR := arch/$(notdir $(AQARCH))/hal/kernel +HAL_KERNEL_DIR := hal/kernel + +EXTRA_CFLAGS += -Werror + +OBJS := $(OS_KERNEL_DIR)/gc_hal_kernel_debug.o \ + $(OS_KERNEL_DIR)/gc_hal_kernel_device.o \ + $(OS_KERNEL_DIR)/gc_hal_kernel_driver.o \ + $(OS_KERNEL_DIR)/gc_hal_kernel_linux.o \ + $(OS_KERNEL_DIR)/gc_hal_kernel_os.o + +ifeq ($(USE_3D_VG), 1) + +OBJS += $(HAL_KERNEL_DIR)/gc_hal_kernel.o \ + $(HAL_KERNEL_DIR)/gc_hal_kernel_command.o \ + $(HAL_KERNEL_DIR)/gc_hal_kernel_event.o \ + $(HAL_KERNEL_DIR)/gc_hal_kernel_heap.o \ + $(HAL_KERNEL_DIR)/gc_hal_kernel_mmu.o \ + $(HAL_KERNEL_DIR)/gc_hal_kernel_video_memory.o + +OBJS += $(ARCH_KERNEL_DIR)/gc_hal_kernel_hardware.o + +else + +OBJS += $(HAL_KERNEL_DIR)/gc_hal_kernel.o \ + $(HAL_KERNEL_DIR)/gc_hal_kernel_command.o \ + $(HAL_KERNEL_DIR)/gc_hal_kernel_heap.o \ + $(HAL_KERNEL_DIR)/gc_hal_kernel_interrupt.o \ + $(HAL_KERNEL_DIR)/gc_hal_kernel_mmu.o \ + $(HAL_KERNEL_DIR)/gc_hal_kernel_video_memory.o + +OBJS += $(ARCH_KERNEL_DIR)/gc_hal_kernel_hardware.o \ + $(ARCH_KERNEL_DIR)/gc_hal_kernel_hardware_command.o + +endif + +ifeq ($(KERNELRELEASE), ) + +.PHONY: all clean install + +# Define targets. +all: + @mkdir -p $(DRIVER_OUT_DIR) + @make V=$(V) ARCH=$(ARCH_TYPE) -C $(KERNEL_DIR) SUBDIRS=`pwd` modules + +clean: + @rm -rf $(OBJS) + @rm -rf $(DRIVER_OUT_DIR) + @rm -rf modules.order Module.symvers + +install: all + @mkdir -p $(SDK_DIR)/drivers + @cp $(DRIVER_OUT_DIR)/galcore.ko $(SDK_DIR)/drivers + +else + + +EXTRA_CFLAGS += -DLINUX -DDRIVER + +ifeq ($(ENUM_WORKAROUND), 1) +EXTRA_CFLAGS += -DENUM_WORKAROUND=1 +else +EXTRA_CFLAGS += -DENUM_WORKAROUND=0 +endif + +ifeq ($(FLAREON),1) +EXTRA_CFLAGS += -DFLAREON +endif + +ifeq ($(DEBUG), 1) +EXTRA_CFLAGS += -DDBG=1 -DDEBUG -D_DEBUG +else +EXTRA_CFLAGS += -DDBG=0 +endif + +ifeq ($(NO_DMA_COHERENT), 1) +EXTRA_CFLAGS += -DNO_DMA_COHERENT +endif + +ifeq ($(ENABLE_ARM_L2_CACHE), 1) +EXTRA_CFLAGS += -DENABLE_ARM_L2_CACHE=1 +else +EXTRA_CFLAGS += -DENABLE_ARM_L2_CACHE=0 +endif + +ifeq ($(CONFIG_DOVE_GPU), 1) +EXTRA_CFLAGS += -DCONFIG_DOVE_GPU=1 +endif + +ifeq ($(gcdNO_POWER_MANAGEMENT), 1) +EXTRA_CFLAGS += -DgcdNO_POWER_MANAGEMENT=1 +else +EXTRA_CFLAGS += -DgcdNO_POWER_MANAGEMENT=0 +endif + +ifneq ($(USE_PLATFORM_DRIVER), 0) +EXTRA_CFLAGS += -DUSE_PLATFORM_DRIVER=1 +else +EXTRA_CFLAGS += -DUSE_PLATFORM_DRIVER=0 +endif + +ifeq ($(USE_PROFILER), 1) +EXTRA_CFLAGS += -DVIVANTE_PROFILER=1 +else +EXTRA_CFLAGS += -DVIVANTE_PROFILER=0 +endif + +ifeq ($(ANDROID), 1) +EXTRA_CFLAGS += -DANDROID=1 +endif + +ifeq ($(ENABLE_GPU_CLOCK_BY_DRIVER), 1) +EXTRA_CFLAGS += -DENABLE_GPU_CLOCK_BY_DRIVER=1 +else +EXTRA_CFLAGS += -DENABLE_GPU_CLOCK_BY_DRIVER=0 +endif + +ifeq ($(USE_NEW_LINUX_SIGNAL), 1) +EXTRA_CFLAGS += -DUSE_NEW_LINUX_SIGNAL=1 +else +EXTRA_CFLAGS += -DUSE_NEW_LINUX_SIGNAL=0 +endif + +ifeq ($(NO_USER_DIRECT_ACCESS_FROM_KERNEL), 1) +EXTRA_CFLAGS += -DNO_USER_DIRECT_ACCESS_FROM_KERNEL=1 +else +EXTRA_CFLAGS += -DNO_USER_DIRECT_ACCESS_FROM_KERNEL=0 +endif + +EXTRA_CFLAGS += -I$(AQROOT)/hal/inc +EXTRA_CFLAGS += -I$(AQROOT)/hal/kernel +EXTRA_CFLAGS += -I$(AQARCH)/hal/kernel +EXTRA_CFLAGS += -I$(AQARCH)/cmodel/inc +EXTRA_CFLAGS += -I$(AQROOT)/hal/user + +obj-m = $(DRIVER_OUT_DIR)/galcore.o + +$(DRIVER_OUT_DIR)/galcore-objs = $(OBJS) + +endif diff --git a/drivers/staging/rk29/vivante/Kconfig b/drivers/staging/rk29/vivante/Kconfig new file mode 100644 index 000000000000..7e0bfe8f7273 --- /dev/null +++ b/drivers/staging/rk29/vivante/Kconfig @@ -0,0 +1,7 @@ +menu "GPU Vivante" +config VIVANTE + tristate "ROCKCHIP Vivante GPU" + default y + help + Vivante GPU module. +endmenu diff --git a/drivers/staging/rk29/vivante/Makefile b/drivers/staging/rk29/vivante/Makefile new file mode 100644 index 000000000000..7889049712f0 --- /dev/null +++ b/drivers/staging/rk29/vivante/Makefile @@ -0,0 +1,202 @@ +############################################################################## +# +# Copyright (C) 2005 - 2010 by Vivante Corp. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the license, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +############################################################################## + + +# +# Linux build file for kernel HAL driver. +# + +################################################################ +# Arch. + +ARCH_TYPE ?= arm +CPU_TYPE ?= arm920 +CPU_ARCH ?= 0 +STATIC_LINK ?= 0 +EGL_API_FB ?= 0 +USE_VDK ?= 0 +USE_PROFILER ?= 0 +USE_SW_FB ?= 0 +USE_3D_VG =1 +ABI ?= 0 +ANDROID ?= 0 +EGL_API_ANDROID ?= 0 +ENUM_WORKAROUND ?= 0 +ENDIANNESS ?= +QNX ?= 0 +LINUX_OABI ?= 0 +USE_ARMCC ?= 0 + +ifeq ($(LINUX_OABI), 1) +ABI ?= 0 +else +ABI ?= aapcs-linux +endif + +################################################################ +# Force to use dma_coherent_* stuff. + +NO_DMA_COHERENT ?= 0 + +################################################################ +# Set this value to 1 if you are using ARM L2 cache. + +ENABLE_ARM_L2_CACHE = 0 + +################################################################ +# Set this value to 1 if you are using DOVE board. +CONFIG_DOVE_GPU = 0 + + +ENABLE_GPU_CLOCK_BY_DRIVER = 0 + + +AQROOT ?= drivers/staging/rk29/vivante +AQARCH ?= $(AQROOT)/arch/XAQ2 + +#include $(AQROOT)/config +ARCH_TYPE ?= arm +SDK_DIR ?= $(AQROOT)/build/sdk +USE_3D_VG = 1 + +DEBUG = 1 + +#DRIVER_OUT_DIR = hal/driver +#KERNEL_DIR ?= $(TOOL_DIR)/kernel + +OS_KERNEL_DIR := hal/os/linux/kernel +ARCH_KERNEL_DIR := arch/XAQ2/hal/kernel +HAL_KERNEL_DIR := hal/kernel + +EXTRA_CFLAGS += -Werror + +OBJS := $(OS_KERNEL_DIR)/gc_hal_kernel_debug.o \ + $(OS_KERNEL_DIR)/gc_hal_kernel_device.o \ + $(OS_KERNEL_DIR)/gc_hal_kernel_driver.o \ + $(OS_KERNEL_DIR)/gc_hal_kernel_linux.o \ + $(OS_KERNEL_DIR)/gc_hal_kernel_os.o + +ifeq ($(USE_3D_VG), 1) + +OBJS += $(HAL_KERNEL_DIR)/gc_hal_kernel.o \ + $(HAL_KERNEL_DIR)/gc_hal_kernel_command.o \ + $(HAL_KERNEL_DIR)/gc_hal_kernel_event.o \ + $(HAL_KERNEL_DIR)/gc_hal_kernel_heap.o \ + $(HAL_KERNEL_DIR)/gc_hal_kernel_mmu.o \ + $(HAL_KERNEL_DIR)/gc_hal_kernel_video_memory.o + +OBJS += $(ARCH_KERNEL_DIR)/gc_hal_kernel_hardware.o + +else + +OBJS += $(HAL_KERNEL_DIR)/gc_hal_kernel.o \ + $(HAL_KERNEL_DIR)/gc_hal_kernel_command.o \ + $(HAL_KERNEL_DIR)/gc_hal_kernel_heap.o \ + $(HAL_KERNEL_DIR)/gc_hal_kernel_interrupt.o \ + $(HAL_KERNEL_DIR)/gc_hal_kernel_mmu.o \ + $(HAL_KERNEL_DIR)/gc_hal_kernel_video_memory.o + +OBJS += $(ARCH_KERNEL_DIR)/gc_hal_kernel_hardware.o \ + $(ARCH_KERNEL_DIR)/gc_hal_kernel_hardware_command.o + +endif + + +EXTRA_CFLAGS += -DLINUX -DDRIVER + +ifeq ($(ENUM_WORKAROUND), 1) +EXTRA_CFLAGS += -DENUM_WORKAROUND=1 +else +EXTRA_CFLAGS += -DENUM_WORKAROUND=0 +endif + +ifeq ($(FLAREON),1) +EXTRA_CFLAGS += -DFLAREON +endif + +ifeq ($(DEBUG), 1) +EXTRA_CFLAGS += -DDBG=1 -DDEBUG -D_DEBUG +else +EXTRA_CFLAGS += -DDBG=0 +endif + +ifeq ($(NO_DMA_COHERENT), 1) +EXTRA_CFLAGS += -DNO_DMA_COHERENT +endif + +ifeq ($(ENABLE_ARM_L2_CACHE), 1) +EXTRA_CFLAGS += -DENABLE_ARM_L2_CACHE=1 +else +EXTRA_CFLAGS += -DENABLE_ARM_L2_CACHE=0 +endif + +ifeq ($(CONFIG_DOVE_GPU), 1) +EXTRA_CFLAGS += -DCONFIG_DOVE_GPU=1 +endif + +ifeq ($(gcdNO_POWER_MANAGEMENT), 1) +EXTRA_CFLAGS += -DgcdNO_POWER_MANAGEMENT=1 +else +EXTRA_CFLAGS += -DgcdNO_POWER_MANAGEMENT=0 +endif + +ifneq ($(USE_PLATFORM_DRIVER), 0) +EXTRA_CFLAGS += -DUSE_PLATFORM_DRIVER=1 +else +EXTRA_CFLAGS += -DUSE_PLATFORM_DRIVER=0 +endif + +ifeq ($(USE_PROFILER), 1) +EXTRA_CFLAGS += -DVIVANTE_PROFILER=1 +else +EXTRA_CFLAGS += -DVIVANTE_PROFILER=0 +endif + +ifeq ($(ANDROID), 1) +EXTRA_CFLAGS += -DANDROID=1 +endif + +ifeq ($(ENABLE_GPU_CLOCK_BY_DRIVER), 1) +EXTRA_CFLAGS += -DENABLE_GPU_CLOCK_BY_DRIVER=1 +else +EXTRA_CFLAGS += -DENABLE_GPU_CLOCK_BY_DRIVER=0 +endif + +ifeq ($(USE_NEW_LINUX_SIGNAL), 1) +EXTRA_CFLAGS += -DUSE_NEW_LINUX_SIGNAL=1 +else +EXTRA_CFLAGS += -DUSE_NEW_LINUX_SIGNAL=0 +endif + +ifeq ($(NO_USER_DIRECT_ACCESS_FROM_KERNEL), 1) +EXTRA_CFLAGS += -DNO_USER_DIRECT_ACCESS_FROM_KERNEL=1 +else +EXTRA_CFLAGS += -DNO_USER_DIRECT_ACCESS_FROM_KERNEL=0 +endif + +EXTRA_CFLAGS += -I$(AQROOT)/hal/inc +EXTRA_CFLAGS += -I$(AQROOT)/hal/kernel +EXTRA_CFLAGS += -I$(AQARCH)/hal/kernel +EXTRA_CFLAGS += -I$(AQARCH)/cmodel/inc +EXTRA_CFLAGS += -I$(AQROOT)/hal/user + +obj-$(CONFIG_VIVANTE) += galcore.o +galcore-objs := $(OBJS) + diff --git a/drivers/staging/rk29/vivante/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.c b/drivers/staging/rk29/vivante/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.c new file mode 100644 index 000000000000..1e2d1cb98d5b --- /dev/null +++ b/drivers/staging/rk29/vivante/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.c @@ -0,0 +1,3754 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal.h" +#include "gc_hal_kernel.h" + +#define _GC_OBJ_ZONE gcvZONE_HARDWARE + +/******************************************************************************\ +********************************* Support Code ********************************* +\******************************************************************************/ + +static gceSTATUS +_IdentifyHardware( + IN gckOS Os, + OUT gceCHIPMODEL * ChipModel, + OUT gctUINT32_PTR ChipRevision, + OUT gctUINT32_PTR ChipFeatures, + OUT gctUINT32_PTR ChipMinorFeatures0, + OUT gctUINT32_PTR ChipMinorFeatures1 + ) +{ + gceSTATUS status; + gctUINT32 chipIdentity; + + gcmkHEADER_ARG("Os=0x%x", Os); + + /* Read chip identity register. */ + gcmkONERROR( + gckOS_ReadRegister(Os, 0x00018, &chipIdentity)); + + /* Special case for older graphic cores. */ + if (((((gctUINT32) (chipIdentity)) >> (0 ? 31:24) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1)))))) == (0x01 & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1)))))))) + { + *ChipModel = gcv500; + *ChipRevision = ( ((((gctUINT32) (chipIdentity)) >> (0 ? 15:12)) & ((gctUINT32) ((((1 ? 15:12) - (0 ? 15:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:12) - (0 ? 15:12) + 1)))))) ); + } + + else + { + /* Read chip identity register. */ + gcmkONERROR( + gckOS_ReadRegister(Os, + 0x00020, + (gctUINT32_PTR) ChipModel)); + + /* !!!! HACK ALERT !!!! */ + /* Because people change device IDs without letting software know + ** about it - here is the hack to make it all look the same. Only + ** for GC400 family. Next time - TELL ME!!! */ + if ((*ChipModel & 0xFF00) == 0x0400) + { + *ChipModel &= 0x0400; + } + + /* Read CHIP_REV register. */ + gcmkONERROR( + gckOS_ReadRegister(Os, 0x00024, ChipRevision)); + + if ((*ChipModel == gcv300) + && (*ChipRevision == 0x2201) + ) + { + gctUINT32 date, time; + + /* Read date and time registers. */ + gcmkONERROR( + gckOS_ReadRegister(Os, 0x00028, &date)); + + gcmkONERROR( + gckOS_ReadRegister(Os, 0x0002C, &time)); + + if ((date == 0x20080814) && (time == 0x12051100)) + { + /* This IP has an ECO; put the correct revision in it. */ + *ChipRevision = 0x1051; + } + } + } + + /* Read chip feature register. */ + gcmkONERROR( + gckOS_ReadRegister(Os, 0x0001C, ChipFeatures)); + + /* Disable fast clear on GC700. */ + if (*ChipModel == gcv700) + { + *ChipFeatures = ((((gctUINT32) (*ChipFeatures)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); + } + + if (((*ChipModel == gcv500) && (*ChipRevision < 2)) + || ((*ChipModel == gcv300) && (*ChipRevision < 0x2000)) + ) + { + /* GC500 rev 1.x and GC300 rev < 2.0 doesn't have these registers. */ + *ChipMinorFeatures0 = 0; + *ChipMinorFeatures1 = 0; + } + else + { + /* Read chip minor feature register #0. */ + gcmkONERROR( + gckOS_ReadRegister(Os, + 0x00034, + ChipMinorFeatures0)); + + /* Disable fast clear flush on some specific cores. */ + if (((*ChipModel == gcv600) && (*ChipRevision == 0x4302)) + ) + { + *ChipMinorFeatures0 = ((((gctUINT32) (*ChipMinorFeatures0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))); + } + + if (((((gctUINT32) (*ChipMinorFeatures0)) >> (0 ? 21:21) & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1))))))) + ) + { + /* Read chip minor featuress register #1. */ + gcmkONERROR( + gckOS_ReadRegister(Os, + 0x00074, + ChipMinorFeatures1)); + } + else + { + /* Chip doesn't has minor features register #1. */ + *ChipMinorFeatures1 = 0; + } + } + + /* Success. */ + gcmkFOOTER_ARG("*ChipModel=%x *ChipRevision=%x *ChipFeatures=%08x " + "*ChipMinorFeatures0=%08X *ChipMinorFeatures1=%08x", + *ChipModel, *ChipRevision, *ChipFeatures, + *ChipMinorFeatures0, *ChipMinorFeatures1); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +static gceSTATUS +_GetChipSpecs( + IN gckHARDWARE Hardware + ) +{ + gctUINT32 streamCount = 0; + gctUINT32 registerMax = 0; + gctUINT32 threadCount = 0; + gctUINT32 shaderCoreCount = 0; + gctUINT32 vertexCacheSize = 0; + gctUINT32 vertexOutputBufferSize = 0; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + if (((((gctUINT32) (Hardware->chipMinorFeatures0)) >> (0 ? 21:21) & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1)))))))) + { + gctUINT32 specs; + + /* Read gcChipSpecs register. */ + gcmkONERROR( + gckOS_ReadRegister(Hardware->os, 0x00048, &specs)); + + /* Handy macro to improve reading. */ +#define gcmSPEC_FIELD(field) \ + ( ((((gctUINT32) (specs)) >> (0 ? GC_CHIP_SPECS_field)) & ((gctUINT32) ((((1 ? GC_CHIP_SPECS_field) - (0 ? GC_CHIP_SPECS_field) + 1) == 32) ? ~0 : (~(~0 << ((1 ? GC_CHIP_SPECS_field) - (0 ? GC_CHIP_SPECS_field) + 1)))))) ) + + /* Extract the fields. */ + streamCount = ( ((((gctUINT32) (specs)) >> (0 ? 3:0)) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1)))))) ); + registerMax = ( ((((gctUINT32) (specs)) >> (0 ? 7:4)) & ((gctUINT32) ((((1 ? 7:4) - (0 ? 7:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:4) - (0 ? 7:4) + 1)))))) ); + threadCount = ( ((((gctUINT32) (specs)) >> (0 ? 11:8)) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1)))))) ); + shaderCoreCount = ( ((((gctUINT32) (specs)) >> (0 ? 24:20)) & ((gctUINT32) ((((1 ? 24:20) - (0 ? 24:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 24:20) - (0 ? 24:20) + 1)))))) ); + vertexCacheSize = ( ((((gctUINT32) (specs)) >> (0 ? 16:12)) & ((gctUINT32) ((((1 ? 16:12) - (0 ? 16:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:12) - (0 ? 16:12) + 1)))))) ); + vertexOutputBufferSize = ( ((((gctUINT32) (specs)) >> (0 ? 31:28)) & ((gctUINT32) ((((1 ? 31:28) - (0 ? 31:28) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:28) - (0 ? 31:28) + 1)))))) ); + } + + /* Get the stream count. */ + Hardware->streamCount = (streamCount != 0) + ? streamCount + : (Hardware->chipModel >= gcv1000) ? 4 : 1; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Specs: streamCount=%u%s", + Hardware->streamCount, + (streamCount == 0) ? " (default)" : ""); + + /* Get the vertex output buffer size. */ + Hardware->vertexOutputBufferSize = (vertexOutputBufferSize != 0) + ? 1 << vertexOutputBufferSize + : (Hardware->chipModel == gcv400) + ? (Hardware->chipRevision < 0x4000) ? 512 + : (Hardware->chipRevision < 0x4200) ? 256 + : 128 + : (Hardware->chipModel == gcv530) + ? (Hardware->chipRevision < 0x4200) ? 512 + : 128 + : 512; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Specs: vertexOutputBufferSize=%u%s", + Hardware->vertexOutputBufferSize, + (vertexOutputBufferSize == 0) ? " (default)" : ""); + + /* Get the maximum number of threads. */ + Hardware->threadCount = (threadCount != 0) + ? 1 << threadCount + : (Hardware->chipModel == gcv400) ? 64 + : (Hardware->chipModel == gcv500) ? 128 + : (Hardware->chipModel == gcv530) ? 128 + : 256; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Specs: threadCount=%u%s", + Hardware->threadCount, + (threadCount == 0) ? " (default)" : ""); + + /* Get the number of shader cores. */ + Hardware->shaderCoreCount = (shaderCoreCount != 0) + ? shaderCoreCount + : (Hardware->chipModel >= gcv1000) ? 2 + : 1; + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Specs: shaderCoreCount=%u%s", + Hardware->shaderCoreCount, + (shaderCoreCount == 0) ? " (default)" : ""); + + /* Get the vertex cache size. */ + Hardware->vertexCacheSize = (vertexCacheSize != 0) + ? vertexCacheSize + : 8; + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Specs: vertexCacheSize=%u%s", + Hardware->vertexCacheSize, + (vertexCacheSize == 0) ? " (default)" : ""); + + /* Get the maximum number of temporary registers. */ + Hardware->registerMax = (registerMax != 0) + ? 1 << registerMax + : (Hardware->chipModel == gcv400) ? 32 + : 64; + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Specs: registerMax=%u%s", + Hardware->registerMax, + (registerMax == 0) ? " (default)" : ""); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************\ +****************************** gckHARDWARE API code ***************************** +\******************************************************************************/ + +/******************************************************************************* +** +** gckHARDWARE_Construct +** +** Construct a new gckHARDWARE object. +** +** INPUT: +** +** gckOS Os +** Pointer to an initialized gckOS object. +** +** OUTPUT: +** +** gckHARDWARE * Hardware +** Pointer to a variable that will hold the pointer to the gckHARDWARE +** object. +*/ +gceSTATUS +gckHARDWARE_Construct( + IN gckOS Os, + OUT gckHARDWARE * Hardware + ) +{ + gckHARDWARE hardware = gcvNULL; + gceSTATUS status; + gceCHIPMODEL chipModel; + gctUINT32 chipRevision; + gctUINT32 chipFeatures; + gctUINT32 chipMinorFeatures0; + gctUINT32 chipMinorFeatures1; + gctUINT16 data = 0xff00; + + gcmkHEADER_ARG("Os=0x%x", Os); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Hardware != gcvNULL); + + /* Identify the hardware. */ + gcmkONERROR(_IdentifyHardware(Os, + &chipModel, + &chipRevision, + &chipFeatures, + &chipMinorFeatures0, + &chipMinorFeatures1)); + + /* Allocate the gckHARDWARE object. */ + gcmkONERROR(gckOS_Allocate(Os, + gcmSIZEOF(struct _gckHARDWARE), + (gctPOINTER *) &hardware)); + + /* Initialize the gckHARDWARE object. */ + hardware->object.type = gcvOBJ_HARDWARE; + hardware->os = Os; + + /* Set chip identity. */ + hardware->chipModel = chipModel; + hardware->chipRevision = chipRevision; + hardware->chipFeatures = chipFeatures; + hardware->chipMinorFeatures0 = chipMinorFeatures0; + hardware->chipMinorFeatures1 = chipMinorFeatures1; + hardware->powerBaseAddress = ( (chipModel == gcv300) + && (chipRevision < 0x2000) + ) ? 0x100 : 0x00; + hardware->powerMutex = gcvNULL; + + /* Get chip specs. */ + gcmkONERROR(_GetChipSpecs(hardware)); + + /* Determine whether bug fixes #1 are present. */ + hardware->extraEventStates = ((((gctUINT32) (chipMinorFeatures1)) >> (0 ? 3:3) & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1)))))) == (0x0 & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))); + + /* Check if big endian */ + hardware->bigEndian = (*(gctUINT8 *)&data == 0xff); + + /* Initialize the fast clear. */ + gcmkONERROR(gckHARDWARE_SetFastClear(hardware, -1, -1)); + + /* Set power state to ON. */ + hardware->chipPowerState = gcvPOWER_ON; + hardware->lastWaitLink = ~0U; + + gcmkONERROR(gckOS_CreateMutex(Os, &hardware->powerMutex)); + + /* Return pointer to the gckHARDWARE object. */ + *Hardware = hardware; + + /* Success. */ + gcmkFOOTER_ARG("*Hardware=0x%x", *Hardware); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (hardware->powerMutex != gcvNULL) + { + gcmkVERIFY_OK(gckOS_DeleteMutex(Os, hardware->powerMutex)); + } + + if (hardware != gcvNULL) + { + gcmkVERIFY_OK(gckOS_Free(Os, hardware)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_Destroy +** +** Destroy an gckHARDWARE object. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object that needs to be destroyed. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_Destroy( + IN gckHARDWARE Hardware + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Destroy the power mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Hardware->os, Hardware->powerMutex)); + + /* Mark the object as unknown. */ + Hardware->object.type = gcvOBJ_UNKNOWN; + + /* Free the object. */ + gcmkONERROR(gckOS_Free(Hardware->os, Hardware)); + + /* Success. */ + gcmkFOOTER(); + return gcvSTATUS_OK; + +OnError: + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_InitializeHardware +** +** Initialize the hardware. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_InitializeHardware( + IN gckHARDWARE Hardware + ) +{ + gceSTATUS status; + gctUINT32 baseAddress; + gctUINT32 chipRev; + + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Read the chip revision register. */ + gcmkONERROR(gckOS_ReadRegister(Hardware->os, + 0x00024, + &chipRev)); + + if (chipRev != Hardware->chipRevision) + { + /* Chip is not there! */ + gcmkONERROR(gcvSTATUS_CONTEXT_LOSSED); + } + + /* Disable isolate GPU bit. */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, + 0x00000, + ((((gctUINT32) (0x00000100)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))))); + + /* Reset memory counters. */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, + 0x0003C, + ~0U)); + + gcmkONERROR(gckOS_WriteRegister(Hardware->os, + 0x0003C, + 0)); + + /* Get the system's physical base address. */ + gcmkONERROR(gckOS_GetBaseAddress(Hardware->os, &baseAddress)); + + /* Program the base addesses. */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, + 0x0041C, + baseAddress)); + + gcmkONERROR(gckOS_WriteRegister(Hardware->os, + 0x00418, + baseAddress)); + + gcmkONERROR(gckOS_WriteRegister(Hardware->os, + 0x00420, + baseAddress)); + + gcmkONERROR(gckOS_WriteRegister(Hardware->os, + 0x00428, + baseAddress)); + + gcmkONERROR(gckOS_WriteRegister(Hardware->os, + 0x00424, + baseAddress)); + +#if !VIVANTE_PROFILER && 1 + { + gctUINT32 data; + + gcmkONERROR(gckOS_ReadRegister(Hardware->os, + Hardware->powerBaseAddress + + 0x00100, + &data)); + + /* Enable clock gating. */ + data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); + + if ((Hardware->chipRevision == 0x4301) + || (Hardware->chipRevision == 0x4302) + ) + { + /* Disable stall module level clock gating for 4.3.0.1 and 4.3.0.2 + ** revisions. */ + data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))); + } + + gcmkONERROR(gckOS_WriteRegister(Hardware->os, + Hardware->powerBaseAddress + + 0x00100, + data)); + + /* Disable PE clock gating on revs < 5.0 when HZ is present without a + ** bug fix. */ + if ((Hardware->chipRevision < 0x5000) + && ((((gctUINT32) (Hardware->chipMinorFeatures1)) >> (0 ? 9:9) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1)))))) == (0x0 & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) + && ((((gctUINT32) (Hardware->chipMinorFeatures0)) >> (0 ? 27:27) & ((gctUINT32) ((((1 ? 27:27) - (0 ? 27:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:27) - (0 ? 27:27) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 27:27) - (0 ? 27:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:27) - (0 ? 27:27) + 1))))))) + ) + { + gcmkONERROR( + gckOS_ReadRegister(Hardware->os, + Hardware->powerBaseAddress + + 0x00104, + &data)); + + /* Disable PE clock gating. */ + data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))); + + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, + Hardware->powerBaseAddress + + 0x00104, + data)); + } + } +#endif + + /* Test if MMU is initialized. */ + if ((Hardware->kernel != gcvNULL) + && (Hardware->kernel->mmu != gcvNULL) + ) + { + /* Reset MMU. */ + gcmkONERROR( + gckHARDWARE_SetMMU(Hardware, + Hardware->kernel->mmu->pageTableLogical)); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the error. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_QueryMemory +** +** Query the amount of memory available on the hardware. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object. +** +** OUTPUT: +** +** gctSIZE_T * InternalSize +** Pointer to a variable that will hold the size of the internal video +** memory in bytes. If 'InternalSize' is gcvNULL, no information of the +** internal memory will be returned. +** +** gctUINT32 * InternalBaseAddress +** Pointer to a variable that will hold the hardware's base address for +** the internal video memory. This pointer cannot be gcvNULL if +** 'InternalSize' is also non-gcvNULL. +** +** gctUINT32 * InternalAlignment +** Pointer to a variable that will hold the hardware's base address for +** the internal video memory. This pointer cannot be gcvNULL if +** 'InternalSize' is also non-gcvNULL. +** +** gctSIZE_T * ExternalSize +** Pointer to a variable that will hold the size of the external video +** memory in bytes. If 'ExternalSize' is gcvNULL, no information of the +** external memory will be returned. +** +** gctUINT32 * ExternalBaseAddress +** Pointer to a variable that will hold the hardware's base address for +** the external video memory. This pointer cannot be gcvNULL if +** 'ExternalSize' is also non-gcvNULL. +** +** gctUINT32 * ExternalAlignment +** Pointer to a variable that will hold the hardware's base address for +** the external video memory. This pointer cannot be gcvNULL if +** 'ExternalSize' is also non-gcvNULL. +** +** gctUINT32 * HorizontalTileSize +** Number of horizontal pixels per tile. If 'HorizontalTileSize' is +** gcvNULL, no horizontal pixel per tile will be returned. +** +** gctUINT32 * VerticalTileSize +** Number of vertical pixels per tile. If 'VerticalTileSize' is +** gcvNULL, no vertical pixel per tile will be returned. +*/ +gceSTATUS +gckHARDWARE_QueryMemory( + IN gckHARDWARE Hardware, + OUT gctSIZE_T * InternalSize, + OUT gctUINT32 * InternalBaseAddress, + OUT gctUINT32 * InternalAlignment, + OUT gctSIZE_T * ExternalSize, + OUT gctUINT32 * ExternalBaseAddress, + OUT gctUINT32 * ExternalAlignment, + OUT gctUINT32 * HorizontalTileSize, + OUT gctUINT32 * VerticalTileSize + ) +{ + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + if (InternalSize != gcvNULL) + { + /* No internal memory. */ + *InternalSize = 0; + } + + if (ExternalSize != gcvNULL) + { + /* No external memory. */ + *ExternalSize = 0; + } + + if (HorizontalTileSize != gcvNULL) + { + /* 4x4 tiles. */ + *HorizontalTileSize = 4; + } + + if (VerticalTileSize != gcvNULL) + { + /* 4x4 tiles. */ + *VerticalTileSize = 4; + } + + /* Success. */ + gcmkFOOTER_ARG("*InternalSize=%lu *InternalBaseAddress=0x%08x " + "*InternalAlignment=0x%08x *ExternalSize=%lu " + "*ExternalBaseAddress=0x%08x *ExtenalAlignment=0x%08x " + "*HorizontalTileSize=%u *VerticalTileSize=%u", + gcmOPT_VALUE(InternalSize), + gcmOPT_VALUE(InternalBaseAddress), + gcmOPT_VALUE(InternalAlignment), + gcmOPT_VALUE(ExternalSize), + gcmOPT_VALUE(ExternalBaseAddress), + gcmOPT_VALUE(ExternalAlignment), + gcmOPT_VALUE(HorizontalTileSize), + gcmOPT_VALUE(VerticalTileSize)); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHARDWARE_QueryChipIdentity +** +** Query the identity of the hardware. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object. +** +** OUTPUT: +** +** gceCHIPMODEL * ChipModel +** If 'ChipModel' is not gcvNULL, the variable it points to will +** receive the model of the chip. +** +** gctUINT32 * ChipRevision +** If 'ChipRevision' is not gcvNULL, the variable it points to will +** receive the revision of the chip. +** +** gctUINT32 * ChipFeatures +** If 'ChipFeatures' is not gcvNULL, the variable it points to will +** receive the feature set of the chip. +** +** gctUINT32 * ChipMinorFeatures +** If 'ChipMinorFeatures' is not gcvNULL, the variable it points to +** will receive the minor feature set of the chip. +** +** gctUINT32 * ChipMinorFeatures1 +** If 'ChipMinorFeatures1' is not gcvNULL, the variable it points to +** will receive the minor feature set 1 of the chip. +** +*/ +gceSTATUS +gckHARDWARE_QueryChipIdentity( + IN gckHARDWARE Hardware, + OUT gceCHIPMODEL * ChipModel, + OUT gctUINT32 * ChipRevision, + OUT gctUINT32* ChipFeatures, + OUT gctUINT32* ChipMinorFeatures, + OUT gctUINT32* ChipMinorFeatures1 + ) +{ + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Return chip model. */ + if (ChipModel != gcvNULL) + { + *ChipModel = Hardware->chipModel; + } + + /* Return revision number. */ + if (ChipRevision != gcvNULL) + { + *ChipRevision = Hardware->chipRevision; + } + + /* Return feature set. */ + if (ChipFeatures != gcvNULL) + { + gctUINT32 features = Hardware->chipFeatures; + + if (( ((((gctUINT32) (features)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) )) + { + /* Override fast clear by command line. */ + features = ((((gctUINT32) (features)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (Hardware->allowFastClear) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); + } + + if (( ((((gctUINT32) (features)) >> (0 ? 5:5)) & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1)))))) )) + { + /* Override compression by command line. */ + features = ((((gctUINT32) (features)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))) | (((gctUINT32) ((gctUINT32) (Hardware->allowCompression) & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))); + } + + /* Mark 2D pipe as available for GC500.0 through GC500.2 and GC300, + ** since they did not have this bit. */ + if (( (Hardware->chipModel == gcv500) + && (Hardware->chipRevision <= 2) + ) + || (Hardware->chipModel == gcv300) + ) + { + features = ((((gctUINT32) (features)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))); + } + + *ChipFeatures = features; + } + + /* Return minor feature set. */ + if (ChipMinorFeatures != gcvNULL) + { + *ChipMinorFeatures = Hardware->chipMinorFeatures0; + } + + /* Return minor feature set 1. */ + if (ChipMinorFeatures1 != gcvNULL) + { + *ChipMinorFeatures1 = Hardware->chipMinorFeatures1; + } + + /* Success. */ + gcmkFOOTER_ARG("*ChipModel=0x%x *ChipRevision=0x%x *ChipFeatures=0x%08x " + "*ChipMinorFeatures=0x%08x *ChipMinorFeatures1=0x%08x", + gcmOPT_VALUE(ChipModel), gcmOPT_VALUE(ChipRevision), + gcmOPT_VALUE(ChipFeatures), gcmOPT_VALUE(ChipMinorFeatures), + gcmOPT_VALUE(ChipMinorFeatures1)); + return gcvSTATUS_OK; +} + +gceSTATUS +gckHARDWARE_QueryChipSpecs( + IN gckHARDWARE Hardware, + OUT gctUINT32_PTR StreamCount, + OUT gctUINT32_PTR RegisterMax, + OUT gctUINT32_PTR ThreadCount, + OUT gctUINT32_PTR ShaderCoreCount, + OUT gctUINT32_PTR VertexCacheSize, + OUT gctUINT32_PTR VertexOutputBufferSize + ) +{ + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Return the number of streams. */ + if (StreamCount != gcvNULL) + { + *StreamCount = Hardware->streamCount; + } + + /* Return the number of temporary registers. */ + if (RegisterMax != gcvNULL) + { + *RegisterMax = Hardware->registerMax; + } + + /* Return the maximum number of thrteads. */ + if (ThreadCount != gcvNULL) + { + *ThreadCount = Hardware->threadCount; + } + + /* Return the number of shader cores. */ + if (ShaderCoreCount != gcvNULL) + { + *ShaderCoreCount = Hardware->shaderCoreCount; + } + + /* Return the number of entries in the vertex cache. */ + if (VertexCacheSize != gcvNULL) + { + *VertexCacheSize = Hardware->vertexCacheSize; + } + + /* Return the number of entries in the vertex output buffer. */ + if (VertexOutputBufferSize != gcvNULL) + { + *VertexOutputBufferSize = Hardware->vertexOutputBufferSize; + } + + /* Success. */ + gcmkFOOTER_ARG("*StreamCount=%u *RegisterMax=%u *ThreadCount=%u " + "*ShaderCoreCount=%u *VertexCacheSize=%u " + "*VertexOutputBufferSize=%u", + gcmOPT_VALUE(StreamCount), gcmOPT_VALUE(RegisterMax), + gcmOPT_VALUE(ThreadCount), gcmOPT_VALUE(ShaderCoreCount), + gcmOPT_VALUE(VertexCacheSize), + gcmOPT_VALUE(VertexOutputBufferSize)); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHARDWARE_ConvertFormat +** +** Convert an API format to hardware parameters. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object. +** +** gceSURF_FORMAT Format +** API format to convert. +** +** OUTPUT: +** +** gctUINT32 * BitsPerPixel +** Pointer to a variable that will hold the number of bits per pixel. +** +** gctUINT32 * BytesPerTile +** Pointer to a variable that will hold the number of bytes per tile. +*/ +gceSTATUS +gckHARDWARE_ConvertFormat( + IN gckHARDWARE Hardware, + IN gceSURF_FORMAT Format, + OUT gctUINT32 * BitsPerPixel, + OUT gctUINT32 * BytesPerTile + ) +{ + gctUINT32 bitsPerPixel; + gctUINT32 bytesPerTile; + + gcmkHEADER_ARG("Hardware=0x%x Format=%d", Hardware, Format); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Dispatch on format. */ + switch (Format) + { + case gcvSURF_INDEX8: + case gcvSURF_A8: + case gcvSURF_L8: + /* 8-bpp format. */ + bitsPerPixel = 8; + bytesPerTile = (8 * 4 * 4) / 8; + break; + + case gcvSURF_YV12: + case gcvSURF_I420: + case gcvSURF_NV12: + case gcvSURF_NV21: + /* 12-bpp planar YUV formats. */ + bitsPerPixel = 12; + bytesPerTile = (12 * 4 * 4) / 8; + break; + + case gcvSURF_A8L8: + case gcvSURF_X4R4G4B4: + case gcvSURF_A4R4G4B4: + case gcvSURF_X1R5G5B5: + case gcvSURF_A1R5G5B5: + case gcvSURF_R5G5B5X1: + case gcvSURF_R4G4B4X4: + case gcvSURF_X4B4G4R4: + case gcvSURF_X1B5G5R5: + case gcvSURF_B4G4R4X4: + case gcvSURF_R5G6B5: + case gcvSURF_B5G5R5X1: + case gcvSURF_YUY2: + case gcvSURF_UYVY: + case gcvSURF_YVYU: + case gcvSURF_VYUY: + case gcvSURF_NV16: + case gcvSURF_NV61: + case gcvSURF_D16: + /* 16-bpp format. */ + bitsPerPixel = 16; + bytesPerTile = (16 * 4 * 4) / 8; + break; + + case gcvSURF_X8R8G8B8: + case gcvSURF_A8R8G8B8: + case gcvSURF_X8B8G8R8: + case gcvSURF_A8B8G8R8: + case gcvSURF_R8G8B8X8: + case gcvSURF_D32: + /* 32-bpp format. */ + bitsPerPixel = 32; + bytesPerTile = (32 * 4 * 4) / 8; + break; + + case gcvSURF_D24S8: + case gcvSURF_D24X8: + /* 24-bpp format. */ + bitsPerPixel = 32; + bytesPerTile = (32 * 4 * 4) / 8; + break; + + case gcvSURF_DXT1: + case gcvSURF_ETC1: + bitsPerPixel = 4; + bytesPerTile = (4 * 4 * 4) / 8; + break; + + case gcvSURF_DXT2: + case gcvSURF_DXT3: + case gcvSURF_DXT4: + case gcvSURF_DXT5: + bitsPerPixel = 8; + bytesPerTile = (8 * 4 * 4) / 8; + break; + + default: + /* Invalid format. */ + gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT); + return gcvSTATUS_INVALID_ARGUMENT; + } + + /* Set the result. */ + if (BitsPerPixel != gcvNULL) + { + * BitsPerPixel = bitsPerPixel; + } + + if (BytesPerTile != gcvNULL) + { + * BytesPerTile = bytesPerTile; + } + + /* Success. */ + gcmkFOOTER_ARG("*BitsPerPixel=%u *BytesPerTile=%u", + gcmOPT_VALUE(BitsPerPixel), gcmOPT_VALUE(BytesPerTile)); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHARDWARE_SplitMemory +** +** Split a hardware specific memory address into a pool and offset. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object. +** +** gctUINT32 Address +** Address in hardware specific format. +** +** OUTPUT: +** +** gcePOOL * Pool +** Pointer to a variable that will hold the pool type for the address. +** +** gctUINT32 * Offset +** Pointer to a variable that will hold the offset for the address. +*/ +gceSTATUS +gckHARDWARE_SplitMemory( + IN gckHARDWARE Hardware, + IN gctUINT32 Address, + OUT gcePOOL * Pool, + OUT gctUINT32 * Offset + ) +{ + gcmkHEADER_ARG("Hardware=0x%x Addres=%08x", Hardware, Address); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(Pool != gcvNULL); + gcmkVERIFY_ARGUMENT(Offset != gcvNULL); + + /* Dispatch on memory type. */ + switch (( ((((gctUINT32) (Address)) >> (0 ? 31:31)) & ((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1)))))) )) + { + case 0x0: + /* System memory. */ + *Pool = gcvPOOL_SYSTEM; + break; + + case 0x1: + /* Virtual memory. */ + *Pool = gcvPOOL_VIRTUAL; + break; + + default: + /* Invalid memory type. */ + gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT); + return gcvSTATUS_INVALID_ARGUMENT; + } + + /* Return offset of address. */ + *Offset = ( ((((gctUINT32) (Address)) >> (0 ? 30:0)) & ((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1)))))) ); + + /* Success. */ + gcmkFOOTER_ARG("*Pool=%d *Offset=%08x", *Pool, *Offset); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHARDWARE_Execute +** +** Kickstart the hardware's command processor with an initialized command +** buffer. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object. +** +** gctPOINTER Logical +** Logical address of command buffer. +** +** gctSIZE_T Bytes +** Number of bytes for the prefetch unit (until after the first LINK). +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_Execute( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, +#ifdef __QNXNTO__ + IN gctPOINTER Physical, + IN gctBOOL PhysicalAddresses, +#endif + IN gctSIZE_T Bytes + ) +{ + gceSTATUS status; + gctUINT32 address = 0, control; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Bytes=%lu", + Hardware, Logical, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + +#ifdef __QNXNTO__ + if (PhysicalAddresses) + { + /* Convert physical into hardware specific address. */ + gcmkONERROR( + gckHARDWARE_ConvertPhysical(Hardware, Physical, &address)); + } + else + { +#endif + /* Convert logical into hardware specific address. */ + gcmkONERROR( + gckHARDWARE_ConvertLogical(Hardware, Logical, &address)); +#ifdef __QNXNTO__ + } +#endif + + /* Enable all events. */ + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, 0x00014, ~0U)); + + /* Write address register. */ + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, 0x00654, address)); + + /* Build control register. */ + control = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) ((Bytes+7)>>3) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + /* Set big endian */ + if (Hardware->bigEndian) + { + control |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 21:20) - (0 ? 21:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:20) - (0 ? 21:20) + 1))))))) << (0 ? 21:20))) | (((gctUINT32) (0x2 & ((gctUINT32) ((((1 ? 21:20) - (0 ? 21:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:20) - (0 ? 21:20) + 1))))))) << (0 ? 21:20))); + } + + /* Write control register. */ + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, 0x00658, control)); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Started command buffer @ %08x", + address); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_WaitLink +** +** Append a WAIT/LINK command sequence at the specified location in the command +** queue. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Pointer to the current location inside the command queue to append +** WAIT/LINK command sequence at or gcvNULL just to query the size of the +** WAIT/LINK command sequence. +** +** gctUINT32 Offset +** Offset into command buffer required for alignment. +** +** gctSIZE_T * Bytes +** Pointer to the number of bytes available for the WAIT/LINK command +** sequence. If 'Logical' is gcvNULL, this argument will be ignored. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that will receive the number of bytes required +** by the WAIT/LINK command sequence. If 'Bytes' is gcvNULL, nothing will +** be returned. +** +** gctPOINTER * Wait +** Pointer to a variable that will receive the pointer to the WAIT +** command. If 'Wait' is gcvNULL nothing will be returned. +** +** gctSIZE_T * WaitSize +** Pointer to a variable that will receive the number of bytes used by +** the WAIT command. If 'LinkSize' is gcvNULL nothing will be returned. +*/ +gceSTATUS +gckHARDWARE_WaitLink( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT32 Offset, + IN OUT gctSIZE_T * Bytes, + OUT gctPOINTER * Wait, + OUT gctSIZE_T * WaitSize + ) +{ + gceSTATUS status; + gctUINT32 address; + gctUINT32_PTR logical = (gctUINT32_PTR) Logical; + gctSIZE_T bytes; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Offset=%08x *Bytes=%lu", + Hardware, Logical, Offset, gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); + + /* Compute number of bytes required. */ + bytes = gcmALIGN(Offset + 16, 8) - Offset; + + if (Logical != gcvNULL) + { + /* Convert logical into hardware specific address. */ + gcmkONERROR( + gckHARDWARE_ConvertLogical(Hardware, + Logical, + &address)); + + if (*Bytes < bytes) + { + /* Command queue too small. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + + /* Append WAIT(200). */ + logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (200) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%08x: WAIT", address); + + /* Append LINK(2, address). */ + logical[2] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (bytes>>3) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + logical[3] = address; + + Hardware->lastWaitLink = address; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%08x: LINK %08x, #%lu", + address + 8, address, bytes); + + if (Wait != gcvNULL) + { + /* Return pointer to WAIT command. */ + *Wait = Logical; + } + + if (WaitSize != gcvNULL) + { + /* Return number of bytes used by the WAIT command. */ + *WaitSize = 8; + } + } + + if (Bytes != gcvNULL) + { + /* Return number of bytes required by the WAIT/LINK command + ** sequence. */ + *Bytes = bytes; + } + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu *Wait=0x%x *WaitSize=%lu", + gcmOPT_VALUE(Bytes), gcmOPT_POINTER(Wait), + gcmOPT_VALUE(WaitSize)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_End +** +** Append an END command at the specified location in the command queue. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Pointer to the current location inside the command queue to append +** END command at or gcvNULL just to query the size of the END command. +** +** gctSIZE_T * Bytes +** Pointer to the number of bytes available for the END command. If +** 'Logical' is gcvNULL, this argument will be ignored. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that will receive the number of bytes required +** for the END command. If 'Bytes' is gcvNULL, nothing will be returned. +*/ +gceSTATUS +gckHARDWARE_End( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN OUT gctSIZE_T * Bytes + ) +{ + gctUINT32_PTR logical = (gctUINT32_PTR) Logical; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x *Bytes=%lu", + Hardware, Logical, gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); + + if (Logical != gcvNULL) + { + if (*Bytes < 8) + { + /* Command queue too small. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + + /* Append END. */ + logical[0] = + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x02 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "0x%x: END", Logical); + + /* Make sure the CPU writes out the data to memory. */ + gcmkVERIFY_OK( + gckOS_MemoryBarrier(Hardware->os, Logical)); + } + + if (Bytes != gcvNULL) + { + /* Return number of bytes required by the END command. */ + *Bytes = 8; + } + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_Nop +** +** Append a NOP command at the specified location in the command queue. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Pointer to the current location inside the command queue to append +** NOP command at or gcvNULL just to query the size of the NOP command. +** +** gctSIZE_T * Bytes +** Pointer to the number of bytes available for the NOP command. If +** 'Logical' is gcvNULL, this argument will be ignored. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that will receive the number of bytes required +** for the NOP command. If 'Bytes' is gcvNULL, nothing will be returned. +*/ +gceSTATUS +gckHARDWARE_Nop( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN OUT gctSIZE_T * Bytes + ) +{ + gctUINT32_PTR logical = (gctUINT32_PTR) Logical; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x *Bytes=%lu", + Hardware, Logical, gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); + + if (Logical != gcvNULL) + { + if (*Bytes < 8) + { + /* Command queue too small. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + + /* Append NOP. */ + logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "0x%x: NOP", Logical); + } + + if (Bytes != gcvNULL) + { + /* Return number of bytes required by the NOP command. */ + *Bytes = 8; + } + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_Wait +** +** Append a WAIT command at the specified location in the command queue. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Pointer to the current location inside the command queue to append +** WAIT command at or gcvNULL just to query the size of the WAIT command. +** +** gctUINT32 Count +** Number of cycles to wait. +** +** gctSIZE_T * Bytes +** Pointer to the number of bytes available for the WAIT command. If +** 'Logical' is gcvNULL, this argument will be ignored. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that will receive the number of bytes required +** for the NOP command. If 'Bytes' is gcvNULL, nothing will be returned. +*/ +gceSTATUS +gckHARDWARE_Wait( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT32 Count, + IN OUT gctSIZE_T * Bytes + ) +{ + gctUINT32_PTR logical = (gctUINT32_PTR) Logical; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Count=%u *Bytes=%lu", + Hardware, Logical, Count, gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); + + if (Logical != gcvNULL) + { + if (*Bytes < 8) + { + /* Command queue too small. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + + /* Append WAIT. */ + logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (Count) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%x: WAIT %u", Logical, Count); + } + + if (Bytes != gcvNULL) + { + /* Return number of bytes required by the WAIT command. */ + *Bytes = 8; + } + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_Event +** +** Append an EVENT command at the specified location in the command queue. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Pointer to the current location inside the command queue to append +** the EVENT command at or gcvNULL just to query the size of the EVENT +** command. +** +** gctUINT8 Event +** Event ID to program. +** +** gceKERNEL_WHERE FromWhere +** Location of the pipe to send the event. +** +** gctSIZE_T * Bytes +** Pointer to the number of bytes available for the EVENT command. If +** 'Logical' is gcvNULL, this argument will be ignored. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that will receive the number of bytes required +** for the EVENT command. If 'Bytes' is gcvNULL, nothing will be +** returned. +*/ +gceSTATUS +gckHARDWARE_Event( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT8 Event, + IN gceKERNEL_WHERE FromWhere, + IN OUT gctSIZE_T * Bytes + ) +{ + gctUINT size; + gctUINT32 destination = 0; + gctUINT32_PTR logical = (gctUINT32_PTR) Logical; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Event=%u FromWhere=%d *Bytes=%lu", + Hardware, Logical, Event, FromWhere, gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); + gcmkVERIFY_ARGUMENT(Event < 32); + + /* Determine the size of the command. */ + size = (Hardware->extraEventStates && (FromWhere == gcvKERNEL_PIXEL)) + ? gcmALIGN(8 + (1 + 5) * 4, 8) /* EVENT + 5 STATES */ + : 8; + + if (Logical != gcvNULL) + { + if (*Bytes < size) + { + /* Command queue too small. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + + switch (FromWhere) + { + case gcvKERNEL_COMMAND: + /* From command processor. */ + destination = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))) | (((gctUINT32) (0x1&((gctUINT32)((((1?5:5)-(0?5:5)+1)==32)?~0:(~(~0<<((1?5:5)-(0?5:5)+1)))))))<<(0?5:5))); + break; + + case gcvKERNEL_PIXEL: + /* From pixel engine. */ + destination = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))) | (((gctUINT32) (0x1&((gctUINT32)((((1?6:6)-(0?6:6)+1)==32)?~0:(~(~0<<((1?6:6)-(0?6:6)+1)))))))<<(0?6:6))); + break; + + default: + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + /* Append EVENT(Event, destiantion). */ + logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E01) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + + logical[1] = ((((gctUINT32) (destination)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) ((gctUINT32) (Event) & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))); + + /* Make sure the event ID gets written out before GPU can access it. */ + gcmkONERROR( + gckOS_MemoryBarrier(Hardware->os, logical + 1)); + +#if gcdDEBUG + { + gctUINT32 phys; + gckOS_GetPhysicalAddress(Hardware->os, Logical, &phys); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%08x: EVENT %d", phys, Event); + } +#endif + + /* Append the extra states. These are needed for the chips that do not + ** support back-to-back events due to the async interface. The extra + ** states add the necessary delay to ensure that event IDs do not + ** collide. */ + if (size > 8) + { + logical[2] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0100) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + logical[3] = 0; + logical[4] = 0; + logical[5] = 0; + logical[6] = 0; + logical[7] = 0; + } + } + + if (Bytes != gcvNULL) + { + /* Return number of bytes required by the EVENT command. */ + *Bytes = size; + } + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_PipeSelect +** +** Append a PIPESELECT command at the specified location in the command queue. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Pointer to the current location inside the command queue to append +** the PIPESELECT command at or gcvNULL just to query the size of the +** PIPESELECT command. +** +** gctUINT32 Pipe +** Pipe value to select. +** +** gctSIZE_T * Bytes +** Pointer to the number of bytes available for the PIPESELECT command. +** If 'Logical' is gcvNULL, this argument will be ignored. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that will receive the number of bytes required +** for the PIPESELECT command. If 'Bytes' is gcvNULL, nothing will be +** returned. +*/ +gceSTATUS +gckHARDWARE_PipeSelect( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT32 Pipe, + IN OUT gctSIZE_T * Bytes + ) +{ + gctUINT32_PTR logical = (gctUINT32_PTR) Logical; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Pipe=%u *Bytes=%lu", + Hardware, Logical, Pipe, gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); + + /* Append a PipeSelect. */ + if (Logical != gcvNULL) + { + gctUINT32 flush, stall; + + if (*Bytes < 32) + { + /* Command queue too small. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + + flush = (Pipe == 0x1) + ? ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) (0x1&((gctUINT32)((((1?1:1)-(0?1:1)+1)==32)?~0:(~(~0<<((1?1:1)-(0?1:1)+1)))))))<<(0?1:1))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x1&((gctUINT32)((((1?0:0)-(0?0:0)+1)==32)?~0:(~(~0<<((1?0:0)-(0?0:0)+1)))))))<<(0?0:0))) + : ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) | (((gctUINT32) (0x1&((gctUINT32)((((1?3:3)-(0?3:3)+1)==32)?~0:(~(~0<<((1?3:3)-(0?3:3)+1)))))))<<(0?3:3))); + + stall = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); + + /* LoadState(AQFlush, 1), flush. */ + logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + + logical[1] = flush; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%x: FLUSH %x", logical, flush); + + /* LoadState(AQSempahore, 1), stall. */ + logical[2] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + + logical[3] = stall; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%x: SEMAPHORE %x", logical + 2, stall); + + /* Stall, stall. */ + logical[4] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); + + logical[5] = stall; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%x: STALL %x", logical + 4, stall); + + /* LoadState(AQPipeSelect, 1), pipe. */ + logical[6] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E00) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + + logical[7] = Pipe; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%x: PIPE %u", logical + 6, Pipe); + } + + if (Bytes != gcvNULL) + { + /* Return number of bytes required by the PIPESELECT command. */ + *Bytes = 32; + } + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_Link +** +** Append a LINK command at the specified location in the command queue. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Pointer to the current location inside the command queue to append +** the LINK command at or gcvNULL just to query the size of the LINK +** command. +** +** gctPOINTER FetchAddress +** Logical address of destination of LINK. +** +** gctSIZE_T FetchSize +** Number of bytes in destination of LINK. +** +** gctSIZE_T * Bytes +** Pointer to the number of bytes available for the LINK command. If +** 'Logical' is gcvNULL, this argument will be ignored. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that will receive the number of bytes required +** for the LINK command. If 'Bytes' is gcvNULL, nothing will be returned. +*/ +gceSTATUS +gckHARDWARE_Link( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctPOINTER FetchAddress, + IN gctSIZE_T FetchSize, + IN OUT gctSIZE_T * Bytes + ) +{ + gceSTATUS status; + gctSIZE_T bytes; + gctUINT32 address; + gctUINT32_PTR logical = (gctUINT32_PTR) Logical; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x FetchAddress=0x%x FetchSize=%lu " + "*Bytes=%lu", + Hardware, Logical, FetchAddress, FetchSize, + gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); + + if (Logical != gcvNULL) + { + if (*Bytes < 8) + { + /* Command queue too small. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + + /* Convert logical address to hardware address. */ + gcmkONERROR( + gckHARDWARE_ConvertLogical(Hardware, FetchAddress, &address)); + + logical[1] = address; + + /* Make sure the address got written before the LINK command. */ + gcmkONERROR( + gckOS_MemoryBarrier(Hardware->os, logical + 1)); + + /* Compute number of 64-byte aligned bytes to fetch. */ + bytes = gcmALIGN(address + FetchSize, 64) - address; + + /* Append LINK(bytes / 8), FetchAddress. */ + logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (bytes>>3) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + +#if gcdDEBUG + { + gctUINT32 phys; + gckHARDWARE_ConvertLogical(Hardware, Logical, &phys); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%08x: LINK %08x, #%lu", phys, address, bytes); + } +#endif + + /* Memory barrier. */ + gcmkONERROR( + gckOS_MemoryBarrier(Hardware->os, logical)); + } + + if (Bytes != gcvNULL) + { + /* Return number of bytes required by the LINK command. */ + *Bytes = 8; + } + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_AlignToTile +** +** Align the specified width and height to tile boundaries. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gceSURF_TYPE Type +** Type of alignment. +** +** gctUINT32 * Width +** Pointer to the width to be aligned. If 'Width' is gcvNULL, no width +** will be aligned. +** +** gctUINT32 * Height +** Pointer to the height to be aligned. If 'Height' is gcvNULL, no height +** will be aligned. +** +** OUTPUT: +** +** gctUINT32 * Width +** Pointer to a variable that will receive the aligned width. +** +** gctUINT32 * Height +** Pointer to a variable that will receive the aligned height. +** +** gctBOOL_PTR SuperTiled +** Pointer to a variable that receives the super-tiling flag for the +** surface. +*/ +gceSTATUS +gckHARDWARE_AlignToTile( + IN gckHARDWARE Hardware, + IN gceSURF_TYPE Type, + IN OUT gctUINT32_PTR Width, + IN OUT gctUINT32_PTR Height, + OUT gctBOOL_PTR SuperTiled + ) +{ + gctBOOL superTiled = gcvFALSE; + gctUINT32 xAlignment, yAlignment; + + gcmkHEADER_ARG("Hardware=0x%x Type=%d *Width=%u *Height=%u", + Hardware, Type, gcmOPT_VALUE(Width), gcmOPT_VALUE(Height)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Super tiling can be enabled for render targets and depth buffers. */ + superTiled = + ( (Type == gcvSURF_RENDER_TARGET) + || (Type == gcvSURF_DEPTH) + ) + && + /* Of course, hardware needs to support super tiles. */ + ((((gctUINT32) (Hardware->chipMinorFeatures0)) >> (0 ? 12:12) & ((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))); + + /* Compute alignment factors. */ + xAlignment = superTiled ? 64 + : (Type == gcvSURF_TEXTURE) ? 4 + : 16; + yAlignment = superTiled ? 64 : 4; + + if (Width != gcvNULL) + { + /* Align the width. */ + *Width = gcmALIGN(*Width, xAlignment); + } + + if (Height != gcvNULL) + { + /* Align the height. */ + *Height = gcmALIGN(*Height, yAlignment); + } + + if (SuperTiled != gcvNULL) + { + /* Copy the super tiling. */ + *SuperTiled = superTiled; + } + + /* Success. */ + gcmkFOOTER_ARG("*Width=%u *Height=%u *SuperTiled=%d", + gcmOPT_VALUE(Width), gcmOPT_VALUE(Height), + gcmOPT_VALUE(SuperTiled)); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHARDWARE_UpdateQueueTail +** +** Update the tail of the command queue. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Logical address of the start of the command queue. +** +** gctUINT32 Offset +** Offset into the command queue of the tail (last command). +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_UpdateQueueTail( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT32 Offset + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Offset=%08x", + Hardware, Logical, Offset); + + /* Verify the hardware. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Force a barrier. */ + gcmkONERROR( + gckOS_MemoryBarrier(Hardware->os, Logical)); + + /* Notify gckKERNEL object of change. */ + gcmkONERROR( + gckKERNEL_Notify(Hardware->kernel, + gcvNOTIFY_COMMAND_QUEUE, + gcvFALSE)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_ConvertLogical +** +** Convert a logical system address into a hardware specific address. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Logical address to convert. +** +** gctUINT32* Address +** Return hardware specific address. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_ConvertLogical( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + OUT gctUINT32 * Address + ) +{ + gctUINT32 address; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x", Hardware, Logical); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + gcmkVERIFY_ARGUMENT(Address != gcvNULL); + + /* Convert logical address into a physical address. */ + gcmkONERROR( + gckOS_GetPhysicalAddress(Hardware->os, Logical, &address)); + + /* Return hardware specific address. */ + *Address = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ? 30:0))) | (((gctUINT32) ((gctUINT32) (address) & ((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ? 30:0))); + + /* Success. */ + gcmkFOOTER_ARG("*Address=%08x", *Address); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_ConvertPhysical +** +** Convert a physical address into a hardware specific address. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPHYS_ADDR Physical +** Physical address to convert. +** +** gctUINT32* Address +** Return hardware specific address. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_ConvertPhysical( + IN gckHARDWARE Hardware, + IN gctPHYS_ADDR Physical, + OUT gctUINT32 * Address + ) +{ + gctUINT32 address; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(Physical != gcvNULL); + gcmkVERIFY_ARGUMENT(Address != gcvNULL); + + address = (gctUINT32)Physical; + + /* Return hardware specific address. */ + *Address = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ? 30:0))) | (((gctUINT32) ((gctUINT32) (address) & ((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ? 30:0))); + + /* Return the status. */ + gcmkFOOTER_ARG("*Address=%08x", *Address); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHARDWARE_Interrupt +** +** Process an interrupt. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctBOOL InterruptValid +** If gcvTRUE, this function will read the interrupt acknowledge +** register, stores the data, and return whether or not the interrupt +** is ours or not. If gcvFALSE, this functions will read the interrupt +** acknowledge register and combine it with any stored value to handle +** the event notifications. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_Interrupt( + IN gckHARDWARE Hardware, + IN gctBOOL InterruptValid + ) +{ + gckEVENT event; + gctUINT32 data; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x InterruptValid=%d", Hardware, InterruptValid); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Extract gckEVENT object. */ + event = Hardware->kernel->event; + gcmkVERIFY_OBJECT(event, gcvOBJ_EVENT); + + if (InterruptValid) + { + /* Read AQIntrAcknowledge register. */ + gcmkONERROR( + gckOS_ReadRegister(Hardware->os, + 0x00010, + &data)); + +#if gcdDEBUG + if (data & 0x80000000) + { + gcmkONERROR(gckOS_Broadcast(Hardware->os, + Hardware, + gcvBROADCAST_AXI_BUS_ERROR)); + } +#endif + + if (data == 0) + { + /* Not our interrupt. */ + status = gcvSTATUS_NOT_OUR_INTERRUPT; + } + else + { + /* Inform gckEVENT of the interrupt. */ + status = gckEVENT_Interrupt(event, data & 0x7FFFFFFF); + } + } + else + { + /* Handle events. */ + status = gckEVENT_Notify(event, 0); + } + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_QueryCommandBuffer +** +** Query the command buffer alignment and number of reserved bytes. +** +** INPUT: +** +** gckHARDWARE Harwdare +** Pointer to an gckHARDWARE object. +** +** OUTPUT: +** +** gctSIZE_T * Alignment +** Pointer to a variable receiving the alignment for each command. +** +** gctSIZE_T * ReservedHead +** Pointer to a variable receiving the number of reserved bytes at the +** head of each command buffer. +** +** gctSIZE_T * ReservedTail +** Pointer to a variable receiving the number of bytes reserved at the +** tail of each command buffer. +*/ +gceSTATUS +gckHARDWARE_QueryCommandBuffer( + IN gckHARDWARE Hardware, + OUT gctSIZE_T * Alignment, + OUT gctSIZE_T * ReservedHead, + OUT gctSIZE_T * ReservedTail + ) +{ + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + if (Alignment != gcvNULL) + { + /* Align every 8 bytes. */ + *Alignment = 8; + } + + if (ReservedHead != gcvNULL) + { + /* Reserve space for SelectPipe(). */ + *ReservedHead = 32; + } + + if (ReservedTail != gcvNULL) + { + /* Reserve space for Link(). */ + *ReservedTail = 8; + } + + /* Success. */ + gcmkFOOTER_ARG("*Alignment=%lu *ReservedHead=%lu *ReservedTail=%lu", + gcmOPT_VALUE(Alignment), gcmOPT_VALUE(ReservedHead), + gcmOPT_VALUE(ReservedTail)); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHARDWARE_QuerySystemMemory +** +** Query the command buffer alignment and number of reserved bytes. +** +** INPUT: +** +** gckHARDWARE Harwdare +** Pointer to an gckHARDWARE object. +** +** OUTPUT: +** +** gctSIZE_T * SystemSize +** Pointer to a variable that receives the maximum size of the system +** memory. +** +** gctUINT32 * SystemBaseAddress +** Poinetr to a variable that receives the base address for system +** memory. +*/ +gceSTATUS +gckHARDWARE_QuerySystemMemory( + IN gckHARDWARE Hardware, + OUT gctSIZE_T * SystemSize, + OUT gctUINT32 * SystemBaseAddress + ) +{ + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + if (SystemSize != gcvNULL) + { + /* Maximum system memory can be 2GB. */ + *SystemSize = 1U << 31; + } + + if (SystemBaseAddress != gcvNULL) + { + /* Set system memory base address. */ + *SystemBaseAddress = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))); + } + + /* Success. */ + gcmkFOOTER_ARG("*SystemSize=%lu *SystemBaseAddress=%lu", + gcmOPT_VALUE(SystemSize), gcmOPT_VALUE(SystemBaseAddress)); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHARDWARE_SetMMU +** +** Set the page table base address. +** +** INPUT: +** +** gckHARDWARE Harwdare +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Logical address of the page table. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_SetMMU( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical + ) +{ + gceSTATUS status; + gctUINT32 address = 0; + gctUINT32 baseAddress; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x", Hardware, Logical); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + + /* Convert the logical address into an hardware address. */ + gcmkONERROR( + gckHARDWARE_ConvertLogical(Hardware, Logical, &address)); + + /* Also get the base address - we need a real physical address. */ + gcmkONERROR( + gckOS_GetBaseAddress(Hardware->os, &baseAddress)); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Setting page table to 0x%08X", + address + baseAddress); + + /* Write the AQMemoryFePageTable register. */ + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, + 0x00400, + address + baseAddress)); + + /* Write the AQMemoryRaPageTable register. */ + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, + 0x00410, + address + baseAddress)); + + /* Write the AQMemoryTxPageTable register. */ + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, + 0x00404, + address + baseAddress)); + + /* Write the AQMemoryPePageTable register. */ + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, + 0x00408, + address + baseAddress)); + + /* Write the AQMemoryPezPageTable register. */ + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, + 0x0040C, + address + baseAddress)); + + /* Return the status. */ + gcmkFOOTER_NO(); + return status; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_FlushMMU +** +** Flush the page table. +** +** INPUT: +** +** gckHARDWARE Harwdare +** Pointer to an gckHARDWARE object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_FlushMMU( + IN gckHARDWARE Hardware + ) +{ + gceSTATUS status; + gctUINT32 flush; + gctUINT32_PTR buffer; + gctSIZE_T bufferSize; + + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Flush the memory controller. */ + flush = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x1&((gctUINT32)((((1?0:0)-(0?0:0)+1)==32)?~0:(~(~0<<((1?0:0)-(0?0:0)+1)))))))<<(0?0:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) (0x1&((gctUINT32)((((1?1:1)-(0?1:1)+1)==32)?~0:(~(~0<<((1?1:1)-(0?1:1)+1)))))))<<(0?1:1))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) | (((gctUINT32) (0x1&((gctUINT32)((((1?2:2)-(0?2:2)+1)==32)?~0:(~(~0<<((1?2:2)-(0?2:2)+1)))))))<<(0?2:2))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) | (((gctUINT32) (0x1&((gctUINT32)((((1?3:3)-(0?3:3)+1)==32)?~0:(~(~0<<((1?3:3)-(0?3:3)+1)))))))<<(0?3:3))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) | (((gctUINT32) (0x1&((gctUINT32)((((1?4:4)-(0?4:4)+1)==32)?~0:(~(~0<<((1?4:4)-(0?4:4)+1)))))))<<(0?4:4))); + + gcmkONERROR( + gckCOMMAND_Reserve(Hardware->kernel->command, + 8, + (gctPOINTER *) &buffer, + &bufferSize)); + + buffer[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E04) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + + buffer[1] = flush; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%x: FLUSH MMU", buffer); + + gcmkONERROR( + gckCOMMAND_Execute(Hardware->kernel->command, 8)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_BuildVirtualAddress +** +** Build a virtual address. +** +** INPUT: +** +** gckHARDWARE Harwdare +** Pointer to an gckHARDWARE object. +** +** gctUINT32 Index +** Index into page table. +** +** gctUINT32 Offset +** Offset into page. +** +** OUTPUT: +** +** gctUINT32 * Address +** Pointer to a variable receiving te hardware address. +*/ +gceSTATUS +gckHARDWARE_BuildVirtualAddress( + IN gckHARDWARE Hardware, + IN gctUINT32 Index, + IN gctUINT32 Offset, + OUT gctUINT32 * Address + ) +{ + gcmkHEADER_ARG("Hardware=0x%x Index=%u Offset=%u", Hardware, Index, Offset); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(Address != gcvNULL); + + /* Build virtual address. */ + *Address = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ? 30:0))) | (((gctUINT32) ((gctUINT32) (Offset|(Index<<12)) & ((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ? 30:0))); + + /* Success. */ + gcmkFOOTER_ARG("*Address=%08x", *Address); + return gcvSTATUS_OK; +} + +gceSTATUS +gckHARDWARE_GetIdle( + IN gckHARDWARE Hardware, + IN gctBOOL Wait, + OUT gctUINT32 * Data + ) +{ + gceSTATUS status; + gctUINT32 idle = 0; + gctINT retry, poll, pollCount; + + gcmkHEADER_ARG("Hardware=0x%x Wait=%d", Hardware, Wait); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(Data != gcvNULL); + + + /* If we have to wait, try 100 polls per millisecond. */ + pollCount = Wait ? 100 : 1; + + /* At most, try for 1 second. */ + for (retry = 0; retry < 1000; ++retry) + { + /* If we have to wait, try 100 polls per millisecond. */ + for (poll = pollCount; poll > 0; --poll) + { + /* Read register. */ + gcmkONERROR( + gckOS_ReadRegister(Hardware->os, 0x00004, &idle)); + + /* See if we have to wait for FE idle. */ + if (( ((((gctUINT32) (idle)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) )) + { + /* FE is idle. */ + break; + } + } + + /* Check if we need to wait for FE and FE is busy. */ + if (Wait && !( ((((gctUINT32) (idle)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) )) + { + /* Wait a little. */ + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "%s: Waiting for idle: 0x%08X", + __FUNCTION__, idle); + + gcmkVERIFY_OK(gckOS_Delay(Hardware->os, 1)); + } + else + { + break; + } + } + + /* Return idle to caller. */ + *Data = idle; + + /* Success. */ + gcmkFOOTER_ARG("*Data=%08x", *Data); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/* Flush the caches. */ +gceSTATUS +gckHARDWARE_Flush( + IN gckHARDWARE Hardware, + IN gceKERNEL_FLUSH Flush, + IN gctPOINTER Logical, + IN OUT gctSIZE_T * Bytes + ) +{ + gctUINT32 pipe; + gctUINT32 flush = 0; + gctUINT32_PTR logical = (gctUINT32_PTR) Logical; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Flush=%x Logical=0x%x *Bytes=%lu", + Hardware, Flush, Logical, gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Get current pipe. */ + pipe = Hardware->kernel->command->pipeSelect; + + /* Flush 3D color cache. */ + if ((Flush & gcvFLUSH_COLOR) && (pipe == 0x0)) + { + flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) (0x1&((gctUINT32)((((1?1:1)-(0?1:1)+1)==32)?~0:(~(~0<<((1?1:1)-(0?1:1)+1)))))))<<(0?1:1))); + } + + /* Flush 3D depth cache. */ + if ((Flush & gcvFLUSH_DEPTH) && (pipe == 0x0)) + { + flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x1&((gctUINT32)((((1?0:0)-(0?0:0)+1)==32)?~0:(~(~0<<((1?0:0)-(0?0:0)+1)))))))<<(0?0:0))); + } + + /* Flush 3D texture cache. */ + if ((Flush & gcvFLUSH_TEXTURE) && (pipe == 0x0)) + { + flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) | (((gctUINT32) (0x1&((gctUINT32)((((1?2:2)-(0?2:2)+1)==32)?~0:(~(~0<<((1?2:2)-(0?2:2)+1)))))))<<(0?2:2))); + } + + /* Flush 2D cache. */ + if ((Flush & gcvFLUSH_2D) && (pipe == 0x1)) + { + flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) | (((gctUINT32) (0x1&((gctUINT32)((((1?3:3)-(0?3:3)+1)==32)?~0:(~(~0<<((1?3:3)-(0?3:3)+1)))))))<<(0?3:3))); + } + + /* See if there is a valid flush. */ + if (flush == 0) + { + if (Bytes != gcvNULL) + { + /* No bytes required. */ + *Bytes = 0; + } + } + + else + { + /* Copy to command queue. */ + if (Logical != gcvNULL) + { + if (*Bytes < 8) + { + /* Command queue too small. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + + /* Append LOAD_STATE to AQFlush. */ + logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + + logical[1] = flush; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%x: FLUSH %x", logical, flush); + } + + if (Bytes != gcvNULL) + { + /* 8 bytes required. */ + *Bytes = 8; + } + } + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckHARDWARE_SetFastClear( + IN gckHARDWARE Hardware, + IN gctINT Enable, + IN gctINT Compression + ) +{ + gctUINT32 debug; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Enable=%d Compression=%d", + Hardware, Enable, Compression); + + /* Only process if fast clear is available. */ + if (( ((((gctUINT32) (Hardware->chipFeatures)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) )) + { + if (Enable == -1) + { + /* Determine automatic value for fast clear. */ + Enable = (Hardware->chipModel != gcv500) + | (Hardware->chipRevision >= 3); + } + + if (Compression == -1) + { + /* Determine automatic value for compression. */ + Compression = Enable + & ( ((((gctUINT32) (Hardware->chipFeatures)) >> (0 ? 5:5)) & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1)))))) ); + } + + /* Read AQMemoryDebug register. */ + gcmkONERROR( + gckOS_ReadRegister(Hardware->os, 0x00414, &debug)); + + /* Set fast clear bypass. */ + debug = ((((gctUINT32) (debug)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 20:20) - (0 ? 20:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 20:20) - (0 ? 20:20) + 1))))))) << (0 ? 20:20))) | (((gctUINT32) ((gctUINT32) (Enable==0) & ((gctUINT32) ((((1 ? 20:20) - (0 ? 20:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 20:20) - (0 ? 20:20) + 1))))))) << (0 ? 20:20))); + + /* Set copression bypass. */ + debug = ((((gctUINT32) (debug)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1))))))) << (0 ? 21:21))) | (((gctUINT32) ((gctUINT32) (Compression==0) & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1))))))) << (0 ? 21:21))); + + /* Write back AQMemoryDebug register. */ + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, + 0x00414, + debug)); + + /* Store fast clear and comprersison flags. */ + Hardware->allowFastClear = Enable; + Hardware->allowCompression = Compression; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "FastClear=%d Compression=%d", Enable, Compression); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +typedef enum +{ + gcvPOWER_FLAG_INITIALIZE = 1 << 0, + gcvPOWER_FLAG_STALL = 1 << 1, + gcvPOWER_FLAG_STOP = 1 << 2, + gcvPOWER_FLAG_START = 1 << 3, + gcvPOWER_FLAG_RELEASE = 1 << 4, + gcvPOWER_FLAG_DELAY = 1 << 5, + gcvPOWER_FLAG_SAVE = 1 << 6, + gcvPOWER_FLAG_ACQUIRE = 1 << 7, + gcvPOWER_FLAG_OFF = 1 << 8, + gcvPOWER_FLAG_CLOCK_OFF = 1 << 9, +} +gcePOWER_FLAGS; + +/******************************************************************************* +** +** gckHARDWARE_SetPowerManagementState +** +** Set GPU to a specified power state. +** +** INPUT: +** +** gckHARDWARE Harwdare +** Pointer to an gckHARDWARE object. +** +** gceCHIPPOWERSTATE State +** Power State. +** +*/ +gceSTATUS +gckHARDWARE_SetPowerManagementState( + IN gckHARDWARE Hardware, + IN gceCHIPPOWERSTATE State + ) +{ +#if 0 +#if !gcdNO_POWER_MANAGEMENT + gceSTATUS status; + gckCOMMAND command = gcvNULL; + gckOS os; + gctUINT flag, clock; + gctPOINTER buffer; + gctSIZE_T bytes, requested; + gctBOOL acquired = gcvFALSE; + gctBOOL reserved = gcvFALSE; + gctBOOL mutexAcquired = gcvFALSE; + gctBOOL stall = gcvTRUE; + gctBOOL broadcast = gcvFALSE; + gctUINT32 process, thread; + + /* State transition flags. */ + static const gctUINT flags[4][4] = + { + /* gcvPOWER_ON */ + { /* ON */ 0, + /* OFF */ gcvPOWER_FLAG_ACQUIRE | + gcvPOWER_FLAG_STALL | + gcvPOWER_FLAG_STOP | + gcvPOWER_FLAG_OFF | + gcvPOWER_FLAG_CLOCK_OFF, + /* IDLE */ gcvPOWER_FLAG_ACQUIRE | + gcvPOWER_FLAG_STALL, + /* SUSPEND */ gcvPOWER_FLAG_ACQUIRE | + gcvPOWER_FLAG_STALL | + gcvPOWER_FLAG_STOP | + gcvPOWER_FLAG_CLOCK_OFF, + }, + + /* gcvPOWER_OFF */ + { /* ON */ gcvPOWER_FLAG_INITIALIZE | + gcvPOWER_FLAG_START | + gcvPOWER_FLAG_RELEASE | + gcvPOWER_FLAG_DELAY, + /* OFF */ 0, + /* IDLE */ gcvPOWER_FLAG_INITIALIZE | + gcvPOWER_FLAG_START | + gcvPOWER_FLAG_DELAY, + /* SUSPEND */ gcvPOWER_FLAG_INITIALIZE | + gcvPOWER_FLAG_CLOCK_OFF, + }, + + /* gcvPOWER_IDLE */ + { /* ON */ gcvPOWER_FLAG_RELEASE, + /* OFF */ gcvPOWER_FLAG_STOP | + gcvPOWER_FLAG_OFF | + gcvPOWER_FLAG_CLOCK_OFF, + /* IDLE */ 0, + /* SUSPEND */ gcvPOWER_FLAG_STOP | + gcvPOWER_FLAG_CLOCK_OFF, + }, + + /* gcvPOWER_SUSPEND */ + { /* ON */ gcvPOWER_FLAG_START | + gcvPOWER_FLAG_RELEASE | + gcvPOWER_FLAG_DELAY, + /* OFF */ gcvPOWER_FLAG_SAVE | + gcvPOWER_FLAG_OFF | + gcvPOWER_FLAG_CLOCK_OFF, + /* IDLE */ gcvPOWER_FLAG_START | + gcvPOWER_FLAG_DELAY, + /* SUSPEND */ 0, + }, + }; + + /* Clocks. */ + static const gctUINT clocks[4] = + { + /* gcvPOWER_ON */ + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))| + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))| + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | (((gctUINT32) ((gctUINT32) (64) & ((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2)))| + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) , + /* gcvPOWER_OFF */ + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))| + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))| + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2)))| + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) , + /* gcvPOWER_IDLE */ + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))| + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))| + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2)))| + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) , + /* gcvPOWER_SUSPEND */ + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))| + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))| + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2)))| + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))), }; + + gcmkHEADER_ARG("Hardware=0x%x State=%d", Hardware, State); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Get the gckOS object pointer. */ + os = Hardware->os; + gcmkVERIFY_OBJECT(os, gcvOBJ_OS); + + /* Convert the broadcast power state. */ + switch (State) + { + case gcvPOWER_SUSPEND_ATPOWERON: + /* Convert to SUSPEND and don't wait for STALL. */ + State = gcvPOWER_SUSPEND; + stall = gcvFALSE; + break; + + case gcvPOWER_OFF_ATPOWERON: + /* Convert to OFF and don't wait for STALL. */ + State = gcvPOWER_OFF; + stall = gcvFALSE; + break; + + case gcvPOWER_IDLE_BROADCAST: + /* Convert to IDLE and note we are inside breoadcast. */ + State = gcvPOWER_IDLE; + broadcast = gcvTRUE; + break; + + case gcvPOWER_SUSPEND_BROADCAST: + /* Convert to SUSPEND and note we are inside breoadcast. */ + State = gcvPOWER_SUSPEND; + broadcast = gcvTRUE; + break; + + case gcvPOWER_OFF_BROADCAST: + /* Convert to OFF and note we are inside breoadcast. */ + State = gcvPOWER_OFF; + broadcast = gcvTRUE; + break; + + case gcvPOWER_OFF_RECOVERY: + /* Convert to OFF and note we are inside breoadcast. */ + State = gcvPOWER_OFF; + stall = gcvFALSE; + broadcast = gcvTRUE; + break; + + default: + break; + } + + /* Get current process and thread IDs. */ + gcmkONERROR(gckOS_GetProcessID(&process)); + gcmkONERROR(gckOS_GetThreadID(&thread)); + + if (broadcast) + { + /* Try to acquire the power mutex. */ + status = gckOS_AcquireMutex(os, Hardware->powerMutex, 0); + + if (status == gcvSTATUS_TIMEOUT) + { + /* Check if we already own this mutex. */ + if ((Hardware->powerProcess == process) + && (Hardware->powerThread == thread) + ) + { + /* Bail out on recursive power management. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + } + else + { + /* Acquire the power mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(os, Hardware->powerMutex, gcvINFINITE)); + } + } + } + else + { + /* Acquire the power mutex. */ + gcmkONERROR(gckOS_AcquireMutex(os, Hardware->powerMutex, gcvINFINITE)); + } + + Hardware->powerProcess = process; + Hardware->powerThread = thread; + mutexAcquired = gcvTRUE; + + /* Grab control flags and clock. */ + flag = flags[Hardware->chipPowerState][State]; + clock = clocks[State]; + + if (flag == 0) + { + /* Release the power mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex)); + + /* No need to do anything. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + } + + gcmkASSERT(Hardware->kernel != gcvNULL); + gcmkASSERT(Hardware->kernel->command != gcvNULL); + command = Hardware->kernel->command; + + if (flag & gcvPOWER_FLAG_INITIALIZE) + { + /* Turn on the power. */ + gcmkONERROR(gckOS_SetGPUPower(Hardware->os, gcvTRUE, gcvTRUE)); + } + + if ((flag & gcvPOWER_FLAG_STALL) && stall) + { + gctBOOL idle; + gctINT32 atomValue; + + /* Check commit atom. */ + gcmkONERROR( + gckOS_AtomGet(Hardware->os, command->atomCommit, &atomValue)); + + if (atomValue > 0) + { + /* Commits are pending - abort power management. */ + status = broadcast ? gcvSTATUS_CHIP_NOT_READY + : gcvSTATUS_MORE_DATA; + goto OnError; + } + + if (broadcast) + { + /* Check for idle. */ + gcmkONERROR(gckHARDWARE_QueryIdle(Hardware, &idle)); + + if (!idle) + { + status = gcvSTATUS_CHIP_NOT_READY; + goto OnError; + } + } + + else + { + /* Get the size of the flush command. */ + gcmkONERROR(gckHARDWARE_Flush(Hardware, + gcvFLUSH_ALL, + gcvNULL, + &requested)); + + /* Reserve space in the command queue. */ + gcmkONERROR( + gckCOMMAND_Reserve(command, requested, &buffer, &bytes)); + + reserved = gcvTRUE; + + /* Append a flush. */ + gcmkONERROR(gckHARDWARE_Flush(Hardware, + gcvFLUSH_ALL, + buffer, + &bytes)); + + /* Execute the command queue. */ + acquired = gcvFALSE; + gcmkONERROR(gckCOMMAND_Execute(command, requested)); + + /* Wait to finish all commands. */ + gcmkONERROR(gckCOMMAND_Stall(command)); + } + } + + if (flag & gcvPOWER_FLAG_ACQUIRE) + { + /* Acquire the power management semaphore. */ + gcmkONERROR(gckOS_AcquireSemaphore(os, command->powerSemaphore)); + + acquired = gcvTRUE; + } + + if (flag & gcvPOWER_FLAG_STOP) + { + /* Stop the command parser. */ + gcmkONERROR(gckCOMMAND_Stop(command)); + } + + /* Write the clock control register. */ + gcmkONERROR(gckOS_WriteRegister(os, + 0x00000, + clock)); + + /* Done loading the frequency scaler. */ + gcmkONERROR(gckOS_WriteRegister(os, + 0x00000, + ((((gctUINT32) (clock)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))))); + + if (flag & gcvPOWER_FLAG_DELAY) + { + /* Wait for the specified amount of time to settle coming back from + ** power-off or suspend state. */ + gcmkONERROR(gckOS_Delay(os, gcdPOWER_CONTROL_DELAY)); + } + + if (flag & gcvPOWER_FLAG_INITIALIZE) + { + /* Initialize hardware. */ + gcmkONERROR( + gckHARDWARE_InitializeHardware(Hardware)); + + gcmkONERROR( + gckHARDWARE_SetFastClear(Hardware, + Hardware->allowFastClear, + Hardware->allowCompression)); + + /* Force the command queue to reload the next context. */ + command->currentContext = 0; + } + + if (flag & (gcvPOWER_FLAG_OFF | gcvPOWER_FLAG_CLOCK_OFF)) + { + /* Turn off the GPU power. */ + gcmkONERROR( + gckOS_SetGPUPower(os, + (flag & gcvPOWER_FLAG_CLOCK_OFF) ? gcvFALSE + : gcvTRUE, + (flag & gcvPOWER_FLAG_OFF) ? gcvFALSE : gcvTRUE)); + } + + if (flag & gcvPOWER_FLAG_START) + { + /* Start the command processor. */ + gcmkONERROR(gckCOMMAND_Start(command)); + } + + if (flag & gcvPOWER_FLAG_RELEASE) + { + /* Release the power management semaphore. */ + gcmkONERROR(gckOS_ReleaseSemaphore(os, command->powerSemaphore)); + } + + /* Save the new power state. */ + Hardware->chipPowerState = State; + + /* Release the power mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + if (reserved) + { + /* Release command queue. */ + gcmkVERIFY_OK(gckCOMMAND_Release(command)); + } + + if (acquired) + { + /* Release semaphore. */ + gcmkVERIFY_OK( + gckOS_ReleaseSemaphore(Hardware->os, command->powerSemaphore)); + } + + if (mutexAcquired) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +#else + /* Do nothing */ + return gcvSTATUS_OK; +#endif +#endif + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHARDWARE_QueryPowerManagementState +** +** Get GPU power state. +** +** INPUT: +** +** gckHARDWARE Harwdare +** Pointer to an gckHARDWARE object. +** +** gceCHIPPOWERSTATE* State +** Power State. +** +*/ +gceSTATUS +gckHARDWARE_QueryPowerManagementState( + IN gckHARDWARE Hardware, + OUT gceCHIPPOWERSTATE* State + ) +{ + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(State != gcvNULL); + + /* Return the statue. */ + *State = Hardware->chipPowerState; + + /* Success. */ + gcmkFOOTER_ARG("*State=%d", *State); + return gcvSTATUS_OK; +} + +gceSTATUS +gckHARDWARE_QueryIdle( + IN gckHARDWARE Hardware, + OUT gctBOOL_PTR IsIdle + ) +{ + gceSTATUS status; + gctUINT32 idle, address; + + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(IsIdle != gcvNULL); + + /* We are idle when the power is not ON. */ + if (Hardware->chipPowerState != gcvPOWER_ON) + { + *IsIdle = gcvTRUE; + } + + else + { + /* Read idle register. */ + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00004, &idle)); + + /* Pipe must be idle. */ + if ((( ((((gctUINT32) (idle)) >> (0 ? 1:1)) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1)))))) )!=1) + || (( ((((gctUINT32) (idle)) >> (0 ? 3:3)) & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1)))))) )!=1) + || (( ((((gctUINT32) (idle)) >> (0 ? 4:4)) & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1)))))) )!=1) + || (( ((((gctUINT32) (idle)) >> (0 ? 5:5)) & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1)))))) )!=1) + || (( ((((gctUINT32) (idle)) >> (0 ? 6:6)) & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1)))))) )!=1) + || (( ((((gctUINT32) (idle)) >> (0 ? 7:7)) & ((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:7) - (0 ? 7:7) + 1)))))) )!=1) + || (( ((((gctUINT32) (idle)) >> (0 ? 2:2)) & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1)))))) )!=1) + ) + { + /* Something is busy. */ + *IsIdle = gcvFALSE; + } + + else + { + /* Read the current FE address. */ + gcmkONERROR(gckOS_ReadRegister(Hardware->os, + 0x00664, + &address)); + + /* Test if address is inside the last WAIT/LINK sequence. */ + if ((address >= Hardware->lastWaitLink) + && (address <= Hardware->lastWaitLink + 16) + ) + { + /* FE is in last WAIT/LINK and the pipe is idle. */ + *IsIdle = gcvTRUE; + } + else + { + /* FE is not in WAIT/LINK yet. */ + *IsIdle = gcvFALSE; + } + } + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** Handy macros that will help in reading those debug registers. +*/ + +#define gcmkREAD_DEBUG_REGISTER(control, block, index, data) \ + gcmkONERROR( \ + gckOS_WriteRegister(Hardware->os, \ + GC_DEBUG_CONTROL##control##_Address, \ + gcmSETFIELD(0, \ + GC_DEBUG_CONTROL##control, \ + block, \ + index))); \ + gcmkONERROR( \ + gckOS_ReadRegister(Hardware->os, \ + GC_DEBUG_SIGNALS_##block##_Address, \ + &profiler->data)) + +#define gcmkRESET_DEBUG_REGISTER(control, block) \ + gcmkONERROR( \ + gckOS_WriteRegister(Hardware->os, \ + GC_DEBUG_CONTROL##control##_Address, \ + gcmSETFIELD(0, \ + GC_DEBUG_CONTROL##control, \ + block, \ + 15))); \ + gcmkONERROR( \ + gckOS_WriteRegister(Hardware->os, \ + GC_DEBUG_CONTROL##control##_Address, \ + gcmSETFIELD(0, \ + GC_DEBUG_CONTROL##control, \ + block, \ + 0))) + +/******************************************************************************* +** +** gckHARDWARE_ProfileEngine2D +** +** Read the profile registers available in the 2D engine and sets them in the +** profile. The function will also reset the pixelsRendered counter every time. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** OPTIONAL gcs2D_PROFILE_PTR Profile +** Pointer to a gcs2D_Profile structure. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_ProfileEngine2D( + IN gckHARDWARE Hardware, + OPTIONAL gcs2D_PROFILE_PTR Profile + ) +{ + gceSTATUS status; + gcs2D_PROFILE_PTR profiler = Profile; + + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + if (Profile != gcvNULL) + { + /* Read the cycle count. */ + gcmkONERROR( + gckOS_ReadRegister(Hardware->os, + 0x00438, + &Profile->cycleCount)); + + /* Read pixels rendered by 2D engine. */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (11) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00454, &profiler->pixelsRendered)); + + /* Reset counter. */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) +))); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +#if VIVANTE_PROFILER +gceSTATUS +gckHARDWARE_QueryProfileRegisters( + IN gckHARDWARE Hardware, + OUT gcsPROFILER_COUNTERS * Counters + ) +{ + gceSTATUS status; + gcsPROFILER_COUNTERS * profiler = Counters; + + gcmkHEADER_ARG("Hardware=0x%x Counters=0x%x", Hardware, Counters); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Read the counters. */ + gcmkONERROR( + gckOS_ReadRegister(Hardware->os, + 0x00040, + &profiler->gpuTotalRead64BytesPerFrame)); + gcmkONERROR( + gckOS_ReadRegister(Hardware->os, + 0x00044, + &profiler->gpuTotalWrite64BytesPerFrame)); + gcmkONERROR( + gckOS_ReadRegister(Hardware->os, + 0x00438, + &profiler->gpuCyclesCounter)); + + /* Reset counters. */ + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, 0x0003C, 1)); + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, 0x0003C, 0)); + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, 0x00438, 0)); + + /* PE */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00454, &profiler->pe_pixel_count_killed_by_color_pipe)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00454, &profiler->pe_pixel_count_killed_by_depth_pipe)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00454, &profiler->pe_pixel_count_drawn_by_color_pipe)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00454, &profiler->pe_pixel_count_drawn_by_depth_pipe)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) +))); + + /* SH */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (7) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0045C, &profiler->ps_inst_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0045C, &profiler->rendered_pixel_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0045C, &profiler->vs_inst_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (10) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0045C, &profiler->rendered_vertice_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (11) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0045C, &profiler->vtx_branch_inst_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (12) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0045C, &profiler->vtx_texld_inst_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (13) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0045C, &profiler->pxl_branch_inst_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (14) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0045C, &profiler->pxl_texld_inst_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) +))); + + /* PA */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00460, &profiler->pa_input_vtx_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00460, &profiler->pa_input_prim_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00460, &profiler->pa_output_prim_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (6) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00460, &profiler->pa_depth_clipped_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (7) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00460, &profiler->pa_trivial_rejected_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00460, &profiler->pa_culled_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) ))); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) +))); + + /* SE */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00464, &profiler->se_culled_triangle_count)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00464, &profiler->se_culled_lines_count)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) ))); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) +))); + + /* RA */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00448, &profiler->ra_valid_pixel_count)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00448, &profiler->ra_total_quad_count)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00448, &profiler->ra_valid_quad_count_after_early_z)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00448, &profiler->ra_total_primitive_count)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00448, &profiler->ra_pipe_cache_miss_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (10) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00448, &profiler->ra_prefetch_cache_miss_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) +))); + + /* TX */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0044C, &profiler->tx_total_bilinear_requests)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0044C, &profiler->tx_total_trilinear_requests)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0044C, &profiler->tx_total_discarded_texture_requests)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0044C, &profiler->tx_total_texture_requests)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0044C, &profiler->tx_mem_read_count)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (6) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0044C, &profiler->tx_mem_read_in_8B_count)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (7) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0044C, &profiler->tx_cache_miss_count)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0044C, &profiler->tx_cache_hit_texel_count)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0044C, &profiler->tx_cache_miss_texel_count)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) +))); + + /* MC */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00478, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00468, &profiler->mc_total_read_req_8B_from_pipeline)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00478, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00468, &profiler->mc_total_read_req_8B_from_IP)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00478, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00468, &profiler->mc_total_write_req_8B_from_pipeline)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00478, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) ))); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00478, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) +))); + + /* HI */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00478, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0046C, &profiler->hi_axi_cycles_read_request_stalled)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00478, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0046C, &profiler->hi_axi_cycles_write_request_stalled)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00478, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0046C, &profiler->hi_axi_cycles_write_data_stalled)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00478, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) ))); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00478, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) +))); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} +#endif + +gceSTATUS +gckHARDWARE_Reset( + IN gckHARDWARE Hardware + ) +{ + gceSTATUS status; + gctUINT32 control, idle; + gckCOMMAND command; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkASSERT(Hardware->kernel != gcvNULL); + command = Hardware->kernel->command; + gcmkASSERT(command != gcvNULL); + + if (Hardware->chipRevision < 0x4600) + { + /* Not supported - we need the isolation bit. */ + gcmkONERROR(gcvSTATUS_NOT_SUPPORTED); + } + + if (Hardware->chipPowerState == gcvPOWER_ON) + { + /* Acquire the power management semaphore. */ + gcmkONERROR( + gckOS_AcquireSemaphore(Hardware->os, command->powerSemaphore)); + acquired = gcvTRUE; + } + + if ((Hardware->chipPowerState == gcvPOWER_ON) + || (Hardware->chipPowerState == gcvPOWER_IDLE) + ) + { + /* Stop the command processor. */ + gcmkONERROR( + gckCOMMAND_Stop(command)); + + /* Grab the queue mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(Hardware->os, + command->mutexQueue, + gcvINFINITE)); + } + + /* Read register. */ + gcmkONERROR( + gckOS_ReadRegister(Hardware->os, + 0x00000, + &control)); + + for (;;) + { + /* Isolate the GPU. */ + control = ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))); + + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, + 0x00000, + control)); + + /* Set soft reset. */ + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, + 0x00000, + ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))))); + + /* Wait for reset. */ + gcmkONERROR( + gckOS_Delay(Hardware->os, 1)); + + /* Reset soft reset bit. */ + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, + 0x00000, + ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))))); + + /* Reset GPU isolation. */ + control = ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))); + + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, + 0x00000, + control)); + + /* Read idle register. */ + gcmkONERROR( + gckOS_ReadRegister(Hardware->os, + 0x00004, + &idle)); + + if (( ((((gctUINT32) (idle)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) )==0) + { + continue; + } + + /* Read reset register. */ + gcmkONERROR( + gckOS_ReadRegister(Hardware->os, + 0x00000, + &control)); + + if ((( ((((gctUINT32) (control)) >> (0 ? 16:16)) & ((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1)))))) )==0) + || (( ((((gctUINT32) (control)) >> (0 ? 17:17)) & ((gctUINT32) ((((1 ? 17:17) - (0 ? 17:17) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 17:17) - (0 ? 17:17) + 1)))))) )==0) + ) + { + continue; + } + + /* GPU is idle. */ + break; + } + + /* Force an OFF to ON power switch. */ + Hardware->chipPowerState = gcvPOWER_OFF; + gcmkONERROR( + gckHARDWARE_SetPowerManagementState(Hardware, gcvPOWER_ON)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the power management semaphore. */ + gcmkVERIFY_OK( + gckOS_ReleaseSemaphore(Hardware->os, command->powerSemaphore)); + } + + /* Return the error. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckHARDWARE_GetBaseAddress( + IN gckHARDWARE Hardware, + OUT gctUINT32_PTR BaseAddress + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(BaseAddress != gcvNULL); + + /* Test if we have a new Memory Controller. */ + if (((((gctUINT32) (Hardware->chipMinorFeatures0)) >> (0 ? 22:22) & ((gctUINT32) ((((1 ? 22:22) - (0 ? 22:22) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 22:22) - (0 ? 22:22) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 22:22) - (0 ? 22:22) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 22:22) - (0 ? 22:22) + 1)))))))) + { + /* No base address required. */ + *BaseAddress = 0; + } + else + { + /* Get the base address from the OS. */ + gcmkONERROR(gckOS_GetBaseAddress(Hardware->os, BaseAddress)); + } + + /* Success. */ + gcmkFOOTER_ARG("*BaseAddress=0x%08x", *BaseAddress); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckHARDWARE_NeedBaseAddress( + IN gckHARDWARE Hardware, + IN gctUINT32 State, + OUT gctBOOL_PTR NeedBase + ) +{ + gctBOOL need = gcvFALSE; + + gcmkHEADER_ARG("Hardware=0x%x State=0x%08x", Hardware, State); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(NeedBase != gcvNULL); + + /* Make sure this is a load state. */ + if (((((gctUINT32) (State)) >> (0 ? 31:27) & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1)))))) == (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27)+1)))))))) + { + /* Get the state address. */ + switch (( ((((gctUINT32) (State)) >> (0 ? 15:0)) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0)+1)))))))) + { + case 0x0596: + case 0x0597: + case 0x0599: + case 0x059A: + case 0x05A9: + /* These states need a TRUE physical address. */ + need = gcvTRUE; + break; + } + } + + /* Return the flag. */ + *NeedBase = need; + + /* Success. */ + gcmkFOOTER_ARG("*NeedBase=%d", *NeedBase); + return gcvSTATUS_OK; +} + diff --git a/drivers/staging/rk29/vivante/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.h b/drivers/staging/rk29/vivante/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.h new file mode 100644 index 000000000000..70e659f5b07d --- /dev/null +++ b/drivers/staging/rk29/vivante/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.h @@ -0,0 +1,90 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_kernel_hardware_h_ +#define __gc_hal_kernel_hardware_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* gckHARDWARE object. */ +struct _gckHARDWARE +{ + /* Object. */ + gcsOBJECT object; + + /* Pointer to gctKERNEL object. */ + gckKERNEL kernel; + + /* Pointer to gctOS object. */ + gckOS os; + + /* Chip characteristics. */ + gceCHIPMODEL chipModel; + gctUINT32 chipRevision; + gctUINT32 chipFeatures; + gctUINT32 chipMinorFeatures0; + gctUINT32 chipMinorFeatures1; + gctBOOL allowFastClear; + gctBOOL allowCompression; + gctUINT32 powerBaseAddress; + gctBOOL extraEventStates; + + gctUINT32 streamCount; + gctUINT32 registerMax; + gctUINT32 threadCount; + gctUINT32 shaderCoreCount; + gctUINT32 vertexCacheSize; + gctUINT32 vertexOutputBufferSize; + + /* Big endian */ + gctBOOL bigEndian; + + /* Chip status */ + gctPOINTER powerMutex; + gctUINT32 powerProcess; + gctUINT32 powerThread; + gceCHIPPOWERSTATE chipPowerState; + gctUINT32 lastWaitLink; +}; + +gceSTATUS +gckHARDWARE_GetBaseAddress( + IN gckHARDWARE Hardware, + OUT gctUINT32_PTR BaseAddress + ); + +gceSTATUS +gckHARDWARE_NeedBaseAddress( + IN gckHARDWARE Hardware, + IN gctUINT32 State, + OUT gctBOOL_PTR NeedBase + ); + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_kernel_hardware_h_ */ + diff --git a/drivers/staging/rk29/vivante/arch/XAQ2/hal/kernel/makefile.linux b/drivers/staging/rk29/vivante/arch/XAQ2/hal/kernel/makefile.linux new file mode 100644 index 000000000000..ca9f433c7297 --- /dev/null +++ b/drivers/staging/rk29/vivante/arch/XAQ2/hal/kernel/makefile.linux @@ -0,0 +1,55 @@ +############################################################################## +# +# Copyright (C) 2005 - 2010 by Vivante Corp. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the license, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +############################################################################## + + + +# +# Linux build file for architecture dependent kernel HAL layer. +# +# + + +################################################################################ +# Include common definitions. + +include $(AQROOT)/makefile.linux.def + +################################################################################ +# Define a shortcut for the main target. + +STATIC = 1 +TARGET_NAME = libhalarchkernel.a + +################################################################################ +# Supply additional include directories. + +INCLUDE += -I$(AQROOT)/hal/inc +INCLUDE += -I$(AQROOT)/hal/kernel +INCLUDE += -I$(AQARCH)/hal/kernel +INCLUDE += -I$(AQARCH)/cmodel/inc + +CFLAGS += $(INCLUDE) -Werror -ansi + +################################################################################ +# Describe object files. + +OBJECTS = $(OBJ_DIR)/gc_hal_kernel_hardware.o + +include $(AQROOT)/common.target diff --git a/drivers/staging/rk29/vivante/config b/drivers/staging/rk29/vivante/config new file mode 100644 index 000000000000..779ac82311b4 --- /dev/null +++ b/drivers/staging/rk29/vivante/config @@ -0,0 +1,24 @@ +############################################################################## +# +# Copyright (C) 2005 - 2010 by Vivante Corp. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the license, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +############################################################################## + + +ARCH_TYPE ?= arm +SDK_DIR ?= $(AQROOT)/build/sdk +USE_3D_VG = 1 diff --git a/drivers/staging/rk29/vivante/hal/inc/gc_hal.h b/drivers/staging/rk29/vivante/hal/inc/gc_hal.h new file mode 100644 index 000000000000..01e7d36aeeea --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/inc/gc_hal.h @@ -0,0 +1,1859 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_h_ +#define __gc_hal_h_ + +#include "gc_hal_types.h" +#include "gc_hal_enum.h" +#include "gc_hal_base.h" +#include "gc_hal_profiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************\ +******************************* Alignment Macros ******************************* +\******************************************************************************/ + +#define gcmALIGN(n, align) \ +( \ + ((n) + ((align) - 1)) & ~((align) - 1) \ +) + +/******************************************************************************\ +***************************** Element Count Macro ***************************** +\******************************************************************************/ + +#define gcmSIZEOF(a) \ +( \ + (gctSIZE_T) (sizeof(a)) \ +) + +#define gcmCOUNTOF(a) \ +( \ + sizeof(a) / sizeof(a[0]) \ +) + +/******************************************************************************\ +******************************** gcsOBJECT Object ******************************* +\******************************************************************************/ + +/* Type of objects. */ +typedef enum _gceOBJECT_TYPE +{ + gcvOBJ_UNKNOWN = 0, + gcvOBJ_2D = gcmCC('2','D',' ',' '), + gcvOBJ_3D = gcmCC('3','D',' ',' '), + gcvOBJ_ATTRIBUTE = gcmCC('A','T','T','R'), + gcvOBJ_BRUSHCACHE = gcmCC('B','R','U','$'), + gcvOBJ_BRUSHNODE = gcmCC('B','R','U','n'), + gcvOBJ_BRUSH = gcmCC('B','R','U','o'), + gcvOBJ_BUFFER = gcmCC('B','U','F','R'), + gcvOBJ_COMMAND = gcmCC('C','M','D',' '), + gcvOBJ_COMMANDBUFFER = gcmCC('C','M','D','B'), + gcvOBJ_CONTEXT = gcmCC('C','T','X','T'), + gcvOBJ_DEVICE = gcmCC('D','E','V',' '), + gcvOBJ_DUMP = gcmCC('D','U','M','P'), + gcvOBJ_EVENT = gcmCC('E','V','N','T'), + gcvOBJ_FUNCTION = gcmCC('F','U','N','C'), + gcvOBJ_HAL = gcmCC('H','A','L',' '), + gcvOBJ_HARDWARE = gcmCC('H','A','R','D'), + gcvOBJ_HEAP = gcmCC('H','E','A','P'), + gcvOBJ_INDEX = gcmCC('I','N','D','X'), + gcvOBJ_INTERRUPT = gcmCC('I','N','T','R'), + gcvOBJ_KERNEL = gcmCC('K','E','R','N'), + gcvOBJ_MEMORYBUFFER = gcmCC('M','E','M','B'), + gcvOBJ_MMU = gcmCC('M','M','U',' '), + gcvOBJ_OS = gcmCC('O','S',' ',' '), + gcvOBJ_OUTPUT = gcmCC('O','U','T','P'), + gcvOBJ_PAINT = gcmCC('P','N','T',' '), + gcvOBJ_PATH = gcmCC('P','A','T','H'), + gcvOBJ_QUEUE = gcmCC('Q','U','E',' '), + gcvOBJ_SAMPLER = gcmCC('S','A','M','P'), + gcvOBJ_SHADER = gcmCC('S','H','D','R'), + gcvOBJ_STREAM = gcmCC('S','T','R','M'), + gcvOBJ_SURF = gcmCC('S','U','R','F'), + gcvOBJ_TEXTURE = gcmCC('T','X','T','R'), + gcvOBJ_UNIFORM = gcmCC('U','N','I','F'), + gcvOBJ_VARIABLE = gcmCC('V','A','R','I'), + gcvOBJ_VERTEX = gcmCC('V','R','T','X'), + gcvOBJ_VIDMEM = gcmCC('V','M','E','M'), + gcvOBJ_VG = gcmCC('V','G',' ',' '), +} +gceOBJECT_TYPE; + +/* gcsOBJECT object defintinon. */ +typedef struct _gcsOBJECT +{ + /* Type of an object. */ + gceOBJECT_TYPE type; +} +gcsOBJECT; + +/* Kernel settings. */ +typedef struct _gcsKERNEL_SETTINGS +{ + /* Used RealTime signal between kernel and user. */ + gctINT signal; +} +gcsKERNEL_SETTINGS; + +typedef struct _gckHARDWARE * gckHARDWARE; + +/******************************************************************************* +** +** gcmVERIFY_OBJECT +** +** Assert if an object is invalid or is not of the specified type. If the +** object is invalid or not of the specified type, gcvSTATUS_INVALID_OBJECT +** will be returned from the current function. In retail mode this macro +** does nothing. +** +** ARGUMENTS: +** +** obj Object to test. +** t Expected type of the object. +*/ +#ifndef EGL_API_ANDROID +# define _gcmVERIFY_OBJECT(prefix, obj, t) \ + do \ + { \ + if ((obj) == gcvNULL) \ + { \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "VERIFY_OBJECT failed: NULL"); \ + prefix##TRACE(gcvLEVEL_ERROR, " expected: %c%c%c%c", \ + gcmCC_PRINT(t)); \ + prefix##ASSERT((obj) != gcvNULL); \ + prefix##FOOTER_ARG("status=%d", gcvSTATUS_INVALID_OBJECT); \ + return gcvSTATUS_INVALID_OBJECT; \ + } \ + else if (((gcsOBJECT*) (obj))->type != t) \ + { \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "VERIFY_OBJECT failed: %c%c%c%c", \ + gcmCC_PRINT(((gcsOBJECT*) (obj))->type)); \ + prefix##TRACE(gcvLEVEL_ERROR, " expected: %c%c%c%c", \ + gcmCC_PRINT(t)); \ + prefix##ASSERT(((gcsOBJECT*)(obj))->type == t); \ + prefix##FOOTER_ARG("status=%d", gcvSTATUS_INVALID_OBJECT); \ + return gcvSTATUS_INVALID_OBJECT; \ + } \ + } \ + while (gcvFALSE) +# define gcmVERIFY_OBJECT(obj, t) _gcmVERIFY_OBJECT(gcm, obj, t) +# define gcmkVERIFY_OBJECT(obj, t) _gcmVERIFY_OBJECT(gcmk, obj, t) +#else +# define gcmVERIFY_OBJECT(obj, t) do {} while (gcvFALSE) +# define gcmkVERIFY_OBJECT(obj, t) do {} while (gcvFALSE) +#endif + +/******************************************************************************\ +********************************** gckOS Object ********************************* +\******************************************************************************/ + +typedef struct _gckOS * gckOS; + +/* Construct a new gckOS object. */ +gceSTATUS +gckOS_Construct( + IN gctPOINTER Context, + OUT gckOS * Os + ); + +/* Destroy an gckOS object. */ +gceSTATUS +gckOS_Destroy( + IN gckOS Os + ); + +/* Query the video memory. */ +gceSTATUS +gckOS_QueryVideoMemory( + IN gckOS Os, + OUT gctPHYS_ADDR * InternalAddress, + OUT gctSIZE_T * InternalSize, + OUT gctPHYS_ADDR * ExternalAddress, + OUT gctSIZE_T * ExternalSize, + OUT gctPHYS_ADDR * ContiguousAddress, + OUT gctSIZE_T * ContiguousSize + ); + +/* Allocate memory from the heap. */ +gceSTATUS +gckOS_Allocate( + IN gckOS Os, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ); + +/* Free allocated memory. */ +gceSTATUS +gckOS_Free( + IN gckOS Os, + IN gctPOINTER Memory + ); + +/* Wrapper for allocation memory.. */ +gceSTATUS +gckOS_AllocateMemory( + IN gckOS Os, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ); + +/* Wrapper for freeing memory. */ +gceSTATUS +gckOS_FreeMemory( + IN gckOS Os, + IN gctPOINTER Memory + ); + +/* Allocate paged memory. */ +gceSTATUS +gckOS_AllocatePagedMemory( + IN gckOS Os, + IN gctSIZE_T Bytes, + OUT gctPHYS_ADDR * Physical + ); + +/* Allocate paged memory. */ +gceSTATUS +gckOS_AllocatePagedMemoryEx( + IN gckOS Os, + IN gctBOOL Contiguous, + IN gctSIZE_T Bytes, + OUT gctPHYS_ADDR * Physical + ); + +/* Lock pages. */ +gceSTATUS +gckOS_LockPages( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, +#ifdef __QNXNTO__ + IN gctUINT32 Pid, +#endif + OUT gctPOINTER * Logical, + OUT gctSIZE_T * PageCount + ); + +/* Map pages. */ +gceSTATUS +gckOS_MapPages( + IN gckOS Os, + IN gctPHYS_ADDR Physical, +#ifdef __QNXNTO__ + IN gctPOINTER Logical, +#endif + IN gctSIZE_T PageCount, + IN gctPOINTER PageTable + ); + +/* Unlock pages. */ +gceSTATUS +gckOS_UnlockPages( + IN gckOS Os, + IN gctPHYS_ADDR Physical, +#ifdef __QNXNTO__ + IN gctUINT32 Pid, +#endif + IN gctSIZE_T Bytes, + IN gctPOINTER Logical + ); + +/* Free paged memory. */ +gceSTATUS +gckOS_FreePagedMemory( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes + ); + +/* Allocate non-paged memory. */ +gceSTATUS +gckOS_AllocateNonPagedMemory( + IN gckOS Os, + IN gctBOOL InUserSpace, + IN OUT gctSIZE_T * Bytes, + OUT gctPHYS_ADDR * Physical, + OUT gctPOINTER * Logical + ); + +/* Free non-paged memory. */ +gceSTATUS +gckOS_FreeNonPagedMemory( + IN gckOS Os, + IN gctSIZE_T Bytes, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical + ); + +/* Allocate contiguous memory. */ +gceSTATUS +gckOS_AllocateContiguous( + IN gckOS Os, + IN gctBOOL InUserSpace, + IN OUT gctSIZE_T * Bytes, + OUT gctPHYS_ADDR * Physical, + OUT gctPOINTER * Logical + ); + +/* Free contiguous memory. */ +gceSTATUS +gckOS_FreeContiguous( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ); + +/* Get the number fo bytes per page. */ +gceSTATUS +gckOS_GetPageSize( + IN gckOS Os, + OUT gctSIZE_T * PageSize + ); + +/* Get the physical address of a corresponding logical address. */ +gceSTATUS +gckOS_GetPhysicalAddress( + IN gckOS Os, + IN gctPOINTER Logical, + OUT gctUINT32 * Address + ); + +/* Map physical memory. */ +gceSTATUS +gckOS_MapPhysical( + IN gckOS Os, + IN gctUINT32 Physical, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Logical + ); + +/* Unmap previously mapped physical memory. */ +gceSTATUS +gckOS_UnmapPhysical( + IN gckOS Os, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ); + +/* Read data from a hardware register. */ +gceSTATUS +gckOS_ReadRegister( + IN gckOS Os, + IN gctUINT32 Address, + OUT gctUINT32 * Data + ); + +/* Write data to a hardware register. */ +gceSTATUS +gckOS_WriteRegister( + IN gckOS Os, + IN gctUINT32 Address, + IN gctUINT32 Data + ); + +/* Write data to a 32-bit memory location. */ +gceSTATUS +gckOS_WriteMemory( + IN gckOS Os, + IN gctPOINTER Address, + IN gctUINT32 Data + ); + +/* Map physical memory into the process space. */ +gceSTATUS +gckOS_MapMemory( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Logical + ); + +/* Unmap physical memory from the process space. */ +gceSTATUS +gckOS_UnmapMemory( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + IN gctPOINTER Logical + ); + +/* Create a new mutex. */ +gceSTATUS +gckOS_CreateMutex( + IN gckOS Os, + OUT gctPOINTER * Mutex + ); + +/* Delete a mutex. */ +gceSTATUS +gckOS_DeleteMutex( + IN gckOS Os, + IN gctPOINTER Mutex + ); + +/* Acquire a mutex. */ +gceSTATUS +gckOS_AcquireMutex( + IN gckOS Os, + IN gctPOINTER Mutex, + IN gctUINT32 Timeout + ); + +/* Release a mutex. */ +gceSTATUS +gckOS_ReleaseMutex( + IN gckOS Os, + IN gctPOINTER Mutex + ); + +/* Atomically exchange a pair of 32-bit values. */ +gceSTATUS +gckOS_AtomicExchange( + IN gckOS Os, + IN OUT gctUINT32_PTR Target, + IN gctUINT32 NewValue, + OUT gctUINT32_PTR OldValue + ); + +/* Atomically exchange a pair of pointers. */ +gceSTATUS +gckOS_AtomicExchangePtr( + IN gckOS Os, + IN OUT gctPOINTER * Target, + IN gctPOINTER NewValue, + OUT gctPOINTER * OldValue + ); + +/******************************************************************************* +** +** gckOS_AtomConstruct +** +** Create an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** OUTPUT: +** +** gctPOINTER * Atom +** Pointer to a variable receiving the constructed atom. +*/ +gceSTATUS +gckOS_AtomConstruct( + IN gckOS Os, + OUT gctPOINTER * Atom + ); + +/******************************************************************************* +** +** gckOS_AtomDestroy +** +** Destroy an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom to destroy. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_AtomDestroy( + IN gckOS Os, + OUT gctPOINTER Atom + ); + +/******************************************************************************* +** +** gckOS_AtomGet +** +** Get the 32-bit value protected by an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom. +** +** OUTPUT: +** +** gctINT32_PTR Value +** Pointer to a variable the receives the value of the atom. +*/ +gceSTATUS +gckOS_AtomGet( + IN gckOS Os, + IN gctPOINTER Atom, + OUT gctINT32_PTR Value + ); + +/******************************************************************************* +** +** gckOS_AtomIncrement +** +** Atomically increment the 32-bit integer value inside an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom. +** +** OUTPUT: +** +** gctINT32_PTR Value +** Pointer to a variable the receives the original value of the atom. +*/ +gceSTATUS +gckOS_AtomIncrement( + IN gckOS Os, + IN gctPOINTER Atom, + OUT gctINT32_PTR Value + ); + +/******************************************************************************* +** +** gckOS_AtomDecrement +** +** Atomically decrement the 32-bit integer value inside an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom. +** +** OUTPUT: +** +** gctINT32_PTR Value +** Pointer to a variable the receives the original value of the atom. +*/ +gceSTATUS +gckOS_AtomDecrement( + IN gckOS Os, + IN gctPOINTER Atom, + OUT gctINT32_PTR Value + ); + +/* Delay a number of microseconds. */ +gceSTATUS +gckOS_Delay( + IN gckOS Os, + IN gctUINT32 Delay + ); + +/* Memory barrier. */ +gceSTATUS +gckOS_MemoryBarrier( + IN gckOS Os, + IN gctPOINTER Address + ); + +/* Map user pointer. */ +gceSTATUS +gckOS_MapUserPointer( + IN gckOS Os, + IN gctPOINTER Pointer, + IN gctSIZE_T Size, + OUT gctPOINTER * KernelPointer + ); + +/* Unmap user pointer. */ +gceSTATUS +gckOS_UnmapUserPointer( + IN gckOS Os, + IN gctPOINTER Pointer, + IN gctSIZE_T Size, + IN gctPOINTER KernelPointer + ); + +#ifdef __QNXNTO__ +/* Map user physical address. */ +gceSTATUS +gckOS_MapUserPhysical( + IN gckOS Os, + IN gctPHYS_ADDR Phys, + OUT gctPOINTER * KernelPointer + ); + +/* Allocate from user's shared pool. */ +gceSTATUS +gckOS_AllocateNonPagedMemoryShmPool( + IN gckOS Os, + IN gctBOOL InUserSpace, + IN gctUINT32 Pid, + IN gctHANDLE Handle, + IN OUT gctSIZE_T * Bytes, + OUT gctPHYS_ADDR * Physical, + OUT gctPOINTER * Logical + ); +#endif + +gceSTATUS +gckOS_SuspendInterrupt( + IN gckOS Os + ); + +gceSTATUS +gckOS_ResumeInterrupt( + IN gckOS Os + ); + +/* Get the base address for the physical memory. */ +gceSTATUS +gckOS_GetBaseAddress( + IN gckOS Os, + OUT gctUINT32_PTR BaseAddress + ); + +/* Perform a memory copy. */ +gceSTATUS +gckOS_MemCopy( + IN gctPOINTER Destination, + IN gctCONST_POINTER Source, + IN gctSIZE_T Bytes + ); + +/* Zero memory. */ +gceSTATUS +gckOS_ZeroMemory( + IN gctPOINTER Memory, + IN gctSIZE_T Bytes + ); + +/* Device I/O control to the kernel HAL layer. */ +gceSTATUS +gckOS_DeviceControl( + IN gckOS Os, + IN gctBOOL FromUser, + IN gctUINT32 IoControlCode, + IN gctPOINTER InputBuffer, + IN gctSIZE_T InputBufferSize, + OUT gctPOINTER OutputBuffer, + IN gctSIZE_T OutputBufferSize + ); + +/******************************************************************************* +** +** gckOS_GetProcessID +** +** Get current process ID. +** +** INPUT: +** +** Nothing. +** +** OUTPUT: +** +** gctUINT32_PTR ProcessID +** Pointer to the variable that receives the process ID. +*/ +gceSTATUS +gckOS_GetProcessID( + OUT gctUINT32_PTR ProcessID + ); + +/******************************************************************************* +** +** gckOS_GetThreadID +** +** Get current thread ID. +** +** INPUT: +** +** Nothing. +** +** OUTPUT: +** +** gctUINT32_PTR ThreadID +** Pointer to the variable that receives the thread ID. +*/ +gceSTATUS +gckOS_GetThreadID( + OUT gctUINT32_PTR ThreadID + ); + +/******************************************************************************\ +********************************** Signal Object ********************************* +\******************************************************************************/ + +/* User signal command codes. */ +typedef enum _gceUSER_SIGNAL_COMMAND_CODES +{ + gcvUSER_SIGNAL_CREATE, + gcvUSER_SIGNAL_DESTROY, + gcvUSER_SIGNAL_SIGNAL, + gcvUSER_SIGNAL_WAIT, +} +gceUSER_SIGNAL_COMMAND_CODES; + +/* Create a signal. */ +gceSTATUS +gckOS_CreateSignal( + IN gckOS Os, + IN gctBOOL ManualReset, + OUT gctSIGNAL * Signal + ); + +/* Destroy a signal. */ +gceSTATUS +gckOS_DestroySignal( + IN gckOS Os, + IN gctSIGNAL Signal + ); + +/* Signal a signal. */ +gceSTATUS +gckOS_Signal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctBOOL State + ); + +/* Wait for a signal. */ +gceSTATUS +gckOS_WaitSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctUINT32 Wait + ); + +/* Map a user signal to the kernel space. */ +gceSTATUS +gckOS_MapSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctHANDLE Process, + OUT gctSIGNAL * MappedSignal + ); + +/* Map user memory. */ +gceSTATUS +gckOS_MapUserMemory( + IN gckOS Os, + IN gctPOINTER Memory, + IN gctSIZE_T Size, + OUT gctPOINTER * Info, + OUT gctUINT32_PTR Address + ); + +/* Unmap user memory. */ +gceSTATUS +gckOS_UnmapUserMemory( + IN gckOS Os, + IN gctPOINTER Memory, + IN gctSIZE_T Size, + IN gctPOINTER Info, + IN gctUINT32 Address + ); + +#if !USE_NEW_LINUX_SIGNAL +/* Create signal to be used in the user space. */ +gceSTATUS +gckOS_CreateUserSignal( + IN gckOS Os, + IN gctBOOL ManualReset, + OUT gctINT * SignalID + ); + +/* Destroy signal used in the user space. */ +gceSTATUS +gckOS_DestroyUserSignal( + IN gckOS Os, + IN gctINT SignalID + ); + +/* Wait for signal used in the user space. */ +gceSTATUS +gckOS_WaitUserSignal( + IN gckOS Os, + IN gctINT SignalID, + IN gctUINT32 Wait + ); + +/* Signal a signal used in the user space. */ +gceSTATUS +gckOS_SignalUserSignal( + IN gckOS Os, + IN gctINT SignalID, + IN gctBOOL State + ); +#endif /* USE_NEW_LINUX_SIGNAL */ + +/* Set a signal owned by a process. */ +#if defined(__QNXNTO__) +gceSTATUS +gckOS_UserSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctINT Recvid, + IN gctINT Coid + ); +#else +gceSTATUS +gckOS_UserSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctHANDLE Process + ); +#endif + +/******************************************************************************\ +** Cache Support +*/ + +gceSTATUS +gckOS_CacheFlush( + gckOS Os, + gctHANDLE ProcessId, + gctPOINTER Logical, + gctSIZE_T Bytes + ); + +gceSTATUS +gckOS_CacheInvalidate( + gckOS Os, + gctHANDLE ProcessId, + gctPOINTER Logical, + gctSIZE_T Bytes + ); + +/******************************************************************************\ +** Debug Support +*/ + +void +gckOS_SetDebugLevel( + IN gctUINT32 Level + ); + +void +gckOS_SetDebugZone( + IN gctUINT32 Zone + ); + +void +gckOS_SetDebugLevelZone( + IN gctUINT32 Level, + IN gctUINT32 Zone + ); + +void +gckOS_SetDebugZones( + IN gctUINT32 Zones, + IN gctBOOL Enable + ); + +void +gckOS_SetDebugFile( + IN gctCONST_STRING FileName + ); + +/******************************************************************************* +** Broadcast interface. +*/ + +typedef enum _gceBROADCAST +{ + /* GPU might be idle. */ + gcvBROADCAST_GPU_IDLE, + + /* A commit is going to happen. */ + gcvBROADCAST_GPU_COMMIT, + + /* GPU seems to be stuck. */ + gcvBROADCAST_GPU_STUCK, + + /* First process gets attached. */ + gcvBROADCAST_FIRST_PROCESS, + + /* Last process gets detached. */ + gcvBROADCAST_LAST_PROCESS, + + /* AXI bus error. */ + gcvBROADCAST_AXI_BUS_ERROR, +} +gceBROADCAST; + +gceSTATUS +gckOS_Broadcast( + IN gckOS Os, + IN gckHARDWARE Hardware, + IN gceBROADCAST Reason + ); + +/******************************************************************************* +** +** gckOS_SetGPUPower +** +** Set the power of the GPU on or off. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object.ß +** +** gctBOOL Clock +** gcvTRUE to turn on the clock, or gcvFALSE to turn off the clock. +** +** gctBOOL Power +** gcvTRUE to turn on the power, or gcvFALSE to turn off the power. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_SetGPUPower( + IN gckOS Os, + IN gctBOOL Clock, + IN gctBOOL Power + ); + +/******************************************************************************* +** Semaphores. +*/ + +/* Create a new semaphore. */ +gceSTATUS +gckOS_CreateSemaphore( + IN gckOS Os, + OUT gctPOINTER * Semaphore + ); + +/* Delete a semahore. */ +gceSTATUS +gckOS_DestroySemaphore( + IN gckOS Os, + IN gctPOINTER Semaphore + ); + +/* Acquire a semahore. */ +gceSTATUS +gckOS_AcquireSemaphore( + IN gckOS Os, + IN gctPOINTER Semaphore + ); + +/* Release a semahore. */ +gceSTATUS +gckOS_ReleaseSemaphore( + IN gckOS Os, + IN gctPOINTER Semaphore + ); + +/******************************************************************************\ +********************************* gckHEAP Object ******************************** +\******************************************************************************/ + +typedef struct _gckHEAP * gckHEAP; + +/* Construct a new gckHEAP object. */ +gceSTATUS +gckHEAP_Construct( + IN gckOS Os, + IN gctSIZE_T AllocationSize, + OUT gckHEAP * Heap + ); + +/* Destroy an gckHEAP object. */ +gceSTATUS +gckHEAP_Destroy( + IN gckHEAP Heap + ); + +/* Allocate memory. */ +gceSTATUS +gckHEAP_Allocate( + IN gckHEAP Heap, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Node + ); + +/* Free memory. */ +gceSTATUS +gckHEAP_Free( + IN gckHEAP Heap, + IN gctPOINTER Node + ); + +/* Profile the heap. */ +gceSTATUS +gckHEAP_ProfileStart( + IN gckHEAP Heap + ); + +gceSTATUS +gckHEAP_ProfileEnd( + IN gckHEAP Heap, + IN gctCONST_STRING Title + ); + +#if defined gcdHAL_TEST +gceSTATUS +gckHEAP_Test( + IN gckHEAP Heap, + IN gctSIZE_T Vectors, + IN gctSIZE_T MaxSize + ); +#endif + +/******************************************************************************\ +******************************** gckVIDMEM Object ****************************** +\******************************************************************************/ + +typedef struct _gckVIDMEM * gckVIDMEM; +typedef union _gcuVIDMEM_NODE * gcuVIDMEM_NODE_PTR; +typedef struct _gckKERNEL * gckKERNEL; + +/* Construct a new gckVIDMEM object. */ +gceSTATUS +gckVIDMEM_Construct( + IN gckOS Os, + IN gctUINT32 BaseAddress, + IN gctSIZE_T Bytes, + IN gctSIZE_T Threshold, + IN gctSIZE_T Banking, + OUT gckVIDMEM * Memory + ); + +/* Destroy an gckVDIMEM object. */ +gceSTATUS +gckVIDMEM_Destroy( + IN gckVIDMEM Memory + ); + +/* Allocate rectangular memory. */ +gceSTATUS +gckVIDMEM_Allocate( + IN gckVIDMEM Memory, + IN gctUINT Width, + IN gctUINT Height, + IN gctUINT Depth, + IN gctUINT BytesPerPixel, + IN gctUINT32 Alignment, + IN gceSURF_TYPE Type, +#ifdef __QNXNTO__ + IN gctHANDLE Handle, +#endif + OUT gcuVIDMEM_NODE_PTR * Node + ); + +/* Allocate linear memory. */ +gceSTATUS +gckVIDMEM_AllocateLinear( + IN gckVIDMEM Memory, + IN gctSIZE_T Bytes, + IN gctUINT32 Alignment, + IN gceSURF_TYPE Type, +#ifdef __QNXNTO__ + IN gctHANDLE Handle, +#endif + OUT gcuVIDMEM_NODE_PTR * Node + ); + +/* Free memory. */ +gceSTATUS +gckVIDMEM_Free( + IN gcuVIDMEM_NODE_PTR Node + ); + +/* Lock memory. */ +gceSTATUS +gckVIDMEM_Lock( + IN gcuVIDMEM_NODE_PTR Node, + OUT gctUINT32 * Address + ); + +/* Unlock memory. */ +gceSTATUS +gckVIDMEM_Unlock( + IN gcuVIDMEM_NODE_PTR Node, + IN gceSURF_TYPE Type, + IN OUT gctBOOL * Asynchroneous + ); + +/* Construct a gcuVIDMEM_NODE union for virtual memory. */ +gceSTATUS +gckVIDMEM_ConstructVirtual( + IN gckKERNEL Kernel, + IN gctBOOL Contiguous, + IN gctSIZE_T Bytes, +#ifdef __QNXNTO__ + IN gctHANDLE Handle, +#endif + OUT gcuVIDMEM_NODE_PTR * Node + ); + +/* Destroy a gcuVIDMEM_NODE union for virtual memory. */ +gceSTATUS +gckVIDMEM_DestroyVirtual( + IN gcuVIDMEM_NODE_PTR Node + ); + +#ifdef __QNXNTO__ +/* Set the allocating process' PID for this node. */ +gceSTATUS +gckVIDMEM_SetPID( + IN gcuVIDMEM_NODE_PTR Node, + IN gctUINT32 Pid); +#endif + +/******************************************************************************\ +******************************** gckKERNEL Object ****************************** +\******************************************************************************/ + +struct _gcsHAL_INTERFACE; + +/* Notifications. */ +typedef enum _gceNOTIFY +{ + gcvNOTIFY_INTERRUPT, + gcvNOTIFY_COMMAND_QUEUE, +} +gceNOTIFY; + +/* Event locations. */ +typedef enum _gceKERNEL_WHERE +{ + gcvKERNEL_COMMAND, + gcvKERNEL_VERTEX, + gcvKERNEL_TRIANGLE, + gcvKERNEL_TEXTURE, + gcvKERNEL_PIXEL, +} +gceKERNEL_WHERE; + +/* Flush flags. */ +typedef enum _gceKERNEL_FLUSH +{ + gcvFLUSH_COLOR = 0x01, + gcvFLUSH_DEPTH = 0x02, + gcvFLUSH_TEXTURE = 0x04, + gcvFLUSH_2D = 0x08, + gcvFLUSH_ALL = gcvFLUSH_COLOR + | gcvFLUSH_DEPTH + | gcvFLUSH_TEXTURE + | gcvFLUSH_2D, +} +gceKERNEL_FLUSH; + +/* Construct a new gckKERNEL object. */ +gceSTATUS +gckKERNEL_Construct( + IN gckOS Os, + IN gctPOINTER Context, + OUT gckKERNEL * Kernel + ); + +/* Destroy an gckKERNEL object. */ +gceSTATUS +gckKERNEL_Destroy( + IN gckKERNEL Kernel + ); + +/* Dispatch a user-level command. */ +gceSTATUS +gckKERNEL_Dispatch( + IN gckKERNEL Kernel, + IN gctBOOL FromUser, + IN OUT struct _gcsHAL_INTERFACE * Interface + ); + +/* Query the video memory. */ +gceSTATUS +gckKERNEL_QueryVideoMemory( + IN gckKERNEL Kernel, + OUT struct _gcsHAL_INTERFACE * Interface + ); + +/* Lookup the gckVIDMEM object for a pool. */ +gceSTATUS +gckKERNEL_GetVideoMemoryPool( + IN gckKERNEL Kernel, + IN gcePOOL Pool, + OUT gckVIDMEM * VideoMemory + ); + +/* Map video memory. */ +gceSTATUS +gckKERNEL_MapVideoMemory( + IN gckKERNEL Kernel, + IN gctBOOL InUserSpace, + IN gctUINT32 Address, +#ifdef __QNXNTO__ + IN gctUINT32 Pid, + IN gctUINT32 Bytes, +#endif + OUT gctPOINTER * Logical + ); + +#ifdef __QNXNTO__ +/* Unmap video memory. */ +gceSTATUS +gckKERNEL_UnmapVideoMemory( + IN gckKERNEL Kernel, + IN gctPOINTER Logical, + IN gctUINT32 Pid, + IN gctUINT32 Bytes + ); +#endif + +/* Map memory. */ +gceSTATUS +gckKERNEL_MapMemory( + IN gckKERNEL Kernel, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Logical + ); + +/* Unmap memory. */ +gceSTATUS +gckKERNEL_UnmapMemory( + IN gckKERNEL Kernel, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + IN gctPOINTER Logical + ); + +/* Notification of events. */ +gceSTATUS +gckKERNEL_Notify( + IN gckKERNEL Kernel, + IN gceNOTIFY Notifcation, + IN gctBOOL Data + ); + +gceSTATUS +gckKERNEL_QuerySettings( + IN gckKERNEL Kernel, + OUT gcsKERNEL_SETTINGS * Settings + ); + +/******************************************************************************* +** +** gckKERNEL_Recovery +** +** Try to recover the GPU from a fatal error. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckKERNEL_Recovery( + IN gckKERNEL Kernel + ); + +/******************************************************************************\ +******************************* gckHARDWARE Object ***************************** +\******************************************************************************/ + +/* Construct a new gckHARDWARE object. */ +gceSTATUS +gckHARDWARE_Construct( + IN gckOS Os, + OUT gckHARDWARE * Hardware + ); + +/* Destroy an gckHARDWARE object. */ +gceSTATUS +gckHARDWARE_Destroy( + IN gckHARDWARE Hardware + ); + +/* Query system memory requirements. */ +gceSTATUS +gckHARDWARE_QuerySystemMemory( + IN gckHARDWARE Hardware, + OUT gctSIZE_T * SystemSize, + OUT gctUINT32 * SystemBaseAddress + ); + +/* Build virtual address. */ +gceSTATUS +gckHARDWARE_BuildVirtualAddress( + IN gckHARDWARE Hardware, + IN gctUINT32 Index, + IN gctUINT32 Offset, + OUT gctUINT32 * Address + ); + +/* Query command buffer requirements. */ +gceSTATUS +gckHARDWARE_QueryCommandBuffer( + IN gckHARDWARE Hardware, + OUT gctSIZE_T * Alignment, + OUT gctSIZE_T * ReservedHead, + OUT gctSIZE_T * ReservedTail + ); + +/* Add a WAIT/LINK pair in the command queue. */ +gceSTATUS +gckHARDWARE_WaitLink( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT32 Offset, + IN OUT gctSIZE_T * Bytes, + OUT gctPOINTER * Wait, + OUT gctSIZE_T * WaitBytes + ); + +/* Kickstart the command processor. */ +gceSTATUS +gckHARDWARE_Execute( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, +#ifdef __QNXNTO__ + IN gctPOINTER Physical, + IN gctBOOL PhysicalAddresses, +#endif + IN gctSIZE_T Bytes + ); + +/* Add an END command in the command queue. */ +gceSTATUS +gckHARDWARE_End( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN OUT gctSIZE_T * Bytes + ); + +/* Add a NOP command in the command queue. */ +gceSTATUS +gckHARDWARE_Nop( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN OUT gctSIZE_T * Bytes + ); + +/* Add a WAIT command in the command queue. */ +gceSTATUS +gckHARDWARE_Wait( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT32 Count, + IN OUT gctSIZE_T * Bytes + ); + +/* Add a PIPESELECT command in the command queue. */ +gceSTATUS +gckHARDWARE_PipeSelect( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT32 Pipe, + IN OUT gctSIZE_T * Bytes + ); + +/* Add a LINK command in the command queue. */ +gceSTATUS +gckHARDWARE_Link( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctPOINTER FetchAddress, + IN gctSIZE_T FetchSize, + IN OUT gctSIZE_T * Bytes + ); + +/* Add an EVENT command in the command queue. */ +gceSTATUS +gckHARDWARE_Event( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT8 Event, + IN gceKERNEL_WHERE FromWhere, + IN OUT gctSIZE_T * Bytes + ); + +/* Query the available memory. */ +gceSTATUS +gckHARDWARE_QueryMemory( + IN gckHARDWARE Hardware, + OUT gctSIZE_T * InternalSize, + OUT gctUINT32 * InternalBaseAddress, + OUT gctUINT32 * InternalAlignment, + OUT gctSIZE_T * ExternalSize, + OUT gctUINT32 * ExternalBaseAddress, + OUT gctUINT32 * ExternalAlignment, + OUT gctUINT32 * HorizontalTileSize, + OUT gctUINT32 * VerticalTileSize + ); + +/* Query the identity of the hardware. */ +gceSTATUS +gckHARDWARE_QueryChipIdentity( + IN gckHARDWARE Hardware, + OUT gceCHIPMODEL* ChipModel, + OUT gctUINT32* ChipRevision, + OUT gctUINT32* ChipFeatures, + OUT gctUINT32* ChipMinorFeatures, + OUT gctUINT32* ChipMinorFeatures1 + ); + +/* Query the specifications sof the hardware. */ +gceSTATUS +gckHARDWARE_QueryChipSpecs( + IN gckHARDWARE Hardware, + OUT gctUINT32_PTR StreamCount, + OUT gctUINT32_PTR RegisterMax, + OUT gctUINT32_PTR ThreadCount, + OUT gctUINT32_PTR ShaderCoreCount, + OUT gctUINT32_PTR VertexCacheSize, + OUT gctUINT32_PTR VertexOutputBufferSize + ); + +/* Convert an API format. */ +gceSTATUS +gckHARDWARE_ConvertFormat( + IN gckHARDWARE Hardware, + IN gceSURF_FORMAT Format, + OUT gctUINT32 * BitsPerPixel, + OUT gctUINT32 * BytesPerTile + ); + +/* Split a harwdare specific address into API stuff. */ +gceSTATUS +gckHARDWARE_SplitMemory( + IN gckHARDWARE Hardware, + IN gctUINT32 Address, + OUT gcePOOL * Pool, + OUT gctUINT32 * Offset + ); + +/* Align size to tile boundary. */ +gceSTATUS +gckHARDWARE_AlignToTile( + IN gckHARDWARE Hardware, + IN gceSURF_TYPE Type, + IN OUT gctUINT32_PTR Width, + IN OUT gctUINT32_PTR Height, + OUT gctBOOL_PTR SuperTiled + ); + +/* Update command queue tail pointer. */ +gceSTATUS +gckHARDWARE_UpdateQueueTail( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT32 Offset + ); + +/* Convert logical address to hardware specific address. */ +gceSTATUS +gckHARDWARE_ConvertLogical( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + OUT gctUINT32 * Address + ); + +#ifdef __QNXNTO__ +/* Convert physical address to hardware specific address. */ +gceSTATUS +gckHARDWARE_ConvertPhysical( + IN gckHARDWARE Hardware, + IN gctPHYS_ADDR Physical, + OUT gctUINT32 * Address + ); +#endif + +/* Interrupt manager. */ +gceSTATUS +gckHARDWARE_Interrupt( + IN gckHARDWARE Hardware, + IN gctBOOL InterruptValid + ); + +/* Program MMU. */ +gceSTATUS +gckHARDWARE_SetMMU( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical + ); + +/* Flush the MMU. */ +gceSTATUS +gckHARDWARE_FlushMMU( + IN gckHARDWARE Hardware + ); + +/* Get idle register. */ +gceSTATUS +gckHARDWARE_GetIdle( + IN gckHARDWARE Hardware, + IN gctBOOL Wait, + OUT gctUINT32 * Data + ); + +/* Flush the caches. */ +gceSTATUS +gckHARDWARE_Flush( + IN gckHARDWARE Hardware, + IN gceKERNEL_FLUSH Flush, + IN gctPOINTER Logical, + IN OUT gctSIZE_T * Bytes + ); + +/* Enable/disable fast clear. */ +gceSTATUS +gckHARDWARE_SetFastClear( + IN gckHARDWARE Hardware, + IN gctINT Enable, + IN gctINT Compression + ); + +gceSTATUS +gckHARDWARE_ReadInterrupt( + IN gckHARDWARE Hardware, + OUT gctUINT32_PTR IDs + ); + +/* Power management. */ +gceSTATUS +gckHARDWARE_SetPowerManagementState( + IN gckHARDWARE Hardware, + IN gceCHIPPOWERSTATE State + ); + +gceSTATUS +gckHARDWARE_QueryPowerManagementState( + IN gckHARDWARE Hardware, + OUT gceCHIPPOWERSTATE* State + ); + +/* Profile 2D Engine. */ +gceSTATUS +gckHARDWARE_ProfileEngine2D( + IN gckHARDWARE Hardware, + OUT gcs2D_PROFILE_PTR Profile + ); + +gceSTATUS +gckHARDWARE_InitializeHardware( + IN gckHARDWARE Hardware + ); + +gceSTATUS +gckHARDWARE_Reset( + IN gckHARDWARE Hardware + ); + +/******************************************************************************\ +***************************** gckINTERRUPT Object ****************************** +\******************************************************************************/ + +typedef struct _gckINTERRUPT * gckINTERRUPT; + +typedef gceSTATUS (* gctINTERRUPT_HANDLER)( + IN gckKERNEL Kernel + ); + +gceSTATUS +gckINTERRUPT_Construct( + IN gckKERNEL Kernel, + OUT gckINTERRUPT * Interrupt + ); + +gceSTATUS +gckINTERRUPT_Destroy( + IN gckINTERRUPT Interrupt + ); + +gceSTATUS +gckINTERRUPT_SetHandler( + IN gckINTERRUPT Interrupt, + IN OUT gctINT32_PTR Id, + IN gctINTERRUPT_HANDLER Handler + ); + +gceSTATUS +gckINTERRUPT_Notify( + IN gckINTERRUPT Interrupt, + IN gctBOOL Valid + ); + +/******************************************************************************\ +******************************** gckEVENT Object ******************************* +\******************************************************************************/ + +typedef struct _gckEVENT * gckEVENT; + +/* Construct a new gckEVENT object. */ +gceSTATUS +gckEVENT_Construct( + IN gckKERNEL Kernel, + OUT gckEVENT * Event + ); + +/* Destroy an gckEVENT object. */ +gceSTATUS +gckEVENT_Destroy( + IN gckEVENT Event + ); + +/* Schedule a FreeNonPagedMemory event. */ +gceSTATUS +gckEVENT_FreeNonPagedMemory( + IN gckEVENT Event, + IN gctSIZE_T Bytes, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical, + IN gceKERNEL_WHERE FromWhere + ); + +/* Schedule a FreeContiguousMemory event. */ +gceSTATUS +gckEVENT_FreeContiguousMemory( + IN gckEVENT Event, + IN gctSIZE_T Bytes, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical, + IN gceKERNEL_WHERE FromWhere + ); + +/* Schedule a FreeVideoMemory event. */ +gceSTATUS +gckEVENT_FreeVideoMemory( + IN gckEVENT Event, + IN gcuVIDMEM_NODE_PTR VideoMemory, + IN gceKERNEL_WHERE FromWhere + ); + +/* Schedule a signal event. */ +gceSTATUS +gckEVENT_Signal( + IN gckEVENT Event, + IN gctSIGNAL Signal, + IN gceKERNEL_WHERE FromWhere + ); + +/* Schedule an Unlock event. */ +gceSTATUS +gckEVENT_Unlock( + IN gckEVENT Event, + IN gceKERNEL_WHERE FromWhere, + IN gcuVIDMEM_NODE_PTR Node, + IN gceSURF_TYPE Type + ); + +gceSTATUS +gckEVENT_Submit( + IN gckEVENT Event, + IN gctBOOL Wait + ); + +struct _gcsQUEUE; + +/* Commit an event queue. */ +gceSTATUS +gckEVENT_Commit( + IN gckEVENT Event, + IN struct _gcsQUEUE * Queue + ); + +/* Event callback routine. */ +gceSTATUS +gckEVENT_Notify( + IN gckEVENT Event, + IN gctUINT32 IDs + ); + +/* Event callback routine. */ +gceSTATUS +gckEVENT_Interrupt( + IN gckEVENT Event, + IN gctUINT32 IDs + ); + +/******************************************************************************\ +******************************* gckCOMMAND Object ****************************** +\******************************************************************************/ + +typedef struct _gckCOMMAND * gckCOMMAND; + +/* Construct a new gckCOMMAND object. */ +gceSTATUS +gckCOMMAND_Construct( + IN gckKERNEL Kernel, + OUT gckCOMMAND * Command + ); + +/* Destroy an gckCOMMAND object. */ +gceSTATUS +gckCOMMAND_Destroy( + IN gckCOMMAND Command + ); + +/* Start the command queue. */ +gceSTATUS +gckCOMMAND_Start( + IN gckCOMMAND Command + ); + +/* Stop the command queue. */ +gceSTATUS +gckCOMMAND_Stop( + IN gckCOMMAND Command + ); + +/* Commit a buffer to the command queue. */ +gceSTATUS +gckCOMMAND_Commit( + IN gckCOMMAND Command, + IN gcoCMDBUF CommandBuffer, + IN gcoCONTEXT Context, + IN gctHANDLE Process + ); + +/* Reserve space in the command buffer. */ +gceSTATUS +gckCOMMAND_Reserve( + IN gckCOMMAND Command, + IN gctSIZE_T RequestedBytes, + OUT gctPOINTER * Buffer, + OUT gctSIZE_T * BufferSize + ); + +/* Release reserved space in the command buffer. */ +gceSTATUS +gckCOMMAND_Release( + IN gckCOMMAND Command + ); + +/* Execute reserved space in the command buffer. */ +gceSTATUS +gckCOMMAND_Execute( + IN gckCOMMAND Command, + IN gctSIZE_T RequstedBytes + ); + +/* Stall the command queue. */ +gceSTATUS +gckCOMMAND_Stall( + IN gckCOMMAND Command + ); + +/******************************************************************************\ +********************************* gckMMU Object ******************************** +\******************************************************************************/ + +typedef struct _gckMMU * gckMMU; + +/* Construct a new gckMMU object. */ +gceSTATUS +gckMMU_Construct( + IN gckKERNEL Kernel, + IN gctSIZE_T MmuSize, + OUT gckMMU * Mmu + ); + +/* Destroy an gckMMU object. */ +gceSTATUS +gckMMU_Destroy( + IN gckMMU Mmu + ); + +/* Allocate pages inside the MMU. */ +gceSTATUS +gckMMU_AllocatePages( + IN gckMMU Mmu, + IN gctSIZE_T PageCount, + OUT gctPOINTER * PageTable, + OUT gctUINT32 * Address + ); + +/* Remove a page table from the MMU. */ +gceSTATUS +gckMMU_FreePages( + IN gckMMU Mmu, + IN gctPOINTER PageTable, + IN gctSIZE_T PageCount + ); + +#ifdef __QNXNTO__ +gceSTATUS +gckMMU_InsertNode( + IN gckMMU Mmu, + IN gcuVIDMEM_NODE_PTR Node); + +gceSTATUS +gckMMU_RemoveNode( + IN gckMMU Mmu, + IN gcuVIDMEM_NODE_PTR Node); +#endif + +#ifdef __QNXNTO__ +gceSTATUS +gckMMU_FreeHandleMemory( + IN gckMMU Mmu, + IN gctHANDLE Handle + ); +#endif + +#if defined gcdHAL_TEST +gceSTATUS +gckMMU_Test( + IN gckMMU Mmu, + IN gctSIZE_T Vectors, + IN gctINT MaxSize + ); +#endif + +gceSTATUS +gckHARDWARE_QueryProfileRegisters( + IN gckHARDWARE Hardware, + OUT gcsPROFILER_COUNTERS * Counters + ); + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_h_ */ + diff --git a/drivers/staging/rk29/vivante/hal/inc/gc_hal_base.h b/drivers/staging/rk29/vivante/hal/inc/gc_hal_base.h new file mode 100644 index 000000000000..738d1893dbec --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/inc/gc_hal_base.h @@ -0,0 +1,2485 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_base_h_ +#define __gc_hal_base_h_ + +#include "gc_hal_enum.h" +#include "gc_hal_types.h" +#include "gc_hal_dump.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************\ +****************************** Object Declarations ***************************** +\******************************************************************************/ + +typedef struct _gcoHAL * gcoHAL; +typedef struct _gcoOS * gcoOS; +typedef struct _gco2D * gco2D; +typedef struct _gcoVG * gcoVG; +typedef struct _gco3D * gco3D; +typedef struct _gcoSURF * gcoSURF; +typedef struct _gcsSURF_INFO * gcsSURF_INFO_PTR; +typedef struct _gcsSURF_NODE * gcsSURF_NODE_PTR; +typedef struct _gcsSURF_FORMAT_INFO * gcsSURF_FORMAT_INFO_PTR; +typedef struct _gcsPOINT * gcsPOINT_PTR; +typedef struct _gcsSIZE * gcsSIZE_PTR; +typedef struct _gcsRECT * gcsRECT_PTR; +typedef struct _gcsBOUNDARY * gcsBOUNDARY_PTR; +typedef struct _gcoDUMP * gcoDUMP; +typedef struct _gcoHARDWARE * gcoHARDWARE; + +/******************************************************************************\ +********************************* Enumerations ********************************* +\******************************************************************************/ + +/* Video memory pool type. */ +typedef enum _gcePOOL +{ + gcvPOOL_UNKNOWN, + gcvPOOL_DEFAULT, + gcvPOOL_LOCAL, + gcvPOOL_LOCAL_INTERNAL, + gcvPOOL_LOCAL_EXTERNAL, + gcvPOOL_UNIFIED, + gcvPOOL_SYSTEM, + gcvPOOL_VIRTUAL, + gcvPOOL_USER, + gcvPOOL_CONTIGUOUS +} +gcePOOL; + +/* Blending functions. */ +typedef enum _gceBLEND_FUNCTION +{ + gcvBLEND_ZERO, + gcvBLEND_ONE, + gcvBLEND_SOURCE_COLOR, + gcvBLEND_INV_SOURCE_COLOR, + gcvBLEND_SOURCE_ALPHA, + gcvBLEND_INV_SOURCE_ALPHA, + gcvBLEND_TARGET_COLOR, + gcvBLEND_INV_TARGET_COLOR, + gcvBLEND_TARGET_ALPHA, + gcvBLEND_INV_TARGET_ALPHA, + gcvBLEND_SOURCE_ALPHA_SATURATE, + gcvBLEND_CONST_COLOR, + gcvBLEND_INV_CONST_COLOR, + gcvBLEND_CONST_ALPHA, + gcvBLEND_INV_CONST_ALPHA, +} +gceBLEND_FUNCTION; + +/* Blending modes. */ +typedef enum _gceBLEND_MODE +{ + gcvBLEND_ADD, + gcvBLEND_SUBTRACT, + gcvBLEND_REVERSE_SUBTRACT, + gcvBLEND_MIN, + gcvBLEND_MAX, +} +gceBLEND_MODE; + +/* API flags. */ +typedef enum _gceAPI +{ + gcvAPI_D3D = 0x1, + gcvAPI_OPENGL = 0x2, +} +gceAPI; + +/* Depth modes. */ +typedef enum _gceDEPTH_MODE +{ + gcvDEPTH_NONE, + gcvDEPTH_Z, + gcvDEPTH_W, +} +gceDEPTH_MODE; + +typedef enum _gceWHERE +{ + gcvWHERE_COMMAND, + gcvWHERE_RASTER, + gcvWHERE_PIXEL, +} +gceWHERE; + +typedef enum _gceHOW +{ + gcvHOW_SEMAPHORE = 0x1, + gcvHOW_STALL = 0x2, + gcvHOW_SEMAPHORE_STALL = 0x3, +} +gceHOW; + +/******************************************************************************\ +********************************* gcoHAL Object ********************************* +\******************************************************************************/ + +/* Construct a new gcoHAL object. */ +gceSTATUS +gcoHAL_Construct( + IN gctPOINTER Context, + IN gcoOS Os, + OUT gcoHAL * Hal + ); + +/* Destroy an gcoHAL object. */ +gceSTATUS +gcoHAL_Destroy( + IN gcoHAL Hal + ); + +/* Get pointer to gco2D object. */ +gceSTATUS +gcoHAL_Get2DEngine( + IN gcoHAL Hal, + OUT gco2D * Engine + ); + +/* Get pointer to gcoVG object. */ +gceSTATUS +gcoHAL_GetVGEngine( + IN gcoHAL Hal, + OUT gcoVG * Engine + ); + +/* Get pointer to gco3D object. */ +gceSTATUS +gcoHAL_Get3DEngine( + IN gcoHAL Hal, + OUT gco3D * Engine + ); + +/* Verify whether the specified feature is available in hardware. */ +gceSTATUS +gcoHAL_IsFeatureAvailable( + IN gcoHAL Hal, + IN gceFEATURE Feature + ); + +/* Query the identity of the hardware. */ +gceSTATUS +gcoHAL_QueryChipIdentity( + IN gcoHAL Hal, + OUT gceCHIPMODEL* ChipModel, + OUT gctUINT32* ChipRevision, + OUT gctUINT32* ChipFeatures, + OUT gctUINT32* ChipMinorFeatures + ); + +/* Query the amount of video memory. */ +gceSTATUS +gcoHAL_QueryVideoMemory( + IN gcoHAL Hal, + OUT gctPHYS_ADDR * InternalAddress, + OUT gctSIZE_T * InternalSize, + OUT gctPHYS_ADDR * ExternalAddress, + OUT gctSIZE_T * ExternalSize, + OUT gctPHYS_ADDR * ContiguousAddress, + OUT gctSIZE_T * ContiguousSize + ); + +/* Map video memory. */ +gceSTATUS +gcoHAL_MapMemory( + IN gcoHAL Hal, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T NumberOfBytes, + OUT gctPOINTER * Logical + ); + +/* Unmap video memory. */ +gceSTATUS +gcoHAL_UnmapMemory( + IN gcoHAL Hal, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T NumberOfBytes, + IN gctPOINTER Logical + ); + +/* Schedule an unmap of a buffer mapped through its physical address. */ +gceSTATUS +gcoHAL_ScheduleUnmapMemory( + IN gcoHAL Hal, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T NumberOfBytes, + IN gctPOINTER Logical + ); + +/* Schedule an unmap of a user buffer using event mechanism. */ +gceSTATUS +gcoHAL_ScheduleUnmapUserMemory( + IN gcoHAL Hal, + IN gctPOINTER Info, + IN gctSIZE_T Size, + IN gctUINT32 Address, + IN gctPOINTER Memory + ); + +/* Commit the current command buffer. */ +gceSTATUS +gcoHAL_Commit( + IN gcoHAL Hal, + IN gctBOOL Stall + ); + +/* Query the tile capabilities. */ +gceSTATUS +gcoHAL_QueryTiled( + IN gcoHAL Hal, + OUT gctINT32 * TileWidth2D, + OUT gctINT32 * TileHeight2D, + OUT gctINT32 * TileWidth3D, + OUT gctINT32 * TileHeight3D + ); + +gceSTATUS +gcoHAL_Compact( + IN gcoHAL Hal + ); + +gceSTATUS +gcoHAL_ProfileStart( + IN gcoHAL Hal + ); + +gceSTATUS +gcoHAL_ProfileEnd( + IN gcoHAL Hal, + IN gctCONST_STRING Title + ); + +/* Power Management */ +gceSTATUS +gcoHAL_SetPowerManagementState( + IN gcoHAL Hal, + IN gceCHIPPOWERSTATE State + ); + +gceSTATUS +gcoHAL_QueryPowerManagementState( + IN gcoHAL Hal, + OUT gceCHIPPOWERSTATE *State + ); + +/* Set the filter type for filter blit. */ +gceSTATUS +gcoHAL_SetFilterType( + IN gcoHAL Hal, + IN gceFILTER_TYPE FilterType + ); + +gceSTATUS +gcoHAL_GetDump( + IN gcoHAL Hal, + OUT gcoDUMP * Dump + ); + +/* Call the kernel HAL layer. */ +gceSTATUS +gcoHAL_Call( + IN gcoHAL Hal, + IN OUT gcsHAL_INTERFACE_PTR Interface + ); + +/* Schedule an event. */ +gceSTATUS +gcoHAL_ScheduleEvent( + IN gcoHAL Hal, + IN OUT gcsHAL_INTERFACE_PTR Interface + ); + +/* Destroy a surface. */ +gceSTATUS +gcoHAL_DestroySurface( + IN gcoHAL Hal, + IN gcoSURF Surface + ); + +/******************************************************************************\ +********************************** gcoOS Object ********************************* +\******************************************************************************/ + +/* Construct a new gcoOS object. */ +gceSTATUS +gcoOS_Construct( + IN gctPOINTER Context, + OUT gcoOS * Os + ); + +/* Destroy an gcoOS object. */ +gceSTATUS +gcoOS_Destroy( + IN gcoOS Os + ); + +/* Get the base address for the physical memory. */ +gceSTATUS +gcoOS_GetBaseAddress( + IN gcoOS Os, + OUT gctUINT32_PTR BaseAddress + ); + +/* Allocate memory from the heap. */ +gceSTATUS +gcoOS_Allocate( + IN gcoOS Os, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ); + +/* Free allocated memory. */ +gceSTATUS +gcoOS_Free( + IN gcoOS Os, + IN gctPOINTER Memory + ); + +/* Allocate memory. */ +gceSTATUS +gcoOS_AllocateMemory( + IN gcoOS Os, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ); + +/* Free memory. */ +gceSTATUS +gcoOS_FreeMemory( + IN gcoOS Os, + IN gctPOINTER Memory + ); + +/* Allocate contiguous memory. */ +gceSTATUS +gcoOS_AllocateContiguous( + IN gcoOS Os, + IN gctBOOL InUserSpace, + IN OUT gctSIZE_T * Bytes, + OUT gctPHYS_ADDR * Physical, + OUT gctPOINTER * Logical + ); + +/* Free contiguous memory. */ +gceSTATUS +gcoOS_FreeContiguous( + IN gcoOS Os, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ); + +/* Map user memory. */ +gceSTATUS +gcoOS_MapUserMemory( + IN gcoOS Os, + IN gctPOINTER Memory, + IN gctSIZE_T Size, + OUT gctPOINTER * Info, + OUT gctUINT32_PTR Address + ); + +/* Unmap user memory. */ +gceSTATUS +gcoOS_UnmapUserMemory( + IN gcoOS Os, + IN gctPOINTER Memory, + IN gctSIZE_T Size, + IN gctPOINTER Info, + IN gctUINT32 Address + ); + +/* Device I/O Control call to the kernel HAL layer. */ +gceSTATUS +gcoOS_DeviceControl( + IN gcoOS Os, + IN gctUINT32 IoControlCode, + IN gctPOINTER InputBuffer, + IN gctSIZE_T InputBufferSize, + IN gctPOINTER OutputBuffer, + IN gctSIZE_T OutputBufferSize + ); + +/* Allocate non paged memory. */ +gceSTATUS gcoOS_AllocateNonPagedMemory( + IN gcoOS Os, + IN gctBOOL InUserSpace, + IN OUT gctSIZE_T * Bytes, + OUT gctPHYS_ADDR * Physical, + OUT gctPOINTER * Logical + ); + +/* Free non paged memory. */ +gceSTATUS gcoOS_FreeNonPagedMemory( + IN gcoOS Os, + IN gctSIZE_T Bytes, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical + ); + +typedef enum _gceFILE_MODE +{ + gcvFILE_CREATE = 0, + gcvFILE_APPEND, + gcvFILE_READ, + gcvFILE_CREATETEXT, + gcvFILE_APPENDTEXT, + gcvFILE_READTEXT, +} +gceFILE_MODE; + +/* Open a file. */ +gceSTATUS +gcoOS_Open( + IN gcoOS Os, + IN gctCONST_STRING FileName, + IN gceFILE_MODE Mode, + OUT gctFILE * File + ); + +/* Close a file. */ +gceSTATUS +gcoOS_Close( + IN gcoOS Os, + IN gctFILE File + ); + +/* Read data from a file. */ +gceSTATUS +gcoOS_Read( + IN gcoOS Os, + IN gctFILE File, + IN gctSIZE_T ByteCount, + IN gctPOINTER Data, + OUT gctSIZE_T * ByteRead + ); + +/* Write data to a file. */ +gceSTATUS +gcoOS_Write( + IN gcoOS Os, + IN gctFILE File, + IN gctSIZE_T ByteCount, + IN gctCONST_POINTER Data + ); + +typedef enum _gceFILE_WHENCE +{ + gcvFILE_SEEK_SET, + gcvFILE_SEEK_CUR, + gcvFILE_SEEK_END +} +gceFILE_WHENCE; + +/* Set the current position of a file. */ +gceSTATUS +gcoOS_Seek( + IN gcoOS Os, + IN gctFILE File, + IN gctUINT32 Offset, + IN gceFILE_WHENCE Whence + ); + +/* Set the current position of a file. */ +gceSTATUS +gcoOS_SetPos( + IN gcoOS Os, + IN gctFILE File, + IN gctUINT32 Position + ); + +/* Get the current position of a file. */ +gceSTATUS +gcoOS_GetPos( + IN gcoOS Os, + IN gctFILE File, + OUT gctUINT32 * Position + ); + +/* Perform a memory copy. */ +gceSTATUS +gcoOS_MemCopy( + IN gctPOINTER Destination, + IN gctCONST_POINTER Source, + IN gctSIZE_T Bytes + ); + +/* Perform a memory fill. */ +gceSTATUS +gcoOS_MemFill( + IN gctPOINTER Destination, + IN gctUINT8 Filler, + IN gctSIZE_T Bytes + ); + +/* Zero memory. */ +gceSTATUS +gcoOS_ZeroMemory( + IN gctPOINTER Memory, + IN gctSIZE_T Bytes + ); + +/* Find the last occurance of a character inside a string. */ +gceSTATUS +gcoOS_StrFindReverse( + IN gctCONST_STRING String, + IN gctINT8 Character, + OUT gctSTRING * Output + ); + +gceSTATUS +gcoOS_StrLen( + IN gctCONST_STRING String, + OUT gctSIZE_T * Length + ); + +gceSTATUS +gcoOS_StrDup( + IN gcoOS Os, + IN gctCONST_STRING String, + OUT gctSTRING * Target + ); + +/* Copy a string. */ +gceSTATUS +gcoOS_StrCopySafe( + IN gctSTRING Destination, + IN gctSIZE_T DestinationSize, + IN gctCONST_STRING Source + ); + +/* Append a string. */ +gceSTATUS +gcoOS_StrCatSafe( + IN gctSTRING Destination, + IN gctSIZE_T DestinationSize, + IN gctCONST_STRING Source + ); + +/* Compare two strings. */ +gceSTATUS +gcoOS_StrCmp( + IN gctCONST_STRING String1, + IN gctCONST_STRING String2 + ); + +/* Compare characters of two strings. */ +gceSTATUS +gcoOS_StrNCmp( + IN gctCONST_STRING String1, + IN gctCONST_STRING String2, + IN gctSIZE_T Count + ); + +/* Convert string to float. */ +gceSTATUS +gcoOS_StrToFloat( + IN gctCONST_STRING String, + OUT gctFLOAT * Float + ); + +/* Convert string to integer. */ +gceSTATUS +gcoOS_StrToInt( + IN gctCONST_STRING String, + OUT gctINT * Int + ); + +gceSTATUS +gcoOS_MemCmp( + IN gctCONST_POINTER Memory1, + IN gctCONST_POINTER Memory2, + IN gctSIZE_T Bytes + ); + +gceSTATUS +gcoOS_PrintStrSafe( + OUT gctSTRING String, + IN gctSIZE_T StringSize, + IN OUT gctUINT * Offset, + IN gctCONST_STRING Format, + ... + ); + +gceSTATUS +gcoOS_PrintStrVSafe( + OUT gctSTRING String, + IN gctSIZE_T StringSize, + IN OUT gctUINT * Offset, + IN gctCONST_STRING Format, + IN gctPOINTER Arguments + ); + +gceSTATUS +gcoOS_LoadLibrary( + IN gcoOS Os, + IN gctCONST_STRING Library, + OUT gctHANDLE * Handle + ); + +gceSTATUS +gcoOS_FreeLibrary( + IN gcoOS Os, + IN gctHANDLE Handle + ); + +gceSTATUS +gcoOS_GetProcAddress( + IN gcoOS Os, + IN gctHANDLE Handle, + IN gctCONST_STRING Name, + OUT gctPOINTER * Function + ); + +gceSTATUS +gcoOS_Compact( + IN gcoOS Os + ); + +gceSTATUS +gcoOS_ProfileStart( + IN gcoOS Os + ); + +gceSTATUS +gcoOS_ProfileEnd( + IN gcoOS Os, + IN gctCONST_STRING Title + ); + +gceSTATUS +gcoOS_SetProfileSetting( + IN gcoOS Os, + IN gctBOOL Enable, + IN gctCONST_STRING FileName + ); + +/* Query the video memory. */ +gceSTATUS +gcoOS_QueryVideoMemory( + IN gcoOS Os, + OUT gctPHYS_ADDR * InternalAddress, + OUT gctSIZE_T * InternalSize, + OUT gctPHYS_ADDR * ExternalAddress, + OUT gctSIZE_T * ExternalSize, + OUT gctPHYS_ADDR * ContiguousAddress, + OUT gctSIZE_T * ContiguousSize + ); + +/*----------------------------------------------------------------------------*/ +/*----- Atoms ----------------------------------------------------------------*/ + +typedef struct gcsATOM * gcsATOM_PTR; + +/* Construct an atom. */ +gceSTATUS +gcoOS_AtomConstruct( + IN gcoOS Os, + OUT gcsATOM_PTR * Atom + ); + +/* Destroy an atom. */ +gceSTATUS +gcoOS_AtomDestroy( + IN gcoOS Os, + IN gcsATOM_PTR Atom + ); + +/* Increment an atom. */ +gceSTATUS +gcoOS_AtomIncrement( + IN gcoOS Os, + IN gcsATOM_PTR Atom, + OUT gctINT32_PTR OldValue + ); + +/* Decrement an atom. */ +gceSTATUS +gcoOS_AtomDecrement( + IN gcoOS Os, + IN gcsATOM_PTR Atom, + OUT gctINT32_PTR OldValue + ); + +gctHANDLE +gcoOS_GetCurrentProcessID( + void + ); + +/*----------------------------------------------------------------------------*/ +/*----- Time -----------------------------------------------------------------*/ + +/* Get the number of milliseconds since the system started. */ +gctUINT32 +gcoOS_GetTicks( + void + ); + +/* Get time in microseconds. */ +gceSTATUS +gcoOS_GetTime( + gctUINT64_PTR Time + ); + +/* Get CPU usage in microseconds. */ +gceSTATUS +gcoOS_GetCPUTime( + gctUINT64_PTR CPUTime + ); + +/* Get memory usage. */ +gceSTATUS +gcoOS_GetMemoryUsage( + gctUINT32_PTR MaxRSS, + gctUINT32_PTR IxRSS, + gctUINT32_PTR IdRSS, + gctUINT32_PTR IsRSS + ); + +/* Delay a number of microseconds. */ +gceSTATUS +gcoOS_Delay( + IN gcoOS Os, + IN gctUINT32 Delay + ); + +/*----------------------------------------------------------------------------*/ +/*----- Mutexes --------------------------------------------------------------*/ + +/* Create a new mutex. */ +gceSTATUS +gcoOS_CreateMutex( + IN gcoOS Os, + OUT gctPOINTER * Mutex + ); + +/* Delete a mutex. */ +gceSTATUS +gcoOS_DeleteMutex( + IN gcoOS Os, + IN gctPOINTER Mutex + ); + +/* Acquire a mutex. */ +gceSTATUS +gcoOS_AcquireMutex( + IN gcoOS Os, + IN gctPOINTER Mutex, + IN gctUINT32 Timeout + ); + +/* Release a mutex. */ +gceSTATUS +gcoOS_ReleaseMutex( + IN gcoOS Os, + IN gctPOINTER Mutex + ); + +/*----------------------------------------------------------------------------*/ +/*----- Signals --------------------------------------------------------------*/ + +/* Create a signal. */ +gceSTATUS +gcoOS_CreateSignal( + IN gcoOS Os, + IN gctBOOL ManualReset, + OUT gctSIGNAL * Signal + ); + +/* Destroy a signal. */ +gceSTATUS +gcoOS_DestroySignal( + IN gcoOS Os, + IN gctSIGNAL Signal + ); + +/* Signal a signal. */ +gceSTATUS +gcoOS_Signal( + IN gcoOS Os, + IN gctSIGNAL Signal, + IN gctBOOL State + ); + +/* Wait for a signal. */ +gceSTATUS +gcoOS_WaitSignal( + IN gcoOS Os, + IN gctSIGNAL Signal, + IN gctUINT32 Wait + ); + +/* Write a register. */ +gceSTATUS +gcoOS_WriteRegister( + IN gcoOS Os, + IN gctUINT32 Address, + IN gctUINT32 Data + ); + +/* Read a register. */ +gceSTATUS +gcoOS_ReadRegister( + IN gcoOS Os, + IN gctUINT32 Address, + OUT gctUINT32 * Data + ); + +gceSTATUS +gcoOS_CacheFlush( + IN gcoOS Os, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ); + +gceSTATUS +gcoOS_CacheInvalidate( + IN gcoOS Os, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ); + +/******************************************************************************* +** gcoMATH object +*/ + +#define gcdPI 3.14159265358979323846f + +gctUINT32 +gcoMATH_Log2in5dot5( + IN gctINT X + ); + +gctFLOAT +gcoMATH_Sine( + IN gctFLOAT X + ); + +gctFLOAT +gcoMATH_Cosine( + IN gctFLOAT X + ); + +gctFLOAT +gcoMATH_Floor( + IN gctFLOAT X + ); + +gctFLOAT +gcoMATH_Ceiling( + IN gctFLOAT X + ); + +gctFLOAT +gcoMATH_SquareRoot( + IN gctFLOAT X + ); + +gctFLOAT +gcoMATH_Log2( + IN gctFLOAT X + ); + +gctFLOAT +gcoMATH_Power( + IN gctFLOAT X, + IN gctFLOAT Y + ); + +gctFLOAT +gcoMATH_Modulo( + IN gctFLOAT X, + IN gctFLOAT Y + ); + +gctFLOAT +gcoMATH_Exp( + IN gctFLOAT X + ); + +gctFLOAT +gcoMATH_Absolute( + IN gctFLOAT X + ); + +gctFLOAT +gcoMATH_ArcCosine( + IN gctFLOAT X + ); + +gctFLOAT +gcoMATH_Tangent( + IN gctFLOAT X + ); + +gctFLOAT +gcoMATH_UInt2Float( + IN gctUINT X + ); + +gctUINT +gcoMATH_Float2UInt( + IN gctFLOAT X + ); + +gctFLOAT +gcoMATH_Multiply( + IN gctFLOAT X, + IN gctFLOAT Y + ); + +/******************************************************************************\ +**************************** Coordinate Structures ***************************** +\******************************************************************************/ + +typedef struct _gcsPOINT +{ + gctINT32 x; + gctINT32 y; +} +gcsPOINT; + +typedef struct _gcsSIZE +{ + gctINT32 width; + gctINT32 height; +} +gcsSIZE; + +typedef struct _gcsRECT +{ + gctINT32 left; + gctINT32 top; + gctINT32 right; + gctINT32 bottom; +} +gcsRECT; + + +/******************************************************************************\ +********************************* gcoSURF Object ******************************** +\******************************************************************************/ + +/*----------------------------------------------------------------------------*/ +/*------------------------------- gcoSURF Common ------------------------------*/ + +/* Color format classes. */ +typedef enum _gceFORMAT_CLASS +{ + gcvFORMAT_CLASS_RGBA = 4500, + gcvFORMAT_CLASS_YUV, + gcvFORMAT_CLASS_INDEX, + gcvFORMAT_CLASS_LUMINANCE, + gcvFORMAT_CLASS_BUMP, + gcvFORMAT_CLASS_DEPTH, +} +gceFORMAT_CLASS; + +/* Special enums for width field in gcsFORMAT_COMPONENT. */ +typedef enum _gceCOMPONENT_CONTROL +{ + gcvCOMPONENT_NOTPRESENT = 0x00, + gcvCOMPONENT_DONTCARE = 0x80, + gcvCOMPONENT_WIDTHMASK = 0x7F, + gcvCOMPONENT_ODD = 0x80 +} +gceCOMPONENT_CONTROL; + +/* Color format component parameters. */ +typedef struct _gcsFORMAT_COMPONENT +{ + gctUINT8 start; + gctUINT8 width; +} +gcsFORMAT_COMPONENT; + +/* RGBA color format class. */ +typedef struct _gcsFORMAT_CLASS_TYPE_RGBA +{ + gcsFORMAT_COMPONENT alpha; + gcsFORMAT_COMPONENT red; + gcsFORMAT_COMPONENT green; + gcsFORMAT_COMPONENT blue; +} +gcsFORMAT_CLASS_TYPE_RGBA; + +/* YUV color format class. */ +typedef struct _gcsFORMAT_CLASS_TYPE_YUV +{ + gcsFORMAT_COMPONENT y; + gcsFORMAT_COMPONENT u; + gcsFORMAT_COMPONENT v; +} +gcsFORMAT_CLASS_TYPE_YUV; + +/* Index color format class. */ +typedef struct _gcsFORMAT_CLASS_TYPE_INDEX +{ + gcsFORMAT_COMPONENT value; +} +gcsFORMAT_CLASS_TYPE_INDEX; + +/* Luminance color format class. */ +typedef struct _gcsFORMAT_CLASS_TYPE_LUMINANCE +{ + gcsFORMAT_COMPONENT alpha; + gcsFORMAT_COMPONENT value; +} +gcsFORMAT_CLASS_TYPE_LUMINANCE; + +/* Bump map color format class. */ +typedef struct _gcsFORMAT_CLASS_TYPE_BUMP +{ + gcsFORMAT_COMPONENT alpha; + gcsFORMAT_COMPONENT l; + gcsFORMAT_COMPONENT v; + gcsFORMAT_COMPONENT u; + gcsFORMAT_COMPONENT q; + gcsFORMAT_COMPONENT w; +} +gcsFORMAT_CLASS_TYPE_BUMP; + +/* Depth and stencil format class. */ +typedef struct _gcsFORMAT_CLASS_TYPE_DEPTH +{ + gcsFORMAT_COMPONENT depth; + gcsFORMAT_COMPONENT stencil; +} +gcsFORMAT_CLASS_TYPE_DEPTH; + +/* Format parameters. */ +typedef struct _gcsSURF_FORMAT_INFO +{ + /* Format code and class. */ + gceSURF_FORMAT format; + gceFORMAT_CLASS fmtClass; + + /* The size of one pixel in bits. */ + gctUINT8 bitsPerPixel; + + /* Component swizzle. */ + gceSURF_SWIZZLE swizzle; + + /* Some formats have two neighbour pixels interleaved together. */ + /* To describe such format, set the flag to 1 and add another */ + /* like this one describing the odd pixel format. */ + gctUINT8 interleaved; + + /* Format components. */ + union + { + gcsFORMAT_CLASS_TYPE_BUMP bump; + gcsFORMAT_CLASS_TYPE_RGBA rgba; + gcsFORMAT_CLASS_TYPE_YUV yuv; + gcsFORMAT_CLASS_TYPE_LUMINANCE lum; + gcsFORMAT_CLASS_TYPE_INDEX index; + gcsFORMAT_CLASS_TYPE_DEPTH depth; + } u; +} +gcsSURF_FORMAT_INFO; + +/* Frame buffer information. */ +typedef struct _gcsSURF_FRAMEBUFFER +{ + gctPOINTER logical; + gctUINT width, height; + gctINT stride; + gceSURF_FORMAT format; +} +gcsSURF_FRAMEBUFFER; + +/* Generic pixel component descriptors. */ +extern gcsFORMAT_COMPONENT gcvPIXEL_COMP_XXX8; +extern gcsFORMAT_COMPONENT gcvPIXEL_COMP_XX8X; +extern gcsFORMAT_COMPONENT gcvPIXEL_COMP_X8XX; +extern gcsFORMAT_COMPONENT gcvPIXEL_COMP_8XXX; + +typedef enum _gceORIENTATION +{ + gcvORIENTATION_TOP_BOTTOM, + gcvORIENTATION_BOTTOM_TOP, +} +gceORIENTATION; + + +/* Construct a new gcoSURF object. */ +gceSTATUS +gcoSURF_Construct( + IN gcoHAL Hal, + IN gctUINT Width, + IN gctUINT Height, + IN gctUINT Depth, + IN gceSURF_TYPE Type, + IN gceSURF_FORMAT Format, + IN gcePOOL Pool, + OUT gcoSURF * Surface + ); + +/* Destroy an gcoSURF object. */ +gceSTATUS +gcoSURF_Destroy( + IN gcoSURF Surface + ); + +/* Map user-allocated surface. */ +gceSTATUS +gcoSURF_MapUserSurface( + IN gcoSURF Surface, + IN gctUINT Alignment, + IN gctPOINTER Logical, + IN gctUINT32 Physical + ); + +/* Set the color type of the surface. */ +gceSTATUS +gcoSURF_SetColorType( + IN gcoSURF Surface, + IN gceSURF_COLOR_TYPE ColorType + ); + +/* Get the color type of the surface. */ +gceSTATUS +gcoSURF_GetColorType( + IN gcoSURF Surface, + OUT gceSURF_COLOR_TYPE *ColorType + ); + +/* Set the surface ration angle. */ +gceSTATUS +gcoSURF_SetRotation( + IN gcoSURF Surface, + IN gceSURF_ROTATION Rotation + ); + +/* Verify and return the state of the tile status mechanism. */ +gceSTATUS +gcoSURF_IsTileStatusSupported( + IN gcoSURF Surface + ); + +/* Enable tile status for the specified surface. */ +gceSTATUS +gcoSURF_EnableTileStatus( + IN gcoSURF Surface + ); + +/* Disable tile status for the specified surface. */ +gceSTATUS +gcoSURF_DisableTileStatus( + IN gcoSURF Surface, + IN gctBOOL Decompress + ); + +/* Get surface size. */ +gceSTATUS +gcoSURF_GetSize( + IN gcoSURF Surface, + OUT gctUINT * Width, + OUT gctUINT * Height, + OUT gctUINT * Depth + ); + +/* Get surface aligned sizes. */ +gceSTATUS +gcoSURF_GetAlignedSize( + IN gcoSURF Surface, + OUT gctUINT * Width, + OUT gctUINT * Height, + OUT gctINT * Stride + ); + +/* Get surface type and format. */ +gceSTATUS +gcoSURF_GetFormat( + IN gcoSURF Surface, + OUT gceSURF_TYPE * Type, + OUT gceSURF_FORMAT * Format + ); + +/* Lock the surface. */ +gceSTATUS +gcoSURF_Lock( + IN gcoSURF Surface, + IN OUT gctUINT32 * Address, + IN OUT gctPOINTER * Memory + ); + +/* Unlock the surface. */ +gceSTATUS +gcoSURF_Unlock( + IN gcoSURF Surface, + IN gctPOINTER Memory + ); + +/* Return pixel format parameters. */ +gceSTATUS +gcoSURF_QueryFormat( + IN gceSURF_FORMAT Format, + OUT gcsSURF_FORMAT_INFO_PTR * Info + ); + +/* Compute the color pixel mask. */ +gceSTATUS +gcoSURF_ComputeColorMask( + IN gcsSURF_FORMAT_INFO_PTR Format, + OUT gctUINT32_PTR ColorMask + ); + +/* Flush the surface. */ +gceSTATUS +gcoSURF_Flush( + IN gcoSURF Surface + ); + +/* Fill surface with a value. */ +gceSTATUS +gcoSURF_Fill( + IN gcoSURF Surface, + IN gcsPOINT_PTR Origin, + IN gcsSIZE_PTR Size, + IN gctUINT32 Value, + IN gctUINT32 Mask + ); + +/* Alpha blend two surfaces together. */ +gceSTATUS +gcoSURF_Blend( + IN gcoSURF SrcSurface, + IN gcoSURF DestSurface, + IN gcsPOINT_PTR SrcOrig, + IN gcsPOINT_PTR DestOrigin, + IN gcsSIZE_PTR Size, + IN gceSURF_BLEND_MODE Mode + ); + +/* Create a new gcoSURF wrapper object. */ +gceSTATUS +gcoSURF_ConstructWrapper( + IN gcoHAL Hal, + OUT gcoSURF * Surface + ); + +/* Set the underlying buffer for the surface wrapper. */ +gceSTATUS +gcoSURF_SetBuffer( + IN gcoSURF Surface, + IN gceSURF_TYPE Type, + IN gceSURF_FORMAT Format, + IN gctUINT Stride, + IN gctPOINTER Logical, + IN gctUINT32 Physical + ); + +/* Set the size of the surface in pixels and map the underlying buffer. */ +gceSTATUS +gcoSURF_SetWindow( + IN gcoSURF Surface, + IN gctUINT X, + IN gctUINT Y, + IN gctUINT Width, + IN gctUINT Height + ); + +/* Increase reference count of the surface. */ +gceSTATUS +gcoSURF_ReferenceSurface( + IN gcoSURF Surface + ); + +/* Get surface reference count. */ +gceSTATUS +gcoSURF_QueryReferenceCount( + IN gcoSURF Surface, + OUT gctINT32 * ReferenceCount + ); + +/* Set surface orientation. */ +gceSTATUS +gcoSURF_SetOrientation( + IN gcoSURF Surface, + IN gceORIENTATION Orientation + ); + +/* Query surface orientation. */ +gceSTATUS +gcoSURF_QueryOrientation( + IN gcoSURF Surface, + OUT gceORIENTATION * Orientation + ); + +/******************************************************************************\ +********************************* gcoDUMP Object ******************************** +\******************************************************************************/ + +/* Construct a new gcoDUMP object. */ +gceSTATUS +gcoDUMP_Construct( + IN gcoOS Os, + IN gcoHAL Hal, + OUT gcoDUMP * Dump + ); + +/* Destroy a gcoDUMP object. */ +gceSTATUS +gcoDUMP_Destroy( + IN gcoDUMP Dump + ); + +/* Enable/disable dumping. */ +gceSTATUS +gcoDUMP_Control( + IN gcoDUMP Dump, + IN gctSTRING FileName + ); + +gceSTATUS +gcoDUMP_IsEnabled( + IN gcoDUMP Dump, + OUT gctBOOL * Enabled + ); + +/* Add surface. */ +gceSTATUS +gcoDUMP_AddSurface( + IN gcoDUMP Dump, + IN gctINT32 Width, + IN gctINT32 Height, + IN gceSURF_FORMAT PixelFormat, + IN gctUINT32 Address, + IN gctSIZE_T ByteCount + ); + +/* Mark the beginning of a frame. */ +gceSTATUS +gcoDUMP_FrameBegin( + IN gcoDUMP Dump + ); + +/* Mark the end of a frame. */ +gceSTATUS +gcoDUMP_FrameEnd( + IN gcoDUMP Dump + ); + +/* Dump data. */ +gceSTATUS +gcoDUMP_DumpData( + IN gcoDUMP Dump, + IN gceDUMP_TAG Type, + IN gctUINT32 Address, + IN gctSIZE_T ByteCount, + IN gctCONST_POINTER Data + ); + +/* Delete an address. */ +gceSTATUS +gcoDUMP_Delete( + IN gcoDUMP Dump, + IN gctUINT32 Address + ); + +/******************************************************************************\ +******************************* gcsRECT Structure ****************************** +\******************************************************************************/ + +/* Initialize rectangle structure. */ +gceSTATUS +gcsRECT_Set( + OUT gcsRECT_PTR Rect, + IN gctINT32 Left, + IN gctINT32 Top, + IN gctINT32 Right, + IN gctINT32 Bottom + ); + +/* Return the width of the rectangle. */ +gceSTATUS +gcsRECT_Width( + IN gcsRECT_PTR Rect, + OUT gctINT32 * Width + ); + +/* Return the height of the rectangle. */ +gceSTATUS +gcsRECT_Height( + IN gcsRECT_PTR Rect, + OUT gctINT32 * Height + ); + +/* Ensure that top left corner is to the left and above the right bottom. */ +gceSTATUS +gcsRECT_Normalize( + IN OUT gcsRECT_PTR Rect + ); + +/* Compare two rectangles. */ +gceSTATUS +gcsRECT_IsEqual( + IN gcsRECT_PTR Rect1, + IN gcsRECT_PTR Rect2, + OUT gctBOOL * Equal + ); + +/* Compare the sizes of two rectangles. */ +gceSTATUS +gcsRECT_IsOfEqualSize( + IN gcsRECT_PTR Rect1, + IN gcsRECT_PTR Rect2, + OUT gctBOOL * EqualSize + ); + + +/******************************************************************************\ +**************************** gcsBOUNDARY Structure ***************************** +\******************************************************************************/ + +typedef struct _gcsBOUNDARY +{ + gctINT x; + gctINT y; + gctINT width; + gctINT height; +} +gcsBOUNDARY; + +/******************************************************************************\ +********************************* gcoHEAP Object ******************************** +\******************************************************************************/ + +typedef struct _gcoHEAP * gcoHEAP; + +/* Construct a new gcoHEAP object. */ +gceSTATUS +gcoHEAP_Construct( + IN gcoOS Os, + IN gctSIZE_T AllocationSize, + OUT gcoHEAP * Heap + ); + +/* Destroy an gcoHEAP object. */ +gceSTATUS +gcoHEAP_Destroy( + IN gcoHEAP Heap + ); + +/* Allocate memory. */ +gceSTATUS +gcoHEAP_Allocate( + IN gcoHEAP Heap, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Node + ); + +/* Free memory. */ +gceSTATUS +gcoHEAP_Free( + IN gcoHEAP Heap, + IN gctPOINTER Node + ); + +/* Profile the heap. */ +gceSTATUS +gcoHEAP_ProfileStart( + IN gcoHEAP Heap + ); + +gceSTATUS +gcoHEAP_ProfileEnd( + IN gcoHEAP Heap, + IN gctCONST_STRING Title + ); + +#if defined gcdHAL_TEST +gceSTATUS +gcoHEAP_Test( + IN gcoHEAP Heap, + IN gctSIZE_T Vectors, + IN gctSIZE_T MaxSize + ); +#endif + +/******************************************************************************\ +******************************* Debugging Macros ******************************* +\******************************************************************************/ + +void +gcoOS_SetDebugLevel( + IN gctUINT32 Level + ); + +void +gcoOS_SetDebugZone( + IN gctUINT32 Zone + ); + +void +gcoOS_SetDebugLevelZone( + IN gctUINT32 Level, + IN gctUINT32 Zone + ); + +void +gcoOS_SetDebugZones( + IN gctUINT32 Zones, + IN gctBOOL Enable + ); + +void +gcoOS_SetDebugFile( + IN gctCONST_STRING FileName + ); + +/******************************************************************************* +** +** gcmFATAL +** +** Print a message to the debugger and execute a break point. +** +** ARGUMENTS: +** +** message Message. +** ... Optional arguments. +*/ + +void +gckOS_DebugFatal( + IN gctCONST_STRING Message, + ... + ); + +void +gcoOS_DebugFatal( + IN gctCONST_STRING Message, + ... + ); + +#if gcdDEBUG +# define gcmFATAL gcoOS_DebugFatal +# define gcmkFATAL gckOS_DebugFatal +#elif gcdHAS_ELLIPSES +# define gcmFATAL(...) +# define gcmkFATAL(...) +#else + gcmINLINE static void + __dummy_fatal( + IN gctCONST_STRING Message, + ... + ) + { + } +# define gcmFATAL __dummy_fatal +# define gcmkFATAL __dummy_fatal +#endif + +#define gcmENUM2TEXT(e) case e: return #e + +/******************************************************************************* +** +** gcmTRACE +** +** Print a message to the debugfer if the correct level has been set. In +** retail mode this macro does nothing. +** +** ARGUMENTS: +** +** level Level of message. +** message Message. +** ... Optional arguments. +*/ +#define gcvLEVEL_NONE -1 +#define gcvLEVEL_ERROR 0 +#define gcvLEVEL_WARNING 1 +#define gcvLEVEL_INFO 2 +#define gcvLEVEL_VERBOSE 3 + +void +gckOS_DebugTrace( + IN gctUINT32 Level, + IN gctCONST_STRING Message, + ... + ); +void + +gcoOS_DebugTrace( + IN gctUINT32 Level, + IN gctCONST_STRING Message, + ... + ); + +#if gcdDEBUG +# define gcmTRACE gcoOS_DebugTrace +# define gcmkTRACE gckOS_DebugTrace +#elif gcdHAS_ELLIPSES +# define gcmTRACE(...) +# define gcmkTRACE(...) +#else + gcmINLINE static void + __dummy_trace( + IN gctUINT32 Level, + IN gctCONST_STRING Message, + ... + ) + { + } +# define gcmTRACE __dummy_trace +# define gcmkTRACE __dummy_trace +#endif + +/* Debug zones. */ +#define gcvZONE_OS (1 << 0) +#define gcvZONE_HARDWARE (1 << 1) +#define gcvZONE_HEAP (1 << 2) + +/* Kernel zones. */ +#define gcvZONE_KERNEL (1 << 3) +#define gcvZONE_VIDMEM (1 << 4) +#define gcvZONE_COMMAND (1 << 5) +#define gcvZONE_DRIVER (1 << 6) +#define gcvZONE_CMODEL (1 << 7) +#define gcvZONE_MMU (1 << 8) +#define gcvZONE_EVENT (1 << 9) +#define gcvZONE_DEVICE (1 << 10) + +/* User zones. */ +#define gcvZONE_HAL (1 << 3) +#define gcvZONE_BUFFER (1 << 4) +#define gcvZONE_CONTEXT (1 << 5) +#define gcvZONE_SURFACE (1 << 6) +#define gcvZONE_INDEX (1 << 7) +#define gcvZONE_STREAM (1 << 8) +#define gcvZONE_TEXTURE (1 << 9) +#define gcvZONE_2D (1 << 10) +#define gcvZONE_3D (1 << 11) +#define gcvZONE_COMPILER (1 << 12) +#define gcvZONE_MEMORY (1 << 13) +#define gcvZONE_STATE (1 << 14) +#define gcvZONE_AUX (1 << 15) + +/* API definitions. */ +#define gcvZONE_API_HAL (0 << 28) +#define gcvZONE_API_EGL (1 << 28) +#define gcvZONE_API_ES11 (2 << 28) +#define gcvZONE_API_ES20 (3 << 28) +#define gcvZONE_API_VG11 (4 << 28) +#define gcvZONE_API_GL (5 << 28) +#define gcvZONE_API_DFB (6 << 28) +#define gcvZONE_API_GDI (7 << 28) +#define gcvZONE_API_D3D (8 << 28) + +#define gcmZONE_GET_API(zone) ((zone) >> 28) +#define gcdZONE_MASK 0x0FFFFFFF + +/* Handy zones. */ +#define gcvZONE_NONE 0 +#define gcvZONE_ALL gcdZONE_MASK + +/******************************************************************************* +** +** gcmTRACE_ZONE +** +** Print a message to the debugger if the correct level and zone has been +** set. In retail mode this macro does nothing. +** +** ARGUMENTS: +** +** Level Level of message. +** Zone Zone of message. +** Message Message. +** ... Optional arguments. +*/ + +void +gckOS_DebugTraceZone( + IN gctUINT32 Level, + IN gctUINT32 Zone, + IN gctCONST_STRING Message, + ... + ); + +void +gcoOS_DebugTraceZone( + IN gctUINT32 Level, + IN gctUINT32 Zone, + IN gctCONST_STRING Message, + ... + ); + +#if gcdDEBUG +# define gcmTRACE_ZONE gcoOS_DebugTraceZone +# define gcmkTRACE_ZONE gckOS_DebugTraceZone +#elif gcdHAS_ELLIPSES +# define gcmTRACE_ZONE(...) +# define gcmkTRACE_ZONE(...) +#else + gcmINLINE static void + __dummy_trace_zone( + IN gctUINT32 Level, + IN gctUINT32 Zone, + IN gctCONST_STRING Message, + ... + ) + { + } +# define gcmTRACE_ZONE __dummy_trace_zone +# define gcmkTRACE_ZONE __dummy_trace_zone +#endif + +/******************************************************************************\ +******************************** Logging Macros ******************************** +\******************************************************************************/ + +#define gcdHEADER_LEVEL gcvLEVEL_VERBOSE + +#define gcmHEADER() \ + gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "++%s(%d)", __FUNCTION__, __LINE__) + +#if gcdHAS_ELLIPSES +# define gcmHEADER_ARG(Text, ...) \ + gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "++%s(%d): " Text, __FUNCTION__, __LINE__, __VA_ARGS__) +#else + gcmINLINE static void + __dummy_header_arg( + IN gctCONST_STRING Text, + ... + ) + { + } +# define gcmHEADER_ARG __dummy_header_arg +#endif + +#define gcmFOOTER() \ + gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "--%s(%d): status=%d", \ + __FUNCTION__, __LINE__, status) + +#define gcmFOOTER_NO() \ + gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "--%s(%d)", __FUNCTION__, __LINE__) + +#if gcdHAS_ELLIPSES +# define gcmFOOTER_ARG(Text, ...) \ + gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "--%s(%d): " Text, \ + __FUNCTION__, __LINE__, __VA_ARGS__) +#else + gcmINLINE static void + __dummy_footer_arg( + IN gctCONST_STRING Text, + ... + ) + { + } +# define gcmFOOTER_ARG __dummy_footer_arg +#endif + +#define gcmkHEADER() \ + gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "++%s(%d)", __FUNCTION__, __LINE__) + +#if gcdHAS_ELLIPSES +# define gcmkHEADER_ARG(Text, ...) \ + gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "++%s(%d): " Text, __FUNCTION__, __LINE__, __VA_ARGS__) +#else + gcmINLINE static void + __dummy_kheader_arg( + IN gctCONST_STRING Text, + ... + ) + { + } +# define gcmkHEADER_ARG __dummy_kheader_arg +#endif + +#define gcmkFOOTER() \ + gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "--%s(%d): status=%d", \ + __FUNCTION__, __LINE__, status) + +#define gcmkFOOTER_NO() \ + gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "--%s(%d)", __FUNCTION__, __LINE__) + +#if gcdHAS_ELLIPSES +# define gcmkFOOTER_ARG(Text, ...) \ + gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "--%s(%d): " Text, \ + __FUNCTION__, __LINE__, __VA_ARGS__) +#else + gcmINLINE static void + __dummy_kfooter_arg( + IN gctCONST_STRING Text, + ... + ) + { + } +# define gcmkFOOTER_ARG __dummy_kfooter_arg +#endif + +#define gcmOPT_VALUE(ptr) (((ptr) == gcvNULL) ? 0 : *(ptr)) +#define gcmOPT_POINTER(ptr) (((ptr) == gcvNULL) ? gcvNULL : *(ptr)) + +void +gcoOS_Print( + IN gctCONST_STRING Message, + ... + ); +void +gckOS_Print( + IN gctCONST_STRING Message, + ... + ); +#define gcmPRINT gcoOS_Print +#define gcmkPRINT gckOS_Print + +/******************************************************************************* +** +** gcmDUMP +** +** Print a dump message. +** +** ARGUMENTS: +** +** gctSTRING Message. +** +** ... Optional arguments. +*/ +#if gcdDUMP + gceSTATUS + gcfDump( + IN gcoOS Os, + IN gctCONST_STRING String, + ... + ); +# define gcmDUMP gcfDump +#elif gcdHAS_ELLIPSES +# define gcmDUMP(...) +#else + gcmINLINE static void + __dummy_dump( + IN gcoOS Os, + IN gctCONST_STRING Message, + ... + ) + { + } +# define gcmDUMP __dummy_dump +#endif + +/******************************************************************************* +** +** gcmDUMP_DATA +** +** Add data to the dump. +** +** ARGUMENTS: +** +** gctSTRING Tag +** Tag for dump. +** +** gctPOINTER Logical +** Logical address of buffer. +** +** gctSIZE_T Bytes +** Number of bytes. +*/ + +#if gcdDUMP + gceSTATUS + gcfDumpData( + IN gcoOS Os, + IN gctSTRING Tag, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ); +# define gcmDUMP_DATA gcfDumpData +#elif gcdHAS_ELLIPSES +# define gcmDUMP_DATA(...) +#else + gcmINLINE static void + __dummy_dump_data( + IN gcoOS Os, + IN gctSTRING Tag, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ) + { + } +# define gcmDUMP_DATA __dummy_dump_data +#endif + +/******************************************************************************* +** +** gcmDUMP_BUFFER +** +** Print a buffer to the dump. +** +** ARGUMENTS: +** +** gctSTRING Tag +** Tag for dump. +** +** gctUINT32 Physical +** Physical address of buffer. +** +** gctPOINTER Logical +** Logical address of buffer. +** +** gctUINT32 Offset +** Offset into buffer. +** +** gctSIZE_T Bytes +** Number of bytes. +*/ + +#if gcdDUMP +gceSTATUS +gcfDumpBuffer( + IN gcoOS Os, + IN gctSTRING Tag, + IN gctUINT32 Physical, + IN gctPOINTER Logical, + IN gctUINT32 Offset, + IN gctSIZE_T Bytes + ); +# define gcmDUMP_BUFFER gcfDumpBuffer +#elif gcdHAS_ELLIPSES +# define gcmDUMP_BUFFER(...) +#else + gcmINLINE static void + __dummy_dump_buffer( + IN gcoOS Os, + IN gctSTRING Tag, + IN gctUINT32 Physical, + IN gctPOINTER Logical, + IN gctUINT32 Offset, + IN gctSIZE_T Bytes + ) + { + } +# define gcmDUMP_BUFFER __dummy_dump_buffer +#endif + +/******************************************************************************* +** +** gcmDUMP_API +** +** Print a dump message for a high level API prefixed by the function name. +** +** ARGUMENTS: +** +** gctSTRING Message. +** +** ... Optional arguments. +*/ +#if gcdDUMP_API + gceSTATUS + gcfDumpApi( + IN gctCONST_STRING String, + ... + ); +# define gcmDUMP_API gcfDumpApi +#elif gcdHAS_ELLIPSES +# define gcmDUMP_API(...) +#else + gcmINLINE static void + __dummy_dump_api( + IN gctCONST_STRING Message, + ... + ) + { + } +# define gcmDUMP_API __dummy_dump_api +#endif + +/******************************************************************************* +** +** gcmDUMP_API_ARRAY +** +** Print an array of data. +** +** ARGUMENTS: +** +** gctUINT32_PTR Pointer to array. +** gctUINT32 Size. +*/ +#if gcdDUMP_API + gceSTATUS + gcfDumpArray( + IN gctCONST_POINTER Data, + IN gctUINT32 Size + ); +# define gcmDUMP_API_ARRAY gcfDumpArray +#elif gcdHAS_ELLIPSES +# define gcmDUMP_API_ARRAY(...) +#else + gcmINLINE static void + __dummy_dump_api_array( + IN gctCONST_POINTER Data, + IN gctUINT32 Size + ) + { + } +# define gcmDUMP_API_ARRAY __dummy_dump_api_array +#endif + +/******************************************************************************* +** +** gcmDUMP_API_ARRAY_TOKEN +** +** Print an array of data terminated by a token. +** +** ARGUMENTS: +** +** gctUINT32_PTR Pointer to array. +** gctUINT32 Termination. +*/ +#if gcdDUMP_API + gceSTATUS + gcfDumpArrayToken( + IN gctCONST_POINTER Data, + IN gctUINT32 Termination + ); +# define gcmDUMP_API_ARRAY_TOKEN gcfDumpArrayToken +#elif gcdHAS_ELLIPSES +# define gcmDUMP_API_ARRAY_TOKEN(...) +#else + gcmINLINE static void + __dummy_dump_api_array_token( + IN gctCONST_POINTER Data, + IN gctUINT32 Termination + ) + { + } +# define gcmDUMP_API_ARRAY_TOKEN __dummy_dump_api_array_token +#endif + +/******************************************************************************* +** +** gcmTRACE_RELEASE +** +** Print a message to the shader debugger. +** +** ARGUMENTS: +** +** message Message. +** ... Optional arguments. +*/ + +#define gcmTRACE_RELEASE gcoOS_DebugShaderTrace + +void +gcoOS_DebugShaderTrace( + IN gctCONST_STRING Message, + ... + ); + +void +gcoOS_SetDebugShaderFiles( + IN gctCONST_STRING VSFileName, + IN gctCONST_STRING FSFileName + ); + +void +gcoOS_SetDebugShaderFileType( + IN gctUINT32 ShaderType + ); + +/******************************************************************************* +** +** gcmBREAK +** +** Break into the debugger. In retail mode this macro does nothing. +** +** ARGUMENTS: +** +** None. +*/ + +void +gcoOS_DebugBreak( + void + ); + +void +gckOS_DebugBreak( + void + ); + +#if gcdDEBUG +# define gcmBREAK gcoOS_DebugBreak +# define gcmkBREAK gckOS_DebugBreak +#else +# define gcmBREAK() +# define gcmkBREAK() +#endif + +/******************************************************************************* +** +** gcmASSERT +** +** Evaluate an expression and break into the debugger if the expression +** evaluates to false. In retail mode this macro does nothing. +** +** ARGUMENTS: +** +** exp Expression to evaluate. +*/ +#if gcdDEBUG +# define _gcmASSERT(prefix, exp) \ + do \ + { \ + if (!(exp)) \ + { \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "ASSERT at %s(%d) in " __FILE__, \ + __FUNCTION__, __LINE__); \ + prefix##TRACE(gcvLEVEL_ERROR, \ + "(%s)", #exp); \ + prefix##BREAK(); \ + } \ + } \ + while (gcvFALSE) +# define gcmASSERT(exp) _gcmASSERT(gcm, exp) +# define gcmkASSERT(exp) _gcmASSERT(gcmk, exp) +#else +# define gcmASSERT(exp) +# define gcmkASSERT(exp) +#endif + +/******************************************************************************* +** +** gcmVERIFY +** +** Verify if an expression returns true. If the expression does not +** evaluates to true, an assertion will happen in debug mode. +** +** ARGUMENTS: +** +** exp Expression to evaluate. +*/ +#if gcdDEBUG +# define gcmVERIFY(exp) gcmASSERT(exp) +# define gcmkVERIFY(exp) gcmkASSERT(exp) +#else +# define gcmVERIFY(exp) exp +# define gcmkVERIFY(exp) exp +#endif + +/******************************************************************************* +** +** gcmVERIFY_OK +** +** Verify a fucntion returns gcvSTATUS_OK. If the function does not return +** gcvSTATUS_OK, an assertion will happen in debug mode. +** +** ARGUMENTS: +** +** func Function to evaluate. +*/ + +void +gcoOS_Verify( + IN gceSTATUS Status + ); + +void +gckOS_Verify( + IN gceSTATUS Status + ); + +#if gcdDEBUG +# define gcmVERIFY_OK(func) \ + do \ + { \ + gceSTATUS verifyStatus = func; \ + gcoOS_Verify(verifyStatus); \ + gcmASSERT(verifyStatus == gcvSTATUS_OK); \ + } \ + while (gcvFALSE) +# define gcmkVERIFY_OK(func) \ + do \ + { \ + gceSTATUS verifyStatus = func; \ + gckOS_Verify(verifyStatus); \ + gcmkASSERT(verifyStatus == gcvSTATUS_OK); \ + } \ + while (gcvFALSE) +#else +# define gcmVERIFY_OK(func) func +# define gcmkVERIFY_OK(func) func +#endif + +/******************************************************************************* +** +** gcmERR_BREAK +** +** Executes a break statement on error. +** +** ASSUMPTIONS: +** +** 'status' variable of gceSTATUS type must be defined. +** +** ARGUMENTS: +** +** func Function to evaluate. +*/ +#define _gcmERR_BREAK(prefix, func) \ + status = func; \ + if (gcmIS_ERROR(status)) \ + { \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "ERR_BREAK: status=%d @ %s(%d) in " __FILE__, \ + status, __FUNCTION__, __LINE__); \ + break; \ + } \ + do { } while (gcvFALSE) +#define gcmERR_BREAK(func) _gcmERR_BREAK(gcm, func) +#define gcmkERR_BREAK(func) _gcmERR_BREAK(gcmk, func) + +/******************************************************************************* +** +** gcmERR_RETURN +** +** Executes a return on error. +** +** ASSUMPTIONS: +** +** 'status' variable of gceSTATUS type must be defined. +** +** ARGUMENTS: +** +** func Function to evaluate. +*/ +#define _gcmERR_RETURN(prefix, func) \ + status = func; \ + if (gcmIS_ERROR(status)) \ + { \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "ERR_RETURN: status=%d @ %s(%d) in " __FILE__, \ + status, __FUNCTION__, __LINE__); \ + return status; \ + } \ + do { } while (gcvFALSE) +#define gcmERR_RETURN(func) _gcmERR_RETURN(gcm, func) +#define gcmkERR_RETURN(func) _gcmERR_RETURN(gcmk, func) + +/******************************************************************************* +** +** gcmONERROR +** +** Jump to the error handler in case there is an error. +** +** ASSUMPTIONS: +** +** 'status' variable of gceSTATUS type must be defined. +** +** ARGUMENTS: +** +** func Function to evaluate. +*/ +#define _gcmONERROR(prefix, func) \ + do \ + { \ + status = func; \ + if (gcmIS_ERROR(status)) \ + { \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "ONERROR: status=%d @ %s(%d) in " __FILE__, \ + status, __FUNCTION__, __LINE__); \ + goto OnError; \ + } \ + } \ + while (gcvFALSE) +#define gcmONERROR(func) _gcmONERROR(gcm, func) +#define gcmkONERROR(func) _gcmONERROR(gcmk, func) + +/******************************************************************************* +** +** gcmVERIFY_LOCK +** +** Verifies whether the surface is locked. +** +** ARGUMENTS: +** +** surfaceInfo Pointer to the surface iniformational structure. +*/ +#define gcmVERIFY_LOCK(surfaceInfo) \ + if (!surfaceInfo->node.valid) \ + { \ + status = gcvSTATUS_MEMORY_UNLOCKED; \ + break; \ + } \ + do { } while (gcvFALSE) + +/******************************************************************************* +** +** gcmVERIFY_NODE_LOCK +** +** Verifies whether the surface node is locked. +** +** ARGUMENTS: +** +** surfaceInfo Pointer to the surface iniformational structure. +*/ +#define gcmVERIFY_NODE_LOCK(surfaceNode) \ + if (!surfaceNode->valid) \ + { \ + status = gcvSTATUS_MEMORY_UNLOCKED; \ + break; \ + } \ + do { } while (gcvFALSE) + +/******************************************************************************* +** +** gcmBADOBJECT_BREAK +** +** Executes a break statement on bad object. +** +** ARGUMENTS: +** +** obj Object to test. +** t Expected type of the object. +*/ +#define gcmBADOBJECT_BREAK(obj, t) \ + if ((obj == gcvNULL) \ + || (((gcsOBJECT *)(obj))->type != t) \ + ) \ + { \ + status = gcvSTATUS_INVALID_OBJECT; \ + break; \ + } \ + do { } while (gcvFALSE) + +/******************************************************************************* +** +** gcmCHECK_STATUS +** +** Executes a break statement on error. +** +** ASSUMPTIONS: +** +** 'status' variable of gceSTATUS type must be defined. +** +** ARGUMENTS: +** +** func Function to evaluate. +*/ +#define _gcmCHECK_STATUS(prefix, func) \ + do \ + { \ + last = func; \ + if (gcmIS_ERROR(last)) \ + { \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "CHECK_STATUS: status=%d @ %s(%d) in " __FILE__, \ + last, __FUNCTION__, __LINE__); \ + status = last; \ + } \ + } \ + while (gcvFALSE) +#define gcmCHECK_STATUS(func) _gcmCHECK_STATUS(gcm, func) +#define gcmkCHECK_STATUS(func) _gcmCHECK_STATUS(gcmk, func) + +/******************************************************************************* +** +** gcmVERIFY_ARGUMENT +** +** Assert if an argument does not apply to the specified expression. If +** the argument evaluates to false, gcvSTATUS_INVALID_ARGUMENT will be +** returned from the current function. In retail mode this macro does +** nothing. +** +** ARGUMENTS: +** +** arg Argument to evaluate. +*/ +#ifndef EGL_API_ANDROID +# define _gcmVERIFY_ARGUMENT(prefix, arg) \ + do \ + { \ + if (!(arg)) \ + { \ + prefix##TRACE(gcvLEVEL_ERROR, #prefix "VERIFY_ARGUMENT failed:"); \ + prefix##ASSERT(arg); \ + prefix##FOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT); \ + return gcvSTATUS_INVALID_ARGUMENT; \ + } \ + } \ + while (gcvFALSE) +# define gcmVERIFY_ARGUMENT(arg) _gcmVERIFY_ARGUMENT(gcm, arg) +# define gcmkVERIFY_ARGUMENT(arg) _gcmVERIFY_ARGUMENT(gcmk, arg) +#else +# define gcmVERIFY_ARGUMENT(arg) +# define gcmkVERIFY_ARGUMENT(arg) +#endif + +/******************************************************************************* +** +** gcmVERIFY_ARGUMENT_RETURN +** +** Assert if an argument does not apply to the specified expression. If +** the argument evaluates to false, gcvSTATUS_INVALID_ARGUMENT will be +** returned from the current function. In retail mode this macro does +** nothing. +** +** ARGUMENTS: +** +** arg Argument to evaluate. +*/ +#ifndef EGL_API_ANDROID +# define _gcmVERIFY_ARGUMENT_RETURN(prefix, arg, value) \ + do \ + { \ + if (!(arg)) \ + { \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "gcmVERIFY_ARGUMENT_RETURN failed:"); \ + prefix##ASSERT(arg); \ + prefix##FOOTER_ARG("value=%d", value); \ + return value; \ + } \ + } \ + while (gcvFALSE) +# define gcmVERIFY_ARGUMENT_RETURN(arg, value) \ + _gcmVERIFY_ARGUMENT_RETURN(gcm, arg, value) +# define gcmkVERIFY_ARGUMENT_RETURN(arg, value) \ + _gcmVERIFY_ARGUMENT_RETURN(gcmk, arg, value) +#else +# define gcmVERIFY_ARGUMENT_RETURN(arg, value) +# define gcmkVERIFY_ARGUMENT_RETURN(arg, value) +#endif +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_base_h_ */ + diff --git a/drivers/staging/rk29/vivante/hal/inc/gc_hal_compiler.h b/drivers/staging/rk29/vivante/hal/inc/gc_hal_compiler.h new file mode 100644 index 000000000000..6bc96b24bd1c --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/inc/gc_hal_compiler.h @@ -0,0 +1,1841 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +/* +** Include file the defines the front- and back-end compilers, as well as the +** objects they use. +*/ + +#ifndef __gc_hal_compiler_h_ +#define __gc_hal_compiler_h_ + +#include "gc_hal_types.h" +#include "gc_hal_engine.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************\ +|******************************* SHADER LANGUAGE ******************************| +\******************************************************************************/ + +/* Possible shader language opcodes. */ +typedef enum _gcSL_OPCODE +{ + gcSL_NOP, /* 0x00 */ + gcSL_MOV, /* 0x01 */ + gcSL_SAT, /* 0x02 */ + gcSL_DP3, /* 0x03 */ + gcSL_DP4, /* 0x04 */ + gcSL_ABS, /* 0x05 */ + gcSL_JMP, /* 0x06 */ + gcSL_ADD, /* 0x07 */ + gcSL_MUL, /* 0x08 */ + gcSL_RCP, /* 0x09 */ + gcSL_SUB, /* 0x0A */ + gcSL_KILL, /* 0x0B */ + gcSL_TEXLD, /* 0x0C */ + gcSL_CALL, /* 0x0D */ + gcSL_RET, /* 0x0E */ + gcSL_NORM, /* 0x0F */ + gcSL_MAX, /* 0x10 */ + gcSL_MIN, /* 0x11 */ + gcSL_POW, /* 0x12 */ + gcSL_RSQ, /* 0x13 */ + gcSL_LOG, /* 0x14 */ + gcSL_FRAC, /* 0x15 */ + gcSL_FLOOR, /* 0x16 */ + gcSL_CEIL, /* 0x17 */ + gcSL_CROSS, /* 0x18 */ + gcSL_TEXLDP, /* 0x19 */ + gcSL_TEXBIAS, /* 0x1A */ + gcSL_TEXGRAD, /* 0x1B */ + gcSL_TEXLOD, /* 0x1C */ + gcSL_SIN, /* 0x1D */ + gcSL_COS, /* 0x1E */ + gcSL_TAN, /* 0x1F */ + gcSL_EXP, /* 0x20 */ + gcSL_SIGN, /* 0x21 */ + gcSL_STEP, /* 0x22 */ + gcSL_SQRT, /* 0x23 */ + gcSL_ACOS, /* 0x24 */ + gcSL_ASIN, /* 0x25 */ + gcSL_ATAN, /* 0x26 */ + gcSL_SET, /* 0x27 */ + gcSL_DSX, /* 0x28 */ + gcSL_DSY, /* 0x29 */ + gcSL_FWIDTH, /* 0x2A */ +} +gcSL_OPCODE; + +typedef enum _gcSL_FORMAT +{ + gcSL_FLOAT, /* 0 */ + gcSL_INTEGER, /* 1 */ + gcSL_BOOLEAN, /* 2 */ +} +gcSL_FORMAT; + +/* Destination write enable bits. */ +typedef enum _gcSL_ENABLE +{ + gcSL_ENABLE_X = 0x1, + gcSL_ENABLE_Y = 0x2, + gcSL_ENABLE_Z = 0x4, + gcSL_ENABLE_W = 0x8, + /* Combinations. */ + gcSL_ENABLE_XY = gcSL_ENABLE_X | gcSL_ENABLE_Y, + gcSL_ENABLE_XYZ = gcSL_ENABLE_X | gcSL_ENABLE_Y | gcSL_ENABLE_Z, + gcSL_ENABLE_XYZW = gcSL_ENABLE_X | gcSL_ENABLE_Y | gcSL_ENABLE_Z | gcSL_ENABLE_W, + gcSL_ENABLE_XYW = gcSL_ENABLE_X | gcSL_ENABLE_Y | gcSL_ENABLE_W, + gcSL_ENABLE_XZ = gcSL_ENABLE_X | gcSL_ENABLE_Z, + gcSL_ENABLE_XZW = gcSL_ENABLE_X | gcSL_ENABLE_Z | gcSL_ENABLE_W, + gcSL_ENABLE_XW = gcSL_ENABLE_X | gcSL_ENABLE_W, + gcSL_ENABLE_YZ = gcSL_ENABLE_Y | gcSL_ENABLE_Z, + gcSL_ENABLE_YZW = gcSL_ENABLE_Y | gcSL_ENABLE_Z | gcSL_ENABLE_W, + gcSL_ENABLE_YW = gcSL_ENABLE_Y | gcSL_ENABLE_W, + gcSL_ENABLE_ZW = gcSL_ENABLE_Z | gcSL_ENABLE_W, +} +gcSL_ENABLE; + +/* Possible indices. */ +typedef enum _gcSL_INDEXED +{ + gcSL_NOT_INDEXED, /* 0 */ + gcSL_INDEXED_X, /* 1 */ + gcSL_INDEXED_Y, /* 2 */ + gcSL_INDEXED_Z, /* 3 */ + gcSL_INDEXED_W, /* 4 */ +} +gcSL_INDEXED; + +/* Opcode conditions. */ +typedef enum _gcSL_CONDITION +{ + gcSL_ALWAYS, /* 0x0 */ + gcSL_NOT_EQUAL, /* 0x1 */ + gcSL_LESS_OR_EQUAL, /* 0x2 */ + gcSL_LESS, /* 0x3 */ + gcSL_EQUAL, /* 0x4 */ + gcSL_GREATER, /* 0x5 */ + gcSL_GREATER_OR_EQUAL, /* 0x6 */ + gcSL_AND, /* 0x7 */ + gcSL_OR, /* 0x8 */ + gcSL_XOR, /* 0x9 */ +} +gcSL_CONDITION; + +/* Possible source operand types. */ +typedef enum _gcSL_TYPE +{ + gcSL_NONE, /* 0x0 */ + gcSL_TEMP, /* 0x1 */ + gcSL_ATTRIBUTE, /* 0x2 */ + gcSL_UNIFORM, /* 0x3 */ + gcSL_SAMPLER, /* 0x4 */ + gcSL_CONSTANT, /* 0x5 */ + gcSL_OUTPUT, /* 0x6 */ + gcSL_PHYSICAL, /* 0x7 */ +} +gcSL_TYPE; + +/* Swizzle generator macro. */ +#define gcmSWIZZLE(Component1, Component2, Component3, Component4) \ +( \ + (gcSL_SWIZZLE_ ## Component1 << 0) | \ + (gcSL_SWIZZLE_ ## Component2 << 2) | \ + (gcSL_SWIZZLE_ ## Component3 << 4) | \ + (gcSL_SWIZZLE_ ## Component4 << 6) \ +) + +/* Possible swizzle values. */ +typedef enum _gcSL_SWIZZLE +{ + gcSL_SWIZZLE_X, /* 0x0 */ + gcSL_SWIZZLE_Y, /* 0x1 */ + gcSL_SWIZZLE_Z, /* 0x2 */ + gcSL_SWIZZLE_W, /* 0x3 */ + /* Combinations. */ + gcSL_SWIZZLE_XXXX = gcmSWIZZLE(X, X, X, X), + gcSL_SWIZZLE_YYYY = gcmSWIZZLE(Y, Y, Y, Y), + gcSL_SWIZZLE_ZZZZ = gcmSWIZZLE(Z, Z, Z, Z), + gcSL_SWIZZLE_WWWW = gcmSWIZZLE(W, W, W, W), + gcSL_SWIZZLE_XYYY = gcmSWIZZLE(X, Y, Y, Y), + gcSL_SWIZZLE_XZZZ = gcmSWIZZLE(X, Z, Z, Z), + gcSL_SWIZZLE_XWWW = gcmSWIZZLE(X, W, W, W), + gcSL_SWIZZLE_YZZZ = gcmSWIZZLE(Y, Z, Z, Z), + gcSL_SWIZZLE_YWWW = gcmSWIZZLE(Y, W, W, W), + gcSL_SWIZZLE_ZWWW = gcmSWIZZLE(Z, W, W, W), + gcSL_SWIZZLE_XYZZ = gcmSWIZZLE(X, Y, Z, Z), + gcSL_SWIZZLE_XYWW = gcmSWIZZLE(X, Y, W, W), + gcSL_SWIZZLE_XZWW = gcmSWIZZLE(X, Z, W, W), + gcSL_SWIZZLE_YZWW = gcmSWIZZLE(Y, Z, W, W), + gcSL_SWIZZLE_XXYZ = gcmSWIZZLE(X, X, Y, Z), + gcSL_SWIZZLE_XYZW = gcmSWIZZLE(X, Y, Z, W), + gcSL_SWIZZLE_XYXY = gcmSWIZZLE(X, Y, X, Y), +} +gcSL_SWIZZLE; + + +/******************************************************************************\ +|*********************************** SHADERS **********************************| +\******************************************************************************/ + +/* Shader types. */ +#define gcSHADER_TYPE_UNKNOWN 0 +#define gcSHADER_TYPE_VERTEX 1 +#define gcSHADER_TYPE_FRAGMENT 2 + +/* gcSHADER objects. */ +typedef struct _gcSHADER * gcSHADER; +typedef struct _gcATTRIBUTE * gcATTRIBUTE; +typedef struct _gcUNIFORM * gcUNIFORM; +typedef struct _gcOUTPUT * gcOUTPUT; +typedef struct _gcsFUNCTION * gcFUNCTION; +typedef struct _gcsHINT * gcsHINT_PTR; +typedef struct _gcSHADER_PROFILER * gcSHADER_PROFILER; +typedef struct _gcVARIABLE * gcVARIABLE; + +/* gcSHADER_TYPE enumeration. */ +typedef enum _gcSHADER_TYPE +{ + gcSHADER_FLOAT_X1, /* 0x00 */ + gcSHADER_FLOAT_X2, /* 0x01 */ + gcSHADER_FLOAT_X3, /* 0x02 */ + gcSHADER_FLOAT_X4, /* 0x03 */ + gcSHADER_FLOAT_2X2, /* 0x04 */ + gcSHADER_FLOAT_3X3, /* 0x05 */ + gcSHADER_FLOAT_4X4, /* 0x06 */ + gcSHADER_BOOLEAN_X1, /* 0x07 */ + gcSHADER_BOOLEAN_X2, /* 0x08 */ + gcSHADER_BOOLEAN_X3, /* 0x09 */ + gcSHADER_BOOLEAN_X4, /* 0x0A */ + gcSHADER_INTEGER_X1, /* 0x0B */ + gcSHADER_INTEGER_X2, /* 0x0C */ + gcSHADER_INTEGER_X3, /* 0x0D */ + gcSHADER_INTEGER_X4, /* 0x0E */ + gcSHADER_SAMPLER_1D, /* 0x0F */ + gcSHADER_SAMPLER_2D, /* 0x10 */ + gcSHADER_SAMPLER_3D, /* 0x11 */ + gcSHADER_SAMPLER_CUBIC, /* 0x12 */ + gcSHADER_FIXED_X1, /* 0x13 */ + gcSHADER_FIXED_X2, /* 0x14 */ + gcSHADER_FIXED_X3, /* 0x15 */ + gcSHADER_FIXED_X4, /* 0x16 */ +} +gcSHADER_TYPE; + +/* Shader flags. */ +typedef enum _gceSHADER_FLAGS +{ + gcvSHADER_DEAD_CODE = 0x01, + gcvSHADER_RESOURCE_USAGE = 0x02, + gcvSHADER_OPTIMIZER = 0x04, + gcvSHADER_USE_GL_Z = 0x08, + gcvSHADER_USE_GL_POSITION = 0x10, + gcvSHADER_USE_GL_FACE = 0x20, + gcvSHADER_USE_GL_POINT_COORD = 0x40, +} +gceSHADER_FLAGS; + +/* Function argument qualifier */ +typedef enum _gceINPUT_OUTPUT +{ + gcvFUNCTION_INPUT, + gcvFUNCTION_OUTPUT, + gcvFUNCTION_INOUT +} +gceINPUT_OUTPUT; + +/******************************************************************************* +** gcSHADER_Construct +******************************************************************************** +** +** Construct a new gcSHADER object. +** +** INPUT: +** +** gcoOS Hal +** Pointer to an gcoHAL object. +** +** gctINT ShaderType +** Type of gcSHADER object to cerate. 'ShaderType' can be one of the +** following: +** +** gcSHADER_TYPE_VERTEX Vertex shader. +** gcSHADER_TYPE_FRAGMENT Fragment shader. +** +** OUTPUT: +** +** gcSHADER * Shader +** Pointer to a variable receiving the gcSHADER object pointer. +*/ +gceSTATUS +gcSHADER_Construct( + IN gcoHAL Hal, + IN gctINT ShaderType, + OUT gcSHADER * Shader + ); + +/******************************************************************************* +** gcSHADER_Destroy +******************************************************************************** +** +** Destroy a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_Destroy( + IN gcSHADER Shader + ); + +/******************************************************************************* +** gcSHADER_Load +******************************************************************************** +** +** Load a gcSHADER object from a binary buffer. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctPOINTER Buffer +** Pointer to a binary buffer containg the shader data to load. +** +** gctSIZE_T BufferSize +** Number of bytes inside the binary buffer pointed to by 'Buffer'. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_Load( + IN gcSHADER Shader, + IN gctPOINTER Buffer, + IN gctSIZE_T BufferSize + ); + +/******************************************************************************* +** gcSHADER_Save +******************************************************************************** +** +** Save a gcSHADER object to a binary buffer. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctPOINTER Buffer +** Pointer to a binary buffer to be used as storage for the gcSHADER +** object. If 'Buffer' is gcvNULL, the gcSHADER object will not be saved, +** but the number of bytes required to hold the binary output for the +** gcSHADER object will be returned. +** +** gctSIZE_T * BufferSize +** Pointer to a variable holding the number of bytes allocated in +** 'Buffer'. Only valid if 'Buffer' is not gcvNULL. +** +** OUTPUT: +** +** gctSIZE_T * BufferSize +** Pointer to a variable receiving the number of bytes required to hold +** the binary form of the gcSHADER object. +*/ +gceSTATUS +gcSHADER_Save( + IN gcSHADER Shader, + IN gctPOINTER Buffer, + IN OUT gctSIZE_T * BufferSize + ); + +/******************************************************************************* +** gcSHADER_AddAttribute +******************************************************************************** +** +** Add an attribute to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctCONST_STRING Name +** Name of the attribute to add. +** +** gcSHADER_TYPE Type +** Type of the attribute to add. +** +** gctSIZE_T Length +** Array length of the attribute to add. 'Length' must be at least 1. +** +** gctBOOL IsTexture +** gcvTRUE if the attribute is used as a texture coordinate, gcvFALSE if not. +** +** OUTPUT: +** +** gcATTRIBUTE * Attribute +** Pointer to a variable receiving the gcATTRIBUTE object pointer. +*/ +gceSTATUS +gcSHADER_AddAttribute( + IN gcSHADER Shader, + IN gctCONST_STRING Name, + IN gcSHADER_TYPE Type, + IN gctSIZE_T Length, + IN gctBOOL IsTexture, + OUT gcATTRIBUTE * Attribute + ); + +/******************************************************************************* +** gcSHADER_GetAttributeCount +******************************************************************************** +** +** Get the number of attributes for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** gctSIZE_T * Count +** Pointer to a variable receiving the number of attributes. +*/ +gceSTATUS +gcSHADER_GetAttributeCount( + IN gcSHADER Shader, + OUT gctSIZE_T * Count + ); + +/******************************************************************************* +** gcSHADER_GetAttribute +******************************************************************************** +** +** Get the gcATTRIBUTE object poniter for an indexed attribute for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctUINT Index +** Index of the attribute to retrieve. +** +** OUTPUT: +** +** gcATTRIBUTE * Attribute +** Pointer to a variable receiving the gcATTRIBUTE object pointer. +*/ +gceSTATUS +gcSHADER_GetAttribute( + IN gcSHADER Shader, + IN gctUINT Index, + OUT gcATTRIBUTE * Attribute + ); + +/******************************************************************************* +** gcSHADER_GetPositionAttribute +******************************************************************************** +** +** Get the gcATTRIBUTE object pointer for the attribute that defines the +** position. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** gctUINT * Index +** Pointer to a variable receiving the index of te gcATTRIBUTE object +** used as a position. +** +** gcATTRIBUTE * Attribute +** Pointer to a variable receiving the gcATTRIBUTE object pointer. +*/ +gceSTATUS +gcSHADER_GetPositionAttribute( + IN gcSHADER Shader, + OUT gctUINT * Index, + OUT gcATTRIBUTE * Attribute + ); + +/******************************************************************************* +** gcSHADER_AddUniform +******************************************************************************** +** +** Add an uniform to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctCONST_STRING Name +** Name of the uniform to add. +** +** gcSHADER_TYPE Type +** Type of the uniform to add. +** +** gctSIZE_T Length +** Array length of the uniform to add. 'Length' must be at least 1. +** +** OUTPUT: +** +** gcUNIFORM * Uniform +** Pointer to a variable receiving the gcUNIFORM object pointer. +*/ +gceSTATUS +gcSHADER_AddUniform( + IN gcSHADER Shader, + IN gctCONST_STRING Name, + IN gcSHADER_TYPE Type, + IN gctSIZE_T Length, + OUT gcUNIFORM * Uniform + ); + +/******************************************************************************* +** gcSHADER_GetUniformCount +******************************************************************************** +** +** Get the number of uniforms for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** gctSIZE_T * Count +** Pointer to a variable receiving the number of uniforms. +*/ +gceSTATUS +gcSHADER_GetUniformCount( + IN gcSHADER Shader, + OUT gctSIZE_T * Count + ); + +/******************************************************************************* +** gcSHADER_GetUniform +******************************************************************************** +** +** Get the gcUNIFORM object pointer for an indexed uniform for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctUINT Index +** Index of the uniform to retrieve. +** +** OUTPUT: +** +** gcUNIFORM * Uniform +** Pointer to a variable receiving the gcUNIFORM object pointer. +*/ +gceSTATUS +gcSHADER_GetUniform( + IN gcSHADER Shader, + IN gctUINT Index, + OUT gcUNIFORM * Uniform + ); + +/******************************************************************************* +** gcSHADER_AddOutput +******************************************************************************** +** +** Add an output to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctCONST_STRING Name +** Name of the output to add. +** +** gcSHADER_TYPE Type +** Type of the output to add. +** +** gctSIZE_T Length +** Array length of the output to add. 'Length' must be at least 1. +** +** gctUINT16 TempRegister +** Temporary register index that holds the output value. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddOutput( + IN gcSHADER Shader, + IN gctCONST_STRING Name, + IN gcSHADER_TYPE Type, + IN gctSIZE_T Length, + IN gctUINT16 TempRegister + ); + +gceSTATUS +gcSHADER_AddOutputIndexed( + IN gcSHADER Shader, + IN gctCONST_STRING Name, + IN gctSIZE_T Index, + IN gctUINT16 TempIndex + ); + +/******************************************************************************* +** gcSHADER_GetOutputCount +******************************************************************************** +** +** Get the number of outputs for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** gctSIZE_T * Count +** Pointer to a variable receiving the number of outputs. +*/ +gceSTATUS +gcSHADER_GetOutputCount( + IN gcSHADER Shader, + OUT gctSIZE_T * Count + ); + +/******************************************************************************* +** gcSHADER_GetOutput +******************************************************************************** +** +** Get the gcOUTPUT object pointer for an indexed output for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctUINT Index +** Index of output to retrieve. +** +** OUTPUT: +** +** gcOUTPUT * Output +** Pointer to a variable receiving the gcOUTPUT object pointer. +*/ +gceSTATUS +gcSHADER_GetOutput( + IN gcSHADER Shader, + IN gctUINT Index, + OUT gcOUTPUT * Output + ); + +/******************************************************************************* +** gcSHADER_AddVariable +******************************************************************************** +** +** Add a variable to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctCONST_STRING Name +** Name of the variable to add. +** +** gcSHADER_TYPE Type +** Type of the variable to add. +** +** gctSIZE_T Length +** Array length of the variable to add. 'Length' must be at least 1. +** +** gctUINT16 TempRegister +** Temporary register index that holds the variable value. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddVariable( + IN gcSHADER Shader, + IN gctCONST_STRING Name, + IN gcSHADER_TYPE Type, + IN gctSIZE_T Length, + IN gctUINT16 TempRegister + ); + +/******************************************************************************* +** gcSHADER_GetVariableCount +******************************************************************************** +** +** Get the number of variables for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** gctSIZE_T * Count +** Pointer to a variable receiving the number of variables. +*/ +gceSTATUS +gcSHADER_GetVariableCount( + IN gcSHADER Shader, + OUT gctSIZE_T * Count + ); + +/******************************************************************************* +** gcSHADER_GetVariable +******************************************************************************** +** +** Get the gcVARIABLE object pointer for an indexed variable for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctUINT Index +** Index of variable to retrieve. +** +** OUTPUT: +** +** gcVARIABLE * Variable +** Pointer to a variable receiving the gcVARIABLE object pointer. +*/ +gceSTATUS +gcSHADER_GetVariable( + IN gcSHADER Shader, + IN gctUINT Index, + OUT gcVARIABLE * Variable + ); + +/******************************************************************************* +** gcSHADER_AddOpcode +******************************************************************************** +** +** Add an opcode to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcSL_OPCODE Opcode +** Opcode to add. +** +** gctUINT16 TempRegister +** Temporary register index that acts as the target of the opcode. +** +** gctUINT8 Enable +** Write enable bits for the temporary register that acts as the target +** of the opcode. +** +** gcSL_FORMAT Format +** Format of the temporary register. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddOpcode( + IN gcSHADER Shader, + IN gcSL_OPCODE Opcode, + IN gctUINT16 TempRegister, + IN gctUINT8 Enable, + IN gcSL_FORMAT Format + ); + +gceSTATUS +gcSHADER_AddOpcode2( + IN gcSHADER Shader, + IN gcSL_OPCODE Opcode, + IN gcSL_CONDITION Condition, + IN gctUINT16 TempRegister, + IN gctUINT8 Enable, + IN gcSL_FORMAT Format + ); + +/******************************************************************************* +** gcSHADER_AddOpcodeIndexed +******************************************************************************** +** +** Add an opcode to a gcSHADER object that writes to an dynamically indexed +** target. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcSL_OPCODE Opcode +** Opcode to add. +** +** gctUINT16 TempRegister +** Temporary register index that acts as the target of the opcode. +** +** gctUINT8 Enable +** Write enable bits for the temporary register that acts as the +** target of the opcode. +** +** gcSL_INDEXED Mode +** Location of the dynamic index inside the temporary register. Valid +** values can be: +** +** gcSL_INDEXED_X - Use x component of the temporary register. +** gcSL_INDEXED_Y - Use y component of the temporary register. +** gcSL_INDEXED_Z - Use z component of the temporary register. +** gcSL_INDEXED_W - Use w component of the temporary register. +** +** gctUINT16 IndexRegister +** Temporary register index that holds the dynamic index. +** +** gcSL_FORMAT Format +** Format of the temporary register. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddOpcodeIndexed( + IN gcSHADER Shader, + IN gcSL_OPCODE Opcode, + IN gctUINT16 TempRegister, + IN gctUINT8 Enable, + IN gcSL_INDEXED Mode, + IN gctUINT16 IndexRegister, + IN gcSL_FORMAT Format + ); + +/******************************************************************************* +** gcSHADER_AddOpcodeConditional +******************************************************************************** +** +** Add an conditional opcode to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcSL_OPCODE Opcode +** Opcode to add. +** +** gcSL_CONDITION Condition +** Condition that needs to evaluate to gcvTRUE in order for the opcode to +** execute. +** +** gctUINT Label +** Target label if 'Condition' evaluates to gcvTRUE. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddOpcodeConditional( + IN gcSHADER Shader, + IN gcSL_OPCODE Opcode, + IN gcSL_CONDITION Condition, + IN gctUINT Label + ); + +/******************************************************************************* +** gcSHADER_AddLabel +******************************************************************************** +** +** Define a label at the current instruction of a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctUINT Label +** Label to define. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddLabel( + IN gcSHADER Shader, + IN gctUINT Label + ); + +/******************************************************************************* +** gcSHADER_AddSource +******************************************************************************** +** +** Add a source operand to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcSL_TYPE Type +** Type of the source operand. +** +** gctUINT16 SourceIndex +** Index of the source operand. +** +** gctUINT8 Swizzle +** x, y, z, and w swizzle values packed into one 8-bit value. +** +** gcSL_FORMAT Format +** Format of the source operand. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddSource( + IN gcSHADER Shader, + IN gcSL_TYPE Type, + IN gctUINT16 SourceIndex, + IN gctUINT8 Swizzle, + IN gcSL_FORMAT Format + ); + +/******************************************************************************* +** gcSHADER_AddSourceIndexed +******************************************************************************** +** +** Add a dynamically indexed source operand to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcSL_TYPE Type +** Type of the source operand. +** +** gctUINT16 SourceIndex +** Index of the source operand. +** +** gctUINT8 Swizzle +** x, y, z, and w swizzle values packed into one 8-bit value. +** +** gcSL_INDEXED Mode +** Addressing mode for the index. +** +** gctUINT16 IndexRegister +** Temporary register index that holds the dynamic index. +** +** gcSL_FORMAT Format +** Format of the source operand. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddSourceIndexed( + IN gcSHADER Shader, + IN gcSL_TYPE Type, + IN gctUINT16 SourceIndex, + IN gctUINT8 Swizzle, + IN gcSL_INDEXED Mode, + IN gctUINT16 IndexRegister, + IN gcSL_FORMAT Format + ); + +/******************************************************************************* +** gcSHADER_AddSourceAttribute +******************************************************************************** +** +** Add an attribute as a source operand to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcATTRIBUTE Attribute +** Pointer to a gcATTRIBUTE object. +** +** gctUINT8 Swizzle +** x, y, z, and w swizzle values packed into one 8-bit value. +** +** gctINT Index +** Static index into the attribute in case the attribute is a matrix +** or array. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddSourceAttribute( + IN gcSHADER Shader, + IN gcATTRIBUTE Attribute, + IN gctUINT8 Swizzle, + IN gctINT Index + ); + +/******************************************************************************* +** gcSHADER_AddSourceAttributeIndexed +******************************************************************************** +** +** Add an indexed attribute as a source operand to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcATTRIBUTE Attribute +** Pointer to a gcATTRIBUTE object. +** +** gctUINT8 Swizzle +** x, y, z, and w swizzle values packed into one 8-bit value. +** +** gctINT Index +** Static index into the attribute in case the attribute is a matrix +** or array. +** +** gcSL_INDEXED Mode +** Addressing mode of the dynamic index. +** +** gctUINT16 IndexRegister +** Temporary register index that holds the dynamic index. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddSourceAttributeIndexed( + IN gcSHADER Shader, + IN gcATTRIBUTE Attribute, + IN gctUINT8 Swizzle, + IN gctINT Index, + IN gcSL_INDEXED Mode, + IN gctUINT16 IndexRegister + ); + +/******************************************************************************* +** gcSHADER_AddSourceUniform +******************************************************************************** +** +** Add a uniform as a source operand to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** gctUINT8 Swizzle +** x, y, z, and w swizzle values packed into one 8-bit value. +** +** gctINT Index +** Static index into the uniform in case the uniform is a matrix or +** array. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddSourceUniform( + IN gcSHADER Shader, + IN gcUNIFORM Uniform, + IN gctUINT8 Swizzle, + IN gctINT Index + ); + +/******************************************************************************* +** gcSHADER_AddSourceUniformIndexed +******************************************************************************** +** +** Add an indexed uniform as a source operand to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** gctUINT8 Swizzle +** x, y, z, and w swizzle values packed into one 8-bit value. +** +** gctINT Index +** Static index into the uniform in case the uniform is a matrix or +** array. +** +** gcSL_INDEXED Mode +** Addressing mode of the dynamic index. +** +** gctUINT16 IndexRegister +** Temporary register index that holds the dynamic index. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddSourceUniformIndexed( + IN gcSHADER Shader, + IN gcUNIFORM Uniform, + IN gctUINT8 Swizzle, + IN gctINT Index, + IN gcSL_INDEXED Mode, + IN gctUINT16 IndexRegister + ); + +gceSTATUS +gcSHADER_AddSourceSamplerIndexed( + IN gcSHADER Shader, + IN gctUINT8 Swizzle, + IN gcSL_INDEXED Mode, + IN gctUINT16 IndexRegister + ); + +/******************************************************************************* +** gcSHADER_AddSourceConstant +******************************************************************************** +** +** Add a constant floating pointer value as a source operand to a gcSHADER +** object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctFLOAT Constant +** Floating pointer constant. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddSourceConstant( + IN gcSHADER Shader, + IN gctFLOAT Constant + ); + +/******************************************************************************* +** gcSHADER_Pack +******************************************************************************** +** +** Pack a dynamically created gcSHADER object by trimming the allocated arrays +** and resolving all the labeling. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_Pack( + IN gcSHADER Shader + ); + +/******************************************************************************* +** gcSHADER_SetOptimizationOption +******************************************************************************** +** +** Set optimization option of a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctUINT OptimizationOption +** Optimization option. Can be one of the following: +** +** 0 - No optimization. +** 1 - Full optimization. +** Other value - For optimizer testing. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_SetOptimizationOption( + IN gcSHADER Shader, + IN gctUINT OptimizationOption + ); + +gceSTATUS +gcSHADER_AddFunction( + IN gcSHADER Shader, + IN gctCONST_STRING Name, + OUT gcFUNCTION * Function + ); + +gceSTATUS +gcSHADER_BeginFunction( + IN gcSHADER Shader, + IN gcFUNCTION Function + ); + +gceSTATUS +gcSHADER_EndFunction( + IN gcSHADER Shader, + IN gcFUNCTION Function + ); + +/******************************************************************************* +** gcATTRIBUTE_GetType +******************************************************************************** +** +** Get the type and array length of a gcATTRIBUTE object. +** +** INPUT: +** +** gcATTRIBUTE Attribute +** Pointer to a gcATTRIBUTE object. +** +** OUTPUT: +** +** gcSHADER_TYPE * Type +** Pointer to a variable receiving the type of the attribute. 'Type' +** can be gcvNULL, in which case no type will be returned. +** +** gctSIZE_T * ArrayLength +** Pointer to a variable receiving the length of the array if the +** attribute was declared as an array. If the attribute was not +** declared as an array, the array length will be 1. 'ArrayLength' can +** be gcvNULL, in which case no array length will be returned. +*/ +gceSTATUS +gcATTRIBUTE_GetType( + IN gcATTRIBUTE Attribute, + OUT gcSHADER_TYPE * Type, + OUT gctSIZE_T * ArrayLength + ); + +/******************************************************************************* +** gcATTRIBUTE_GetName +******************************************************************************** +** +** Get the name of a gcATTRIBUTE object. +** +** INPUT: +** +** gcATTRIBUTE Attribute +** Pointer to a gcATTRIBUTE object. +** +** OUTPUT: +** +** gctSIZE_T * Length +** Pointer to a variable receiving the length of the attribute name. +** 'Length' can be gcvNULL, in which case no length will be returned. +** +** gctCONST_STRING * Name +** Pointer to a variable receiving the pointer to the attribute name. +** 'Name' can be gcvNULL, in which case no name will be returned. +*/ +gceSTATUS +gcATTRIBUTE_GetName( + IN gcATTRIBUTE Attribute, + OUT gctSIZE_T * Length, + OUT gctCONST_STRING * Name + ); + +/******************************************************************************* +** gcATTRIBUTE_IsEnabled +******************************************************************************** +** +** Query the enabled state of a gcATTRIBUTE object. +** +** INPUT: +** +** gcATTRIBUTE Attribute +** Pointer to a gcATTRIBUTE object. +** +** OUTPUT: +** +** gctBOOL * Enabled +** Pointer to a variable receiving the enabled state of the attribute. +*/ +gceSTATUS +gcATTRIBUTE_IsEnabled( + IN gcATTRIBUTE Attribute, + OUT gctBOOL * Enabled + ); + +/******************************************************************************* +** gcUNIFORM_GetType +******************************************************************************** +** +** Get the type and array length of a gcUNIFORM object. +** +** INPUT: +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** OUTPUT: +** +** gcSHADER_TYPE * Type +** Pointer to a variable receiving the type of the uniform. 'Type' can +** be gcvNULL, in which case no type will be returned. +** +** gctSIZE_T * ArrayLength +** Pointer to a variable receiving the length of the array if the +** uniform was declared as an array. If the uniform was not declared +** as an array, the array length will be 1. 'ArrayLength' can be gcvNULL, +** in which case no array length will be returned. +*/ +gceSTATUS +gcUNIFORM_GetType( + IN gcUNIFORM Uniform, + OUT gcSHADER_TYPE * Type, + OUT gctSIZE_T * ArrayLength + ); + +/******************************************************************************* +** gcUNIFORM_GetName +******************************************************************************** +** +** Get the name of a gcUNIFORM object. +** +** INPUT: +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** OUTPUT: +** +** gctSIZE_T * Length +** Pointer to a variable receiving the length of the uniform name. +** 'Length' can be gcvNULL, in which case no length will be returned. +** +** gctCONST_STRING * Name +** Pointer to a variable receiving the pointer to the uniform name. +** 'Name' can be gcvNULL, in which case no name will be returned. +*/ +gceSTATUS +gcUNIFORM_GetName( + IN gcUNIFORM Uniform, + OUT gctSIZE_T * Length, + OUT gctCONST_STRING * Name + ); + +/******************************************************************************* +** gcUNIFORM_GetSampler +******************************************************************************** +** +** Get the physical sampler number for a sampler gcUNIFORM object. +** +** INPUT: +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** OUTPUT: +** +** gctUINT32 * Sampler +** Pointer to a variable receiving the physical sampler. +*/ +gceSTATUS +gcUNIFORM_GetSampler( + IN gcUNIFORM Uniform, + OUT gctUINT32 * Sampler + ); + +/******************************************************************************* +** gcUNIFORM_SetValue +******************************************************************************** +** +** Set the value of a uniform in integer. +** +** INPUT: +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** gctSIZE_T Count +** Number of entries to program if the uniform has been declared as an +** array. +** +** const gctINT * Value +** Pointer to a buffer holding the integer values for the uniform. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcUNIFORM_SetValue( + IN gcUNIFORM Uniform, + IN gctSIZE_T Count, + IN const gctINT * Value + ); + +/******************************************************************************* +** gcUNIFORM_SetValueX +******************************************************************************** +** +** Set the value of a uniform in fixed point. +** +** INPUT: +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** gctSIZE_T Count +** Number of entries to program if the uniform has been declared as an +** array. +** +** const gctFIXED_POINT * Value +** Pointer to a buffer holding the fixed point values for the uniform. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcUNIFORM_SetValueX( + IN gcUNIFORM Uniform, + IN gctSIZE_T Count, + IN gctFIXED_POINT * Value + ); + +/******************************************************************************* +** gcUNIFORM_SetValueF +******************************************************************************** +** +** Set the value of a uniform in floating point. +** +** INPUT: +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** gctSIZE_T Count +** Number of entries to program if the uniform has been declared as an +** array. +** +** const gctFLOAT * Value +** Pointer to a buffer holding the floating point values for the +** uniform. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcUNIFORM_SetValueF( + IN gcUNIFORM Uniform, + IN gctSIZE_T Count, + IN const gctFLOAT * Value + ); + +/******************************************************************************* +** gcOUTPUT_GetType +******************************************************************************** +** +** Get the type and array length of a gcOUTPUT object. +** +** INPUT: +** +** gcOUTPUT Output +** Pointer to a gcOUTPUT object. +** +** OUTPUT: +** +** gcSHADER_TYPE * Type +** Pointer to a variable receiving the type of the output. 'Type' can +** be gcvNULL, in which case no type will be returned. +** +** gctSIZE_T * ArrayLength +** Pointer to a variable receiving the length of the array if the +** output was declared as an array. If the output was not declared +** as an array, the array length will be 1. 'ArrayLength' can be gcvNULL, +** in which case no array length will be returned. +*/ +gceSTATUS +gcOUTPUT_GetType( + IN gcOUTPUT Output, + OUT gcSHADER_TYPE * Type, + OUT gctSIZE_T * ArrayLength + ); + +/******************************************************************************* +** gcOUTPUT_GetIndex +******************************************************************************** +** +** Get the index of a gcOUTPUT object. +** +** INPUT: +** +** gcOUTPUT Output +** Pointer to a gcOUTPUT object. +** +** OUTPUT: +** +** gctUINT * Index +** Pointer to a variable receiving the temporary register index of the +** output. 'Index' can be gcvNULL,. in which case no index will be +** returned. +*/ +gceSTATUS +gcOUTPUT_GetIndex( + IN gcOUTPUT Output, + OUT gctUINT * Index + ); + +/******************************************************************************* +** gcOUTPUT_GetName +******************************************************************************** +** +** Get the name of a gcOUTPUT object. +** +** INPUT: +** +** gcOUTPUT Output +** Pointer to a gcOUTPUT object. +** +** OUTPUT: +** +** gctSIZE_T * Length +** Pointer to a variable receiving the length of the output name. +** 'Length' can be gcvNULL, in which case no length will be returned. +** +** gctCONST_STRING * Name +** Pointer to a variable receiving the pointer to the output name. +** 'Name' can be gcvNULL, in which case no name will be returned. +*/ +gceSTATUS +gcOUTPUT_GetName( + IN gcOUTPUT Output, + OUT gctSIZE_T * Length, + OUT gctCONST_STRING * Name + ); + +/******************************************************************************* +*********************************************************** F U N C T I O N S ** +*******************************************************************************/ + +gceSTATUS +gcFUNCTION_AddArgument( + IN gcFUNCTION Function, + IN gctUINT16 TempIndex, + IN gctUINT8 Enable, + IN gctUINT8 Qualifier + ); + +gceSTATUS +gcFUNCTION_GetArgument( + IN gcFUNCTION Function, + IN gctUINT16 Index, + OUT gctUINT16_PTR Temp, + OUT gctUINT8_PTR Enable, + OUT gctUINT8_PTR Swizzle + ); + +gceSTATUS +gcFUNCTION_GetLabel( + IN gcFUNCTION Function, + OUT gctUINT_PTR Label + ); + +/******************************************************************************* +** gcCompileShader +******************************************************************************** +** +** Compile a shader. +** +** INPUT: +** +** gcoOS Hal +** Pointer to an gcoHAL object. +** +** gctINT ShaderType +** Shader type to compile. Can be one of the following values: +** +** gcSHADER_TYPE_VERTEX +** Compile a vertex shader. +** +** gcSHADER_TYPE_FRAGMENT +** Compile a fragment shader. +** +** gctSIZE_T SourceSize +** Size of the source buffer in bytes. +** +** gctCONST_STRING Source +** Pointer to the buffer containing the shader source code. +** +** OUTPUT: +** +** gcSHADER * Binary +** Pointer to a variable receiving the pointer to a gcSHADER object +** containg the compiled shader code. +** +** gctSTRING * Log +** Pointer to a variable receiving a string pointer containging the +** compile log. +*/ +gceSTATUS +gcCompileShader( + IN gcoHAL Hal, + IN gctINT ShaderType, + IN gctSIZE_T SourceSize, + IN gctCONST_STRING Source, + OUT gcSHADER * Binary, + OUT gctSTRING * Log + ); + +/******************************************************************************* +** gcOptimizeShader +******************************************************************************** +** +** Optimize a shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object holding information about the compiled +** shader. +** +** gctFILE LogFile +** Pointer to an open FILE object. +*/ +gceSTATUS +gcOptimizeShader( + IN gcSHADER Shader, + IN gctFILE LogFile + ); + +/******************************************************************************* +** gcLinkShaders +******************************************************************************** +** +** Link two shaders and generate a harwdare specific state buffer by compiling +** the compiler generated code through the resource allocator and code +** generator. +** +** INPUT: +** +** gcSHADER VertexShader +** Pointer to a gcSHADER object holding information about the compiled +** vertex shader. +** +** gcSHADER FragmentShader +** Pointer to a gcSHADER object holding information about the compiled +** fragment shader. +** +** gceSHADER_FLAGS Flags +** Compiler flags. Can be any of the following: +** +** gcvSHADER_DEAD_CODE - Dead code elimination. +** gcvSHADER_RESOURCE_USAGE - Resource usage optimizaion. +** gcvSHADER_OPTIMIZER - Full optimization. +** gcvSHADER_USE_GL_Z - Use OpenGL ES Z coordinate. +** gcvSHADER_USE_GL_POSITION - Use OpenGL ES gl_Position. +** gcvSHADER_USE_GL_FACE - Use OpenGL ES gl_FaceForward. +** +** OUTPUT: +** +** gctSIZE_T * StateBufferSize +** Pointer to a variable receicing the number of bytes in the buffer +** returned in 'StateBuffer'. +** +** gctPOINTER * StateBuffer +** Pointer to a variable receiving a buffer pointer that contains the +** states required to download the shaders into the hardware. +** +** gcsHINT_PTR * Hints +** Pointer to a variable receiving a gcsHINT structure pointer that +** contains information required when loading the shader states. +*/ +gceSTATUS +gcLinkShaders( + IN gcSHADER VertexShader, + IN gcSHADER FragmentShader, + IN gceSHADER_FLAGS Flags, + OUT gctSIZE_T * StateBufferSize, + OUT gctPOINTER * StateBuffer, + OUT gcsHINT_PTR * Hints + ); + +/******************************************************************************* +** gcLoadShaders +******************************************************************************** +** +** Load a pre-compiled and pre-linked shader program into the hardware. +** +** INPUT: +** +** gcoHAL Hal +** Pointer to a gcoHAL object. +** +** gctSIZE_T StateBufferSize +** The number of bytes in the 'StateBuffer'. +** +** gctPOINTER StateBuffer +** Pointer to the states that make up the shader program. +** +** gcsHINT_PTR Hints +** Pointer to a gcsHINT structure that contains information required +** when loading the shader states. +** +** gcePRIMITIVE PrimitiveType +** Primitive type to be rendered. +*/ +gceSTATUS +gcLoadShaders( + IN gcoHAL Hal, + IN gctSIZE_T StateBufferSize, + IN gctPOINTER StateBuffer, + IN gcsHINT_PTR Hints, + IN gcePRIMITIVE PrimitiveType + ); + +/******************************************************************************* +** gcSaveProgram +******************************************************************************** +** +** Save pre-compiled shaders and pre-linked programs to a binary file. +** +** INPUT: +** +** gcSHADER VertexShader +** Pointer to vertex shader object. +** +** gcSHADER FragmentShader +** Pointer to fragment shader object. +** +** gctSIZE_T ProgramBufferSize +** Number of bytes in 'ProgramBuffer'. +** +** gctPOINTER ProgramBuffer +** Pointer to buffer containing the program states. +** +** gcsHINT_PTR Hints +** Pointer to HINTS structure for program states. +** +** OUTPUT: +** +** gctPOINTER * Binary +** Pointer to a variable receiving the binary data to be saved. +** +** gctSIZE_T * BinarySize +** Pointer to a variable receiving the number of bytes inside 'Binary'. +*/ +gceSTATUS +gcSaveProgram( + IN gcSHADER VertexShader, + IN gcSHADER FragmentShader, + IN gctSIZE_T ProgramBufferSize, + IN gctPOINTER ProgramBuffer, + IN gcsHINT_PTR Hints, + OUT gctPOINTER * Binary, + OUT gctSIZE_T * BinarySize + ); + +/******************************************************************************* +** gcLoadProgram +******************************************************************************** +** +** Load pre-compiled shaders and pre-linked programs from a binary file. +** +** INPUT: +** +** gctPOINTER Binary +** Pointer to the binary data loaded. +** +** gctSIZE_T BinarySize +** Number of bytes in 'Binary'. +** +** OUTPUT: +** +** gcSHADER * VertexShader +** Pointer to a variable receiving the vertex shader object. +** +** gcSHADER * FragmentShader +** Pointer to a variable receiving the fragment shader object. +** +** gctSIZE_T * ProgramBufferSize +** Pointer to a variable receicing the number of bytes in the buffer +** returned in 'ProgramBuffer'. +** +** gctPOINTER * ProgramBuffer +** Pointer to a variable receiving a buffer pointer that contains the +** states required to download the shaders into the hardware. +** +** gcsHINT_PTR * Hints +** Pointer to a variable receiving a gcsHINT structure pointer that +** contains information required when loading the shader states. +*/ +gceSTATUS +gcLoadProgram( + IN gctPOINTER Binary, + IN gctSIZE_T BinarySize, + OUT gcSHADER * VertexShader, + OUT gcSHADER * FragmentShader, + OUT gctSIZE_T * ProgramBufferSize, + OUT gctPOINTER * ProgramBuffer, + OUT gcsHINT_PTR * Hints + ); + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_compiler_h_ */ + diff --git a/drivers/staging/rk29/vivante/hal/inc/gc_hal_driver.h b/drivers/staging/rk29/vivante/hal/inc/gc_hal_driver.h new file mode 100644 index 000000000000..7943e03ed2f4 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/inc/gc_hal_driver.h @@ -0,0 +1,633 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_driver_h_ +#define __gc_hal_driver_h_ + +#include "gc_hal_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************\ +******************************* I/O Control Codes ****************************** +\******************************************************************************/ + +#define gcvHAL_CLASS "galcore" +#define IOCTL_GCHAL_INTERFACE 30000 +#define IOCTL_GCHAL_KERNEL_INTERFACE 30001 +#define IOCTL_GCHAL_TERMINATE 30002 + +/******************************************************************************\ +********************************* Command Codes ******************************** +\******************************************************************************/ + +typedef enum _gceHAL_COMMAND_CODES +{ + /* Generic query. */ + gcvHAL_QUERY_VIDEO_MEMORY, + gcvHAL_QUERY_CHIP_IDENTITY, + + /* Contiguous memory. */ + gcvHAL_ALLOCATE_NON_PAGED_MEMORY, + gcvHAL_FREE_NON_PAGED_MEMORY, + gcvHAL_ALLOCATE_CONTIGUOUS_MEMORY, + gcvHAL_FREE_CONTIGUOUS_MEMORY, + + /* Video memory allocation. */ + gcvHAL_ALLOCATE_VIDEO_MEMORY, /* Enforced alignment. */ + gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY, /* No alignment. */ + gcvHAL_FREE_VIDEO_MEMORY, + + /* Physical-to-logical mapping. */ + gcvHAL_MAP_MEMORY, + gcvHAL_UNMAP_MEMORY, + + /* Logical-to-physical mapping. */ + gcvHAL_MAP_USER_MEMORY, + gcvHAL_UNMAP_USER_MEMORY, + + /* Surface lock/unlock. */ + gcvHAL_LOCK_VIDEO_MEMORY, + gcvHAL_UNLOCK_VIDEO_MEMORY, + + /* Event queue. */ + gcvHAL_EVENT_COMMIT, + + gcvHAL_USER_SIGNAL, + gcvHAL_SIGNAL, + gcvHAL_WRITE_DATA, + + gcvHAL_COMMIT, + gcvHAL_STALL, + + gcvHAL_READ_REGISTER, + gcvHAL_WRITE_REGISTER, + + gcvHAL_GET_PROFILE_SETTING, + gcvHAL_SET_PROFILE_SETTING, + + gcvHAL_READ_ALL_PROFILE_REGISTERS, + gcvHAL_PROFILE_REGISTERS_2D, + + /* Power management. */ + gcvHAL_SET_POWER_MANAGEMENT_STATE, + gcvHAL_QUERY_POWER_MANAGEMENT_STATE, + + gcvHAL_GET_BASE_ADDRESS, + + gcvHAL_SET_IDLE, /* reserved */ + + /* Queries. */ + gcvHAL_QUERY_KERNEL_SETTINGS, + + /* Reset. */ + gcvHAL_RESET, + + /* Map physical address into handle. */ + gcvHAL_MAP_PHYSICAL, + + /* Debugger stuff. */ + gcvHAL_DEBUG, + + /* Cache stuff. */ + gcvHAL_CACHE, +} +gceHAL_COMMAND_CODES; + +/******************************************************************************\ +****************************** Interface Structure ***************************** +\******************************************************************************/ + +#define gcdMAX_PROFILE_FILE_NAME 128 + +typedef struct _gcsHAL_INTERFACE +{ + /* Command code. */ + gceHAL_COMMAND_CODES command; + + /* Status value. */ + gceSTATUS status; + + /* Handle to this interface channel. */ + gctHANDLE handle; + + /* Pid of the client. */ + gctUINT32 pid; + + /* Union of command structures. */ + union _u + { + /* gcvHAL_GET_BASE_ADDRESS */ + struct _gcsHAL_GET_BASE_ADDRESS + { + /* Physical memory address of internal memory. */ + OUT gctUINT32 baseAddress; + } + GetBaseAddress; + + /* gcvHAL_QUERY_VIDEO_MEMORY */ + struct _gcsHAL_QUERY_VIDEO_MEMORY + { + /* Physical memory address of internal memory. */ + OUT gctPHYS_ADDR internalPhysical; + + /* Size in bytes of internal memory.*/ + OUT gctSIZE_T internalSize; + + /* Physical memory address of external memory. */ + OUT gctPHYS_ADDR externalPhysical; + + /* Size in bytes of external memory.*/ + OUT gctSIZE_T externalSize; + + /* Physical memory address of contiguous memory. */ + OUT gctPHYS_ADDR contiguousPhysical; + + /* Size in bytes of contiguous memory.*/ + OUT gctSIZE_T contiguousSize; + } + QueryVideoMemory; + + /* gcvHAL_QUERY_CHIP_IDENTITY */ + struct _gcsHAL_QUERY_CHIP_IDENTITY + { + + /* Chip model. */ + OUT gceCHIPMODEL chipModel; + + /* Revision value.*/ + OUT gctUINT32 chipRevision; + + /* Supported feature fields. */ + OUT gctUINT32 chipFeatures; + + /* Supported minor feature fields. */ + OUT gctUINT32 chipMinorFeatures; + + /* Supported minor feature 1 fields. */ + OUT gctUINT32 chipMinorFeatures1; + + /* Number of streams supported. */ + OUT gctUINT32 streamCount; + + /* Total number of temporary registers per thread. */ + OUT gctUINT32 registerMax; + + /* Maximum number of threads. */ + OUT gctUINT32 threadCount; + + /* Number of shader cores. */ + OUT gctUINT32 shaderCoreCount; + + /* Size of the vertex cache. */ + OUT gctUINT32 vertexCacheSize; + + /* Number of entries in the vertex output buffer. */ + OUT gctUINT32 vertexOutputBufferSize; + } + QueryChipIdentity; + + /* gcvHAL_MAP_MEMORY */ + struct _gcsHAL_MAP_MEMORY + { + /* Physical memory address to map. */ + IN gctPHYS_ADDR physical; + + /* Number of bytes in physical memory to map. */ + IN gctSIZE_T bytes; + + /* Address of mapped memory. */ + OUT gctPOINTER logical; + } + MapMemory; + + /* gcvHAL_UNMAP_MEMORY */ + struct _gcsHAL_UNMAP_MEMORY + { + /* Physical memory address to unmap. */ + IN gctPHYS_ADDR physical; + + /* Number of bytes in physical memory to unmap. */ + IN gctSIZE_T bytes; + + /* Address of mapped memory to unmap. */ + IN gctPOINTER logical; + } + UnmapMemory; + + /* gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY */ + struct _gcsHAL_ALLOCATE_LINEAR_VIDEO_MEMORY + { + /* Number of bytes to allocate. */ + IN OUT gctUINT bytes; + + /* Buffer alignment. */ + IN gctUINT alignment; + + /* Type of allocation. */ + IN gceSURF_TYPE type; + + /* Memory pool to allocate from. */ + IN OUT gcePOOL pool; + + /* Allocated video memory. */ + OUT gcuVIDMEM_NODE_PTR node; + } + AllocateLinearVideoMemory; + + /* gcvHAL_ALLOCATE_VIDEO_MEMORY */ + struct _gcsHAL_ALLOCATE_VIDEO_MEMORY + { + /* Width of rectangle to allocate. */ + IN OUT gctUINT width; + + /* Height of rectangle to allocate. */ + IN OUT gctUINT height; + + /* Depth of rectangle to allocate. */ + IN gctUINT depth; + + /* Format rectangle to allocate in gceSURF_FORMAT. */ + IN gceSURF_FORMAT format; + + /* Type of allocation. */ + IN gceSURF_TYPE type; + + /* Memory pool to allocate from. */ + IN OUT gcePOOL pool; + + /* Allocated video memory. */ + OUT gcuVIDMEM_NODE_PTR node; + } + AllocateVideoMemory; + + /* gcvHAL_FREE_VIDEO_MEMORY */ + struct _gcsHAL_FREE_VIDEO_MEMORY + { + /* Allocated video memory. */ + IN gcuVIDMEM_NODE_PTR node; + +#ifdef __QNXNTO__ +/* TODO: This is part of the unlock - why is it here? */ + /* Mapped logical address to unmap in user space. */ + OUT gctPOINTER memory; + + /* Number of bytes to allocated. */ + OUT gctSIZE_T bytes; +#endif + } + FreeVideoMemory; + + /* gcvHAL_LOCK_VIDEO_MEMORY */ + struct _gcsHAL_LOCK_VIDEO_MEMORY + { + /* Allocated video memory. */ + IN gcuVIDMEM_NODE_PTR node; + + /* Hardware specific address. */ + OUT gctUINT32 address; + + /* Mapped logical address. */ + OUT gctPOINTER memory; + } + LockVideoMemory; + + /* gcvHAL_UNLOCK_VIDEO_MEMORY */ + struct _gcsHAL_UNLOCK_VIDEO_MEMORY + { + /* Allocated video memory. */ + IN gcuVIDMEM_NODE_PTR node; + + /* Type of surface. */ + IN gceSURF_TYPE type; + + /* Flag to unlock surface asynchroneously. */ + IN OUT gctBOOL asynchroneous; + } + UnlockVideoMemory; + + /* gcvHAL_ALLOCATE_NON_PAGED_MEMORY */ + struct _gcsHAL_ALLOCATE_NON_PAGED_MEMORY + { + /* Number of bytes to allocate. */ + IN OUT gctSIZE_T bytes; + + /* Physical address of allocation. */ + OUT gctPHYS_ADDR physical; + + /* Logical address of allocation. */ + OUT gctPOINTER logical; + } + AllocateNonPagedMemory; + + /* gcvHAL_FREE_NON_PAGED_MEMORY */ + struct _gcsHAL_FREE_NON_PAGED_MEMORY + { + /* Number of bytes allocated. */ + IN gctSIZE_T bytes; + + /* Physical address of allocation. */ + IN gctPHYS_ADDR physical; + + /* Logical address of allocation. */ + IN gctPOINTER logical; + } + FreeNonPagedMemory; + + /* gcvHAL_EVENT_COMMIT. */ + struct _gcsHAL_EVENT_COMMIT + { + /* Event queue. */ + IN struct _gcsQUEUE * queue; + } + Event; + + /* gcvHAL_COMMIT */ + struct _gcsHAL_COMMIT + { + /* Command buffer. */ + IN gcoCMDBUF commandBuffer; + + /* Context buffer. */ + IN gcoCONTEXT contextBuffer; + + /* Process handle. */ + IN gctHANDLE process; + } + Commit; + + /* gcvHAL_MAP_USER_MEMORY */ + struct _gcsHAL_MAP_USER_MEMORY + { + /* Base address of user memory to map. */ + IN gctPOINTER memory; + + /* Size of user memory in bytes to map. */ + IN gctSIZE_T size; + + /* Info record required by gcvHAL_UNMAP_USER_MEMORY. */ + OUT gctPOINTER info; + + /* Physical address of mapped memory. */ + OUT gctUINT32 address; + } + MapUserMemory; + + /* gcvHAL_UNMAP_USER_MEMORY */ + struct _gcsHAL_UNMAP_USER_MEMORY + { + /* Base address of user memory to unmap. */ + IN gctPOINTER memory; + + /* Size of user memory in bytes to unmap. */ + IN gctSIZE_T size; + + /* Info record returned by gcvHAL_MAP_USER_MEMORY. */ + IN gctPOINTER info; + + /* Physical address of mapped memory as returned by + gcvHAL_MAP_USER_MEMORY. */ + IN gctUINT32 address; + } + UnmapUserMemory; + +#if !USE_NEW_LINUX_SIGNAL + /* gcsHAL_USER_SIGNAL */ + struct _gcsHAL_USER_SIGNAL + { + /* Command. */ + gceUSER_SIGNAL_COMMAND_CODES command; + + /* Signal ID. */ + IN OUT gctINT id; + + /* Reset mode. */ + IN gctBOOL manualReset; + + /* Wait timedout. */ + IN gctUINT32 wait; + + /* State. */ + IN gctBOOL state; + } + UserSignal; +#endif + + /* gcvHAL_SIGNAL. */ + struct _gcsHAL_SIGNAL + { + /* Signal handle to signal. */ + IN gctSIGNAL signal; + + /* Reserved. */ + IN gctSIGNAL auxSignal; + + /* Process owning the signal. */ + IN gctHANDLE process; + +#if defined(__QNXNTO__) + /* Client pulse side-channel connection ID. Set by client in gcoOS_CreateSignal. */ + IN gctINT32 coid; + + /* Set by server. */ + IN gctINT32 rcvid; +#endif + /* Event generated from where of pipeline */ + IN gceKERNEL_WHERE fromWhere; + } + Signal; + + /* gcvHAL_WRITE_DATA. */ + struct _gcsHAL_WRITE_DATA + { + /* Address to write data to. */ + IN gctUINT32 address; + + /* Data to write. */ + IN gctUINT32 data; + } + WriteData; + + /* gcvHAL_ALLOCATE_CONTIGUOUS_MEMORY */ + struct _gcsHAL_ALLOCATE_CONTIGUOUS_MEMORY + { + /* Number of bytes to allocate. */ + IN OUT gctSIZE_T bytes; + + /* Physical address of allocation. */ + OUT gctPHYS_ADDR physical; + + /* Logical address of allocation. */ + OUT gctPOINTER logical; + + } + AllocateContiguousMemory; + + /* gcvHAL_FREE_CONTIGUOUS_MEMORY */ + struct _gcsHAL_FREE_CONTIGUOUS_MEMORY + { + /* Number of bytes allocated. */ + IN gctSIZE_T bytes; + + /* Physical address of allocation. */ + IN gctPHYS_ADDR physical; + + /* Logical address of allocation. */ + IN gctPOINTER logical; + } + FreeContiguousMemory; + + /* gcvHAL_READ_REGISTER */ + struct _gcsHAL_READ_REGISTER + { + /* Logical address of memory to write data to. */ + IN gctUINT32 address; + + /* Data read. */ + OUT gctUINT32 data; + } + ReadRegisterData; + + /* gcvHAL_WRITE_REGISTER */ + struct _gcsHAL_WRITE_REGISTER + { + /* Logical address of memory to write data to. */ + IN gctUINT32 address; + + /* Data read. */ + IN gctUINT32 data; + } + WriteRegisterData; + + /* gcvHAL_GET_PROFILE_SETTING */ + struct _gcsHAL_GET_PROFILE_SETTING + { + /* Enable profiling */ + OUT gctBOOL enable; + + /* The profile file name */ + OUT gctCHAR fileName[gcdMAX_PROFILE_FILE_NAME]; + } + GetProfileSetting; + + /* gcvHAL_SET_PROFILE_SETTING */ + struct _gcsHAL_SET_PROFILE_SETTING + { + /* Enable profiling */ + IN gctBOOL enable; + + /* The profile file name */ + IN gctCHAR fileName[gcdMAX_PROFILE_FILE_NAME]; + } + SetProfileSetting; + + /* gcvHAL_READ_ALL_PROFILE_REGISTERS */ + struct _gcsHAL_READ_ALL_PROFILE_REGISTERS + { + /* Data read. */ + OUT gcsPROFILER_COUNTERS counters; + } + RegisterProfileData; + + /* gcvHAL_PROFILE_REGISTERS_2D */ + struct _gcsHAL_PROFILE_REGISTERS_2D + { + /* Data read. */ + OUT gcs2D_PROFILE_PTR hwProfile2D; + } + RegisterProfileData2D; + + /* Power management. */ + /* gcvHAL_SET_POWER_MANAGEMENT_STATE */ + struct _gcsHAL_SET_POWER_MANAGEMENT + { + /* Data read. */ + IN gceCHIPPOWERSTATE state; + } + SetPowerManagement; + + /* gcvHAL_QUERY_POWER_MANAGEMENT_STATE */ + struct _gcsHAL_QUERY_POWER_MANAGEMENT + { + /* Data read. */ + OUT gceCHIPPOWERSTATE state; + + /* Idle query. */ + OUT gctBOOL isIdle; + } + QueryPowerManagement; + + /* gcvHAL_QUERY_KERNEL_SETTINGS */ + struct _gcsHAL_QUERY_KERNEL_SETTINGS + { + /* Settings.*/ + OUT gcsKERNEL_SETTINGS settings; + } + QueryKernelSettings; + + /* gcvHAL_MAP_PHYSICAL */ + struct _gcsHAL_MAP_PHYSICAL + { + /* gcvTRUE to map, gcvFALSE to unmap. */ + IN gctBOOL map; + + /* Physical address. */ + IN OUT gctPHYS_ADDR physical; + } + MapPhysical; + + /* gcvHAL_DEBUG */ + struct _gcsHAL_DEBUG + { + /* If gcvTRUE, set the debug information. */ + IN gctBOOL set; + IN gctUINT32 level; + IN gctUINT32 zones; + IN gctBOOL enable; + + /* Message to print if not empty. */ + IN gctCHAR message[80]; + } + Debug; + + struct _gcsHAL_CACHE + { + IN gctBOOL invalidate; + IN gctHANDLE process; + IN gctPOINTER logical; + IN gctSIZE_T bytes; + } + Cache; + } + u; +} +gcsHAL_INTERFACE; + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_driver_h_ */ + diff --git a/drivers/staging/rk29/vivante/hal/inc/gc_hal_dump.h b/drivers/staging/rk29/vivante/hal/inc/gc_hal_dump.h new file mode 100644 index 000000000000..2264b60cf612 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/inc/gc_hal_dump.h @@ -0,0 +1,90 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_dump_h_ +#define __gc_hal_dump_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** FILE LAYOUT: +** +** gcsDUMP_FILE structure +** +** gcsDUMP_DATA frame +** gcsDUMP_DATA or gcDUMP_DATA_SIZE records rendingring the frame +** gctUINT8 data[length] +*/ + +#define gcvDUMP_FILE_SIGNATURE gcmCC('g','c','D','B') + +typedef struct _gcsDUMP_FILE +{ + gctUINT32 signature; /* File signature */ + gctSIZE_T length; /* Length of file */ + gctUINT32 frames; /* Number of frames in file */ +} +gcsDUMP_FILE; + +typedef enum _gceDUMP_TAG +{ + gcvTAG_SURFACE = gcmCC('s','u','r','f'), + gcvTAG_FRAME = gcmCC('f','r','m',' '), + gcvTAG_COMMAND = gcmCC('c','m','d',' '), + gcvTAG_INDEX = gcmCC('i','n','d','x'), + gcvTAG_STREAM = gcmCC('s','t','r','m'), + gcvTAG_TEXTURE = gcmCC('t','e','x','t'), + gcvTAG_RENDER_TARGET = gcmCC('r','n','d','r'), + gcvTAG_DEPTH = gcmCC('z','b','u','f'), + gcvTAG_RESOLVE = gcmCC('r','s','l','v'), + gcvTAG_DELETE = gcmCC('d','e','l',' '), +} +gceDUMP_TAG; + +typedef struct _gcsDUMP_SURFACE +{ + gceDUMP_TAG type; /* Type of record. */ + gctUINT32 address; /* Address of the surface. */ + gctINT16 width; /* Width of surface. */ + gctINT16 height; /* Height of surface. */ + gceSURF_FORMAT format; /* Surface pixel format. */ + gctSIZE_T length; /* Number of bytes inside the surface. */ +} +gcsDUMP_SURFACE; + +typedef struct _gcsDUMP_DATA +{ + gceDUMP_TAG type; /* Type of record. */ + gctSIZE_T length; /* Number of bytes of data. */ + gctUINT32 address; /* Address for the data. */ +} +gcsDUMP_DATA; + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_dump_h_ */ + diff --git a/drivers/staging/rk29/vivante/hal/inc/gc_hal_engine.h b/drivers/staging/rk29/vivante/hal/inc/gc_hal_engine.h new file mode 100644 index 000000000000..fc43f66dfda1 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/inc/gc_hal_engine.h @@ -0,0 +1,1548 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_engine_h_ +#define __gc_hal_engine_h_ + +#include "gc_hal_types.h" +#include "gc_hal_enum.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************\ +****************************** Object Declarations ***************************** +\******************************************************************************/ + +typedef struct _gcoSTREAM * gcoSTREAM; +typedef struct _gcoVERTEX * gcoVERTEX; +typedef struct _gcoTEXTURE * gcoTEXTURE; +typedef struct _gcoINDEX * gcoINDEX; +typedef struct _gcsVERTEX_ATTRIBUTES * gcsVERTEX_ATTRIBUTES_PTR; + +/******************************************************************************\ +********************************* Enumerations ********************************* +\******************************************************************************/ + +/* Shading format. */ +typedef enum _gceSHADING +{ + gcvSHADING_SMOOTH, + gcvSHADING_FLAT_D3D, + gcvSHADING_FLAT_OPENGL, +} +gceSHADING; + +/* Culling modes. */ +typedef enum _gceCULL +{ + gcvCULL_NONE, + gcvCULL_CCW, + gcvCULL_CW, +} +gceCULL; + +/* Fill modes. */ +typedef enum _gceFILL +{ + gcvFILL_POINT, + gcvFILL_WIRE_FRAME, + gcvFILL_SOLID, +} +gceFILL; + +/* Compare modes. */ +typedef enum _gceCOMPARE +{ + gcvCOMPARE_NEVER, + gcvCOMPARE_NOT_EQUAL, + gcvCOMPARE_LESS, + gcvCOMPARE_LESS_OR_EQUAL, + gcvCOMPARE_EQUAL, + gcvCOMPARE_GREATER, + gcvCOMPARE_GREATER_OR_EQUAL, + gcvCOMPARE_ALWAYS, +} +gceCOMPARE; + +/* Stencil modes. */ +typedef enum _gceSTENCIL_MODE +{ + gcvSTENCIL_NONE, + gcvSTENCIL_SINGLE_SIDED, + gcvSTENCIL_DOUBLE_SIDED, +} +gceSTENCIL_MODE; + +/* Stencil operations. */ +typedef enum _gceSTENCIL_OPERATION +{ + gcvSTENCIL_KEEP, + gcvSTENCIL_REPLACE, + gcvSTENCIL_ZERO, + gcvSTENCIL_INVERT, + gcvSTENCIL_INCREMENT, + gcvSTENCIL_DECREMENT, + gcvSTENCIL_INCREMENT_SATURATE, + gcvSTENCIL_DECREMENT_SATURATE, +} +gceSTENCIL_OPERATION; + +/* Stencil selection. */ +typedef enum _gceSTENCIL_WHERE +{ + gcvSTENCIL_FRONT, + gcvSTENCIL_BACK, +} +gceSTENCIL_WHERE; + +/* Texture addressing selection. */ +typedef enum _gceTEXTURE_WHICH +{ + gcvTEXTURE_S, + gcvTEXTURE_T, + gcvTEXTURE_R, +} +gceTEXTURE_WHICH; + +/* Texture addressing modes. */ +typedef enum _gceTEXTURE_ADDRESSING +{ + gcvTEXTURE_WRAP, + gcvTEXTURE_CLAMP, + gcvTEXTURE_BORDER, + gcvTEXTURE_MIRROR, + gcvTEXTURE_MIRROR_ONCE, +} +gceTEXTURE_ADDRESSING; + +/* Texture filters. */ +typedef enum _gceTEXTURE_FILTER +{ + gcvTEXTURE_NONE, + gcvTEXTURE_POINT, + gcvTEXTURE_LINEAR, + gcvTEXTURE_ANISOTROPIC, +} +gceTEXTURE_FILTER; + +/* Primitive types. */ +typedef enum _gcePRIMITIVE +{ + gcvPRIMITIVE_POINT_LIST, + gcvPRIMITIVE_LINE_LIST, + gcvPRIMITIVE_LINE_STRIP, + gcvPRIMITIVE_LINE_LOOP, + gcvPRIMITIVE_TRIANGLE_LIST, + gcvPRIMITIVE_TRIANGLE_STRIP, + gcvPRIMITIVE_TRIANGLE_FAN, +} +gcePRIMITIVE; + +/* Index types. */ +typedef enum _gceINDEX_TYPE +{ + gcvINDEX_8, + gcvINDEX_16, + gcvINDEX_32, +} +gceINDEX_TYPE; + +/******************************************************************************\ +********************************* gcoHAL Object ********************************* +\******************************************************************************/ + +/* Query the target capabilities. */ +gceSTATUS +gcoHAL_QueryTargetCaps( + IN gcoHAL Hal, + OUT gctUINT * MaxWidth, + OUT gctUINT * MaxHeight, + OUT gctUINT * MultiTargetCount, + OUT gctUINT * MaxSamples + ); + +gceSTATUS +gcoHAL_SetDepthOnly( + IN gcoHAL Hal, + IN gctBOOL Enable + ); + +gceSTATUS +gcoHAL_QueryShaderCaps( + IN gcoHAL Hal, + OUT gctUINT * VertexUniforms, + OUT gctUINT * FragmentUniforms, + OUT gctUINT * Varyings + ); + +gceSTATUS +gcoHAL_QueryTextureCaps( + IN gcoHAL Hal, + OUT gctUINT * MaxWidth, + OUT gctUINT * MaxHeight, + OUT gctUINT * MaxDepth, + OUT gctBOOL * Cubic, + OUT gctBOOL * NonPowerOfTwo, + OUT gctUINT * VertexSamplers, + OUT gctUINT * PixelSamplers + ); + +gceSTATUS +gcoHAL_QueryStreamCaps( + IN gcoHAL Hal, + OUT gctUINT32 * MaxAttributes, + OUT gctUINT32 * MaxStreamSize, + OUT gctUINT32 * NumberOfStreams, + OUT gctUINT32 * Alignment + ); + +/******************************************************************************\ +********************************* gcoSURF Object ******************************** +\******************************************************************************/ + +/*----------------------------------------------------------------------------*/ +/*--------------------------------- gcoSURF 3D --------------------------------*/ + +/* Copy surface. */ +gceSTATUS +gcoSURF_Copy( + IN gcoSURF Surface, + IN gcoSURF Source + ); + +/* Clear surface. */ +gceSTATUS +gcoSURF_Clear( + IN gcoSURF Surface, + IN gctUINT Flags + ); + +/* Set number of samples for a gcoSURF object. */ +gceSTATUS +gcoSURF_SetSamples( + IN gcoSURF Surface, + IN gctUINT Samples + ); + +/* Get the number of samples per pixel. */ +gceSTATUS +gcoSURF_GetSamples( + IN gcoSURF Surface, + OUT gctUINT_PTR Samples + ); + +/* Clear rectangular surface. */ +gceSTATUS +gcoSURF_ClearRect( + IN gcoSURF Surface, + IN gctINT Left, + IN gctINT Top, + IN gctINT Right, + IN gctINT Bottom, + IN gctUINT Flags + ); + +/* TO BE REMOVED */ +#if 1 + gceSTATUS + depr_gcoSURF_Resolve( + IN gcoSURF SrcSurface, + IN gcoSURF DestSurface, + IN gctUINT32 DestAddress, + IN gctPOINTER DestBits, + IN gctINT DestStride, + IN gceSURF_TYPE DestType, + IN gceSURF_FORMAT DestFormat, + IN gctUINT DestWidth, + IN gctUINT DestHeight + ); + + gceSTATUS + depr_gcoSURF_ResolveRect( + IN gcoSURF SrcSurface, + IN gcoSURF DestSurface, + IN gctUINT32 DestAddress, + IN gctPOINTER DestBits, + IN gctINT DestStride, + IN gceSURF_TYPE DestType, + IN gceSURF_FORMAT DestFormat, + IN gctUINT DestWidth, + IN gctUINT DestHeight, + IN gcsPOINT_PTR SrcOrigin, + IN gcsPOINT_PTR DestOrigin, + IN gcsPOINT_PTR RectSize + ); +#endif + +/* Resample surface. */ +gceSTATUS +gcoSURF_Resample( + IN gcoSURF SrcSurface, + IN gcoSURF DestSurface + ); + +/* Resolve surface. */ +gceSTATUS +gcoSURF_Resolve( + IN gcoSURF SrcSurface, + IN gcoSURF DestSurface + ); + +/* Resolve rectangular area of a surface. */ +gceSTATUS +gcoSURF_ResolveRect( + IN gcoSURF SrcSurface, + IN gcoSURF DestSurface, + IN gcsPOINT_PTR SrcOrigin, + IN gcsPOINT_PTR DestOrigin, + IN gcsPOINT_PTR RectSize + ); + +/* Set surface resolvability. */ +gceSTATUS +gcoSURF_SetResolvability( + IN gcoSURF Surface, + IN gctBOOL Resolvable + ); + +/******************************************************************************\ +******************************** gcoINDEX Object ******************************* +\******************************************************************************/ + +/* Construct a new gcoINDEX object. */ +gceSTATUS +gcoINDEX_Construct( + IN gcoHAL Hal, + OUT gcoINDEX * Index + ); + +/* Destroy a gcoINDEX object. */ +gceSTATUS +gcoINDEX_Destroy( + IN gcoINDEX Index + ); + +/* Lock index in memory. */ +gceSTATUS +gcoINDEX_Lock( + IN gcoINDEX Index, + OUT gctUINT32 * Address, + OUT gctPOINTER * Memory + ); + +/* Unlock index that was previously locked with gcoINDEX_Lock. */ +gceSTATUS +gcoINDEX_Unlock( + IN gcoINDEX Index + ); + +/* Upload index data into the memory. */ +gceSTATUS +gcoINDEX_Load( + IN gcoINDEX Index, + IN gceINDEX_TYPE IndexType, + IN gctUINT32 IndexCount, + IN gctPOINTER IndexBuffer + ); + +/* Bind an index object to the hardware. */ +gceSTATUS +gcoINDEX_Bind( + IN gcoINDEX Index, + IN gceINDEX_TYPE Type + ); + +/* Bind an index object to the hardware. */ +gceSTATUS +gcoINDEX_BindOffset( + IN gcoINDEX Index, + IN gceINDEX_TYPE Type, + IN gctUINT32 Offset + ); + +/* Free existing index buffer. */ +gceSTATUS +gcoINDEX_Free( + IN gcoINDEX Index + ); + +/* Upload data into an index buffer. */ +gceSTATUS +gcoINDEX_Upload( + IN gcoINDEX Index, + IN gctCONST_POINTER Buffer, + IN gctSIZE_T Bytes + ); + +/* Upload data into an index buffer starting at an offset. */ +gceSTATUS +gcoINDEX_UploadOffset( + IN gcoINDEX Index, + IN gctUINT32 Offset, + IN gctCONST_POINTER Buffer, + IN gctSIZE_T Bytes + ); + +/* Query the index capabilities. */ +gceSTATUS +gcoINDEX_QueryCaps( + OUT gctBOOL * Index8, + OUT gctBOOL * Index16, + OUT gctBOOL * Index32, + OUT gctUINT * MaxIndex + ); + +/* Determine the index range in the current index buffer. */ +gceSTATUS +gcoINDEX_GetIndexRange( + IN gcoINDEX Index, + IN gceINDEX_TYPE Type, + IN gctUINT32 Offset, + IN gctUINT32 Count, + OUT gctUINT32 * MinimumIndex, + OUT gctUINT32 * MaximumIndex + ); + +/* Dynamic buffer management. */ +gceSTATUS +gcoINDEX_SetDynamic( + IN gcoINDEX Index, + IN gctSIZE_T Bytes, + IN gctUINT Buffers + ); + +gceSTATUS +gcoINDEX_UploadDynamic( + IN gcoINDEX Index, + IN gctCONST_POINTER Data, + IN gctSIZE_T Bytes + ); + +/******************************************************************************\ +********************************** gco3D Object ********************************* +\******************************************************************************/ + +/* Clear flags. */ +typedef enum _gceCLEAR +{ + gcvCLEAR_COLOR = 0x1, + gcvCLEAR_DEPTH = 0x2, + gcvCLEAR_STENCIL = 0x4, + gcvCLEAR_HZ = 0x8, + gcvCLEAR_HAS_VAA = 0x10, +} +gceCLEAR; + +/* Blending targets. */ +typedef enum _gceBLEND_UNIT +{ + gcvBLEND_SOURCE, + gcvBLEND_TARGET, +} +gceBLEND_UNIT; + +/* Construct a new gco3D object. */ +gceSTATUS +gco3D_Construct( + IN gcoHAL Hal, + OUT gco3D * Engine + ); + +/* Destroy an gco3D object. */ +gceSTATUS +gco3D_Destroy( + IN gco3D Engine + ); + +/* Set 3D API type. */ +gceSTATUS +gco3D_SetAPI( + IN gco3D Engine, + IN gceAPI ApiType + ); + +/* Set render target. */ +gceSTATUS +gco3D_SetTarget( + IN gco3D Engine, + IN gcoSURF Surface + ); + +/* Unset render target. */ +gceSTATUS +gco3D_UnsetTarget( + IN gco3D Engine, + IN gcoSURF Surface + ); + +/* Set depth buffer. */ +gceSTATUS +gco3D_SetDepth( + IN gco3D Engine, + IN gcoSURF Surface + ); + +/* Unset depth buffer. */ +gceSTATUS +gco3D_UnsetDepth( + IN gco3D Engine, + IN gcoSURF Surface + ); + +/* Set viewport. */ +gceSTATUS +gco3D_SetViewport( + IN gco3D Engine, + IN gctINT32 Left, + IN gctINT32 Top, + IN gctINT32 Right, + IN gctINT32 Bottom + ); + +/* Set scissors. */ +gceSTATUS +gco3D_SetScissors( + IN gco3D Engine, + IN gctINT32 Left, + IN gctINT32 Top, + IN gctINT32 Right, + IN gctINT32 Bottom + ); + +/* Set clear color. */ +gceSTATUS +gco3D_SetClearColor( + IN gco3D Engine, + IN gctUINT8 Red, + IN gctUINT8 Green, + IN gctUINT8 Blue, + IN gctUINT8 Alpha + ); + +/* Set fixed point clear color. */ +gceSTATUS +gco3D_SetClearColorX( + IN gco3D Engine, + IN gctFIXED_POINT Red, + IN gctFIXED_POINT Green, + IN gctFIXED_POINT Blue, + IN gctFIXED_POINT Alpha + ); + +/* Set floating point clear color. */ +gceSTATUS +gco3D_SetClearColorF( + IN gco3D Engine, + IN gctFLOAT Red, + IN gctFLOAT Green, + IN gctFLOAT Blue, + IN gctFLOAT Alpha + ); + +/* Set fixed point clear depth. */ +gceSTATUS +gco3D_SetClearDepthX( + IN gco3D Engine, + IN gctFIXED_POINT Depth + ); + +/* Set floating point clear depth. */ +gceSTATUS +gco3D_SetClearDepthF( + IN gco3D Engine, + IN gctFLOAT Depth + ); + +/* Set clear stencil. */ +gceSTATUS +gco3D_SetClearStencil( + IN gco3D Engine, + IN gctUINT32 Stencil + ); + +/* Clear a Rect sub-surface. */ +gceSTATUS +gco3D_ClearRect( + IN gco3D Engine, + IN gctUINT32 Address, + IN gctPOINTER Memory, + IN gctUINT32 Stride, + IN gceSURF_FORMAT Format, + IN gctINT32 Left, + IN gctINT32 Top, + IN gctINT32 Right, + IN gctINT32 Bottom, + IN gctUINT32 Width, + IN gctUINT32 Height, + IN gctUINT32 Flags + ); + +/* Clear surface. */ +gceSTATUS +gco3D_Clear( + IN gco3D Engine, + IN gctUINT32 Address, + IN gctUINT32 Stride, + IN gceSURF_FORMAT Format, + IN gctUINT32 Width, + IN gctUINT32 Height, + IN gctUINT32 Flags + ); + + +/* Clear tile status. */ +gceSTATUS +gco3D_ClearTileStatus( + IN gco3D Engine, + IN gcsSURF_INFO_PTR Surface, + IN gctUINT32 TileStatusAddress, + IN gctUINT32 Flags + ); + +/* Set shading mode. */ +gceSTATUS +gco3D_SetShading( + IN gco3D Engine, + IN gceSHADING Shading + ); + +/* Set blending mode. */ +gceSTATUS +gco3D_EnableBlending( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set blending function. */ +gceSTATUS +gco3D_SetBlendFunction( + IN gco3D Engine, + IN gceBLEND_UNIT Unit, + IN gceBLEND_FUNCTION FunctionRGB, + IN gceBLEND_FUNCTION FunctionAlpha + ); + +/* Set blending mode. */ +gceSTATUS +gco3D_SetBlendMode( + IN gco3D Engine, + IN gceBLEND_MODE ModeRGB, + IN gceBLEND_MODE ModeAlpha + ); + +/* Set blending color. */ +gceSTATUS +gco3D_SetBlendColor( + IN gco3D Engine, + IN gctUINT Red, + IN gctUINT Green, + IN gctUINT Blue, + IN gctUINT Alpha + ); + +/* Set fixed point blending color. */ +gceSTATUS +gco3D_SetBlendColorX( + IN gco3D Engine, + IN gctFIXED_POINT Red, + IN gctFIXED_POINT Green, + IN gctFIXED_POINT Blue, + IN gctFIXED_POINT Alpha + ); + +/* Set floating point blending color. */ +gceSTATUS +gco3D_SetBlendColorF( + IN gco3D Engine, + IN gctFLOAT Red, + IN gctFLOAT Green, + IN gctFLOAT Blue, + IN gctFLOAT Alpha + ); + +/* Set culling mode. */ +gceSTATUS +gco3D_SetCulling( + IN gco3D Engine, + IN gceCULL Mode + ); + +/* Enable point size */ +gceSTATUS +gco3D_SetPointSizeEnable( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set point sprite */ +gceSTATUS +gco3D_SetPointSprite( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set fill mode. */ +gceSTATUS +gco3D_SetFill( + IN gco3D Engine, + IN gceFILL Mode + ); + +/* Set depth compare mode. */ +gceSTATUS +gco3D_SetDepthCompare( + IN gco3D Engine, + IN gceCOMPARE Compare + ); + +/* Enable depth writing. */ +gceSTATUS +gco3D_EnableDepthWrite( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set depth mode. */ +gceSTATUS +gco3D_SetDepthMode( + IN gco3D Engine, + IN gceDEPTH_MODE Mode + ); + +/* Set depth range. */ +gceSTATUS +gco3D_SetDepthRangeX( + IN gco3D Engine, + IN gceDEPTH_MODE Mode, + IN gctFIXED_POINT Near, + IN gctFIXED_POINT Far + ); + +/* Set depth range. */ +gceSTATUS +gco3D_SetDepthRangeF( + IN gco3D Engine, + IN gceDEPTH_MODE Mode, + IN gctFLOAT Near, + IN gctFLOAT Far + ); + +/* Set last pixel enable */ +gceSTATUS +gco3D_SetLastPixelEnable( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set depth Bias and Scale */ +gceSTATUS +gco3D_SetDepthScaleBiasX( + IN gco3D Engine, + IN gctFIXED_POINT DepthScale, + IN gctFIXED_POINT DepthBias + ); + +gceSTATUS +gco3D_SetDepthScaleBiasF( + IN gco3D Engine, + IN gctFLOAT DepthScale, + IN gctFLOAT DepthBias + ); + +/* Enable or disable dithering. */ +gceSTATUS +gco3D_EnableDither( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set color write enable bits. */ +gceSTATUS +gco3D_SetColorWrite( + IN gco3D Engine, + IN gctUINT8 Enable + ); + +/* Enable or disable early depth. */ +gceSTATUS +gco3D_SetEarlyDepth( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Enable or disable depth-only mode. */ +gceSTATUS +gco3D_SetDepthOnly( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set stencil mode. */ +gceSTATUS +gco3D_SetStencilMode( + IN gco3D Engine, + IN gceSTENCIL_MODE Mode + ); + +/* Set stencil mask. */ +gceSTATUS +gco3D_SetStencilMask( + IN gco3D Engine, + IN gctUINT8 Mask + ); + +/* Set stencil write mask. */ +gceSTATUS +gco3D_SetStencilWriteMask( + IN gco3D Engine, + IN gctUINT8 Mask + ); + +/* Set stencil reference. */ +gceSTATUS +gco3D_SetStencilReference( + IN gco3D Engine, + IN gctUINT8 Reference + ); + +/* Set stencil compare. */ +gceSTATUS +gco3D_SetStencilCompare( + IN gco3D Engine, + IN gceSTENCIL_WHERE Where, + IN gceCOMPARE Compare + ); + +/* Set stencil operation on pass. */ +gceSTATUS +gco3D_SetStencilPass( + IN gco3D Engine, + IN gceSTENCIL_WHERE Where, + IN gceSTENCIL_OPERATION Operation + ); + +/* Set stencil operation on fail. */ +gceSTATUS +gco3D_SetStencilFail( + IN gco3D Engine, + IN gceSTENCIL_WHERE Where, + IN gceSTENCIL_OPERATION Operation + ); + +/* Set stencil operation on depth fail. */ +gceSTATUS +gco3D_SetStencilDepthFail( + IN gco3D Engine, + IN gceSTENCIL_WHERE Where, + IN gceSTENCIL_OPERATION Operation + ); + +/* Enable or disable alpha test. */ +gceSTATUS +gco3D_SetAlphaTest( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set alpha test compare. */ +gceSTATUS +gco3D_SetAlphaCompare( + IN gco3D Engine, + IN gceCOMPARE Compare + ); + +/* Set alpha test reference in unsigned integer. */ +gceSTATUS +gco3D_SetAlphaReference( + IN gco3D Engine, + IN gctUINT8 Reference + ); + +/* Set alpha test reference in fixed point. */ +gceSTATUS +gco3D_SetAlphaReferenceX( + IN gco3D Engine, + IN gctFIXED_POINT Reference + ); + +/* Set alpha test reference in floating point. */ +gceSTATUS +gco3D_SetAlphaReferenceF( + IN gco3D Engine, + IN gctFLOAT Reference + ); + +/* Enable/Disable anti-alias line. */ +gceSTATUS +gco3D_SetAntiAliasLine( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set texture slot for anti-alias line. */ +gceSTATUS +gco3D_SetAALineTexSlot( + IN gco3D Engine, + IN gctUINT TexSlot + ); + +/* Set anti-alias line width scale. */ +gceSTATUS +gco3D_SetAALineWidth( + IN gco3D Engine, + IN gctFLOAT Width + ); + +/* Draw a number of primitives. */ +gceSTATUS +gco3D_DrawPrimitives( + IN gco3D Engine, + IN gcePRIMITIVE Type, + IN gctINT StartVertex, + IN gctSIZE_T PrimitiveCount + ); + +/* Draw a number of primitives using offsets. */ +gceSTATUS +gco3D_DrawPrimitivesOffset( + IN gco3D Engine, + IN gcePRIMITIVE Type, + IN gctINT32 StartOffset, + IN gctSIZE_T PrimitiveCount + ); + +/* Draw a number of indexed primitives. */ +gceSTATUS +gco3D_DrawIndexedPrimitives( + IN gco3D Engine, + IN gcePRIMITIVE Type, + IN gctINT BaseVertex, + IN gctINT StartIndex, + IN gctSIZE_T PrimitiveCount + ); + +/* Draw a number of indexed primitives using offsets. */ +gceSTATUS +gco3D_DrawIndexedPrimitivesOffset( + IN gco3D Engine, + IN gcePRIMITIVE Type, + IN gctINT32 BaseOffset, + IN gctINT32 StartOffset, + IN gctSIZE_T PrimitiveCount + ); + +/* Enable or disable anti-aliasing. */ +gceSTATUS +gco3D_SetAntiAlias( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Write data into the command buffer. */ +gceSTATUS +gco3D_WriteBuffer( + IN gco3D Engine, + IN gctCONST_POINTER Data, + IN gctSIZE_T Bytes, + IN gctBOOL Aligned + ); + +/*Send sempahore and stall until sempahore is signalled.*/ +gceSTATUS +gco3D_Semaphore( + IN gco3D Engine, + IN gceWHERE From, + IN gceWHERE To, + IN gceHOW How); + +/*Set the subpixels center .*/ +gceSTATUS +gco3D_SetCentroids( + IN gco3D Engine, + IN gctUINT32 Index, + IN gctPOINTER Centroids + ); +/*----------------------------------------------------------------------------*/ +/*-------------------------- gco3D Fragment Processor ------------------------*/ + +/* Set the fragment processor configuration. */ +gceSTATUS +gco3D_SetFragmentConfiguration( + IN gco3D Engine, + IN gctBOOL ColorFromStream, + IN gctBOOL EnableFog, + IN gctBOOL EnableSmoothPoint, + IN gctUINT32 ClipPlanes + ); + +/* Enable/disable texture stage operation. */ +gceSTATUS +gco3D_EnableTextureStage( + IN gco3D Engine, + IN gctINT Stage, + IN gctBOOL Enable + ); + +/* Program the channel enable masks for the color texture function. */ +gceSTATUS +gco3D_SetTextureColorMask( + IN gco3D Engine, + IN gctINT Stage, + IN gctBOOL ColorEnabled, + IN gctBOOL AlphaEnabled + ); + +/* Program the channel enable masks for the alpha texture function. */ +gceSTATUS +gco3D_SetTextureAlphaMask( + IN gco3D Engine, + IN gctINT Stage, + IN gctBOOL ColorEnabled, + IN gctBOOL AlphaEnabled + ); + +/* Program the constant fragment color. */ +gceSTATUS +gco3D_SetFragmentColorX( + IN gco3D Engine, + IN gctFIXED_POINT Red, + IN gctFIXED_POINT Green, + IN gctFIXED_POINT Blue, + IN gctFIXED_POINT Alpha + ); + +gceSTATUS +gco3D_SetFragmentColorF( + IN gco3D Engine, + IN gctFLOAT Red, + IN gctFLOAT Green, + IN gctFLOAT Blue, + IN gctFLOAT Alpha + ); + +/* Program the constant fog color. */ +gceSTATUS +gco3D_SetFogColorX( + IN gco3D Engine, + IN gctFIXED_POINT Red, + IN gctFIXED_POINT Green, + IN gctFIXED_POINT Blue, + IN gctFIXED_POINT Alpha + ); + +gceSTATUS +gco3D_SetFogColorF( + IN gco3D Engine, + IN gctFLOAT Red, + IN gctFLOAT Green, + IN gctFLOAT Blue, + IN gctFLOAT Alpha + ); + +/* Program the constant texture color. */ +gceSTATUS +gco3D_SetTetxureColorX( + IN gco3D Engine, + IN gctINT Stage, + IN gctFIXED_POINT Red, + IN gctFIXED_POINT Green, + IN gctFIXED_POINT Blue, + IN gctFIXED_POINT Alpha + ); + +gceSTATUS +gco3D_SetTetxureColorF( + IN gco3D Engine, + IN gctINT Stage, + IN gctFLOAT Red, + IN gctFLOAT Green, + IN gctFLOAT Blue, + IN gctFLOAT Alpha + ); + +/* Configure color texture function. */ +gceSTATUS +gco3D_SetColorTextureFunction( + IN gco3D Engine, + IN gctINT Stage, + IN gceTEXTURE_FUNCTION Function, + IN gceTEXTURE_SOURCE Source0, + IN gceTEXTURE_CHANNEL Channel0, + IN gceTEXTURE_SOURCE Source1, + IN gceTEXTURE_CHANNEL Channel1, + IN gceTEXTURE_SOURCE Source2, + IN gceTEXTURE_CHANNEL Channel2, + IN gctINT Scale + ); + +/* Configure alpha texture function. */ +gceSTATUS +gco3D_SetAlphaTextureFunction( + IN gco3D Engine, + IN gctINT Stage, + IN gceTEXTURE_FUNCTION Function, + IN gceTEXTURE_SOURCE Source0, + IN gceTEXTURE_CHANNEL Channel0, + IN gceTEXTURE_SOURCE Source1, + IN gceTEXTURE_CHANNEL Channel1, + IN gceTEXTURE_SOURCE Source2, + IN gceTEXTURE_CHANNEL Channel2, + IN gctINT Scale + ); + + +/******************************************************************************\ +******************************* gcoTEXTURE Object ******************************* +\******************************************************************************/ + +/* Cube faces. */ +typedef enum _gceTEXTURE_FACE +{ + gcvFACE_NONE, + gcvFACE_POSITIVE_X, + gcvFACE_NEGATIVE_X, + gcvFACE_POSITIVE_Y, + gcvFACE_NEGATIVE_Y, + gcvFACE_POSITIVE_Z, + gcvFACE_NEGATIVE_Z, +} +gceTEXTURE_FACE; + +/* Construct a new gcoTEXTURE object. */ +gceSTATUS +gcoTEXTURE_Construct( + IN gcoHAL Hal, + OUT gcoTEXTURE * Texture + ); + +/* Construct a new sized gcoTEXTURE object. */ +gceSTATUS +gcoTEXTURE_ConstructSized( + IN gcoHAL Hal, + IN gceSURF_FORMAT Format, + IN gctUINT Width, + IN gctUINT Height, + IN gctUINT Depth, + IN gctUINT Faces, + IN gctUINT MipMapCount, + IN gcePOOL Pool, + OUT gcoTEXTURE * Texture + ); + +/* Destroy an gcoTEXTURE object. */ +gceSTATUS +gcoTEXTURE_Destroy( + IN gcoTEXTURE Texture + ); + +/* Upload data to an gcoTEXTURE object. */ +gceSTATUS +gcoTEXTURE_Upload( + IN gcoTEXTURE Texture, + IN gceTEXTURE_FACE Face, + IN gctUINT Width, + IN gctUINT Height, + IN gctUINT Slice, + IN gctCONST_POINTER Memory, + IN gctINT Stride, + IN gceSURF_FORMAT Format + ); + +/* Upload data to an gcoTEXTURE object. */ +gceSTATUS +gcoTEXTURE_UploadSub( + IN gcoTEXTURE Texture, + IN gctUINT MipMap, + IN gceTEXTURE_FACE Face, + IN gctUINT X, + IN gctUINT Y, + IN gctUINT Width, + IN gctUINT Height, + IN gctUINT Slice, + IN gctCONST_POINTER Memory, + IN gctINT Stride, + IN gceSURF_FORMAT Format + ); + +/* Upload compressed data to an gcoTEXTURE object. */ +gceSTATUS +gcoTEXTURE_UploadCompressed( + IN gcoTEXTURE Texture, + IN gceTEXTURE_FACE Face, + IN gctUINT Width, + IN gctUINT Height, + IN gctUINT Slice, + IN gctCONST_POINTER Memory, + IN gctSIZE_T Bytes + ); + +/* Get gcoSURF object for a mipmap level. */ +gceSTATUS +gcoTEXTURE_GetMipMap( + IN gcoTEXTURE Texture, + IN gctUINT MipMap, + OUT gcoSURF * Surface + ); + +/* Get gcoSURF object for a mipmap level and face offset. */ +gceSTATUS +gcoTEXTURE_GetMipMapFace( + IN gcoTEXTURE Texture, + IN gctUINT MipMap, + IN gceTEXTURE_FACE Face, + OUT gcoSURF * Surface, + OUT gctUINT32_PTR Offset + ); + +gceSTATUS +gcoTEXTURE_AddMipMap( + IN gcoTEXTURE Texture, + IN gctINT Level, + IN gceSURF_FORMAT Format, + IN gctUINT Width, + IN gctUINT Height, + IN gctUINT Depth, + IN gctUINT Faces, + IN gcePOOL Pool, + OUT gcoSURF * Surface + ); + +gceSTATUS +gcoTEXTURE_AddMipMapFromClient( + IN gcoTEXTURE Texture, + IN gctINT Level, + IN gcoSURF Surface + ); + +gceSTATUS +gcoTEXTURE_AddMipMapFromSurface( + IN gcoTEXTURE Texture, + IN gctINT Level, + IN gcoSURF Surface + ); + +gceSTATUS +gcoTEXTURE_SetEndianHint( + IN gcoTEXTURE Texture, + IN gceENDIAN_HINT EndianHint + ); + +gceSTATUS +gcoTEXTURE_SetAddressingMode( + IN gcoTEXTURE Texture, + IN gceTEXTURE_WHICH Which, + IN gceTEXTURE_ADDRESSING Mode + ); + +gceSTATUS +gcoTEXTURE_SetBorderColor( + IN gcoTEXTURE Texture, + IN gctUINT Red, + IN gctUINT Green, + IN gctUINT Blue, + IN gctUINT Alpha + ); + +gceSTATUS +gcoTEXTURE_SetBorderColorX( + IN gcoTEXTURE Texture, + IN gctFIXED_POINT Red, + IN gctFIXED_POINT Green, + IN gctFIXED_POINT Blue, + IN gctFIXED_POINT Alpha + ); + +gceSTATUS +gcoTEXTURE_SetBorderColorF( + IN gcoTEXTURE Texture, + IN gctFLOAT Red, + IN gctFLOAT Green, + IN gctFLOAT Blue, + IN gctFLOAT Alpha + ); + +gceSTATUS +gcoTEXTURE_SetMinFilter( + IN gcoTEXTURE Texture, + IN gceTEXTURE_FILTER Filter + ); + +gceSTATUS +gcoTEXTURE_SetMagFilter( + IN gcoTEXTURE Texture, + IN gceTEXTURE_FILTER Filter + ); + +gceSTATUS +gcoTEXTURE_SetMipFilter( + IN gcoTEXTURE Texture, + IN gceTEXTURE_FILTER Filter + ); + +gceSTATUS +gcoTEXTURE_SetLODBiasX( + IN gcoTEXTURE Texture, + IN gctFIXED_POINT Bias + ); + +gceSTATUS +gcoTEXTURE_SetLODBiasF( + IN gcoTEXTURE Texture, + IN gctFLOAT Bias + ); + +gceSTATUS +gcoTEXTURE_SetLODMinX( + IN gcoTEXTURE Texture, + IN gctFIXED_POINT LevelOfDetail + ); + +gceSTATUS +gcoTEXTURE_SetLODMinF( + IN gcoTEXTURE Texture, + IN gctFLOAT LevelOfDetail + ); + +gceSTATUS +gcoTEXTURE_SetLODMaxX( + IN gcoTEXTURE Texture, + IN gctFIXED_POINT LevelOfDetail + ); + +gceSTATUS +gcoTEXTURE_SetLODMaxF( + IN gcoTEXTURE Texture, + IN gctFLOAT LevelOfDetail + ); + +gceSTATUS +gcoTEXTURE_Bind( + IN gcoTEXTURE Texture, + IN gctINT Sampler + ); + +gceSTATUS +gcoTEXTURE_Disable( + IN gcoHAL Hal, + IN gctINT Sampler + ); + +gceSTATUS +gcoTEXTURE_Flush( + IN gcoTEXTURE Texture + ); + +gceSTATUS +gcoTEXTURE_QueryCaps( + OUT gctUINT * MaxWidth, + OUT gctUINT * MaxHeight, + OUT gctUINT * MaxDepth, + OUT gctBOOL * Cubic, + OUT gctBOOL * NonPowerOfTwo, + OUT gctUINT * VertexSamplers, + OUT gctUINT * PixelSamplers + ); + +gceSTATUS +gcoTEXTURE_GetClosestFormat( + IN gcoHAL Hal, + IN gceSURF_FORMAT InFormat, + OUT gceSURF_FORMAT* OutFormat + ); + +gceSTATUS +gcoTEXTURE_RenderIntoMipMap( + IN gcoTEXTURE Texture, + IN gctINT Level + ); + +gceSTATUS +gcoTEXTURE_IsRenderable( + IN gcoTEXTURE Texture, + IN gctUINT Level + ); + +gceSTATUS +gcoTEXTURE_IsComplete( + IN gcoTEXTURE Texture, + IN gctINT MaxLevel + ); + +/******************************************************************************\ +******************************* gcoSTREAM Object ****************************** +\******************************************************************************/ + +typedef enum _gceVERTEX_FORMAT +{ + gcvVERTEX_BYTE, + gcvVERTEX_UNSIGNED_BYTE, + gcvVERTEX_SHORT, + gcvVERTEX_UNSIGNED_SHORT, + gcvVERTEX_INT, + gcvVERTEX_UNSIGNED_INT, + gcvVERTEX_FIXED, + gcvVERTEX_HALF, + gcvVERTEX_FLOAT, +} +gceVERTEX_FORMAT; + +gceSTATUS +gcoSTREAM_Construct( + IN gcoHAL Hal, + OUT gcoSTREAM * Stream + ); + +gceSTATUS +gcoSTREAM_Destroy( + IN gcoSTREAM Stream + ); + +gceSTATUS +gcoSTREAM_Upload( + IN gcoSTREAM Stream, + IN gctCONST_POINTER Buffer, + IN gctUINT32 Offset, + IN gctSIZE_T Bytes, + IN gctBOOL Dynamic + ); + +gceSTATUS +gcoSTREAM_SetStride( + IN gcoSTREAM Stream, + IN gctUINT32 Stride + ); + +gceSTATUS +gcoSTREAM_Lock( + IN gcoSTREAM Stream, + OUT gctPOINTER * Logical, + OUT gctUINT32 * Physical + ); + +gceSTATUS +gcoSTREAM_Unlock( + IN gcoSTREAM Stream); + +gceSTATUS +gcoSTREAM_Reserve( + IN gcoSTREAM Stream, + IN gctSIZE_T Bytes + ); + +gceSTATUS +gcoSTREAM_Flush( + IN gcoSTREAM Stream + ); + +/* Dynamic buffer API. */ +gceSTATUS +gcoSTREAM_SetDynamic( + IN gcoSTREAM Stream, + IN gctSIZE_T Bytes, + IN gctUINT Buffers + ); + +typedef struct _gcsSTREAM_INFO +{ + gctUINT index; + gceVERTEX_FORMAT format; + gctBOOL normalized; + gctUINT components; + gctSIZE_T size; + gctCONST_POINTER data; + gctUINT stride; +} +gcsSTREAM_INFO, * gcsSTREAM_INFO_PTR; + +gceSTATUS +gcoSTREAM_UploadDynamic( + IN gcoSTREAM Stream, + IN gctUINT VertexCount, + IN gctUINT InfoCount, + IN gcsSTREAM_INFO_PTR Info, + IN gcoVERTEX Vertex + ); + +/******************************************************************************\ +******************************** gcoVERTEX Object ****************************** +\******************************************************************************/ + +typedef struct _gcsVERTEX_ATTRIBUTES +{ + gceVERTEX_FORMAT format; + gctBOOL normalized; + gctUINT32 components; + gctSIZE_T size; + gctUINT32 stream; + gctUINT32 offset; + gctUINT32 stride; +} +gcsVERTEX_ATTRIBUTES; + +gceSTATUS +gcoVERTEX_Construct( + IN gcoHAL Hal, + OUT gcoVERTEX * Vertex + ); + +gceSTATUS +gcoVERTEX_Destroy( + IN gcoVERTEX Vertex + ); + +gceSTATUS +gcoVERTEX_Reset( + IN gcoVERTEX Vertex + ); + +gceSTATUS +gcoVERTEX_EnableAttribute( + IN gcoVERTEX Vertex, + IN gctUINT32 Index, + IN gceVERTEX_FORMAT Format, + IN gctBOOL Normalized, + IN gctUINT32 Components, + IN gcoSTREAM Stream, + IN gctUINT32 Offset, + IN gctUINT32 Stride + ); + +gceSTATUS +gcoVERTEX_DisableAttribute( + IN gcoVERTEX Vertex, + IN gctUINT32 Index + ); + +gceSTATUS +gcoVERTEX_Bind( + IN gcoVERTEX Vertex + ); + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_engine_h_ */ + diff --git a/drivers/staging/rk29/vivante/hal/inc/gc_hal_enum.h b/drivers/staging/rk29/vivante/hal/inc/gc_hal_enum.h new file mode 100644 index 000000000000..18cfd70f1932 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/inc/gc_hal_enum.h @@ -0,0 +1,550 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_enum_h_ +#define __gc_hal_enum_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Chip models. */ +typedef enum _gceCHIPMODEL +{ + gcv300 = 0x0300, + gcv400 = 0x0400, + gcv410 = 0x0410, + gcv450 = 0x0450, + gcv500 = 0x0500, + gcv530 = 0x0530, + gcv600 = 0x0600, + gcv700 = 0x0700, + gcv800 = 0x0800, + gcv860 = 0x0860, + gcv1000 = 0x1000, +} +gceCHIPMODEL; + +/* Chip features. */ +typedef enum _gceFEATURE +{ + gcvFEATURE_PIPE_2D, + gcvFEATURE_PIPE_3D, + gcvFEATURE_PIPE_VG, + gcvFEATURE_DC, + gcvFEATURE_HIGH_DYNAMIC_RANGE, + gcvFEATURE_MODULE_CG, + gcvFEATURE_MIN_AREA, + gcvFEATURE_BUFFER_INTERLEAVING, + gcvFEATURE_BYTE_WRITE_2D, + gcvFEATURE_ENDIANNESS_CONFIG, + gcvFEATURE_DUAL_RETURN_BUS, + gcvFEATURE_DEBUG_MODE, + gcvFEATURE_YUY2_RENDER_TARGET, + gcvFEATURE_FRAGMENT_PROCESSOR, + gcvFEATURE_2DPE20, + gcvFEATURE_FAST_CLEAR, + gcvFEATURE_YUV420_TILER, + gcvFEATURE_YUY2_AVERAGING, + gcvFEATURE_FLIP_Y, + gcvFEATURE_EARLY_Z, + gcvFEATURE_Z_COMPRESSION, + gcvFEATURE_MSAA, + gcvFEATURE_SPECIAL_ANTI_ALIASING, + gcvFEATURE_SPECIAL_MSAA_LOD, + gcvFEATURE_422_TEXTURE_COMPRESSION, + gcvFEATURE_DXT_TEXTURE_COMPRESSION, + gcvFEATURE_ETC1_TEXTURE_COMPRESSION, + gcvFEATURE_CORRECT_TEXTURE_CONVERTER, + gcvFEATURE_TEXTURE_8K, + gcvFEATURE_SCALER, + gcvFEATURE_YUV420_SCALER, + gcvFEATURE_SHADER_HAS_W, + gcvFEATURE_SHADER_HAS_SIGN, + gcvFEATURE_SHADER_HAS_FLOOR, + gcvFEATURE_SHADER_HAS_CEIL, + gcvFEATURE_SHADER_HAS_SQRT, + gcvFEATURE_SHADER_HAS_TRIG, + gcvFEATURE_VAA, + gcvFEATURE_HZ, + gcvFEATURE_CORRECT_STENCIL, + gcvFEATURE_VG20, + gcvFEATURE_VG_FILTER, + gcvFEATURE_VG21, + gcvFEATURE_VG_DOUBLE_BUFFER, + gcvFEATURE_MC20, + gcvFEATURE_SUPER_TILED, +} +gceFEATURE; + +/* Chip Power Status. */ +typedef enum _gceCHIPPOWERSTATE +{ + gcvPOWER_ON, + gcvPOWER_OFF, + gcvPOWER_IDLE, + gcvPOWER_SUSPEND, + gcvPOWER_SUSPEND_ATPOWERON, + gcvPOWER_OFF_ATPOWERON, + gcvPOWER_IDLE_BROADCAST, + gcvPOWER_SUSPEND_BROADCAST, + gcvPOWER_OFF_BROADCAST, + gcvPOWER_OFF_RECOVERY, +} +gceCHIPPOWERSTATE; + +/* Surface types. */ +typedef enum _gceSURF_TYPE +{ + gcvSURF_TYPE_UNKNOWN, + gcvSURF_INDEX, + gcvSURF_VERTEX, + gcvSURF_TEXTURE, + gcvSURF_RENDER_TARGET, + gcvSURF_DEPTH, + gcvSURF_BITMAP, + gcvSURF_TILE_STATUS, + gcvSURF_MASK, + gcvSURF_SCISSOR, + gcvSURF_HIERARCHICAL_DEPTH, + gcvSURF_NUM_TYPES, /* Make sure this is the last one! */ + + /* Combinations. */ + gcvSURF_NO_TILE_STATUS = 0x100, + gcvSURF_RENDER_TARGET_NO_TILE_STATUS = gcvSURF_RENDER_TARGET + | gcvSURF_NO_TILE_STATUS, + gcvSURF_DEPTH_NO_TILE_STATUS = gcvSURF_DEPTH + | gcvSURF_NO_TILE_STATUS, +} +gceSURF_TYPE; + +typedef enum _gceSURF_COLOR_TYPE +{ + gcvSURF_COLOR_UNKNOWN, + gcvSURF_COLOR_LINEAR = 0x01, + gcvSURF_COLOR_ALPHA_PRE = 0x02, +} +gceSURF_COLOR_TYPE; + +/* Rotation. */ +typedef enum _gceSURF_ROTATION +{ + gcvSURF_0_DEGREE, + gcvSURF_90_DEGREE, + gcvSURF_180_DEGREE, + gcvSURF_270_DEGREE +} +gceSURF_ROTATION; + +/* Surface formats. */ +typedef enum _gceSURF_FORMAT +{ + /* Unknown format. */ + gcvSURF_UNKNOWN, + + /* Palettized formats. */ + gcvSURF_INDEX1 = 100, + gcvSURF_INDEX4, + gcvSURF_INDEX8, + + /* RGB formats. */ + gcvSURF_A2R2G2B2 = 200, + gcvSURF_R3G3B2, + gcvSURF_A8R3G3B2, + gcvSURF_X4R4G4B4, + gcvSURF_A4R4G4B4, + gcvSURF_R4G4B4A4, + gcvSURF_X1R5G5B5, + gcvSURF_A1R5G5B5, + gcvSURF_R5G5B5A1, + gcvSURF_R5G6B5, + gcvSURF_R8G8B8, + gcvSURF_X8R8G8B8, + gcvSURF_A8R8G8B8, + gcvSURF_R8G8B8A8, + gcvSURF_G8R8G8B8, + gcvSURF_R8G8B8G8, + gcvSURF_X2R10G10B10, + gcvSURF_A2R10G10B10, + gcvSURF_X12R12G12B12, + gcvSURF_A12R12G12B12, + gcvSURF_X16R16G16B16, + gcvSURF_A16R16G16B16, + gcvSURF_R8G8B8X8, + gcvSURF_R5G5B5X1, + gcvSURF_R4G4B4X4, + + /* BGR formats. */ + gcvSURF_A4B4G4R4 = 300, + gcvSURF_A1B5G5R5, + gcvSURF_B5G6R5, + gcvSURF_B8G8R8, + gcvSURF_X8B8G8R8, + gcvSURF_A8B8G8R8, + gcvSURF_A2B10G10R10, + gcvSURF_A16B16G16R16, + gcvSURF_G16R16, + gcvSURF_B4G4R4A4, + gcvSURF_B5G5R5A1, + gcvSURF_B8G8R8X8, + gcvSURF_B8G8R8A8, + gcvSURF_X4B4G4R4, + gcvSURF_X1B5G5R5, + gcvSURF_B4G4R4X4, + gcvSURF_B5G5R5X1, + + /* Compressed formats. */ + gcvSURF_DXT1 = 400, + gcvSURF_DXT2, + gcvSURF_DXT3, + gcvSURF_DXT4, + gcvSURF_DXT5, + gcvSURF_CXV8U8, + gcvSURF_ETC1, + + /* YUV formats. */ + gcvSURF_YUY2 = 500, + gcvSURF_UYVY, + gcvSURF_YV12, + gcvSURF_I420, + gcvSURF_NV12, + gcvSURF_NV21, + gcvSURF_NV16, + gcvSURF_NV61, + gcvSURF_YVYU, + gcvSURF_VYUY, + + /* Depth formats. */ + gcvSURF_D16 = 600, + gcvSURF_D24S8, + gcvSURF_D32, + gcvSURF_D24X8, + + /* Alpha formats. */ + gcvSURF_A4 = 700, + gcvSURF_A8, + gcvSURF_A12, + gcvSURF_A16, + gcvSURF_A32, + gcvSURF_A1, + + /* Luminance formats. */ + gcvSURF_L4 = 800, + gcvSURF_L8, + gcvSURF_L12, + gcvSURF_L16, + gcvSURF_L32, + gcvSURF_L1, + + /* Alpha/Luminance formats. */ + gcvSURF_A4L4 = 900, + gcvSURF_A2L6, + gcvSURF_A8L8, + gcvSURF_A4L12, + gcvSURF_A12L12, + gcvSURF_A16L16, + + /* Bump formats. */ + gcvSURF_L6V5U5 = 1000, + gcvSURF_V8U8, + gcvSURF_X8L8V8U8, + gcvSURF_Q8W8V8U8, + gcvSURF_A2W10V10U10, + gcvSURF_V16U16, + gcvSURF_Q16W16V16U16, + + /* Floating point formats. */ + gcvSURF_R16F = 1100, + gcvSURF_G16R16F, + gcvSURF_A16B16G16R16F, + gcvSURF_R32F, + gcvSURF_G32R32F, + gcvSURF_A32B32G32R32F, + +#if 0 + /* FIXME: remove HDR support for now. */ + /* HDR formats. */ + gcvSURF_HDR7E3 = 1200, + gcvSURF_HDR6E4, + gcvSURF_HDR5E5, + gcvSURF_HDR6E5, +#endif +} +gceSURF_FORMAT; + +/* Pixel swizzle modes. */ +typedef enum _gceSURF_SWIZZLE +{ + gcvSURF_NOSWIZZLE, + gcvSURF_ARGB, + gcvSURF_ABGR, + gcvSURF_RGBA, + gcvSURF_BGRA +} +gceSURF_SWIZZLE; + +/* Transparency modes. */ +typedef enum _gceSURF_TRANSPARENCY +{ + /* Valid only for PE 1.0 */ + gcvSURF_OPAQUE, + gcvSURF_SOURCE_MATCH, + gcvSURF_SOURCE_MASK, + gcvSURF_PATTERN_MASK, +} +gceSURF_TRANSPARENCY; + +/* Transparency modes. */ +typedef enum _gce2D_TRANSPARENCY +{ + /* Valid only for PE 2.0 */ + gcv2D_OPAQUE, + gcv2D_KEYED, + gcv2D_MASKED +} +gce2D_TRANSPARENCY; + +/* Mono packing modes. */ +typedef enum _gceSURF_MONOPACK +{ + gcvSURF_PACKED8, + gcvSURF_PACKED16, + gcvSURF_PACKED32, + gcvSURF_UNPACKED, +} +gceSURF_MONOPACK; + +/* Blending modes. */ +typedef enum _gceSURF_BLEND_MODE +{ + /* Porter-Duff blending modes. */ + /* Fsrc Fdst */ + gcvBLEND_CLEAR, /* 0 0 */ + gcvBLEND_SRC, /* 1 0 */ + gcvBLEND_DST, /* 0 1 */ + gcvBLEND_SRC_OVER_DST, /* 1 1 - Asrc */ + gcvBLEND_DST_OVER_SRC, /* 1 - Adst 1 */ + gcvBLEND_SRC_IN_DST, /* Adst 0 */ + gcvBLEND_DST_IN_SRC, /* 0 Asrc */ + gcvBLEND_SRC_OUT_DST, /* 1 - Adst 0 */ + gcvBLEND_DST_OUT_SRC, /* 0 1 - Asrc */ + gcvBLEND_SRC_ATOP_DST, /* Adst 1 - Asrc */ + gcvBLEND_DST_ATOP_SRC, /* 1 - Adst Asrc */ + gcvBLEND_SRC_XOR_DST, /* 1 - Adst 1 - Asrc */ + + /* Special blending modes. */ + gcvBLEND_SET, /* DST = 1 */ + gcvBLEND_SUB /* DST = DST * (1 - SRC) */ +} +gceSURF_BLEND_MODE; + +/* Per-pixel alpha modes. */ +typedef enum _gceSURF_PIXEL_ALPHA_MODE +{ + gcvSURF_PIXEL_ALPHA_STRAIGHT, + gcvSURF_PIXEL_ALPHA_INVERSED +} +gceSURF_PIXEL_ALPHA_MODE; + +/* Global alpha modes. */ +typedef enum _gceSURF_GLOBAL_ALPHA_MODE +{ + gcvSURF_GLOBAL_ALPHA_OFF, + gcvSURF_GLOBAL_ALPHA_ON, + gcvSURF_GLOBAL_ALPHA_SCALE +} +gceSURF_GLOBAL_ALPHA_MODE; + +/* Color component modes for alpha blending. */ +typedef enum _gceSURF_PIXEL_COLOR_MODE +{ + gcvSURF_COLOR_STRAIGHT, + gcvSURF_COLOR_MULTIPLY +} +gceSURF_PIXEL_COLOR_MODE; + +/* Color component modes for alpha blending. */ +typedef enum _gce2D_PIXEL_COLOR_MULTIPLY_MODE +{ + gcv2D_COLOR_MULTIPLY_DISABLE, + gcv2D_COLOR_MULTIPLY_ENABLE +} +gce2D_PIXEL_COLOR_MULTIPLY_MODE; + +/* Color component modes for alpha blending. */ +typedef enum _gce2D_GLOBAL_COLOR_MULTIPLY_MODE +{ + gcv2D_GLOBAL_COLOR_MULTIPLY_DISABLE, + gcv2D_GLOBAL_COLOR_MULTIPLY_ALPHA, + gcv2D_GLOBAL_COLOR_MULTIPLY_COLOR +} +gce2D_GLOBAL_COLOR_MULTIPLY_MODE; + +/* Alpha blending factor modes. */ +typedef enum _gceSURF_BLEND_FACTOR_MODE +{ + gcvSURF_BLEND_ZERO, + gcvSURF_BLEND_ONE, + gcvSURF_BLEND_STRAIGHT, + gcvSURF_BLEND_INVERSED, + gcvSURF_BLEND_COLOR, + gcvSURF_BLEND_COLOR_INVERSED, + gcvSURF_BLEND_SRC_ALPHA_SATURATED +} +gceSURF_BLEND_FACTOR_MODE; + +/* Alpha blending porter duff rules. */ +typedef enum _gce2D_PORTER_DUFF_RULE +{ + gcvPD_CLEAR, + gcvPD_SRC, + gcvPD_SRC_OVER, + gcvPD_DST_OVER, + gcvPD_SRC_IN, + gcvPD_DST_IN, + gcvPD_SRC_OUT, + gcvPD_DST_OUT, + gcvPD_SRC_ATOP, + gcvPD_DST_ATOP, + gcvPD_ADD, + gcvPD_XOR, + gcvPD_DST +} +gce2D_PORTER_DUFF_RULE; + +/* Alpha blending factor modes. */ +typedef enum _gce2D_YUV_COLOR_MODE +{ + gcv2D_YUV_601, + gcv2D_YUV_709 +} +gce2D_YUV_COLOR_MODE; + +/* 2D Rotation and flipping. */ +typedef enum _gce2D_ORIENTATION +{ + gcv2D_0_DEGREE, + gcv2D_90_DEGREE, + gcv2D_180_DEGREE, + gcv2D_270_DEGREE, + gcv2D_X_FLIP, + gcv2D_Y_FLIP +} +gce2D_ORIENTATION; + +typedef enum _gce2D_COMMAND +{ + gcv2D_CLEAR, + gcv2D_LINE, + gcv2D_BLT, + gcv2D_STRETCH, + gcv2D_HOR_FILTER, + gcv2D_VER_FILTER, +} +gce2D_COMMAND; + +/* Texture functions. */ +typedef enum _gceTEXTURE_FUNCTION +{ + gcvTEXTURE_DUMMY = 0, + gcvTEXTURE_REPLACE = 0, + gcvTEXTURE_MODULATE, + gcvTEXTURE_ADD, + gcvTEXTURE_ADD_SIGNED, + gcvTEXTURE_INTERPOLATE, + gcvTEXTURE_SUBTRACT, + gcvTEXTURE_DOT3 +} +gceTEXTURE_FUNCTION; + +/* Texture sources. */ +typedef enum _gceTEXTURE_SOURCE +{ + gcvCOLOR_FROM_TEXTURE, + gcvCOLOR_FROM_CONSTANT_COLOR, + gcvCOLOR_FROM_PRIMARY_COLOR, + gcvCOLOR_FROM_PREVIOUS_COLOR +} +gceTEXTURE_SOURCE; + +/* Texture source channels. */ +typedef enum _gceTEXTURE_CHANNEL +{ + gcvFROM_COLOR, + gcvFROM_ONE_MINUS_COLOR, + gcvFROM_ALPHA, + gcvFROM_ONE_MINUS_ALPHA +} +gceTEXTURE_CHANNEL; + +/* Filter types. */ +typedef enum _gceFILTER_TYPE +{ + gcvFILTER_SYNC, + gcvFILTER_BLUR, + gcvFILTER_USER +} +gceFILTER_TYPE; + +/* Filter pass types. */ +typedef enum _gceFILTER_PASS_TYPE +{ + gcvFILTER_HOR_PASS, + gcvFILTER_VER_PASS +} +gceFILTER_PASS_TYPE; + +/* Endian hints. */ +typedef enum _gceENDIAN_HINT +{ + gcvENDIAN_NO_SWAP = 0, + gcvENDIAN_SWAP_WORD, + gcvENDIAN_SWAP_DWORD +} +gceENDIAN_HINT; + +/* Endian hints. */ +typedef enum _gceTILING +{ + gcvLINEAR, + gcvTILED, + gcvSUPERTILED +} +gceTILING; + +/******************************************************************************\ +****************************** Object Declarations ***************************** +\******************************************************************************/ + +typedef struct _gcoCONTEXT * gcoCONTEXT; +typedef struct _gcoCMDBUF * gcoCMDBUF; +typedef struct _gcoQUEUE * gcoQUEUE; +typedef struct _gcsHAL_INTERFACE * gcsHAL_INTERFACE_PTR; +typedef struct gcs2D_PROFILE * gcs2D_PROFILE_PTR; + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_enum_h_ */ + diff --git a/drivers/staging/rk29/vivante/hal/inc/gc_hal_mem.h b/drivers/staging/rk29/vivante/hal/inc/gc_hal_mem.h new file mode 100644 index 000000000000..9b7d28ccb1a5 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/inc/gc_hal_mem.h @@ -0,0 +1,471 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +/* +** Include file for the local memory management. +*/ + +#ifndef __gc_hal_mem_h_ +#define __gc_hal_mem_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************* +** Usage: + + The macros to declare MemPool type and functions are + gcmMEM_DeclareFSMemPool (Type, TypeName, Prefix) + gcmMEM_DeclareVSMemPool (Type, TypeName, Prefix) + gcmMEM_DeclareAFSMemPool(Type, TypeName, Prefix) + + The data structures for MemPool are + typedef struct _gcsMEM_FS_MEM_POOL * gcsMEM_FS_MEM_POOL; + typedef struct _gcsMEM_VS_MEM_POOL * gcsMEM_VS_MEM_POOL; + typedef struct _gcsMEM_AFS_MEM_POOL * gcsMEM_AFS_MEM_POOL; + + The MemPool constructor and destructor functions are + gcfMEM_InitFSMemPool(gcsMEM_FS_MEM_POOL *, gcoOS, gctUINT, gctUINT); + gcfMEM_FreeFSMemPool(gcsMEM_FS_MEM_POOL *); + gcfMEM_InitVSMemPool(gcsMEM_VS_MEM_POOL *, gcoOS, gctUINT, gctBOOL); + gcfMEM_FreeVSMemPool(gcsMEM_VS_MEM_POOL *); + gcfMEM_InitAFSMemPool(gcsMEM_AFS_MEM_POOL *, gcoOS, gctUINT); + gcfMEM_FreeAFSMemPool(gcsMEM_AFS_MEM_POOL *); + + FS: for Fixed-Size data structures + VS: for Variable-size data structures + AFS: for Array of Fixed-Size data structures + + + // Example 1: For a fixed-size data structure, struct gcsNode. + // It is used locally in a file, so the functions are static without prefix. + // At top level, declear allocate and free functions. + // The first argument is the data type. + // The second armument is the short name used in the fuctions. + gcmMEM_DeclareFSMemPool(struct gcsNode, Node, ); + + // The previous macro creates two inline functions, + // _AllocateNode and _FreeNode. + + // In function or struct + gcsMEM_FS_MEM_POOL nodeMemPool; + + // In function, + struct gcsNode * node; + gceSTATUS status; + + // Before using the memory pool, initialize it. + // The second argument is the gcoOS object. + // The third argument is the number of data structures to allocate for each chunk. + status = gcfMEM_InitFSMemPool(&nodeMemPool, os, 100, sizeof(struct gcsNode)); + ... + + // Allocate a node. + status = _AllocateNode(nodeMemPool, &node); + ... + // Free a node. + _FreeNode(nodeMemPool, node); + + // After using the memory pool, free it. + gcfMEM_FreeFSMemPool(&nodeMemPool); + + + // Example 2: For array of fixed-size data structures, struct gcsNode. + // It is used in several files, so the functions are extern with prefix. + // At top level, declear allocate and free functions. + // The first argument is the data type, and the second one is the short name + // used in the fuctions. + gcmMEM_DeclareAFSMemPool(struct gcsNode, NodeArray, gcfOpt); + + // The previous macro creates two inline functions, + // gcfOpt_AllocateNodeArray and gcfOpt_FreeNodeArray. + + // In function or struct + gcsMEM_AFS_MEM_POOL nodeArrayMemPool; + + // In function, + struct gcsNode * nodeArray; + gceSTATUS status; + + // Before using the array memory pool, initialize it. + // The second argument is the gcoOS object, the third is the number of data + // structures to allocate for each chunk. + status = gcfMEM_InitAFSMemPool(&nodeArrayMemPool, os, sizeof(struct gcsNode)); + ... + + // Allocate a node array of size 100. + status = gcfOpt_AllocateNodeArray(nodeArrayMemPool, &nodeArray, 100); + ... + // Free a node array. + gcfOpt_FreeNodeArray(&nodeArrayMemPool, nodeArray); + + // After using the array memory pool, free it. + gcfMEM_FreeAFSMemPool(&nodeArrayMemPool); + +*******************************************************************************/ + +/******************************************************************************* +** To switch back to use gcoOS_Allocate and gcoOS_Free, add +** #define USE_LOCAL_MEMORY_POOL 0 +** before including this file. +*******************************************************************************/ +#ifndef USE_LOCAL_MEMORY_POOL +/* + USE_LOCAL_MEMORY_POOL + + This define enables the local memory management to improve performance. +*/ +#define USE_LOCAL_MEMORY_POOL 1 +#endif + +/******************************************************************************* +** Memory Pool Data Structures +*******************************************************************************/ +#if USE_LOCAL_MEMORY_POOL + typedef struct _gcsMEM_FS_MEM_POOL * gcsMEM_FS_MEM_POOL; + typedef struct _gcsMEM_VS_MEM_POOL * gcsMEM_VS_MEM_POOL; + typedef struct _gcsMEM_AFS_MEM_POOL * gcsMEM_AFS_MEM_POOL; +#else + typedef gcoOS gcsMEM_FS_MEM_POOL; + typedef gcoOS gcsMEM_VS_MEM_POOL; + typedef gcoOS gcsMEM_AFS_MEM_POOL; +#endif + +/******************************************************************************* +** Memory Pool Macros +*******************************************************************************/ +#if USE_LOCAL_MEMORY_POOL +#define gcmMEM_DeclareFSMemPool(Type, TypeName, Prefix) \ +gceSTATUS \ +Prefix##_Allocate##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type ** Pointer \ + ) \ +{ \ + return(gcfMEM_FSMemPoolGetANode(MemPool, (gctPOINTER *) Pointer)); \ +} \ + \ +gceSTATUS \ +Prefix##_CAllocate##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type ** Pointer \ + ) \ +{ \ + gceSTATUS status; \ + gcmERR_RETURN(gcfMEM_FSMemPoolGetANode(MemPool, (gctPOINTER *) Pointer)); \ + gcmVERIFY_OK(gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, gcmSIZEOF(Type))); \ + return gcvSTATUS_OK; \ +} \ + \ +gceSTATUS \ +Prefix##_Free##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type * Pointer \ + ) \ +{ \ + return(gcfMEM_FSMemPoolFreeANode(MemPool, (gctPOINTER) Pointer)); \ +} \ + \ +gceSTATUS \ +Prefix##_Free##TypeName##List( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type * FirstPointer, \ + Type * LastPointer \ + ) \ +{ \ + return(gcfMEM_FSMemPoolFreeAList(MemPool, (gctPOINTER) FirstPointer, (gctPOINTER) LastPointer)); \ +} + +#define gcmMEM_DeclareVSMemPool(Type, TypeName, Prefix) \ +gceSTATUS \ +Prefix##_Allocate##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type ** Pointer, \ + gctUINT Size \ + ) \ +{ \ + return(gcfMEM_VSMemPoolGetANode(MemPool, Size, (gctPOINTER *) Pointer)); \ +} \ + \ +gceSTATUS \ + Prefix##_CAllocate##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type ** Pointer, \ + gctUINT Size \ + ) \ +{ \ + gceSTATUS status; \ + gcmERR_RETURN(gcfMEM_VSMemPoolGetANode(MemPool, Size, (gctPOINTER *) Pointer)); \ + gcmVERIFY_OK(gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, size)); \ + return gcvSTATUS_OK; \ +} \ + \ +gceSTATUS \ +Prefix##_Free##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type * Pointer \ + ) \ +{ \ + return(gcfMEM_VSMemPoolFreeANode(MemPool, (gctPOINTER) Pointer)); \ +} + +#define gcmMEM_DeclareAFSMemPool(Type, TypeName, Prefix) \ +gceSTATUS \ +Prefix##_Allocate##TypeName( \ + gcsMEM_AFS_MEM_POOL MemPool, \ + Type ** Pointer, \ + gctUINT Count \ + ) \ +{ \ + return(gcfMEM_AFSMemPoolGetANode(MemPool, Count, (gctPOINTER *) Pointer)); \ +} \ + \ +gceSTATUS \ +Prefix##_CAllocate##TypeName( \ + gcsMEM_AFS_MEM_POOL MemPool, \ + Type ** Pointer, \ + gctUINT Count \ + ) \ +{ \ + gceSTATUS status; \ + gcmERR_RETURN(gcfMEM_AFSMemPoolGetANode(MemPool, Count, (gctPOINTER *) Pointer)); \ + gcmVERIFY_OK(gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, Count * gcmSIZEOF(Type))); \ + return gcvSTATUS_OK; \ +} \ + \ +gceSTATUS \ +Prefix##_Free##TypeName( \ + gcsMEM_AFS_MEM_POOL MemPool, \ + Type * Pointer \ + ) \ +{ \ + return(gcfMEM_AFSMemPoolFreeANode(MemPool, (gctPOINTER) Pointer)); \ +} + +#else + +#define gcmMEM_DeclareFSMemPool(Type, TypeName, Prefix) \ +gceSTATUS \ +Prefix##_Allocate##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type ** Pointer \ + ) \ +{ \ + return(gcoOS_Allocate(MemPool, \ + gcmSIZEOF(Type), \ + (gctPOINTER *) Pointer)); \ +} \ + \ +gceSTATUS \ +Prefix##_CAllocate##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type ** Pointer \ + ) \ +{ \ + gceSTATUS status; \ + gcmERR_RETURN(gcoOS_Allocate(MemPool, \ + gcmSIZEOF(Type), \ + (gctPOINTER *) Pointer)); \ + gcmVERIFY_OK(gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, gcmSIZEOF(Type))); \ + return gcvSTATUS_OK; \ +} \ + \ +gceSTATUS \ +Prefix##_Free##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type * Pointer \ + ) \ +{ \ + return(gcoOS_Free(MemPool, Pointer)); \ +} + +#define gcmMEM_DeclareVSMemPool(Type, TypeName, Prefix) \ +gceSTATUS \ +Prefix##_Allocate##TypeName( \ + gcsMEM_VS_MEM_POOL MemPool, \ + Type ** Pointer, \ + gctUINT Size \ + ) \ +{ \ + return(gcoOS_Allocate(MemPool, \ + Size, \ + (gctPOINTER *) Pointer)); \ +} \ + \ +gceSTATUS \ +Prefix##_CAllocate##TypeName( \ + gcsMEM_VS_MEM_POOL MemPool, \ + Type ** Pointer, \ + gctUINT Size \ + ) \ +{ \ + gceSTATUS status; \ + gcmERR_RETURN(gcoOS_Allocate(MemPool, \ + Size, \ + (gctPOINTER *) Pointer)); \ + gcmVERIFY_OK(gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, Size)); \ + return gcvSTATUS_OK; \ +} \ + \ +gceSTATUS \ +Prefix##_Free##TypeName( \ + gcsMEM_VS_MEM_POOL MemPool, \ + Type * Pointer \ + ) \ +{ \ + return(gcoOS_Free(MemPool, Pointer)); \ +} + +#define gcmMEM_DeclareAFSMemPool(Type, TypeName, Prefix) \ +gceSTATUS \ +Prefix##_Allocate##TypeName( \ + gcsMEM_AFS_MEM_POOL MemPool, \ + Type ** Pointer, \ + gctUINT Count \ + ) \ +{ \ + return(gcoOS_Allocate(MemPool, \ + Count * gcmSIZEOF(Type), \ + (gctPOINTER *) Pointer)); \ +} \ + \ +gceSTATUS \ +Prefix##_CAllocate##TypeName( \ + gcsMEM_AFS_MEM_POOL MemPool, \ + Type ** Pointer, \ + gctUINT Count \ + ) \ +{ \ + gceSTATUS status; \ + gcmERR_RETURN(gcoOS_Allocate(MemPool, \ + Count * gcmSIZEOF(Type), \ + (gctPOINTER *) Pointer)); \ + gcmVERIFY_OK(gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, Count * gcmSIZEOF(Type))); \ + return gcvSTATUS_OK; \ +} \ + \ +gceSTATUS \ +Prefix##_Free##TypeName( \ + gcsMEM_AFS_MEM_POOL MemPool, \ + Type * Pointer \ + ) \ +{ \ + return(gcoOS_Free(MemPool, Pointer)); \ +} +#endif + +/******************************************************************************* +** Memory Pool Data Functions +*******************************************************************************/ +gceSTATUS +gcfMEM_InitFSMemPool( + IN gcsMEM_FS_MEM_POOL * MemPool, + IN gcoOS OS, + IN gctUINT NodeCount, + IN gctUINT NodeSize + ); + +gceSTATUS +gcfMEM_FreeFSMemPool( + IN gcsMEM_FS_MEM_POOL * MemPool + ); + +gceSTATUS +gcfMEM_FSMemPoolGetANode( + IN gcsMEM_FS_MEM_POOL MemPool, + OUT gctPOINTER * Node + ); + +gceSTATUS +gcfMEM_FSMemPoolFreeANode( + IN gcsMEM_FS_MEM_POOL MemPool, + IN gctPOINTER Node + ); + +gceSTATUS +gcfMEM_FSMemPoolFreeAList( + IN gcsMEM_FS_MEM_POOL MemPool, + IN gctPOINTER FirstNode, + IN gctPOINTER LastNode + ); + +gceSTATUS +gcfMEM_InitVSMemPool( + IN gcsMEM_VS_MEM_POOL * MemPool, + IN gcoOS OS, + IN gctUINT BlockSize, + IN gctBOOL RecycleFreeNode + ); + +gceSTATUS +gcfMEM_FreeVSMemPool( + IN gcsMEM_VS_MEM_POOL * MemPool + ); + +gceSTATUS +gcfMEM_VSMemPoolGetANode( + IN gcsMEM_VS_MEM_POOL MemPool, + IN gctUINT Size, + IN gctUINT Alignment, + OUT gctPOINTER * Node + ); + +gceSTATUS +gcfMEM_VSMemPoolFreeANode( + IN gcsMEM_VS_MEM_POOL MemPool, + IN gctPOINTER Node + ); + +gceSTATUS +gcfMEM_InitAFSMemPool( + IN gcsMEM_AFS_MEM_POOL *MemPool, + IN gcoOS OS, + IN gctUINT NodeCount, + IN gctUINT NodeSize + ); + +gceSTATUS +gcfMEM_FreeAFSMemPool( + IN gcsMEM_AFS_MEM_POOL *MemPool + ); + +gceSTATUS +gcfMEM_AFSMemPoolGetANode( + IN gcsMEM_AFS_MEM_POOL MemPool, + IN gctUINT Count, + OUT gctPOINTER * Node + ); + +gceSTATUS +gcfMEM_AFSMemPoolFreeANode( + IN gcsMEM_AFS_MEM_POOL MemPool, + IN gctPOINTER Node + ); + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_mem_h_ */ + diff --git a/drivers/staging/rk29/vivante/hal/inc/gc_hal_options.h b/drivers/staging/rk29/vivante/hal/inc/gc_hal_options.h new file mode 100644 index 000000000000..b6f830f62b72 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/inc/gc_hal_options.h @@ -0,0 +1,259 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_options_h_ +#define __gc_hal_options_h_ + +/* + USE_NEW_LINUX_SIGNAL + + This define enables the Linux kernel signaling between kernel and user. +*/ +#ifndef USE_NEW_LINUX_SIGNAL +# define USE_NEW_LINUX_SIGNAL 0 +#endif + +/* + NO_USER_DIRECT_ACCESS_FROM_KERNEL + + This define enables the Linux kernel behavior accessing user memory. +*/ +#ifndef NO_USER_DIRECT_ACCESS_FROM_KERNEL +# define NO_USER_DIRECT_ACCESS_FROM_KERNEL 0 +#endif + +/* + VIVANTE_PROFILER + + This define enables the profiler. +*/ +#ifndef VIVANTE_PROFILER +# define VIVANTE_PROFILER 0 +#endif + +/* + gcdUSE_VG + + Enable VG HAL layer (only for GC350). +*/ +#ifndef gcdUSE_VG +# define gcdUSE_VG 0 +#endif + +/* + USE_SW_FB + + Set to 1 if the frame buffer memory cannot be accessed by the GPU. +*/ +#ifndef USE_SW_FB +#define USE_SW_FB 0 +#endif + +/* + USE_SHADER_SYMBOL_TABLE + + This define enables the symbol table in shader object. +*/ +#define USE_SHADER_SYMBOL_TABLE 1 + +/* + USE_SUPER_SAMPLING + + This define enables super-sampling support. +*/ +#define USE_SUPER_SAMPLING 0 + +/* + PROFILE_HAL_COUNTERS + + This define enables HAL counter profiling support. + HW and SHADER Counter profiling depends on this. +*/ +#define PROFILE_HAL_COUNTERS 1 + +/* + PROFILE_HW_COUNTERS + + This define enables HW counter profiling support. +*/ +#define PROFILE_HW_COUNTERS 1 + +/* + PROFILE_SHADER_COUNTERS + + This define enables SHADER counter profiling support. +*/ +#define PROFILE_SHADER_COUNTERS 1 + +/* + COMMAND_PROCESSOR_VERSION + + The version of the command buffer and task manager. +*/ +#define COMMAND_PROCESSOR_VERSION 1 + +/* + gcdDUMP + + When set to 1, a dump of all states and memory uploads, as well as other + hardware related execution will be printed to the debug console. This + data can be used for playing back applications. +*/ +#define gcdDUMP 0 + +/* + gcdDUMP_API + + When set to 1, a high level dump of the EGL and GL/VG APs's are + captured. +*/ +#define gcdDUMP_API 0 + +/* + gcdDUMP_IN_KERNEL + + When set to 1, all dumps will happen in the kernel. This is handy if + you want the kernel to dump its command buffers as well and the data + needs to be in sync. +*/ +#define gcdDUMP_IN_KERNEL 0 + +/* + gcdDUMP_COMMAND + + When set to non-zero, the command queue will dump all incoming command + and context buffers as well as all other modifications to the command + queue. +*/ +#define gcdDUMP_COMMAND 0 + +/* + gcdNULL_DRIVER +*/ +#define gcdNULL_DRIVER 0 + +/* + gcdENABLE_TIMEOUT_DETECTION + + Enable timeout detection. +*/ +#define gcdENABLE_TIMEOUT_DETECTION 0 + +/* + gcdCMD_BUFFERS + + Number of command buffers to use per client. Each command buffer is 32kB in + size. +*/ +#define gcdCMD_BUFFERS 2 + +/* + gcdPOWER_CONTROL_DELAY + + The delay in milliseconds required to wait until the GPU has woke up from a + suspend or power-down state. This is system dependent because the bus clock + also needs to be stabalize. +*/ +#define gcdPOWER_CONTROL_DELAY 1 + +/* + gcdMMU_SIZE + + Size of the MMU page table in bytes. Each 4 bytes can hold 4kB worth of + virtual data. +*/ +#define gcdMMU_SIZE (128 << 10) + +/* + gcdSECURE_USER + + Use logical addresses instead of physical addresses in user land. In this + case a hint table is created for both command buffers and context buffers, + and that hint table will be used to patch up those buffers in the kernel + when they are ready to submit. +*/ +#define gcdSECURE_USER 0 + +/* + gcdSECURE_CACHE_SLOTS + + Number of slots in the logical to DMA address cache table. Each time a + logical address needs to be translated into a DMA address for the GPU, this + cache will be walked. The replacement scheme is LRU. +*/ +#define gcdSECURE_CACHE_SLOTS 64 + +/* + gcdREGISTER_ACCESS_FROM_USER + + Set to 1 to allow IOCTL calls to get through from user land. This should + only be in debug or development drops. +*/ +#ifndef gcdREGISTER_ACCESS_FROM_USER +# define gcdREGISTER_ACCESS_FROM_USER 1 +#endif + +/* + gcdHEAP_SIZE + + Set the allocation size for the internal heaps. Each time a heap is full, + a new heap will be allocated with this minmimum amount of bytes. The bigger + this size, the fewer heaps there are to allocate, the better the + performance. However, heaps won't be freed until they are completely free, + so there might be some more memory waste if the size is too big. +*/ +#define gcdHEAP_SIZE (64 << 10) + +/* + gcdNO_POWER_MANAGEMENT + + This define disables the power management code. +*/ +#ifndef gcdNO_POWER_MANAGEMENT +# define gcdNO_POWER_MANAGEMENT 0 +#endif + +/* + gcdFPGA_BUILD + + This define enables work arounds for FPGA images. +*/ +#if !defined(gcdFPGA_BUILD) +# define gcdFPGA_BUILD 0 +#endif + +/* + gcdGPU_TIMEOUT + + This define specified the number of milliseconds the system will wait before + it broadcasts the GPU is stuck. In other words, it will define the timeout + of any operation that needs to wait for the GPU. + + If the value is 0, no timeout will be checked for. +*/ +#if !defined(gcdGPU_TIMEOUT) +# define gcdGPU_TIMEOUT 0 +#endif + +#endif /* __gc_hal_options_h_ */ + diff --git a/drivers/staging/rk29/vivante/hal/inc/gc_hal_profiler.h b/drivers/staging/rk29/vivante/hal/inc/gc_hal_profiler.h new file mode 100644 index 000000000000..8fe1f55b6d69 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/inc/gc_hal_profiler.h @@ -0,0 +1,232 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + +#ifndef __gc_hal_profiler_h_ +#define __gc_hal_profiler_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define GLVERTEX_OBJECT 10 +#define GLVERTEX_OBJECT_BYTES 11 + +#define GLINDEX_OBJECT 20 +#define GLINDEX_OBJECT_BYTES 21 + +#define GLTEXTURE_OBJECT 30 +#define GLTEXTURE_OBJECT_BYTES 31 + +#if VIVANTE_PROFILER +#define gcmPROFILE_GC(Hal, Enum, Value) gcoPROFILER_Count(Hal, Enum, Value) +#else +#define gcmPROFILE_GC(Hal, Enum, Value) do { } while (gcvFALSE) +#endif + +/* HW profile information. */ +typedef struct _gcsPROFILER_COUNTERS +{ + /* HW static counters. */ + gctUINT32 gpuClock; + gctUINT32 axiClock; + gctUINT32 shaderClock; + + /* HW vairable counters. */ + gctUINT32 gpuClockStart; + gctUINT32 gpuClockEnd; + + /* HW vairable counters. */ + gctUINT32 gpuCyclesCounter; + gctUINT32 gpuTotalRead64BytesPerFrame; + gctUINT32 gpuTotalWrite64BytesPerFrame; + + /* PE */ + gctUINT32 pe_pixel_count_killed_by_color_pipe; + gctUINT32 pe_pixel_count_killed_by_depth_pipe; + gctUINT32 pe_pixel_count_drawn_by_color_pipe; + gctUINT32 pe_pixel_count_drawn_by_depth_pipe; + + /* SH */ + gctUINT32 ps_inst_counter; + gctUINT32 rendered_pixel_counter; + gctUINT32 vs_inst_counter; + gctUINT32 rendered_vertice_counter; + gctUINT32 vtx_branch_inst_counter; + gctUINT32 vtx_texld_inst_counter; + gctUINT32 pxl_branch_inst_counter; + gctUINT32 pxl_texld_inst_counter; + + /* PA */ + gctUINT32 pa_input_vtx_counter; + gctUINT32 pa_input_prim_counter; + gctUINT32 pa_output_prim_counter; + gctUINT32 pa_depth_clipped_counter; + gctUINT32 pa_trivial_rejected_counter; + gctUINT32 pa_culled_counter; + + /* SE */ + gctUINT32 se_culled_triangle_count; + gctUINT32 se_culled_lines_count; + + /* RA */ + gctUINT32 ra_valid_pixel_count; + gctUINT32 ra_total_quad_count; + gctUINT32 ra_valid_quad_count_after_early_z; + gctUINT32 ra_total_primitive_count; + gctUINT32 ra_pipe_cache_miss_counter; + gctUINT32 ra_prefetch_cache_miss_counter; + gctUINT32 ra_eez_culled_counter; + + /* TX */ + gctUINT32 tx_total_bilinear_requests; + gctUINT32 tx_total_trilinear_requests; + gctUINT32 tx_total_discarded_texture_requests; + gctUINT32 tx_total_texture_requests; + gctUINT32 tx_mem_read_count; + gctUINT32 tx_mem_read_in_8B_count; + gctUINT32 tx_cache_miss_count; + gctUINT32 tx_cache_hit_texel_count; + gctUINT32 tx_cache_miss_texel_count; + + /* MC */ + gctUINT32 mc_total_read_req_8B_from_pipeline; + gctUINT32 mc_total_read_req_8B_from_IP; + gctUINT32 mc_total_write_req_8B_from_pipeline; + + /* HI */ + gctUINT32 hi_axi_cycles_read_request_stalled; + gctUINT32 hi_axi_cycles_write_request_stalled; + gctUINT32 hi_axi_cycles_write_data_stalled; +} +gcsPROFILER_COUNTERS; + +/* HAL profile information. */ +typedef struct _gcsPROFILER +{ + gctFILE file; + + /* Aggregate Information */ + + /* Clock Info */ + gctUINT64 frameStart; + gctUINT64 frameEnd; + + /* Current frame information */ + gctUINT32 frameNumber; + gctUINT64 frameStartTimeusec; + gctUINT64 frameEndTimeusec; + gctUINT64 frameStartCPUTimeusec; + gctUINT64 frameEndCPUTimeusec; + +#if PROFILE_HAL_COUNTERS + gctUINT32 vertexBufferTotalBytesAlloc; + gctUINT32 vertexBufferNewBytesAlloc; + int vertexBufferTotalObjectsAlloc; + int vertexBufferNewObjectsAlloc; + + gctUINT32 indexBufferTotalBytesAlloc; + gctUINT32 indexBufferNewBytesAlloc; + int indexBufferTotalObjectsAlloc; + int indexBufferNewObjectsAlloc; + + gctUINT32 textureBufferTotalBytesAlloc; + gctUINT32 textureBufferNewBytesAlloc; + int textureBufferTotalObjectsAlloc; + int textureBufferNewObjectsAlloc; + + gctUINT32 numCommits; + gctUINT32 drawPointCount; + gctUINT32 drawLineCount; + gctUINT32 drawTriangleCount; + gctUINT32 drawVertexCount; + gctUINT32 redundantStateChangeCalls; +#endif +} +gcsPROFILER; + +/* Memory profile information. */ +struct _gcsMemProfile +{ + /* Memory Usage */ + gctUINT32 videoMemUsed; + gctUINT32 systemMemUsed; + gctUINT32 commitBufferSize; + gctUINT32 contextBufferCopyBytes; +}; + +/* Shader profile information. */ +struct _gcsSHADER_PROFILER +{ + gctUINT32 shaderLength; + gctUINT32 shaderALUCycles; + gctUINT32 shaderTexLoadCycles; + gctUINT32 shaderTempRegCount; + gctUINT32 shaderSamplerRegCount; + gctUINT32 shaderInputRegCount; + gctUINT32 shaderOutputRegCount; +}; + +/* Initialize the gcsProfiler. */ +gceSTATUS +gcoPROFILER_Initialize( + IN gcoHAL Hal, + IN gctFILE File + ); + +/* Destroy the gcProfiler. */ +gceSTATUS +gcoPROFILER_Destroy( + IN gcoHAL Hal + ); + +/* Call to signal end of frame. */ +gceSTATUS +gcoPROFILER_EndFrame( + IN gcoHAL Hal + ); + +gceSTATUS +gcoPROFILER_Count( + IN gcoHAL Hal, + IN gctUINT32 Enum, + IN gctINT Value + ); + +/* Profile input vertex shader. */ +gceSTATUS +gcoPROFILER_ShaderVS( + IN gcoHAL Hal, + IN gctPOINTER Vs + ); + +/* Profile input fragment shader. */ +gceSTATUS +gcoPROFILER_ShaderFS( + IN gcoHAL Hal, + IN gctPOINTER Fs + ); + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_profiler_h_ */ + diff --git a/drivers/staging/rk29/vivante/hal/inc/gc_hal_raster.h b/drivers/staging/rk29/vivante/hal/inc/gc_hal_raster.h new file mode 100644 index 000000000000..64f897f02648 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/inc/gc_hal_raster.h @@ -0,0 +1,781 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_raster_h_ +#define __gc_hal_raster_h_ + +#include "gc_hal_enum.h" +#include "gc_hal_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************\ +****************************** Object Declarations ***************************** +\******************************************************************************/ + +typedef struct _gcoBRUSH * gcoBRUSH; +typedef struct _gcoBRUSH_CACHE * gcoBRUSH_CACHE; + +/******************************************************************************\ +******************************** gcoBRUSH Object ******************************* +\******************************************************************************/ + +/* Create a new solid color gcoBRUSH object. */ +gceSTATUS +gcoBRUSH_ConstructSingleColor( + IN gcoHAL Hal, + IN gctUINT32 ColorConvert, + IN gctUINT32 Color, + IN gctUINT64 Mask, + gcoBRUSH * Brush + ); + +/* Create a new monochrome gcoBRUSH object. */ +gceSTATUS +gcoBRUSH_ConstructMonochrome( + IN gcoHAL Hal, + IN gctUINT32 OriginX, + IN gctUINT32 OriginY, + IN gctUINT32 ColorConvert, + IN gctUINT32 FgColor, + IN gctUINT32 BgColor, + IN gctUINT64 Bits, + IN gctUINT64 Mask, + gcoBRUSH * Brush + ); + +/* Create a color gcoBRUSH object. */ +gceSTATUS +gcoBRUSH_ConstructColor( + IN gcoHAL Hal, + IN gctUINT32 OriginX, + IN gctUINT32 OriginY, + IN gctPOINTER Address, + IN gceSURF_FORMAT Format, + IN gctUINT64 Mask, + gcoBRUSH * Brush + ); + +/* Destroy an gcoBRUSH object. */ +gceSTATUS +gcoBRUSH_Destroy( + IN gcoBRUSH Brush + ); + +/******************************************************************************\ +******************************** gcoSURF Object ******************************* +\******************************************************************************/ + +/* Set cipping rectangle. */ +gceSTATUS +gcoSURF_SetClipping( + IN gcoSURF Surface + ); + +/* Clear one or more rectangular areas. */ +gceSTATUS +gcoSURF_Clear2D( + IN gcoSURF DestSurface, + IN gctUINT32 RectCount, + IN gcsRECT_PTR DestRect, + IN gctUINT32 LoColor, + IN gctUINT32 HiColor + ); + +/* Draw one or more Bresenham lines. */ +gceSTATUS +gcoSURF_Line( + IN gcoSURF Surface, + IN gctUINT32 LineCount, + IN gcsRECT_PTR Position, + IN gcoBRUSH Brush, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop + ); + +/* Generic rectangular blit. */ +gceSTATUS +gcoSURF_Blit( + IN OPTIONAL gcoSURF SrcSurface, + IN gcoSURF DestSurface, + IN gctUINT32 RectCount, + IN OPTIONAL gcsRECT_PTR SrcRect, + IN gcsRECT_PTR DestRect, + IN OPTIONAL gcoBRUSH Brush, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop, + IN OPTIONAL gceSURF_TRANSPARENCY Transparency, + IN OPTIONAL gctUINT32 TransparencyColor, + IN OPTIONAL gctPOINTER Mask, + IN OPTIONAL gceSURF_MONOPACK MaskPack + ); + +/* Monochrome blit. */ +gceSTATUS +gcoSURF_MonoBlit( + IN gcoSURF DestSurface, + IN gctPOINTER Source, + IN gceSURF_MONOPACK SourcePack, + IN gcsPOINT_PTR SourceSize, + IN gcsPOINT_PTR SourceOrigin, + IN gcsRECT_PTR DestRect, + IN OPTIONAL gcoBRUSH Brush, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop, + IN gctBOOL ColorConvert, + IN gctUINT8 MonoTransparency, + IN gceSURF_TRANSPARENCY Transparency, + IN gctUINT32 FgColor, + IN gctUINT32 BgColor + ); + +/* Filter blit. */ +gceSTATUS +gcoSURF_FilterBlit( + IN gcoSURF SrcSurface, + IN gcoSURF DestSurface, + IN gcsRECT_PTR SrcRect, + IN gcsRECT_PTR DestRect, + IN gcsRECT_PTR DestSubRect + ); + +/* Enable alpha blending engine in the hardware and disengage the ROP engine. */ +gceSTATUS +gcoSURF_EnableAlphaBlend( + IN gcoSURF Surface, + IN gctUINT8 SrcGlobalAlphaValue, + IN gctUINT8 DstGlobalAlphaValue, + IN gceSURF_PIXEL_ALPHA_MODE SrcAlphaMode, + IN gceSURF_PIXEL_ALPHA_MODE DstAlphaMode, + IN gceSURF_GLOBAL_ALPHA_MODE SrcGlobalAlphaMode, + IN gceSURF_GLOBAL_ALPHA_MODE DstGlobalAlphaMode, + IN gceSURF_BLEND_FACTOR_MODE SrcFactorMode, + IN gceSURF_BLEND_FACTOR_MODE DstFactorMode, + IN gceSURF_PIXEL_COLOR_MODE SrcColorMode, + IN gceSURF_PIXEL_COLOR_MODE DstColorMode + ); + +/* Disable alpha blending engine in the hardware and engage the ROP engine. */ +gceSTATUS +gcoSURF_DisableAlphaBlend( + IN gcoSURF Surface + ); + +/* Copy a rectangular area with format conversion. */ +gceSTATUS +gcoSURF_CopyPixels( + IN gcoSURF Source, + IN gcoSURF Target, + IN gctINT SourceX, + IN gctINT SourceY, + IN gctINT TargetX, + IN gctINT TargetY, + IN gctINT Width, + IN gctINT Height + ); + +/* Read surface pixel. */ +gceSTATUS +gcoSURF_ReadPixel( + IN gcoSURF Surface, + IN gctPOINTER Memory, + IN gctINT X, + IN gctINT Y, + IN gceSURF_FORMAT Format, + OUT gctPOINTER PixelValue + ); + +/* Write surface pixel. */ +gceSTATUS +gcoSURF_WritePixel( + IN gcoSURF Surface, + IN gctPOINTER Memory, + IN gctINT X, + IN gctINT Y, + IN gceSURF_FORMAT Format, + IN gctPOINTER PixelValue + ); + +/******************************************************************************\ +********************************** gco2D Object ********************************* +\******************************************************************************/ + +/* Construct a new gco2D object. */ +gceSTATUS +gco2D_Construct( + IN gcoHAL Hal, + OUT gco2D * Hardware + ); + +/* Destroy an gco2D object. */ +gceSTATUS +gco2D_Destroy( + IN gco2D Hardware + ); + +/* Sets the maximum number of brushes in the brush cache. */ +gceSTATUS +gco2D_SetBrushLimit( + IN gco2D Hardware, + IN gctUINT MaxCount + ); + +/* Flush the brush. */ +gceSTATUS +gco2D_FlushBrush( + IN gco2D Engine, + IN gcoBRUSH Brush, + IN gceSURF_FORMAT Format + ); + +/* Program the specified solid color brush. */ +gceSTATUS +gco2D_LoadSolidBrush( + IN gco2D Engine, + IN gceSURF_FORMAT Format, + IN gctUINT32 ColorConvert, + IN gctUINT32 Color, + IN gctUINT64 Mask + ); + +/* Configure monochrome source. */ +gceSTATUS +gco2D_SetMonochromeSource( + IN gco2D Engine, + IN gctBOOL ColorConvert, + IN gctUINT8 MonoTransparency, + IN gceSURF_MONOPACK DataPack, + IN gctBOOL CoordRelative, + IN gceSURF_TRANSPARENCY Transparency, + IN gctUINT32 FgColor, + IN gctUINT32 BgColor + ); + +/* Configure color source. */ +gceSTATUS +gco2D_SetColorSource( + IN gco2D Engine, + IN gctUINT32 Address, + IN gctUINT32 Stride, + IN gceSURF_FORMAT Format, + IN gceSURF_ROTATION Rotation, + IN gctUINT32 SurfaceWidth, + IN gctBOOL CoordRelative, + IN gceSURF_TRANSPARENCY Transparency, + IN gctUINT32 TransparencyColor + ); + +/* Configure color source extension for full rotation. */ +gceSTATUS +gco2D_SetColorSourceEx( + IN gco2D Engine, + IN gctUINT32 Address, + IN gctUINT32 Stride, + IN gceSURF_FORMAT Format, + IN gceSURF_ROTATION Rotation, + IN gctUINT32 SurfaceWidth, + IN gctUINT32 SurfaceHeight, + IN gctBOOL CoordRelative, + IN gceSURF_TRANSPARENCY Transparency, + IN gctUINT32 TransparencyColor + ); + +/* Configure color source. */ +gceSTATUS +gco2D_SetColorSourceAdvanced( + IN gco2D Engine, + IN gctUINT32 Address, + IN gctUINT32 Stride, + IN gceSURF_FORMAT Format, + IN gceSURF_ROTATION Rotation, + IN gctUINT32 SurfaceWidth, + IN gctUINT32 SurfaceHeight, + IN gctBOOL CoordRelative + ); + +/* Configure masked color source. */ +gceSTATUS +gco2D_SetMaskedSource( + IN gco2D Engine, + IN gctUINT32 Address, + IN gctUINT32 Stride, + IN gceSURF_FORMAT Format, + IN gctBOOL CoordRelative, + IN gceSURF_MONOPACK MaskPack + ); + +/* Configure masked color source extension for full rotation. */ +gceSTATUS +gco2D_SetMaskedSourceEx( + IN gco2D Engine, + IN gctUINT32 Address, + IN gctUINT32 Stride, + IN gceSURF_FORMAT Format, + IN gctBOOL CoordRelative, + IN gceSURF_MONOPACK MaskPack, + IN gceSURF_ROTATION Rotation, + IN gctUINT32 SurfaceWidth, + IN gctUINT32 SurfaceHeight + ); + +/* Setup the source rectangle. */ +gceSTATUS +gco2D_SetSource( + IN gco2D Engine, + IN gcsRECT_PTR SrcRect + ); + +/* Set clipping rectangle. */ +gceSTATUS +gco2D_SetClipping( + IN gco2D Engine, + IN gcsRECT_PTR Rect + ); + +/* Configure destination. */ +gceSTATUS +gco2D_SetTarget( + IN gco2D Engine, + IN gctUINT32 Address, + IN gctUINT32 Stride, + IN gceSURF_ROTATION Rotation, + IN gctUINT32 SurfaceWidth + ); + +/* Configure destination extension for full rotation. */ +gceSTATUS +gco2D_SetTargetEx( + IN gco2D Engine, + IN gctUINT32 Address, + IN gctUINT32 Stride, + IN gceSURF_ROTATION Rotation, + IN gctUINT32 SurfaceWidth, + IN gctUINT32 SurfaceHeight + ); + +/* Calculate and program the stretch factors. */ +gceSTATUS +gco2D_SetStretchFactors( + IN gco2D Engine, + IN gctUINT32 HorFactor, + IN gctUINT32 VerFactor + ); + +/* Calculate and program the stretch factors based on the rectangles. */ +gceSTATUS +gco2D_SetStretchRectFactors( + IN gco2D Engine, + IN gcsRECT_PTR SrcRect, + IN gcsRECT_PTR DestRect + ); + +/* Create a new solid color gcoBRUSH object. */ +gceSTATUS +gco2D_ConstructSingleColorBrush( + IN gco2D Engine, + IN gctUINT32 ColorConvert, + IN gctUINT32 Color, + IN gctUINT64 Mask, + gcoBRUSH * Brush + ); + +/* Create a new monochrome gcoBRUSH object. */ +gceSTATUS +gco2D_ConstructMonochromeBrush( + IN gco2D Engine, + IN gctUINT32 OriginX, + IN gctUINT32 OriginY, + IN gctUINT32 ColorConvert, + IN gctUINT32 FgColor, + IN gctUINT32 BgColor, + IN gctUINT64 Bits, + IN gctUINT64 Mask, + gcoBRUSH * Brush + ); + +/* Create a color gcoBRUSH object. */ +gceSTATUS +gco2D_ConstructColorBrush( + IN gco2D Engine, + IN gctUINT32 OriginX, + IN gctUINT32 OriginY, + IN gctPOINTER Address, + IN gceSURF_FORMAT Format, + IN gctUINT64 Mask, + gcoBRUSH * Brush + ); + +/* Clear one or more rectangular areas. */ +gceSTATUS +gco2D_Clear( + IN gco2D Engine, + IN gctUINT32 RectCount, + IN gcsRECT_PTR Rect, + IN gctUINT32 Color32, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop, + IN gceSURF_FORMAT DestFormat + ); + +/* Draw one or more Bresenham lines. */ +gceSTATUS +gco2D_Line( + IN gco2D Engine, + IN gctUINT32 LineCount, + IN gcsRECT_PTR Position, + IN gcoBRUSH Brush, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop, + IN gceSURF_FORMAT DestFormat + ); + +/* Draw one or more Bresenham lines based on the 32-bit color. */ +gceSTATUS +gco2D_ColorLine( + IN gco2D Engine, + IN gctUINT32 LineCount, + IN gcsRECT_PTR Position, + IN gctUINT32 Color32, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop, + IN gceSURF_FORMAT DestFormat + ); + +/* Generic blit. */ +gceSTATUS +gco2D_Blit( + IN gco2D Engine, + IN gctUINT32 RectCount, + IN gcsRECT_PTR Rect, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop, + IN gceSURF_FORMAT DestFormat + ); + +/* Batch blit. */ +gceSTATUS +gco2D_BatchBlit( + IN gco2D Engine, + IN gctUINT32 RectCount, + IN gcsRECT_PTR SrcRect, + IN gcsRECT_PTR DestRect, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop, + IN gceSURF_FORMAT DestFormat + ); + +/* Stretch blit. */ +gceSTATUS +gco2D_StretchBlit( + IN gco2D Engine, + IN gctUINT32 RectCount, + IN gcsRECT_PTR Rect, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop, + IN gceSURF_FORMAT DestFormat + ); + +/* Monochrome blit. */ +gceSTATUS +gco2D_MonoBlit( + IN gco2D Engine, + IN gctPOINTER StreamBits, + IN gcsPOINT_PTR StreamSize, + IN gcsRECT_PTR StreamRect, + IN gceSURF_MONOPACK SrcStreamPack, + IN gceSURF_MONOPACK DestStreamPack, + IN gcsRECT_PTR DestRect, + IN gctUINT32 FgRop, + IN gctUINT32 BgRop, + IN gceSURF_FORMAT DestFormat + ); + +/* Set kernel size. */ +gceSTATUS +gco2D_SetKernelSize( + IN gco2D Engine, + IN gctUINT8 HorKernelSize, + IN gctUINT8 VerKernelSize + ); + +/* Set filter type. */ +gceSTATUS +gco2D_SetFilterType( + IN gco2D Engine, + IN gceFILTER_TYPE FilterType + ); + +/* Set the filter kernel by user. */ +gceSTATUS +gco2D_SetUserFilterKernel( + IN gco2D Engine, + IN gceFILTER_PASS_TYPE PassType, + IN gctUINT16_PTR KernelArray + ); + +/* Select the pass(es) to be done for user defined filter. */ +gceSTATUS +gco2D_EnableUserFilterPasses( + IN gco2D Engine, + IN gctBOOL HorPass, + IN gctBOOL VerPass + ); + +/* Frees the temporary buffer allocated by filter blit operation. */ +gceSTATUS +gco2D_FreeFilterBuffer( + IN gco2D Engine + ); + +/* Filter blit. */ +gceSTATUS +gco2D_FilterBlit( + IN gco2D Engine, + IN gctUINT32 SrcAddress, + IN gctUINT SrcStride, + IN gctUINT32 SrcUAddress, + IN gctUINT SrcUStride, + IN gctUINT32 SrcVAddress, + IN gctUINT SrcVStride, + IN gceSURF_FORMAT SrcFormat, + IN gceSURF_ROTATION SrcRotation, + IN gctUINT32 SrcSurfaceWidth, + IN gcsRECT_PTR SrcRect, + IN gctUINT32 DestAddress, + IN gctUINT DestStride, + IN gceSURF_FORMAT DestFormat, + IN gceSURF_ROTATION DestRotation, + IN gctUINT32 DestSurfaceWidth, + IN gcsRECT_PTR DestRect, + IN gcsRECT_PTR DestSubRect + ); + +/* Filter blit extension for full rotation. */ +gceSTATUS +gco2D_FilterBlitEx( + IN gco2D Engine, + IN gctUINT32 SrcAddress, + IN gctUINT SrcStride, + IN gctUINT32 SrcUAddress, + IN gctUINT SrcUStride, + IN gctUINT32 SrcVAddress, + IN gctUINT SrcVStride, + IN gceSURF_FORMAT SrcFormat, + IN gceSURF_ROTATION SrcRotation, + IN gctUINT32 SrcSurfaceWidth, + IN gctUINT32 SrcSurfaceHeight, + IN gcsRECT_PTR SrcRect, + IN gctUINT32 DestAddress, + IN gctUINT DestStride, + IN gceSURF_FORMAT DestFormat, + IN gceSURF_ROTATION DestRotation, + IN gctUINT32 DestSurfaceWidth, + IN gctUINT32 DestSurfaceHeight, + IN gcsRECT_PTR DestRect, + IN gcsRECT_PTR DestSubRect + ); + +/* Enable alpha blending engine in the hardware and disengage the ROP engine. */ +gceSTATUS +gco2D_EnableAlphaBlend( + IN gco2D Engine, + IN gctUINT8 SrcGlobalAlphaValue, + IN gctUINT8 DstGlobalAlphaValue, + IN gceSURF_PIXEL_ALPHA_MODE SrcAlphaMode, + IN gceSURF_PIXEL_ALPHA_MODE DstAlphaMode, + IN gceSURF_GLOBAL_ALPHA_MODE SrcGlobalAlphaMode, + IN gceSURF_GLOBAL_ALPHA_MODE DstGlobalAlphaMode, + IN gceSURF_BLEND_FACTOR_MODE SrcFactorMode, + IN gceSURF_BLEND_FACTOR_MODE DstFactorMode, + IN gceSURF_PIXEL_COLOR_MODE SrcColorMode, + IN gceSURF_PIXEL_COLOR_MODE DstColorMode + ); + +/* Enable alpha blending engine in the hardware. */ +gceSTATUS +gco2D_EnableAlphaBlendAdvanced( + IN gco2D Engine, + IN gceSURF_PIXEL_ALPHA_MODE SrcAlphaMode, + IN gceSURF_PIXEL_ALPHA_MODE DstAlphaMode, + IN gceSURF_GLOBAL_ALPHA_MODE SrcGlobalAlphaMode, + IN gceSURF_GLOBAL_ALPHA_MODE DstGlobalAlphaMode, + IN gceSURF_BLEND_FACTOR_MODE SrcFactorMode, + IN gceSURF_BLEND_FACTOR_MODE DstFactorMode + ); + +/* Enable alpha blending engine with Porter Duff rule. */ +gceSTATUS +gco2D_SetPorterDuffBlending( + IN gco2D Engine, + IN gce2D_PORTER_DUFF_RULE Rule + ); + +/* Disable alpha blending engine in the hardware and engage the ROP engine. */ +gceSTATUS +gco2D_DisableAlphaBlend( + IN gco2D Engine + ); + +/* Retrieve the maximum number of 32-bit data chunks for a single DE command. */ +gctUINT32 +gco2D_GetMaximumDataCount( + void + ); + +/* Retrieve the maximum number of rectangles, that can be passed in a single DE command. */ +gctUINT32 +gco2D_GetMaximumRectCount( + void + ); + +/* Returns the pixel alignment of the surface. */ +gceSTATUS +gco2D_GetPixelAlignment( + gceSURF_FORMAT Format, + gcsPOINT_PTR Alignment + ); + +/* Retrieve monochrome stream pack size. */ +gceSTATUS +gco2D_GetPackSize( + IN gceSURF_MONOPACK StreamPack, + OUT gctUINT32 * PackWidth, + OUT gctUINT32 * PackHeight + ); + +/* Flush the 2D pipeline. */ +gceSTATUS +gco2D_Flush( + IN gco2D Engine + ); + +/* Load 256-entry color table for INDEX8 source surfaces. */ +gceSTATUS +gco2D_LoadPalette( + IN gco2D Engine, + IN gctUINT FirstIndex, + IN gctUINT IndexCount, + IN gctPOINTER ColorTable, + IN gctBOOL ColorConvert + ); + +/* Enable/disable 2D BitBlt mirrorring. */ +gceSTATUS +gco2D_SetBitBlitMirror( + IN gco2D Engine, + IN gctBOOL HorizontalMirror, + IN gctBOOL VerticalMirror + ); + +/* Set the transparency for source, destination and pattern. */ +gceSTATUS +gco2D_SetTransparencyAdvanced( + IN gco2D Engine, + IN gce2D_TRANSPARENCY SrcTransparency, + IN gce2D_TRANSPARENCY DstTransparency, + IN gce2D_TRANSPARENCY PatTransparency + ); + +/* Set the source color key. */ +gceSTATUS +gco2D_SetSourceColorKeyAdvanced( + IN gco2D Engine, + IN gctUINT32 ColorKey + ); + +/* Set the source color key range. */ +gceSTATUS +gco2D_SetSourceColorKeyRangeAdvanced( + IN gco2D Engine, + IN gctUINT32 ColorKeyLow, + IN gctUINT32 ColorKeyHigh + ); + +/* Set the target color key. */ +gceSTATUS +gco2D_SetTargetColorKeyAdvanced( + IN gco2D Engine, + IN gctUINT32 ColorKey + ); + +/* Set the target color key range. */ +gceSTATUS +gco2D_SetTargetColorKeyRangeAdvanced( + IN gco2D Engine, + IN gctUINT32 ColorKeyLow, + IN gctUINT32 ColorKeyHigh + ); + +/* Set the YUV color space mode. */ +gceSTATUS +gco2D_SetYUVColorMode( + IN gco2D Engine, + IN gce2D_YUV_COLOR_MODE Mode + ); + +/* Setup the source global color value in ARGB8 format. */ +gceSTATUS gco2D_SetSourceGlobalColorAdvanced( + IN gco2D Engine, + IN gctUINT32 Color32 + ); + +/* Setup the target global color value in ARGB8 format. */ +gceSTATUS gco2D_SetTargetGlobalColorAdvanced( + IN gco2D Engine, + IN gctUINT32 Color32 + ); + +/* Setup the source and target pixel multiply modes. */ +gceSTATUS +gco2D_SetPixelMultiplyModeAdvanced( + IN gco2D Engine, + IN gce2D_PIXEL_COLOR_MULTIPLY_MODE SrcPremultiplySrcAlpha, + IN gce2D_PIXEL_COLOR_MULTIPLY_MODE DstPremultiplyDstAlpha, + IN gce2D_GLOBAL_COLOR_MULTIPLY_MODE SrcPremultiplyGlobalMode, + IN gce2D_PIXEL_COLOR_MULTIPLY_MODE DstDemultiplyDstAlpha + ); + +/* Set the GPU clock cycles after which the idle engine will keep auto-flushing. */ +gceSTATUS +gco2D_SetAutoFlushCycles( + IN gco2D Engine, + IN gctUINT32 Cycles + ); + +/* Read the profile registers available in the 2D engine and sets them in the profile. + The function will also reset the pixelsRendered counter every time. +*/ +gceSTATUS +gco2D_ProfileEngine( + IN gco2D Engine, + OPTIONAL gcs2D_PROFILE_PTR Profile + ); + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_raster_h_ */ + diff --git a/drivers/staging/rk29/vivante/hal/inc/gc_hal_types.h b/drivers/staging/rk29/vivante/hal/inc/gc_hal_types.h new file mode 100644 index 000000000000..d572d5fbb67e --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/inc/gc_hal_types.h @@ -0,0 +1,544 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_types_h_ +#define __gc_hal_types_h_ + +#include "gc_hal_options.h" + +#ifdef _WIN32 +#pragma warning(disable:4127) /* Conditional expression is constant (do { } + ** while(0)). */ +#pragma warning(disable:4100) /* Unreferenced formal parameter. */ +#pragma warning(disable:4204) /* Non-constant aggregate initializer (C99). */ +#pragma warning(disable:4131) /* Uses old-style declarator (for Bison and + ** Flex generated files). */ +#pragma warning(disable:4206) /* Translation unit is empty. */ +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************\ +** Platform macros. +*/ + +#if defined(__GNUC__) +# define gcdHAS_ELLIPSES 1 /* GCC always has it. */ +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define gcdHAS_ELLIPSES 1 /* C99 has it. */ +#elif defined(_MSC_VER) && (_MSC_VER >= 1500) +# define gcdHAS_ELLIPSES 1 /* MSVC 2007+ has it. */ +#elif defined(UNDER_CE) +# define gcdHAS_ELLIPSES 0 /* Windows CE doesn't have it. */ +#else +# error "gcdHAS_ELLIPSES: Platform could not be determined" +#endif + +/******************************************************************************\ +************************************ Keyword *********************************** +\******************************************************************************/ + +#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) +# define gcmINLINE inline /* C99 keyword. */ +#elif defined(__GNUC__) +# define gcmINLINE __inline__ /* GNU keyword. */ +#elif defined(_MSC_VER) || defined(UNDER_CE) +# define gcmINLINE __inline /* Internal keyword. */ +#else +# error "gcmINLINE: Platform could not be determined" +#endif + +#ifndef gcdDEBUG +# if (defined(DBG) && DBG) || defined(DEBUG) || defined(_DEBUG) +# define gcdDEBUG 1 +# else +# define gcdDEBUG 0 +# endif +#endif + +#ifdef _USRDLL +# ifdef _MSC_VER +# ifdef HAL_EXPORTS +# define HALAPI __declspec(dllexport) +# else +# define HALAPI __declspec(dllimport) +# endif +# define HALDECL __cdecl +# else +# ifdef HAL_EXPORTS +# define HALAPI +# else +# define HALAPI extern +# endif +# endif +#else +# define HALAPI +# define HALDECL +#endif + +/******************************************************************************\ +********************************** Common Types ******************************** +\******************************************************************************/ + +#define gcvFALSE 0 +#define gcvTRUE 1 + +#define gcvINFINITE ((gctUINT32) ~0U) + +typedef int gctBOOL; +typedef gctBOOL * gctBOOL_PTR; + +typedef int gctINT; +typedef signed char gctINT8; +typedef signed short gctINT16; +typedef signed int gctINT32; +typedef signed long long gctINT64; + +typedef gctINT * gctINT_PTR; +typedef gctINT8 * gctINT8_PTR; +typedef gctINT16 * gctINT16_PTR; +typedef gctINT32 * gctINT32_PTR; +typedef gctINT64 * gctINT64_PTR; + +typedef unsigned int gctUINT; +typedef unsigned char gctUINT8; +typedef unsigned short gctUINT16; +typedef unsigned int gctUINT32; +typedef unsigned long long gctUINT64; + +typedef gctUINT * gctUINT_PTR; +typedef gctUINT8 * gctUINT8_PTR; +typedef gctUINT16 * gctUINT16_PTR; +typedef gctUINT32 * gctUINT32_PTR; +typedef gctUINT64 * gctUINT64_PTR; + +typedef unsigned long gctSIZE_T; +typedef gctSIZE_T * gctSIZE_T_PTR; + +#ifdef __cplusplus +# define gcvNULL 0 +#else +# define gcvNULL ((void *) 0) +#endif + +typedef float gctFLOAT; +typedef signed int gctFIXED_POINT; +typedef float * gctFLOAT_PTR; + +typedef void * gctPHYS_ADDR; +typedef void * gctHANDLE; +typedef void * gctFILE; +typedef void * gctSIGNAL; +typedef void * gctWINDOW; +typedef void * gctIMAGE; + +typedef void * gctPOINTER; +typedef const void * gctCONST_POINTER; + +typedef char gctCHAR; +typedef char * gctSTRING; +typedef const char * gctCONST_STRING; + +typedef struct _gcsCOUNT_STRING +{ + gctSIZE_T Length; + gctCONST_STRING String; +} +gcsCOUNT_STRING; + +/* Fixed point constants. */ +#define gcvZERO_X ((gctFIXED_POINT) 0x00000000) +#define gcvHALF_X ((gctFIXED_POINT) 0x00008000) +#define gcvONE_X ((gctFIXED_POINT) 0x00010000) +#define gcvNEGONE_X ((gctFIXED_POINT) 0xFFFF0000) +#define gcvTWO_X ((gctFIXED_POINT) 0x00020000) + +/******************************************************************************\ +******************************* Fixed Point Math ******************************* +\******************************************************************************/ + +#define gcmXMultiply(x1, x2) \ + (gctFIXED_POINT) (((gctINT64) (x1) * (x2)) >> 16) + +#define gcmXDivide(x1, x2) \ + (gctFIXED_POINT) ((((gctINT64) (x1)) << 16) / (x2)) + +#define gcmXMultiplyDivide(x1, x2, x3) \ + (gctFIXED_POINT) ((gctINT64) (x1) * (x2) / (x3)) + +/* 2D Engine profile. */ +struct gcs2D_PROFILE +{ + /* Cycle count. + 32bit counter incremented every 2D clock cycle. + Wraps back to 0 when the counter overflows. + */ + gctUINT32 cycleCount; + + /* Pixels rendered by the 2D engine. + Resets to 0 every time it is read. */ + gctUINT32 pixelsRendered; +}; + + +/* Macro to combine four characters into a Charcater Code. */ +#define gcmCC(c1, c2, c3, c4) \ +( \ + (char) (c1) \ + | \ + ((char) (c2) << 8) \ + | \ + ((char) (c3) << 16) \ + | \ + ((char) (c4) << 24) \ +) + +#define gcmPRINTABLE(c) ((((c) >= ' ') && ((c) <= '}')) ? (c) : ' ') + +#define gcmCC_PRINT(cc) \ + gcmPRINTABLE((char) ( (cc) & 0xFF)), \ + gcmPRINTABLE((char) (((cc) >> 8) & 0xFF)), \ + gcmPRINTABLE((char) (((cc) >> 16) & 0xFF)), \ + gcmPRINTABLE((char) (((cc) >> 24) & 0xFF)) + +/******************************************************************************\ +****************************** Function Parameters ***************************** +\******************************************************************************/ + +#define IN +#define OUT +#define OPTIONAL + +/******************************************************************************\ +********************************* Status Codes ********************************* +\******************************************************************************/ + +typedef enum _gceSTATUS +{ + gcvSTATUS_OK = 0, + gcvSTATUS_FALSE = 0, + gcvSTATUS_TRUE = 1, + gcvSTATUS_NO_MORE_DATA = 2, + gcvSTATUS_CACHED = 3, + gcvSTATUS_MIPMAP_TOO_LARGE = 4, + gcvSTATUS_NAME_NOT_FOUND = 5, + gcvSTATUS_NOT_OUR_INTERRUPT = 6, + gcvSTATUS_MISMATCH = 7, + gcvSTATUS_MIPMAP_TOO_SMALL = 8, + gcvSTATUS_LARGER = 9, + gcvSTATUS_SMALLER = 10, + gcvSTATUS_CHIP_NOT_READY = 11, + gcvSTATUS_NEED_CONVERSION = 12, + gcvSTATUS_SKIP = 13, + gcvSTATUS_DATA_TOO_LARGE = 14, + gcvSTATUS_INVALID_CONFIG = 15, + gcvSTATUS_CHANGED = 16, + + gcvSTATUS_INVALID_ARGUMENT = -1, + gcvSTATUS_INVALID_OBJECT = -2, + gcvSTATUS_OUT_OF_MEMORY = -3, + gcvSTATUS_MEMORY_LOCKED = -4, + gcvSTATUS_MEMORY_UNLOCKED = -5, + gcvSTATUS_HEAP_CORRUPTED = -6, + gcvSTATUS_GENERIC_IO = -7, + gcvSTATUS_INVALID_ADDRESS = -8, + gcvSTATUS_CONTEXT_LOSSED = -9, + gcvSTATUS_TOO_COMPLEX = -10, + gcvSTATUS_BUFFER_TOO_SMALL = -11, + gcvSTATUS_INTERFACE_ERROR = -12, + gcvSTATUS_NOT_SUPPORTED = -13, + gcvSTATUS_MORE_DATA = -14, + gcvSTATUS_TIMEOUT = -15, + gcvSTATUS_OUT_OF_RESOURCES = -16, + gcvSTATUS_INVALID_DATA = -17, + gcvSTATUS_INVALID_MIPMAP = -18, + gcvSTATUS_NOT_FOUND = -19, + gcvSTATUS_NOT_ALIGNED = -20, + gcvSTATUS_INVALID_REQUEST = -21, + gcvSTATUS_GPU_NOT_RESPONDING = -22, + + /* Linker errors. */ + gcvSTATUS_GLOBAL_TYPE_MISMATCH = -1000, + gcvSTATUS_TOO_MANY_ATTRIBUTES = -1001, + gcvSTATUS_TOO_MANY_UNIFORMS = -1002, + gcvSTATUS_TOO_MANY_VARYINGS = -1003, + gcvSTATUS_UNDECLARED_VARYING = -1004, + gcvSTATUS_VARYING_TYPE_MISMATCH = -1005, + gcvSTATUS_MISSING_MAIN = -1006, + gcvSTATUS_NAME_MISMATCH = -1007, + gcvSTATUS_INVALID_INDEX = -1008, +} +gceSTATUS; + +/******************************************************************************\ +********************************* Status Macros ******************************** +\******************************************************************************/ + +#define gcmIS_ERROR(status) (status < 0) +#define gcmNO_ERROR(status) (status >= 0) +#define gcmIS_SUCCESS(status) (status == gcvSTATUS_OK) + +/******************************************************************************\ +********************************* Field Macros ********************************* +\******************************************************************************/ + +#define __gcmSTART(reg_field) \ + (0 ? reg_field) + +#define __gcmEND(reg_field) \ + (1 ? reg_field) + +#define __gcmGETSIZE(reg_field) \ + (__gcmEND(reg_field) - __gcmSTART(reg_field) + 1) + +#define __gcmALIGN(data, reg_field) \ + (((gctUINT32) (data)) << __gcmSTART(reg_field)) + +#define __gcmMASK(reg_field) \ + ((gctUINT32) ((__gcmGETSIZE(reg_field) == 32) \ + ? ~0 \ + : (~(~0 << __gcmGETSIZE(reg_field))))) + +/******************************************************************************* +** +** gcmFIELDMASK +** +** Get aligned field mask. +** +** ARGUMENTS: +** +** reg Name of register. +** field Name of field within register. +*/ +#define gcmFIELDMASK(reg, field) \ +( \ + __gcmALIGN(__gcmMASK(reg##_##field), reg##_##field) \ +) + +/******************************************************************************* +** +** gcmGETFIELD +** +** Extract the value of a field from specified data. +** +** ARGUMENTS: +** +** data Data value. +** reg Name of register. +** field Name of field within register. +*/ +#define gcmGETFIELD(data, reg, field) \ +( \ + ((((gctUINT32) (data)) >> __gcmSTART(reg##_##field)) \ + & __gcmMASK(reg##_##field)) \ +) + +/******************************************************************************* +** +** gcmSETFIELD +** +** Set the value of a field within specified data. +** +** ARGUMENTS: +** +** data Data value. +** reg Name of register. +** field Name of field within register. +** value Value for field. +*/ +#define gcmSETFIELD(data, reg, field, value) \ +( \ + (((gctUINT32) (data)) \ + & ~__gcmALIGN(__gcmMASK(reg##_##field), reg##_##field)) \ + | __gcmALIGN((gctUINT32) (value) \ + & __gcmMASK(reg##_##field), reg##_##field) \ +) + +/******************************************************************************* +** +** gcmSETFIELDVALUE +** +** Set the value of a field within specified data with a +** predefined value. +** +** ARGUMENTS: +** +** data Data value. +** reg Name of register. +** field Name of field within register. +** value Name of the value within the field. +*/ +#define gcmSETFIELDVALUE(data, reg, field, value) \ +( \ + (((gctUINT32) (data)) \ + & ~__gcmALIGN(__gcmMASK(reg##_##field), reg##_##field)) \ + | __gcmALIGN(reg##_##field##_##value \ + & __gcmMASK(reg##_##field), reg##_##field) \ +) + +/******************************************************************************* +** +** gcmSETMASKEDFIELD +** +** Set the value of a masked field with specified data. +** +** ARGUMENTS: +** +** reg Name of register. +** field Name of field within register. +** value Value for field. +*/ +#define gcmSETMASKEDFIELD(reg, field, value) \ +( \ + gcmSETFIELD(~0, reg, field, value) & \ + gcmSETFIELDVALUE(~0, reg, MASK_ ## field, ENABLED) \ +) + +/******************************************************************************* +** +** gcmVERIFYFIELDVALUE +** +** Verify if the value of a field within specified data equals a +** predefined value. +** +** ARGUMENTS: +** +** data Data value. +** reg Name of register. +** field Name of field within register. +** value Name of the value within the field. +*/ +#define gcmVERIFYFIELDVALUE(data, reg, field, value) \ +( \ + (((gctUINT32) (data)) >> __gcmSTART(reg##_##field) & \ + __gcmMASK(reg##_##field)) \ + == \ + (reg##_##field##_##value & __gcmMASK(reg##_##field)) \ +) + +/******************************************************************************* +** Bit field macros. +*/ + +#define __gcmSTARTBIT(Field) \ + ( 1 ? Field ) + +#define __gcmBITSIZE(Field) \ + ( 0 ? Field ) + +#define __gcmBITMASK(Field) \ +( \ + (1 << __gcmBITSIZE(Field)) - 1 \ +) + +#define gcmGETBITS(Value, Type, Field) \ +( \ + ( ((Type) (Value)) >> __gcmSTARTBIT(Field) ) \ + & \ + __gcmBITMASK(Field) \ +) + +#define gcmSETBITS(Value, Type, Field, NewValue) \ +( \ + ( ((Type) (Value)) \ + & ~(__gcmBITMASK(Field) << __gcmSTARTBIT(Field)) \ + ) \ + | \ + ( ( ((Type) (NewValue)) \ + & __gcmBITMASK(Field) \ + ) << __gcmSTARTBIT(Field) \ + ) \ +) + +/******************************************************************************\ +******************************** Min/Max Macros ******************************** +\******************************************************************************/ + +#define gcmMIN(x, y) (((x) <= (y)) ? (x) : (y)) +#define gcmMAX(x, y) (((x) >= (y)) ? (x) : (y)) +#define gcmCLAMP(x, min, max) (((x) < (min)) ? (min) : \ + ((x) > (max)) ? (max) : (x)) +#define gcmABS(x) (((x) < 0) ? -(x) : (x)) +#define gcmNEG(x) (((x) < 0) ? (x) : -(x)) + +/******************************************************************************* +** +** gcmPTR2INT +** +** Convert a pointer to an integer value. +** +** ARGUMENTS: +** +** p Pointer value. +*/ +#if defined(_WIN32) || (defined(__LP64__) && __LP64__) +# define gcmPTR2INT(p) \ + ( \ + (gctUINT32) (gctUINT64) (p) \ + ) +#else +# define gcmPTR2INT(p) \ + ( \ + (gctUINT32) (p) \ + ) +#endif + +/******************************************************************************* +** +** gcmINT2PTR +** +** Convert an integer value into a pointer. +** +** ARGUMENTS: +** +** v Integer value. +*/ +#define gcmINT2PTR(i) \ +( \ + (gctPOINTER) (i) \ +) + +/******************************************************************************* +** +** gcmOFFSETOF +** +** Compute the byte offset of a field inside a structure. +** +** ARGUMENTS: +** +** s Structure name. +** field Field name. +*/ +#define gcmOFFSETOF(s, field) \ +( \ + gcmPTR2INT(& (((struct s *) 0)->field)) \ +) + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_types_h_ */ + diff --git a/drivers/staging/rk29/vivante/hal/kernel/gc_hal_kernel.c b/drivers/staging/rk29/vivante/hal/kernel/gc_hal_kernel.c new file mode 100644 index 000000000000..0e5d0bb9aee7 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/kernel/gc_hal_kernel.c @@ -0,0 +1,1237 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_precomp.h" + +#define _GC_OBJ_ZONE gcvZONE_KERNEL + +/******************************************************************************\ +******************************* gckKERNEL API Code ****************************** +\******************************************************************************/ + +/******************************************************************************* +** +** gckKERNEL_Construct +** +** Construct a new gckKERNEL object. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** IN gctPOINTER Context +** Pointer to a driver defined context. +** +** OUTPUT: +** +** gckKERNEL * Kernel +** Pointer to a variable that will hold the pointer to the gckKERNEL +** object. +*/ + +#ifdef ANDROID +#define DEFAULT_PROFILE_FILE_NAME "/sdcard/vprofiler.xml" +#else +#define DEFAULT_PROFILE_FILE_NAME "vprofiler.xml" +#endif + +gceSTATUS +gckKERNEL_Construct( + IN gckOS Os, + IN gctPOINTER Context, + OUT gckKERNEL * Kernel + ) +{ + gckKERNEL kernel = gcvNULL; + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%x Context=0x%x", Os, Context); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Kernel != gcvNULL); + + /* Allocate the gckKERNEL object. */ + gcmkONERROR( + gckOS_Allocate(Os, + gcmSIZEOF(struct _gckKERNEL), + (gctPOINTER *) &kernel)); + + /* Zero the object pointers. */ + kernel->hardware = gcvNULL; + kernel->command = gcvNULL; + kernel->event = gcvNULL; + kernel->mmu = gcvNULL; + + /* Initialize the gckKERNEL object. */ + kernel->object.type = gcvOBJ_KERNEL; + kernel->os = Os; + + /* Save context. */ + kernel->context = Context; + + /* Construct atom holding number of clients. */ + kernel->atomClients = gcvNULL; + gcmkONERROR(gckOS_AtomConstruct(Os, &kernel->atomClients)); + +#if gcdSECURE_USER + kernel->cacheSlots = 0; + kernel->cacheTimeStamp = 0; +#endif + + /* Construct the gckHARDWARE object. */ + gcmkONERROR( + gckHARDWARE_Construct(Os, &kernel->hardware)); + + /* Set pointer to gckKERNEL object in gckHARDWARE object. */ + kernel->hardware->kernel = kernel; + + /* Initialize the hardware. */ + gcmkONERROR( + gckHARDWARE_InitializeHardware(kernel->hardware)); + + /* Construct the gckCOMMAND object. */ + gcmkONERROR( + gckCOMMAND_Construct(kernel, &kernel->command)); + + /* Construct the gckEVENT object. */ + gcmkONERROR( + gckEVENT_Construct(kernel, &kernel->event)); + + /* Construct the gckMMU object. */ + gcmkONERROR( + gckMMU_Construct(kernel, gcdMMU_SIZE, &kernel->mmu)); + +#if VIVANTE_PROFILER + /* Initialize profile setting */ +#if defined ANDROID + kernel->profileEnable = gcvFALSE; +#else + kernel->profileEnable = gcvTRUE; +#endif + + gcmkVERIFY_OK( + gckOS_MemCopy(kernel->profileFileName, + DEFAULT_PROFILE_FILE_NAME, + gcmSIZEOF(DEFAULT_PROFILE_FILE_NAME) + 1)); +#endif + + /* Return pointer to the gckKERNEL object. */ + *Kernel = kernel; + + /* Success. */ + gcmkFOOTER_ARG("*Kernel=0x%x", *Kernel); + return gcvSTATUS_OK; + +OnError: + if (kernel != gcvNULL) + { + if (kernel->event != gcvNULL) + { + gcmkVERIFY_OK(gckEVENT_Destroy(kernel->event)); + } + + if (kernel->command != gcvNULL) + { + gcmkVERIFY_OK(gckCOMMAND_Destroy(kernel->command)); + } + + if (kernel->hardware != gcvNULL) + { + gcmkVERIFY_OK(gckHARDWARE_Destroy(kernel->hardware)); + } + + if (kernel->atomClients != gcvNULL) + { + gcmkVERIFY_OK(gckOS_AtomDestroy(Os, kernel->atomClients)); + } + + gcmkVERIFY_OK(gckOS_Free(Os, kernel)); + } + + /* Return the error. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckKERNEL_Destroy +** +** Destroy an gckKERNEL object. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object to destroy. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckKERNEL_Destroy( + IN gckKERNEL Kernel + ) +{ + gcmkHEADER_ARG("Kernel=0x%x", Kernel); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + + /* Destroy the gckMMU object. */ + gcmkVERIFY_OK(gckMMU_Destroy(Kernel->mmu)); + + /* Destroy the gckEVENT object. */ + gcmkVERIFY_OK(gckEVENT_Destroy(Kernel->event)); + + /* Destroy the gckCOMMNAND object. */ + gcmkVERIFY_OK(gckCOMMAND_Destroy(Kernel->command)); + + /* Destroy the gckHARDWARE object. */ + gcmkVERIFY_OK(gckHARDWARE_Destroy(Kernel->hardware)); + + /* Detsroy the client atom. */ + gcmkVERIFY_OK(gckOS_AtomDestroy(Kernel->os, Kernel->atomClients)); + + /* Mark the gckKERNEL object as unknown. */ + Kernel->object.type = gcvOBJ_UNKNOWN; + + /* Free the gckKERNEL object. */ + gcmkVERIFY_OK(gckOS_Free(Kernel->os, Kernel)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** _AllocateMemory +** +** Private function to walk all required memory pools to allocate the requested +** amount of video memory. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gcsHAL_INTERFACE * Interface +** Pointer to a gcsHAL_INTERFACE structure that defines the command to +** be dispatched. +** +** OUTPUT: +** +** gcsHAL_INTERFACE * Interface +** Pointer to a gcsHAL_INTERFACE structure that receives any data to be +** returned. +*/ +static gceSTATUS +_AllocateMemory( + IN gckKERNEL Kernel, + IN OUT gcePOOL * Pool, + IN gctSIZE_T Bytes, + IN gctSIZE_T Alignment, + IN gceSURF_TYPE Type, +#ifdef __QNXNTO__ + IN gctHANDLE Handle, +#endif + OUT gcuVIDMEM_NODE_PTR * Node + ) +{ + gcePOOL pool; + gceSTATUS status; + gckVIDMEM videoMemory; + + gcmkVERIFY_ARGUMENT(Pool != gcvNULL); + + /* Get initial pool. */ + switch (pool = *Pool) + { + case gcvPOOL_DEFAULT: + case gcvPOOL_LOCAL: + pool = gcvPOOL_LOCAL_INTERNAL; + break; + + case gcvPOOL_UNIFIED: + pool = gcvPOOL_SYSTEM; + break; + + default: + break; + } + + do + { + /* Verify the number of bytes to allocate. */ + if (Bytes == 0) + { + gcmkERR_BREAK(gcvSTATUS_INVALID_ARGUMENT); + } + + if (pool == gcvPOOL_VIRTUAL) + { + /* Create a gcuVIDMEM_NODE for virtual memory. */ +#ifdef __QNXNTO__ + gcmkERR_BREAK( + gckVIDMEM_ConstructVirtual(Kernel, gcvFALSE, Bytes, Handle, Node)); +#else + gcmkERR_BREAK( + gckVIDMEM_ConstructVirtual(Kernel, gcvFALSE, Bytes, Node)); +#endif + + /* Success. */ + break; + } + else if (pool == gcvPOOL_CONTIGUOUS) + { + /* Create a gcuVIDMEM_NODE for contiguous memory. */ +#ifdef __QNXNTO__ + status = gckVIDMEM_ConstructVirtual(Kernel, gcvTRUE, Bytes, Handle, Node); +#else + status = gckVIDMEM_ConstructVirtual(Kernel, gcvTRUE, Bytes, Node); +#endif + if (gcmIS_SUCCESS(status)) + { + /* Memory allocated. */ + break; + } + } + else + { + /* Get pointer to gckVIDMEM object for pool. */ + status = gckKERNEL_GetVideoMemoryPool(Kernel, pool, &videoMemory); + + if (gcmIS_SUCCESS(status)) + { + /* Allocate memory. */ + status = gckVIDMEM_AllocateLinear(videoMemory, + Bytes, + Alignment, + Type, +#ifdef __QNXNTO__ + Handle, +#endif + Node); + + if (gcmIS_SUCCESS(status)) + { + /* Memory allocated. */ + (*Node)->VidMem.pool = pool; + break; + } + } + } + + if (pool == gcvPOOL_LOCAL_INTERNAL) + { + /* Advance to external memory. */ + pool = gcvPOOL_LOCAL_EXTERNAL; + } + else + if (pool == gcvPOOL_LOCAL_EXTERNAL) + { + /* Advance to contiguous system memory. */ + pool = gcvPOOL_SYSTEM; + } + else + if (pool == gcvPOOL_SYSTEM) + { + /* Advance to contiguous memory. */ + pool = gcvPOOL_CONTIGUOUS; + } + else + if ((pool == gcvPOOL_CONTIGUOUS) + && (Type != gcvSURF_TILE_STATUS) + ) + { + /* Advance to virtual memory. */ + pool = gcvPOOL_VIRTUAL; + } + else + { + /* Out of pools. */ + break; + } + } + /* Loop only for multiple selection pools. */ + while ((*Pool == gcvPOOL_DEFAULT) + || (*Pool == gcvPOOL_LOCAL) + || (*Pool == gcvPOOL_UNIFIED) + ); + + if (gcmIS_SUCCESS(status)) + { + /* Return pool used for allocation. */ + *Pool = pool; + } + + /* Return status. */ + return status; +} + +/******************************************************************************* +** +** gckKERNEL_Dispatch +** +** Dispatch a command received from the user HAL layer. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gctBOOL FromUser +** whether the call is from the user space. +** +** gcsHAL_INTERFACE * Interface +** Pointer to a gcsHAL_INTERFACE structure that defines the command to +** be dispatched. +** +** OUTPUT: +** +** gcsHAL_INTERFACE * Interface +** Pointer to a gcsHAL_INTERFACE structure that receives any data to be +** returned. +*/ +gceSTATUS +gckKERNEL_Dispatch( + IN gckKERNEL Kernel, + IN gctBOOL FromUser, + IN OUT gcsHAL_INTERFACE * Interface + ) +{ + gceSTATUS status; + gctUINT32 bitsPerPixel; + gctSIZE_T bytes; + gcuVIDMEM_NODE_PTR node; + gctBOOL locked = gcvFALSE; + gctPHYS_ADDR physical; + gctUINT32 address; + + gcmkHEADER_ARG("Kernel=0x%x FromUser=%d Interface=0x%x", + Kernel, FromUser, Interface); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Interface != gcvNULL); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_KERNEL, + "Dispatching command %d", Interface->command); + + /* Dispatch on command. */ + switch (Interface->command) + { + case gcvHAL_GET_BASE_ADDRESS: + /* Get base address. */ + gcmkONERROR( + gckOS_GetBaseAddress(Kernel->os, + &Interface->u.GetBaseAddress.baseAddress)); + break; + + case gcvHAL_QUERY_VIDEO_MEMORY: + /* Query video memory size. */ + gcmkONERROR(gckKERNEL_QueryVideoMemory(Kernel, Interface)); + break; + + case gcvHAL_QUERY_CHIP_IDENTITY: + /* Query chip identity. */ + gcmkONERROR( + gckHARDWARE_QueryChipIdentity( + Kernel->hardware, + &Interface->u.QueryChipIdentity.chipModel, + &Interface->u.QueryChipIdentity.chipRevision, + &Interface->u.QueryChipIdentity.chipFeatures, + &Interface->u.QueryChipIdentity.chipMinorFeatures, + &Interface->u.QueryChipIdentity.chipMinorFeatures1)); + + /* Query chip specifications. */ + gcmkONERROR( + gckHARDWARE_QueryChipSpecs( + Kernel->hardware, + &Interface->u.QueryChipIdentity.streamCount, + &Interface->u.QueryChipIdentity.registerMax, + &Interface->u.QueryChipIdentity.threadCount, + &Interface->u.QueryChipIdentity.shaderCoreCount, + &Interface->u.QueryChipIdentity.vertexCacheSize, + &Interface->u.QueryChipIdentity.vertexOutputBufferSize)); + break; + + case gcvHAL_MAP_MEMORY: + physical = Interface->u.MapMemory.physical; + + /* Map memory. */ + gcmkONERROR( + gckKERNEL_MapMemory(Kernel, + physical, + Interface->u.MapMemory.bytes, + &Interface->u.MapMemory.logical)); + break; + + case gcvHAL_UNMAP_MEMORY: + physical = Interface->u.UnmapMemory.physical; + + /* Unmap memory. */ + gcmkONERROR( + gckKERNEL_UnmapMemory(Kernel, + physical, + Interface->u.UnmapMemory.bytes, + Interface->u.UnmapMemory.logical)); + break; + + case gcvHAL_ALLOCATE_NON_PAGED_MEMORY: + /* Allocate non-paged memory. */ +#ifdef __QNXNTO__ + if (FromUser) + { + gcmkONERROR( + gckOS_AllocateNonPagedMemoryShmPool( + Kernel->os, + FromUser, + Interface->pid, + Interface->handle, + &Interface->u.AllocateNonPagedMemory.bytes, + &Interface->u.AllocateNonPagedMemory.physical, + &Interface->u.AllocateNonPagedMemory.logical)); + break; + } +#endif + gcmkONERROR( + gckOS_AllocateNonPagedMemory( + Kernel->os, + FromUser, + &Interface->u.AllocateNonPagedMemory.bytes, + &Interface->u.AllocateNonPagedMemory.physical, + &Interface->u.AllocateNonPagedMemory.logical)); + break; + + case gcvHAL_FREE_NON_PAGED_MEMORY: + physical = Interface->u.FreeNonPagedMemory.physical; + + /* Free non-paged memory. */ + gcmkONERROR( + gckOS_FreeNonPagedMemory(Kernel->os, + Interface->u.FreeNonPagedMemory.bytes, + physical, + Interface->u.FreeNonPagedMemory.logical)); + break; + + case gcvHAL_ALLOCATE_CONTIGUOUS_MEMORY: + /* Allocate contiguous memory. */ +#ifdef __QNXNTO__ + if (FromUser) + { + gcmkONERROR( + gckOS_AllocateNonPagedMemoryShmPool( + Kernel->os, + FromUser, + Interface->pid, + Interface->handle, + &Interface->u.AllocateNonPagedMemory.bytes, + &Interface->u.AllocateNonPagedMemory.physical, + &Interface->u.AllocateNonPagedMemory.logical)); + break; + } +#endif + gcmkONERROR( + gckOS_AllocateContiguous( + Kernel->os, + FromUser, + &Interface->u.AllocateContiguousMemory.bytes, + &Interface->u.AllocateContiguousMemory.physical, + &Interface->u.AllocateContiguousMemory.logical)); + + break; + + case gcvHAL_FREE_CONTIGUOUS_MEMORY: + physical = Interface->u.FreeContiguousMemory.physical; + + /* Free contiguous memory. */ + gcmkONERROR( + gckOS_FreeContiguous(Kernel->os, + physical, + Interface->u.FreeContiguousMemory.logical, + Interface->u.FreeContiguousMemory.bytes)); + break; + + case gcvHAL_ALLOCATE_VIDEO_MEMORY: + /* Align width and height to tiles. */ + gcmkONERROR( + gckHARDWARE_AlignToTile(Kernel->hardware, + Interface->u.AllocateVideoMemory.type, + &Interface->u.AllocateVideoMemory.width, + &Interface->u.AllocateVideoMemory.height, + gcvNULL)); + + /* Convert format into bytes per pixel and bytes per tile. */ + gcmkONERROR( + gckHARDWARE_ConvertFormat(Kernel->hardware, + Interface->u.AllocateVideoMemory.format, + &bitsPerPixel, + gcvNULL)); + + /* Compute number of bytes for the allocation. */ + bytes = Interface->u.AllocateVideoMemory.width * bitsPerPixel + * Interface->u.AllocateVideoMemory.height + * Interface->u.AllocateVideoMemory.depth / 8; + + /* Allocate memory. */ +#ifdef __QNXNTO__ + gcmkONERROR( + _AllocateMemory(Kernel, + &Interface->u.AllocateVideoMemory.pool, + bytes, + 64, + Interface->u.AllocateVideoMemory.type, + Interface->handle, + &Interface->u.AllocateVideoMemory.node)); +#else + gcmkONERROR( + _AllocateMemory(Kernel, + &Interface->u.AllocateVideoMemory.pool, + bytes, + 64, + Interface->u.AllocateVideoMemory.type, + &Interface->u.AllocateVideoMemory.node)); +#endif + break; + + case gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY: + /* Allocate memory. */ +#ifdef __QNXNTO__ + gcmkONERROR( + _AllocateMemory(Kernel, + &Interface->u.AllocateLinearVideoMemory.pool, + Interface->u.AllocateLinearVideoMemory.bytes, + Interface->u.AllocateLinearVideoMemory.alignment, + Interface->u.AllocateLinearVideoMemory.type, + Interface->handle, + &Interface->u.AllocateLinearVideoMemory.node)); + + /* Set the current user pid in the node, + * which is used while locking memory. */ + gcmkVERIFY_OK(gckVIDMEM_SetPID( + Interface->u.AllocateLinearVideoMemory.node, + Interface->pid)); +#else + gcmkONERROR( + _AllocateMemory(Kernel, + &Interface->u.AllocateLinearVideoMemory.pool, + Interface->u.AllocateLinearVideoMemory.bytes, + Interface->u.AllocateLinearVideoMemory.alignment, + Interface->u.AllocateLinearVideoMemory.type, + &Interface->u.AllocateLinearVideoMemory.node)); +#endif + break; + + case gcvHAL_FREE_VIDEO_MEMORY: +#ifdef __QNXNTO__ + node = Interface->u.FreeVideoMemory.node; + if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM + && node->VidMem.logical != gcvNULL) + { + gcmkONERROR( + gckKERNEL_UnmapVideoMemory(Kernel, + node->VidMem.logical, + Interface->pid, + node->VidMem.bytes)); + node->VidMem.logical = gcvNULL; + } +#endif + /* Free video memory. */ + gcmkONERROR( + gckVIDMEM_Free(Interface->u.FreeVideoMemory.node)); + break; + + case gcvHAL_LOCK_VIDEO_MEMORY: + /* Lock video memory. */ + gcmkONERROR( + gckVIDMEM_Lock(Interface->u.LockVideoMemory.node, + &Interface->u.LockVideoMemory.address)); + + locked = gcvTRUE; + + node = Interface->u.LockVideoMemory.node; + if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM) + { + /* Map video memory address into user space. */ +#ifdef __QNXNTO__ + if (node->VidMem.logical == gcvNULL) + { + gcmkONERROR( + gckKERNEL_MapVideoMemory(Kernel, + FromUser, + Interface->u.LockVideoMemory.address, + Interface->pid, + node->VidMem.bytes, + &node->VidMem.logical)); + } + Interface->u.LockVideoMemory.memory = node->VidMem.logical; +#else + gcmkONERROR( + gckKERNEL_MapVideoMemory(Kernel, + FromUser, + Interface->u.LockVideoMemory.address, + &Interface->u.LockVideoMemory.memory)); +#endif + +#ifdef __QNXNTO__ + /* Add more information to node, which is used while unmapping. */ + gcmkVERIFY_OK(gckVIDMEM_SetPID( + Interface->u.LockVideoMemory.node, + Interface->pid)); +#endif + } + + else + { + /* Copy logical memory for virtual memory. */ + Interface->u.LockVideoMemory.memory = node->Virtual.logical; + + /* Success. */ + status = gcvSTATUS_OK; + } + +#if gcdSECURE_USER + /* Return logical address as physical address. */ + Interface->u.LockVideoMemory.address = + gcmPTR2INT(Interface->u.LockVideoMemory.memory); +#endif + break; + + case gcvHAL_UNLOCK_VIDEO_MEMORY: + /* Unlock video memory. */ + node = Interface->u.UnlockVideoMemory.node; + + /* Unlock video memory. */ + gcmkONERROR( + gckVIDMEM_Unlock(node, + Interface->u.UnlockVideoMemory.type, + &Interface->u.UnlockVideoMemory.asynchroneous)); + break; + + case gcvHAL_EVENT_COMMIT: + /* Commit an event queue. */ + gcmkONERROR( + gckEVENT_Commit(Kernel->event, + Interface->u.Event.queue)); + break; + + case gcvHAL_COMMIT: + /* Commit a command and context buffer. */ + gcmkONERROR( + gckCOMMAND_Commit(Kernel->command, + Interface->u.Commit.commandBuffer, + Interface->u.Commit.contextBuffer, + Interface->u.Commit.process)); + break; + + case gcvHAL_STALL: + /* Stall the command queue. */ + gcmkONERROR(gckCOMMAND_Stall(Kernel->command)); + break; + + case gcvHAL_MAP_USER_MEMORY: + /* Map user memory to DMA. */ + gcmkONERROR( + gckOS_MapUserMemory(Kernel->os, + Interface->u.MapUserMemory.memory, + Interface->u.MapUserMemory.size, + &Interface->u.MapUserMemory.info, + &Interface->u.MapUserMemory.address)); + break; + + case gcvHAL_UNMAP_USER_MEMORY: + address = Interface->u.MapUserMemory.address; + + /* Unmap user memory. */ + gcmkONERROR( + gckOS_UnmapUserMemory(Kernel->os, + Interface->u.UnmapUserMemory.memory, + Interface->u.UnmapUserMemory.size, + Interface->u.UnmapUserMemory.info, + address)); + break; + +#if !USE_NEW_LINUX_SIGNAL + case gcvHAL_USER_SIGNAL: + /* Dispatch depends on the user signal subcommands. */ + switch(Interface->u.UserSignal.command) + { + case gcvUSER_SIGNAL_CREATE: + /* Create a signal used in the user space. */ + gcmkONERROR( + gckOS_CreateUserSignal(Kernel->os, + Interface->u.UserSignal.manualReset, + &Interface->u.UserSignal.id)); + break; + + case gcvUSER_SIGNAL_DESTROY: + /* Destroy the signal. */ + gcmkONERROR( + gckOS_DestroyUserSignal(Kernel->os, + Interface->u.UserSignal.id)); + break; + + case gcvUSER_SIGNAL_SIGNAL: + /* Signal the signal. */ + gcmkONERROR( + gckOS_SignalUserSignal(Kernel->os, + Interface->u.UserSignal.id, + Interface->u.UserSignal.state)); + break; + + case gcvUSER_SIGNAL_WAIT: + /* Wait on the signal. */ + status = gckOS_WaitUserSignal(Kernel->os, + Interface->u.UserSignal.id, + Interface->u.UserSignal.wait); + break; + + default: + /* Invalid user signal command. */ + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + break; +#endif + + case gcvHAL_SET_POWER_MANAGEMENT_STATE: + /* Set the power management state. */ + gcmkONERROR( + gckHARDWARE_SetPowerManagementState( + Kernel->hardware, + Interface->u.SetPowerManagement.state)); + break; + + case gcvHAL_QUERY_POWER_MANAGEMENT_STATE: + /* Chip is not idle. */ + Interface->u.QueryPowerManagement.isIdle = gcvFALSE; + + /* Query the power management state. */ + gcmkONERROR(gckHARDWARE_QueryPowerManagementState( + Kernel->hardware, + &Interface->u.QueryPowerManagement.state)); + + /* Query the idle state. */ + gcmkONERROR( + gckHARDWARE_QueryIdle(Kernel->hardware, + &Interface->u.QueryPowerManagement.isIdle)); + break; + + case gcvHAL_READ_REGISTER: +#if gcdREGISTER_ACCESS_FROM_USER + /* Read a register. */ + gcmkONERROR( + gckOS_ReadRegister(Kernel->os, + Interface->u.ReadRegisterData.address, + &Interface->u.ReadRegisterData.data)); +#else + /* No access from user land to read registers. */ + Interface->u.ReadRegisterData.data = 0; + status = gcvSTATUS_NOT_SUPPORTED; +#endif + break; + + case gcvHAL_WRITE_REGISTER: +#if gcdREGISTER_ACCESS_FROM_USER + /* Write a register. */ + gcmkONERROR( + gckOS_WriteRegister(Kernel->os, + Interface->u.WriteRegisterData.address, + Interface->u.WriteRegisterData.data)); +#else + /* No access from user land to write registers. */ + status = gcvSTATUS_NOT_SUPPORTED; +#endif + break; + + case gcvHAL_READ_ALL_PROFILE_REGISTERS: +#if VIVANTE_PROFILER + /* Read all 3D profile registers. */ + gcmkONERROR( + gckHARDWARE_QueryProfileRegisters( + Kernel->hardware, + &Interface->u.RegisterProfileData.counters)); +#else + status = gcvSTATUS_OK; +#endif + break; + + case gcvHAL_PROFILE_REGISTERS_2D: +#if VIVANTE_PROFILER + /* Read all 2D profile registers. */ + gcmkONERROR( + gckHARDWARE_ProfileEngine2D( + Kernel->hardware, + Interface->u.RegisterProfileData2D.hwProfile2D)); +#else + status = gcvSTATUS_OK; +#endif + break; + + case gcvHAL_GET_PROFILE_SETTING: +#if VIVANTE_PROFILER + /* Get profile setting */ + Interface->u.GetProfileSetting.enable = Kernel->profileEnable; + + gcmkVERIFY_OK( + gckOS_MemCopy(Interface->u.GetProfileSetting.fileName, + Kernel->profileFileName, + gcdMAX_PROFILE_FILE_NAME)); +#endif + + status = gcvSTATUS_OK; + break; + + case gcvHAL_SET_PROFILE_SETTING: +#if VIVANTE_PROFILER + /* Set profile setting */ + Kernel->profileEnable = Interface->u.SetProfileSetting.enable; + + gcmkVERIFY_OK( + gckOS_MemCopy(Kernel->profileFileName, + Interface->u.SetProfileSetting.fileName, + gcdMAX_PROFILE_FILE_NAME)); +#endif + + status = gcvSTATUS_OK; + break; + + case gcvHAL_QUERY_KERNEL_SETTINGS: + /* Get kernel settings. */ + gcmkONERROR( + gckKERNEL_QuerySettings(Kernel, + &Interface->u.QueryKernelSettings.settings)); + break; + + case gcvHAL_RESET: + /* Reset the hardware. */ + gcmkONERROR( + gckHARDWARE_Reset(Kernel->hardware)); + break; + + case gcvHAL_DEBUG: + /* Set debug level and zones. */ + if (Interface->u.Debug.set) + { + gckOS_SetDebugLevel(Interface->u.Debug.level); + gckOS_SetDebugZones(Interface->u.Debug.zones, + Interface->u.Debug.enable); + } + + if (Interface->u.Debug.message[0] != '\0') + { + /* Print a message to the debugger. */ + gcmkPRINT(Interface->u.Debug.message); + } + status = gcvSTATUS_OK; + break; + + case gcvHAL_CACHE: + if (Interface->u.Cache.invalidate) + { + /* Flush and invalidate the cache. */ + status = gckOS_CacheInvalidate(Kernel->os, + Interface->u.Cache.process, + Interface->u.Cache.logical, + Interface->u.Cache.bytes); + } + else + { + /* Flush the cache. */ + status = gckOS_CacheFlush(Kernel->os, + Interface->u.Cache.process, + Interface->u.Cache.logical, + Interface->u.Cache.bytes); + } + break; + + default: + /* Invalid command. */ + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + +OnError: + /* Save status. */ + Interface->status = status; + + if (gcmIS_ERROR(status)) + { + if (locked) + { + /* Roll back the lock. */ + gcmkVERIFY_OK( + gckVIDMEM_Unlock(Interface->u.LockVideoMemory.node, + gcvSURF_TYPE_UNKNOWN, + gcvNULL)); + } + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckKERNEL_AttachProcess( + IN gckKERNEL Kernel, + IN gctBOOL Attach + ) +{ + gceSTATUS status; + gctINT32 old; + + gcmkHEADER_ARG("Kernel=0x%x Attach=%d", Kernel, Attach); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + + if (Attach) + { + /* Increment the number of clients attached. */ + gcmkONERROR( + gckOS_AtomIncrement(Kernel->os, Kernel->atomClients, &old)); + + if (old == 0) + { + gcmkONERROR(gckOS_Broadcast(Kernel->os, + Kernel->hardware, + gcvBROADCAST_FIRST_PROCESS)); + } + } + + else + { + /* Decrement the number of clients attached. */ + gcmkONERROR( + gckOS_AtomDecrement(Kernel->os, Kernel->atomClients, &old)); + + if (old == 1) + { + /* Last client detached, switch to SUSPEND power state. */ + gcmkONERROR(gckOS_Broadcast(Kernel->os, + Kernel->hardware, + gcvBROADCAST_LAST_PROCESS)); + + /* Flush the debug cache. */ + gcmkPRINT("$$FLUSH$$"); + } + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +#if gcdSECURE_USER +gceSTATUS +gckKERNEL_MapLogicalToPhysical( + IN gckKERNEL Kernel, + IN gctHANDLE Process, + IN OUT gctPOINTER * Data + ) +{ + gctUINT i, oldest; + gceSTATUS status; + gctUINT32 baseAddress; + + gcmkHEADER_ARG("Kernel=0x%x Process=0x%x *Data=0x%x", + Kernel, Process, gcmOPT_POINTER(Data)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Data != gcvNULL); + + /* Get base address. */ + gcmkONERROR(gckHARDWARE_GetBaseAddress(Kernel->hardware, &baseAddress)); + + /* Walk all used cache slots. */ + for (i = oldest = 0; i < Kernel->cacheSlots; ++i) + { + if ((Kernel->cache[i].logical == *Data) + && (Kernel->cache[i].process == Process) + ) + { + /* Bail out. */ + break; + } + + if (i == 0) + { + /* First slot. */ + oldest = i; + } + + /* Test if this cache slot is older. */ + else if (Kernel->cache[i].stamp < Kernel->cache[oldest].stamp) + { + oldest = i; + } + } + + /* See if we had a match. */ + if (i == Kernel->cacheSlots) + { + /* See if there is room in the cache. */ + if (i < gcmCOUNTOF(Kernel->cache)) + { + /* Just append to the cache. */ + i = Kernel->cacheSlots++; + } + + else + { + /* Evict the oldest cache line. */ + i = oldest; + } + + /* Initialize the cache line. */ + Kernel->cache[i].logical = *Data; + Kernel->cache[i].process = Process; + + /* Map the logical address to a DMA address. */ + gcmkONERROR(gckOS_GetPhysicalAddress(Kernel->os, + *Data, + &Kernel->cache[i].dma)); + + if (baseAddress != 0) + { + gctBOOL needBase; + + /* Does this state load need a base address? */ + gcmkONERROR(gckHARDWARE_NeedBaseAddress(Kernel->hardware, + ((gctUINT32_PTR) Data)[-1], + &needBase)); + + if (needBase) + { + /* Add the base address. */ + Kernel->cache[i].dma += baseAddress; + } + } + } + + /* Increment time stamp of the cache slot. */ + Kernel->cache[i].stamp = Kernel->cacheTimeStamp++; + + /* Return DMA address. */ + *Data = gcmINT2PTR(Kernel->cache[i].dma); + + /* Success. */ + gcmkFOOTER_ARG("*Data=0x%08x", *Data); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} +#endif + +/******************************************************************************* +** +** gckKERNEL_Recovery +** +** Try to recover the GPU from a fatal error. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckKERNEL_Recovery( + IN gckKERNEL Kernel + ) +{ + gceSTATUS status; + gckEVENT event; + gckHARDWARE hardware; +#if gcdSECURE_USER + gctUINT32 processID; +#endif + + gcmkHEADER_ARG("Kernel=0x%x", Kernel); + + /* Validate the arguemnts. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + + /* Grab gckEVENT object. */ + event = Kernel->event; + gcmkVERIFY_OBJECT(event, gcvOBJ_EVENT); + + /* Grab gckHARDWARE object. */ + hardware = Kernel->hardware; + gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); + + /* Handle all outstanding events now. */ + event->pending = ~0U; + gcmkONERROR(gckEVENT_Notify(event, 1)); + + /* Again in case more events got submitted. */ + event->pending = ~0U; + gcmkONERROR(gckEVENT_Notify(event, 2)); + +#if gcdSECURE_USER + /* Flush the secure mapping cache. */ + gcmkONERROR(gckOS_GetProcessID(&processID)); + gcmkONERROR(gckKERNEL_MapLogicalToPhysical(Kernel, processID, gcvNULL)); +#endif + + /* Try issuing a soft reset for the GPU. */ + status = gckHARDWARE_Reset(hardware); + if (status == gcvSTATUS_NOT_SUPPORTED) + { + /* Switch to OFF power. The next submit should return the GPU to ON + ** state. */ + gcmkONERROR( + gckHARDWARE_SetPowerManagementState(hardware, + gcvPOWER_OFF_RECOVERY)); + } + else + { + /* Bail out on reset error. */ + gcmkONERROR(status); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + diff --git a/drivers/staging/rk29/vivante/hal/kernel/gc_hal_kernel.h b/drivers/staging/rk29/vivante/hal/kernel/gc_hal_kernel.h new file mode 100644 index 000000000000..35adeb725f8b --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/kernel/gc_hal_kernel.h @@ -0,0 +1,406 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_kernel_h_ +#define __gc_hal_kernel_h_ + +#include "gc_hal.h" +#include "gc_hal_kernel_hardware.h" +#include "gc_hal_driver.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************\ +********************************** Structures ********************************** +\******************************************************************************/ + +#if gcdSECURE_USER +typedef struct _gckLOGICAL_CACHE +{ + gctHANDLE process; + gctPOINTER logical; + gctUINT32 dma; + gctUINT64 stamp; +} +gckLOGICAL_CACHE; +#endif + +/* gckKERNEL object. */ +struct _gckKERNEL +{ + /* Object. */ + gcsOBJECT object; + + /* Pointer to gckOS object. */ + gckOS os; + + /* Pointer to gckHARDWARE object. */ + gckHARDWARE hardware; + + /* Pointer to gckCOMMAND object. */ + gckCOMMAND command; + + /* Pointer to gckEVENT object. */ + gckEVENT event; + + /* Pointer to context. */ + gctPOINTER context; + + /* Pointer to gckMMU object. */ + gckMMU mmu; + + /* Arom holding number of clients. */ + gctPOINTER atomClients; + +#if VIVANTE_PROFILER + /* Enable profiling */ + gctBOOL profileEnable; + + /* The profile file name */ + gctCHAR profileFileName[gcdMAX_PROFILE_FILE_NAME]; +#endif + +#if gcdSECURE_USER + gckLOGICAL_CACHE cache[gcdSECURE_CACHE_SLOTS]; + gctUINT cacheSlots; + gctUINT64 cacheTimeStamp; +#endif +}; + +#define gcdCOMMAND_QUEUES 2 + +/* gckCOMMAND object. */ +struct _gckCOMMAND +{ + /* Object. */ + gcsOBJECT object; + + /* Pointer to required object. */ + gckKERNEL kernel; + gckOS os; + + /* Number of bytes per page. */ + gctSIZE_T pageSize; + + /* Current pipe select. */ + gctUINT32 pipeSelect; + + /* Command queue running flag. */ + gctBOOL running; + + /* Idle flag and commit stamp. */ + gctBOOL idle; + gctUINT64 commitStamp; + + /* Command queue mutex. */ + gctPOINTER mutexQueue; + + /* Context switching mutex. */ + gctPOINTER mutexContext; + + /* Command queue power semaphore. */ + gctPOINTER powerSemaphore; + + /* Current command queue. */ + struct _gcskCOMMAND_QUEUE + { + gctSIGNAL signal; + gctPHYS_ADDR physical; + gctPOINTER logical; + } + queues[gcdCOMMAND_QUEUES]; + + gctPHYS_ADDR physical; + gctPOINTER logical; + gctINT index; + gctUINT32 offset; + + /* The command queue is new. */ + gctBOOL newQueue; + gctBOOL submit; + + /* Context counter used for unique ID. */ + gctUINT64 contextCounter; + + /* Current context ID. */ + gctUINT64 currentContext; + + /* Pointer to last WAIT command. */ + gctPOINTER wait; + gctSIZE_T waitSize; + + /* Command buffer alignment. */ + gctSIZE_T alignment; + gctSIZE_T reservedHead; + gctSIZE_T reservedTail; + + /* Commit counter. */ + gctPOINTER atomCommit; +}; + +typedef struct _gcsEVENT * gcsEVENT_PTR; + +/* Structure holding one event to be processed. */ +typedef struct _gcsEVENT +{ + /* Pointer to next event in queue. */ + gcsEVENT_PTR next; + + /* Event information. */ + gcsHAL_INTERFACE event; + +#ifdef __QNXNTO__ + /* Kernel. */ + gckKERNEL kernel; +#endif +} +gcsEVENT; + +/* Structure holding a list of events to be processed by an interrupt. */ +typedef struct _gcsEVENT_QUEUE +{ + /* Time stamp. */ + gctUINT64 stamp; + + /* Source of the event. */ + gceKERNEL_WHERE source; + + /* Pointer to head of event queue. */ + gcsEVENT_PTR head; + + /* Pointer to tail of event queue. */ + gcsEVENT_PTR tail; + + /* Process ID owning the event queue. */ + gctUINT32 processID; +} +gcsEVENT_QUEUE; + +/* gckEVENT object. */ +struct _gckEVENT +{ + /* The object. */ + gcsOBJECT object; + + /* Pointer to required objects. */ + gckOS os; + gckKERNEL kernel; + + /* Time stamp. */ + gctUINT64 stamp; + gctUINT64 lastCommitStamp; + + /* Queue mutex. */ + gctPOINTER mutexQueue; + + /* Array of event queues. */ + gcsEVENT_QUEUE queues[31]; + gctUINT8 lastID; + + /* Pending events. */ + volatile gctUINT pending; + + /* List of free event structures and its mutex. */ + gcsEVENT_PTR freeList; + gctSIZE_T freeCount; + gctPOINTER freeMutex; + + /* Events queued to be added to an event queue and its mutex. */ + gcsEVENT_QUEUE list; + gctPOINTER listMutex; +}; + +/* gcuVIDMEM_NODE structure. */ +typedef union _gcuVIDMEM_NODE +{ + /* Allocated from gckVIDMEM. */ + struct _gcsVIDMEM_NODE_VIDMEM + { + /* Owner of this node. */ + gckVIDMEM memory; + + /* Dual-linked list of nodes. */ + gcuVIDMEM_NODE_PTR next; + gcuVIDMEM_NODE_PTR prev; + + /* Dual linked list of free nodes. */ + gcuVIDMEM_NODE_PTR nextFree; + gcuVIDMEM_NODE_PTR prevFree; + + /* Information for this node. */ + gctUINT32 offset; + gctSIZE_T bytes; + gctUINT32 alignment; + +#ifdef __QNXNTO__ + /* Client/server vaddr (mapped using mmap_join). */ + gctPOINTER logical; + + /* Unique handle of the caller process channel. */ + gctHANDLE handle; +#endif + + /* Locked counter. */ + gctINT32 locked; + + /* Memory pool. */ + gcePOOL pool; + gctUINT32 physical; + } + VidMem; + + /* Allocated from gckOS. */ + struct _gcsVIDMEM_NODE_VIRTUAL + { + /* Pointer to gckKERNEL object. */ + gckKERNEL kernel; + + /* Information for this node. */ + gctBOOL contiguous; + gctPHYS_ADDR physical; + gctSIZE_T bytes; + gctPOINTER logical; + + /* Page table information. */ + gctSIZE_T pageCount; + gctPOINTER pageTable; + gctUINT32 address; + + /* Mutex. */ + gctPOINTER mutex; + + /* Locked counter. */ + gctINT32 locked; + +#ifdef __QNXNTO__ + /* Single linked list of nodes. */ + gcuVIDMEM_NODE_PTR next; + + /* PID of the caller process channel. */ + gctUINT32 userPID; + + /* Unique handle of the caller process channel. */ + gctHANDLE handle; + + /* Unlock pending flag. */ + gctBOOL unlockPending; + + /* Free pending flag. */ + gctBOOL freePending; +#else + /* Pending flag. */ + gctBOOL pending; +#endif + } + Virtual; +} +gcuVIDMEM_NODE; + +/* gckVIDMEM object. */ +struct _gckVIDMEM +{ + /* Object. */ + gcsOBJECT object; + + /* Pointer to gckOS object. */ + gckOS os; + + /* Information for this video memory heap. */ + gctUINT32 baseAddress; + gctSIZE_T bytes; + gctSIZE_T freeBytes; + + /* Mapping for each type of surface. */ + gctINT mapping[gcvSURF_NUM_TYPES]; + + /* Sentinel nodes for up to 8 banks. */ + gcuVIDMEM_NODE sentinel[8]; + + /* Allocation threshold. */ + gctSIZE_T threshold; + + /* The heap mutex. */ + gctPOINTER mutex; +}; + +/* gckMMU object. */ +struct _gckMMU +{ + /* The object. */ + gcsOBJECT object; + + /* Pointer to gckOS object. */ + gckOS os; + + /* Pointer to gckHARDWARE object. */ + gckHARDWARE hardware; + + /* The page table mutex. */ + gctPOINTER pageTableMutex; + + /* Page table information. */ + gctSIZE_T pageTableSize; + gctPHYS_ADDR pageTablePhysical; + gctUINT32_PTR pageTableLogical; + gctUINT32 pageTableEntries; + + /* Free entries. */ + gctUINT32 heapList; + gctBOOL freeNodes; + +#ifdef __QNXNTO__ + /* Single linked list of all allocated nodes. */ + gctPOINTER nodeMutex; + gcuVIDMEM_NODE_PTR nodeList; +#endif +}; + +gceSTATUS +gckKERNEL_AttachProcess( + IN gckKERNEL Kernel, + IN gctBOOL Attach + ); + +#if gcdSECURE_USER +gceSTATUS +gckKERNEL_MapLogicalToPhysical( + IN gckKERNEL Kernel, + IN gctHANDLE Process, + IN OUT gctPOINTER * Data + ); +#endif + +gceSTATUS +gckHARDWARE_QueryIdle( + IN gckHARDWARE Hardware, + OUT gctBOOL_PTR IsIdle + ); + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_kernel_h_ */ + diff --git a/drivers/staging/rk29/vivante/hal/kernel/gc_hal_kernel_command.c b/drivers/staging/rk29/vivante/hal/kernel/gc_hal_kernel_command.c new file mode 100644 index 000000000000..f0a9cf8b683b --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/kernel/gc_hal_kernel_command.c @@ -0,0 +1,1797 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_precomp.h" +#include "gc_hal_user_context.h" + +#if defined(__QNXNTO__) +#include +#endif + +#define _GC_OBJ_ZONE gcvZONE_COMMAND + +/******************************************************************************\ +********************************* Support Code ********************************* +\******************************************************************************/ + +#if gcdDUMP_COMMAND +static void +_DumpCommand( + IN gckCOMMAND Command, + IN gctPOINTER Pointer, + IN gctSIZE_T Bytes + ) +{ + gctUINT32_PTR data = (gctUINT32_PTR) Pointer; + gctUINT32 address; + + gckOS_GetPhysicalAddress(Command->os, Pointer, &address); + + gcmkPRINT("@[kernel.command %08X %08X", address, Bytes); + while (Bytes >= 8*4) + { + gcmkPRINT(" %08X %08X %08X %08X %08X %08X %08X %08X", + data[0], data[1], data[2], data[3], data[4], data[5], data[6], + data[7]); + data += 8; + Bytes -= 32; + } + + switch (Bytes) + { + case 7*4: + gcmkPRINT(" %08X %08X %08X %08X %08X %08X %08X", + data[0], data[1], data[2], data[3], data[4], data[5], + data[6]); + break; + + case 6*4: + gcmkPRINT(" %08X %08X %08X %08X %08X %08X", + data[0], data[1], data[2], data[3], data[4], data[5]); + break; + + case 5*4: + gcmkPRINT(" %08X %08X %08X %08X %08X", + data[0], data[1], data[2], data[3], data[4]); + break; + + case 4*4: + gcmkPRINT(" %08X %08X %08X %08X", data[0], data[1], data[2], data[3]); + break; + + case 3*4: + gcmkPRINT(" %08X %08X %08X", data[0], data[1], data[2]); + break; + + case 2*4: + gcmkPRINT(" %08X %08X", data[0], data[1]); + break; + + case 1*4: + gcmkPRINT(" %08X", data[0]); + break; + } + + gcmkPRINT("] -- command"); +} +#endif + +/******************************************************************************* +** +** _NewQueue +** +** Allocate a new command queue. +** +** INPUT: +** +** gckCOMMAND Command +** Pointer to an gckCOMMAND object. +** +** OUTPUT: +** +** gckCOMMAND Command +** gckCOMMAND object has been updated with a new command queue. +*/ +static gceSTATUS +_NewQueue( + IN OUT gckCOMMAND Command + ) +{ + gceSTATUS status; + gctINT currentIndex, newIndex; + + gcmkHEADER_ARG("Command=0x%x", Command); + + /* Switch to the next command buffer. */ + currentIndex = Command->index; + newIndex = (currentIndex + 1) % gcdCOMMAND_QUEUES; + + /* Wait for availability. */ +#if gcdDUMP_COMMAND + gcmkPRINT("@[kernel.waitsignal]"); +#endif + + gcmkONERROR( + gckOS_WaitSignal(Command->os, + Command->queues[newIndex].signal, + gcvINFINITE)); + + if (currentIndex >= 0) + { + /* Mark the command queue as available. */ + gcmkONERROR(gckEVENT_Signal(Command->kernel->event, + Command->queues[currentIndex].signal, + gcvKERNEL_COMMAND)); + } + + /* Update gckCOMMAND object with new command queue. */ + Command->index = newIndex; + Command->newQueue = gcvTRUE; + Command->physical = Command->queues[newIndex].physical; + Command->logical = Command->queues[newIndex].logical; + Command->offset = 0; + + if (currentIndex >= 0) + { + /* Submit the event queue. */ + Command->submit = gcvTRUE; + } + + /* Success. */ + gcmkFOOTER_ARG("Command->index=%d", Command->index); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************\ +****************************** gckCOMMAND API Code ****************************** +\******************************************************************************/ + +/******************************************************************************* +** +** gckCOMMAND_Construct +** +** Construct a new gckCOMMAND object. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** OUTPUT: +** +** gckCOMMAND * Command +** Pointer to a variable that will hold the pointer to the gckCOMMAND +** object. +*/ +gceSTATUS +gckCOMMAND_Construct( + IN gckKERNEL Kernel, + OUT gckCOMMAND * Command + ) +{ + gckOS os; + gckCOMMAND command = gcvNULL; + gceSTATUS status; + gctINT i; + + gcmkHEADER_ARG("Kernel=0x%x", Kernel); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Command != gcvNULL); + + /* Extract the gckOS object. */ + os = Kernel->os; + + /* Allocate the gckCOMMAND structure. */ + gcmkONERROR( + gckOS_Allocate(os, + gcmSIZEOF(struct _gckCOMMAND), + (gctPOINTER *) &command)); + + /* Initialize the gckCOMMAND object.*/ + command->object.type = gcvOBJ_COMMAND; + command->kernel = Kernel; + command->os = os; + command->mutexQueue = gcvNULL; + command->mutexContext = gcvNULL; + command->powerSemaphore = gcvNULL; + command->atomCommit = gcvNULL; + + /* No command queues created yet. */ + command->index = 0; + for (i = 0; i < gcdCOMMAND_QUEUES; ++i) + { + command->queues[i].signal = gcvNULL; + command->queues[i].logical = gcvNULL; + } + + /* Get the command buffer requirements. */ + gcmkONERROR( + gckHARDWARE_QueryCommandBuffer(Kernel->hardware, + &command->alignment, + &command->reservedHead, + &command->reservedTail)); + + /* No contexts available yet. */ + command->contextCounter = command->currentContext = 0; + + /* Create the command queue mutex. */ + gcmkONERROR( + gckOS_CreateMutex(os, &command->mutexQueue)); + + /* Create the context switching mutex. */ + gcmkONERROR( + gckOS_CreateMutex(os, &command->mutexContext)); + + /* Create the power management semaphore. */ + gcmkONERROR( + gckOS_CreateSemaphore(os, &command->powerSemaphore)); + + /* Create the commit atom. */ + gcmkONERROR(gckOS_AtomConstruct(os, &command->atomCommit)); + + /* Get the page size from teh OS. */ + gcmkONERROR( + gckOS_GetPageSize(os, &command->pageSize)); + + /* Set hardware to pipe 0. */ + command->pipeSelect = 0; + + /* Pre-allocate the command queues. */ + for (i = 0; i < gcdCOMMAND_QUEUES; ++i) + { + gcmkONERROR( + gckOS_AllocateNonPagedMemory(os, + gcvFALSE, + &command->pageSize, + &command->queues[i].physical, + &command->queues[i].logical)); + gcmkONERROR( + gckOS_CreateSignal(os, gcvFALSE, &command->queues[i].signal)); + + gcmkONERROR( + gckOS_Signal(os, command->queues[i].signal, gcvTRUE)); + } + + /* No command queue in use yet. */ + command->index = -1; + command->logical = gcvNULL; + command->newQueue = gcvFALSE; + command->submit = gcvFALSE; + + /* Command is not yet running. */ + command->running = gcvFALSE; + + /* Command queue is idle. */ + command->idle = gcvTRUE; + + /* Commit stamp is zero. */ + command->commitStamp = 0; + + /* Return pointer to the gckCOMMAND object. */ + *Command = command; + + /* Success. */ + gcmkFOOTER_ARG("*Command=0x%x", *Command); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (command != gcvNULL) + { + if (command->atomCommit != gcvNULL) + { + gcmkVERIFY_OK(gckOS_AtomDestroy(os, command->atomCommit)); + } + + if (command->powerSemaphore != gcvNULL) + { + gcmkVERIFY_OK(gckOS_DestroySemaphore(os, command->powerSemaphore)); + } + + if (command->mutexContext != gcvNULL) + { + gcmkVERIFY_OK(gckOS_DeleteMutex(os, command->mutexContext)); + } + + if (command->mutexQueue != gcvNULL) + { + gcmkVERIFY_OK(gckOS_DeleteMutex(os, command->mutexQueue)); + } + + for (i = 0; i < gcdCOMMAND_QUEUES; ++i) + { + if (command->queues[i].signal != gcvNULL) + { + gcmkVERIFY_OK( + gckOS_DestroySignal(os, command->queues[i].signal)); + } + + if (command->queues[i].logical != gcvNULL) + { + gcmkVERIFY_OK( + gckOS_FreeNonPagedMemory(os, + command->pageSize, + command->queues[i].physical, + command->queues[i].logical)); + } + } + + gcmkVERIFY_OK(gckOS_Free(os, command)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckCOMMAND_Destroy +** +** Destroy an gckCOMMAND object. +** +** INPUT: +** +** gckCOMMAND Command +** Pointer to an gckCOMMAND object to destroy. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckCOMMAND_Destroy( + IN gckCOMMAND Command + ) +{ + gctINT i; + + gcmkHEADER_ARG("Command=0x%x", Command); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + + /* Stop the command queue. */ + gcmkVERIFY_OK(gckCOMMAND_Stop(Command)); + + for (i = 0; i < gcdCOMMAND_QUEUES; ++i) + { + gcmkASSERT(Command->queues[i].signal != gcvNULL); + gcmkVERIFY_OK( + gckOS_DestroySignal(Command->os, Command->queues[i].signal)); + + gcmkASSERT(Command->queues[i].logical != gcvNULL); + gcmkVERIFY_OK( + gckOS_FreeNonPagedMemory(Command->os, + Command->pageSize, + Command->queues[i].physical, + Command->queues[i].logical)); + } + + /* Delete the context switching mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Command->os, Command->mutexContext)); + + /* Delete the command queue mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Command->os, Command->mutexQueue)); + + /* Destroy the power management semaphore. */ + gcmkVERIFY_OK(gckOS_DestroySemaphore(Command->os, Command->powerSemaphore)); + + /* Destroy the commit atom. */ + gcmkVERIFY_OK(gckOS_AtomDestroy(Command->os, Command->atomCommit)); + + /* Mark object as unknown. */ + Command->object.type = gcvOBJ_UNKNOWN; + + /* Free the gckCOMMAND object. */ + gcmkVERIFY_OK(gckOS_Free(Command->os, Command)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckCOMMAND_Start +** +** Start up the command queue. +** +** INPUT: +** +** gckCOMMAND Command +** Pointer to an gckCOMMAND object to start. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckCOMMAND_Start( + IN gckCOMMAND Command + ) +{ + gckHARDWARE hardware; + gceSTATUS status; + gctSIZE_T bytes; + + gcmkHEADER_ARG("Command=0x%x", Command); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + + if (Command->running) + { + /* Command queue already running. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + } + + /* Extract the gckHARDWARE object. */ + hardware = Command->kernel->hardware; + gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); + + if (Command->logical == gcvNULL) + { + /* Start at beginning of a new queue. */ + gcmkONERROR(_NewQueue(Command)); + } + + /* Start at beginning of page. */ + Command->offset = 0; + + /* Append WAIT/LINK. */ + bytes = Command->pageSize; + gcmkONERROR( + gckHARDWARE_WaitLink(hardware, + Command->logical, + 0, + &bytes, + &Command->wait, + &Command->waitSize)); + + /* Flush the cache for the wait/link. */ + gcmkONERROR(gckOS_CacheFlush(Command->os, + gcvNULL, + Command->logical, + bytes)); + + /* Adjust offset. */ + Command->offset = bytes; + Command->newQueue = gcvFALSE; + + /* Enable command processor. */ +#ifdef __QNXNTO__ + gcmkONERROR( + gckHARDWARE_Execute(hardware, + Command->logical, + Command->physical, + gcvTRUE, + bytes)); +#else + gcmkONERROR( + gckHARDWARE_Execute(hardware, + Command->logical, + bytes)); +#endif + /* Command queue is running. */ + Command->running = gcvTRUE; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckCOMMAND_Stop +** +** Stop the command queue. +** +** INPUT: +** +** gckCOMMAND Command +** Pointer to an gckCOMMAND object to stop. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckCOMMAND_Stop( + IN gckCOMMAND Command + ) +{ + gckHARDWARE hardware; + gceSTATUS status; + gctUINT32 idle; + + gcmkHEADER_ARG("Command=0x%x", Command); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + + if (!Command->running) + { + /* Command queue is not running. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + } + + /* Extract the gckHARDWARE object. */ + hardware = Command->kernel->hardware; + gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); + + /* Replace last WAIT with END. */ + gcmkONERROR( + gckHARDWARE_End(hardware, + Command->wait, + &Command->waitSize)); + + /* Wait for idle. */ + gcmkONERROR( + gckHARDWARE_GetIdle(hardware, gcvTRUE, &idle)); + + /* Command queue is no longer running. */ + Command->running = gcvFALSE; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +typedef struct _gcsMAPPED * gcsMAPPED_PTR; +struct _gcsMAPPED +{ + gcsMAPPED_PTR next; + gctPOINTER pointer; + gctPOINTER kernelPointer; + gctSIZE_T bytes; +}; + +static gceSTATUS +_AddMap( + IN gckOS Os, + IN gctPOINTER Source, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Destination, + IN OUT gcsMAPPED_PTR * Stack + ) +{ + gcsMAPPED_PTR map = gcvNULL; + gceSTATUS status; + + /* Don't try to map NULL pointers. */ + if (Source == gcvNULL) + { + *Destination = gcvNULL; + return gcvSTATUS_OK; + } + + /* Allocate the gcsMAPPED structure. */ + gcmkONERROR( + gckOS_Allocate(Os, gcmSIZEOF(*map), (gctPOINTER *) &map)); + + /* Map the user pointer into kernel addressing space. */ + gcmkONERROR( + gckOS_MapUserPointer(Os, Source, Bytes, Destination)); + + /* Save mapping. */ + map->pointer = Source; + map->kernelPointer = *Destination; + map->bytes = Bytes; + + /* Push structure on top of the stack. */ + map->next = *Stack; + *Stack = map; + + /* Success. */ + return gcvSTATUS_OK; + +OnError: + if (gcmIS_ERROR(status) && (map != gcvNULL)) + { + /* Roll back on error. */ + gcmkVERIFY_OK(gckOS_Free(Os, map)); + } + + /* Return the status. */ + return status; +} + +/******************************************************************************* +** +** gckCOMMAND_Commit +** +** Commit a command buffer to the command queue. +** +** INPUT: +** +** gckCOMMAND Command +** Pointer to an gckCOMMAND object. +** +** gcoCMDBUF CommandBuffer +** Pointer to an gcoCMDBUF object. +** +** gcoCONTEXT Context +** Pointer to an gcoCONTEXT object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckCOMMAND_Commit( + IN gckCOMMAND Command, + IN gcoCMDBUF CommandBuffer, + IN gcoCONTEXT Context, + IN gctHANDLE Process + ) +{ + gcoCMDBUF commandBuffer; + gcoCONTEXT context; + gckHARDWARE hardware = gcvNULL; + gceSTATUS status; + gctPOINTER initialLink, link; + gctSIZE_T bytes, initialSize, lastRun; + gcoCMDBUF buffer; + gctPOINTER wait; + gctSIZE_T waitSize; + gctUINT32 offset; + gctPOINTER fetchAddress; + gctSIZE_T fetchSize; + gctUINT8_PTR logical; + gcsMAPPED_PTR stack = gcvNULL; + gctINT acquired = 0; +#if gcdSECURE_USER + gctUINT32_PTR hint; +#endif +#if gcdDUMP_COMMAND + gctPOINTER dataPointer; + gctSIZE_T dataBytes; +#endif + gctPOINTER flushPointer; + gctSIZE_T flushSize; + gctBOOL semaAcquired = gcvFALSE; + gctINT32 atomValue; + gctBOOL atomIncremented = gcvFALSE; + gctBOOL powerAcquired = gcvFALSE; + + gcmkHEADER_ARG("Command=0x%x CommandBuffer=0x%x Context=0x%x", + Command, CommandBuffer, Context); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + +#if gcdNULL_DRIVER == 2 + /* Do nothing with infinite hardware. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +#endif + + gcmkONERROR( + _AddMap(Command->os, + CommandBuffer, + gcmSIZEOF(struct _gcoCMDBUF), + (gctPOINTER *) &commandBuffer, + &stack)); + gcmkVERIFY_OBJECT(commandBuffer, gcvOBJ_COMMANDBUFFER); + gcmkONERROR( + _AddMap(Command->os, + Context, + gcmSIZEOF(struct _gcoCONTEXT), + (gctPOINTER *) &context, + &stack)); + gcmkVERIFY_OBJECT(context, gcvOBJ_CONTEXT); + + /* Extract the gckHARDWARE and gckEVENT objects. */ + hardware = Command->kernel->hardware; + gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); + + /* Grab the power mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(Command->os, hardware->powerMutex, gcvINFINITE)); + powerAcquired = gcvTRUE; + + /* Increment the commit atom. */ + gcmkONERROR(gckOS_AtomIncrement(Command->os, + Command->atomCommit, + &atomValue)); + atomIncremented = gcvTRUE; + + /* Release the power mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Command->os, hardware->powerMutex)); + powerAcquired = gcvFALSE; + + /* Notify the system the GPU has a commit. */ + gcmkONERROR(gckOS_Broadcast(Command->os, + hardware, + gcvBROADCAST_GPU_COMMIT)); + + /* Acquire the power management semaphore. */ + gcmkONERROR(gckOS_AcquireSemaphore(Command->os, Command->powerSemaphore)); + semaAcquired = gcvTRUE; + + /* Acquire the context switching mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(Command->os, + Command->mutexContext, + gcvINFINITE)); + + ++acquired; + + /* Reserved slot in the context or command buffer. */ + gcmkONERROR( + gckHARDWARE_PipeSelect(hardware, gcvNULL, 0, &bytes)); + + /* Test if we need to switch to this context. */ + if ((context->id != 0) + && (context->id != Command->currentContext) + ) + { + /* Map the context buffer. */ + gcmkONERROR( + _AddMap(Command->os, + context->logical, + context->bufferSize, + (gctPOINTER *) &logical, + &stack)); + +#if gcdSECURE_USER + /* Map the hint array. */ + gcmkONERROR( + _AddMap(Command->os, + context->hintArray, + context->hintCount * gcmSIZEOF(gctUINT32), + (gctPOINTER *) &hint, + &stack)); + + /* Loop while we have valid hints. */ + while (*hint != 0) + { + /* Map handle into physical address. */ + gcmkONERROR( + gckKERNEL_MapLogicalToPhysical( + Command->kernel, + Process, + (gctPOINTER *) (logical + *hint))); + + /* Next hint. */ + ++hint; + } +#endif + + /* See if we have to check pipes. */ + if (context->pipe2DIndex != 0) + { + /* See if we are in the correct pipe. */ + if (context->initialPipe == Command->pipeSelect) + { + gctUINT32 reserved = bytes; + gctUINT8_PTR nop = logical; + + /* Already in the correct pipe, fill context buffer with NOP. */ + while (reserved > 0) + { + bytes = reserved; + gcmkONERROR( + gckHARDWARE_Nop(hardware, nop, &bytes)); + + gcmkASSERT(reserved >= bytes); + reserved -= bytes; + nop += bytes; + } + } + else + { + /* Switch to the correct pipe. */ + gcmkONERROR( + gckHARDWARE_PipeSelect(hardware, + logical, + context->initialPipe, + &bytes)); + } + } + + /* Save initial link pointer. */ + initialLink = logical; + initialSize = context->bufferSize; + + /* Save initial buffer to flush. */ + flushPointer = initialLink; + flushSize = initialSize; + + /* Save pointer to next link. */ + gcmkONERROR( + _AddMap(Command->os, + context->link, + 8, + &link, + &stack)); + + /* Start parsing CommandBuffer. */ + buffer = commandBuffer; + + /* Mark context buffer as used. */ + if (context->inUse != gcvNULL) + { + gctBOOL_PTR inUse; + + gcmkONERROR( + _AddMap(Command->os, + (gctPOINTER) context->inUse, + gcmSIZEOF(gctBOOL), + (gctPOINTER *) &inUse, + &stack)); + + *inUse = gcvTRUE; + } + } + + else + { + /* Test if this is a new context. */ + if (context->id == 0) + { + /* Generate unique ID for the context buffer. */ + context->id = ++ Command->contextCounter; + + if (context->id == 0) + { + /* Context counter overflow (wow!) */ + gcmkONERROR(gcvSTATUS_TOO_COMPLEX); + } + } + + /* Map the command buffer. */ + gcmkONERROR( + _AddMap(Command->os, + commandBuffer->logical, + commandBuffer->offset, + (gctPOINTER *) &logical, + &stack)); + +#if gcdSECURE_USER + /* Map the hint table. */ + gcmkONERROR( + _AddMap(Command->os, + commandBuffer->hintCommit, + commandBuffer->offset - commandBuffer->startOffset, + (gctPOINTER *) &hint, + &stack)); + + /* Walk while we have valid hints. */ + while (*hint != 0) + { + /* Map the handle to a physical address. */ + gcmkONERROR( + gckKERNEL_MapLogicalToPhysical( + Command->kernel, + Process, + (gctPOINTER *) (logical + *hint))); + + /* Next hint. */ + ++hint; + } +#endif + + if (context->entryPipe == Command->pipeSelect) + { + gctUINT32 reserved = Command->reservedHead; + gctUINT8_PTR nop = logical + commandBuffer->startOffset; + + /* Already in the correct pipe, fill context buffer with NOP. */ + while (reserved > 0) + { + bytes = reserved; + gcmkONERROR( + gckHARDWARE_Nop(hardware, nop, &bytes)); + + gcmkASSERT(reserved >= bytes); + reserved -= bytes; + nop += bytes; + } + } + else + { + /* Switch to the correct pipe. */ + gcmkONERROR( + gckHARDWARE_PipeSelect(hardware, + logical + commandBuffer->startOffset, + context->entryPipe, + &bytes)); + } + + /* Save initial link pointer. */ + initialLink = logical + commandBuffer->startOffset; + initialSize = commandBuffer->offset + - commandBuffer->startOffset + + Command->reservedTail; + + /* Save initial buffer to flush. */ + flushPointer = initialLink; + flushSize = initialSize; + + /* Save pointer to next link. */ + link = logical + commandBuffer->offset; + + /* No more data. */ + buffer = gcvNULL; + } + +#if gcdDUMP_COMMAND + dataPointer = initialLink; + dataBytes = initialSize; +#endif + + /* Loop through all remaining command buffers. */ + if (buffer != gcvNULL) + { + /* Map the command buffer. */ + gcmkONERROR( + _AddMap(Command->os, + buffer->logical, + buffer->offset + Command->reservedTail, + (gctPOINTER *) &logical, + &stack)); + +#if gcdSECURE_USER + /* Map the hint table. */ + gcmkONERROR( + _AddMap(Command->os, + buffer->hintCommit, + buffer->offset - buffer->startOffset, + (gctPOINTER *) &hint, + &stack)); + + /* Walk while we have valid hints. */ + while (*hint != 0) + { + /* Map the handle to a physical address. */ + gcmkONERROR( + gckKERNEL_MapLogicalToPhysical( + Command->kernel, + Process, + (gctPOINTER *) (logical + *hint))); + + /* Next hint. */ + ++hint; + } +#endif + + /* First slot becomes a NOP. */ + { + gctUINT32 reserved = Command->reservedHead; + gctUINT8_PTR nop = logical + buffer->startOffset; + + /* Already in the correct pipe, fill context buffer with NOP. */ + while (reserved > 0) + { + bytes = reserved; + gcmkONERROR( + gckHARDWARE_Nop(hardware, nop, &bytes)); + + gcmkASSERT(reserved >= bytes); + reserved -= bytes; + nop += bytes; + } + } + + /* Generate the LINK to this command buffer. */ + gcmkONERROR( + gckHARDWARE_Link(hardware, + link, + logical + buffer->startOffset, + buffer->offset + - buffer->startOffset + + Command->reservedTail, + &bytes)); + + /* Flush the initial buffer. */ + gcmkONERROR(gckOS_CacheFlush(Command->os, + Process, + flushPointer, + flushSize)); + + /* Save new flush pointer. */ + flushPointer = logical + buffer->startOffset; + flushSize = buffer->offset + - buffer->startOffset + + Command->reservedTail; + +#if gcdDUMP_COMMAND + _DumpCommand(Command, dataPointer, dataBytes); + dataPointer = logical + buffer->startOffset; + dataBytes = buffer->offset - buffer->startOffset + + Command->reservedTail; +#endif + + /* Save pointer to next link. */ + link = logical + buffer->offset; + } + + /* Compute number of bytes required for WAIT/LINK. */ + gcmkONERROR( + gckHARDWARE_WaitLink(hardware, + gcvNULL, + Command->offset, + &bytes, + gcvNULL, + gcvNULL)); + + lastRun = bytes; + + /* Grab the command queue mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(Command->os, + Command->mutexQueue, + gcvINFINITE)); + + ++acquired; + + /* Compute number of bytes left in current command queue. */ + bytes = Command->pageSize - Command->offset; + + if (bytes < lastRun) + { + /* Create a new command queue. */ + gcmkONERROR(_NewQueue(Command)); + + /* Adjust run size with any extra commands inserted. */ + lastRun += Command->offset; + } + + /* Get current offset. */ + offset = Command->offset; + + /* Append WAIT/LINK in command queue. */ + bytes = Command->pageSize - offset; + + gcmkONERROR( + gckHARDWARE_WaitLink(hardware, + (gctUINT8 *) Command->logical + offset, + offset, + &bytes, + &wait, + &waitSize)); + + /* Flush the cache for the wait/link. */ + gcmkONERROR(gckOS_CacheFlush(Command->os, + gcvNULL, + (gctUINT8 *) Command->logical + offset, + bytes)); + +#if gcdDUMP_COMMAND + _DumpCommand(Command, (gctUINT8 *) Command->logical + offset, bytes); +#endif + + /* Adjust offset. */ + offset += bytes; + + if (Command->newQueue) + { + /* Compute fetch location and size for a new command queue. */ + fetchAddress = Command->logical; + fetchSize = offset; + } + else + { + /* Compute fetch location and size for an existing command queue. */ + fetchAddress = (gctUINT8 *) Command->logical + Command->offset; + fetchSize = offset - Command->offset; + } + + bytes = 8; + + /* Link in WAIT/LINK. */ + gcmkONERROR( + gckHARDWARE_Link(hardware, + link, + fetchAddress, + fetchSize, + &bytes)); + + /* Flush the cache for the command buffer. */ + gcmkONERROR(gckOS_CacheFlush(Command->os, + Process, + flushPointer, + flushSize)); + +#if gcdDUMP_COMMAND + _DumpCommand(Command, dataPointer, dataBytes); +#endif + + /* Execute the entire sequence. */ + gcmkONERROR( + gckHARDWARE_Link(hardware, + Command->wait, + initialLink, + initialSize, + &Command->waitSize)); + + /* Flush the cache for the link. */ + gcmkONERROR(gckOS_CacheFlush(Command->os, + gcvNULL, + Command->wait, + Command->waitSize)); + +#if gcdDUMP_COMMAND + _DumpCommand(Command, Command->wait, Command->waitSize); +#endif + + /* Update command queue offset. */ + Command->offset = offset; + Command->newQueue = gcvFALSE; + + /* Update address of last WAIT. */ + Command->wait = wait; + Command->waitSize = waitSize; + + /* Update context and pipe select. */ + Command->currentContext = context->id; + Command->pipeSelect = context->currentPipe; + + /* Update queue tail pointer. */ + gcmkONERROR( + gckHARDWARE_UpdateQueueTail(hardware, + Command->logical, + Command->offset)); + +#if gcdDUMP_COMMAND + gcmkPRINT("@[kernel.commit]"); +#endif + + /* Release the command queue mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Command->os, Command->mutexQueue)); + --acquired; + + /* Release the context switching mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Command->os, Command->mutexContext)); + --acquired; + + /* Release the power management semaphore. */ + gcmkONERROR(gckOS_ReleaseSemaphore(Command->os, Command->powerSemaphore)); + semaAcquired = gcvFALSE; + + /* Submit events if asked for. */ + if (Command->submit) + { + /* Submit events. */ + status = gckEVENT_Submit(Command->kernel->event, gcvFALSE); + + if (gcmIS_SUCCESS(status)) + { + /* Success. */ + Command->submit = gcvFALSE; + } + else + { + gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_COMMAND, + "gckEVENT_Submit returned %d", + status); + } + } + + /* Success. */ + status = gcvSTATUS_OK; + +OnError: + if (acquired > 1) + { + /* Release the command queue mutex. */ + gcmkVERIFY_OK( + gckOS_ReleaseMutex(Command->os, Command->mutexQueue)); + } + + if (acquired > 0) + { + /* Release the context switching mutex. */ + gcmkVERIFY_OK( + gckOS_ReleaseMutex(Command->os, Command->mutexContext)); + } + + if (semaAcquired) + { + /* Release the power management semaphore. */ + gcmkVERIFY_OK( + gckOS_ReleaseSemaphore(Command->os, Command->powerSemaphore)); + } + + if (atomIncremented) + { + /* Decrement the commit atom. */ + gcmkVERIFY_OK(gckOS_AtomDecrement(Command->os, + Command->atomCommit, + &atomValue)); + } + + /* Unmap all mapped pointers. */ + while (stack != gcvNULL) + { + gcsMAPPED_PTR map = stack; + stack = map->next; + + gcmkVERIFY_OK( + gckOS_UnmapUserPointer(Command->os, + map->pointer, + map->bytes, + map->kernelPointer)); + + gcmkVERIFY_OK( + gckOS_Free(Command->os, map)); + } + + if (powerAcquired) + { + /* Release the power mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Command->os, hardware->powerMutex)); + } + + /* Return status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckCOMMAND_Reserve +** +** Reserve space in the command queue. Also acquire the command queue mutex. +** +** INPUT: +** +** gckCOMMAND Command +** Pointer to an gckCOMMAND object. +** +** gctSIZE_T RequestedBytes +** Number of bytes previously reserved. +** +** OUTPUT: +** +** gctPOINTER * Buffer +** Pointer to a variable that will receive the address of the reserved +** space. +** +** gctSIZE_T * BufferSize +** Pointer to a variable that will receive the number of bytes +** available in the command queue. +*/ +gceSTATUS +gckCOMMAND_Reserve( + IN gckCOMMAND Command, + IN gctSIZE_T RequestedBytes, + OUT gctPOINTER * Buffer, + OUT gctSIZE_T * BufferSize + ) +{ + gceSTATUS status; + gctSIZE_T requiredBytes, bytes; + gctBOOL acquired = gcvFALSE; + gctBOOL semaAcquired = gcvTRUE; + gctINT32 atomValue; + gctBOOL atomIncremented = gcvFALSE; + gctBOOL powerAcquired = gcvFALSE; + + gcmkHEADER_ARG("Command=0x%x RequestedBytes=%lu", Command, RequestedBytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + + /* Grab the power mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Command->os, + Command->kernel->hardware->powerMutex, + gcvINFINITE)); + powerAcquired = gcvTRUE; + + /* Increment the commit atom. */ + gcmkONERROR( + gckOS_AtomIncrement(Command->os, Command->atomCommit, &atomValue)); + atomIncremented = gcvTRUE; + + /* Release the power mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Command->os, + Command->kernel->hardware->powerMutex)); + powerAcquired = gcvFALSE; + + /* Notify the system the GPU has a commit. */ + gcmkONERROR(gckOS_Broadcast(Command->os, + Command->kernel->hardware, + gcvBROADCAST_GPU_COMMIT)); + + /* Grab the power management semaphore. */ + gcmkONERROR(gckOS_AcquireSemaphore(Command->os, Command->powerSemaphore)); + semaAcquired = gcvTRUE; + + /* Grab the conmmand queue mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(Command->os, + Command->mutexQueue, + gcvINFINITE)); + acquired = gcvTRUE; + + /* Compute number of bytes required for WAIT/LINK. */ + gcmkONERROR( + gckHARDWARE_WaitLink(Command->kernel->hardware, + gcvNULL, + Command->offset + gcmALIGN(RequestedBytes, + Command->alignment), + &requiredBytes, + gcvNULL, + gcvNULL)); + + /* Compute total number of bytes required. */ + requiredBytes += gcmALIGN(RequestedBytes, Command->alignment); + + /* Compute number of bytes available in command queue. */ + bytes = Command->pageSize - Command->offset; + + if (bytes < requiredBytes) + { + /* Create a new command queue. */ + gcmkONERROR(_NewQueue(Command)); + + /* Recompute number of bytes available in command queue. */ + bytes = Command->pageSize - Command->offset; + + if (bytes < requiredBytes) + { + /* Rare case, not enough room in command queue. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + } + + /* Return pointer to empty slot command queue. */ + *Buffer = (gctUINT8 *) Command->logical + Command->offset; + + /* Return number of bytes left in command queue. */ + *BufferSize = bytes; + + /* Success. */ + gcmkFOOTER_ARG("*Buffer=0x%x *BufferSize=%lu", *Buffer, *BufferSize); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release command queue mutex on error. */ + gcmkVERIFY_OK( + gckOS_ReleaseMutex(Command->os, Command->mutexQueue)); + } + + if (semaAcquired) + { + /* Release the power management semaphore. */ + gcmkVERIFY_OK( + gckOS_ReleaseSemaphore(Command->os, Command->powerSemaphore)); + } + + if (atomIncremented) + { + /* Decrement the commit atom. */ + gcmkVERIFY_OK( + gckOS_AtomDecrement(Command->os, Command->atomCommit, &atomValue)); + } + + if (powerAcquired) + { + /* Release the power mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Command->os, + Command->kernel->hardware->powerMutex)); + } + + /* Return status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckCOMMAND_Release +** +** Release a previously reserved command queue. The command FIFO mutex will be +** released. +** +** INPUT: +** +** gckCOMMAND Command +** Pointer to an gckCOMMAND object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckCOMMAND_Release( + IN gckCOMMAND Command + ) +{ + gceSTATUS status; + gctINT32 atomValue; + + gcmkHEADER_ARG("Command=0x%x", Command); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + + /* Release the command queue mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Command->os, Command->mutexQueue)); + + /* Release the power management semaphore. */ + gcmkONERROR(gckOS_ReleaseSemaphore(Command->os, Command->powerSemaphore)); + + /* Decrement the commit atom. */ + gcmkONERROR( + gckOS_AtomDecrement(Command->os, Command->atomCommit, &atomValue)); + + /* Success. */ + gcmkFOOTER_NO(); + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckCOMMAND_Execute +** +** Execute a previously reserved command queue by appending a WAIT/LINK command +** sequence after it and modifying the last WAIT into a LINK command. The +** command FIFO mutex will be released whether this function succeeds or not. +** +** INPUT: +** +** gckCOMMAND Command +** Pointer to an gckCOMMAND object. +** +** gctSIZE_T RequestedBytes +** Number of bytes previously reserved. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckCOMMAND_Execute( + IN gckCOMMAND Command, + IN gctSIZE_T RequestedBytes + ) +{ + gctUINT32 offset; + gctPOINTER address; + gctSIZE_T bytes; + gceSTATUS status; + gctPOINTER wait; + gctSIZE_T waitBytes; + gctINT32 atomValue; + + gcmkHEADER_ARG("Command=0x%x RequestedBytes=%lu", Command, RequestedBytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + + /* Compute offset for WAIT/LINK. */ + offset = Command->offset + RequestedBytes; + + /* Compute number of byts left in command queue. */ + bytes = Command->pageSize - offset; + + /* Append WAIT/LINK in command queue. */ + gcmkONERROR( + gckHARDWARE_WaitLink(Command->kernel->hardware, + (gctUINT8 *) Command->logical + offset, + offset, + &bytes, + &wait, + &waitBytes)); + + if (Command->newQueue) + { + /* For a new command queue, point to the start of the command + ** queue and include both the commands inserted at the head of it + ** and the WAIT/LINK. */ + address = Command->logical; + bytes += offset; + } + else + { + /* For an existing command queue, point to the current offset and + ** include the WAIT/LINK. */ + address = (gctUINT8 *) Command->logical + Command->offset; + bytes += RequestedBytes; + } + + /* Flush the cache. */ + gcmkONERROR(gckOS_CacheFlush(Command->os, gcvNULL, address, bytes)); + +#if gcdDUMP_COMMAND + _DumpCommand(Command, address, bytes); +#endif + + /* Convert the last WAIT into a LINK. */ + gcmkONERROR(gckHARDWARE_Link(Command->kernel->hardware, + Command->wait, + address, + bytes, + &Command->waitSize)); + + /* Flush the cache. */ + gcmkONERROR(gckOS_CacheFlush(Command->os, + gcvNULL, + Command->wait, + Command->waitSize)); + +#if gcdDUMP_COMMAND + _DumpCommand(Command, Command->wait, 8); +#endif + + /* Update the pointer to the last WAIT. */ + Command->wait = wait; + Command->waitSize = waitBytes; + + /* Update the command queue. */ + Command->offset += bytes; + Command->newQueue = gcvFALSE; + + /* Update queue tail pointer. */ + gcmkONERROR( + gckHARDWARE_UpdateQueueTail(Command->kernel->hardware, + Command->logical, + Command->offset)); + +#if gcdDUMP_COMMAND + gcmkPRINT("@[kernel.execute]"); +#endif + + /* Release the command queue mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Command->os, Command->mutexQueue)); + + /* Release the power management semaphore. */ + gcmkONERROR(gckOS_ReleaseSemaphore(Command->os, Command->powerSemaphore)); + + /* Submit events if asked for. */ + if (Command->submit) + { + /* Submit events. */ + status = gckEVENT_Submit(Command->kernel->event, gcvFALSE); + + if (gcmIS_SUCCESS(status)) + { + /* Success. */ + Command->submit = gcvFALSE; + } + else + { + gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_COMMAND, + "gckEVENT_Submit returned %d", + status); + } + } + + /* Decrement the commit atom. */ + gcmkONERROR( + gckOS_AtomDecrement(Command->os, Command->atomCommit, &atomValue)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Release the command queue mutex. */ + gcmkVERIFY_OK( + gckOS_ReleaseMutex(Command->os, Command->mutexQueue)); + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckCOMMAND_Stall +** +** The calling thread will be suspended until the command queue has been +** completed. +** +** INPUT: +** +** gckCOMMAND Command +** Pointer to an gckCOMMAND object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckCOMMAND_Stall( + IN gckCOMMAND Command + ) +{ + gckOS os; + gckHARDWARE hardware; + gckEVENT event; + gceSTATUS status; + gctSIGNAL signal = gcvNULL; + gctUINT timer = 0; + + gcmkHEADER_ARG("Command=0x%x", Command); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + +#if gcdNULL_DRIVER == 2 + /* Do nothing with infinite hardware. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +#endif + + /* Extract the gckOS object pointer. */ + os = Command->os; + gcmkVERIFY_OBJECT(os, gcvOBJ_OS); + + /* Extract the gckHARDWARE object pointer. */ + hardware = Command->kernel->hardware; + gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); + + /* Extract the gckEVENT object pointer. */ + event = Command->kernel->event; + gcmkVERIFY_OBJECT(event, gcvOBJ_EVENT); + + /* Allocate the signal. */ + gcmkONERROR( + gckOS_CreateSignal(os, gcvTRUE, &signal)); + + /* Append the EVENT command to trigger the signal. */ + gcmkONERROR(gckEVENT_Signal(event, + signal, + gcvKERNEL_PIXEL)); + + /* Submit the event queue. */ + gcmkONERROR(gckEVENT_Submit(event, gcvTRUE)); + +#if gcdDUMP_COMMAND + gcmkPRINT("@[kernel.stall]"); +#endif + + if (status == gcvSTATUS_CHIP_NOT_READY) + { + /* Error. */ + goto OnError; + } + + do + { + /* Wait for the signal. */ + status = gckOS_WaitSignal(os, signal, 250); + + if (status == gcvSTATUS_TIMEOUT) + { +#if gcdDEBUG + gctUINT32 idle; + + /* Read idle register. */ + gcmkVERIFY_OK( + gckHARDWARE_GetIdle(Command->kernel->hardware, + gcvFALSE, + &idle)); + + gcmkTRACE(gcvLEVEL_ERROR, + "%s(%d): idle=%08x", + __FUNCTION__, __LINE__, idle); + + gcmkVERIFY_OK( + gckOS_MemoryBarrier(os, gcvNULL)); + +#ifdef __QNXNTO__ + gctUINT32 reg_cmdbuf_fetch; + gctUINT32 reg_intr; + + gcmkVERIFY_OK( + gckOS_ReadRegister(Command->kernel->hardware->os, 0x0664, ®_cmdbuf_fetch)); + + if (idle == 0x7FFFFFFE) + { + /* + * GPU is idle so there should not be pending interrupts. + * Just double check. + * + * Note that reading interrupt register clears it. + * That's why we don't read it in all cases. + */ + gcmkVERIFY_OK( + gckOS_ReadRegister(Command->kernel->hardware->os, 0x10, ®_intr)); + + slogf( + _SLOG_SETCODE(1, 0), + _SLOG_CRITICAL, + "GALcore: Stall timeout (idle = 0x%X, command buffer fetch = 0x%X, interrupt = 0x%X)", + idle, reg_cmdbuf_fetch, reg_intr); + } + else + { + slogf( + _SLOG_SETCODE(1, 0), + _SLOG_CRITICAL, + "GALcore: Stall timeout (idle = 0x%X, command buffer fetch = 0x%X)", + idle, reg_cmdbuf_fetch); + } +#endif +#endif + /* Advance timer. */ + timer += 250; + } + } + while (gcmIS_ERROR(status) +#if gcdGPU_TIMEOUT + && (timer < gcdGPU_TIMEOUT) +#endif + ); + + /* Bail out on timeout. */ + if (gcmIS_ERROR(status)) + { + /* Broadcast the stuck GPU. */ + gcmkONERROR(gckOS_Broadcast(os, + Command->kernel->hardware, + gcvBROADCAST_GPU_STUCK)); + + gcmkONERROR(gcvSTATUS_GPU_NOT_RESPONDING); + } + + /* Delete the signal. */ + gcmkVERIFY_OK(gckOS_DestroySignal(os, signal)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Free the signal. */ + if (signal != gcvNULL) + { + gcmkVERIFY_OK(gckOS_DestroySignal(os, signal)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + diff --git a/drivers/staging/rk29/vivante/hal/kernel/gc_hal_kernel_event.c b/drivers/staging/rk29/vivante/hal/kernel/gc_hal_kernel_event.c new file mode 100644 index 000000000000..08e810055af5 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/kernel/gc_hal_kernel_event.c @@ -0,0 +1,1481 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_precomp.h" +#include "gc_hal_user_context.h" + +#define _GC_OBJ_ZONE gcvZONE_EVENT + +#define gcdEVENT_ALLOCATION_COUNT (4096 / gcmSIZEOF(gcsHAL_INTERFACE)) +#define gcdEVENT_MIN_THRESHOLD 4 + +/******************************************************************************\ +********************************* Support Code ********************************* +\******************************************************************************/ + +/******************************************************************************* +** +** _GetEvent +** +** Get an empty event ID. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** OUTPUT: +** +** gctUINT8 * EventID +** Pointer to a variable that receives an empty event ID. +*/ +static gceSTATUS +_GetEvent( + IN gckEVENT Event, + OUT gctUINT8 * EventID, + IN gceKERNEL_WHERE Source + ) +{ + gctINT i, id; + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Event=0x%x Source=%d", Event, Source); + + /* Grab the queue mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Event->os, + Event->mutexQueue, + gcvINFINITE)); + acquired = gcvTRUE; + + /* Walk through all events. */ + id = Event->lastID; + for (i = 0; i < gcmCOUNTOF(Event->queues); ++i) + { + if (Event->queues[id].head == gcvNULL) + { + *EventID = (gctUINT8) id; + + Event->lastID = (id + 1) % gcmCOUNTOF(Event->queues); + + /* Save time stamp of event. */ + Event->queues[id].stamp = ++(Event->stamp); + Event->queues[id].source = Source; + + /* Release the queue mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->mutexQueue)); + + /* Success. */ + gcmkFOOTER_ARG("*EventID=%u", *EventID); + return gcvSTATUS_OK; + } + + id = (id + 1) % gcmCOUNTOF(Event->queues); + } + + /* Release the queue mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->mutexQueue)); + acquired = gcvFALSE; + + /* Out of resources. */ + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + +OnError: + if (acquired) + { + /* Release the queue mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->mutexQueue)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +static gceSTATUS +_IsEmpty( + IN gckEVENT Event, + OUT gctBOOL_PTR IsEmpty + ) +{ + gceSTATUS status; + gctSIZE_T i; + + gcmkHEADER_ARG("Event=0x%x", Event); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(IsEmpty != gcvNULL); + + /* Assume the event queue is empty. */ + *IsEmpty = gcvTRUE; + + /* Walk the event queue. */ + for (i = 0; i < gcmCOUNTOF(Event->queues); ++i) + { + /* Check whether this event is in use. */ + if (Event->queues[i].head != gcvNULL) + { + /* The event is in use, hence the queue is not empty. */ + *IsEmpty = gcvFALSE; + break; + } + } + + /* Try acquiring the mutex. */ + status = gckOS_AcquireMutex(Event->os, Event->mutexQueue, 0); + if (status == gcvSTATUS_TIMEOUT) + { + /* Timeout - queue is no longer empty. */ + *IsEmpty = gcvFALSE; + } + else + { + /* Bail out on error. */ + gcmkONERROR(status); + + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->mutexQueue)); + } + + /* Success. */ + gcmkFOOTER_ARG("*IsEmpty=%d", gcmOPT_VALUE(IsEmpty)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************\ +******************************* gckEVENT API Code ******************************* +\******************************************************************************/ + +/******************************************************************************* +** +** gckEVENT_Construct +** +** Construct a new gckEVENT object. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** OUTPUT: +** +** gckEVENT * Event +** Pointer to a variable that receives the gckEVENT object pointer. +*/ +gceSTATUS +gckEVENT_Construct( + IN gckKERNEL Kernel, + OUT gckEVENT * Event + ) +{ + gckOS os; + gceSTATUS status; + gckEVENT event = gcvNULL; + int i; + gcsEVENT_PTR record; + + gcmkHEADER_ARG("Kernel=0x%x", Kernel); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Event != gcvNULL); + + /* Extract the pointer to the gckOS object. */ + os = Kernel->os; + gcmkVERIFY_OBJECT(os, gcvOBJ_OS); + + /* Allocate the gckEVENT object. */ + gcmkONERROR( + gckOS_Allocate(os, + gcmSIZEOF(struct _gckEVENT), + (gctPOINTER *) &event)); + + /* Initialize the gckEVENT object. */ + event->object.type = gcvOBJ_EVENT; + event->kernel = Kernel; + event->os = os; + event->mutexQueue = gcvNULL; + event->freeList = gcvNULL; + event->freeCount = 0; + event->freeMutex = gcvNULL; + event->list.head = gcvNULL; + event->list.tail = gcvNULL; + event->listMutex = gcvNULL; + event->lastID = 0; + + /* Create the mutexes. */ + gcmkONERROR( + gckOS_CreateMutex(os, &event->mutexQueue)); + + gcmkONERROR( + gckOS_CreateMutex(os, &event->freeMutex)); + + gcmkONERROR( + gckOS_CreateMutex(os, &event->listMutex)); + + /* Create a bunch of event reccords. */ + for (i = 0; i < gcdEVENT_ALLOCATION_COUNT; ++i) + { + /* Allocate an event record. */ + gcmkONERROR( + gckOS_Allocate(os, gcmSIZEOF(gcsEVENT), (gctPOINTER *) &record)); + + /* Push it on the free list. */ + record->next = event->freeList; + event->freeList = record; + event->freeCount += 1; + } + + /* Zero out the entire event queue. */ + for (i = 0; i < gcmCOUNTOF(event->queues); ++i) + { + event->queues[i].head = gcvNULL; + } + + /* Zero out the time stamp. */ + event->stamp = 0; + + /* No events to handle. */ + event->pending = 0; + + /* Return pointer to the gckEVENT object. */ + *Event = event; + + /* Success. */ + gcmkFOOTER_ARG("*Event=0x%x", *Event); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (event != gcvNULL) + { + if (event->mutexQueue != gcvNULL) + { + gcmkVERIFY_OK(gckOS_DeleteMutex(os, event->mutexQueue)); + } + + if (event->freeMutex != gcvNULL) + { + gcmkVERIFY_OK(gckOS_DeleteMutex(os, event->freeMutex)); + } + + if (event->listMutex != gcvNULL) + { + gcmkVERIFY_OK(gckOS_DeleteMutex(os, event->listMutex)); + } + + while (event->freeList != gcvNULL) + { + record = event->freeList; + event->freeList = record->next; + + gcmkVERIFY_OK(gckOS_Free(os, record)); + } + + gcmkVERIFY_OK(gckOS_Free(os, event)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckEVENT_Destroy +** +** Destroy an gckEVENT object. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckEVENT_Destroy( + IN gckEVENT Event + ) +{ + gcsEVENT_PTR record; + + gcmkHEADER_ARG("Event=0x%x", Event); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + + /* Delete the queue mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->mutexQueue)); + + /* Free all free events. */ + while (Event->freeList != gcvNULL) + { + record = Event->freeList; + Event->freeList = record->next; + + gcmkVERIFY_OK(gckOS_Free(Event->os, record)); + } + + /* Delete the free mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->freeMutex)); + + /* Free all pending events. */ + while (Event->list.head != gcvNULL) + { + record = Event->list.head; + Event->list.head = record->next; + + gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_EVENT, + "Event record 0x%x is still pending for %d.", + record, Event->list.source); + gcmkVERIFY_OK(gckOS_Free(Event->os, record)); + } + + /* Delete the list mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->listMutex)); + + /* Mark the gckEVENT object as unknown. */ + Event->object.type = gcvOBJ_UNKNOWN; + + /* Free the gckEVENT object. */ + gcmkVERIFY_OK(gckOS_Free(Event->os, Event)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +static gceSTATUS +gckEVENT_AllocateRecord( + IN gckEVENT Event, + IN gctBOOL AllocateAllowed, + OUT gcsEVENT_PTR * Record + ) +{ + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + gctINT i; + gcsEVENT_PTR record; + + gcmkHEADER_ARG("Event=0x%x AllocateAllowed=%d", Event, AllocateAllowed); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(Record != gcvNULL); + + /* Test if we are below the allocation threshold. */ + if (AllocateAllowed + && (Event->freeCount < gcdEVENT_MIN_THRESHOLD) + ) + { + /* Allocate a bunch of records. */ + for (i = 0; i < gcdEVENT_ALLOCATION_COUNT; ++i) + { + /* Allocate an event record. */ + status = gckOS_Allocate(Event->os, + gcmSIZEOF(gcsEVENT), + (gctPOINTER *) &record); + + if (gcmIS_ERROR(status)) + { + gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_EVENT, + "Out of memory allocating event records."); + break; + } + + /* Acquire the mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Event->os, + Event->freeMutex, + gcvINFINITE)); + acquired = gcvTRUE; + + /* Push it on the free list. */ + record->next = Event->freeList; + Event->freeList = record; + Event->freeCount += 1; + + /* Release the mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->freeMutex)); + } + } + + /* Acquire the mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Event->os, Event->freeMutex, gcvINFINITE)); + acquired = gcvTRUE; + + *Record = Event->freeList; + Event->freeList = Event->freeList->next; + Event->freeCount -= 1; + + /* Release the mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->freeMutex)); + + /* Success. */ + gcmkFOOTER_ARG("*Record=0x%x", gcmOPT_POINTER(Record)); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (acquired) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->freeMutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +static gceSTATUS +gckEVENT_FreeRecord( + IN gckEVENT Event, + IN gcsEVENT_PTR Record + ) +{ + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Event=0x%x Record=0x%x", Event, Record); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(Record != gcvNULL); + + /* Acquire the mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Event->os, Event->freeMutex, gcvINFINITE)); + acquired = gcvTRUE; + + /* Push the record on the free list. */ + Record->next = Event->freeList; + Event->freeList = Record; + Event->freeCount += 1; + + /* Release the mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->freeMutex)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (acquired) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->freeMutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return gcvSTATUS_OK; +} + +static gceSTATUS +gckEVENT_AddList( + IN gckEVENT Event, + IN gcsHAL_INTERFACE_PTR Interface, + IN gceKERNEL_WHERE FromWhere, + IN gctBOOL AllocateAllowed + ) +{ + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + gcsEVENT_PTR record = gcvNULL; + + gcmkHEADER_ARG("Event=0x%x Interface=0x%x FromWhere=%d AllocateAllowed=%d", + Event, Interface, FromWhere, AllocateAllowed); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(Interface != gcvNULL); + + switch (FromWhere) + { + case gcvKERNEL_COMMAND: + case gcvKERNEL_PIXEL: + /* Check if the requested source matches the list. */ + if ((Event->list.head != gcvNULL) + && (Event->list.source != FromWhere) + ) + { + /* No match - auto-submit the list. */ + status = gckEVENT_Submit(Event, gcvFALSE); + + if (status == gcvSTATUS_OUT_OF_RESOURCES) + { + /* When we are out of resources, just convert to submit from + ** PIXEL. */ + Event->list.source = FromWhere = gcvKERNEL_PIXEL; + } + + else + { + /* Check for error. */ + gcmkONERROR(status); + } + } + break; + + default: + /* Invalid argument. */ + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + /* Allocate a free record. */ + gcmkONERROR(gckEVENT_AllocateRecord(Event, AllocateAllowed, &record)); + + /* Copy the event interface into the record. */ + gcmkONERROR(gckOS_MemCopy(&record->event, + Interface, + gcmSIZEOF(record->event))); + + gcmkASSERT + ( (Interface->command == gcvHAL_FREE_NON_PAGED_MEMORY) + || (Interface->command == gcvHAL_FREE_CONTIGUOUS_MEMORY) + || (Interface->command == gcvHAL_FREE_VIDEO_MEMORY) + || (Interface->command == gcvHAL_WRITE_DATA) + || (Interface->command == gcvHAL_UNLOCK_VIDEO_MEMORY) + || (Interface->command == gcvHAL_SIGNAL) + || (Interface->command == gcvHAL_UNMAP_USER_MEMORY) + ); + + record->next = gcvNULL; + + /* Acquire the mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Event->os, Event->listMutex, gcvINFINITE)); + acquired = gcvTRUE; + + if (Event->list.head == gcvNULL) + { + /* List doesn't exist yet. */ + Event->list.head = record; + Event->list.tail = record; + } + else + { + /* Append to the current list. */ + Event->list.tail->next = record; + Event->list.tail = record; + } + + /* Mark the source of this event. */ + Event->list.source = FromWhere; + + /* Release the mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->listMutex)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (acquired) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->listMutex)); + } + + if (record != gcvNULL) + { + gcmkVERIFY_OK(gckEVENT_FreeRecord(Event, record)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckEVENT_FreeNonPagedMemory +** +** Schedule an event to free non-paged memory. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** gctSIZE_T Bytes +** Number of bytes of non-paged memory to free. +** +** gctPHYS_ADDR Physical +** Physical address of non-paged memory to free. +** +** gctPOINTER Logical +** Logical address of non-paged memory to free. +** +** gceKERNEL_WHERE FromWhere +** Place in the pipe where the event needs to be generated. +*/ +gceSTATUS +gckEVENT_FreeNonPagedMemory( + IN gckEVENT Event, + IN gctSIZE_T Bytes, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical, + IN gceKERNEL_WHERE FromWhere + ) +{ + gceSTATUS status; + gcsHAL_INTERFACE iface; + + gcmkHEADER_ARG("Event=0x%x Bytes=%lu Physical=0x%x Logical=0x%x " + "FromWhere=%d", + Event, Bytes, Physical, Logical, FromWhere); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(Physical != gcvNULL); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + + /* Create an event. */ + iface.command = gcvHAL_FREE_NON_PAGED_MEMORY; + iface.u.FreeNonPagedMemory.bytes = Bytes; + iface.u.FreeNonPagedMemory.physical = Physical; + iface.u.FreeNonPagedMemory.logical = Logical; + + /* Append it to the queue. */ + gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckEVENT_FreeContigiuousMemory +** +** Schedule an event to free contiguous memory. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** gctSIZE_T Bytes +** Number of bytes of contiguous memory to free. +** +** gctPHYS_ADDR Physical +** Physical address of contiguous memory to free. +** +** gctPOINTER Logical +** Logical address of contiguous memory to free. +** +** gceKERNEL_WHERE FromWhere +** Place in the pipe where the event needs to be generated. +*/ +gceSTATUS +gckEVENT_FreeContiguousMemory( + IN gckEVENT Event, + IN gctSIZE_T Bytes, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical, + IN gceKERNEL_WHERE FromWhere + ) +{ + gceSTATUS status; + gcsHAL_INTERFACE iface; + + gcmkHEADER_ARG("Event=0x%x Bytes=%lu Physical=0x%x Logical=0x%x " + "FromWhere=%d", + Event, Bytes, Physical, Logical, FromWhere); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(Physical != gcvNULL); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + + /* Create an event. */ + iface.command = gcvHAL_FREE_CONTIGUOUS_MEMORY; + iface.u.FreeContiguousMemory.bytes = Bytes; + iface.u.FreeContiguousMemory.physical = Physical; + iface.u.FreeContiguousMemory.logical = Logical; + + /* Append it to the queue. */ + gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckEVENT_FreeVideoMemory +** +** Schedule an event to free video memory. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** gcuVIDMEM_NODE_PTR VideoMemory +** Pointer to a gcuVIDMEM_NODE object to free. +** +** gceKERNEL_WHERE FromWhere +** Place in the pipe where the event needs to be generated. +*/ +gceSTATUS +gckEVENT_FreeVideoMemory( + IN gckEVENT Event, + IN gcuVIDMEM_NODE_PTR VideoMemory, + IN gceKERNEL_WHERE FromWhere + ) +{ + gceSTATUS status; + gcsHAL_INTERFACE iface; + + gcmkHEADER_ARG("Event=0x%x VideoMemory=0x%x FromWhere=%d", + Event, VideoMemory, FromWhere); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(VideoMemory != gcvNULL); + + /* Create an event. */ + iface.command = gcvHAL_FREE_VIDEO_MEMORY; + iface.u.FreeVideoMemory.node = VideoMemory; + + /* Append it to the queue. */ + gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckEVENT_Signal +** +** Schedule an event to trigger a signal. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** gctSIGNAL Signal +** Pointer to the signal to trigger. +** +** gceKERNEL_WHERE FromWhere +** Place in the pipe where the event needs to be generated. +** +*/ +gceSTATUS +gckEVENT_Signal( + IN gckEVENT Event, + IN gctSIGNAL Signal, + IN gceKERNEL_WHERE FromWhere + ) +{ + gceSTATUS status; + gcsHAL_INTERFACE iface; + + gcmkHEADER_ARG("Event=0x%x Signal=0x%x FromWhere=%d", + Event, Signal, FromWhere); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(Signal != gcvNULL); + + /* Mark the event as a signal. */ + iface.command = gcvHAL_SIGNAL; + iface.u.Signal.signal = Signal; +#ifdef __QNXNTO__ + iface.u.Signal.coid = 0; + iface.u.Signal.rcvid = 0; +#else + iface.u.Signal.auxSignal = gcvNULL; + iface.u.Signal.process = gcvNULL; +#endif + + /* Append it to the queue. */ + gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckEVENT_Unlock +** +** Schedule an event to unlock virtual memory. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** gceKERNEL_WHERE FromWhere +** Place in the pipe where the event needs to be generated. +** +** gcuVIDMEM_NODE_PTR Node +** Pointer to a gcuVIDMEM_NODE union that specifies the virtual memory +** to unlock. +** +** gceSURF_TYPE Type +** Type of surface to unlock. +*/ +gceSTATUS +gckEVENT_Unlock( + IN gckEVENT Event, + IN gceKERNEL_WHERE FromWhere, + IN gcuVIDMEM_NODE_PTR Node, + IN gceSURF_TYPE Type + ) +{ + gceSTATUS status; + gcsHAL_INTERFACE iface; + + gcmkHEADER_ARG("Event=0x%x FromWhere=%d Node=0x%x Type=%d", + Event, FromWhere, Node, Type); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(Node != gcvNULL); + + /* Mark the event as an unlock. */ + iface.command = gcvHAL_UNLOCK_VIDEO_MEMORY; + iface.u.UnlockVideoMemory.node = Node; + iface.u.UnlockVideoMemory.type = Type; + iface.u.UnlockVideoMemory.asynchroneous = 0; + + /* Append it to the queue. */ + gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckEVENT_Commit( + IN gckEVENT Event, + IN gcsQUEUE_PTR Queue + ) +{ + gceSTATUS status; + gcsQUEUE_PTR record = gcvNULL, next; + + gcmkHEADER_ARG("Event=0x%x Queue=0x%x", Event, Queue); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + + /* Loop while there are records in the queue. */ + while (Queue != gcvNULL) + { + /* Map record into kernel memory. */ + gcmkONERROR(gckOS_MapUserPointer(Event->os, + Queue, + gcmSIZEOF(gcsQUEUE), + (gctPOINTER *) &record)); + + /* Append event record to event queue. */ + gcmkONERROR( + gckEVENT_AddList(Event, &record->iface, gcvKERNEL_PIXEL, gcvTRUE)); + + /* Next record in the queue. */ + next = record->next; + + /* Unmap record from kernel memory. */ + gcmkONERROR( + gckOS_UnmapUserPointer(Event->os, + Queue, + gcmSIZEOF(gcsQUEUE), + (gctPOINTER *) record)); + record = gcvNULL; + + Queue = next; + } + + /* Submit the event list. */ + gcmkONERROR(gckEVENT_Submit(Event, gcvTRUE)); + + /* Success */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (record != gcvNULL) + { + gcmkVERIFY_OK(gckOS_UnmapUserPointer(Event->os, + Queue, + gcmSIZEOF(gcsQUEUE), + (gctPOINTER *) record)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckEVENT_Interrupt( + IN gckEVENT Event, + IN gctUINT32 Data + ) +{ + gcmkHEADER_ARG("Event=0x%x Data=%08x", Event, Data); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + + /* Combine current interrupt status with pending flags. */ + Event->pending |= Data; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +gceSTATUS +gckEVENT_Notify( + IN gckEVENT Event, + IN gctUINT32 IDs + ) +{ + gceSTATUS status = gcvSTATUS_OK; + gctINT i; + gcsEVENT_QUEUE * queue; + gctUINT mask = 0; + gctBOOL acquired = gcvFALSE; +#ifdef __QNXNTO__ + gcuVIDMEM_NODE_PTR node; +#endif + gctUINT pending; + gctBOOL suspended = gcvFALSE; + gctBOOL empty = gcvFALSE, idle = gcvFALSE; + + gcmkHEADER_ARG("Event=0x%x", Event); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + + for (;;) + { + /* Suspend interrupts. */ + gcmkONERROR(gckOS_SuspendInterrupt(Event->os)); + suspended = gcvTRUE; + + /* Get current interrupts. */ + pending = Event->pending; + + /* Resume interrupts. */ + gcmkONERROR(gckOS_ResumeInterrupt(Event->os)); + suspended = gcvFALSE; + + if (pending == 0) + { + /* No more pending interrupts - done. */ + break; + } + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT, + "Pending interrupts 0x%08x", pending); + + queue = gcvNULL; + +#if gcdDEBUG + for (i = 0; i < gcmCOUNTOF(Event->queues); ++i) + { + if (Event->queues[i].head != gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT, + "Queue(%d): stamp=%llu source=%d", + i, + Event->queues[i].stamp, + Event->queues[i].source); + } + } +#endif + + /* Find the oldest pending interrupt. */ + for (i = 0; i < gcmCOUNTOF(Event->queues); ++i) + { + if ((Event->queues[i].head != gcvNULL) + && (pending & (1 << i)) + ) + { + if ((queue == gcvNULL) + || (Event->queues[i].stamp < queue->stamp) + ) + { + queue = &Event->queues[i]; + mask = 1 << i; + } + } + } + + if (queue == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_EVENT, + "Interrupts 0x08x are not pending.", pending); + + /* Suspend interrupts. */ + gcmkONERROR(gckOS_SuspendInterrupt(Event->os)); + suspended = gcvTRUE; + + /* Mark pending interrupts as handled. */ + Event->pending &= ~pending; + + /* Resume interrupts. */ + gcmkONERROR(gckOS_ResumeInterrupt(Event->os)); + suspended = gcvFALSE; + + break; + } + + /* Check whether there is a missed interrupt. */ + for (i = 0; i < gcmCOUNTOF(Event->queues); ++i) + { + if ((Event->queues[i].head != gcvNULL) + && (Event->queues[i].stamp < queue->stamp) + && (Event->queues[i].source == queue->source) + ) + { + gcmkTRACE(gcvLEVEL_ERROR, + "Event %d lost (stamp %llu)", + i, Event->queues[i].stamp); + + /* Use this event instead. */ + queue = &Event->queues[i]; + mask = 0; + } + } + + /* Walk all events for this interrupt. */ + while (queue->head != gcvNULL) + { + gcsEVENT_PTR event; +#ifndef __QNXNTO__ + gctPOINTER logical; +#endif + + event = queue->head; + + /* Dispatch on event type. */ + switch (event->event.command) + { + case gcvHAL_FREE_NON_PAGED_MEMORY: + /* Free non-paged memory. */ + status = gckOS_FreeNonPagedMemory( + Event->os, + event->event.u.FreeNonPagedMemory.bytes, + event->event.u.FreeNonPagedMemory.physical, + event->event.u.FreeNonPagedMemory.logical); + break; + + case gcvHAL_FREE_CONTIGUOUS_MEMORY: + /* Unmap the user memory. */ + status = gckOS_FreeContiguous( + Event->os, + event->event.u.FreeContiguousMemory.physical, + event->event.u.FreeContiguousMemory.logical, + event->event.u.FreeContiguousMemory.bytes); + break; + + case gcvHAL_FREE_VIDEO_MEMORY: +#ifdef __QNXNTO__ + node = event->event.u.FreeVideoMemory.node; + if ((node->VidMem.memory->object.type == gcvOBJ_VIDMEM) + && (node->VidMem.logical != gcvNULL) + ) + { + gcmkERR_BREAK( + gckKERNEL_UnmapVideoMemory(event->kernel, + node->VidMem.logical, + event->event.pid, + node->VidMem.bytes)); + node->VidMem.logical = gcvNULL; + } +#endif + + /* Free video memory. */ + status = gckVIDMEM_Free(event->event.u.FreeVideoMemory.node); + break; + + case gcvHAL_WRITE_DATA: +#ifndef __QNXNTO__ + /* Convert physical into logical address. */ + gcmkERR_BREAK( + gckOS_MapPhysical(Event->os, + event->event.u.WriteData.address, + gcmSIZEOF(gctUINT32), + &logical)); + + /* Write data. */ + gcmkERR_BREAK( + gckOS_WriteMemory(Event->os, + logical, + event->event.u.WriteData.data)); + + /* Unmap the physical memory. */ + gcmkERR_BREAK( + gckOS_UnmapPhysical(Event->os, + logical, + gcmSIZEOF(gctUINT32))); +#else + /* Write data. */ + gcmkERR_BREAK( + gckOS_WriteMemory(Event->os, + (gctPOINTER) + event->event.u.WriteData.address, + event->event.u.WriteData.data)); +#endif + break; + + case gcvHAL_UNLOCK_VIDEO_MEMORY: + /* Unlock. */ + status = gckVIDMEM_Unlock(event->event.u.UnlockVideoMemory.node, + event->event.u.UnlockVideoMemory.type, + gcvNULL); + break; + + case gcvHAL_SIGNAL: +#ifdef __QNXNTO__ + if ((event->event.u.Signal.coid == 0) + && (event->event.u.Signal.rcvid == 0) + ) + { + /* Kernel signal. */ + gcmkERR_BREAK( + gckOS_Signal(Event->os, + event->event.u.Signal.signal, + gcvTRUE)); + } + else + { + /* User signal. */ + gcmkERR_BREAK( + gckOS_UserSignal(Event->os, + event->event.u.Signal.signal, + event->event.u.Signal.rcvid, + event->event.u.Signal.coid)); + } +#else + /* Set signal. */ + if (event->event.u.Signal.process == gcvNULL) + { + /* Kernel signal. */ + gcmkERR_BREAK( + gckOS_Signal(Event->os, + event->event.u.Signal.signal, + gcvTRUE)); + } + else + { + /* User signal. */ + gcmkERR_BREAK( + gckOS_UserSignal(Event->os, + event->event.u.Signal.signal, + event->event.u.Signal.process)); + } + + gcmkASSERT(event->event.u.Signal.auxSignal == gcvNULL); +#endif + break; + + case gcvHAL_UNMAP_USER_MEMORY: + /* Unmap the user memory. */ + status = + gckOS_UnmapUserMemory(Event->os, + event->event.u.UnmapUserMemory.memory, + event->event.u.UnmapUserMemory.size, + event->event.u.UnmapUserMemory.info, + event->event.u.UnmapUserMemory.address); + break; + + default: + /* Invalid argument. */ + gcmkFATAL("Unknown event type: %d", event->event.command); + status = gcvSTATUS_INVALID_ARGUMENT; + break; + } + + /* Make sure there are no errors generated. */ + gcmkASSERT(gcmNO_ERROR(status)); + + /* Pop the event from the event queue. */ + gcmkONERROR( + gckOS_AcquireMutex(Event->os, Event->mutexQueue, gcvINFINITE)); + acquired = gcvTRUE; + + /* Unlink head from chain. */ + queue->head = event->next; + + gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->mutexQueue)); + acquired = gcvFALSE; + + /* Free the event. */ + gcmkVERIFY_OK(gckEVENT_FreeRecord(Event, event)); + } + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT, + "Handled interrupt 0x%08x", mask); + + /* Suspend interrupts. */ + gcmkONERROR(gckOS_SuspendInterrupt(Event->os)); + suspended = gcvTRUE; + + /* Mark pending interrupt as handled. */ + Event->pending &= ~mask; + + /* Resume interrupts. */ + gcmkONERROR(gckOS_ResumeInterrupt(Event->os)); + suspended = gcvFALSE; + } + + /* Check whether the event queue is empty. */ + gcmkONERROR(_IsEmpty(Event, &empty)); + + if (empty) + { + /* Query whether the hardware is idle. */ + gcmkONERROR(gckHARDWARE_QueryIdle(Event->kernel->hardware, &idle)); + + if (idle) + { + /* Inform the system of idle GPU. */ + gcmkONERROR(gckOS_Broadcast(Event->os, + Event->kernel->hardware, + gcvBROADCAST_GPU_IDLE)); + } + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->mutexQueue)); + } + + if (suspended) + { + /* Resume interrupts. */ + gcmkVERIFY_OK(gckOS_ResumeInterrupt(Event->os)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckEVENT_Submit( + IN gckEVENT Event, + IN gctBOOL Wait + ) +{ + gctUINT8 id = 0xFF; + gctSIZE_T bytes; + gctPOINTER buffer; + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + gctBOOL reserved = gcvFALSE; +#if gcdGPU_TIMEOUT + gctUINT32 timer = 0; +#endif + + gcmkHEADER_ARG("Event=0x%x Wait=%d", Event, Wait); + + /* Only process if we have events queued. */ + if (Event->list.head != gcvNULL) + { + for (;;) + { + /* Allocate an event ID. */ + status = _GetEvent(Event, &id, Event->list.source); + + if (gcmIS_ERROR(status)) + { + /* Out of resources? */ + if (Wait && (status == gcvSTATUS_OUT_OF_RESOURCES)) + { + /* Delay a while. */ + gcmkONERROR(gckOS_Delay(Event->os, 1)); + +#if gcdGPU_TIMEOUT + /* Increment the wait timer. */ + timer += 1; + + if (timer == gcdGPU_TIMEOUT) + { + /* Try to call any outstanding events. */ + gcmkONERROR( + gckHARDWARE_Interrupt(Event->kernel->hardware, + gcvTRUE)); + } + else if (timer > gcdGPU_TIMEOUT) + { + /* Broadcast GPU stuck. */ + gcmkONERROR(gckOS_Broadcast(Event->os, + Event->kernel->hardware, + gcvBROADCAST_GPU_STUCK)); + + /* Bail out. */ + gcmkONERROR(gcvSTATUS_GPU_NOT_RESPONDING); + } +#endif + } + else + { + gcmkONERROR(status); + } + } + else + { + /* Got en event ID. */ + break; + } + } + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_EVENT, "Using id=%d", id); + + /* Acquire the list mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Event->os, + Event->listMutex, + gcvINFINITE)); + acquired = gcvTRUE; + + /* Copy event list to event ID queue. */ + Event->queues[id].source = Event->list.source; + Event->queues[id].head = Event->list.head; + + /* Get process ID. */ + gcmkONERROR(gckOS_GetProcessID(&Event->queues[id].processID)); + + /* Mark event list as empty. */ + Event->list.head = gcvNULL; + + /* Release the list mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->listMutex)); + acquired = gcvFALSE; + +#if gcdNULL_DRIVER == 2 + /* Notify immediately on infinite hardware. */ + gcmkONERROR(gckEVENT_Interrupt(Event, 1 << id)); + + gcmkONERROR(gckEVENT_Notify(Event, 0)); +#else + /* Get the size of the hardware event. */ + gcmkONERROR(gckHARDWARE_Event(Event->kernel->hardware, + gcvNULL, + id, + gcvKERNEL_PIXEL, + &bytes)); + + /* Reserve space in the command queue. */ + gcmkONERROR(gckCOMMAND_Reserve(Event->kernel->command, + bytes, + &buffer, + &bytes)); + reserved = gcvTRUE; + + /* Set the hardware event in the command queue. */ + gcmkONERROR(gckHARDWARE_Event(Event->kernel->hardware, + buffer, + id, + Event->queues[id].source, + &bytes)); + + /* Execute the hardware event. */ + gcmkONERROR(gckCOMMAND_Execute(Event->kernel->command, bytes)); + reserved = gcvFALSE; +#endif + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Need to unroll the mutex acquire. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->listMutex)); + } + + if (reserved) + { + /* Need to release the command buffer. */ + gcmkVERIFY_OK(gckCOMMAND_Release(Event->kernel->command)); + } + + if (id != 0xFF) + { + /* Need to unroll the event allocation. */ + Event->queues[id].head = gcvNULL; + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + diff --git a/drivers/staging/rk29/vivante/hal/kernel/gc_hal_kernel_heap.c b/drivers/staging/rk29/vivante/hal/kernel/gc_hal_kernel_heap.c new file mode 100644 index 000000000000..e14e1c9c1744 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/kernel/gc_hal_kernel_heap.c @@ -0,0 +1,1056 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +/** +** @file +** gckHEAP object for kernel HAL layer. The heap implemented here is an arena- +** based memory allocation. An arena-based memory heap allocates data quickly +** from specified arenas and reduces memory fragmentation. +** +*/ +#include "gc_hal_kernel_precomp.h" + +#define _GC_OBJ_ZONE gcvZONE_HEAP + +/******************************************************************************* +***** Structures *************************************************************** +*******************************************************************************/ + +#define gcdIN_USE ((gcskNODE_PTR) ~0) + +typedef struct _gcskNODE * gcskNODE_PTR; +typedef struct _gcskNODE +{ + /* Number of byets in node. */ + gctSIZE_T bytes; + + /* Pointer to next free node, or gcvNULL to mark the node as freed, or + ** gcdIN_USE to mark the node as used. */ + gcskNODE_PTR next; + +#if gcdDEBUG + /* Time stamp of allocation. */ + gctUINT64 timeStamp; +#endif +} +gcskNODE; + +typedef struct _gcskHEAP * gcskHEAP_PTR; +typedef struct _gcskHEAP +{ + /* Linked list. */ + gcskHEAP_PTR next; + gcskHEAP_PTR prev; + + /* Heap size. */ + gctSIZE_T size; + + /* Free list. */ + gcskNODE_PTR freeList; +} +gcskHEAP; + +struct _gckHEAP +{ + /* Object. */ + gcsOBJECT object; + + /* Pointer to a gckOS object. */ + gckOS os; + + /* Locking mutex. */ + gctPOINTER mutex; + + /* Allocation parameters. */ + gctSIZE_T allocationSize; + + /* Heap list. */ + gcskHEAP_PTR heap; +#if gcdDEBUG + gctUINT64 timeStamp; +#endif + +#if VIVANTE_PROFILER || gcdDEBUG + /* Profile information. */ + gctUINT32 allocCount; + gctUINT64 allocBytes; + gctUINT64 allocBytesMax; + gctUINT64 allocBytesTotal; + gctUINT32 heapCount; + gctUINT32 heapCountMax; + gctUINT64 heapMemory; + gctUINT64 heapMemoryMax; +#endif +}; + +/******************************************************************************* +***** Static Support Functions ************************************************* +*******************************************************************************/ + +#if gcdDEBUG +static gctSIZE_T +_DumpHeap( + IN gcskHEAP_PTR Heap + ) +{ + gctPOINTER p; + gctSIZE_T leaked = 0; + + /* Start at first node. */ + for (p = Heap + 1;;) + { + /* Convert the pointer. */ + gcskNODE_PTR node = (gcskNODE_PTR) p; + + /* Check if this is a used node. */ + if (node->next == gcdIN_USE) + { + /* Print the leaking node. */ + gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_HEAP, + "Detected leaking: node=0x%x bytes=%lu timeStamp=%llu " + "(%08X %c%c%c%c)", + node, node->bytes, node->timeStamp, + ((gctUINT32_PTR) (node + 1))[0], + gcmPRINTABLE(((gctUINT8_PTR) (node + 1))[0]), + gcmPRINTABLE(((gctUINT8_PTR) (node + 1))[1]), + gcmPRINTABLE(((gctUINT8_PTR) (node + 1))[2]), + gcmPRINTABLE(((gctUINT8_PTR) (node + 1))[3])); + + /* Add leaking byte count. */ + leaked += node->bytes; + } + + /* Test for end of heap. */ + if (node->bytes == 0) + { + break; + } + + else + { + /* Move to next node. */ + p = (gctUINT8_PTR) node + node->bytes; + } + } + + /* Return the number of leaked bytes. */ + return leaked; +} +#endif + +static gceSTATUS +_CompactKernelHeap( + IN gckHEAP Heap + ) +{ + gcskHEAP_PTR heap, next; + gctPOINTER p; + gcskHEAP_PTR freeList = gcvNULL; + + gcmkHEADER_ARG("Heap=0x%x", Heap); + + /* Walk all the heaps. */ + for (heap = Heap->heap; heap != gcvNULL; heap = next) + { + gcskNODE_PTR lastFree = gcvNULL; + + /* Zero out the free list. */ + heap->freeList = gcvNULL; + + /* Start at the first node. */ + for (p = (gctUINT8_PTR) (heap + 1);;) + { + /* Convert the pointer. */ + gcskNODE_PTR node = (gcskNODE_PTR) p; + + gcmkASSERT(p <= (gctPOINTER) ((gctUINT8_PTR) (heap + 1) + heap->size)); + + /* Test if this node not used. */ + if (node->next != gcdIN_USE) + { + /* Test if this is the end of the heap. */ + if (node->bytes == 0) + { + break; + } + + /* Test of this is the first free node. */ + else if (lastFree == gcvNULL) + { + /* Initialzie the free list. */ + heap->freeList = node; + lastFree = node; + } + + else + { + /* Test if this free node is contiguous with the previous + ** free node. */ + if ((gctUINT8_PTR) lastFree + lastFree->bytes == p) + { + /* Just increase the size of the previous free node. */ + lastFree->bytes += node->bytes; + } + else + { + /* Add to linked list. */ + lastFree->next = node; + lastFree = node; + } + } + } + + /* Move to next node. */ + p = (gctUINT8_PTR) node + node->bytes; + } + + /* Mark the end of the chain. */ + if (lastFree != gcvNULL) + { + lastFree->next = gcvNULL; + } + + /* Get next heap. */ + next = heap->next; + + /* Check if the entire heap is free. */ + if ((heap->freeList != gcvNULL) + && (heap->freeList->bytes == heap->size - gcmSIZEOF(gcskNODE)) + ) + { + /* Remove the heap from the linked list. */ + if (heap->prev == gcvNULL) + { + Heap->heap = next; + } + else + { + heap->prev->next = next; + } + + if (heap->next != gcvNULL) + { + heap->next->prev = heap->prev; + } + +#if VIVANTE_PROFILER || gcdDEBUG + /* Update profiling. */ + Heap->heapCount -= 1; + Heap->heapMemory -= heap->size + gcmSIZEOF(gcskHEAP); +#endif + + /* Add this heap to the list of heaps that need to be freed. */ + heap->next = freeList; + freeList = heap; + } + } + + if (freeList != gcvNULL) + { + /* Release the mutex, remove any chance for a dead lock. */ + gcmkVERIFY_OK( + gckOS_ReleaseMutex(Heap->os, Heap->mutex)); + + /* Free all heaps in the free list. */ + for (heap = freeList; heap != gcvNULL; heap = next) + { + /* Get pointer to the next heap. */ + next = heap->next; + + /* Free the heap. */ + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HEAP, + "Freeing heap 0x%x (%lu bytes)", + heap, heap->size + gcmSIZEOF(gcskHEAP)); + gcmkVERIFY_OK(gckOS_FreeMemory(Heap->os, heap)); + } + + /* Acquire the mutex again. */ + gcmkVERIFY_OK( + gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE)); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +***** gckHEAP API Code ********************************************************* +*******************************************************************************/ + +/******************************************************************************* +** +** gckHEAP_Construct +** +** Construct a new gckHEAP object. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctSIZE_T AllocationSize +** Minimum size per arena. +** +** OUTPUT: +** +** gckHEAP * Heap +** Pointer to a variable that will hold the pointer to the gckHEAP +** object. +*/ +gceSTATUS +gckHEAP_Construct( + IN gckOS Os, + IN gctSIZE_T AllocationSize, + OUT gckHEAP * Heap + ) +{ + gceSTATUS status; + gckHEAP heap = gcvNULL; + + gcmkHEADER_ARG("Os=0x%x AllocationSize=%lu", Os, AllocationSize); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Heap != gcvNULL); + + /* Allocate the gckHEAP object. */ + gcmkONERROR( + gckOS_AllocateMemory(Os, + gcmSIZEOF(struct _gckHEAP), + (gctPOINTER *) &heap)); + + /* Initialize the gckHEAP object. */ + heap->object.type = gcvOBJ_HEAP; + heap->os = Os; + heap->allocationSize = AllocationSize; + heap->heap = gcvNULL; +#if gcdDEBUG + heap->timeStamp = 0; +#endif + +#if VIVANTE_PROFILER || gcdDEBUG + /* Zero the counters. */ + heap->allocCount = 0; + heap->allocBytes = 0; + heap->allocBytesMax = 0; + heap->allocBytesTotal = 0; + heap->heapCount = 0; + heap->heapCountMax = 0; + heap->heapMemory = 0; + heap->heapMemoryMax = 0; +#endif + + /* Create the mutex. */ + gcmkONERROR(gckOS_CreateMutex(Os, &heap->mutex)); + + /* Return the pointer to the gckHEAP object. */ + *Heap = heap; + + /* Success. */ + gcmkFOOTER_ARG("*Heap=0x%x", Heap); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (heap != gcvNULL) + { + /* Free the heap structure. */ + gcmkVERIFY_OK(gckOS_FreeMemory(Os, heap)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHEAP_Destroy +** +** Destroy a gckHEAP object. +** +** INPUT: +** +** gckHEAP Heap +** Pointer to a gckHEAP object to destroy. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHEAP_Destroy( + IN gckHEAP Heap + ) +{ + gcskHEAP_PTR heap; +#if gcdDEBUG + gctSIZE_T leaked = 0; +#endif + + gcmkHEADER_ARG("Heap=0x%x", Heap); + + for (heap = Heap->heap; heap != gcvNULL; heap = Heap->heap) + { + /* Unlink heap from linked list. */ + Heap->heap = heap->next; + +#if gcdDEBUG + /* Check for leaked memory. */ + leaked += _DumpHeap(heap); +#endif + + /* Free the heap. */ + gcmkVERIFY_OK(gckOS_FreeMemory(Heap->os, heap)); + } + + /* Free the mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Heap->os, Heap->mutex)); + + /* Free the heap structure. */ + gcmkVERIFY_OK(gckOS_FreeMemory(Heap->os, Heap)); + + /* Success. */ +#if gcdDEBUG + gcmkFOOTER_ARG("leaked=%lu", leaked); +#else + gcmkFOOTER_NO(); +#endif + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHEAP_Allocate +** +** Allocate data from the heap. +** +** INPUT: +** +** gckHEAP Heap +** Pointer to a gckHEAP object. +** +** IN gctSIZE_T Bytes +** Number of byte to allocate. +** +** OUTPUT: +** +** gctPOINTER * Memory +** Pointer to a variable that will hold the address of the allocated +** memory. +*/ +gceSTATUS +gckHEAP_Allocate( + IN gckHEAP Heap, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ) +{ + gctBOOL acquired = gcvFALSE; + gcskHEAP_PTR heap; + gceSTATUS status; + gctSIZE_T bytes; + gcskNODE_PTR node, used, prevFree = gcvNULL; + gctPOINTER memory = gcvNULL; + + gcmkHEADER_ARG("Heap=0x%x Bytes=%lu", Heap, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Memory != gcvNULL); + + /* Determine number of bytes required for a node. */ + bytes = gcmALIGN(Bytes + gcmSIZEOF(gcskNODE), 8); + + /* Acquire the mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE)); + + acquired = gcvTRUE; + + /* Check if this allocation is bigger than the default allocation size. */ + if (bytes > Heap->allocationSize - gcmSIZEOF(gcskHEAP)) + { + /* Adjust allocation size. */ + Heap->allocationSize = bytes * 2; + } + + else if (Heap->heap != gcvNULL) + { + gctINT i; + + /* 2 retries, since we might need to compact. */ + for (i = 0; i < 2; ++i) + { + /* Walk all the heaps. */ + for (heap = Heap->heap; heap != gcvNULL; heap = heap->next) + { + /* Check if this heap has enough bytes to hold the request. */ + if (bytes < heap->size) + { + prevFree = gcvNULL; + + /* Walk the chain of free nodes. */ + for (node = heap->freeList; + node != gcvNULL; + node = node->next + ) + { + gcmkASSERT(node->next != gcdIN_USE); + + /* Check if this free node has enough bytes. */ + if (node->bytes >= bytes) + { + /* Use the node. */ + goto UseNode; + } + + /* Save current free node for linked list management. */ + prevFree = node; + } + } + } + + if (i == 0) + { + /* Compact the heap. */ + gcmkVERIFY_OK(_CompactKernelHeap(Heap)); + +#if gcdDEBUG + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "===== KERNEL HEAP ====="); + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "Number of allocations : %12u", + Heap->allocCount); + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "Number of bytes allocated : %12llu", + Heap->allocBytes); + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "Maximum allocation size : %12llu", + Heap->allocBytesMax); + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "Total number of bytes allocated : %12llu", + Heap->allocBytesTotal); + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "Number of heaps : %12u", + Heap->heapCount); + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "Heap memory in bytes : %12llu", + Heap->heapMemory); + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "Maximum number of heaps : %12u", + Heap->heapCountMax); + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "Maximum heap memory in bytes : %12llu", + Heap->heapMemoryMax); +#endif + } + } + } + + /* Release the mutex. */ + gcmkONERROR( + gckOS_ReleaseMutex(Heap->os, Heap->mutex)); + + acquired = gcvFALSE; + + /* Allocate a new heap. */ + gcmkONERROR( + gckOS_AllocateMemory(Heap->os, + Heap->allocationSize, + &memory)); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HEAP, + "Allocated heap 0x%x (%lu bytes)", + memory, Heap->allocationSize); + + /* Acquire the mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE)); + + acquired = gcvTRUE; + + /* Use the allocated memory as the heap. */ + heap = (gcskHEAP_PTR) memory; + + /* Insert this heap to the head of the chain. */ + heap->next = Heap->heap; + heap->prev = gcvNULL; + heap->size = Heap->allocationSize - gcmSIZEOF(gcskHEAP); + + if (heap->next != gcvNULL) + { + heap->next->prev = heap; + } + Heap->heap = heap; + + /* Mark the end of the heap. */ + node = (gcskNODE_PTR) ( (gctUINT8_PTR) heap + + Heap->allocationSize + - gcmSIZEOF(gcskNODE) + ); + node->bytes = 0; + node->next = gcvNULL; + + /* Create a free list. */ + node = (gcskNODE_PTR) (heap + 1); + heap->freeList = node; + + /* Initialize the free list. */ + node->bytes = heap->size - gcmSIZEOF(gcskNODE); + node->next = gcvNULL; + + /* No previous free. */ + prevFree = gcvNULL; + +#if VIVANTE_PROFILER || gcdDEBUG + /* Update profiling. */ + Heap->heapCount += 1; + Heap->heapMemory += Heap->allocationSize; + + if (Heap->heapCount > Heap->heapCountMax) + { + Heap->heapCountMax = Heap->heapCount; + } + if (Heap->heapMemory > Heap->heapMemoryMax) + { + Heap->heapMemoryMax = Heap->heapMemory; + } +#endif + +UseNode: + /* Verify some stuff. */ + gcmkASSERT(heap != gcvNULL); + gcmkASSERT(node != gcvNULL); + gcmkASSERT(node->bytes >= bytes); + + if (heap->prev != gcvNULL) + { + /* Unlink the heap from the linked list. */ + heap->prev->next = heap->next; + if (heap->next != gcvNULL) + { + heap->next->prev = heap->prev; + } + + /* Move the heap to the front of the list. */ + heap->next = Heap->heap; + heap->prev = gcvNULL; + Heap->heap = heap; + heap->next->prev = heap; + } + + /* Check if there is enough free space left after usage for another free + ** node. */ + if (node->bytes - bytes >= gcmSIZEOF(gcskNODE)) + { + /* Allocated used space from the back of the free list. */ + used = (gcskNODE_PTR) ((gctUINT8_PTR) node + node->bytes - bytes); + + /* Adjust the number of free bytes. */ + node->bytes -= bytes; + gcmkASSERT(node->bytes >= gcmSIZEOF(gcskNODE)); + } + else + { + /* Remove this free list from the chain. */ + if (prevFree == gcvNULL) + { + heap->freeList = node->next; + } + else + { + prevFree->next = node->next; + } + + /* Consume the entire free node. */ + used = (gcskNODE_PTR) node; + bytes = node->bytes; + } + + /* Mark node as used. */ + used->bytes = bytes; + used->next = gcdIN_USE; +#if gcdDEBUG + used->timeStamp = ++Heap->timeStamp; +#endif + +#if VIVANTE_PROFILER || gcdDEBUG + /* Update profile counters. */ + Heap->allocCount += 1; + Heap->allocBytes += bytes; + Heap->allocBytesMax = gcmMAX(Heap->allocBytes, Heap->allocBytesMax); + Heap->allocBytesTotal += bytes; +#endif + + /* Release the mutex. */ + gcmkVERIFY_OK( + gckOS_ReleaseMutex(Heap->os, Heap->mutex)); + + /* Return pointer to memory. */ + *Memory = used + 1; + + /* Success. */ + gcmkFOOTER_ARG("*Memory=0x%x", *Memory); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkVERIFY_OK( + gckOS_ReleaseMutex(Heap->os, Heap->mutex)); + } + + if (memory != gcvNULL) + { + /* Free the heap memory. */ + gckOS_FreeMemory(Heap->os, memory); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHEAP_Free +** +** Free allocated memory from the heap. +** +** INPUT: +** +** gckHEAP Heap +** Pointer to a gckHEAP object. +** +** IN gctPOINTER Memory +** Pointer to memory to free. +** +** OUTPUT: +** +** NOTHING. +*/ +gceSTATUS +gckHEAP_Free( + IN gckHEAP Heap, + IN gctPOINTER Memory + ) +{ + gcskNODE_PTR node; + gceSTATUS status; + + gcmkHEADER_ARG("Heap=0x%x Memory=0x%x", Heap, Memory); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP); + gcmkVERIFY_ARGUMENT(Memory != gcvNULL); + + /* Acquire the mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE)); + + /* Pointer to structure. */ + node = (gcskNODE_PTR) Memory - 1; + + /* Mark the node as freed. */ + node->next = gcvNULL; + +#if VIVANTE_PROFILER || gcdDEBUG + /* Update profile counters. */ + Heap->allocBytes -= node->bytes; +#endif + + /* Release the mutex. */ + gcmkVERIFY_OK( + gckOS_ReleaseMutex(Heap->os, Heap->mutex)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +#if VIVANTE_PROFILER +gceSTATUS +gckHEAP_ProfileStart( + IN gckHEAP Heap + ) +{ + gcmkHEADER_ARG("Heap=0x%x", Heap); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP); + + /* Zero the counters. */ + Heap->allocCount = 0; + Heap->allocBytes = 0; + Heap->allocBytesMax = 0; + Heap->allocBytesTotal = 0; + Heap->heapCount = 0; + Heap->heapCountMax = 0; + Heap->heapMemory = 0; + Heap->heapMemoryMax = 0; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +gceSTATUS +gckHEAP_ProfileEnd( + IN gckHEAP Heap, + IN gctCONST_STRING Title + ) +{ + gcmkHEADER_ARG("Heap=0x%x Title=0x%x", Heap, Title); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP); + gcmkVERIFY_ARGUMENT(Title != gcvNULL); + + gcmkPRINT(""); + gcmkPRINT("=====[ HEAP - %s ]=====", Title); + gcmkPRINT("Number of allocations : %12u", Heap->allocCount); + gcmkPRINT("Number of bytes allocated : %12llu", Heap->allocBytes); + gcmkPRINT("Maximum allocation size : %12llu", Heap->allocBytesMax); + gcmkPRINT("Total number of bytes allocated : %12llu", Heap->allocBytesTotal); + gcmkPRINT("Number of heaps : %12u", Heap->heapCount); + gcmkPRINT("Heap memory in bytes : %12llu", Heap->heapMemory); + gcmkPRINT("Maximum number of heaps : %12u", Heap->heapCountMax); + gcmkPRINT("Maximum heap memory in bytes : %12llu", Heap->heapMemoryMax); + gcmkPRINT("=============================================="); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} +#endif /* VIVANTE_PROFILER */ + +/******************************************************************************* +***** Test Code **************************************************************** +*******************************************************************************/ + +#if defined gcdHAL_TEST + +#include +#define gcmRANDOM(n) (rand() % n) + +typedef struct +{ + gctSIZE_T bytes; + gctPOINTER memory; +} +gcskHEAP_TEST; + +gceSTATUS +gckHEAP_Test( + IN gckHEAP Heap, + IN gctSIZE_T Vectors, + IN gctSIZE_T MaxSize + ) +{ + gctSIZE_T nodeCount = MaxSize / 4; + gcskHEAP_TEST * nodes = gcvNULL; + gctSIZE_T bytes, index, i; + gceSTATUS status, failure = gcvSTATUS_OK; + gctUINT8_PTR memory; + gcskHEAP_PTR heap, current; + + /* Allocate the node array. */ + gcmkONERROR( + gckOS_AllocateMemory(Heap->os, + nodeCount * gcmSIZEOF(gcskHEAP_TEST), + (gctPOINTER *) &nodes)); + + /* Mark all nodes as free. */ + gcmkONERROR( + gckOS_ZeroMemory(nodes, nodeCount * gcmSIZEOF(gcskHEAP_TEST))); + + gcmkONERROR(gckHEAP_ProfileStart(Heap)); + + /* Loop through all vectors. */ + while (Vectors-- > 0) + { + /* Get a random index. */ + index = gcmRANDOM(nodeCount); + + /* Test if we need to allocate pages. */ + if (nodes[index].bytes == 0) + { + /* Generate a random byte size. */ + do + { + bytes = gcmALIGN(gcmRANDOM(MaxSize), gcmSIZEOF(gctSIZE_T)); + } + while (bytes == 0); + + /* Allocate pages. */ + status = gckHEAP_Allocate(Heap, bytes, (gctPOINTER *) &memory); + + if (gcmIS_SUCCESS(status)) + { + /* Mark node as allocated. */ + nodes[index].bytes = bytes; + nodes[index].memory = memory; + + /* Put signature in the memory. */ + for (i = 0; i < bytes; i += gcmSIZEOF(gctSIZE_T)) + { + *(gctSIZE_T_PTR) (memory + i) = index; + } + } + else + { + gcmkTRACE(gcvLEVEL_WARNING, + "%s(%d): Failed to allocate %lu bytes", + __FUNCTION__, __LINE__, bytes); + } + } + else + { + /* Verify the memory. */ + memory = nodes[index].memory; + for (i = 0; i < nodes[index].bytes; i += gcmSIZEOF(gctSIZE_T)) + { + if (*(gctSIZE_T_PTR) (memory + i) != index) + { + gcmkFATAL("%s(%d): Corruption detected at index %lu", + __FUNCTION__, __LINE__, index); + + failure = gcvSTATUS_HEAP_CORRUPTED; + } + } + + /* Free the memory. */ + status = gckHEAP_Free(Heap, memory); + + if (gcmIS_ERROR(status)) + { + gcmkFATAL("%s(%d): Cannot free %lu bytes at 0x%x (index=%lu)", + __FUNCTION__, __LINE__, + nodes[index].bytes, memory, index); + + failure = status; + } + + /* Mark the node as free. */ + nodes[index].bytes = 0; + } + + /* Verify the heap chain. */ + i = 0; + for (current = Heap->heap; current != gcvNULL; current = current->next) + { + gctSIZE_T j; + for (heap = Heap->heap, j = 0; j < i; heap = heap->next, ++j) + { + if (heap == current) + { + gcmkFATAL("%s(%d): Linked list corrupted for heap 0x%x", + __FUNCTION__, __LINE__, current); + + failure = gcvSTATUS_HEAP_CORRUPTED; + } + } + + if (heap != current) + { + gcmkFATAL("%s(%d): Linked list corrupted for heap 0x%x", + __FUNCTION__, __LINE__, current); + + failure = gcvSTATUS_HEAP_CORRUPTED; + } + + ++i; + } + } + + /* Walk the entire array of nodes. */ + for (index = 0; index < nodeCount; ++index) + { + /* Test if we need to free pages. */ + if (nodes[index].bytes != 0) + { + /* Verify the memory. */ + memory = nodes[index].memory; + for (i = 0; i < nodes[index].bytes; i += gcmSIZEOF(gctSIZE_T)) + { + if (*(gctSIZE_T_PTR) (memory + i) != index) + { + gcmkFATAL("%s(%d): Corruption detected at page %lu", + __FUNCTION__, __LINE__, index); + + failure = gcvSTATUS_HEAP_CORRUPTED; + } + } + + /* Free the memory. */ + status = gckHEAP_Free(Heap, memory); + + if (gcmIS_ERROR(status)) + { + gcmkFATAL("%s(%d): Cannot free %u bytes at 0x%x (index=%lu)", + __FUNCTION__, __LINE__, + nodes[index].bytes, memory, index); + + failure = status; + } + } + } + + /* Perform garbage collection. */ + gcmkONERROR(_CompactKernelHeap(Heap)); + + /* Show profiling. */ + gcmkONERROR(gckHEAP_ProfileEnd(Heap, "Profile")); + + /* Verify we did not loose any nodes. */ + if (Heap->heap != gcvNULL) + { + gcmkFATAL("%s(%d): Detected leaking in the heap.", + __FUNCTION__, __LINE__); + + failure = gcvSTATUS_HEAP_CORRUPTED; + } + +OnError: + /* Roll back. */ + if (nodes != gcvNULL) + { + gcmkVERIFY_OK( + gckOS_FreeMemory(Heap->os, nodes)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} +#endif + diff --git a/drivers/staging/rk29/vivante/hal/kernel/gc_hal_kernel_mmu.c b/drivers/staging/rk29/vivante/hal/kernel/gc_hal_kernel_mmu.c new file mode 100644 index 000000000000..ed77149566d7 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/kernel/gc_hal_kernel_mmu.c @@ -0,0 +1,928 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_precomp.h" + +#define _GC_OBJ_ZONE gcvZONE_MMU + +typedef enum _gceMMU_TYPE +{ + gcvMMU_USED = 0, + gcvMMU_SINGLE, + gcvMMU_FREE, +} +gceMMU_TYPE; + +static gceSTATUS +_Link( + IN gckMMU Mmu, + IN gctUINT32 Index, + IN gctUINT32 Next + ) +{ + if (Index >= Mmu->pageTableEntries) + { + /* Just move heap pointer. */ + Mmu->heapList = Next; + } + else + { + /* Address page table. */ + gctUINT32_PTR pageTable = Mmu->pageTableLogical; + + /* Dispatch on node type. */ + switch (pageTable[Index] & 0xFF) + { + case gcvMMU_SINGLE: + /* Set single index. */ + pageTable[Index] = (Next << 8) | gcvMMU_SINGLE; + break; + + case gcvMMU_FREE: + /* Set index. */ + pageTable[Index + 1] = Next; + break; + + default: + gcmkFATAL("MMU table correcupted at index %u!", Index); + return gcvSTATUS_HEAP_CORRUPTED; + } + } + + /* Success. */ + return gcvSTATUS_OK; +} + +static gceSTATUS +_AddFree( + IN gckMMU Mmu, + IN gctUINT32 Index, + IN gctUINT32 Node, + IN gctUINT32 Count + ) +{ + gctUINT32_PTR pageTable = Mmu->pageTableLogical; + + if (Count == 1) + { + /* Initialize a single page node. */ + pageTable[Node] = (~0U << 8) | gcvMMU_SINGLE; + } + else + { + /* Initialize the node. */ + pageTable[Node + 0] = (Count << 8) | gcvMMU_FREE; + pageTable[Node + 1] = ~0U; + } + + /* Append the node. */ + return _Link(Mmu, Index, Node); +} + +static gceSTATUS +_Collect( + IN gckMMU Mmu + ) +{ + gctUINT32_PTR pageTable = Mmu->pageTableLogical; + gceSTATUS status; + gctUINT32 i, previous, start = 0, count = 0; + + /* Flush the MMU cache. */ + gcmkONERROR( + gckHARDWARE_FlushMMU(Mmu->hardware)); + + previous = Mmu->heapList = ~0U; + Mmu->freeNodes = gcvFALSE; + + /* Walk the entire page table. */ + for (i = 0; i < Mmu->pageTableEntries; ++i) + { + /* Dispatch based on type of page. */ + switch (pageTable[i] & 0xFF) + { + case gcvMMU_USED: + /* Used page, so close any open node. */ + if (count > 0) + { + /* Add the node. */ + gcmkONERROR(_AddFree(Mmu, previous, start, count)); + + /* Reset the node. */ + previous = start; + count = 0; + } + break; + + case gcvMMU_SINGLE: + /* Single free node. */ + if (count++ == 0) + { + /* Start a new node. */ + start = i; + } + break; + + case gcvMMU_FREE: + /* A free node. */ + if (count == 0) + { + /* Start a new node. */ + start = i; + } + + /* Advance the count. */ + count += pageTable[i] >> 8; + + /* Advance the index into the page table. */ + i += (pageTable[i] >> 8) - 1; + break; + + default: + gcmkFATAL("MMU page table correcupted at index %u!", i); + return gcvSTATUS_HEAP_CORRUPTED; + } + } + + /* See if we have an open node left. */ + if (count > 0) + { + /* Add the node to the list. */ + gcmkONERROR(_AddFree(Mmu, previous, start, count)); + } + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_MMU, + "Performed a garbage collection of the MMU heap."); + + /* Success. */ + return gcvSTATUS_OK; + +OnError: + /* Return the staus. */ + return status; +} + +/******************************************************************************* +** +** gckMMU_Construct +** +** Construct a new gckMMU object. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gctSIZE_T MmuSize +** Number of bytes for the page table. +** +** OUTPUT: +** +** gckMMU * Mmu +** Pointer to a variable that receives the gckMMU object pointer. +*/ +gceSTATUS +gckMMU_Construct( + IN gckKERNEL Kernel, + IN gctSIZE_T MmuSize, + OUT gckMMU * Mmu + ) +{ + gckOS os; + gckHARDWARE hardware; + gceSTATUS status; + gckMMU mmu = gcvNULL; + gctUINT32_PTR pageTable; + + gcmkHEADER_ARG("Kernel=0x%x MmuSize=%lu", Kernel, MmuSize); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(MmuSize > 0); + gcmkVERIFY_ARGUMENT(Mmu != gcvNULL); + + /* Extract the gckOS object pointer. */ + os = Kernel->os; + gcmkVERIFY_OBJECT(os, gcvOBJ_OS); + + /* Extract the gckHARDWARE object pointer. */ + hardware = Kernel->hardware; + gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); + + /* Allocate memory for the gckMMU object. */ + gcmkONERROR( + gckOS_Allocate(os, sizeof(struct _gckMMU), (gctPOINTER *) &mmu)); + + /* Initialize the gckMMU object. */ + mmu->object.type = gcvOBJ_MMU; + mmu->os = os; + mmu->hardware = hardware; + mmu->pageTableMutex = gcvNULL; + mmu->pageTableLogical = gcvNULL; +#ifdef __QNXNTO__ + mmu->nodeList = gcvNULL; + mmu->nodeMutex = gcvNULL; +#endif + + /* Create the page table mutex. */ + gcmkONERROR(gckOS_CreateMutex(os, &mmu->pageTableMutex)); + +#ifdef __QNXNTO__ + /* Create the node list mutex. */ + gcmkONERROR(gckOS_CreateMutex(os, &mmu->nodeMutex)); +#endif + + /* Allocate the page table (not more than 256 kB). */ + mmu->pageTableSize = gcmMIN(MmuSize, 256 << 10); + gcmkONERROR( + gckOS_AllocateContiguous(os, + gcvFALSE, + &mmu->pageTableSize, + &mmu->pageTablePhysical, + (gctPOINTER *) &mmu->pageTableLogical)); + + /* Compute number of entries in page table. */ + mmu->pageTableEntries = mmu->pageTableSize / sizeof(gctUINT32); + + /* Mark all pages as free. */ + pageTable = mmu->pageTableLogical; + pageTable[0] = (mmu->pageTableEntries << 8) | gcvMMU_FREE; + pageTable[1] = ~0U; + mmu->heapList = 0; + mmu->freeNodes = gcvFALSE; + + /* Set page table address. */ + gcmkONERROR( + gckHARDWARE_SetMMU(hardware, (gctPOINTER) mmu->pageTableLogical)); + + /* Return the gckMMU object pointer. */ + *Mmu = mmu; + + /* Success. */ + gcmkFOOTER_ARG("*Mmu=0x%x", *Mmu); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (mmu != gcvNULL) + { + if (mmu->pageTableLogical != gcvNULL) + { + /* Free the page table. */ + gcmkVERIFY_OK( + gckOS_FreeContiguous(os, + mmu->pageTablePhysical, + (gctPOINTER) mmu->pageTableLogical, + mmu->pageTableSize)); + } + + if (mmu->pageTableMutex != gcvNULL) + { + /* Delete the mutex. */ + gcmkVERIFY_OK( + gckOS_DeleteMutex(os, mmu->pageTableMutex)); + } + +#ifdef __QNXNTO__ + if (mmu->nodeMutex != gcvNULL) + { + /* Delete the mutex. */ + gcmkVERIFY_OK( + gckOS_DeleteMutex(os, mmu->nodeMutex)); + } +#endif + + /* Mark the gckMMU object as unknown. */ + mmu->object.type = gcvOBJ_UNKNOWN; + + /* Free the allocates memory. */ + gcmkVERIFY_OK(gckOS_Free(os, mmu)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckMMU_Destroy +** +** Destroy a gckMMU object. +** +** INPUT: +** +** gckMMU Mmu +** Pointer to an gckMMU object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckMMU_Destroy( + IN gckMMU Mmu + ) +{ +#ifdef __QNXNTO__ + gcuVIDMEM_NODE_PTR node, next; +#endif + + gcmkHEADER_ARG("Mmu=0x%x", Mmu); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); + +#ifdef __QNXNTO__ + /* Free all associated virtual memory. */ + for (node = Mmu->nodeList; node != gcvNULL; node = next) + { + next = node->Virtual.next; + gcmkVERIFY_OK(gckVIDMEM_Free(node, gcvNULL)); + } +#endif + + /* Free the page table. */ + gcmkVERIFY_OK( + gckOS_FreeContiguous(Mmu->os, + Mmu->pageTablePhysical, + (gctPOINTER) Mmu->pageTableLogical, + Mmu->pageTableSize)); + +#ifdef __QNXNTO__ + /* Delete the node list mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Mmu->os, Mmu->nodeMutex)); +#endif + + /* Delete the page table mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Mmu->os, Mmu->pageTableMutex)); + + /* Mark the gckMMU object as unknown. */ + Mmu->object.type = gcvOBJ_UNKNOWN; + + /* Free the gckMMU object. */ + gcmkVERIFY_OK(gckOS_Free(Mmu->os, Mmu)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckMMU_AllocatePages +** +** Allocate pages inside the page table. +** +** INPUT: +** +** gckMMU Mmu +** Pointer to an gckMMU object. +** +** gctSIZE_T PageCount +** Number of pages to allocate. +** +** OUTPUT: +** +** gctPOINTER * PageTable +** Pointer to a variable that receives the base address of the page +** table. +** +** gctUINT32 * Address +** Pointer to a variable that receives the hardware specific address. +*/ +gceSTATUS +gckMMU_AllocatePages( + IN gckMMU Mmu, + IN gctSIZE_T PageCount, + OUT gctPOINTER * PageTable, + OUT gctUINT32 * Address + ) +{ + gceSTATUS status; + gctBOOL mutex = gcvFALSE; + gctUINT32 index = 0, previous = ~0U, left; + gctUINT32_PTR pageTable; + gctBOOL gotIt; + gctUINT32 address; + + gcmkHEADER_ARG("Mmu=0x%x PageCount=%lu", Mmu, PageCount); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); + gcmkVERIFY_ARGUMENT(PageCount > 0); + gcmkVERIFY_ARGUMENT(PageTable != gcvNULL); + + if (PageCount > Mmu->pageTableEntries) + { + /* Not enough pages avaiable. */ + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } + + /* Grab the mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE)); + mutex = gcvTRUE; + + /* Cast pointer to page table. */ + for (pageTable = Mmu->pageTableLogical, gotIt = gcvFALSE; !gotIt;) + { + /* Walk the heap list. */ + for (index = Mmu->heapList; !gotIt && (index < Mmu->pageTableEntries);) + { + /* Check the node type. */ + switch (pageTable[index] & 0xFF) + { + case gcvMMU_SINGLE: + /* Single odes are valid if we only need 1 page. */ + if (PageCount == 1) + { + gotIt = gcvTRUE; + } + else + { + /* Move to next node. */ + previous = index; + index = pageTable[index] >> 8; + } + break; + + case gcvMMU_FREE: + /* Test if the node has enough space. */ + if (PageCount <= (pageTable[index] >> 8)) + { + gotIt = gcvTRUE; + } + else + { + /* Move to next node. */ + previous = index; + index = pageTable[index + 1]; + } + break; + + default: + gcmkFATAL("MMU table correcupted at index %u!", index); + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } + } + + /* Test if we are out of memory. */ + if (index >= Mmu->pageTableEntries) + { + if (Mmu->freeNodes) + { + /* Time to move out the trash! */ + gcmkONERROR(_Collect(Mmu)); + } + else + { + /* Out of resources. */ + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } + } + } + + switch (pageTable[index] & 0xFF) + { + case gcvMMU_SINGLE: + /* Unlink single node from free list. */ + gcmkONERROR( + _Link(Mmu, previous, pageTable[index] >> 8)); + break; + + case gcvMMU_FREE: + /* Check how many pages will be left. */ + left = (pageTable[index] >> 8) - PageCount; + switch (left) + { + case 0: + /* The entire node is consumed, just unlink it. */ + gcmkONERROR( + _Link(Mmu, previous, pageTable[index + 1])); + break; + + case 1: + /* One page will remain. Convert the node to a single node and + ** advance the index. */ + pageTable[index] = (pageTable[index + 1] << 8) | gcvMMU_SINGLE; + index ++; + break; + + default: + /* Enough pages remain for a new node. However, we will just adjust + ** the size of the current node and advance the index. */ + pageTable[index] = (left << 8) | gcvMMU_FREE; + index += left; + break; + } + break; + } + + /* Mark node as used. */ + pageTable[index] = gcvMMU_USED; + + /* Return pointer to page table. */ + *PageTable = &pageTable[index]; + + /* Build virtual address. */ + gcmkONERROR( + gckHARDWARE_BuildVirtualAddress(Mmu->hardware, index, 0, &address)); + + if (Address != gcvNULL) + { + *Address = address; + } + + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex)); + + /* Success. */ + gcmkFOOTER_ARG("*PageTable=0x%x *Address=%08x", + *PageTable, gcmOPT_VALUE(Address)); + return gcvSTATUS_OK; + +OnError: + if (mutex) + { + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckMMU_FreePages +** +** Free pages inside the page table. +** +** INPUT: +** +** gckMMU Mmu +** Pointer to an gckMMU object. +** +** gctPOINTER PageTable +** Base address of the page table to free. +** +** gctSIZE_T PageCount +** Number of pages to free. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckMMU_FreePages( + IN gckMMU Mmu, + IN gctPOINTER PageTable, + IN gctSIZE_T PageCount + ) +{ + gctUINT32_PTR pageTable; + + gcmkHEADER_ARG("Mmu=0x%x PageTable=0x%x PageCount=%lu", + Mmu, PageTable, PageCount); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); + gcmkVERIFY_ARGUMENT(PageTable != gcvNULL); + gcmkVERIFY_ARGUMENT(PageCount > 0); + + /* Convert the pointer. */ + pageTable = (gctUINT32_PTR) PageTable; + + if (PageCount == 1) + { + /* Single page node. */ + pageTable[0] = (~0U << 8) | gcvMMU_SINGLE; + } + else + { + /* Mark the node as free. */ + pageTable[0] = (PageCount << 8) | gcvMMU_FREE; + pageTable[1] = ~0U; + } + + /* We have free nodes. */ + Mmu->freeNodes = gcvTRUE; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +#ifdef __QNXNTO__ +gceSTATUS +gckMMU_InsertNode( + IN gckMMU Mmu, + IN gcuVIDMEM_NODE_PTR Node) +{ + gceSTATUS status; + gctBOOL mutex = gcvFALSE; + + gcmkHEADER_ARG("Mmu=0x%x Node=0x%x", Mmu, Node); + + gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); + + gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->nodeMutex, gcvINFINITE)); + mutex = gcvTRUE; + + Node->Virtual.next = Mmu->nodeList; + Mmu->nodeList = Node; + + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->nodeMutex)); + + gcmkFOOTER(); + return gcvSTATUS_OK; + +OnError: + if (mutex) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->nodeMutex)); + } + + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckMMU_RemoveNode( + IN gckMMU Mmu, + IN gcuVIDMEM_NODE_PTR Node) +{ + gceSTATUS status; + gctBOOL mutex = gcvFALSE; + gcuVIDMEM_NODE_PTR *iter; + + gcmkHEADER_ARG("Mmu=0x%x Node=0x%x", Mmu, Node); + + gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); + + gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->nodeMutex, gcvINFINITE)); + mutex = gcvTRUE; + + for (iter = &Mmu->nodeList; *iter; iter = &(*iter)->Virtual.next) + { + if (*iter == Node) + { + *iter = Node->Virtual.next; + break; + } + } + + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->nodeMutex)); + + gcmkFOOTER(); + return gcvSTATUS_OK; + +OnError: + if (mutex) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->nodeMutex)); + } + + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckMMU_FreeHandleMemory( + IN gckMMU Mmu, + IN gctHANDLE Handle + ) +{ + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + gcuVIDMEM_NODE_PTR curr, next; + + gcmkHEADER_ARG("Mmu=0x%x Handle=0x%x", Mmu, Handle); + + gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); + + gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->nodeMutex, gcvINFINITE)); + acquired = gcvTRUE; + + for (curr = Mmu->nodeList; curr != gcvNULL; curr = next) + { + next = curr->Virtual.next; + + if (curr->Virtual.handle == Handle) + { + while (curr->Virtual.locked > 0 || curr->Virtual.unlockPending) + { + gcmkONERROR(gckVIDMEM_Unlock(curr, gcvSURF_TYPE_UNKNOWN, gcvNULL, gcvNULL)); + } + + gcmkVERIFY_OK(gckVIDMEM_Free(curr, gcvNULL)); + } + } + + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->nodeMutex)); + + gcmkFOOTER(); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->nodeMutex)); + } + + gcmkFOOTER(); + return status; +} +#endif + +/****************************************************************************** +****************************** T E S T C O D E ****************************** +******************************************************************************/ + +#if defined gcdHAL_TEST + +#include +#define gcmRANDOM(n) (rand() % n) + +typedef struct +{ + gctSIZE_T pageCount; + gctUINT32_PTR pageTable; +} +gcsMMU_TEST; + +gceSTATUS +gckMMU_Test( + IN gckMMU Mmu, + IN gctSIZE_T Vectors, + IN gctINT MaxSize + ) +{ + const gctINT nodeCount = MaxSize / 4; + gcsMMU_TEST * nodes = gcvNULL; + gceSTATUS status, failure = gcvSTATUS_OK; + gctSIZE_T i, count; + gctUINT32_PTR pageTable; + gctINT index; + + /* Allocate the node array. */ + gcmkONERROR( + gckOS_Allocate(Mmu->os, + nodeCount * gcmSIZEOF(gcsMMU_TEST), + (gctPOINTER *) &nodes)); + + /* Mark all nodes as free. */ + gcmkONERROR( + gckOS_ZeroMemory(nodes, nodeCount * gcmSIZEOF(gcsMMU_TEST))); + + /* Loop through all vectors. */ + while (Vectors-- > 0) + { + /* Get a random index. */ + index = gcmRANDOM(nodeCount); + + /* Test if we need to allocate pages. */ + if (nodes[index].pageCount == 0) + { + /* Generate a random page count. */ + do + { + count = gcmRANDOM(MaxSize); + } + while (count == 0); + + /* Allocate pages. */ + status = gckMMU_AllocatePages(Mmu, + count, + (gctPOINTER *) &pageTable, + gcvNULL); + + if (gcmIS_SUCCESS(status)) + { + /* Mark node as allocated. */ + nodes[index].pageCount = count; + nodes[index].pageTable = pageTable; + + /* Put signature in the page table. */ + for (i = 0; i < count; ++i) + { + pageTable[i] = (index << 8) | gcvMMU_USED; + } + } + else + { + gcmkTRACE(gcvLEVEL_WARNING, + "gckMMU_Test: Failed to allocate %u pages", + count); + } + } + else + { + /* Verify the page table. */ + pageTable = nodes[index].pageTable; + for (i = 0; i < nodes[index].pageCount; ++i) + { + if (pageTable[i] != ((index << 8) | gcvMMU_USED)) + { + gcmkFATAL("gckMMU_Test: Corruption detected at page %u", + index); + + failure = gcvSTATUS_HEAP_CORRUPTED; + } + } + + /* Free the pages. */ + status = gckMMU_FreePages(Mmu, pageTable, nodes[index].pageCount); + + if (gcmIS_ERROR(status)) + { + gcmkFATAL("gckMMU_Test: Cannot free %u pages at 0x%x (index=%u)", + nodes[index].pageCount, pageTable, index); + + failure = status; + } + + /* Mark the node as free. */ + nodes[index].pageCount = 0; + } + } + + /* Walk the entire array of nodes. */ + for (index = 0; index < nodeCount; ++index) + { + /* Test if we need to free pages. */ + if (nodes[index].pageCount != 0) + { + /* Verify the page table. */ + pageTable = nodes[index].pageTable; + for (i = 0; i < nodes[index].pageCount; ++i) + { + if (pageTable[i] != ((index << 8) | gcvMMU_USED)) + { + gcmkFATAL("gckMMU_Test: Corruption detected at page %u", + index); + + failure = gcvSTATUS_HEAP_CORRUPTED; + } + } + + /* Free the pages. */ + status = gckMMU_FreePages(Mmu, pageTable, nodes[index].pageCount); + + if (gcmIS_ERROR(status)) + { + gcmkFATAL("gckMMU_Test: Cannot free %u pages at 0x%x (index=%u)", + nodes[index].pageCount, pageTable, index); + + failure = status; + } + } + } + + /* Perform garbage collection. */ + gcmkONERROR(_Collect(Mmu)); + + /* Verify we did not loose any nodes. */ + if ((Mmu->heapList != 0) + || ((Mmu->pageTableLogical[0] & 0xFF) != gcvMMU_FREE) + || (Mmu->pageTableEntries != (Mmu->pageTableLogical[0] >> 8)) + ) + { + gcmkFATAL("gckMMU_Test: Detected leaking in the page table."); + + failure = gcvSTATUS_HEAP_CORRUPTED; + } + +OnError: + /* Free the array of nodes. */ + if (nodes != gcvNULL) + { + gcmkVERIFY_OK(gckOS_Free(Mmu->os, nodes)); + } + + /* Return test status. */ + return failure; +} +#endif + diff --git a/drivers/staging/rk29/vivante/hal/kernel/gc_hal_kernel_precomp.h b/drivers/staging/rk29/vivante/hal/kernel/gc_hal_kernel_precomp.h new file mode 100644 index 000000000000..0379a7528416 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/kernel/gc_hal_kernel_precomp.h @@ -0,0 +1,32 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_kernel_precomp_h_ +#define __gc_hal_kernel_precomp_h_ + +#include "gc_hal.h" +#include "gc_hal_driver.h" +#include "gc_hal_kernel.h" + +#endif /* __gc_hal_kernel_precomp_h_ */ + diff --git a/drivers/staging/rk29/vivante/hal/kernel/gc_hal_kernel_video_memory.c b/drivers/staging/rk29/vivante/hal/kernel/gc_hal_kernel_video_memory.c new file mode 100644 index 000000000000..3adb5c6779ad --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/kernel/gc_hal_kernel_video_memory.c @@ -0,0 +1,1754 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_precomp.h" + +#define _GC_OBJ_ZONE gcvZONE_VIDMEM + +/******************************************************************************\ +******************************* Private Functions ****************************** +\******************************************************************************/ + +/******************************************************************************* +** +** _Split +** +** Split a node on the required byte boundary. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gcuVIDMEM_NODE_PTR Node +** Pointer to the node to split. +** +** gctSIZE_T Bytes +** Number of bytes to keep in the node. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** gctBOOL +** gcvTRUE if the node was split successfully, or gcvFALSE if there is an +** error. +** +*/ +static gctBOOL +_Split( + IN gckOS Os, + IN gcuVIDMEM_NODE_PTR Node, + IN gctSIZE_T Bytes + ) +{ + gcuVIDMEM_NODE_PTR node; + + /* Make sure the byte boundary makes sense. */ + if ((Bytes <= 0) || (Bytes > Node->VidMem.bytes)) + { + return gcvFALSE; + } + + /* Allocate a new gcuVIDMEM_NODE object. */ + if (gcmIS_ERROR(gckOS_Allocate(Os, + gcmSIZEOF(gcuVIDMEM_NODE), + (gctPOINTER *) &node))) + { + /* Error. */ + return gcvFALSE; + } + + /* Initialize gcuVIDMEM_NODE structure. */ + node->VidMem.offset = Node->VidMem.offset + Bytes; + node->VidMem.bytes = Node->VidMem.bytes - Bytes; + node->VidMem.alignment = 0; + node->VidMem.locked = 0; + node->VidMem.memory = Node->VidMem.memory; + node->VidMem.pool = Node->VidMem.pool; + node->VidMem.physical = Node->VidMem.physical; +#ifdef __QNXNTO__ + node->VidMem.logical = gcvNULL; + node->VidMem.handle = 0; +#endif + + /* Insert node behind specified node. */ + node->VidMem.next = Node->VidMem.next; + node->VidMem.prev = Node; + Node->VidMem.next = node->VidMem.next->VidMem.prev = node; + + /* Insert free node behind specified node. */ + node->VidMem.nextFree = Node->VidMem.nextFree; + node->VidMem.prevFree = Node; + Node->VidMem.nextFree = node->VidMem.nextFree->VidMem.prevFree = node; + + /* Adjust size of specified node. */ + Node->VidMem.bytes = Bytes; + + /* Success. */ + return gcvTRUE; +} + +/******************************************************************************* +** +** _Merge +** +** Merge two adjacent nodes together. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gcuVIDMEM_NODE_PTR Node +** Pointer to the first of the two nodes to merge. +** +** OUTPUT: +** +** Nothing. +** +*/ +static gceSTATUS +_Merge( + IN gckOS Os, + IN gcuVIDMEM_NODE_PTR Node + ) +{ + gcuVIDMEM_NODE_PTR node; + + /* Save pointer to next node. */ + node = Node->VidMem.next; + + /* This is a good time to make sure the heap is not corrupted. */ + if (Node->VidMem.offset + Node->VidMem.bytes != node->VidMem.offset) + { + /* Corrupted heap. */ + gcmkASSERT( + Node->VidMem.offset + Node->VidMem.bytes == node->VidMem.offset); + return gcvSTATUS_HEAP_CORRUPTED; + } + + /* Adjust byte count. */ + Node->VidMem.bytes += node->VidMem.bytes; + + /* Unlink next node from linked list. */ + Node->VidMem.next = node->VidMem.next; + Node->VidMem.nextFree = node->VidMem.nextFree; + + Node->VidMem.next->VidMem.prev = + Node->VidMem.nextFree->VidMem.prevFree = Node; + + /* Free next node. */ + return gckOS_Free(Os, node); +} + +/******************************************************************************\ +******************************* gckVIDMEM API Code ****************************** +\******************************************************************************/ + +/******************************************************************************* +** +** gckVIDMEM_ConstructVirtual +** +** Construct a new gcuVIDMEM_NODE union for virtual memory. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gctSIZE_T Bytes +** Number of byte to allocate. +** +** OUTPUT: +** +** gcuVIDMEM_NODE_PTR * Node +** Pointer to a variable that receives the gcuVIDMEM_NODE union pointer. +*/ +gceSTATUS +gckVIDMEM_ConstructVirtual( + IN gckKERNEL Kernel, + IN gctBOOL Contiguous, + IN gctSIZE_T Bytes, +#ifdef __QNXNTO__ + IN gctHANDLE Handle, +#endif + OUT gcuVIDMEM_NODE_PTR * Node + ) +{ + gckOS os; + gceSTATUS status; + gcuVIDMEM_NODE_PTR node = gcvNULL; + + gcmkHEADER_ARG("Kernel=0x%x Bytes=%lu", Kernel, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Node != gcvNULL); +#ifdef __QNXNTO__ + gcmkVERIFY_ARGUMENT(Handle != gcvNULL); +#endif + + /* Extract the gckOS object pointer. */ + os = Kernel->os; + gcmkVERIFY_OBJECT(os, gcvOBJ_OS); + + /* Allocate an gcuVIDMEM_NODE union. */ + gcmkONERROR( + gckOS_Allocate(os, gcmSIZEOF(gcuVIDMEM_NODE), (gctPOINTER *) &node)); + + /* Initialize gcuVIDMEM_NODE union for virtual memory. */ + node->Virtual.kernel = Kernel; + node->Virtual.contiguous = Contiguous; + node->Virtual.locked = 0; + node->Virtual.logical = gcvNULL; + node->Virtual.pageTable = gcvNULL; + node->Virtual.mutex = gcvNULL; +#ifdef __QNXNTO__ + node->Virtual.next = gcvNULL; + node->Virtual.unlockPending = gcvFALSE; + node->Virtual.freePending = gcvFALSE; + node->Virtual.handle = Handle; +#else + node->Virtual.pending = gcvFALSE; +#endif + + /* Create the mutex. */ + gcmkONERROR( + gckOS_CreateMutex(os, &node->Virtual.mutex)); + + /* Allocate the virtual memory. */ + gcmkONERROR( + gckOS_AllocatePagedMemoryEx(os, + node->Virtual.contiguous, + node->Virtual.bytes = Bytes, + &node->Virtual.physical)); + +#ifdef __QNXNTO__ + /* Register. */ + gckMMU_InsertNode(Kernel->mmu, node); +#endif + + /* Return pointer to the gcuVIDMEM_NODE union. */ + *Node = node; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "Created virtual node 0x%x for %u bytes @ 0x%x", + node, Bytes, node->Virtual.physical); + + /* Success. */ + gcmkFOOTER_ARG("*Node=0x%x", *Node); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (node != gcvNULL) + { + if (node->Virtual.mutex != gcvNULL) + { + /* Destroy the mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(os, node->Virtual.mutex)); + } + + /* Free the structure. */ + gcmkVERIFY_OK(gckOS_Free(os, node)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckVIDMEM_DestroyVirtual +** +** Destroy an gcuVIDMEM_NODE union for virtual memory. +** +** INPUT: +** +** gcuVIDMEM_NODE_PTR Node +** Pointer to a gcuVIDMEM_NODE union. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckVIDMEM_DestroyVirtual( + IN gcuVIDMEM_NODE_PTR Node + ) +{ + gckOS os; + + gcmkHEADER_ARG("Node=0x%x", Node); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Node->Virtual.kernel, gcvOBJ_KERNEL); + + /* Extact the gckOS object pointer. */ + os = Node->Virtual.kernel->os; + gcmkVERIFY_OBJECT(os, gcvOBJ_OS); + +#ifdef __QNXNTO__ + /* Unregister. */ + gcmkVERIFY_OK( + gckMMU_RemoveNode(Node->Virtual.kernel->mmu, Node)); + + /* Free virtual memory. */ + gcmkVERIFY_OK( + gckOS_FreePagedMemory(os, + Node->Virtual.physical, + Node->Virtual.bytes)); +#endif + + /* Delete the mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(os, Node->Virtual.mutex)); + + if (Node->Virtual.pageTable != gcvNULL) + { + /* Free the pages. */ + gcmkVERIFY_OK(gckMMU_FreePages(Node->Virtual.kernel->mmu, + Node->Virtual.pageTable, + Node->Virtual.pageCount)); + } + + /* Delete the gcuVIDMEM_NODE union. */ + gcmkVERIFY_OK(gckOS_Free(os, Node)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckVIDMEM_Construct +** +** Construct a new gckVIDMEM object. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctUINT32 BaseAddress +** Base address for the video memory heap. +** +** gctSIZE_T Bytes +** Number of bytes in the video memory heap. +** +** gctSIZE_T Threshold +** Minimum number of bytes beyond am allocation before the node is +** split. Can be used as a minimum alignment requirement. +** +** gctSIZE_T BankSize +** Number of bytes per physical memory bank. Used by bank +** optimization. +** +** OUTPUT: +** +** gckVIDMEM * Memory +** Pointer to a variable that will hold the pointer to the gckVIDMEM +** object. +*/ +gceSTATUS +gckVIDMEM_Construct( + IN gckOS Os, + IN gctUINT32 BaseAddress, + IN gctSIZE_T Bytes, + IN gctSIZE_T Threshold, + IN gctSIZE_T BankSize, + OUT gckVIDMEM * Memory + ) +{ + gckVIDMEM memory = gcvNULL; + gceSTATUS status; + gcuVIDMEM_NODE_PTR node; + gctINT i, banks = 0; + + gcmkHEADER_ARG("Os=0x%x BaseAddress=%08x Bytes=%lu Threshold=%lu " + "BankSize=%lu", + Os, BaseAddress, Bytes, Threshold, BankSize); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Memory != gcvNULL); + + /* Allocate the gckVIDMEM object. */ + gcmkONERROR( + gckOS_Allocate(Os, + gcmSIZEOF(struct _gckVIDMEM), + (gctPOINTER *) &memory)); + + /* Initialize the gckVIDMEM object. */ + memory->object.type = gcvOBJ_VIDMEM; + memory->os = Os; + + /* Set video memory heap information. */ + memory->baseAddress = BaseAddress; + memory->bytes = Bytes; + memory->freeBytes = Bytes; + memory->threshold = Threshold; + memory->mutex = gcvNULL; + + BaseAddress = 0; + + /* Walk all possible banks. */ + for (i = 0; i < gcmCOUNTOF(memory->sentinel); ++i) + { + gctSIZE_T bytes; + + if (BankSize == 0) + { + /* Use all bytes for the first bank. */ + bytes = Bytes; + } + else + { + /* Compute number of bytes for this bank. */ + bytes = gcmALIGN(BaseAddress + 1, BankSize) - BaseAddress; + + if (bytes > Bytes) + { + /* Make sure we don't exceed the total number of bytes. */ + bytes = Bytes; + } + } + + if (bytes == 0) + { + /* Mark heap is not used. */ + memory->sentinel[i].VidMem.next = + memory->sentinel[i].VidMem.prev = + memory->sentinel[i].VidMem.nextFree = + memory->sentinel[i].VidMem.prevFree = gcvNULL; + continue; + } + + /* Allocate one gcuVIDMEM_NODE union. */ + gcmkONERROR( + gckOS_Allocate(Os, + gcmSIZEOF(gcuVIDMEM_NODE), + (gctPOINTER *) &node)); + + /* Initialize gcuVIDMEM_NODE union. */ + node->VidMem.memory = memory; + + node->VidMem.next = + node->VidMem.prev = + node->VidMem.nextFree = + node->VidMem.prevFree = &memory->sentinel[i]; + + node->VidMem.offset = BaseAddress; + node->VidMem.bytes = bytes; + node->VidMem.alignment = 0; + node->VidMem.physical = 0; + node->VidMem.pool = gcvPOOL_UNKNOWN; + + node->VidMem.locked = 0; + +#ifdef __QNXNTO__ + node->VidMem.logical = gcvNULL; + node->VidMem.handle = 0; +#endif + + /* Initialize the linked list of nodes. */ + memory->sentinel[i].VidMem.next = + memory->sentinel[i].VidMem.prev = + memory->sentinel[i].VidMem.nextFree = + memory->sentinel[i].VidMem.prevFree = node; + + /* Mark sentinel. */ + memory->sentinel[i].VidMem.bytes = 0; + + /* Adjust address for next bank. */ + BaseAddress += bytes; + Bytes -= bytes; + banks ++; + } + + /* Assign all the bank mappings. */ + memory->mapping[gcvSURF_RENDER_TARGET] = banks - 1; + memory->mapping[gcvSURF_BITMAP] = banks - 1; + if (banks > 1) --banks; + memory->mapping[gcvSURF_DEPTH] = banks - 1; + memory->mapping[gcvSURF_HIERARCHICAL_DEPTH] = banks - 1; + if (banks > 1) --banks; + memory->mapping[gcvSURF_TEXTURE] = banks - 1; + if (banks > 1) --banks; + memory->mapping[gcvSURF_VERTEX] = banks - 1; + if (banks > 1) --banks; + memory->mapping[gcvSURF_INDEX] = banks - 1; + if (banks > 1) --banks; + memory->mapping[gcvSURF_TILE_STATUS] = banks - 1; + if (banks > 1) --banks; + memory->mapping[gcvSURF_TYPE_UNKNOWN] = 0; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "[GALCORE] INDEX: bank %d", + memory->mapping[gcvSURF_INDEX]); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "[GALCORE] VERTEX: bank %d", + memory->mapping[gcvSURF_VERTEX]); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "[GALCORE] TEXTURE: bank %d", + memory->mapping[gcvSURF_TEXTURE]); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "[GALCORE] RENDER_TARGET: bank %d", + memory->mapping[gcvSURF_RENDER_TARGET]); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "[GALCORE] DEPTH: bank %d", + memory->mapping[gcvSURF_DEPTH]); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "[GALCORE] TILE_STATUS: bank %d", + memory->mapping[gcvSURF_TILE_STATUS]); + + /* Allocate the mutex. */ + gcmkONERROR(gckOS_CreateMutex(Os, &memory->mutex)); + + /* Return pointer to the gckVIDMEM object. */ + *Memory = memory; + + /* Success. */ + gcmkFOOTER_ARG("*Memory=0x%x", *Memory); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (memory != gcvNULL) + { + if (memory->mutex != gcvNULL) + { + /* Delete the mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Os, memory->mutex)); + } + + for (i = 0; i < banks; ++i) + { + /* Free the heap. */ + gcmkASSERT(memory->sentinel[i].VidMem.next != gcvNULL); + gcmkVERIFY_OK(gckOS_Free(Os, memory->sentinel[i].VidMem.next)); + } + + /* Free the object. */ + gcmkVERIFY_OK(gckOS_Free(Os, memory)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckVIDMEM_Destroy +** +** Destroy an gckVIDMEM object. +** +** INPUT: +** +** gckVIDMEM Memory +** Pointer to an gckVIDMEM object to destroy. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckVIDMEM_Destroy( + IN gckVIDMEM Memory + ) +{ + gcuVIDMEM_NODE_PTR node, next; + gctINT i; + + gcmkHEADER_ARG("Memory=0x%x", Memory); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM); + + /* Walk all sentinels. */ + for (i = 0; i < gcmCOUNTOF(Memory->sentinel); ++i) + { + /* Bail out of the heap is not used. */ + if (Memory->sentinel[i].VidMem.next == gcvNULL) + { + break; + } + + /* Walk all the nodes until we reach the sentinel. */ + for (node = Memory->sentinel[i].VidMem.next; + node->VidMem.bytes != 0; + node = next) + { + /* Save pointer to the next node. */ + next = node->VidMem.next; + + /* Free the node. */ + gcmkVERIFY_OK(gckOS_Free(Memory->os, node)); + } + } + + /* Free the mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Memory->os, Memory->mutex)); + + /* Mark the object as unknown. */ + Memory->object.type = gcvOBJ_UNKNOWN; + + /* Free the gckVIDMEM object. */ + gcmkVERIFY_OK(gckOS_Free(Memory->os, Memory)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckVIDMEM_Allocate +** +** Allocate rectangular memory from the gckVIDMEM object. +** +** INPUT: +** +** gckVIDMEM Memory +** Pointer to an gckVIDMEM object. +** +** gctUINT Width +** Width of rectangle to allocate. Make sure the width is properly +** aligned. +** +** gctUINT Height +** Height of rectangle to allocate. Make sure the height is properly +** aligned. +** +** gctUINT Depth +** Depth of rectangle to allocate. This equals to the number of +** rectangles to allocate contiguously (i.e., for cubic maps and volume +** textures). +** +** gctUINT BytesPerPixel +** Number of bytes per pixel. +** +** gctUINT32 Alignment +** Byte alignment for allocation. +** +** gceSURF_TYPE Type +** Type of surface to allocate (use by bank optimization). +** +** OUTPUT: +** +** gcuVIDMEM_NODE_PTR * Node +** Pointer to a variable that will hold the allocated memory node. +*/ +gceSTATUS +gckVIDMEM_Allocate( + IN gckVIDMEM Memory, + IN gctUINT Width, + IN gctUINT Height, + IN gctUINT Depth, + IN gctUINT BytesPerPixel, + IN gctUINT32 Alignment, + IN gceSURF_TYPE Type, +#ifdef __QNXNTO__ + IN gctHANDLE Handle, +#endif + OUT gcuVIDMEM_NODE_PTR * Node + ) +{ + gctSIZE_T bytes; + gceSTATUS status; + + gcmkHEADER_ARG("Memory=0x%x Width=%u Height=%u Depth=%u BytesPerPixel=%u " + "Alignment=%u Type=%d", + Memory, Width, Height, Depth, BytesPerPixel, Alignment, + Type); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM); + gcmkVERIFY_ARGUMENT(Width > 0); + gcmkVERIFY_ARGUMENT(Height > 0); + gcmkVERIFY_ARGUMENT(Depth > 0); + gcmkVERIFY_ARGUMENT(BytesPerPixel > 0); + gcmkVERIFY_ARGUMENT(Node != gcvNULL); +#ifdef __QNXNTO__ + gcmkVERIFY_ARGUMENT(Handle != gcvNULL); +#endif + + /* Compute linear size. */ + bytes = Width * Height * Depth * BytesPerPixel; + + /* Allocate through linear function. */ +#ifdef __QNXNTO__ + gcmkONERROR( + gckVIDMEM_AllocateLinear(Memory, bytes, Alignment, Type, Handle, Node)); +#else + gcmkONERROR( + gckVIDMEM_AllocateLinear(Memory, bytes, Alignment, Type, Node)); +#endif + + /* Success. */ + gcmkFOOTER_ARG("*Node=0x%x", *Node); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +static gcuVIDMEM_NODE_PTR +_FindNode( + IN gckVIDMEM Memory, + IN gctINT Bank, + IN gctSIZE_T Bytes, + IN OUT gctUINT32_PTR Alignment + ) +{ + gcuVIDMEM_NODE_PTR node; + gctUINT32 alignment; + + /* Walk all free nodes until we have one that is big enough or we have + reached the sentinel. */ + for (node = Memory->sentinel[Bank].VidMem.nextFree; + node->VidMem.bytes != 0; + node = node->VidMem.nextFree) + { + /* Compute number of bytes to skip for alignment. */ + alignment = (*Alignment == 0) + ? 0 + : (*Alignment - (node->VidMem.offset % *Alignment)); + + if (alignment == *Alignment) + { + /* Node is already aligned. */ + alignment = 0; + } + + if (node->VidMem.bytes >= Bytes + alignment) + { + /* This node is big enough. */ + *Alignment = alignment; + return node; + } + } + + /* Not enough memory. */ + return gcvNULL; +} + +/******************************************************************************* +** +** gckVIDMEM_AllocateLinear +** +** Allocate linear memory from the gckVIDMEM object. +** +** INPUT: +** +** gckVIDMEM Memory +** Pointer to an gckVIDMEM object. +** +** gctSIZE_T Bytes +** Number of bytes to allocate. +** +** gctUINT32 Alignment +** Byte alignment for allocation. +** +** gceSURF_TYPE Type +** Type of surface to allocate (use by bank optimization). +** +** OUTPUT: +** +** gcuVIDMEM_NODE_PTR * Node +** Pointer to a variable that will hold the allocated memory node. +*/ +gceSTATUS +gckVIDMEM_AllocateLinear( + IN gckVIDMEM Memory, + IN gctSIZE_T Bytes, + IN gctUINT32 Alignment, + IN gceSURF_TYPE Type, +#ifdef __QNXNTO__ + IN gctHANDLE Handle, +#endif + OUT gcuVIDMEM_NODE_PTR * Node + ) +{ + gceSTATUS status; + gcuVIDMEM_NODE_PTR node; + gctUINT32 alignment; + gctINT bank, i; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Memory=0x%x Bytes=%lu Alignment=%u Type=%d", + Memory, Bytes, Alignment, Type); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Node != gcvNULL); +#ifdef __QNXNTO__ + gcmkVERIFY_ARGUMENT(Handle != gcvNULL); +#endif + + /* Acquire the mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(Memory->os, Memory->mutex, gcvINFINITE)); + + acquired = gcvTRUE; + + if (Bytes > Memory->freeBytes) + { + /* Not enough memory. */ + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + /* Find the default bank for this surface type. */ + gcmkASSERT((gctINT) Type < gcmCOUNTOF(Memory->mapping)); + bank = Memory->mapping[Type]; + alignment = Alignment; + + /* Find a free node in the default bank. */ + node = _FindNode(Memory, bank, Bytes, &alignment); + + /* Out of memory? */ + if (node == gcvNULL) + { + /* Walk all lower banks. */ + for (i = bank - 1; i >= 0; --i) + { + /* Find a free node inside the current bank. */ + node = _FindNode(Memory, i, Bytes, &alignment); + if (node != gcvNULL) + { + break; + } + } + } + + if (node == gcvNULL) + { + /* Walk all upper banks. */ + for (i = bank + 1; i < gcmCOUNTOF(Memory->sentinel); ++i) + { + if (Memory->sentinel[i].VidMem.nextFree == gcvNULL) + { + /* Abort when we reach unused banks. */ + break; + } + + /* Find a free node inside the current bank. */ + node = _FindNode(Memory, i, Bytes, &alignment); + if (node != gcvNULL) + { + break; + } + } + } + + if (node == gcvNULL) + { + /* Out of memory. */ + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + /* Do we have an alignment? */ + if (alignment > 0) + { + /* Split the node so it is aligned. */ + if (_Split(Memory->os, node, alignment)) + { + /* Successful split, move to aligned node. */ + node = node->VidMem.next; + + /* Remove alignment. */ + alignment = 0; + } + } + + /* Do we have enough memory after the allocation to split it? */ + if (node->VidMem.bytes - Bytes > Memory->threshold) + { + /* Adjust the node size. */ + _Split(Memory->os, node, Bytes); + } + + /* Remove the node from the free list. */ + node->VidMem.prevFree->VidMem.nextFree = node->VidMem.nextFree; + node->VidMem.nextFree->VidMem.prevFree = node->VidMem.prevFree; + node->VidMem.nextFree = + node->VidMem.prevFree = gcvNULL; + + /* Fill in the information. */ + node->VidMem.alignment = alignment; + node->VidMem.memory = Memory; +#ifdef __QNXNTO__ + node->VidMem.logical = gcvNULL; + node->VidMem.handle = Handle; +#endif + + /* Adjust the number of free bytes. */ + Memory->freeBytes -= node->VidMem.bytes; + + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex)); + + /* Return the pointer to the node. */ + *Node = node; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "Allocated %u bytes @ 0x%x [0x%08X]", + node->VidMem.bytes, node, node->VidMem.offset); + + /* Success. */ + gcmkFOOTER_ARG("*Node=0x%x", *Node); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckVIDMEM_Free +** +** Free an allocated video memory node. +** +** INPUT: +** +** gcuVIDMEM_NODE_PTR Node +** Pointer to a gcuVIDMEM_NODE object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckVIDMEM_Free( + IN gcuVIDMEM_NODE_PTR Node + ) +{ + gckVIDMEM memory = gcvNULL; + gcuVIDMEM_NODE_PTR node; + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Node=0x%x", Node); + + /* Verify the arguments. */ + if ((Node == gcvNULL) + || (Node->VidMem.memory == gcvNULL) + ) + { + /* Invalid object. */ + gcmkONERROR(gcvSTATUS_INVALID_OBJECT); + } + + /**************************** Video Memory ********************************/ + + if (Node->VidMem.memory->object.type == gcvOBJ_VIDMEM) + { + if (Node->VidMem.locked > 0) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_VIDMEM, + "Node 0x%x is locked (%d)", + Node, Node->VidMem.locked); + + /* Node is locked. */ + gcmkONERROR(gcvSTATUS_MEMORY_LOCKED); + } + + /* Extract pointer to gckVIDMEM object owning the node. */ + memory = Node->VidMem.memory; + + /* Acquire the mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(memory->os, memory->mutex, gcvINFINITE)); + + acquired = gcvTRUE; + +#ifdef __QNXNTO__ + /* Reset handle to 0. */ + Node->VidMem.logical = gcvNULL; + Node->VidMem.handle = 0; + + /* Don't try to a re-free an already freed node. */ + if ((Node->VidMem.nextFree == gcvNULL) + && (Node->VidMem.prevFree == gcvNULL) + ) +#endif + { + /* Update the number of free bytes. */ + memory->freeBytes += Node->VidMem.bytes; + + /* Find the next free node. */ + for (node = Node->VidMem.next; + node->VidMem.nextFree == gcvNULL; + node = node->VidMem.next) ; + + /* Insert this node in the free list. */ + Node->VidMem.nextFree = node; + Node->VidMem.prevFree = node->VidMem.prevFree; + + Node->VidMem.prevFree->VidMem.nextFree = + node->VidMem.prevFree = Node; + + /* Is the next node a free node and not the sentinel? */ + if ((Node->VidMem.next == Node->VidMem.nextFree) + && (Node->VidMem.next->VidMem.bytes != 0) + ) + { + /* Merge this node with the next node. */ + gcmkONERROR(_Merge(memory->os, node = Node)); + gcmkASSERT(node->VidMem.nextFree != node); + gcmkASSERT(node->VidMem.prevFree != node); + } + + /* Is the previous node a free node and not the sentinel? */ + if ((Node->VidMem.prev == Node->VidMem.prevFree) + && (Node->VidMem.prev->VidMem.bytes != 0) + ) + { + /* Merge this node with the previous node. */ + gcmkONERROR(_Merge(memory->os, node = Node->VidMem.prev)); + gcmkASSERT(node->VidMem.nextFree != node); + gcmkASSERT(node->VidMem.prevFree != node); + } + } + + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(memory->os, memory->mutex)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + } + + /*************************** Virtual Memory *******************************/ + + /* Verify the gckKERNEL object pointer. */ + gcmkVERIFY_OBJECT(Node->Virtual.kernel, gcvOBJ_KERNEL); + +#ifdef __QNXNTO__ + if (!Node->Virtual.unlockPending && (Node->Virtual.locked > 0)) +#else + if (!Node->Virtual.pending && (Node->Virtual.locked > 0)) +#endif + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_VIDMEM, + "gckVIDMEM_Free: Virtual node 0x%x is locked (%d)", + Node, Node->Virtual.locked); + + /* Node is locked. */ + gcmkONERROR(gcvSTATUS_MEMORY_LOCKED); + } + +#ifdef __QNXNTO__ + if (!Node->Virtual.freePending) { if (Node->Virtual.unlockPending) +#else + if (Node->Virtual.pending) +#endif + { + gcmkASSERT(Node->Virtual.locked == 1); + + /* Schedule the node to be freed. */ + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "gckVIDMEM_Free: Scheduling node 0x%x to be freed later", + Node); + + /* Schedule the video memory to be freed again. */ + gcmkONERROR(gckEVENT_FreeVideoMemory(Node->Virtual.kernel->event, + Node, + gcvKERNEL_PIXEL)); + +#ifdef __QNXNTO__ + Node->Virtual.freePending = gcvTRUE; } +#endif + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_SKIP; + } + + else + { + /* Free the virtual memory. */ + gcmkVERIFY_OK(gckOS_FreePagedMemory(Node->Virtual.kernel->os, + Node->Virtual.physical, + Node->Virtual.bytes)); + + /* Destroy the gcuVIDMEM_NODE union. */ + gcmkVERIFY_OK(gckVIDMEM_DestroyVirtual(Node)); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(memory->os, memory->mutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + + +#ifdef __QNXNTO__ +/******************************************************************************* +** +** gcoVIDMEM_FreeHandleMemory +** +** Free all allocated video memory nodes for a handle. +** +** INPUT: +** +** gcoVIDMEM Memory +** Pointer to an gcoVIDMEM object.. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckVIDMEM_FreeHandleMemory( + IN gckVIDMEM Memory, + IN gctHANDLE Handle + ) +{ + gceSTATUS status; + gctBOOL mutex = gcvFALSE; + gcuVIDMEM_NODE_PTR node; + gctINT i; + gctUINT32 nodeCount = 0, byteCount = 0; + gctBOOL again; + + gcmkHEADER_ARG("Memory=0x%x Handle=0x%x", Memory, Handle); + + gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM); + + gcmkONERROR(gckOS_AcquireMutex(Memory->os, Memory->mutex, gcvINFINITE)); + mutex = gcvTRUE; + + /* Walk all sentinels. */ + for (i = 0; i < gcmCOUNTOF(Memory->sentinel); ++i) + { + /* Bail out of the heap if it is not used. */ + if (Memory->sentinel[i].VidMem.next == gcvNULL) + { + break; + } + + do + { + again = gcvFALSE; + + /* Walk all the nodes until we reach the sentinel. */ + for (node = Memory->sentinel[i].VidMem.next; + node->VidMem.bytes != 0; + node = node->VidMem.next) + { + /* Free the node if it was allocated by Handle. */ + if (node->VidMem.handle == Handle) + { + /* Unlock video memory. */ + while (gckVIDMEM_Unlock(node, gcvSURF_TYPE_UNKNOWN, gcvNULL, gcvNULL) + != gcvSTATUS_MEMORY_UNLOCKED) + ; + + nodeCount++; + byteCount += node->VidMem.bytes; + + /* Free video memory. */ + gcmkVERIFY_OK(gckVIDMEM_Free(node, gcvNULL)); + + /* + * Freeing may cause a merge which will invalidate our iteration. + * Don't be clever, just restart. + */ + again = gcvTRUE; + + break; + } + } + } + while (again); + } + + gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex)); + gcmkFOOTER(); + return gcvSTATUS_OK; + +OnError: + if (mutex) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex)); + } + + gcmkFOOTER(); + return status; +} +#endif + +/******************************************************************************* +** +** gckVIDMEM_Lock +** +** Lock a video memory node and return it's hardware specific address. +** +** INPUT: +** +** gcuVIDMEM_NODE_PTR Node +** Pointer to a gcuVIDMEM_NODE union. +** +** OUTPUT: +** +** gctUINT32 * Address +** Pointer to a variable that will hold the hardware specific address. +*/ +gceSTATUS +gckVIDMEM_Lock( + IN gcuVIDMEM_NODE_PTR Node, + OUT gctUINT32 * Address + ) +{ + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + gctBOOL locked = gcvFALSE; + gckOS os = gcvNULL; + + gcmkHEADER_ARG("Node=0x%x", Node); + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Address != gcvNULL); + + if ((Node == gcvNULL) + || (Node->VidMem.memory == gcvNULL) + ) + { + /* Invalid object. */ + gcmkONERROR(gcvSTATUS_INVALID_OBJECT); + } + + /**************************** Video Memory ********************************/ + + if (Node->VidMem.memory->object.type == gcvOBJ_VIDMEM) + { + /* Increment the lock count. */ + Node->VidMem.locked ++; + + /* Return the address of the node. */ + *Address = Node->VidMem.memory->baseAddress + + Node->VidMem.offset + + Node->VidMem.alignment; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "Locked node 0x%x (%d) @ 0x%08X", + Node, + Node->VidMem.locked, + *Address); + } + + /*************************** Virtual Memory *******************************/ + + else + { + /* Verify the gckKERNEL object pointer. */ + gcmkVERIFY_OBJECT(Node->Virtual.kernel, gcvOBJ_KERNEL); + + /* Extract the gckOS object pointer. */ + os = Node->Virtual.kernel->os; + gcmkVERIFY_OBJECT(os, gcvOBJ_OS); + + /* Grab the mutex. */ + gcmkONERROR(gckOS_AcquireMutex(os, Node->Virtual.mutex, gcvINFINITE)); + acquired = gcvTRUE; + + /* Increment the lock count. */ + if (Node->Virtual.locked ++ == 0) + { + /* Is this node pending for a final unlock? */ +#ifdef __QNXNTO__ + if (!Node->Virtual.contiguous && Node->Virtual.unlockPending) +#else + if (!Node->Virtual.contiguous && Node->Virtual.pending) +#endif + { + /* Make sure we have a page table. */ + gcmkASSERT(Node->Virtual.pageTable != gcvNULL); + + /* Remove pending unlock. */ +#ifdef __QNXNTO__ + Node->Virtual.unlockPending = gcvFALSE; +#else + Node->Virtual.pending = gcvFALSE; +#endif + } + + /* First lock - create a page table. */ + gcmkASSERT(Node->Virtual.pageTable == gcvNULL); + + /* Make sure we mark our node as not flushed. */ +#ifdef __QNXNTO__ + Node->Virtual.unlockPending = gcvFALSE; +#else + Node->Virtual.pending = gcvFALSE; +#endif + + /* Lock the allocated pages. */ +#ifdef __QNXNTO__ + gcmkONERROR( + gckOS_LockPages(os, + Node->Virtual.physical, + Node->Virtual.bytes, + Node->Virtual.userPID, + &Node->Virtual.logical, + &Node->Virtual.pageCount)); +#else + gcmkONERROR( + gckOS_LockPages(os, + Node->Virtual.physical, + Node->Virtual.bytes, + &Node->Virtual.logical, + &Node->Virtual.pageCount)); +#endif + + locked = gcvTRUE; + + if (Node->Virtual.contiguous) + { + /* Get physical address directly */ + gcmkONERROR(gckOS_GetPhysicalAddress(os, + Node->Virtual.logical, + &Node->Virtual.address)); + } + else + { + /* Allocate pages inside the MMU. */ + gcmkONERROR( + gckMMU_AllocatePages(Node->Virtual.kernel->mmu, + Node->Virtual.pageCount, + &Node->Virtual.pageTable, + &Node->Virtual.address)); + + /* Map the pages. */ +#ifdef __QNXNTO__ + gcmkONERROR( + gckOS_MapPages(os, + Node->Virtual.physical, + Node->Virtual.logical, + Node->Virtual.pageCount, + Node->Virtual.pageTable)); +#else + gcmkONERROR( + gckOS_MapPages(os, + Node->Virtual.physical, + Node->Virtual.pageCount, + Node->Virtual.pageTable)); +#endif + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "Mapped virtual node 0x%x to 0x%08X", + Node, + Node->Virtual.address); + } + } + + /* Return hardware address. */ + *Address = Node->Virtual.address; + + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex)); + } + + /* Success. */ + gcmkFOOTER_ARG("*Address=%08x", *Address); + return gcvSTATUS_OK; + +OnError: + if (locked) + { + if (Node->Virtual.pageTable != gcvNULL) + { + /* Free the pages from the MMU. */ + gcmkVERIFY_OK( + gckMMU_FreePages(Node->Virtual.kernel->mmu, + Node->Virtual.pageTable, + Node->Virtual.pageCount)); + + Node->Virtual.pageTable = gcvNULL; + } + + /* Unlock the pages. */ +#ifdef __QNXNTO__ + gcmkVERIFY_OK( + gckOS_UnlockPages(os, + Node->Virtual.physical, + Node->Virtual.userPID, + Node->Virtual.bytes, + Node->Virtual.logical)); +#else + gcmkVERIFY_OK( + gckOS_UnlockPages(os, + Node->Virtual.physical, + Node->Virtual.bytes, + Node->Virtual.logical)); +#endif + } + + if (acquired) + { + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckVIDMEM_Unlock +** +** Unlock a video memory node. +** +** INPUT: +** +** gcuVIDMEM_NODE_PTR Node +** Pointer to a locked gcuVIDMEM_NODE union. +** +** gceSURF_TYPE Type +** Type of surface to unlock. +** +** gctSIZE_T * CommandSize +** Pointer to a variable specifying the number of bytes in the command +** buffer specified by 'Commands'. If gcvNULL, there is no command +** buffer and the video memory shoud be unlocked synchronously. +** +** gctBOOL * Asynchroneous +** Pointer to a variable specifying whether the surface should be +** unlocked asynchroneously or not. +** +** OUTPUT: +** +** gctBOOL * Asynchroneous +** Pointer to a variable receiving the number of bytes used in the +** command buffer specified by 'Commands'. If gcvNULL, there is no +** command buffer. +*/ +gceSTATUS +gckVIDMEM_Unlock( + IN gcuVIDMEM_NODE_PTR Node, + IN gceSURF_TYPE Type, + IN OUT gctBOOL * Asynchroneous + ) +{ + gceSTATUS status; + gckKERNEL kernel; + gckHARDWARE hardware; + gctPOINTER buffer; + gctSIZE_T requested, bufferSize; + gckCOMMAND command = gcvNULL; + gceKERNEL_FLUSH flush; + gckOS os = gcvNULL; + gctBOOL acquired = gcvFALSE; + gctBOOL needRelease = gcvFALSE; + gctBOOL pendingUnlock = gcvFALSE; + + gcmkHEADER_ARG("Node=0x%x Type=%d *Asynchroneous=%d", + Node, Type, gcmOPT_VALUE(Asynchroneous)); + + /* Verify the arguments. */ + if ((Node == gcvNULL) + || (Node->VidMem.memory == gcvNULL) + ) + { + /* Invalid object. */ + gcmkONERROR(gcvSTATUS_INVALID_OBJECT); + } + + /**************************** Video Memory ********************************/ + + if (Node->VidMem.memory->object.type == gcvOBJ_VIDMEM) + { + if (Node->VidMem.locked <= 0) + { + /* The surface was not locked. */ + gcmkONERROR(gcvSTATUS_MEMORY_UNLOCKED); + } + + /* Decrement the lock count. */ + Node->VidMem.locked --; + + if (Asynchroneous != gcvNULL) + { + /* No need for any events. */ + *Asynchroneous = gcvFALSE; + } + } + + /*************************** Virtual Memory *******************************/ + + else + { + /* Verify the gckKERNEL object pointer. */ + kernel = Node->Virtual.kernel; + gcmkVERIFY_OBJECT(kernel, gcvOBJ_KERNEL); + + /* Verify the gckHARDWARE object pointer. */ + hardware = Node->Virtual.kernel->hardware; + gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); + + /* Verify the gckCOMMAND object pointer. */ + command = Node->Virtual.kernel->command; + gcmkVERIFY_OBJECT(command, gcvOBJ_COMMAND); + + if (Asynchroneous == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "gckVIDMEM_Unlock: Unlocking virtual node 0x%x (%d)", + Node, + Node->Virtual.locked); + + /* Get the gckOS object pointer. */ + os = kernel->os; + gcmkVERIFY_OBJECT(os, gcvOBJ_OS); + + /* Grab the mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(os, Node->Virtual.mutex, gcvINFINITE)); + + /* If we need to unlock a node from virtual memory we have to be + ** very carefull. If the node is still inside the caches we + ** might get a bus error later if the cache line needs to be + ** replaced. So - we have to flush the caches before we do + ** anything. We also need to stall to make sure the flush has + ** happened. However - when we get to this point we are inside + ** the interrupt handler and we cannot just gckCOMMAND_Wait + ** because it will wait forever. So - what we do here is we + ** verify the type of the surface, flush the appropriate cache, + ** mark the node as flushed, and issue another unlock to unmap + ** the MMU. */ + if (!Node->Virtual.contiguous + && (Node->Virtual.locked == 1) +#ifdef __QNXTO__ + && !Node->Virtual.unlockPending +#else + && !Node->Virtual.pending +#endif + ) + { + if (Type == gcvSURF_BITMAP) + { + /* Flush 2D cache. */ + flush = gcvFLUSH_2D; + } + else if (Type == gcvSURF_RENDER_TARGET) + { + /* Flush color cache. */ + flush = gcvFLUSH_COLOR; + } + else if (Type == gcvSURF_DEPTH) + { + /* Flush depth cache. */ + flush = gcvFLUSH_DEPTH; + } + else + { + /* No flush required. */ + flush = (gceKERNEL_FLUSH) 0; + } + + gcmkONERROR( + gckHARDWARE_Flush(hardware, flush, gcvNULL, &requested)); + + if (requested != 0) + { + gcmkONERROR( + gckCOMMAND_Reserve(command, + requested, + &buffer, + &bufferSize)); + + needRelease = gcvTRUE; + + gcmkONERROR(gckHARDWARE_Flush(hardware, + flush, + buffer, + &bufferSize)); + + gcmkONERROR( + gckEVENT_Unlock(Node->Virtual.kernel->event, + gcvKERNEL_PIXEL, + Node, + Type)); + + /* Mark node as pending. */ +#ifdef __QNXNTO__ + Node->Virtual.unlockPending = gcvTRUE; +#else + Node->Virtual.pending = gcvTRUE; +#endif + + needRelease = gcvFALSE; + + gcmkONERROR(gckCOMMAND_Execute(command, requested)); + + pendingUnlock = gcvTRUE; + } + } + + if (!pendingUnlock) + { + if (Node->Virtual.locked == 0) + { + status = gcvSTATUS_MEMORY_UNLOCKED; + goto OnError; + } + + /* Decrement lock count. */ + -- Node->Virtual.locked; + + /* See if we can unlock the resources. */ + if (Node->Virtual.locked == 0) + { + /* Unlock the pages. */ +#ifdef __QNXNTO__ + gcmkONERROR( + gckOS_UnlockPages(os, + Node->Virtual.physical, + Node->Virtual.userPID, + Node->Virtual.bytes, + Node->Virtual.logical)); +#else + gcmkONERROR( + gckOS_UnlockPages(os, + Node->Virtual.physical, + Node->Virtual.bytes, + Node->Virtual.logical)); +#endif + + /* Free the page table. */ + if (Node->Virtual.pageTable != gcvNULL) + { + gcmkONERROR( + gckMMU_FreePages(Node->Virtual.kernel->mmu, + Node->Virtual.pageTable, + Node->Virtual.pageCount)); + + /* Mark page table as freed. */ + Node->Virtual.pageTable = gcvNULL; + } + + /* Mark node as unlocked. */ +#ifdef __QNXTO + Node->Virtual.unlockPending = gcvFALSE; +#else + Node->Virtual.pending = gcvFALSE; +#endif + } + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "Unmapped virtual node 0x%x from 0x%08X", + Node, Node->Virtual.address); + } + + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex)); + } + + else + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "Scheduled unlock for virtual node 0x%x", + Node); + + /* Schedule the surface to be unlocked. */ + *Asynchroneous = gcvTRUE; + } + } + + /* Success. */ + gcmkFOOTER_ARG("*Asynchroneous=%d", gcmOPT_VALUE(Asynchroneous)); + return gcvSTATUS_OK; + +OnError: + if (needRelease) + { + gcmkVERIFY_OK(gckCOMMAND_Release(command)); + } + + if (acquired) + { + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +#ifdef __QNXNTO__ +/* Set the allocating process' PID for this node. */ +gceSTATUS +gckVIDMEM_SetPID( + IN gcuVIDMEM_NODE_PTR Node, + IN gctUINT32 Pid + ) +{ + if (Node != gcvNULL) + { + if (Node->VidMem.memory->object.type != gcvOBJ_VIDMEM) + { + Node->Virtual.userPID = Pid; + } + + } + else + { + return gcvSTATUS_INVALID_OBJECT; + } + + return gcvSTATUS_OK; +} +#endif + diff --git a/drivers/staging/rk29/vivante/hal/kernel/makefile.linux b/drivers/staging/rk29/vivante/hal/kernel/makefile.linux new file mode 100644 index 000000000000..d4dc5bbaa338 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/kernel/makefile.linux @@ -0,0 +1,59 @@ +############################################################################## +# +# Copyright (C) 2005 - 2010 by Vivante Corp. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the license, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +############################################################################## + + + +# +# Linux build file for architecture dependent kernel HAL layer. +# +# + + +################################################################################ +# Include common definitions. + +include $(AQROOT)/makefile.linux.def + +################################################################################ +# Define a shortcut for the main target. + +STATIC = 1 +TARGET_NAME = libhalkernel.a + +################################################################################ +# Supply additional include directories. + +INCLUDE += -I$(AQROOT)/hal/inc +INCLUDE += -I$(AQROOT)/hal/user +INCLUDE += -I$(AQARCH)/hal/kernel + +CFLAGS += $(INCLUDE) -Werror -ansi + +################################################################################ +# Describe object files. + +OBJECTS = $(OBJ_DIR)/gc_hal_kernel_command.o \ + $(OBJ_DIR)/gc_hal_kernel_event.o \ + $(OBJ_DIR)/gc_hal_kernel_heap.o \ + $(OBJ_DIR)/gc_hal_kernel.o \ + $(OBJ_DIR)/gc_hal_kernel_mmu.o \ + $(OBJ_DIR)/gc_hal_kernel_video_memory.o + +include $(AQROOT)/common.target diff --git a/drivers/staging/rk29/vivante/hal/makefile.linux b/drivers/staging/rk29/vivante/hal/makefile.linux new file mode 100644 index 000000000000..08596c609cfa --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/makefile.linux @@ -0,0 +1,47 @@ +############################################################################## +# +# Copyright (c) 2005 - 2010 by Vivante Corp. All rights reserved. +# +# The material in this file is confidential and contains trade secrets +# of Vivante Corporation. This is proprietary information owned by +# Vivante Corporation. No part of this work may be disclosed, +# reproduced, copied, transmitted, or used in any way for any purpose, +# without the express written permission of Vivante Corporation. +# +############################################################################## +# +# Auto-generated file on 10/12/2010. Do not edit!!! +# +############################################################################## + + + +# +# Linux build file for the user level HAL libraries. +# + + + +################################################################################ +# Define make command. + +MAKE = make --makefile=makefile.linux + + +################################################################################ +# Define build directories. + +HAL_USER_DRV_ARCH := $(AQARCH)/hal/user +ifeq ($(QNX), 1) +HAL_USER_DRV_OS := $(AQROOT)/hal/os/qnx/user +else +HAL_USER_DRV_OS := $(AQROOT)/hal/os/linux/user +endif +HAL_USER_DRV_MAIN := $(AQROOT)/hal/user + +$(HAL_USER_DRV_MAIN): $(HAL_USER_DRV_ARCH) $(HAL_USER_DRV_OS) + +MODULES := $(HAL_USER_DRV_ARCH) $(HAL_USER_DRV_OS) $(HAL_USER_DRV_MAIN) +MAIN_MODULE = $(HAL_USER_DRV_MAIN) + +include $(AQROOT)/common.node diff --git a/drivers/staging/rk29/vivante/hal/os/libGAL.def.mak b/drivers/staging/rk29/vivante/hal/os/libGAL.def.mak new file mode 100644 index 000000000000..1a5a8df0d3ce --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/os/libGAL.def.mak @@ -0,0 +1,540 @@ +############################################################################## +# +# Copyright (c) 2005 - 2010 by Vivante Corp. All rights reserved. +# +# The material in this file is confidential and contains trade secrets +# of Vivante Corporation. This is proprietary information owned by +# Vivante Corporation. No part of this work may be disclosed, +# reproduced, copied, transmitted, or used in any way for any purpose, +# without the express written permission of Vivante Corporation. +# +############################################################################## +# +# Auto-generated file on 10/12/2010. Do not edit!!! +# +############################################################################## + + +"$(DEFFILE)" : $(AQROOT)\hal\os\libGAL.def.mak + @copy << "$(DEFFILE)" +; +; !! Do not edit this file - it is automatically generated !! +; + +LIBRARY libGAL + +EXPORTS + ;gcoOS + gcoOS_SetDebugLevel + gcoOS_SetDebugZone + gcoOS_SetDebugFile + gcoOS_SetDebugZones + gcoOS_SetDebugLevelZone + gcoOS_SetDebugShaderFiles + gcoOS_DebugFatal + gcoOS_DebugTrace + gcoOS_DebugTraceZone + gcoOS_Print + gcoOS_DebugBreak + gcoOS_Verify + gcoOS_Construct + gcoOS_Destroy + gcoOS_QueryVideoMemory + gcoOS_Allocate + gcoOS_Free + gcoOS_AllocateNonPagedMemory + gcoOS_FreeNonPagedMemory + gcoOS_AllocateContiguous + gcoOS_FreeContiguous + gcoOS_CreateMutex + gcoOS_DeleteMutex + gcoOS_AcquireMutex + gcoOS_ReleaseMutex + gcoOS_CreateSignal + gcoOS_DestroySignal + gcoOS_Signal + gcoOS_WaitSignal + gcoOS_DeviceControl + gcoOS_Open + gcoOS_Close + gcoOS_Read + gcoOS_Write + gcoOS_Seek + gcoOS_SetPos + gcoOS_GetPos + gcoOS_MemCopy + gcoOS_ZeroMemory + gcoOS_MemFill + gcoOS_StrLen + gcoOS_StrFindReverse + gcoOS_StrCopySafe + gcoOS_StrCatSafe + gcoOS_StrCmp + gcoOS_StrNCmp + gcoOS_StrToFloat + gcoOS_StrToInt + gcoOS_MemCmp + gcoOS_PrintStrSafe + gcoOS_PrintStrVSafe + gcoOS_MapUserMemory + gcoOS_UnmapUserMemory + gcoOS_StrDup + gcoOS_LoadLibrary + gcoOS_FreeLibrary + gcoOS_GetProcAddress + gcoOS_Delay + gcoOS_GetCurrentProcessID + gcoOS_AtomConstruct + gcoOS_AtomDestroy + gcoOS_AtomIncrement + gcoOS_AtomDecrement + gcoOS_GetTicks + gcoOS_GetTime + gcoOS_GetCPUTime + gcoOS_GetMemoryUsage + gcoOS_GetBaseAddress + gcoOS_ReadRegister + gcoOS_WriteRegister + +!IFNDEF VIVANTE_NO_3D + ; gcsMEM + gcfMEM_InitFSMemPool + gcfMEM_FreeFSMemPool + gcfMEM_FSMemPoolGetANode + gcfMEM_FSMemPoolFreeANode + gcfMEM_FSMemPoolFreeAList + gcfMEM_InitAFSMemPool + gcfMEM_FreeAFSMemPool + gcfMEM_AFSMemPoolGetANode + gcfMEM_AFSMemPoolFreeANode +!ENDIF + + ; gcoHAL + gcoHAL_Construct + gcoHAL_Destroy + gcoHAL_IsFeatureAvailable + gcoHAL_QueryChipIdentity + gcoHAL_Call + gcoHAL_QueryVideoMemory + gcoHAL_MapMemory + gcoHAL_UnmapMemory + gcoHAL_ScheduleUnmapMemory + gcoHAL_ScheduleUnmapUserMemory + gcoHAL_Commit + gcoHAL_QueryTiled + gcoHAL_Get2DEngine + gcoHAL_Get3DEngine + gcoHAL_GetVGEngine + gcoHAL_GetDump + gcoHAL_ScheduleEvent +!IFNDEF VIVANTE_NO_3D + gcoHAL_QueryTargetCaps + gcoHAL_SetDepthOnly + gcoHAL_QueryShaderCaps + gcoHAL_QueryTextureCaps + gcoHAL_QueryStreamCaps +!ENDIF + gcoHAL_ProfileStart + gcoHAL_ProfileEnd + gcoHAL_Compact + gcoHAL_SetPowerManagementState + gcoHAL_QueryPowerManagementState + gcoHAL_DestroySurface + + ; gcoDUMP + gcoDUMP_Construct + gcoDUMP_Destroy + gcoDUMP_Control + gcoDUMP_IsEnabled + gcoDUMP_AddSurface + gcoDUMP_FrameBegin + gcoDUMP_FrameEnd + gcoDUMP_DumpData + gcoDUMP_Delete + gcfDump + + ; gcoSURF + gcoSURF_Construct + gcoSURF_Destroy + gcoSURF_MapUserSurface + gcoSURF_GetSize + gcoSURF_GetAlignedSize + gcoSURF_GetFormat + gcoSURF_Lock + gcoSURF_Unlock + gcoSURF_Fill + gcoSURF_Blend + gcoSURF_SetClipping + gcoSURF_Clear2D + gcoSURF_Line + gcoSURF_Blit + gcoSURF_MonoBlit + gcoSURF_FilterBlit + gcoSURF_EnableAlphaBlend + gcoSURF_DisableAlphaBlend + gcoSURF_CopyPixels + gcoSURF_ReadPixel + gcoSURF_WritePixel + gcoSURF_QueryFormat + gcoSURF_Flush + gcoSURF_SetColorType + gcoSURF_GetColorType + gcoSURF_SetRotation + gcoSURF_ConstructWrapper + gcoSURF_SetBuffer + gcoSURF_SetWindow + gcoSURF_ReferenceSurface + gcoSURF_SetOrientation + gcoSURF_QueryOrientation + gcoSURF_QueryReferenceCount + +!IFNDEF VIVANTE_NO_3D + gcoSURF_IsTileStatusSupported + gcoSURF_EnableTileStatus + gcoSURF_DisableTileStatus + gcoSURF_SetSamples + gcoSURF_GetSamples + gcoSURF_Copy + gcoSURF_Clear + gcoSURF_ClearRect + gcoSURF_Resample + gcoSURF_Resolve + gcoSURF_ResolveRect + depr_gcoSURF_Resolve + depr_gcoSURF_ResolveRect + gcoSURF_SetResolvability +!ENDIF + +!IFNDEF VIVANTE_NO_3D + ; gcoINDEX + gcoINDEX_Construct + gcoINDEX_Destroy + gcoINDEX_Lock + gcoINDEX_Unlock + gcoINDEX_Load + gcoINDEX_Bind + gcoINDEX_BindOffset + gcoINDEX_Free + gcoINDEX_Upload + gcoINDEX_UploadOffset + gcoINDEX_QueryCaps + gcoINDEX_GetIndexRange + gcoINDEX_SetDynamic + gcoINDEX_UploadDynamic +!ENDIF + + ; gco2D + gco2D_Construct + gco2D_Destroy + gco2D_SetBrushLimit + gco2D_FlushBrush + gco2D_LoadSolidBrush + gco2D_SetMonochromeSource + gco2D_SetColorSource + gco2D_SetColorSourceEx + gco2D_SetColorSourceAdvanced + gco2D_SetMaskedSource + gco2D_SetMaskedSourceEx + gco2D_SetSource + gco2D_SetClipping + gco2D_SetTarget + gco2D_SetTargetEx + gco2D_SetStretchFactors + gco2D_SetStretchRectFactors + gco2D_ConstructSingleColorBrush + gco2D_ConstructMonochromeBrush + gco2D_ConstructColorBrush + gco2D_Clear + gco2D_Line + gco2D_ColorLine + gco2D_Blit + gco2D_BatchBlit + gco2D_StretchBlit + gco2D_MonoBlit + gco2D_SetKernelSize + gco2D_SetFilterType + gco2D_SetUserFilterKernel + gco2D_EnableUserFilterPasses + gco2D_FreeFilterBuffer + gco2D_FilterBlit + gco2D_FilterBlitEx + gco2D_EnableAlphaBlend + gco2D_EnableAlphaBlendAdvanced + gco2D_SetPorterDuffBlending + gco2D_DisableAlphaBlend + gco2D_GetPackSize + gco2D_Flush + gco2D_LoadPalette + gco2D_SetBitBlitMirror + gco2D_SetTransparencyAdvanced + gco2D_SetSourceColorKeyAdvanced + gco2D_SetSourceColorKeyRangeAdvanced + gco2D_SetTargetColorKeyAdvanced + gco2D_SetTargetColorKeyRangeAdvanced + gco2D_SetYUVColorMode + gco2D_SetSourceGlobalColorAdvanced + gco2D_SetTargetGlobalColorAdvanced + gco2D_SetPixelMultiplyModeAdvanced + gco2D_SetAutoFlushCycles + gco2D_ProfileEngine + gco2D_GetMaximumDataCount + + +!IFNDEF VIVANTE_NO_3D + gco3D_Construct + gco3D_Destroy + gco3D_SetAPI + gco3D_SetTarget + gco3D_SetDepth + gco3D_SetViewport + gco3D_SetScissors + gco3D_SetClearColor + gco3D_SetClearColorX + gco3D_SetClearColorF + gco3D_SetClearDepthX + gco3D_SetClearDepthF + gco3D_SetClearStencil + gco3D_Clear + gco3D_ClearRect + gco3D_ClearTileStatus + gco3D_ClearHzTileStatus + gco3D_SetShading + gco3D_EnableBlending + gco3D_SetBlendFunction + gco3D_SetBlendMode + gco3D_SetBlendColor + gco3D_SetBlendColorX + gco3D_SetBlendColorF + gco3D_SetCulling + gco3D_SetPointSizeEnable + gco3D_SetPointSprite + gco3D_SetFill + gco3D_SetDepthCompare + gco3D_EnableDepthWrite + gco3D_SetDepthRangeX + gco3D_SetDepthMode + gco3D_SetDepthRangeF + gco3D_SetLastPixelEnable + gco3D_SetDepthScaleBiasX + gco3D_SetDepthScaleBiasF + gco3D_EnableDither + gco3D_SetColorWrite + gco3D_SetEarlyDepth + gco3D_SetDepthOnly + gco3D_SetStencilMode + gco3D_SetStencilMask + gco3D_SetStencilWriteMask + gco3D_SetStencilReference + gco3D_SetStencilCompare + gco3D_SetStencilPass + gco3D_SetStencilFail + gco3D_SetStencilDepthFail + gco3D_SetAlphaTest + gco3D_SetAlphaCompare + gco3D_SetAlphaReference + gco3D_SetAlphaReferenceX + gco3D_SetAlphaReferenceF + gco3D_SetAntiAliasLine + gco3D_SetAALineTexSlot + gco3D_SetAALineWidth + gco3D_DrawPrimitives + gco3D_DrawPrimitivesOffset + gco3D_DrawIndexedPrimitives + gco3D_DrawIndexedPrimitivesOffset + gco3D_SetAntiAlias + gco3D_WriteBuffer + gco3D_SetFragmentConfiguration + gco3D_EnableTextureStage + gco3D_SetTextureColorMask + gco3D_SetTextureAlphaMask + gco3D_SetFragmentColorX + gco3D_SetFragmentColorF + gco3D_SetFogColorX + gco3D_SetFogColorF + gco3D_SetTetxureColorX + gco3D_SetTetxureColorF + gco3D_SetColorTextureFunction + gco3D_SetAlphaTextureFunction + gco3D_Semaphore + gco3D_SetCentroids +!ENDIF + +!IFNDEF VIVANTE_NO_3D + ; gcoTEXTURE + gcoTEXTURE_Construct + gcoTEXTURE_ConstructSized + gcoTEXTURE_Destroy + gcoTEXTURE_Upload + gcoTEXTURE_UploadSub + gcoTEXTURE_UploadCompressed + gcoTEXTURE_GetMipMap + gcoTEXTURE_GetMipMapFace + gcoTEXTURE_AddMipMap + gcoTEXTURE_AddMipMapFromClient + gcoTEXTURE_AddMipMapFromSurface + gcoTEXTURE_SetEndianHint + gcoTEXTURE_SetAddressingMode + gcoTEXTURE_SetBorderColor + gcoTEXTURE_SetBorderColorX + gcoTEXTURE_SetBorderColorF + gcoTEXTURE_SetMinFilter + gcoTEXTURE_SetMagFilter + gcoTEXTURE_SetMipFilter + gcoTEXTURE_SetLODBiasX + gcoTEXTURE_SetLODBiasF + gcoTEXTURE_SetLODMinX + gcoTEXTURE_SetLODMinF + gcoTEXTURE_SetLODMaxX + gcoTEXTURE_SetLODMaxF + gcoTEXTURE_Bind + gcoTEXTURE_Flush + gcoTEXTURE_QueryCaps + gcoTEXTURE_GetClosestFormat + gcoTEXTURE_Disable + gcoTEXTURE_RenderIntoMipMap + gcoTEXTURE_IsRenderable + gcoTEXTURE_IsComplete +!ENDIF + + ; gcsRECT + gcsRECT_Height + gcsRECT_Width + gcsRECT_Set + +!IFNDEF VIVANTE_NO_3D + ; gcoHARDWARE + gcoHARDWARE_QueryTextureCaps + gcoHARDWARE_QueryShaderCaps + gcoHARDWARE_QueryIndexCaps + gcoHARDWARE_QueryStreamCaps +!ENDIF + + ; gcoBRUSH + gcoBRUSH_Destroy + +!IFNDEF VIVANTE_NO_3D + ; gcSHADER + gcOptimizeShader + gcLinkShaders + gcLoadShaders + gcSaveProgram + gcSHADER_Construct + gcSHADER_Destroy + gcSHADER_AddUniform + gcSHADER_AddSource + gcSHADER_AddSourceAttributeIndexed + gcSHADER_AddSourceUniformIndexed + gcSHADER_AddSourceSamplerIndexed + gcSHADER_AddOpcodeIndexed + gcSHADER_AddSourceIndexed + gcSHADER_AddAttribute + gcSHADER_AddOutput + gcSHADER_AddOutputIndexed + gcSHADER_AddSourceAttribute + gcSHADER_AddSourceConstant + gcSHADER_AddSourceUniform + gcSHADER_AddLabel + gcSHADER_AddOpcode + gcSHADER_AddOpcode2 + gcSHADER_AddOpcodeConditional + gcSHADER_AddVariable + gcSHADER_Pack + gcSHADER_Load + gcSHADER_Save + gcSHADER_GetUniform + gcSHADER_GetUniformCount + gcSHADER_GetAttribute + gcSHADER_GetAttributeCount + gcSHADER_GetPositionAttribute + gcSHADER_GetVariable + gcSHADER_GetVariableCount + gcSHADER_AddFunction + gcSHADER_BeginFunction + gcSHADER_EndFunction + gcSHADER_SetOptimizationOption + gcSHADER_GetPositionAttribute +!ENDIF + +!IFNDEF VIVANTE_NO_3D + ; gcATTRIBUTE + gcATTRIBUTE_GetName + gcATTRIBUTE_GetType + gcATTRIBUTE_IsEnabled +!ENDIF + +!IFNDEF VIVANTE_NO_3D + ; gcFUNCTION + gcFUNCTION_AddArgument + gcFUNCTION_GetArgument + gcFUNCTION_GetLabel +!ENDIF + +!IFNDEF VIVANTE_NO_3D + ; gcUNIFORM + gcUNIFORM_GetName + gcUNIFORM_GetType + gcUNIFORM_GetSampler + gcUNIFORM_SetValue + gcUNIFORM_SetValueX + gcUNIFORM_SetValueF +!ENDIF + +!IFNDEF VIVANTE_NO_3D + ; gcoSTREAM + gcoSTREAM_Construct + gcoSTREAM_Destroy + gcoSTREAM_Upload + gcoSTREAM_SetStride + gcoSTREAM_Lock + gcoSTREAM_Unlock + gcoSTREAM_Reserve + gcoSTREAM_Flush + gcoSTREAM_SetDynamic + gcoSTREAM_UploadDynamic +!ENDIF + +!IFNDEF VIVANTE_NO_3D + ; gcoVERTEX + gcoVERTEX_Construct + gcoVERTEX_Destroy + gcoVERTEX_Reset + gcoVERTEX_EnableAttribute + gcoVERTEX_DisableAttribute + gcoVERTEX_Bind +!ENDIF + +!IFNDEF VIVANTE_NO_3D + ; gcoBUFFER + gcoBUFFER_Construct + gcoBUFFER_Destroy + gcoBUFFER_Reserve + gcoBUFFER_Write + gcoBUFFER_Commit +!ENDIF + +!IFNDEF VIVANTE_NO_PROFILER + ; gcoPROFILER + ;gcoPROFILER_Initialize + ;gcoPROFILER_Destroy + ;gcoPROFILER_EndFrame + ;gcoPROFILER_ShaderFS + ;gcoPROFILER_ShaderVS +!ENDIF + + ; gcoMATH + gcoMATH_Log2in5dot5 + gcoMATH_Sine + gcoMATH_Cosine + gcoMATH_Floor + gcoMATH_Ceiling + gcoMATH_SquareRoot + gcoMATH_Log2 + gcoMATH_Power + gcoMATH_Modulo + gcoMATH_ArcCosine + gcoMATH_Absolute + gcoMATH_Exp + gcoMATH_UInt2Float + gcoMATH_Float2UInt + gcoMATH_Multiply +<< diff --git a/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_debug.c b/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_debug.c new file mode 100644 index 000000000000..3577a3960bf8 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_debug.c @@ -0,0 +1,449 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_linux.h" +#include "linux/spinlock.h" +#include + +/* + gcdBUFFERED_OUTPUT + + When set to non-zero, all output is collected into a buffer with the + specified size. Once the buffer gets full, or the token "$$FLUSH$$" has + been received, the debug buffer will be printed to the console. +*/ +#define gcdBUFFERED_OUTPUT 0 + +/******************************************************************************\ +******************************** Debug Variables ******************************* +\******************************************************************************/ + +static gceSTATUS _lastError = gcvSTATUS_OK; +static gctUINT32 _debugLevel = gcvLEVEL_WARNING; +static gctUINT32 _debugZones = gcvZONE_ALL; +static gctINT _indent = 0; +static spinlock_t _lock = SPIN_LOCK_UNLOCKED; + +static void +OutputDebugString( + IN gctCONST_STRING String + ) +{ +#if gcdBUFFERED_OUTPUT + static gctCHAR outputBuffer[gcdBUFFERED_OUTPUT]; + static gctINT outputBufferIndex = 0; + gctINT n, i; + + n = (String != gcvNULL) ? strlen(String) + 1 : 0; + + if ((n == 0) || (outputBufferIndex + n > gcmSIZEOF(outputBuffer))) + { + for (i = 0; i < outputBufferIndex; i += strlen(outputBuffer + i) + 1) + { + printk(outputBuffer + i); + } + + outputBufferIndex = 0; + } + + if (n > 0) + { + memcpy(outputBuffer + outputBufferIndex, String, n); + outputBufferIndex += n; + } +#else + if (String != gcvNULL) + { + printk(String); + } +#endif +} + +static void +_Print( + IN gctCONST_STRING Message, + IN va_list Arguments + ) +{ + char buffer[1024]; + int i, n; + + if (strcmp(Message, "$$FLUSH$$") == 0) + { + spin_lock(&_lock); + { + OutputDebugString(gcvNULL); + } + spin_unlock(&_lock); + return; + } + + if (strncmp(Message, "--", 2) == 0) + { + if (_indent == 0) + { + printk("ERROR: _indent=0\n"); + } + + _indent -= 2; + } + + for (i = 0; i < _indent; ++i) + { + buffer[i] = ' '; + } + + /* Print message to buffer. */ + n = vsnprintf(buffer + i, sizeof(buffer) - i, Message, Arguments); + if ((n <= 0) || (buffer[i + n - 1] != '\n')) + { + /* Append new-line. */ + strncat(buffer, "\n", sizeof(buffer)); + } + + /* Output to debugger. */ + spin_lock(&_lock); + { + OutputDebugString(buffer); + } + spin_unlock(&_lock); + + if (strncmp(Message, "++", 2) == 0) + { + _indent += 2; + } +} + +/******************************************************************************\ +********************************* Debug Macros ********************************* +\******************************************************************************/ + +#define _DEBUGPRINT(Message) \ +{ \ + va_list arguments; \ + \ + va_start(arguments, Message); \ + _Print(Message, arguments); \ + va_end(arguments); \ +} + +/******************************************************************************\ +********************************** Debug Code ********************************** +\******************************************************************************/ + +/******************************************************************************* +** +** gckOS_Print +** +** Send a message to the debugger. +** +** INPUT: +** +** gctCONST_STRING Message +** Pointer to message. +** +** ... +** Optional arguments. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_Print( + IN gctCONST_STRING Message, + ... + ) +{ + _DEBUGPRINT(Message); +} + +/******************************************************************************* +** +** gckOS_DebugTrace +** +** Send a leveled message to the debugger. +** +** INPUT: +** +** gctUINT32 Level +** Debug level of message. +** +** gctCONST_STRING Message +** Pointer to message. +** +** ... +** Optional arguments. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_DebugTrace( + IN gctUINT32 Level, + IN gctCONST_STRING Message, + ... + ) +{ + if (Level > _debugLevel) + { + return; + } + + _DEBUGPRINT(Message); +} + +/******************************************************************************* +** +** gckOS_DebugTraceZone +** +** Send a leveled and zoned message to the debugger. +** +** INPUT: +** +** gctUINT32 Level +** Debug level for message. +** +** gctUINT32 Zone +** Debug zone for message. +** +** gctCONST_STRING Message +** Pointer to message. +** +** ... +** Optional arguments. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_DebugTraceZone( + IN gctUINT32 Level, + IN gctUINT32 Zone, + IN gctCONST_STRING Message, + ... + ) +{ + if ((Level > _debugLevel) || !(Zone & _debugZones)) + { + return; + } + + _DEBUGPRINT(Message); +} + +/******************************************************************************* +** +** gckOS_DebugBreak +** +** Break into the debugger. +** +** INPUT: +** +** Nothing. +** +** OUTPUT: +** +** Nothing. +*/ +void +gckOS_DebugBreak( + void + ) +{ + gckOS_DebugTrace(gcvLEVEL_ERROR, "gckOS_DebugBreak"); +} + +/******************************************************************************* +** +** gckOS_DebugFatal +** +** Send a message to the debugger and break into the debugger. +** +** INPUT: +** +** gctCONST_STRING Message +** Pointer to message. +** +** ... +** Optional arguments. +** +** OUTPUT: +** +** Nothing. +*/ +void +gckOS_DebugFatal( + IN gctCONST_STRING Message, + ... + ) +{ + _DEBUGPRINT(Message); + + /* Break into the debugger. */ + gckOS_DebugBreak(); +} + +/******************************************************************************* +** +** gckOS_SetDebugLevel +** +** Set the debug level. +** +** INPUT: +** +** gctUINT32 Level +** New debug level. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_SetDebugLevel( + IN gctUINT32 Level + ) +{ + _debugLevel = Level; +} + +/******************************************************************************* +** +** gckOS_SetDebugZone +** +** Set the debug zone. +** +** INPUT: +** +** gctUINT32 Zone +** New debug zone. +** +** OUTPUT: +** +** Nothing. +*/ +void +gckOS_SetDebugZone( + IN gctUINT32 Zone + ) +{ + _debugZones = Zone; +} + +/******************************************************************************* +** +** gckOS_SetDebugLevelZone +** +** Set the debug level and zone. +** +** INPUT: +** +** gctUINT32 Level +** New debug level. +** +** gctUINT32 Zone +** New debug zone. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_SetDebugLevelZone( + IN gctUINT32 Level, + IN gctUINT32 Zone + ) +{ + _debugLevel = Level; + _debugZones = Zone; +} + +/******************************************************************************* +** +** gckOS_SetDebugZones +** +** Enable or disable debug zones. +** +** INPUT: +** +** gctUINT32 Zones +** Debug zones to enable or disable. +** +** gctBOOL Enable +** Set to gcvTRUE to enable the zones (or the Zones with the current +** zones) or gcvFALSE to disable the specified Zones. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_SetDebugZones( + IN gctUINT32 Zones, + IN gctBOOL Enable + ) +{ + if (Enable) + { + /* Enable the zones. */ + _debugZones |= Zones; + } + else + { + /* Disable the zones. */ + _debugZones &= ~Zones; + } +} + +/******************************************************************************* +** +** gckOS_Verify +** +** Called to verify the result of a function call. +** +** INPUT: +** +** gceSTATUS Status +** Function call result. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_Verify( + IN gceSTATUS Status + ) +{ + _lastError = Status; +} + diff --git a/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_device.c b/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_device.c new file mode 100644 index 000000000000..51ab04d06cab --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_device.c @@ -0,0 +1,836 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_linux.h" +#include +#include +#include +#include + +#define _GC_OBJ_ZONE gcvZONE_DEVICE + +#ifdef FLAREON +static struct dove_gpio_irq_handler gc500_handle; +#endif + +/******************************************************************************\ +******************************** gckGALDEVICE Code ******************************* +\******************************************************************************/ + +gceSTATUS +gckGALDEVICE_AllocateMemory( + IN gckGALDEVICE Device, + IN gctSIZE_T Bytes, + OUT gctPOINTER *Logical, + OUT gctPHYS_ADDR *Physical, + OUT gctUINT32 *PhysAddr + ) +{ + gceSTATUS status; + + gcmkVERIFY_ARGUMENT(Device != NULL); + gcmkVERIFY_ARGUMENT(Logical != NULL); + gcmkVERIFY_ARGUMENT(Physical != NULL); + gcmkVERIFY_ARGUMENT(PhysAddr != NULL); + + status = gckOS_AllocateContiguous(Device->os, + gcvFALSE, + &Bytes, + Physical, + Logical); + + if (gcmIS_ERROR(status)) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER, + "gckGALDEVICE_AllocateMemory: error status->0x%x", + status); + + return status; + } + + *PhysAddr = ((PLINUX_MDL)*Physical)->dmaHandle - Device->baseAddress; + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "gckGALDEVICE_AllocateMemory: phys_addr->0x%x phsical->0x%x Logical->0x%x", + (gctUINT32)*Physical, + (gctUINT32)*PhysAddr, + (gctUINT32)*Logical); + + /* Success. */ + return gcvSTATUS_OK; +} + +gceSTATUS +gckGALDEVICE_FreeMemory( + IN gckGALDEVICE Device, + IN gctPOINTER Logical, + IN gctPHYS_ADDR Physical) +{ + gcmkVERIFY_ARGUMENT(Device != NULL); + + return gckOS_FreeContiguous(Device->os, + Physical, + Logical, + ((PLINUX_MDL)Physical)->numPages*PAGE_SIZE); +} + +irqreturn_t isrRoutine(int irq, void *ctxt) +{ + gckGALDEVICE device = (gckGALDEVICE) ctxt; + int handled = 0; + + /* Call kernel interrupt notification. */ + if (gckKERNEL_Notify(device->kernel, + gcvNOTIFY_INTERRUPT, + gcvTRUE) == gcvSTATUS_OK) + { + device->dataReady = gcvTRUE; + + up(&device->sema); + + handled = 1; + } + + return IRQ_RETVAL(handled); +} + +int threadRoutine(void *ctxt) +{ + gckGALDEVICE device = (gckGALDEVICE) ctxt; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "Starting isr Thread with extension->%p", + device); + + for (;;) + { + static int down; + + down = down_interruptible(&device->sema); + device->dataReady = gcvFALSE; + + if (device->killThread == gcvTRUE) + { + /* The daemon exits. */ + while (!kthread_should_stop()) + { + gckOS_Delay(device->os, 1); + } + + return 0; + } + else + { + gckKERNEL_Notify(device->kernel, gcvNOTIFY_INTERRUPT, gcvFALSE); + } + } +} + +/******************************************************************************* +** +** gckGALDEVICE_Setup_ISR +** +** Start the ISR routine. +** +** INPUT: +** +** gckGALDEVICE Device +** Pointer to an gckGALDEVICE object. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** gcvSTATUS_OK +** Setup successfully. +** gcvSTATUS_GENERIC_IO +** Setup failed. +*/ +gceSTATUS +gckGALDEVICE_Setup_ISR( + IN gckGALDEVICE Device + ) +{ + gctINT ret; + + gcmkVERIFY_ARGUMENT(Device != NULL); + + if (Device->irqLine == 0) + { + return gcvSTATUS_GENERIC_IO; + } + + /* Hook up the isr based on the irq line. */ +#ifdef FLAREON + gc500_handle.dev_name = "galcore interrupt service"; + gc500_handle.dev_id = Device; + gc500_handle.handler = isrRoutine; + gc500_handle.intr_gen = GPIO_INTR_LEVEL_TRIGGER; + gc500_handle.intr_trig = GPIO_TRIG_HIGH_LEVEL; + ret = dove_gpio_request (DOVE_GPIO0_7, &gc500_handle); +#else + ret = request_irq(Device->irqLine, + isrRoutine, + IRQF_DISABLED, + "galcore interrupt service", + Device); +#endif + + + if (ret != 0) { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Setup_ISR: " + "Could not register irq line->%d", + Device->irqLine); + + Device->isrInitialized = gcvFALSE; + + return gcvSTATUS_GENERIC_IO; + } + + Device->isrInitialized = gcvTRUE; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Setup_ISR: " + "Setup the irq line->%d", + Device->irqLine); + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckGALDEVICE_Release_ISR +** +** Release the irq line. +** +** INPUT: +** +** gckGALDEVICE Device +** Pointer to an gckGALDEVICE object. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** Nothing. +*/ +gceSTATUS +gckGALDEVICE_Release_ISR( + IN gckGALDEVICE Device + ) +{ + gcmkVERIFY_ARGUMENT(Device != NULL); + + /* release the irq */ + if (Device->isrInitialized) + { +#ifdef FLAREON + dove_gpio_free (DOVE_GPIO0_7, "galcore interrupt service"); +#else + free_irq(Device->irqLine, Device); +#endif + } + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckGALDEVICE_Start_Thread +** +** Start the daemon thread. +** +** INPUT: +** +** gckGALDEVICE Device +** Pointer to an gckGALDEVICE object. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** gcvSTATUS_OK +** Start successfully. +** gcvSTATUS_GENERIC_IO +** Start failed. +*/ +gceSTATUS +gckGALDEVICE_Start_Thread( + IN gckGALDEVICE Device + ) +{ + gcmkVERIFY_ARGUMENT(Device != NULL); + + /* start the kernel thread */ + Device->threadCtxt = kthread_run(threadRoutine, + Device, + "galcore daemon thread"); + + Device->threadInitialized = gcvTRUE; + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Start_Thread: " + "Start the daemon thread."); + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckGALDEVICE_Stop_Thread +** +** Stop the gal device, including the following actions: stop the daemon +** thread, release the irq. +** +** INPUT: +** +** gckGALDEVICE Device +** Pointer to an gckGALDEVICE object. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** Nothing. +*/ +gceSTATUS +gckGALDEVICE_Stop_Thread( + gckGALDEVICE Device + ) +{ + gcmkVERIFY_ARGUMENT(Device != NULL); + + /* stop the thread */ + if (Device->threadInitialized) + { + Device->killThread = gcvTRUE; + up(&Device->sema); + + kthread_stop(Device->threadCtxt); + } + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckGALDEVICE_Start +** +** Start the gal device, including the following actions: setup the isr routine +** and start the daemoni thread. +** +** INPUT: +** +** gckGALDEVICE Device +** Pointer to an gckGALDEVICE object. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** gcvSTATUS_OK +** Start successfully. +*/ +gceSTATUS +gckGALDEVICE_Start( + IN gckGALDEVICE Device + ) +{ + /* start the daemon thread */ + gcmkVERIFY_OK(gckGALDEVICE_Start_Thread(Device)); + + /* setup the isr routine */ + gcmkVERIFY_OK(gckGALDEVICE_Setup_ISR(Device)); + + /* Switch to SUSPEND power state. */ + gcmkVERIFY_OK( + gckHARDWARE_SetPowerManagementState(Device->kernel->hardware, + gcvPOWER_SUSPEND_ATPOWERON)); + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckGALDEVICE_Stop +** +** Stop the gal device, including the following actions: stop the daemon +** thread, release the irq. +** +** INPUT: +** +** gckGALDEVICE Device +** Pointer to an gckGALDEVICE object. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** Nothing. +*/ +gceSTATUS +gckGALDEVICE_Stop( + gckGALDEVICE Device + ) +{ + gcmkVERIFY_ARGUMENT(Device != NULL); + + /* Switch to ON power state. */ + gcmkVERIFY_OK( + gckHARDWARE_SetPowerManagementState(Device->kernel->hardware, + gcvPOWER_ON)); + + if (Device->isrInitialized) + { + gckGALDEVICE_Release_ISR(Device); + } + + if (Device->threadInitialized) + { + gckGALDEVICE_Stop_Thread(Device); + } + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckGALDEVICE_Construct +** +** Constructor. +** +** INPUT: +** +** OUTPUT: +** +** gckGALDEVICE * Device +** Pointer to a variable receiving the gckGALDEVICE object pointer on +** success. +*/ +gceSTATUS +gckGALDEVICE_Construct( + IN gctINT IrqLine, + IN gctUINT32 RegisterMemBase, + IN gctSIZE_T RegisterMemSize, + IN gctUINT32 ContiguousBase, + IN gctSIZE_T ContiguousSize, + IN gctSIZE_T BankSize, + IN gctINT FastClear, + IN gctINT Compression, + IN gctUINT32 BaseAddress, + IN gctINT Signal, + OUT gckGALDEVICE *Device + ) +{ + gctUINT32 internalBaseAddress = 0, internalAlignment = 0; + gctUINT32 externalBaseAddress = 0, externalAlignment = 0; + gctUINT32 horizontalTileSize, verticalTileSize; + gctUINT32 physAddr; + gctUINT32 physical; + gckGALDEVICE device; + gceSTATUS status; + + gcmkTRACE(gcvLEVEL_VERBOSE, "[galcore] Enter gckGALDEVICE_Construct"); + + /* Allocate device structure. */ + device = kmalloc(sizeof(struct _gckGALDEVICE), GFP_KERNEL); + if (!device) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Construct: Can't allocate memory."); + + return gcvSTATUS_OUT_OF_MEMORY; + } + memset(device, 0, sizeof(struct _gckGALDEVICE)); + + physical = RegisterMemBase; + + /* Set up register memory region */ + if (physical != 0) + { + /* Request a region. */ + request_mem_region(RegisterMemBase, RegisterMemSize, "galcore register region"); + device->registerBase = (gctPOINTER) ioremap_nocache(RegisterMemBase, + RegisterMemSize); + if (!device->registerBase) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Construct: Unable to map location->0x%lX for size->%ld", + RegisterMemBase, + RegisterMemSize); + + return gcvSTATUS_OUT_OF_RESOURCES; + } + + physical += RegisterMemSize; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Construct: " + "RegisterBase after mapping Address->0x%x is 0x%x", + (gctUINT32)RegisterMemBase, + (gctUINT32)device->registerBase); + } + + /* construct the gckOS object */ + device->baseAddress = BaseAddress; + gcmkVERIFY_OK(gckOS_Construct(device, &device->os)); + + /* construct the gckKERNEL object. */ + gcmkVERIFY_OK(gckKERNEL_Construct(device->os, device, &device->kernel)); + + gcmkVERIFY_OK(gckHARDWARE_SetFastClear(device->kernel->hardware, + FastClear, + Compression)); + + /* query the ceiling of the system memory */ + gcmkVERIFY_OK(gckHARDWARE_QuerySystemMemory(device->kernel->hardware, + &device->systemMemorySize, + &device->systemMemoryBaseAddress)); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Construct: " + "Will be trying to allocate contiguous memory of 0x%x bytes", + (gctUINT32)device->systemMemoryBaseAddress); + +#if COMMAND_PROCESSOR_VERSION == 1 + /* start the command queue */ + gcmkVERIFY_OK(gckCOMMAND_Start(device->kernel->command)); +#endif + + /* initialize the thread daemon */ + sema_init(&device->sema, 0); + + device->threadInitialized = gcvFALSE; + device->killThread = gcvFALSE; + + /* initialize the isr */ + device->isrInitialized = gcvFALSE; + device->dataReady = gcvFALSE; + device->irqLine = IrqLine; + + device->signal = Signal; + + /* query the amount of video memory */ + gcmkVERIFY_OK(gckHARDWARE_QueryMemory(device->kernel->hardware, + &device->internalSize, + &internalBaseAddress, + &internalAlignment, + &device->externalSize, + &externalBaseAddress, + &externalAlignment, + &horizontalTileSize, + &verticalTileSize)); + + /* set up the internal memory region */ + if (device->internalSize > 0) + { + gceSTATUS status = gckVIDMEM_Construct(device->os, + internalBaseAddress, + device->internalSize, + internalAlignment, + 0, + &device->internalVidMem); + + if (gcmIS_ERROR(status)) + { + /* error, remove internal heap */ + device->internalSize = 0; + } + else + { + /* map internal memory */ + device->internalPhysical = (gctPHYS_ADDR)physical; + device->internalLogical = (gctPOINTER)ioremap_nocache( + physical, device->internalSize); + + gcmkASSERT(device->internalLogical != NULL); + + physical += device->internalSize; + } + } + + if (device->externalSize > 0) + { + /* create the external memory heap */ + gceSTATUS status = gckVIDMEM_Construct(device->os, + externalBaseAddress, + device->externalSize, + externalAlignment, + 0, + &device->externalVidMem); + + if (gcmIS_ERROR(status)) + { + /* error, remove internal heap */ + device->externalSize = 0; + } + else + { + /* map internal memory */ + device->externalPhysical = (gctPHYS_ADDR)physical; + device->externalLogical = (gctPOINTER)ioremap_nocache( + physical, device->externalSize); + + gcmkASSERT(device->externalLogical != NULL); + + physical += device->externalSize; + } + } + + /* set up the contiguous memory */ + device->contiguousSize = ContiguousSize; + + if (ContiguousBase == 0) + { + status = gcvSTATUS_OUT_OF_MEMORY; + + while (device->contiguousSize > 0) + { + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Construct: Will be trying to allocate contiguous memory of %ld bytes", + device->contiguousSize + ); + + /* allocate contiguous memory */ + status = gckGALDEVICE_AllocateMemory( + device, + device->contiguousSize, + &device->contiguousBase, + &device->contiguousPhysical, + &physAddr + ); + + if (gcmIS_SUCCESS(status)) + { + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Construct: Contiguous allocated size->0x%08X Virt->0x%08lX physAddr->0x%08X", + device->contiguousSize, + device->contiguousBase, + physAddr + ); + + status = gckVIDMEM_Construct( + device->os, + physAddr | device->systemMemoryBaseAddress, + device->contiguousSize, + 64, + BankSize, + &device->contiguousVidMem + ); + + if (gcmIS_SUCCESS(status)) + { + device->contiguousMapped = gcvFALSE; + + /* success, abort loop */ + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_DRIVER, + "Using %u bytes of contiguous memory.", + device->contiguousSize + ); + + break; + } + + gcmkVERIFY_OK(gckGALDEVICE_FreeMemory( + device, + device->contiguousBase, + device->contiguousPhysical + )); + + device->contiguousBase = NULL; + } + + if (device->contiguousSize <= (4 << 20)) + { + device->contiguousSize = 0; + } + else + { + device->contiguousSize -= (4 << 20); + } + } + } + else + { + /* Create the contiguous memory heap. */ + status = gckVIDMEM_Construct( + device->os, + (ContiguousBase - device->baseAddress) | device->systemMemoryBaseAddress, + ContiguousSize, + 64, + BankSize, + &device->contiguousVidMem + ); + + if (gcmIS_ERROR(status)) + { + /* Error, roll back. */ + device->contiguousVidMem = gcvNULL; + device->contiguousSize = 0; + } + else + { + /* Map the contiguous memory. */ + request_mem_region( + ContiguousBase, + ContiguousSize, + "galcore managed memory" + ); + + device->contiguousPhysical = (gctPHYS_ADDR) ContiguousBase; + device->contiguousSize = ContiguousSize; + device->contiguousBase = (gctPOINTER) ioremap_nocache(ContiguousBase, ContiguousSize); + device->contiguousMapped = gcvTRUE; + + if (device->contiguousBase == gcvNULL) + { + /* Error, roll back. */ + gcmkVERIFY_OK(gckVIDMEM_Destroy(device->contiguousVidMem)); + device->contiguousVidMem = gcvNULL; + device->contiguousSize = 0; + + status = gcvSTATUS_OUT_OF_RESOURCES; + } + } + } + + *Device = device; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Construct: Initialized device->%p contiguous->%lu @ %p (0x%08X)", + device, + device->contiguousSize, + device->contiguousBase, + device->contiguousPhysical); + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckGALDEVICE_Destroy +** +** Class destructor. +** +** INPUT: +** +** Nothing. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** Nothing. +*/ +gceSTATUS +gckGALDEVICE_Destroy( + gckGALDEVICE Device) +{ + gcmkVERIFY_ARGUMENT(Device != NULL); + + gcmkTRACE(gcvLEVEL_VERBOSE, "[ENTER] gckGALDEVICE_Destroy"); + + /* Destroy the gckKERNEL object. */ + gcmkVERIFY_OK(gckKERNEL_Destroy(Device->kernel)); + + if (Device->internalVidMem != gcvNULL) + { + /* destroy the internal heap */ + gcmkVERIFY_OK(gckVIDMEM_Destroy(Device->internalVidMem)); + + /* unmap the internal memory */ + iounmap(Device->internalLogical); + } + + if (Device->externalVidMem != gcvNULL) + { + /* destroy the internal heap */ + gcmkVERIFY_OK(gckVIDMEM_Destroy(Device->externalVidMem)); + + /* unmap the external memory */ + iounmap(Device->externalLogical); + } + + if (Device->contiguousVidMem != gcvNULL) + { + /* Destroy the contiguous heap */ + gcmkVERIFY_OK(gckVIDMEM_Destroy(Device->contiguousVidMem)); + + if (Device->contiguousMapped) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Destroy: " + "Unmapping contiguous memory->0x%08lX", + Device->contiguousBase); + + iounmap(Device->contiguousBase); + } + else + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Destroy: " + "Freeing contiguous memory->0x%08lX", + Device->contiguousBase); + + gcmkVERIFY_OK(gckGALDEVICE_FreeMemory(Device, + Device->contiguousBase, + Device->contiguousPhysical)); + } + } + + if (Device->registerBase) + { + iounmap(Device->registerBase); + } + + /* Destroy the gckOS object. */ + gcmkVERIFY_OK(gckOS_Destroy(Device->os)); + + kfree(Device); + + gcmkTRACE(gcvLEVEL_VERBOSE, "[galcore] Leave gckGALDEVICE_Destroy"); + + return gcvSTATUS_OK; +} + diff --git a/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_device.h b/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_device.h new file mode 100644 index 000000000000..75c86f8ad143 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_device.h @@ -0,0 +1,148 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_kernel_device_h_ +#define __gc_hal_kernel_device_h_ + +#define gcdkUSE_MEMORY_RECORD 1 + +#ifdef ANDROID +#define gcdkREPORT_VIDMEM_LEAK 0 +#else +#define gcdkREPORT_VIDMEM_LEAK 1 +#endif + +/******************************************************************************\ +******************************* gckGALDEVICE Structure ******************************* +\******************************************************************************/ + +typedef struct _gckGALDEVICE +{ + /* Objects. */ + gckOS os; + gckKERNEL kernel; + + /* Attributes. */ + gctSIZE_T internalSize; + gctPHYS_ADDR internalPhysical; + gctPOINTER internalLogical; + gckVIDMEM internalVidMem; + gctSIZE_T externalSize; + gctPHYS_ADDR externalPhysical; + gctPOINTER externalLogical; + gckVIDMEM externalVidMem; + gckVIDMEM contiguousVidMem; + gctPOINTER contiguousBase; + gctPHYS_ADDR contiguousPhysical; + gctSIZE_T contiguousSize; + gctBOOL contiguousMapped; + gctPOINTER contiguousMappedUser; + gctSIZE_T systemMemorySize; + gctUINT32 systemMemoryBaseAddress; + gctPOINTER registerBase; + gctSIZE_T registerSize; + gctUINT32 baseAddress; + + /* IRQ management. */ + gctINT irqLine; + gctBOOL isrInitialized; + gctBOOL dataReady; + + /* Thread management. */ + struct task_struct *threadCtxt; + struct semaphore sema; + gctBOOL threadInitialized; + gctBOOL killThread; + + /* Signal management. */ + gctINT signal; +} +* gckGALDEVICE; + +#if gcdkUSE_MEMORY_RECORD +typedef struct MEMORY_RECORD +{ + gcuVIDMEM_NODE_PTR node; + + struct MEMORY_RECORD * prev; + struct MEMORY_RECORD * next; +} +MEMORY_RECORD, * MEMORY_RECORD_PTR; +#endif + +typedef struct _gcsHAL_PRIVATE_DATA +{ + gckGALDEVICE device; + gctPOINTER mappedMemory; + gctPOINTER contiguousLogical; + +#if gcdkUSE_MEMORY_RECORD + MEMORY_RECORD memoryRecordList; +#endif +} +gcsHAL_PRIVATE_DATA, * gcsHAL_PRIVATE_DATA_PTR; + +gceSTATUS gckGALDEVICE_Setup_ISR( + IN gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Release_ISR( + IN gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Start_Thread( + IN gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Stop_Thread( + gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Start( + IN gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Stop( + gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Construct( + IN gctINT IrqLine, + IN gctUINT32 RegisterMemBase, + IN gctSIZE_T RegisterMemSize, + IN gctUINT32 ContiguousBase, + IN gctSIZE_T ContiguousSize, + IN gctSIZE_T BankSize, + IN gctINT FastClear, + IN gctINT Compression, + IN gctUINT32 BaseAddress, + IN gctINT Signal, + OUT gckGALDEVICE *Device + ); + +gceSTATUS gckGALDEVICE_Destroy( + IN gckGALDEVICE Device + ); + +#endif /* __gc_hal_kernel_device_h_ */ + diff --git a/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_driver.c b/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_driver.c new file mode 100644 index 000000000000..ce27af5c6672 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_driver.c @@ -0,0 +1,804 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include +#include + + +#include "gc_hal_kernel_linux.h" +#include "gc_hal_driver.h" +#include "gc_hal_user_context.h" + +#if USE_PLATFORM_DRIVER +#include +#endif + +MODULE_DESCRIPTION("Vivante Graphics Driver"); +MODULE_LICENSE("GPL"); + +struct class *gpuClass; + +static gckGALDEVICE galDevice; + +static int major = 199; +module_param(major, int, 0644); + +int irqLine = 0; +module_param(irqLine, int, 0644); + +long registerMemBase = 0x80000000; +module_param(registerMemBase, long, 0644); + +ulong registerMemSize = 256 << 10; +module_param(registerMemSize, ulong, 0644); + +long contiguousSize = 4 << 20; +module_param(contiguousSize, long, 0644); + +ulong contiguousBase = 0; +module_param(contiguousBase, ulong, 0644); + +long bankSize = 32 << 20; +module_param(bankSize, long, 0644); + +int fastClear = -1; +module_param(fastClear, int, 0644); + +int compression = -1; +module_param(compression, int, 0644); + +int signal = 48; +module_param(signal, int, 0644); + +ulong baseAddress = 0; +module_param(baseAddress, ulong, 0644); + +int showArgs = 0; +module_param(showArgs, int, 0644); + +static int drv_open(struct inode *inode, struct file *filp); +static int drv_release(struct inode *inode, struct file *filp); +static int drv_ioctl(struct inode *inode, struct file *filp, + unsigned int ioctlCode, unsigned long arg); +static int drv_mmap(struct file * filp, struct vm_area_struct * vma); + +struct file_operations driver_fops = +{ + .open = drv_open, + .release = drv_release, + .ioctl = drv_ioctl, + .mmap = drv_mmap, +}; + +int drv_open(struct inode *inode, struct file* filp) +{ + gcsHAL_PRIVATE_DATA_PTR private; + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_DRIVER, + "Entering drv_open\n"); + + private = kmalloc(sizeof(gcsHAL_PRIVATE_DATA), GFP_KERNEL); + + if (private == gcvNULL) + { + return -ENOTTY; + } + + private->device = galDevice; + private->mappedMemory = gcvNULL; + private->contiguousLogical = gcvNULL; + +#if gcdkUSE_MEMORY_RECORD + private->memoryRecordList.prev = &private->memoryRecordList; + private->memoryRecordList.next = &private->memoryRecordList; +#endif + + /* A process gets attached. */ + gcmkVERIFY_OK( + gckKERNEL_AttachProcess(galDevice->kernel, gcvTRUE)); + + if (!galDevice->contiguousMapped) + { + gcmkVERIFY_OK(gckOS_MapMemory(galDevice->os, + galDevice->contiguousPhysical, + galDevice->contiguousSize, + &private->contiguousLogical)); + } + + filp->private_data = private; + + return 0; +} + +extern void +OnProcessExit( + IN gckOS Os, + IN gckKERNEL Kernel + ); + +int drv_release(struct inode* inode, struct file* filp) +{ + gcsHAL_PRIVATE_DATA_PTR private; + gckGALDEVICE device; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "Entering drv_close\n"); + + private = filp->private_data; + gcmkASSERT(private != gcvNULL); + + device = private->device; + +#if gcdkUSE_MEMORY_RECORD + FreeAllMemoryRecord(galDevice->os, &private->memoryRecordList); + +#ifdef ANDROID + gcmkVERIFY_OK(gckOS_Delay(galDevice->os, 1000)); +#else + gcmkVERIFY_OK(gckCOMMAND_Stall(device->kernel->command)); +#endif +#endif + + if (!device->contiguousMapped) + { + if (private->contiguousLogical != gcvNULL) + { + gcmkVERIFY_OK(gckOS_UnmapMemory(galDevice->os, + galDevice->contiguousPhysical, + galDevice->contiguousSize, + private->contiguousLogical)); + } + } + + /* A process gets detached. */ + gcmkVERIFY_OK( + gckKERNEL_AttachProcess(galDevice->kernel, gcvFALSE)); + + kfree(private); + filp->private_data = NULL; + + return 0; +} + +int drv_ioctl(struct inode *inode, + struct file *filp, + unsigned int ioctlCode, + unsigned long arg) +{ + gcsHAL_INTERFACE iface; + gctUINT32 copyLen; + DRIVER_ARGS drvArgs; + gckGALDEVICE device; + gceSTATUS status; + gcsHAL_PRIVATE_DATA_PTR private; + + private = filp->private_data; + + if (private == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER, + "[galcore] drv_ioctl: private_data is NULL\n"); + + return -ENOTTY; + } + + device = private->device; + + if (device == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER, + "[galcore] drv_ioctl: device is NULL\n"); + + return -ENOTTY; + } + + if (ioctlCode != IOCTL_GCHAL_INTERFACE + && ioctlCode != IOCTL_GCHAL_KERNEL_INTERFACE) + { + /* Unknown command. Fail the I/O. */ + return -ENOTTY; + } + + /* Get the drvArgs to begin with. */ + copyLen = copy_from_user(&drvArgs, + (void *) arg, + sizeof(DRIVER_ARGS)); + + if (copyLen != 0) + { + /* The input buffer is not big enough. So fail the I/O. */ + return -ENOTTY; + } + + /* Now bring in the gcsHAL_INTERFACE structure. */ + if ((drvArgs.InputBufferSize != sizeof(gcsHAL_INTERFACE)) + || (drvArgs.OutputBufferSize != sizeof(gcsHAL_INTERFACE)) + ) + { + return -ENOTTY; + } + + copyLen = copy_from_user(&iface, + drvArgs.InputBuffer, + sizeof(gcsHAL_INTERFACE)); + + if (copyLen != 0) + { + /* The input buffer is not big enough. So fail the I/O. */ + return -ENOTTY; + } + +#if gcdkUSE_MEMORY_RECORD + if (iface.command == gcvHAL_EVENT_COMMIT) + { + MEMORY_RECORD_PTR mr; + gcsQUEUE_PTR queue = iface.u.Event.queue; + + while (queue != gcvNULL) + { + gcsQUEUE_PTR record, next; + + /* Map record into kernel memory. */ + gcmkERR_BREAK(gckOS_MapUserPointer(device->os, + queue, + gcmSIZEOF(gcsQUEUE), + (gctPOINTER *) &record)); + + switch (record->iface.command) + { + case gcvHAL_FREE_VIDEO_MEMORY: + mr = FindMemoryRecord(device->os, + &private->memoryRecordList, + record->iface.u.FreeVideoMemory.node); + + if (mr != gcvNULL) + { + DestoryMemoryRecord(device->os, mr); + } + else + { + printk("*ERROR* Invalid video memory (%p) for free\n", + record->iface.u.FreeVideoMemory.node); + } + break; + + default: + break; + } + + /* Next record in the queue. */ + next = record->next; + + /* Unmap record from kernel memory. */ + gcmkERR_BREAK(gckOS_UnmapUserPointer(device->os, + queue, + gcmSIZEOF(gcsQUEUE), + (gctPOINTER *) record)); + queue = next; + } + } +#endif + + status = gckKERNEL_Dispatch(device->kernel, + (ioctlCode == IOCTL_GCHAL_INTERFACE) , &iface); + + if (gcmIS_ERROR(status)) + { + gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DRIVER, + "[galcore] gckKERNEL_Dispatch returned %d.\n", + status); + } + + else if (gcmIS_ERROR(iface.status)) + { + gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DRIVER, + "[galcore] IOCTL %d returned %d.\n", + iface.command, + iface.status); + } + + /* See if this was a LOCK_VIDEO_MEMORY command. */ + else if (iface.command == gcvHAL_LOCK_VIDEO_MEMORY) + { + /* Special case for mapped memory. */ + if (private->mappedMemory != gcvNULL + && iface.u.LockVideoMemory.node->VidMem.memory->object.type + == gcvOBJ_VIDMEM) + { + /* Compute offset into mapped memory. */ + gctUINT32 offset = (gctUINT8 *) iface.u.LockVideoMemory.memory + - (gctUINT8 *) device->contiguousBase; + + /* Compute offset into user-mapped region. */ + iface.u.LockVideoMemory.memory = + (gctUINT8 *) private->mappedMemory + offset; + } + } +#if gcdkUSE_MEMORY_RECORD + else if (iface.command == gcvHAL_ALLOCATE_VIDEO_MEMORY) + { + CreateMemoryRecord(device->os, + &private->memoryRecordList, + iface.u.AllocateVideoMemory.node); + } + else if (iface.command == gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY) + { + CreateMemoryRecord(device->os, + &private->memoryRecordList, + iface.u.AllocateLinearVideoMemory.node); + } + else if (iface.command == gcvHAL_FREE_VIDEO_MEMORY) + { + MEMORY_RECORD_PTR mr; + + mr = FindMemoryRecord(device->os, + &private->memoryRecordList, + iface.u.FreeVideoMemory.node); + + if (mr != gcvNULL) + { + DestoryMemoryRecord(device->os, mr); + } + else + { + printk("*ERROR* Invalid video memory for free\n"); + } + } +#endif + + /* Copy data back to the user. */ + copyLen = copy_to_user(drvArgs.OutputBuffer, + &iface, + sizeof(gcsHAL_INTERFACE)); + + if (copyLen != 0) + { + /* The output buffer is not big enough. So fail the I/O. */ + return -ENOTTY; + } + + return 0; +} + +static int drv_mmap(struct file * filp, struct vm_area_struct * vma) +{ + gcsHAL_PRIVATE_DATA_PTR private = filp->private_data; + gckGALDEVICE device; + int ret; + unsigned long size = vma->vm_end - vma->vm_start; + + if (private == gcvNULL) + { + return -ENOTTY; + } + + device = private->device; + + if (device == gcvNULL) + { + return -ENOTTY; + } + + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_flags |= VM_IO | VM_DONTCOPY | VM_DONTEXPAND; + vma->vm_pgoff = 0; + + if (device->contiguousMapped) + { + ret = io_remap_pfn_range(vma, + vma->vm_start, + (gctUINT32) device->contiguousPhysical >> PAGE_SHIFT, + size, + vma->vm_page_prot); + + private->mappedMemory = (ret == 0) ? (gctPOINTER) vma->vm_start : gcvNULL; + + return ret; + } + else + { + return -ENOTTY; + } +} + + +static struct miscdevice miscdev = { + .name = "galcore", + .fops = &driver_fops, + .minor = MISC_DYNAMIC_MINOR, +}; + + + + +#if !USE_PLATFORM_DRIVER +static int __init drv_init(void) +#else +static int drv_init(void) +#endif +{ + int ret; + gckGALDEVICE device; + +#if ENABLE_GPU_CLOCK_BY_DRIVER && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) + struct clk * clk = NULL; +#endif + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_DRIVER, + "Entering drv_init\n"); + +#if ENABLE_GPU_CLOCK_BY_DRIVER && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) + clk = clk_get(NULL, "GCCLK"); + if (IS_ERR(clk)) + { + int retval = PTR_ERR(clk); + printk("clk get error: %d\n", retval); + return -ENODEV; + } + + /* APMU_GC_156M, APMU_GC_624M, APMU_GC_PLL2, APMU_GC_PLL2_DIV2 currently */ + if (clk_set_rate(clk, 624000000)) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER, + "[galcore] Can't set core clock."); + return -EAGAIN; + } + clk_enable(clk); +#endif + + if (showArgs) + { + printk("galcore options:\n"); + printk(" irqLine = %d\n", irqLine); + printk(" registerMemBase = 0x%08lX\n", registerMemBase); + printk(" contiguousSize = %ld\n", contiguousSize); + printk(" contiguousBase = 0x%08lX\n", contiguousBase); + printk(" bankSize = 0x%08lX\n", bankSize); + printk(" fastClear = %d\n", fastClear); + printk(" compression = %d\n", compression); + printk(" signal = %d\n", signal); + printk(" baseAddress = 0x%08lX\n", baseAddress); + } + + /* Create the GAL device. */ + gcmkVERIFY_OK(gckGALDEVICE_Construct(irqLine, + registerMemBase, + registerMemSize, + contiguousBase, + contiguousSize, + bankSize, + fastClear, + compression, + baseAddress, + signal, + &device)); + + /* Start the GAL device. */ + if (gcmIS_ERROR(gckGALDEVICE_Start(device))) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER, + "[galcore] Can't start the gal device.\n"); + + /* Roll back. */ + gckGALDEVICE_Stop(device); + gckGALDEVICE_Destroy(device); + + return -1; + } + + +#if 1 + ret = misc_register(&miscdev); + if (ret < 0) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER, + "[galcore] Could not register misc.\n"); + + /* Roll back. */ + gckGALDEVICE_Stop(device); + gckGALDEVICE_Destroy(device); + + return -1; + } + galDevice = device; +#else + + /* Register the character device. */ + ret = register_chrdev(major, DRV_NAME, &driver_fops); + if (ret < 0) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER, + "[galcore] Could not allocate major number for mmap.\n"); + + /* Roll back. */ + gckGALDEVICE_Stop(device); + gckGALDEVICE_Destroy(device); + + return -1; + } + else + { + if (major == 0) + { + major = ret; + } + } + + galDevice = device; + + gpuClass = class_create(THIS_MODULE, "graphics_class"); + if (IS_ERR(gpuClass)) { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER, + "Failed to create the class.\n"); + return -1; + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) + device_create(gpuClass, NULL, MKDEV(major, 0), NULL, "galcore"); +#else + device_create(gpuClass, NULL, MKDEV(major, 0), "galcore"); +#endif +#endif + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "[galcore] irqLine->%ld, contiguousSize->%lu, memBase->0x%lX\n", + irqLine, + contiguousSize, + registerMemBase); + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_DRIVER, + "[galcore] driver registered successfully.\n"); + + return 0; +} + +#if !USE_PLATFORM_DRIVER +static void __exit drv_exit(void) +#else +static void drv_exit(void) +#endif +{ +#if ENABLE_GPU_CLOCK_BY_DRIVER && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) + struct clk * clk = NULL; +#endif + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_DRIVER, + "[galcore] Entering drv_exit\n"); + +#if 1 + misc_deregister(&miscdev); +#else + + device_destroy(gpuClass, MKDEV(major, 0)); + class_destroy(gpuClass); + + unregister_chrdev(major, DRV_NAME); +#endif + + gckGALDEVICE_Stop(galDevice); + gckGALDEVICE_Destroy(galDevice); + +#if ENABLE_GPU_CLOCK_BY_DRIVER && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) + clk = clk_get(NULL, "GCCLK"); + clk_disable(clk); +#endif +} + +#if !USE_PLATFORM_DRIVER +module_init(drv_init); +module_exit(drv_exit); +#else + +#ifdef CONFIG_DOVE_GPU +#define DEVICE_NAME "dove_gpu" +#else +#define DEVICE_NAME "galcore" +#endif + + +static int __devinit gpu_probe(struct platform_device *pdev) +{ + int ret = -ENODEV; + struct resource *res; + res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,"gpu_irq"); + if (!res) { + printk(KERN_ERR "%s: No irq line supplied.\n",__FUNCTION__); + goto gpu_probe_fail; + } + irqLine = res->start; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM,"gpu_base"); + if (!res) { + printk(KERN_ERR "%s: No register base supplied.\n",__FUNCTION__); + goto gpu_probe_fail; + } + registerMemBase = res->start; + registerMemSize = res->end - res->start; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM,"gpu_mem"); + if (!res) { + printk(KERN_ERR "%s: No memory base supplied.\n",__FUNCTION__); + goto gpu_probe_fail; + } + contiguousBase = res->start; + contiguousSize = res->end-res->start; + + ret = drv_init(); + if(!ret) { + platform_set_drvdata(pdev,galDevice); + return ret; + } + +gpu_probe_fail: + printk(KERN_INFO "Failed to register gpu driver.\n"); + return ret; +} + +static int __devinit gpu_remove(struct platform_device *pdev) +{ + drv_exit(); + + return 0; +} + +static int __devinit gpu_suspend(struct platform_device *dev, pm_message_t state) +{ + gceSTATUS status; + gckGALDEVICE device; + + device = platform_get_drvdata(dev); + + status = gckHARDWARE_SetPowerManagementState(device->kernel->hardware, gcvPOWER_OFF); + + if (gcmIS_ERROR(status)) + { + return -1; + } + + return 0; +} + +static int __devinit gpu_resume(struct platform_device *dev) +{ + gceSTATUS status; + gckGALDEVICE device; + + device = platform_get_drvdata(dev); + + status = gckHARDWARE_SetPowerManagementState(device->kernel->hardware, gcvPOWER_ON); + + if (gcmIS_ERROR(status)) + { + return -1; + } + + return 0; +} + +static struct platform_driver gpu_driver = { + .probe = gpu_probe, + .remove = gpu_remove, + + .suspend = gpu_suspend, + .resume = gpu_resume, + + .driver = { + .name = DEVICE_NAME, + } +}; + +#if 0 +#ifndef CONFIG_DOVE_GPU +static struct resource gpu_resources[] = { + { + .name = "gpu_irq", + .flags = IORESOURCE_IRQ, + }, + { + .name = "gpu_base", + .flags = IORESOURCE_MEM, + }, + { + .name = "gpu_mem", + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device * gpu_device; +#endif +#endif + +static int __init gpu_init(void) +{ + int ret = 0; + +#if 0 //add by dkm +#ifndef CONFIG_DOVE_GPU + gpu_resources[0].start = gpu_resources[0].end = irqLine; + + gpu_resources[1].start = registerMemBase; + gpu_resources[1].end = registerMemBase + registerMemSize; + + gpu_resources[2].start = contiguousBase; + gpu_resources[2].end = contiguousBase + contiguousSize; + + /* Allocate device */ + gpu_device = platform_device_alloc(DEVICE_NAME, -1); + if (!gpu_device) + { + printk(KERN_ERR "galcore: platform_device_alloc failed.\n"); + ret = -ENOMEM; + goto out; + } + + /* Insert resource */ + ret = platform_device_add_resources(gpu_device, gpu_resources, 3); + if (ret) + { + printk(KERN_ERR "galcore: platform_device_add_resources failed.\n"); + goto put_dev; + } + + /* Add device */ + ret = platform_device_add(gpu_device); + if (ret) + { + printk(KERN_ERR "galcore: platform_device_add failed.\n"); + goto del_dev; + } +#endif +#endif + ret = platform_driver_register(&gpu_driver); + if (!ret) + { + goto out; + } + +#if 0 //add by dkm +#ifndef CONFIG_DOVE_GPU +del_dev: + platform_device_del(gpu_device); +put_dev: + platform_device_put(gpu_device); +#endif +#endif + +out: + return ret; + +} + +static void __exit gpu_exit(void) +{ + platform_driver_unregister(&gpu_driver); +#if 0 //add by dkm +#ifndef CONFIG_DOVE_GPU + platform_device_unregister(gpu_device); +#endif +#endif +} + +module_init(gpu_init); +module_exit(gpu_exit); + +#endif + diff --git a/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_linux.c b/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_linux.c new file mode 100644 index 000000000000..36546c9ae899 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_linux.c @@ -0,0 +1,411 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_linux.h" + +#define _GC_OBJ_ZONE gcvZONE_KERNEL + +/******************************************************************************\ +******************************* gckKERNEL API Code ****************************** +\******************************************************************************/ + +/******************************************************************************* +** +** gckKERNEL_QueryVideoMemory +** +** Query the amount of video memory. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** OUTPUT: +** +** gcsHAL_INTERFACE * Interface +** Pointer to an gcsHAL_INTERFACE structure that will be filled in with +** the memory information. +*/ +gceSTATUS +gckKERNEL_QueryVideoMemory( + IN gckKERNEL Kernel, + OUT gcsHAL_INTERFACE * Interface + ) +{ + gckGALDEVICE device; + + gcmkHEADER_ARG("Kernel=%p", Kernel); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Interface != NULL); + + /* Extract the pointer to the gckGALDEVICE class. */ + device = (gckGALDEVICE) Kernel->context; + + /* Get internal memory size and physical address. */ + Interface->u.QueryVideoMemory.internalSize = device->internalSize; + Interface->u.QueryVideoMemory.internalPhysical = device->internalPhysical; + + /* Get external memory size and physical address. */ + Interface->u.QueryVideoMemory.externalSize = device->externalSize; + Interface->u.QueryVideoMemory.externalPhysical = device->externalPhysical; + + /* Get contiguous memory size and physical address. */ + Interface->u.QueryVideoMemory.contiguousSize = device->contiguousSize; + Interface->u.QueryVideoMemory.contiguousPhysical = device->contiguousPhysical; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckKERNEL_GetVideoMemoryPool +** +** Get the gckVIDMEM object belonging to the specified pool. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gcePOOL Pool +** Pool to query gckVIDMEM object for. +** +** OUTPUT: +** +** gckVIDMEM * VideoMemory +** Pointer to a variable that will hold the pointer to the gckVIDMEM +** object belonging to the requested pool. +*/ +gceSTATUS +gckKERNEL_GetVideoMemoryPool( + IN gckKERNEL Kernel, + IN gcePOOL Pool, + OUT gckVIDMEM * VideoMemory + ) +{ + gckGALDEVICE device; + gckVIDMEM videoMemory; + + gcmkHEADER_ARG("Kernel=%p Pool=%d", Kernel, Pool); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(VideoMemory != NULL); + + /* Extract the pointer to the gckGALDEVICE class. */ + device = (gckGALDEVICE) Kernel->context; + + /* Dispatch on pool. */ + switch (Pool) + { + case gcvPOOL_LOCAL_INTERNAL: + /* Internal memory. */ + videoMemory = device->internalVidMem; + break; + + case gcvPOOL_LOCAL_EXTERNAL: + /* External memory. */ + videoMemory = device->externalVidMem; + break; + + case gcvPOOL_SYSTEM: + /* System memory. */ + videoMemory = device->contiguousVidMem; + break; + + default: + /* Unknown pool. */ + videoMemory = NULL; + } + + /* Return pointer to the gckVIDMEM object. */ + *VideoMemory = videoMemory; + + /* Return status. */ + gcmkFOOTER_ARG("*VideoMemory=%p", *VideoMemory); + return (videoMemory == NULL) ? gcvSTATUS_OUT_OF_MEMORY : gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckKERNEL_MapMemory +** +** Map video memory into the current process space. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gctPHYS_ADDR Physical +** Physical address of video memory to map. +** +** gctSIZE_T Bytes +** Number of bytes to map. +** +** OUTPUT: +** +** gctPOINTER * Logical +** Pointer to a variable that will hold the base address of the mapped +** memory region. +*/ +gceSTATUS +gckKERNEL_MapMemory( + IN gckKERNEL Kernel, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Logical + ) +{ + return gckOS_MapMemory(Kernel->os, Physical, Bytes, Logical); +} + +/******************************************************************************* +** +** gckKERNEL_UnmapMemory +** +** Unmap video memory from the current process space. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gctPHYS_ADDR Physical +** Physical address of video memory to map. +** +** gctSIZE_T Bytes +** Number of bytes to map. +** +** gctPOINTER Logical +** Base address of the mapped memory region. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckKERNEL_UnmapMemory( + IN gckKERNEL Kernel, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + IN gctPOINTER Logical + ) +{ + return gckOS_UnmapMemory(Kernel->os, Physical, Bytes, Logical); +} + +/******************************************************************************* +** +** gckKERNEL_MapVideoMemory +** +** Get the logical address for a hardware specific memory address for the +** current process. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gctBOOL InUserSpace +** gcvTRUE to map the memory into the user space. +** +** gctUINT32 Address +** Hardware specific memory address. +** +** OUTPUT: +** +** gctPOINTER * Logical +** Pointer to a variable that will hold the logical address of the +** specified memory address. +*/ +gceSTATUS +gckKERNEL_MapVideoMemory( + IN gckKERNEL Kernel, + IN gctBOOL InUserSpace, + IN gctUINT32 Address, + OUT gctPOINTER * Logical + ) +{ + gckGALDEVICE device; + PLINUX_MDL mdl; + PLINUX_MDL_MAP mdlMap; + gcePOOL pool; + gctUINT32 offset, base; + gceSTATUS status; + gctPOINTER logical; + + gcmkHEADER_ARG("Kernel=%p InUserSpace=%d Address=%08x", + Kernel, InUserSpace, Address); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Logical != NULL); + + /* Extract the pointer to the gckGALDEVICE class. */ + device = (gckGALDEVICE) Kernel->context; + + /* Split the memory address into a pool type and offset. */ + gcmkONERROR( + gckHARDWARE_SplitMemory(Kernel->hardware, Address, &pool, &offset)); + + /* Dispatch on pool. */ + switch (pool) + { + case gcvPOOL_LOCAL_INTERNAL: + /* Internal memory. */ + logical = device->internalLogical; + break; + + case gcvPOOL_LOCAL_EXTERNAL: + /* External memory. */ + logical = device->externalLogical; + break; + + case gcvPOOL_SYSTEM: + /* System memory. */ + if (device->contiguousMapped) + { + logical = device->contiguousBase; + } + else + { + mdl = (PLINUX_MDL) device->contiguousPhysical; + + mdlMap = FindMdlMap(mdl, current->tgid); + gcmkASSERT(mdlMap); + + logical = (gctPOINTER) mdlMap->vmaAddr; + } + + gcmkVERIFY_OK( + gckHARDWARE_SplitMemory(Kernel->hardware, + device->contiguousVidMem->baseAddress, + &pool, + &base)); + + offset -= base; + break; + + default: + /* Invalid memory pool. */ + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + /* Build logical address of specified address. */ + *Logical = (gctPOINTER) ((gctUINT8_PTR) logical + offset); + + /* Success. */ + gcmkFOOTER_ARG("*Logical=%p", *Logical); + return gcvSTATUS_OK; + +OnError: + /* Retunn the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckKERNEL_Notify +** +** This function iscalled by clients to notify the gckKERNRL object of an event. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gceNOTIFY Notification +** Notification event. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckKERNEL_Notify( + IN gckKERNEL Kernel, + IN gceNOTIFY Notification, + IN gctBOOL Data + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Kernel=%p Notification=%d Data=%d", + Kernel, Notification, Data); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + + /* Dispatch on notifcation. */ + switch (Notification) + { + case gcvNOTIFY_INTERRUPT: + /* Process the interrupt. */ +#if COMMAND_PROCESSOR_VERSION > 1 + status = gckINTERRUPT_Notify(Kernel->interrupt, Data); +#else + status = gckHARDWARE_Interrupt(Kernel->hardware, Data); +#endif + break; + + default: + status = gcvSTATUS_OK; + break; + } + + /* Success. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckKERNEL_QuerySettings( + IN gckKERNEL Kernel, + OUT gcsKERNEL_SETTINGS * Settings + ) +{ + gckGALDEVICE device; + + gcmkHEADER_ARG("Kernel=%p", Kernel); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Settings != gcvNULL); + + /* Extract the pointer to the gckGALDEVICE class. */ + device = (gckGALDEVICE) Kernel->context; + + /* Fill in signal. */ + Settings->signal = device->signal; + + /* Success. */ + gcmkFOOTER_ARG("Settings->signal=%d", Settings->signal); + return gcvSTATUS_OK; +} + diff --git a/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_linux.h b/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_linux.h new file mode 100644 index 000000000000..de767ea913e2 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_linux.h @@ -0,0 +1,89 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_kernel_linux_h_ +#define __gc_hal_kernel_linux_h_ + +#include +#include +#include +#include +#include +#include +#include +#ifdef FLAREON +# include +#endif +#include +#include +#include +#include + +#ifdef MODVERSIONS +# include +#endif +#include +#include + +#if ENABLE_GPU_CLOCK_BY_DRIVER && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) +#include +#endif + +#define NTSTRSAFE_NO_CCH_FUNCTIONS +#include "gc_hal.h" +#include "gc_hal_driver.h" +#include "gc_hal_kernel.h" +#include "gc_hal_kernel_device.h" +#include "gc_hal_kernel_os.h" + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) +#define FIND_TASK_BY_PID(x) pid_task(find_vpid(x), PIDTYPE_PID) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) +#define FIND_TASK_BY_PID(x) find_task_by_vpid(x) +#else +#define FIND_TASK_BY_PID(x) find_task_by_pid(x) +#endif + +#define _WIDE(string) L##string +#define WIDE(string) _WIDE(string) + +#define countof(a) (sizeof(a) / sizeof(a[0])) + +#define DRV_NAME "galcore" + +#define GetPageCount(size, offset) ((((size) + ((offset) & ~PAGE_CACHE_MASK)) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT) + +static inline gctINT +GetOrder( + IN gctINT numPages + ) +{ + gctINT order = 0; + + while ((1 << order) < numPages) order++; + + return order; +} + +#endif /* __gc_hal_kernel_linux_h_ */ + diff --git a/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_os.c b/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_os.c new file mode 100644 index 000000000000..9f63033c05ce --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_os.c @@ -0,0 +1,5698 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_linux.h" + +#include +#include +#include +#include +#include +#include +#ifdef NO_DMA_COHERENT +#include +#endif /* NO_DMA_COHERENT */ + +#if !USE_NEW_LINUX_SIGNAL +#define USER_SIGNAL_TABLE_LEN_INIT 64 +#endif + +#define _GC_OBJ_ZONE gcvZONE_OS + +#define MEMORY_LOCK(os) \ + gcmkVERIFY_OK(gckOS_AcquireMutex( \ + (os), \ + (os)->memoryLock, \ + gcvINFINITE)) + +#define MEMORY_UNLOCK(os) \ + gcmkVERIFY_OK(gckOS_ReleaseMutex((os), (os)->memoryLock)) + +#define MEMORY_MAP_LOCK(os) \ + gcmkVERIFY_OK(gckOS_AcquireMutex( \ + (os), \ + (os)->memoryMapLock, \ + gcvINFINITE)) + +#define MEMORY_MAP_UNLOCK(os) \ + gcmkVERIFY_OK(gckOS_ReleaseMutex((os), (os)->memoryMapLock)) + +/******************************************************************************\ +********************************** Structures ********************************** +\******************************************************************************/ + +struct _gckOS +{ + /* Object. */ + gcsOBJECT object; + + /* Heap. */ + gckHEAP heap; + + /* Pointer to device */ + gckGALDEVICE device; + + /* Memory management */ + gctPOINTER memoryLock; + gctPOINTER memoryMapLock; + + struct _LINUX_MDL *mdlHead; + struct _LINUX_MDL *mdlTail; + + gctUINT32 baseAddress; + + /* Kernel process ID. */ + gctUINT32 kernelProcessID; + +#if !USE_NEW_LINUX_SIGNAL + /* Signal management. */ + struct _signal { + /* Unused signal ID number. */ + gctINT unused; + + /* The pointer to the table. */ + gctPOINTER * table; + + /* Signal table length. */ + gctINT tableLen; + + /* The current unused signal ID. */ + gctINT currentID; + + /* Lock. */ + gctPOINTER lock; + } signal; +#endif +}; + +#if !USE_NEW_LINUX_SIGNAL +typedef struct _gcsSIGNAL +{ + /* Kernel sync primitive. */ + struct completion event; + + /* Manual reset flag. */ + gctBOOL manualReset; + + /* The reference counter. */ + atomic_t ref; + + /* The owner of the signal. */ + gctHANDLE process; +} +gcsSIGNAL; + +typedef struct _gcsSIGNAL * gcsSIGNAL_PTR; +#endif + +typedef struct _gcsPageInfo * gcsPageInfo_PTR; + +typedef struct _gcsPageInfo +{ + struct page **pages; + gctUINT32_PTR pageTable; +} +gcsPageInfo; + +static PLINUX_MDL +_CreateMdl( + IN gctINT PID + ) +{ + PLINUX_MDL mdl; + + mdl = (PLINUX_MDL)kmalloc(sizeof(struct _LINUX_MDL), GFP_ATOMIC); + if (mdl == gcvNULL) return gcvNULL; + + mdl->pid = PID; + mdl->maps = gcvNULL; + mdl->prev = gcvNULL; + mdl->next = gcvNULL; + + return mdl; +} + +static gceSTATUS +_DestroyMdlMap( + IN PLINUX_MDL Mdl, + IN PLINUX_MDL_MAP MdlMap + ); + +static gceSTATUS +_DestroyMdl( + IN PLINUX_MDL Mdl + ) +{ + PLINUX_MDL_MAP mdlMap, next; + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Mdl != gcvNULL); + + mdlMap = Mdl->maps; + + while (mdlMap != gcvNULL) + { + next = mdlMap->next; + + gcmkVERIFY_OK(_DestroyMdlMap(Mdl, mdlMap)); + + mdlMap = next; + } + + kfree(Mdl); + + return gcvSTATUS_OK; +} + +static PLINUX_MDL_MAP +_CreateMdlMap( + IN PLINUX_MDL Mdl, + IN gctINT PID + ) +{ + PLINUX_MDL_MAP mdlMap; + + mdlMap = (PLINUX_MDL_MAP)kmalloc(sizeof(struct _LINUX_MDL_MAP), GFP_ATOMIC); + if (mdlMap == gcvNULL) return gcvNULL; + + mdlMap->pid = PID; + mdlMap->vmaAddr = gcvNULL; + mdlMap->vma = gcvNULL; + + mdlMap->next = Mdl->maps; + Mdl->maps = mdlMap; + + return mdlMap; +} + +static gceSTATUS +_DestroyMdlMap( + IN PLINUX_MDL Mdl, + IN PLINUX_MDL_MAP MdlMap + ) +{ + PLINUX_MDL_MAP prevMdlMap; + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(MdlMap != gcvNULL); + gcmkASSERT(Mdl->maps != gcvNULL); + + if (Mdl->maps == MdlMap) + { + Mdl->maps = MdlMap->next; + } + else + { + prevMdlMap = Mdl->maps; + + while (prevMdlMap->next != MdlMap) + { + prevMdlMap = prevMdlMap->next; + + gcmkASSERT(prevMdlMap != gcvNULL); + } + + prevMdlMap->next = MdlMap->next; + } + + kfree(MdlMap); + + return gcvSTATUS_OK; +} + +extern PLINUX_MDL_MAP +FindMdlMap( + IN PLINUX_MDL Mdl, + IN gctINT PID + ) +{ + PLINUX_MDL_MAP mdlMap; + + mdlMap = Mdl->maps; + + while (mdlMap != gcvNULL) + { + if (mdlMap->pid == PID) return mdlMap; + + mdlMap = mdlMap->next; + } + + return gcvNULL; +} + +void +FreeProcessMemoryOnExit( + IN gckOS Os, + IN gckKERNEL Kernel + ) +{ + PLINUX_MDL mdl, nextMdl; + PLINUX_MDL_MAP mdlMap; + + MEMORY_LOCK(Os); + + mdl = Os->mdlHead; + + while (mdl != gcvNULL) + { + if (mdl != Os->mdlTail) + { + nextMdl = mdl->next; + } + else + { + nextMdl = gcvNULL; + } + + if (mdl->pagedMem) + { + mdlMap = mdl->maps; + + if (mdlMap != gcvNULL + && mdlMap->pid == current->tgid + && mdlMap->next == gcvNULL) + { + MEMORY_UNLOCK(Os); + + gcmkVERIFY_OK(gckOS_FreePagedMemory(Os, mdl, mdl->numPages * PAGE_SIZE)); + + MEMORY_LOCK(Os); + + nextMdl = Os->mdlHead; + } + } + + mdl = nextMdl; + } + + MEMORY_UNLOCK(Os); +} + +void +PrintInfoOnExit( + IN gckOS Os, + IN gckKERNEL Kernel + ) +{ + PLINUX_MDL mdl, nextMdl; + PLINUX_MDL_MAP mdlMap; + + MEMORY_LOCK(Os); + + mdl = Os->mdlHead; + + while (mdl != gcvNULL) + { + if (mdl != Os->mdlTail) + { + nextMdl = mdl->next; + } + else + { + nextMdl = gcvNULL; + } + + printk("Unfreed mdl: %p, pid: %d -> pagedMem: %s, addr: %p, dmaHandle: 0x%x, pages: %d", + mdl, + mdl->pid, + mdl->pagedMem? "true" : "false", + mdl->addr, + mdl->dmaHandle, + mdl->numPages); + + mdlMap = mdl->maps; + + while (mdlMap != gcvNULL) + { + printk("\tmap: %p, pid: %d -> vmaAddr: %p, vma: %p", + mdlMap, + mdlMap->pid, + mdlMap->vmaAddr, + mdlMap->vma); + + mdlMap = mdlMap->next; + } + + mdl = nextMdl; + } + + MEMORY_UNLOCK(Os); +} + +void +OnProcessExit( + IN gckOS Os, + IN gckKERNEL Kernel + ) +{ + /* PrintInfoOnExit(Os, Kernel); */ + +#ifdef ANDROID + FreeProcessMemoryOnExit(Os, Kernel); +#endif +} + +/******************************************************************************* +** +** gckOS_Construct +** +** Construct a new gckOS object. +** +** INPUT: +** +** gctPOINTER Context +** Pointer to the gckGALDEVICE class. +** +** OUTPUT: +** +** gckOS * Os +** Pointer to a variable that will hold the pointer to the gckOS object. +*/ +gceSTATUS +gckOS_Construct( + IN gctPOINTER Context, + OUT gckOS * Os + ) +{ + gckOS os; + gceSTATUS status; + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Os != gcvNULL); + + /* Allocate the gckOS object. */ + os = (gckOS) kmalloc(gcmSIZEOF(struct _gckOS), GFP_ATOMIC); + + if (os == gcvNULL) + { + /* Out of memory. */ + return gcvSTATUS_OUT_OF_MEMORY; + } + + /* Zero the memory. */ + gckOS_ZeroMemory(os, gcmSIZEOF(struct _gckOS)); + + /* Initialize the gckOS object. */ + os->object.type = gcvOBJ_OS; + + /* Set device device. */ + os->device = Context; + + /* IMPORTANT! No heap yet. */ + os->heap = gcvNULL; + + /* Initialize the memory lock. */ + gcmkONERROR(gckOS_CreateMutex(os, &os->memoryLock)); + + gcmkONERROR(gckOS_CreateMutex(os, &os->memoryMapLock)); + + /* Create the gckHEAP object. */ + gcmkONERROR(gckHEAP_Construct(os, gcdHEAP_SIZE, &os->heap)); + + os->mdlHead = os->mdlTail = gcvNULL; + + /* Find the base address of the physical memory. */ + os->baseAddress = os->device->baseAddress; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, + "Physical base address set to 0x%08X.", + os->baseAddress); + + /* Get the kernel process ID. */ + gcmkONERROR(gckOS_GetProcessID(&os->kernelProcessID)); + +#if !USE_NEW_LINUX_SIGNAL + /* + * Initialize the signal manager. + * It creates the signals to be used in + * the user space. + */ + + /* Initialize mutex. */ + gcmkONERROR( + gckOS_CreateMutex(os, &os->signal.lock)); + + /* Initialize the signal table. */ + os->signal.table = + kmalloc(gcmSIZEOF(gctPOINTER) * USER_SIGNAL_TABLE_LEN_INIT, GFP_KERNEL); + + if (os->signal.table == gcvNULL) + { + /* Out of memory. */ + status = gcvSTATUS_OUT_OF_MEMORY; + goto OnError; + } + + gckOS_ZeroMemory(os->signal.table, + gcmSIZEOF(gctPOINTER) * USER_SIGNAL_TABLE_LEN_INIT); + + /* Set the signal table length. */ + os->signal.tableLen = USER_SIGNAL_TABLE_LEN_INIT; + + /* The table is empty. */ + os->signal.unused = os->signal.tableLen; + + /* Initial signal ID. */ + os->signal.currentID = 0; +#endif + + /* Return pointer to the gckOS object. */ + *Os = os; + + /* Success. */ + return gcvSTATUS_OK; + +OnError: +#if !USE_NEW_LINUX_SIGNAL + /* Roll back any allocation. */ + if (os->signal.table != gcvNULL) + { + kfree(os->signal.table); + } + + if (os->signal.lock != gcvNULL) + { + gcmkVERIFY_OK( + gckOS_DeleteMutex(os, os->signal.lock)); + } +#endif + + if (os->heap != gcvNULL) + { + gcmkVERIFY_OK( + gckHEAP_Destroy(os->heap)); + } + + if (os->memoryMapLock != gcvNULL) + { + gcmkVERIFY_OK( + gckOS_DeleteMutex(os, os->memoryMapLock)); + } + + if (os->memoryLock != gcvNULL) + { + gcmkVERIFY_OK( + gckOS_DeleteMutex(os, os->memoryLock)); + } + + kfree(os); + + /* Return the error. */ + return status; +} + +/******************************************************************************* +** +** gckOS_Destroy +** +** Destroy an gckOS object. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object that needs to be destroyed. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_Destroy( + IN gckOS Os + ) +{ + gckHEAP heap; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + +#if !USE_NEW_LINUX_SIGNAL + /* + * Destroy the signal manager. + */ + + /* Destroy the mutex. */ + gcmkVERIFY_OK( + gckOS_DeleteMutex(Os, Os->signal.lock)); + + /* Free the signal table. */ + kfree(Os->signal.table); +#endif + + if (Os->heap != NULL) + { + /* Mark gckHEAP as gone. */ + heap = Os->heap; + Os->heap = NULL; + + /* Destroy the gckHEAP object. */ + gcmkVERIFY_OK( + gckHEAP_Destroy(heap)); + } + + /* Destroy the memory lock. */ + gcmkVERIFY_OK( + gckOS_DeleteMutex(Os, Os->memoryMapLock)); + + gcmkVERIFY_OK( + gckOS_DeleteMutex(Os, Os->memoryLock)); + + gcmkPRINT("$$FLUSH$$"); + + /* Mark the gckOS object as unknown. */ + Os->object.type = gcvOBJ_UNKNOWN; + + /* Free the gckOS object. */ + kfree(Os); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_Allocate +** +** Allocate memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIZE_T Bytes +** Number of bytes to allocate. +** +** OUTPUT: +** +** gctPOINTER * Memory +** Pointer to a variable that will hold the allocated memory location. +*/ +gceSTATUS +gckOS_Allocate( + IN gckOS Os, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ) +{ + gceSTATUS status; + + //gcmkHEADER_ARG("Os=0x%x Bytes=%lu", Os, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Memory != NULL); + + /* Do we have a heap? */ + if (Os->heap != NULL) + { + /* Allocate from the heap. */ + gcmkONERROR(gckHEAP_Allocate(Os->heap, Bytes, Memory)); + } + else + { + gcmkONERROR(gckOS_AllocateMemory(Os, Bytes, Memory)); + } + + /* Success. */ + //gcmkFOOTER_ARG("*memory=0x%x", *Memory); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_Free +** +** Free allocated memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Memory +** Pointer to memory allocation to free. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_Free( + IN gckOS Os, + IN gctPOINTER Memory + ) +{ + gceSTATUS status; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Memory != NULL); + + //gcmkHEADER_ARG("Os=0x%x Memory=0x%x", Os, memory); + + /* Do we have a heap? */ + if (Os->heap != NULL) + { + /* Free from the heap. */ + gcmkONERROR(gckHEAP_Free(Os->heap, Memory)); + } + else + { + gcmkONERROR(gckOS_FreeMemory(Os, Memory)); + } + + /* Success. */ + //gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_AllocateMemory +** +** Allocate memory wrapper. +** +** INPUT: +** +** gctSIZE_T Bytes +** Number of bytes to allocate. +** +** OUTPUT: +** +** gctPOINTER * Memory +** Pointer to a variable that will hold the allocated memory location. +*/ +gceSTATUS +gckOS_AllocateMemory( + IN gckOS Os, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ) +{ + gctPOINTER memory; + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%x Bytes=%lu", Os, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Memory != NULL); + + memory = (gctPOINTER) kmalloc(Bytes, GFP_ATOMIC); + + if (memory == NULL) + { + /* Out of memory. */ + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + /* Return pointer to the memory allocation. */ + *Memory = memory; + + /* Success. */ + gcmkFOOTER_ARG("*Memory=%p", *Memory); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_FreeMemory +** +** Free allocated memory wrapper. +** +** INPUT: +** +** gctPOINTER Memory +** Pointer to memory allocation to free. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_FreeMemory( + IN gckOS Os, + IN gctPOINTER Memory + ) +{ + gcmkHEADER_ARG("Memory=%p", Memory); + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Memory != NULL); + + /* Free the memory from the OS pool. */ + kfree(Memory); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_MapMemory +** +** Map physical memory into the current process. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Start of physical address memory. +** +** gctSIZE_T Bytes +** Number of bytes to map. +** +** OUTPUT: +** +** gctPOINTER * Memory +** Pointer to a variable that will hold the logical address of the +** mapped memory. +*/ +gceSTATUS +gckOS_MapMemory( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Logical + ) +{ + PLINUX_MDL_MAP mdlMap; + PLINUX_MDL mdl = (PLINUX_MDL)Physical; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != 0); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Logical != NULL); + + MEMORY_LOCK(Os); + + mdlMap = FindMdlMap(mdl, current->tgid); + + if (mdlMap == gcvNULL) + { + mdlMap = _CreateMdlMap(mdl, current->tgid); + + if (mdlMap == gcvNULL) + { + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_MEMORY; + } + } + + if (mdlMap->vmaAddr == gcvNULL) + { + down_write(¤t->mm->mmap_sem); + + mdlMap->vmaAddr = (char *)do_mmap_pgoff(NULL, + 0L, + mdl->numPages * PAGE_SIZE, + PROT_READ | PROT_WRITE, + MAP_SHARED, + 0); + + if (mdlMap->vmaAddr == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_MapMemory: do_mmap_pgoff error"); + + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "[gckOS_MapMemory] mdl->numPages: %d", + "[gckOS_MapMemory] mdl->vmaAddr: 0x%x", + mdl->numPages, + mdlMap->vmaAddr + ); + + up_write(¤t->mm->mmap_sem); + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_MEMORY; + } + + mdlMap->vma = find_vma(current->mm, (unsigned long)mdlMap->vmaAddr); + + if (!mdlMap->vma) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_MapMemory: find_vma error."); + + mdlMap->vmaAddr = gcvNULL; + + up_write(¤t->mm->mmap_sem); + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_RESOURCES; + } + +#ifndef NO_DMA_COHERENT + if (dma_mmap_coherent(NULL, + mdlMap->vma, + mdl->addr, + mdl->dmaHandle, + mdl->numPages * PAGE_SIZE) < 0) + { + up_write(¤t->mm->mmap_sem); + + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_MapMemory: dma_mmap_coherent error."); + + mdlMap->vmaAddr = gcvNULL; + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_RESOURCES; + } +#else + mdlMap->vma->vm_page_prot = pgprot_noncached(mdlMap->vma->vm_page_prot); + mdlMap->vma->vm_flags |= VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_RESERVED; + mdlMap->vma->vm_pgoff = 0; + + if (remap_pfn_range(mdlMap->vma, + mdlMap->vma->vm_start, + mdl->dmaHandle >> PAGE_SHIFT, + mdl->numPages*PAGE_SIZE, + mdlMap->vma->vm_page_prot) < 0) + { + up_write(¤t->mm->mmap_sem); + + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_MapMemory: remap_pfn_range error."); + + mdlMap->vmaAddr = gcvNULL; + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_RESOURCES; + } +#endif + + up_write(¤t->mm->mmap_sem); + } + + MEMORY_UNLOCK(Os); + + *Logical = mdlMap->vmaAddr; + + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_OS, + "gckOS_MapMemory: User Mapped address for 0x%x is 0x%x pid->%d", + (gctUINT32)mdl->addr, + (gctUINT32)*Logical, + mdlMap->pid); + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_UnmapMemory +** +** Unmap physical memory out of the current process. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Start of physical address memory. +** +** gctSIZE_T Bytes +** Number of bytes to unmap. +** +** gctPOINTER Memory +** Pointer to a previously mapped memory region. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_UnmapMemory( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + IN gctPOINTER Logical + ) +{ + PLINUX_MDL_MAP mdlMap; + PLINUX_MDL mdl = (PLINUX_MDL)Physical; + struct task_struct * task; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != 0); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Logical != NULL); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "in gckOS_UnmapMemory"); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_UnmapMemory Will be unmapping 0x%x mdl->0x%x", + (gctUINT32)Logical, + (gctUINT32)mdl); + + MEMORY_LOCK(Os); + + if (Logical) + { + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, + gcvZONE_OS, + "[gckOS_UnmapMemory] Logical: 0x%x", + Logical + ); + + mdlMap = FindMdlMap(mdl, current->tgid); + + if (mdlMap == gcvNULL || mdlMap->vmaAddr == gcvNULL) + { + MEMORY_UNLOCK(Os); + + return gcvSTATUS_INVALID_ARGUMENT; + } + + /* Get the current pointer for the task with stored pid. */ + task = FIND_TASK_BY_PID(mdlMap->pid); + + if (task != gcvNULL && task->mm != gcvNULL) + { + down_write(&task->mm->mmap_sem); + do_munmap(task->mm, (unsigned long)Logical, mdl->numPages*PAGE_SIZE); + up_write(&task->mm->mmap_sem); + } + else + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "Can't find the task with pid->%d. No unmapping", + mdlMap->pid); + } + + gcmkVERIFY_OK(_DestroyMdlMap(mdl, mdlMap)); + } + + MEMORY_UNLOCK(Os); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AllocateNonPagedMemory +** +** Allocate a number of pages from non-paged memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctBOOL InUserSpace +** gcvTRUE if the pages need to be mapped into user space. +** +** gctSIZE_T * Bytes +** Pointer to a variable that holds the number of bytes to allocate. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that hold the number of bytes allocated. +** +** gctPHYS_ADDR * Physical +** Pointer to a variable that will hold the physical address of the +** allocation. +** +** gctPOINTER * Logical +** Pointer to a variable that will hold the logical address of the +** allocation. +*/ +gceSTATUS +gckOS_AllocateNonPagedMemory( + IN gckOS Os, + IN gctBOOL InUserSpace, + IN OUT gctSIZE_T * Bytes, + OUT gctPHYS_ADDR * Physical, + OUT gctPOINTER * Logical + ) +{ + gctSIZE_T bytes; + gctINT numPages; + PLINUX_MDL mdl; + PLINUX_MDL_MAP mdlMap = 0; + gctSTRING addr; + +#ifdef NO_DMA_COHERENT + struct page * page; + long size, order; + gctPOINTER vaddr; +#endif + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT((Bytes != NULL) && (*Bytes > 0)); + gcmkVERIFY_ARGUMENT(Physical != NULL); + gcmkVERIFY_ARGUMENT(Logical != NULL); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "in gckOS_AllocateNonPagedMemory"); + + /* Align number of bytes to page size. */ + bytes = gcmALIGN(*Bytes, PAGE_SIZE); + + /* Get total number of pages.. */ + numPages = GetPageCount(bytes, 0); + + /* Allocate mdl+vector structure */ + mdl = _CreateMdl(current->tgid); + + if (mdl == gcvNULL) + { + return gcvSTATUS_OUT_OF_MEMORY; + } + + mdl->pagedMem = 0; + mdl->numPages = numPages; + + MEMORY_LOCK(Os); + +#ifndef NO_DMA_COHERENT + addr = dma_alloc_coherent(NULL, + mdl->numPages * PAGE_SIZE, + &mdl->dmaHandle, + GFP_ATOMIC); +#else + size = mdl->numPages * PAGE_SIZE; + order = get_order(size); + page = alloc_pages(GFP_KERNEL | GFP_DMA, order); + + if (page == gcvNULL) + { + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_MEMORY; + } + + vaddr = (gctPOINTER)page_address(page); + addr = ioremap_nocache(virt_to_phys(vaddr), size); + mdl->dmaHandle = virt_to_phys(vaddr); + mdl->kaddr = vaddr; + +#if ENABLE_ARM_L2_CACHE + dma_cache_maint(vaddr, size, DMA_FROM_DEVICE); +#endif + + while (size > 0) + { + SetPageReserved(virt_to_page(vaddr)); + + vaddr += PAGE_SIZE; + size -= PAGE_SIZE; + } +#endif + + if (addr == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "galcore: Can't allocate memorry for size->0x%x", + (gctUINT32)bytes); + + gcmkVERIFY_OK(_DestroyMdl(mdl)); + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_MEMORY; + } + + if ((Os->baseAddress & 0x80000000) != (mdl->dmaHandle & 0x80000000)) + { + mdl->dmaHandle = (mdl->dmaHandle & ~0x80000000) + | (Os->baseAddress & 0x80000000); + } + + mdl->addr = addr; + + /* + * We will not do any mapping from here. + * Mapping will happen from mmap method. + * mdl structure will be used. + */ + + /* Return allocated memory. */ + *Bytes = bytes; + *Physical = (gctPHYS_ADDR) mdl; + + if (InUserSpace) + { + mdlMap = _CreateMdlMap(mdl, current->tgid); + + if (mdlMap == gcvNULL) + { + gcmkVERIFY_OK(_DestroyMdl(mdl)); + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_MEMORY; + } + + /* Only after mmap this will be valid. */ + + /* We need to map this to user space. */ + down_write(¤t->mm->mmap_sem); + + mdlMap->vmaAddr = (gctSTRING)do_mmap_pgoff(gcvNULL, + 0L, + mdl->numPages * PAGE_SIZE, + PROT_READ | PROT_WRITE, + MAP_SHARED, + 0); + + if (mdlMap->vmaAddr == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "galcore: do_mmap_pgoff error"); + + up_write(¤t->mm->mmap_sem); + + gcmkVERIFY_OK(_DestroyMdlMap(mdl, mdlMap)); + gcmkVERIFY_OK(_DestroyMdl(mdl)); + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_MEMORY; + } + + mdlMap->vma = find_vma(current->mm, (unsigned long)mdlMap->vmaAddr); + + if (mdlMap->vma == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "find_vma error"); + + up_write(¤t->mm->mmap_sem); + + gcmkVERIFY_OK(_DestroyMdlMap(mdl, mdlMap)); + gcmkVERIFY_OK(_DestroyMdl(mdl)); + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_RESOURCES; + } + +#ifndef NO_DMA_COHERENT + if (dma_mmap_coherent(NULL, + mdlMap->vma, + mdl->addr, + mdl->dmaHandle, + mdl->numPages * PAGE_SIZE) < 0) + { + up_write(¤t->mm->mmap_sem); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "dma_mmap_coherent error"); + + gcmkVERIFY_OK(_DestroyMdlMap(mdl, mdlMap)); + gcmkVERIFY_OK(_DestroyMdl(mdl)); + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_RESOURCES; + } +#else + mdlMap->vma->vm_page_prot = pgprot_noncached(mdlMap->vma->vm_page_prot); + mdlMap->vma->vm_flags |= VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_RESERVED; + mdlMap->vma->vm_pgoff = 0; + + if (remap_pfn_range(mdlMap->vma, + mdlMap->vma->vm_start, + mdl->dmaHandle >> PAGE_SHIFT, + mdl->numPages * PAGE_SIZE, + mdlMap->vma->vm_page_prot)) + { + up_write(¤t->mm->mmap_sem); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "remap_pfn_range error"); + + gcmkVERIFY_OK(_DestroyMdlMap(mdl, mdlMap)); + gcmkVERIFY_OK(_DestroyMdl(mdl)); + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_RESOURCES; + } +#endif /* NO_DMA_COHERENT */ + + up_write(¤t->mm->mmap_sem); + + *Logical = mdlMap->vmaAddr; + } + else + { + *Logical = (gctPOINTER)mdl->addr; + } + + /* + * Add this to a global list. + * Will be used by get physical address + * and mapuser pointer functions. + */ + + if (!Os->mdlHead) + { + /* Initialize the queue. */ + Os->mdlHead = Os->mdlTail = mdl; + } + else + { + /* Add to the tail. */ + mdl->prev = Os->mdlTail; + Os->mdlTail->next = mdl; + Os->mdlTail = mdl; + } + + MEMORY_UNLOCK(Os); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_AllocateNonPagedMemory: " + "Bytes->0x%x, Mdl->%p, Logical->0x%x dmaHandle->0x%x", + (gctUINT32)bytes, + mdl, + (gctUINT32)mdl->addr, + mdl->dmaHandle); + + if (InUserSpace) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "vmaAddr->0x%x pid->%d", + (gctUINT32)mdlMap->vmaAddr, + mdlMap->pid); + } + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_FreeNonPagedMemory +** +** Free previously allocated and mapped pages from non-paged memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIZE_T Bytes +** Number of bytes allocated. +** +** gctPHYS_ADDR Physical +** Physical address of the allocated memory. +** +** gctPOINTER Logical +** Logical address of the allocated memory. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_FreeNonPagedMemory( + IN gckOS Os, + IN gctSIZE_T Bytes, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical + ) +{ + PLINUX_MDL mdl; + PLINUX_MDL_MAP mdlMap; + struct task_struct * task; + +#ifdef NO_DMA_COHERENT + unsigned size; + gctPOINTER vaddr; +#endif /* NO_DMA_COHERENT */ + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Physical != 0); + gcmkVERIFY_ARGUMENT(Logical != NULL); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "in gckOS_FreeNonPagedMemory"); + + /* Convert physical address into a pointer to a MDL. */ + mdl = (PLINUX_MDL) Physical; + + MEMORY_LOCK(Os); + +#ifndef NO_DMA_COHERENT + dma_free_coherent(gcvNULL, + mdl->numPages * PAGE_SIZE, + mdl->addr, + mdl->dmaHandle); +#else + size = mdl->numPages * PAGE_SIZE; + vaddr = mdl->kaddr; + + while (size > 0) + { + ClearPageReserved(virt_to_page(vaddr)); + + vaddr += PAGE_SIZE; + size -= PAGE_SIZE; + } + + free_pages((unsigned long)mdl->kaddr, get_order(mdl->numPages * PAGE_SIZE)); + + iounmap(mdl->addr); +#endif /* NO_DMA_COHERENT */ + + mdlMap = mdl->maps; + + while (mdlMap != gcvNULL) + { + if (mdlMap->vmaAddr != gcvNULL) + { + /* Get the current pointer for the task with stored pid. */ + task = FIND_TASK_BY_PID(mdlMap->pid); + + if (task != gcvNULL && task->mm != gcvNULL) + { + down_write(&task->mm->mmap_sem); + + if (do_munmap(task->mm, + (unsigned long)mdlMap->vmaAddr, + mdl->numPages * PAGE_SIZE) < 0) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_FreeNonPagedMemory: " + "Unmap Failed ->Mdl->0x%x Logical->0x%x vmaAddr->0x%x", + (gctUINT32)mdl, + (gctUINT32)mdl->addr, + (gctUINT32)mdlMap->vmaAddr); + } + + up_write(&task->mm->mmap_sem); + } + + mdlMap->vmaAddr = gcvNULL; + } + + mdlMap = mdlMap->next; + } + + /* Remove the node from global list.. */ + if (mdl == Os->mdlHead) + { + if ((Os->mdlHead = mdl->next) == gcvNULL) + { + Os->mdlTail = gcvNULL; + } + } + else + { + mdl->prev->next = mdl->next; + if (mdl == Os->mdlTail) + { + Os->mdlTail = mdl->prev; + } + else + { + mdl->next->prev = mdl->prev; + } + } + + MEMORY_UNLOCK(Os); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_FreeNonPagedMemory: " + "Mdl->0x%x Logical->0x%x", + (gctUINT32)mdl, + (gctUINT32)mdl->addr); + + gcmkVERIFY_OK(_DestroyMdl(mdl)); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_ReadRegister +** +** Read data from a register. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctUINT32 Address +** Address of register. +** +** OUTPUT: +** +** gctUINT32 * Data +** Pointer to a variable that receives the data read from the register. +*/ +gceSTATUS gckOS_ReadRegister( + IN gckOS Os, + IN gctUINT32 Address, + OUT gctUINT32 * Data + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Data != NULL); + + *Data = readl((gctUINT8 *)Os->device->registerBase + Address); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_WriteRegister +** +** Write data to a register. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctUINT32 Address +** Address of register. +** +** gctUINT32 Data +** Data for register. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_WriteRegister( + IN gckOS Os, + IN gctUINT32 Address, + IN gctUINT32 Data + ) +{ + writel(Data, (gctUINT8 *)Os->device->registerBase + Address); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_GetPageSize +** +** Get the system's page size. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** OUTPUT: +** +** gctSIZE_T * PageSize +** Pointer to a variable that will receive the system's page size. +*/ +gceSTATUS gckOS_GetPageSize( + IN gckOS Os, + OUT gctSIZE_T * PageSize + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(PageSize != NULL); + + /* Return the page size. */ + *PageSize = (gctSIZE_T) PAGE_SIZE; + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_GetPhysicalAddressProcess +** +** Get the physical system address of a corresponding virtual address for a +** given process. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Logical +** Logical address. +** +** gctUINT ProcessID +** Procedd ID. +** +** OUTPUT: +** +** gctUINT32 * Address +** Poinetr to a variable that receives the 32-bit physical adress. +*/ +gceSTATUS +gckOS_GetPhysicalAddressProcess( + IN gckOS Os, + IN gctPOINTER Logical, + IN gctUINT ProcessID, + OUT gctUINT32 * Address + ) +{ + return gckOS_GetPhysicalAddress(Os, Logical, Address); +} + +/******************************************************************************* +** +** gckOS_GetPhysicalAddress +** +** Get the physical system address of a corresponding virtual address. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Logical +** Logical address. +** +** OUTPUT: +** +** gctUINT32 * Address +** Poinetr to a variable that receives the 32-bit physical adress. +*/ +gceSTATUS gckOS_GetPhysicalAddress( + IN gckOS Os, + IN gctPOINTER Logical, + OUT gctUINT32 * Address + ) +{ + PLINUX_MDL mdl; + PLINUX_MDL_MAP mdlMap; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Address != gcvNULL); + + /* + * Try to search the address in our list. + * This could be an mmaped memory. + * Search in our list. + */ + + MEMORY_LOCK(Os); + + mdl = Os->mdlHead; + + while (mdl != gcvNULL) + { + /* Check for the logical address match. */ + if (mdl->addr + && (gctUINT32)Logical >= (gctUINT32)mdl->addr + && (gctUINT32)Logical < ((gctUINT32)mdl->addr + mdl->numPages*PAGE_SIZE)) + { + if (mdl->dmaHandle) + { + /* The memory was from coherent area. */ + *Address = (gctUINT32)mdl->dmaHandle + + (gctUINT32)((gctUINT32)Logical - (gctUINT32)mdl->addr); + } + else if (mdl->pagedMem) + { + if (mdl->contiguous) + { + *Address = (gctUINT32)virt_to_phys(mdl->addr) + + ((gctUINT32)Logical - (gctUINT32)mdl->addr); + } + else + { + *Address = page_to_phys(vmalloc_to_page((gctSTRING)mdl->addr + + ((gctUINT32)Logical - (gctUINT32)mdl->addr))); + } + } + else + { + *Address = (gctUINT32)virt_to_phys(mdl->addr) + + ((gctUINT32)Logical - (gctUINT32)mdl->addr); + } + break; + } + + mdlMap = FindMdlMap(mdl, current->tgid); + + /* Is the given address within that range. */ + if (mdlMap != gcvNULL + && mdlMap->vmaAddr != gcvNULL + && Logical >= mdlMap->vmaAddr + && Logical < (mdlMap->vmaAddr + mdl->numPages * PAGE_SIZE)) + { + if (mdl->dmaHandle) + { + /* The memory was from coherent area. */ + *Address = (gctUINT32)mdl->dmaHandle + + (gctUINT32)((gctUINT32)Logical + - (gctUINT32)mdlMap->vmaAddr); + } + else if (mdl->pagedMem) + { + if (mdl->contiguous) + { + *Address = (gctUINT32)virt_to_phys(mdl->addr) + + (gctUINT32)(Logical - mdlMap->vmaAddr); + } + else + { + *Address = page_to_phys(vmalloc_to_page((gctSTRING)mdl->addr + + ((gctUINT32)Logical - (gctUINT32)mdlMap->vmaAddr))); + } + } + else + { + /* Return the kernel virtual pointer based on this. */ + *Address = (gctUINT32)virt_to_phys(mdl->addr) + + (gctUINT32)(Logical - mdlMap->vmaAddr); + } + break; + } + + mdl = mdl->next; + } + + /* Subtract base address to get a GPU physical address. */ + gcmkASSERT(*Address >= Os->baseAddress); + *Address -= Os->baseAddress; + + MEMORY_UNLOCK(Os); + + if (mdl == gcvNULL) + { + return gcvSTATUS_INVALID_ARGUMENT; + } + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_MapPhysical +** +** Map a physical address into kernel space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctUINT32 Physical +** Physical address of the memory to map. +** +** gctSIZE_T Bytes +** Number of bytes to map. +** +** OUTPUT: +** +** gctPOINTER * Logical +** Pointer to a variable that receives the base address of the mapped +** memory. +*/ +gceSTATUS gckOS_MapPhysical( + IN gckOS Os, + IN gctUINT32 Physical, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Logical + ) +{ + gctPOINTER logical; + PLINUX_MDL mdl; + gctUINT32 physical; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + + MEMORY_LOCK(Os); + + /* Compute true physical address (before subtraction of the baseAddress). */ + physical = Physical + Os->baseAddress; + + /* Go through our mapping to see if we know this physical address already. */ + mdl = Os->mdlHead; + + while (mdl != gcvNULL) + { + if (mdl->dmaHandle != 0) + { + if ((physical >= mdl->dmaHandle) + && (physical < mdl->dmaHandle + mdl->numPages * PAGE_SIZE) + ) + { + *Logical = mdl->addr + (physical - mdl->dmaHandle); + break; + } + } + + mdl = mdl->next; + } + + if (mdl == gcvNULL) + { + /* Map memory as cached memory. */ + request_mem_region(physical, Bytes, "MapRegion"); + logical = (gctPOINTER) ioremap_nocache(physical, Bytes); + + if (logical == NULL) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, + "gckOS_MapMemory: Failed to ioremap"); + + MEMORY_UNLOCK(Os); + + /* Out of resources. */ + return gcvSTATUS_OUT_OF_RESOURCES; + } + + /* Return pointer to mapped memory. */ + *Logical = logical; + } + + MEMORY_UNLOCK(Os); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, + "gckOS_MapPhysical: " + "Physical->0x%X Bytes->0x%X Logical->0x%X MappingFound->%d", + (gctUINT32) Physical, + (gctUINT32) Bytes, + (gctUINT32) *Logical, + mdl ? 1 : 0); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_UnmapPhysical +** +** Unmap a previously mapped memory region from kernel memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Logical +** Pointer to the base address of the memory to unmap. +** +** gctSIZE_T Bytes +** Number of bytes to unmap. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_UnmapPhysical( + IN gckOS Os, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ) +{ + PLINUX_MDL mdl; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Logical != NULL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + + MEMORY_LOCK(Os); + + mdl = Os->mdlHead; + + while (mdl != gcvNULL) + { + if (mdl->addr != gcvNULL) + { + if (Logical >= (gctPOINTER)mdl->addr + && Logical < (gctPOINTER)((gctSTRING)mdl->addr + mdl->numPages * PAGE_SIZE)) + { + break; + } + } + + mdl = mdl->next; + } + + if (mdl == gcvNULL) + { + /* Unmap the memory. */ + iounmap(Logical); + } + + MEMORY_UNLOCK(Os); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_UnmapPhysical: " + "Logical->0x%x Bytes->0x%x MappingFound(?)->%d", + (gctUINT32)Logical, + (gctUINT32)Bytes, + mdl ? 1 : 0); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_CreateMutex +** +** Create a new mutex. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** OUTPUT: +** +** gctPOINTER * Mutex +** Pointer to a variable that will hold a pointer to the mutex. +*/ +gceSTATUS gckOS_CreateMutex( + IN gckOS Os, + OUT gctPOINTER * Mutex + ) +{ + /* Validate the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Mutex != NULL); + + /* Allocate a FAST_MUTEX structure. */ + *Mutex = (gctPOINTER)kmalloc(sizeof(struct semaphore), GFP_KERNEL); + + if (*Mutex == gcvNULL) + { + return gcvSTATUS_OUT_OF_MEMORY; + } + + /* Initialize the semaphore.. Come up in unlocked state. */ + init_MUTEX(*Mutex); + + /* Return status. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_DeleteMutex +** +** Delete a mutex. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Mutex +** Pointer to the mute to be deleted. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_DeleteMutex( + IN gckOS Os, + IN gctPOINTER Mutex + ) +{ + /* Validate the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Mutex != NULL); + + /* Delete the fast mutex. */ + kfree(Mutex); + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AcquireMutex +** +** Acquire a mutex. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Mutex +** Pointer to the mutex to be acquired. +** +** gctUINT32 Timeout +** Timeout value specified in milliseconds. +** Specify the value of gcvINFINITE to keep the thread suspended +** until the mutex has been acquired. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_AcquireMutex( + IN gckOS Os, + IN gctPOINTER Mutex, + IN gctUINT32 Timeout + ) +{ + /* Validate the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Mutex != NULL); + + if (Timeout == gcvINFINITE) + { + down((struct semaphore *) Mutex); + + /* Success. */ + return gcvSTATUS_OK; + } + + while (gcvTRUE) + { + /* Try to acquire the fast mutex. */ + if (!down_trylock((struct semaphore *) Mutex)) + { + /* Success. */ + return gcvSTATUS_OK; + } + + if (Timeout-- == 0) break; + + /* Wait for 1 millisecond. */ + gcmkVERIFY_OK(gckOS_Delay(Os, 1)); + } + + /* Timeout. */ + return gcvSTATUS_TIMEOUT; +} + +/******************************************************************************* +** +** gckOS_ReleaseMutex +** +** Release an acquired mutex. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Mutex +** Pointer to the mutex to be released. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_ReleaseMutex( + IN gckOS Os, + IN gctPOINTER Mutex + ) +{ + /* Validate the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Mutex != NULL); + + /* Release the fast mutex. */ + up((struct semaphore *) Mutex); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AtomicExchange +** +** Atomically exchange a pair of 32-bit values. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** IN OUT gctINT32_PTR Target +** Pointer to the 32-bit value to exchange. +** +** IN gctINT32 NewValue +** Specifies a new value for the 32-bit value pointed to by Target. +** +** OUT gctINT32_PTR OldValue +** The old value of the 32-bit value pointed to by Target. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_AtomicExchange( + IN gckOS Os, + IN OUT gctUINT32_PTR Target, + IN gctUINT32 NewValue, + OUT gctUINT32_PTR OldValue + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + /* Exchange the pair of 32-bit values. */ + *OldValue = (gctUINT32) atomic_xchg((atomic_t *) Target, (int) NewValue); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AtomicExchangePtr +** +** Atomically exchange a pair of pointers. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** IN OUT gctPOINTER * Target +** Pointer to the 32-bit value to exchange. +** +** IN gctPOINTER NewValue +** Specifies a new value for the pointer pointed to by Target. +** +** OUT gctPOINTER * OldValue +** The old value of the pointer pointed to by Target. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_AtomicExchangePtr( + IN gckOS Os, + IN OUT gctPOINTER * Target, + IN gctPOINTER NewValue, + OUT gctPOINTER * OldValue + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + /* Exchange the pair of pointers. */ + *OldValue = (gctPOINTER) atomic_xchg((atomic_t *) Target, (int) NewValue); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AtomConstruct +** +** Create an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** OUTPUT: +** +** gctPOINTER * Atom +** Pointer to a variable receiving the constructed atom. +*/ +gceSTATUS +gckOS_AtomConstruct( + IN gckOS Os, + OUT gctPOINTER * Atom + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%x", Os); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Atom != gcvNULL); + + /* Allocate the atom. */ + gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(atomic_t), Atom)); + + /* Initialize the atom. */ + atomic_set((atomic_t *) *Atom, 0); + + /* Success. */ + gcmkFOOTER_ARG("*Atom=0x%x", *Atom); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_AtomDestroy +** +** Destroy an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom to destroy. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_AtomDestroy( + IN gckOS Os, + OUT gctPOINTER Atom + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%x Atom=0x%0x", Os, Atom); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Atom != gcvNULL); + + /* Free the atom. */ + gcmkONERROR(gckOS_Free(Os, Atom)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_AtomGet +** +** Get the 32-bit value protected by an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom. +** +** OUTPUT: +** +** gctINT32_PTR Value +** Pointer to a variable the receives the value of the atom. +*/ +gceSTATUS +gckOS_AtomGet( + IN gckOS Os, + IN gctPOINTER Atom, + OUT gctINT32_PTR Value + ) +{ + gcmkHEADER_ARG("Os=0x%x Atom=0x%0x", Os, Atom); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Atom != gcvNULL); + + /* Return the current value of atom. */ + *Value = atomic_read((atomic_t *) Atom); + + /* Success. */ + gcmkFOOTER_ARG("*Value=%d", *Value); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AtomIncrement +** +** Atomically increment the 32-bit integer value inside an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom. +** +** OUTPUT: +** +** gctINT32_PTR Value +** Pointer to a variable the receives the original value of the atom. +*/ +gceSTATUS +gckOS_AtomIncrement( + IN gckOS Os, + IN gctPOINTER Atom, + OUT gctINT32_PTR Value + ) +{ + gcmkHEADER_ARG("Os=0x%x Atom=0x%0x", Os, Atom); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Atom != gcvNULL); + + /* Increment the atom. */ + *Value = atomic_inc_return((atomic_t *) Atom) - 1; + + /* Success. */ + gcmkFOOTER_ARG("*Value=%d", *Value); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AtomDecrement +** +** Atomically decrement the 32-bit integer value inside an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom. +** +** OUTPUT: +** +** gctINT32_PTR Value +** Pointer to a variable the receives the original value of the atom. +*/ +gceSTATUS +gckOS_AtomDecrement( + IN gckOS Os, + IN gctPOINTER Atom, + OUT gctINT32_PTR Value + ) +{ + gcmkHEADER_ARG("Os=0x%x Atom=0x%0x", Os, Atom); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Atom != gcvNULL); + + /* Decrement the atom. */ + *Value = atomic_dec_return((atomic_t *) Atom) + 1; + + /* Success. */ + gcmkFOOTER_ARG("*Value=%d", *Value); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_Delay +** +** Delay execution of the current thread for a number of milliseconds. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctUINT32 Delay +** Delay to sleep, specified in milliseconds. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_Delay( + IN gckOS Os, + IN gctUINT32 Delay + ) +{ + struct timeval now; + unsigned long jiffies; + + if (Delay > 0) + { + /* Convert milliseconds into seconds and microseconds. */ + now.tv_sec = Delay / 1000; + now.tv_usec = (Delay % 1000) * 1000; + + /* Convert timeval to jiffies. */ + jiffies = timeval_to_jiffies(&now); + + /* Schedule timeout. */ + schedule_timeout_interruptible(jiffies); + } + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_MemoryBarrier +** +** Make sure the CPU has executed everything up to this point and the data got +** written to the specified pointer. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Address +** Address of memory that needs to be barriered. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_MemoryBarrier( + IN gckOS Os, + IN gctPOINTER Address + ) +{ + /* Verify thearguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + mb(); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AllocatePagedMemory +** +** Allocate memory from the paged pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIZE_T Bytes +** Number of bytes to allocate. +** +** OUTPUT: +** +** gctPHYS_ADDR * Physical +** Pointer to a variable that receives the physical address of the +** memory allocation. +*/ +gceSTATUS +gckOS_AllocatePagedMemory( + IN gckOS Os, + IN gctSIZE_T Bytes, + OUT gctPHYS_ADDR * Physical + ) +{ + return gckOS_AllocatePagedMemoryEx(Os, gcvFALSE, Bytes, Physical); +} + +/******************************************************************************* +** +** gckOS_AllocatePagedMemoryEx +** +** Allocate memory from the paged pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctBOOL Contiguous +** Need contiguous memory or not. +** +** gctSIZE_T Bytes +** Number of bytes to allocate. +** +** OUTPUT: +** +** gctPHYS_ADDR * Physical +** Pointer to a variable that receives the physical address of the +** memory allocation. +*/ +gceSTATUS gckOS_AllocatePagedMemoryEx( + IN gckOS Os, + IN gctBOOL Contiguous, + IN gctSIZE_T Bytes, + OUT gctPHYS_ADDR * Physical + ) +{ + gctINT numPages; + gctINT i; + PLINUX_MDL mdl; + gctSTRING addr; + gctSIZE_T bytes; + + gcmkHEADER_ARG("Os=0x%0x Contiguous=%d Bytes=%lu", Os, Contiguous, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Physical != NULL); + + bytes = gcmALIGN(Bytes, PAGE_SIZE); + + numPages = GetPageCount(bytes, 0); + + MEMORY_LOCK(Os); + + if (Contiguous) + { + addr = (char *)__get_free_pages(GFP_ATOMIC | GFP_DMA, GetOrder(numPages)); + } + else + { + addr = vmalloc(bytes); + } + + if (!addr) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_AllocatePagedMemoryEx: " + "Can't allocate memorry for size->0x%x", + (gctUINT32)bytes); + + MEMORY_UNLOCK(Os); + + gcmkHEADER_ARG("status=%d", gcvSTATUS_OUT_OF_MEMORY); + return gcvSTATUS_OUT_OF_MEMORY; + } + + mdl = _CreateMdl(current->tgid); + + if (mdl == gcvNULL) + { + if (Contiguous) + { + free_pages((unsigned int) addr, GetOrder(mdl->numPages)); + } + else + { + vfree(addr); + } + + MEMORY_UNLOCK(Os); + + gcmkHEADER_ARG("status=%d", gcvSTATUS_OUT_OF_MEMORY); + return gcvSTATUS_OUT_OF_MEMORY; + } + + mdl->dmaHandle = 0; + mdl->addr = addr; + mdl->numPages = numPages; + mdl->pagedMem = 1; + mdl->contiguous = Contiguous; + + for (i = 0; i < mdl->numPages; i++) + { + struct page *page; + + if (mdl->contiguous) + { + page = virt_to_page((void *)(((unsigned long)addr) + i * PAGE_SIZE)); + } + else + { + page = vmalloc_to_page((void *)(((unsigned long)addr) + i * PAGE_SIZE)); + } + + SetPageReserved(page); + flush_dcache_page(page); + } + + /* Return physical address. */ + *Physical = (gctPHYS_ADDR) mdl; + + /* + * Add this to a global list. + * Will be used by get physical address + * and mapuser pointer functions. + */ + if (!Os->mdlHead) + { + /* Initialize the queue. */ + Os->mdlHead = Os->mdlTail = mdl; + } + else + { + /* Add to tail. */ + mdl->prev = Os->mdlTail; + Os->mdlTail->next = mdl; + Os->mdlTail = mdl; + } + + MEMORY_UNLOCK(Os); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, + "%s: Bytes=%lu Mdl=0x%08x Logical=0x%08x", + __FUNCTION__, bytes, mdl, mdl->addr); + + /* Success. */ + gcmkHEADER_ARG("*Physical=0x%08x", *Physical); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_FreePagedMemory +** +** Free memory allocated from the paged pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Physical address of the allocation. +** +** gctSIZE_T Bytes +** Number of bytes of the allocation. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_FreePagedMemory( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes + ) +{ + PLINUX_MDL mdl = (PLINUX_MDL)Physical; + gctSTRING addr; + gctINT i; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != NULL); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "in gckOS_FreePagedMemory"); + + addr = mdl->addr; + + MEMORY_LOCK(Os); + + for (i = 0; i < mdl->numPages; i++) + { + if (mdl->contiguous) + { + ClearPageReserved(virt_to_page((gctPOINTER)(((unsigned long)addr) + i * PAGE_SIZE))); + } + else + { + ClearPageReserved(vmalloc_to_page((gctPOINTER)(((unsigned long)addr) + i * PAGE_SIZE))); + } + } + + if (mdl->contiguous) + { + free_pages((unsigned long)mdl->addr, GetOrder(mdl->numPages)); + } + else + { + vfree(mdl->addr); + } + + /* Remove the node from global list. */ + if (mdl == Os->mdlHead) + { + if ((Os->mdlHead = mdl->next) == gcvNULL) + { + Os->mdlTail = gcvNULL; + } + } + else + { + mdl->prev->next = mdl->next; + + if (mdl == Os->mdlTail) + { + Os->mdlTail = mdl->prev; + } + else + { + mdl->next->prev = mdl->prev; + } + } + + MEMORY_UNLOCK(Os); + + /* Free the structure... */ + gcmkVERIFY_OK(_DestroyMdl(mdl)); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_FreePagedMemory: Bytes->0x%x, Mdl->0x%x", + (gctUINT32)Bytes, + (gctUINT32)mdl); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_LockPages +** +** Lock memory allocated from the paged pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Physical address of the allocation. +** +** gctSIZE_T Bytes +** Number of bytes of the allocation. +** +** OUTPUT: +** +** gctPOINTER * Logical +** Pointer to a variable that receives the address of the mapped +** memory. +** +** gctSIZE_T * PageCount +** Pointer to a variable that receives the number of pages required for +** the page table according to the GPU page size. +*/ +gceSTATUS gckOS_LockPages( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Logical, + OUT gctSIZE_T * PageCount + ) +{ + PLINUX_MDL mdl; + PLINUX_MDL_MAP mdlMap; + gctSTRING addr; + unsigned long start; + unsigned long pfn; + gctINT i; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != NULL); + gcmkVERIFY_ARGUMENT(Logical != NULL); + gcmkVERIFY_ARGUMENT(PageCount != NULL); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "in gckOS_LockPages"); + + mdl = (PLINUX_MDL) Physical; + + MEMORY_LOCK(Os); + + mdlMap = FindMdlMap(mdl, current->tgid); + + if (mdlMap == gcvNULL) + { + mdlMap = _CreateMdlMap(mdl, current->tgid); + + if (mdlMap == gcvNULL) + { + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_MEMORY; + } + } + + if (mdlMap->vmaAddr == gcvNULL) + { + down_write(¤t->mm->mmap_sem); + + mdlMap->vmaAddr = (gctSTRING)do_mmap_pgoff(NULL, + 0L, + mdl->numPages * PAGE_SIZE, + PROT_READ | PROT_WRITE, + MAP_SHARED, + 0); + + up_write(¤t->mm->mmap_sem); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_LockPages: " + "vmaAddr->0x%x for phys_addr->0x%x", + (gctUINT32)mdlMap->vmaAddr, + (gctUINT32)mdl); + + if (mdlMap->vmaAddr == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_LockPages: do_mmap_pgoff error"); + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_MEMORY; + } + + mdlMap->vma = find_vma(current->mm, (unsigned long)mdlMap->vmaAddr); + + if (mdlMap->vma == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "find_vma error"); + + mdlMap->vmaAddr = gcvNULL; + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_RESOURCES; + } + + mdlMap->vma->vm_flags |= VM_RESERVED; + /* Make this mapping non-cached. */ + mdlMap->vma->vm_page_prot = pgprot_noncached(mdlMap->vma->vm_page_prot); + + addr = mdl->addr; + + /* Now map all the vmalloc pages to this user address. */ + down_write(¤t->mm->mmap_sem); + + if (mdl->contiguous) + { + /* map kernel memory to user space.. */ + if (remap_pfn_range(mdlMap->vma, + mdlMap->vma->vm_start, + virt_to_phys((gctPOINTER)mdl->addr) >> PAGE_SHIFT, + mdlMap->vma->vm_end - mdlMap->vma->vm_start, + mdlMap->vma->vm_page_prot) < 0) + { + up_write(¤t->mm->mmap_sem); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_LockPages: unable to mmap ret"); + + mdlMap->vmaAddr = gcvNULL; + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_MEMORY; + } + } + else + { + start = mdlMap->vma->vm_start; + + for (i = 0; i < mdl->numPages; i++) + { + pfn = vmalloc_to_pfn(addr); + + if (remap_pfn_range(mdlMap->vma, + start, + pfn, + PAGE_SIZE, + mdlMap->vma->vm_page_prot) < 0) + { + up_write(¤t->mm->mmap_sem); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_LockPages: " + "gctPHYS_ADDR->0x%x Logical->0x%x Unable to map addr->0x%x to start->0x%x", + (gctUINT32)Physical, + (gctUINT32)*Logical, + (gctUINT32)addr, + (gctUINT32)start); + + mdlMap->vmaAddr = gcvNULL; + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_MEMORY; + } + + start += PAGE_SIZE; + addr += PAGE_SIZE; + } + } + + up_write(¤t->mm->mmap_sem); + } + + /* Convert pointer to MDL. */ + *Logical = mdlMap->vmaAddr; + + /* Return the page number according to the GPU page size. */ + gcmkASSERT((PAGE_SIZE % 4096) == 0); + gcmkASSERT((PAGE_SIZE / 4096) >= 1); + + *PageCount = mdl->numPages * (PAGE_SIZE / 4096); + + MEMORY_UNLOCK(Os); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_LockPages: " + "gctPHYS_ADDR->0x%x Bytes->0x%x Logical->0x%x pid->%d", + (gctUINT32)Physical, + (gctUINT32)Bytes, + (gctUINT32)*Logical, + mdlMap->pid); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_MapPages +** +** Map paged memory into a page table. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Physical address of the allocation. +** +** gctSIZE_T PageCount +** Number of pages required for the physical address. +** +** gctPOINTER PageTable +** Pointer to the page table to fill in. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_MapPages( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T PageCount, + IN gctPOINTER PageTable + ) +{ + PLINUX_MDL mdl; + gctUINT32* table; + gctSTRING addr; + gctINT i = 0; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != NULL); + gcmkVERIFY_ARGUMENT(PageCount > 0); + gcmkVERIFY_ARGUMENT(PageTable != NULL); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "in gckOS_MapPages"); + + /* Convert pointer to MDL. */ + mdl = (PLINUX_MDL)Physical; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_MapPages: " + "Physical->0x%x PageCount->0x%x PagedMemory->?%d", + (gctUINT32)Physical, + (gctUINT32)PageCount, + mdl->pagedMem); + + MEMORY_LOCK(Os); + + table = (gctUINT32 *)PageTable; + + /* Get all the physical addresses and store them in the page table. */ + + addr = mdl->addr; + + if (mdl->pagedMem) + { + /* Try to get the user pages so DMA can happen. */ + while (PageCount-- > 0) + { + if (mdl->contiguous) + { + *table++ = virt_to_phys(addr); + } + else + { + *table++ = page_to_phys(vmalloc_to_page(addr)); + } + + addr += 4096; + i++; + } + } + else + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "We should not get this call for Non Paged Memory!"); + + while (PageCount-- > 0) + { + *table++ = (gctUINT32)virt_to_phys(addr); + addr += 4096; + } + } + + MEMORY_UNLOCK(Os); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_UnlockPages +** +** Unlock memory allocated from the paged pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Physical address of the allocation. +** +** gctSIZE_T Bytes +** Number of bytes of the allocation. +** +** gctPOINTER Logical +** Address of the mapped memory. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_UnlockPages( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + IN gctPOINTER Logical + ) +{ + PLINUX_MDL_MAP mdlMap; + PLINUX_MDL mdl = (PLINUX_MDL)Physical; + struct task_struct * task; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != NULL); + gcmkVERIFY_ARGUMENT(Logical != NULL); + + /* Make sure there is already a mapping...*/ + gcmkVERIFY_ARGUMENT(mdl->addr != NULL); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "in gckOS_UnlockPages"); + + MEMORY_LOCK(Os); + + mdlMap = mdl->maps; + + while (mdlMap != gcvNULL) + { + if (mdlMap->vmaAddr != gcvNULL) + { + /* Get the current pointer for the task with stored pid. */ + task = FIND_TASK_BY_PID(mdlMap->pid); + + if (task != gcvNULL && task->mm != gcvNULL) + { + down_write(&task->mm->mmap_sem); + do_munmap(task->mm, (unsigned long)Logical, mdl->numPages * PAGE_SIZE); + up_write(&task->mm->mmap_sem); + } + + mdlMap->vmaAddr = gcvNULL; + } + + mdlMap = mdlMap->next; + } + + MEMORY_UNLOCK(Os); + + /* Success. */ + return gcvSTATUS_OK; +} + + +/******************************************************************************* +** +** gckOS_AllocateContiguous +** +** Allocate memory from the contiguous pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctBOOL InUserSpace +** gcvTRUE if the pages need to be mapped into user space. +** +** gctSIZE_T * Bytes +** Pointer to the number of bytes to allocate. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that receives the number of bytes allocated. +** +** gctPHYS_ADDR * Physical +** Pointer to a variable that receives the physical address of the +** memory allocation. +** +** gctPOINTER * Logical +** Pointer to a variable that receives the logical address of the +** memory allocation. +*/ +gceSTATUS gckOS_AllocateContiguous( + IN gckOS Os, + IN gctBOOL InUserSpace, + IN OUT gctSIZE_T * Bytes, + OUT gctPHYS_ADDR * Physical, + OUT gctPOINTER * Logical + ) +{ + /* Same as non-paged memory for now. */ + return gckOS_AllocateNonPagedMemory(Os, + InUserSpace, + Bytes, + Physical, + Logical + ); +} + +/******************************************************************************* +** +** gckOS_FreeContiguous +** +** Free memory allocated from the contiguous pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Physical address of the allocation. +** +** gctPOINTER Logical +** Logicval address of the allocation. +** +** gctSIZE_T Bytes +** Number of bytes of the allocation. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_FreeContiguous( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ) +{ + /* Same of non-paged memory for now. */ + return gckOS_FreeNonPagedMemory(Os, Bytes, Physical, Logical); +} + +/****************************************************************************** +** +** gckOS_GetKernelLogical +** +** Return the kernel logical pointer that corresponods to the specified +** hardware address. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctUINT32 Address +** Hardware physical address. +** +** OUTPUT: +** +** gctPOINTER * KernelPointer +** Pointer to a variable receiving the pointer in kernel address space. +*/ +gceSTATUS +gckOS_GetKernelLogical( + IN gckOS Os, + IN gctUINT32 Address, + OUT gctPOINTER * KernelPointer + ) +{ + gceSTATUS status; + + do + { + gckGALDEVICE device; + gckKERNEL kernel; + gcePOOL pool; + gctUINT32 offset; + gctPOINTER logical; + + /* Extract the pointer to the gckGALDEVICE class. */ + device = (gckGALDEVICE) Os->device; + + /* Kernel shortcut. */ + kernel = device->kernel; + + /* Split the memory address into a pool type and offset. */ + gcmkERR_BREAK(gckHARDWARE_SplitMemory( + kernel->hardware, Address, &pool, &offset + )); + + /* Dispatch on pool. */ + switch (pool) + { + case gcvPOOL_LOCAL_INTERNAL: + /* Internal memory. */ + logical = device->internalLogical; + break; + + case gcvPOOL_LOCAL_EXTERNAL: + /* External memory. */ + logical = device->externalLogical; + break; + + case gcvPOOL_SYSTEM: + /* System memory. */ + logical = device->contiguousBase; + break; + + default: + /* Invalid memory pool. */ + return gcvSTATUS_INVALID_ARGUMENT; + } + + /* Build logical address of specified address. */ + * KernelPointer = ((gctUINT8_PTR) logical) + offset; + + /* Success. */ + return gcvSTATUS_OK; + } + while (gcvFALSE); + + /* Return status. */ + return status; +} + +/******************************************************************************* +** +** gckOS_MapUserPointer +** +** Map a pointer from the user process into the kernel address space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Pointer +** Pointer in user process space that needs to be mapped. +** +** gctSIZE_T Size +** Number of bytes that need to be mapped. +** +** OUTPUT: +** +** gctPOINTER * KernelPointer +** Pointer to a variable receiving the mapped pointer in kernel address +** space. +*/ +gceSTATUS +gckOS_MapUserPointer( + IN gckOS Os, + IN gctPOINTER Pointer, + IN gctSIZE_T Size, + OUT gctPOINTER * KernelPointer + ) +{ +#if NO_USER_DIRECT_ACCESS_FROM_KERNEL + gctPOINTER buf = gcvNULL; + gctUINT32 len; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Pointer != gcvNULL); + gcmkVERIFY_ARGUMENT(Size > 0); + gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL); + + buf = kmalloc(Size, GFP_KERNEL); + if (buf == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "Failed to allocate memory at line %d in %s.", + __LINE__, __FILE__ + ); + + return gcvSTATUS_OUT_OF_MEMORY; + } + + len = copy_from_user(buf, Pointer, Size); + if (len != 0) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "Failed to copy data from user at line %d in %s.", + __LINE__, __FILE__ + ); + + if (buf != gcvNULL) + { + kfree(buf); + } + + return gcvSTATUS_GENERIC_IO; + } + + *KernelPointer = buf; +#else + *KernelPointer = Pointer; +#endif /* NO_USER_DIRECT_ACCESS_FROM_KERNEL */ + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_UnmapUserPointer +** +** Unmap a user process pointer from the kernel address space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Pointer +** Pointer in user process space that needs to be unmapped. +** +** gctSIZE_T Size +** Number of bytes that need to be unmapped. +** +** gctPOINTER KernelPointer +** Pointer in kernel address space that needs to be unmapped. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_UnmapUserPointer( + IN gckOS Os, + IN gctPOINTER Pointer, + IN gctSIZE_T Size, + IN gctPOINTER KernelPointer + ) +{ +#if NO_USER_DIRECT_ACCESS_FROM_KERNEL + gctUINT32 len; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Pointer != gcvNULL); + gcmkVERIFY_ARGUMENT(Size > 0); + gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL); + + len = copy_to_user(Pointer, KernelPointer, Size); + + kfree(KernelPointer); + + if (len != 0) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "Failed to copy data to user at line %d in %s.", + __LINE__, __FILE__ + ); + return gcvSTATUS_GENERIC_IO; + } +#endif /* NO_USER_DIRECT_ACCESS_FROM_KERNEL */ + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_WriteMemory +** +** Write data to a memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Address +** Address of the memory to write to. +** +** gctUINT32 Data +** Data for register. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_WriteMemory( + IN gckOS Os, + IN gctPOINTER Address, + IN gctUINT32 Data + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Address != NULL); + + /* Write memory. */ + writel(Data, (gctUINT8 *)Address); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_CreateSignal +** +** Create a new signal. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctBOOL ManualReset +** If set to gcvTRUE, gckOS_Signal with gcvFALSE must be called in +** order to set the signal to nonsignaled state. +** If set to gcvFALSE, the signal will automatically be set to +** nonsignaled state by gckOS_WaitSignal function. +** +** OUTPUT: +** +** gctSIGNAL * Signal +** Pointer to a variable receiving the created gctSIGNAL. +*/ +gceSTATUS +gckOS_CreateSignal( + IN gckOS Os, + IN gctBOOL ManualReset, + OUT gctSIGNAL * Signal + ) +{ +#if USE_NEW_LINUX_SIGNAL + return gcvSTATUS_NOT_SUPPORTED; +#else + gcsSIGNAL_PTR signal; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Signal != NULL); + + /* Create an event structure. */ + signal = (gcsSIGNAL_PTR)kmalloc(sizeof(gcsSIGNAL), GFP_KERNEL); + + if (signal == gcvNULL) + { + return gcvSTATUS_OUT_OF_MEMORY; + } + + signal->manualReset = ManualReset; + + init_completion(&signal->event); + + atomic_set(&signal->ref, 1); + + *Signal = (gctSIGNAL) signal; + + return gcvSTATUS_OK; +#endif +} + +/******************************************************************************* +** +** gckOS_DestroySignal +** +** Destroy a signal. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to the gctSIGNAL. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_DestroySignal( + IN gckOS Os, + IN gctSIGNAL Signal + ) +{ +#if USE_NEW_LINUX_SIGNAL + return gcvSTATUS_NOT_SUPPORTED; +#else + gcsSIGNAL_PTR signal; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Signal != NULL); + + signal = (gcsSIGNAL_PTR) Signal; + + if (atomic_dec_and_test(&signal->ref)) + { + /* Free the sgianl. */ + kfree(Signal); + } + + /* Success. */ + return gcvSTATUS_OK; +#endif +} + +/******************************************************************************* +** +** gckOS_Signal +** +** Set a state of the specified signal. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to the gctSIGNAL. +** +** gctBOOL State +** If gcvTRUE, the signal will be set to signaled state. +** If gcvFALSE, the signal will be set to nonsignaled state. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_Signal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctBOOL State + ) +{ +#if USE_NEW_LINUX_SIGNAL + return gcvSTATUS_NOT_SUPPORTED; +#else + gcsSIGNAL_PTR signal; + + gcmkHEADER_ARG("Os=0x%x Signal=0x%x State=%d", Os, Signal, State); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Signal != gcvNULL); + + signal = (gcsSIGNAL_PTR) Signal; + + /* Set the new state of the event. */ + if (signal->manualReset) + { + if (State) + { + /* Set the event to a signaled state. */ + complete_all(&signal->event); + } + else + { + /* Set the event to an unsignaled state. */ + INIT_COMPLETION(signal->event); + } + } + else + { + if (State) + { + /* Set the event to a signaled state. */ + complete(&signal->event); + + } + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +#endif +} + +#if USE_NEW_LINUX_SIGNAL +/******************************************************************************* +** +** gckOS_UserSignal +** +** Set the specified signal which is owned by a process to signaled state. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to the gctSIGNAL. +** +** gctHANDLE Process +** Handle of process owning the signal. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_UserSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctHANDLE Process + ) +{ + gceSTATUS status; + gctINT result; + struct task_struct * task; + struct siginfo info; + + task = FIND_TASK_BY_PID((pid_t) Process); + + if (task != gcvNULL) + { + /* Fill in the siginfo structure. */ + info.si_signo = Os->device->signal; + info.si_errno = 0; + info.si_code = __SI_CODE(__SI_RT, SI_KERNEL); + info.si_ptr = Signal; + + /* Send the signal. */ + if ((result = send_sig_info(Os->device->signal, &info, task)) < 0) + { + status = gcvSTATUS_GENERIC_IO; + + gcmkTRACE(gcvLEVEL_ERROR, + "%s(%d): send_sig_info failed.", + __FUNCTION__, __LINE__); + } + else + { + /* Success. */ + status = gcvSTATUS_OK; + } + } + else + { + status = gcvSTATUS_GENERIC_IO; + + gcmkTRACE(gcvLEVEL_ERROR, + "%s(%d): find_task_by_pid failed.", + __FUNCTION__, __LINE__); + } + + /* Return status. */ + return status; +} + +/******************************************************************************* +** +** gckOS_WaitSignal +** +** Wait for a signal to become signaled. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to the gctSIGNAL. +** +** gctUINT32 Wait +** Number of milliseconds to wait. +** Pass the value of gcvINFINITE for an infinite wait. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_WaitSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctUINT32 Wait + ) +{ + return gcvSTATUS_NOT_SUPPORTED; +} + +/******************************************************************************* +** +** gckOS_MapSignal +** +** Map a signal in to the current process space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to tha gctSIGNAL to map. +** +** gctHANDLE Process +** Handle of process owning the signal. +** +** OUTPUT: +** +** gctSIGNAL * MappedSignal +** Pointer to a variable receiving the mapped gctSIGNAL. +*/ +gceSTATUS +gckOS_MapSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctHANDLE Process, + OUT gctSIGNAL * MappedSignal + ) +{ + return gcvSTATUS_NOT_SUPPORTED; +} + +#else + +/******************************************************************************* +** +** gckOS_UserSignal +** +** Set the specified signal which is owned by a process to signaled state. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to the gctSIGNAL. +** +** gctHANDLE Process +** Handle of process owning the signal. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_UserSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctHANDLE Process + ) +{ + gceSTATUS status; + gctSIGNAL signal; + + gcmkHEADER_ARG("Os=0x%x Signal=%d Process=0x%x", + Os, (gctINT) Signal, Process); + + /* Map the signal into kernel space. */ + gcmkONERROR(gckOS_MapSignal(Os, Signal, Process, &signal)); + + /* Signal. */ + status = gckOS_Signal(Os, signal, gcvTRUE); + gcmkFOOTER(); + return status; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_WaitSignal +** +** Wait for a signal to become signaled. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to the gctSIGNAL. +** +** gctUINT32 Wait +** Number of milliseconds to wait. +** Pass the value of gcvINFINITE for an infinite wait. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_WaitSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctUINT32 Wait + ) +{ + gceSTATUS status; + gcsSIGNAL_PTR signal; + gctUINT timeout; + gctUINT rc; + + gcmkHEADER_ARG("Os=0x%x Signal=0x%x Wait=%u", Os, Signal, Wait); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Signal != gcvNULL); + + signal = (gcsSIGNAL_PTR) Signal; + + /* Convert wait to milliseconds. */ + timeout = (Wait == gcvINFINITE) ? MAX_SCHEDULE_TIMEOUT : Wait*HZ/1000; + + /* Linux bug ? */ + if (!signal->manualReset && timeout == 0) timeout = 1; + + rc = wait_for_completion_interruptible_timeout(&signal->event, timeout); + status = ((rc == 0) && !signal->event.done) ? gcvSTATUS_TIMEOUT + : gcvSTATUS_OK; + + /* Return status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_MapSignal +** +** Map a signal in to the current process space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to tha gctSIGNAL to map. +** +** gctHANDLE Process +** Handle of process owning the signal. +** +** OUTPUT: +** +** gctSIGNAL * MappedSignal +** Pointer to a variable receiving the mapped gctSIGNAL. +*/ +gceSTATUS +gckOS_MapSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctHANDLE Process, + OUT gctSIGNAL * MappedSignal + ) +{ + gctINT signalID; + gcsSIGNAL_PTR signal; + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Os=0x%x Signal=0x%x Process=0x%x", Os, Signal, Process); + + gcmkVERIFY_ARGUMENT(Signal != gcvNULL); + gcmkVERIFY_ARGUMENT(MappedSignal != gcvNULL); + + signalID = (gctINT) Signal - 1; + + gcmkONERROR(gckOS_AcquireMutex(Os, Os->signal.lock, gcvINFINITE)); + acquired = gcvTRUE; + + if (signalID >= 0 && signalID < Os->signal.tableLen) + { + /* It is a user space signal. */ + signal = Os->signal.table[signalID]; + + if (signal == gcvNULL) + { + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + } + else + { + /* It is a kernel space signal structure. */ + signal = (gcsSIGNAL_PTR) Signal; + } + + if (atomic_inc_return(&signal->ref) <= 1) + { + /* The previous value is 0, it has been deleted. */ + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + /* Release the mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Os, Os->signal.lock)); + + *MappedSignal = (gctSIGNAL) signal; + + /* Success. */ + gcmkFOOTER_ARG("*MappedSignal=0x%x", *MappedSignal); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signal.lock)); + } + + /* Return the staus. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_CreateUserSignal +** +** Create a new signal to be used in the user space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctBOOL ManualReset +** If set to gcvTRUE, gckOS_Signal with gcvFALSE must be called in +** order to set the signal to nonsignaled state. +** If set to gcvFALSE, the signal will automatically be set to +** nonsignaled state by gckOS_WaitSignal function. +** +** OUTPUT: +** +** gctINT * SignalID +** Pointer to a variable receiving the created signal's ID. +*/ +gceSTATUS +gckOS_CreateUserSignal( + IN gckOS Os, + IN gctBOOL ManualReset, + OUT gctINT * SignalID + ) +{ + gcsSIGNAL_PTR signal; + gctINT unused, currentID, tableLen; + gctPOINTER * table; + gctINT i; + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Os=0x%0x ManualReset=%d", Os, ManualReset); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(SignalID != gcvNULL); + + /* Lock the table. */ + gcmkONERROR( + gckOS_AcquireMutex(Os, Os->signal.lock, gcvINFINITE)); + + acquired = gcvTRUE; + + if (Os->signal.unused < 1) + { + /* Enlarge the table. */ + table = (gctPOINTER *) kmalloc( + sizeof(gctPOINTER) * (Os->signal.tableLen + USER_SIGNAL_TABLE_LEN_INIT), + GFP_KERNEL); + + if (table == gcvNULL) + { + /* Out of memory. */ + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + memset(table + Os->signal.tableLen, 0, sizeof(gctPOINTER) * USER_SIGNAL_TABLE_LEN_INIT); + memcpy(table, Os->signal.table, sizeof(gctPOINTER) * Os->signal.tableLen); + + /* Release the old table. */ + kfree(Os->signal.table); + + /* Update the table. */ + Os->signal.table = table; + Os->signal.currentID = Os->signal.tableLen; + Os->signal.tableLen += USER_SIGNAL_TABLE_LEN_INIT; + Os->signal.unused += USER_SIGNAL_TABLE_LEN_INIT; + } + + table = Os->signal.table; + currentID = Os->signal.currentID; + tableLen = Os->signal.tableLen; + unused = Os->signal.unused; + + /* Create a new signal. */ + gcmkONERROR( + gckOS_CreateSignal(Os, ManualReset, (gctSIGNAL *) &signal)); + + /* Save the process ID. */ + signal->process = (gctHANDLE) current->tgid; + + table[currentID] = signal; + + /* Plus 1 to avoid NULL claims. */ + *SignalID = currentID + 1; + + /* Update the currentID. */ + if (--unused > 0) + { + for (i = 0; i < tableLen; i++) + { + if (++currentID >= tableLen) + { + /* Wrap to the begin. */ + currentID = 0; + } + + if (table[currentID] == gcvNULL) + { + break; + } + } + } + + Os->signal.table = table; + Os->signal.currentID = currentID; + Os->signal.tableLen = tableLen; + Os->signal.unused = unused; + + gcmkONERROR( + gckOS_ReleaseMutex(Os, Os->signal.lock)); + + gcmkFOOTER_ARG("*SignalID=%d", gcmOPT_VALUE(SignalID)); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkONERROR( + gckOS_ReleaseMutex(Os, Os->signal.lock)); + } + + /* Return the staus. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_DestroyUserSignal +** +** Destroy a signal to be used in the user space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctINT SignalID +** The signal's ID. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_DestroyUserSignal( + IN gckOS Os, + IN gctINT SignalID + ) +{ + gceSTATUS status; + gcsSIGNAL_PTR signal; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Os=0x%x SignalID=%d", Os, SignalID); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + gcmkONERROR( + gckOS_AcquireMutex(Os, Os->signal.lock, gcvINFINITE)); + + acquired = gcvTRUE; + + if (SignalID < 1 || SignalID > Os->signal.tableLen) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_DestroyUserSignal: invalid signal->%d.", + (gctINT) SignalID + ); + + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + SignalID -= 1; + + signal = Os->signal.table[SignalID]; + + if (signal == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_DestroyUserSignal: signal is NULL." + ); + + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + /* Check to see if the process is the owner of the signal. */ + if (signal->process != (gctHANDLE) current->tgid) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_DestroyUserSignal: process id doesn't match. ", + "signal->process: %d, current->tgid: %d", + signal->process, + current->tgid); + + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + gcmkONERROR( + gckOS_DestroySignal(Os, signal)); + + /* Update the table. */ + Os->signal.table[SignalID] = gcvNULL; + if (Os->signal.unused++ == 0) + { + Os->signal.currentID = SignalID; + } + + gcmkVERIFY_OK( + gckOS_ReleaseMutex(Os, Os->signal.lock)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkONERROR( + gckOS_ReleaseMutex(Os, Os->signal.lock)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_WaitUserSignal +** +** Wait for a signal used in the user mode to become signaled. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctINT SignalID +** Signal ID. +** +** gctUINT32 Wait +** Number of milliseconds to wait. +** Pass the value of gcvINFINITE for an infinite wait. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_WaitUserSignal( + IN gckOS Os, + IN gctINT SignalID, + IN gctUINT32 Wait + ) +{ + gceSTATUS status; + gcsSIGNAL_PTR signal; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Os=0x%x SignalID=%d Wait=%u", Os, SignalID, Wait); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + gcmkONERROR(gckOS_AcquireMutex(Os, Os->signal.lock, gcvINFINITE)); + acquired = gcvTRUE; + + if (SignalID < 1 || SignalID > Os->signal.tableLen) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_WaitSignal: invalid signal.", + SignalID + ); + + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + SignalID -= 1; + + signal = Os->signal.table[SignalID]; + + gcmkONERROR(gckOS_ReleaseMutex(Os, Os->signal.lock)); + acquired = gcvFALSE; + + if (signal == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_WaitSignal: signal is NULL." + ); + + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + if (signal->process != (gctHANDLE) current->tgid) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_WaitUserSignal: process id doesn't match. " + "signal->process: %d, current->tgid: %d", + signal->process, + current->tgid); + + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + +do{ + status = gckOS_WaitSignal(Os, signal, Wait==gcvINFINITE?5000:Wait); +if(Wait==gcvINFINITE&&status==gcvSTATUS_TIMEOUT){gcmkPRINT("$$FLUSH$$");} +}while(status==gcvSTATUS_TIMEOUT&&Wait==gcvINFINITE); + + /* Return the status. */ + gcmkFOOTER(); + return status; + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkONERROR( + gckOS_ReleaseMutex(Os, Os->signal.lock)); + } + + /* Return the staus. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_SignalUserSignal +** +** Set a state of the specified signal to be used in the user space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctINT SignalID +** SignalID. +** +** gctBOOL State +** If gcvTRUE, the signal will be set to signaled state. +** If gcvFALSE, the signal will be set to nonsignaled state. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_SignalUserSignal( + IN gckOS Os, + IN gctINT SignalID, + IN gctBOOL State + ) +{ + gceSTATUS status; + gcsSIGNAL_PTR signal; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Os=0x%x SignalID=%d State=%d", Os, SignalID, State); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + gcmkONERROR(gckOS_AcquireMutex(Os, Os->signal.lock, gcvINFINITE)); + acquired = gcvTRUE; + + if ((SignalID < 1) + || (SignalID > Os->signal.tableLen) + ) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_OS, + "gckOS_WaitSignal: invalid signal->%d.", SignalID); + + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + SignalID -= 1; + + signal = Os->signal.table[SignalID]; + + gcmkONERROR(gckOS_ReleaseMutex(Os, Os->signal.lock)); + acquired = gcvFALSE; + + if (signal == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_WaitSignal: signal is NULL." + ); + + gcmkONERROR(gcvSTATUS_INVALID_REQUEST); + } + + if (signal->process != (gctHANDLE) current->tgid) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_DestroyUserSignal: process id doesn't match. ", + "signal->process: %d, current->tgid: %d", + signal->process, + current->tgid); + + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + status = gckOS_Signal(Os, signal, State); + + /* Success. */ + gcmkFOOTER(); + return status; + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkONERROR( + gckOS_ReleaseMutex(Os, Os->signal.lock)); + } + + /* Return the staus. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckOS_CleanProcessSignal( + gckOS Os, + gctHANDLE Process + ) +{ + gctINT signal; + + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + gcmkVERIFY_OK(gckOS_AcquireMutex(Os, + Os->signal.lock, + gcvINFINITE + )); + + if (Os->signal.unused == Os->signal.tableLen) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, + Os->signal.lock + )); + + return gcvSTATUS_OK; + } + + for (signal = 0; signal < Os->signal.tableLen; signal++) + { + if (Os->signal.table[signal] != gcvNULL && + ((gcsSIGNAL_PTR)Os->signal.table[signal])->process == Process) + { + gckOS_DestroySignal(Os, Os->signal.table[signal]); + + /* Update the signal table. */ + Os->signal.table[signal] = gcvNULL; + if (Os->signal.unused++ == 0) + { + Os->signal.currentID = signal; + } + } + } + + gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, + Os->signal.lock + )); + + return gcvSTATUS_OK; +} + +#endif /* USE_NEW_LINUX_SIGNAL */ + +/******************************************************************************* +** +** gckOS_MapUserMemory +** +** Lock down a user buffer and return an DMA'able address to be used by the +** hardware to access it. +** +** INPUT: +** +** gctPOINTER Memory +** Pointer to memory to lock down. +** +** gctSIZE_T Size +** Size in bytes of the memory to lock down. +** +** OUTPUT: +** +** gctPOINTER * Info +** Pointer to variable receiving the information record required by +** gckOS_UnmapUserMemory. +** +** gctUINT32_PTR Address +** Pointer to a variable that will receive the address DMA'able by the +** hardware. +*/ +gceSTATUS +gckOS_MapUserMemory( + IN gckOS Os, + IN gctPOINTER Memory, + IN gctSIZE_T Size, + OUT gctPOINTER * Info, + OUT gctUINT32_PTR Address + ) +{ + gceSTATUS status; + gctSIZE_T pageCount, i, j; + gctUINT32_PTR pageTable; + gctUINT32 address; + gctUINT32 start, end, memory; + gctINT result = 0; + + gcsPageInfo_PTR info = gcvNULL; + struct page **pages = gcvNULL; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Memory != gcvNULL); + gcmkVERIFY_ARGUMENT(Size > 0); + gcmkVERIFY_ARGUMENT(Info != gcvNULL); + gcmkVERIFY_ARGUMENT(Address != gcvNULL); + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, + gcvZONE_OS, + "[gckOS_MapUserMemory] enter." + ); + + do + { + memory = (gctUINT32) Memory; + + /* Get the number of required pages. */ + end = (memory + Size + PAGE_SIZE - 1) >> PAGE_SHIFT; + start = memory >> PAGE_SHIFT; + pageCount = end - start; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "[gckOS_MapUserMemory] pageCount: %d.", + pageCount + ); + + /* Invalid argument. */ + if (pageCount == 0) + { + return gcvSTATUS_INVALID_ARGUMENT; + } + + /* Overflow. */ + if ((memory + Size) < memory) + { + return gcvSTATUS_INVALID_ARGUMENT; + } + + MEMORY_MAP_LOCK(Os); + + /* Allocate the Info struct. */ + info = (gcsPageInfo_PTR)kmalloc(sizeof(gcsPageInfo), GFP_KERNEL); + + if (info == gcvNULL) + { + status = gcvSTATUS_OUT_OF_MEMORY; + break; + } + + /* Allocate the array of page addresses. */ + pages = (struct page **)kmalloc(pageCount * sizeof(struct page *), GFP_KERNEL); + + if (pages == gcvNULL) + { + status = gcvSTATUS_OUT_OF_MEMORY; + break; + } + + /* Get the user pages. */ + down_read(¤t->mm->mmap_sem); + result = get_user_pages(current, + current->mm, + memory & PAGE_MASK, + pageCount, + 1, + 0, + pages, + NULL + ); + up_read(¤t->mm->mmap_sem); + + if (result <=0 || result < pageCount) + { + struct vm_area_struct *vma; + + vma = find_vma(current->mm, memory); + + if (vma && (vma->vm_flags & VM_PFNMAP) ) + { + do + { + pte_t * pte; + spinlock_t * ptl; + unsigned long pfn; + + pgd_t * pgd = pgd_offset(current->mm, memory); + pud_t * pud = pud_alloc(current->mm, pgd, memory); + if (pud) + { + pmd_t * pmd = pmd_alloc(current->mm, pud, memory); + if (pmd) + { + pte = pte_offset_map_lock(current->mm, pmd, memory, &ptl); + if (!pte) + { + break; + } + } + else + { + break; + } + } + else + { + break; + } + + pfn = pte_pfn(*pte); + *Address = ((pfn << PAGE_SHIFT) | (((unsigned long)Memory) & ~PAGE_MASK)) + - Os->baseAddress; + *Info = gcvNULL; + + pte_unmap_unlock(pte, ptl); + + /* Release page info struct. */ + if (info != gcvNULL) + { + /* Free the page info struct. */ + kfree(info); + } + + if (pages != gcvNULL) + { + /* Free the page table. */ + kfree(pages); + } + + MEMORY_MAP_UNLOCK(Os); + + return gcvSTATUS_OK; + } + while (gcvFALSE); + + *Address = ~0; + *Info = gcvNULL; + + status = gcvSTATUS_OUT_OF_RESOURCES; + break; + } + else + { + status = gcvSTATUS_OUT_OF_RESOURCES; + break; + } + } + + for (i = 0; i < pageCount; i++) + { + /* Flush the data cache. */ +#ifdef ANDROID + dma_sync_single_for_device( + gcvNULL, + page_to_phys(pages[i]), + PAGE_SIZE, + DMA_TO_DEVICE); +#else + flush_dcache_page(pages[i]); +#endif + } + + /* Allocate pages inside the page table. */ + gcmkERR_BREAK(gckMMU_AllocatePages(Os->device->kernel->mmu, + pageCount * (PAGE_SIZE/4096), + (gctPOINTER *) &pageTable, + &address)); + + /* Fill the page table. */ + for (i = 0; i < pageCount; i++) + { + /* Get the physical address from page struct. */ + pageTable[i * (PAGE_SIZE/4096)] = page_to_phys(pages[i]); + + for (j = 1; j < (PAGE_SIZE/4096); j++) + { + pageTable[i * (PAGE_SIZE/4096) + j] = pageTable[i * (PAGE_SIZE/4096)] + 4096 * j; + } + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "[gckOS_MapUserMemory] pages[%d]: 0x%x, pageTable[%d]: 0x%x.", + i, pages[i], + i, pageTable[i]); + } + + /* Save pointer to page table. */ + info->pageTable = pageTable; + info->pages = pages; + + *Info = (gctPOINTER) info; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "[gckOS_MapUserMemory] info->pages: 0x%x, info->pageTable: 0x%x, info: 0x%x.", + info->pages, + info->pageTable, + info + ); + + /* Return address. */ + *Address = address + (memory & ~PAGE_MASK); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "[gckOS_MapUserMemory] Address: 0x%x.", + *Address + ); + + /* Success. */ + status = gcvSTATUS_OK; + } + while (gcvFALSE); + + if (gcmIS_ERROR(status)) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "[gckOS_MapUserMemory] error occured: %d.", + status + ); + + /* Release page array. */ + if (result > 0 && pages != gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "[gckOS_MapUserMemory] error: page table is freed." + ); + + for (i = 0; i < result; i++) + { + if (pages[i] == gcvNULL) + { + break; + } +#ifdef ANDROID + dma_sync_single_for_device( + gcvNULL, + page_to_phys(pages[i]), + PAGE_SIZE, + DMA_FROM_DEVICE); +#endif + page_cache_release(pages[i]); + } + } + + if (pages != gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "[gckOS_MapUserMemory] error: pages is freed." + ); + + /* Free the page table. */ + kfree(pages); + info->pages = gcvNULL; + } + + /* Release page info struct. */ + if (info != gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "[gckOS_MapUserMemory] error: info is freed." + ); + + /* Free the page info struct. */ + kfree(info); + *Info = gcvNULL; + } + } + + MEMORY_MAP_UNLOCK(Os); + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, + gcvZONE_OS, + "[gckOS_MapUserMemory] leave." + ); + + /* Return the status. */ + return status; +} + +/******************************************************************************* +** +** gckOS_UnmapUserMemory +** +** Unlock a user buffer and that was previously locked down by +** gckOS_MapUserMemory. +** +** INPUT: +** +** gctPOINTER Memory +** Pointer to memory to unlock. +** +** gctSIZE_T Size +** Size in bytes of the memory to unlock. +** +** gctPOINTER Info +** Information record returned by gckOS_MapUserMemory. +** +** gctUINT32_PTR Address +** The address returned by gckOS_MapUserMemory. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_UnmapUserMemory( + IN gckOS Os, + IN gctPOINTER Memory, + IN gctSIZE_T Size, + IN gctPOINTER Info, + IN gctUINT32 Address + ) +{ + gceSTATUS status; + gctUINT32 memory, start, end; + gcsPageInfo_PTR info; + gctSIZE_T pageCount, i; + struct page **pages; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Memory != gcvNULL); + gcmkVERIFY_ARGUMENT(Size > 0); + gcmkVERIFY_ARGUMENT(Info != gcvNULL); + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, + gcvZONE_OS, + "[gckOS_UnmapUserMemory] enter." + ); + + do + { + info = (gcsPageInfo_PTR) Info; + + if (info == gcvNULL) + { + return gcvSTATUS_OK; + } + + pages = info->pages; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "[gckOS_UnmapUserMemory] info: 0x%x, pages: 0x%x.", + info, + pages + ); + + /* Invalid page array. */ + if (pages == gcvNULL) + { + return gcvSTATUS_INVALID_ARGUMENT; + } + + memory = (gctUINT32) Memory; + end = (memory + Size + PAGE_SIZE - 1) >> PAGE_SHIFT; + start = memory >> PAGE_SHIFT; + pageCount = end - start; + + /* Overflow. */ + if ((memory + Size) < memory) + { + return gcvSTATUS_INVALID_ARGUMENT; + } + + /* Invalid argument. */ + if (pageCount == 0) + { + return gcvSTATUS_INVALID_ARGUMENT; + } + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "[gckOS_UnmapUserMemory] memory: 0x%x, pageCount: %d, pageTable: 0x%x.", + memory, + pageCount, + info->pageTable + ); + + MEMORY_MAP_LOCK(Os); + + /* Free the pages from the MMU. */ + gcmkERR_BREAK(gckMMU_FreePages(Os->device->kernel->mmu, + info->pageTable, + pageCount * (PAGE_SIZE/4096) + )); + + /* Release the page cache. */ + for (i = 0; i < pageCount; i++) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "[gckOS_UnmapUserMemory] pages[%d]: 0x%x.", + i, + pages[i] + ); + + if (!PageReserved(pages[i])) + { + SetPageDirty(pages[i]); + } + +#ifdef ANDROID + dma_sync_single_for_device( + gcvNULL, + page_to_phys(pages[i]), + PAGE_SIZE, + DMA_FROM_DEVICE); +#endif + page_cache_release(pages[i]); + } + + /* Success. */ + status = gcvSTATUS_OK; + } + while (gcvFALSE); + + if (info != gcvNULL) + { + /* Free the page array. */ + if (info->pages != gcvNULL) + { + kfree(info->pages); + } + + kfree(info); + } + + MEMORY_MAP_UNLOCK(Os); + + /* Return the status. */ + return status; +} + +/******************************************************************************* +** +** gckOS_GetBaseAddress +** +** Get the base address for the physical memory. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** OUTPUT: +** +** gctUINT32_PTR BaseAddress +** Pointer to a variable that will receive the base address. +*/ +gceSTATUS +gckOS_GetBaseAddress( + IN gckOS Os, + OUT gctUINT32_PTR BaseAddress + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(BaseAddress != gcvNULL); + + /* Return base address. */ + *BaseAddress = Os->baseAddress; + + /* Success. */ + return gcvSTATUS_OK; +} + +gceSTATUS +gckOS_SuspendInterrupt( + IN gckOS Os + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + disable_irq(Os->device->irqLine); + + return gcvSTATUS_OK; +} + +gceSTATUS +gckOS_ResumeInterrupt( + IN gckOS Os + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + enable_irq(Os->device->irqLine); + + return gcvSTATUS_OK; +} + +gceSTATUS +gckOS_MemCopy( + IN gctPOINTER Destination, + IN gctCONST_POINTER Source, + IN gctSIZE_T Bytes + ) +{ + gcmkVERIFY_ARGUMENT(Destination != NULL); + gcmkVERIFY_ARGUMENT(Source != NULL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + + memcpy(Destination, Source, Bytes); + + return gcvSTATUS_OK; +} + +gceSTATUS +gckOS_ZeroMemory( + IN gctPOINTER Memory, + IN gctSIZE_T Bytes + ) +{ + gcmkHEADER_ARG("Memory=0x%x Bytes=%lu", Memory, Bytes); + + gcmkVERIFY_ARGUMENT(Memory != gcvNULL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + + memset(Memory, 0, Bytes); + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +#if gcdkUSE_MEMORY_RECORD +MEMORY_RECORD_PTR +CreateMemoryRecord( + gckOS Os, + MEMORY_RECORD_PTR List, + gcuVIDMEM_NODE_PTR Node + ) +{ + MEMORY_RECORD_PTR mr; + + mr = (MEMORY_RECORD_PTR)kmalloc(sizeof(struct MEMORY_RECORD), GFP_ATOMIC); + if (mr == gcvNULL) return gcvNULL; + + MEMORY_LOCK(Os); + + mr->node = Node; + + mr->prev = List->prev; + mr->next = List; + List->prev->next = mr; + List->prev = mr; + + MEMORY_UNLOCK(Os); + + return mr; +} + +void +DestoryMemoryRecord( + gckOS Os, + MEMORY_RECORD_PTR Mr + ) +{ + MEMORY_LOCK(Os); + + Mr->prev->next = Mr->next; + Mr->next->prev = Mr->prev; + + MEMORY_UNLOCK(Os); + + kfree(Mr); +} + +MEMORY_RECORD_PTR +FindMemoryRecord( + gckOS Os, + MEMORY_RECORD_PTR List, + gcuVIDMEM_NODE_PTR Node + ) +{ + MEMORY_RECORD_PTR mr; + + MEMORY_LOCK(Os); + + mr = List->next; + + while (mr != List) + { + if (mr->node == Node) + { + MEMORY_UNLOCK(Os); + + return mr; + } + + mr = mr->next; + } + + MEMORY_UNLOCK(Os); + + return gcvNULL; +} + +void +FreeAllMemoryRecord( + gckOS Os, + MEMORY_RECORD_PTR List + ) +{ + MEMORY_RECORD_PTR mr; + gctUINT i = 0; + + MEMORY_LOCK(Os); + + while (List->next != List) + { + mr = List->next; + + mr->prev->next = mr->next; + mr->next->prev = mr->prev; + + i++; + + MEMORY_UNLOCK(Os); + + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "Unfreed %s memory: node: %p", + (mr->node->VidMem.memory->object.type == gcvOBJ_VIDMEM)? + "video" : (mr->node->Virtual.contiguous)? + "contiguous" : "virtual", + mr->node); + + while (gcvTRUE) + { + if (mr->node->VidMem.memory->object.type == gcvOBJ_VIDMEM) + { + if (mr->node->VidMem.locked == 0) break; + } + else + { + if (mr->node->Virtual.locked == 0) break; + } + + gckVIDMEM_Unlock(mr->node, gcvSURF_TYPE_UNKNOWN, gcvNULL); + } + + gckVIDMEM_Free(mr->node); + + kfree(mr); + + MEMORY_LOCK(Os); + } + + MEMORY_UNLOCK(Os); + + if (i > 0) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "======== Total %d unfreed video/contiguous/virtual memory ========", i); + } +} +#endif + +/******************************************************************************* +** gckOS_CacheFlush +** +** Flush the cache for the specified addresses. The GPU is going to need the +** data. If the system is allocating memory as non-cachable, this function can +** be ignored. +** +** ARGUMENTS: +** +** gckOS Os +** Pointer to gckOS object. +** +** gctHANDLE Process +** Process handle Logical belongs to or gcvNULL if Logical belongs to +** the kernel. +** +** gctPOINTER Logical +** Logical address to flush. +** +** gctSIZE_T Bytes +** Size of the address range in bytes to flush. +*/ +gceSTATUS +gckOS_CacheFlush( + IN gckOS Os, + IN gctHANDLE Process, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ) +{ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** gckOS_CacheInvalidate +** +** Flush the cache for the specified addresses and invalidate the lines as +** well. The GPU is going to need and modify the data. If the system is +** allocating memory as non-cachable, this function can be ignored. +** +** ARGUMENTS: +** +** gckOS Os +** Pointer to gckOS object. +** +** gctHANDLE Process +** Process handle Logical belongs to or gcvNULL if Logical belongs to +** the kernel. +** +** gctPOINTER Logical +** Logical address to flush. +** +** gctSIZE_T Bytes +** Size of the address range in bytes to flush. +*/ +gceSTATUS +gckOS_CacheInvalidate( + IN gckOS Os, + IN gctHANDLE Process, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ) +{ + return gcvSTATUS_OK; +} + +/******************************************************************************* +********************************* Broadcasting ********************************* +*******************************************************************************/ + +/******************************************************************************* +** +** gckOS_Broadcast +** +** System hook for broadcast events from the kernel driver. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object. +** +** gceBROADCAST Reason +** Reason for the broadcast. Can be one of the following values: +** +** gcvBROADCAST_GPU_IDLE +** Broadcasted when the kernel driver thinks the GPU might be +** idle. This can be used to handle power management. +** +** gcvBROADCAST_GPU_COMMIT +** Broadcasted when any client process commits a command +** buffer. This can be used to handle power management. +** +** gcvBROADCAST_GPU_STUCK +** Broadcasted when the kernel driver hits the timeout waiting +** for the GPU. +** +** gcvBROADCAST_FIRST_PROCESS +** First process is trying to connect to the kernel. +** +** gcvBROADCAST_LAST_PROCESS +** Last process has detached from the kernel. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_Broadcast( + IN gckOS Os, + IN gckHARDWARE Hardware, + IN gceBROADCAST Reason + ) +{ + gceSTATUS status; + gctUINT32 idle = 0, dma = 0, axi = 0, read0 = 0, read1 = 0, write = 0; + + gcmkHEADER_ARG("Os=0x%x Hardware=0x%x Reason=%d", Os, Hardware, Reason); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + switch (Reason) + { + case gcvBROADCAST_FIRST_PROCESS: + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "First process has attached"); + break; + + case gcvBROADCAST_LAST_PROCESS: + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "Last process has detached"); + + /* Put GPU OFF. */ + gcmkONERROR( + gckHARDWARE_SetPowerManagementState(Hardware, + gcvPOWER_OFF_BROADCAST)); + + break; + + case gcvBROADCAST_GPU_IDLE: + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "GPU idle."); + + /* Put GPU IDLE. */ + gcmkONERROR( + gckHARDWARE_SetPowerManagementState(Hardware, + gcvPOWER_IDLE_BROADCAST)); + + break; + + case gcvBROADCAST_GPU_COMMIT: + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "COMMIT has arrived."); + + /* Put GPU ON. */ + gcmkONERROR( + gckHARDWARE_SetPowerManagementState(Hardware, gcvPOWER_ON)); + break; + + case gcvBROADCAST_GPU_STUCK: + gcmkONERROR(gckHARDWARE_GetIdle(Hardware, gcvFALSE, &idle)); + gcmkONERROR(gckOS_ReadRegister(Os, 0x00C, &axi)); + gcmkONERROR(gckOS_ReadRegister(Os, 0x664, &dma)); + gcmkPRINT("!!FATAL!! GPU Stuck"); + gcmkPRINT(" idle=0x%08X axi=0x%08X cmd=0x%08X", idle, axi, dma); + + if (Hardware->chipFeatures & (1 << 4)) + { + gcmkONERROR(gckOS_ReadRegister(Os, 0x43C, &read0)); + gcmkONERROR(gckOS_ReadRegister(Os, 0x440, &read1)); + gcmkONERROR(gckOS_ReadRegister(Os, 0x444, &write)); + gcmkPRINT(" read0=0x%08X read1=0x%08X write=0x%08X", + read0, read1, write); + } + + gcmkONERROR(gckKERNEL_Recovery(Hardware->kernel)); + break; + + case gcvBROADCAST_AXI_BUS_ERROR: + gcmkONERROR(gckHARDWARE_GetIdle(Hardware, gcvFALSE, &idle)); + gcmkONERROR(gckOS_ReadRegister(Os, 0x00C, &axi)); + gcmkONERROR(gckOS_ReadRegister(Os, 0x664, &dma)); + gcmkPRINT("!!FATAL!! AXI Bus Error"); + gcmkPRINT(" idle=0x%08X axi=0x%08X cmd=0x%08X", idle, axi, dma); + + if (Hardware->chipFeatures & (1 << 4)) + { + gcmkONERROR(gckOS_ReadRegister(Os, 0x43C, &read0)); + gcmkONERROR(gckOS_ReadRegister(Os, 0x440, &read1)); + gcmkONERROR(gckOS_ReadRegister(Os, 0x444, &write)); + gcmkPRINT(" read0=0x%08X read1=0x%08X write=0x%08X", + read0, read1, write); + } + + gcmkONERROR(gckKERNEL_Recovery(Hardware->kernel)); + break; + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +********************************** Semaphores ********************************** +*******************************************************************************/ + +/******************************************************************************* +** +** gckOS_CreateSemaphore +** +** Create a semaphore. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** OUTPUT: +** +** gctPOINTER * Semaphore +** Pointer to the variable that will receive the created semaphore. +*/ +gceSTATUS +gckOS_CreateSemaphore( + IN gckOS Os, + OUT gctPOINTER * Semaphore + ) +{ + gceSTATUS status; + struct semaphore *sem; + + gcmkHEADER_ARG("Os=0x%x", Os); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL); + + /* Allocate the semaphore structure. */ + gcmkONERROR( + gckOS_Allocate(Os, gcmSIZEOF(struct semaphore), (gctPOINTER *) &sem)); + + /* Initialize the semaphore. */ + sema_init(sem, 1); + + /* Return to caller. */ + *Semaphore = (gctPOINTER) sem; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_AcquireSemaphore +** +** Acquire a semaphore. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** gctPOINTER Semaphore +** Pointer to the semaphore thet needs to be acquired. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_AcquireSemaphore( + IN gckOS Os, + IN gctPOINTER Semaphore + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%x", Os); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL); + + /* Acquire the semaphore. */ + if (down_interruptible((struct semaphore *) Semaphore)) + { + gcmkONERROR(gcvSTATUS_TIMEOUT); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_ReleaseSemaphore +** +** Release a previously acquired semaphore. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** gctPOINTER Semaphore +** Pointer to the semaphore thet needs to be released. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_ReleaseSemaphore( + IN gckOS Os, + IN gctPOINTER Semaphore + ) +{ + gcmkHEADER_ARG("Os=0x%x Semaphore=0x%x", Os, Semaphore); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL); + + /* Release the semaphore. */ + up((struct semaphore *) Semaphore); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_DestroySemaphore +** +** Destroy a semaphore. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** gctPOINTER Semaphore +** Pointer to the semaphore thet needs to be destroyed. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_DestroySemaphore( + IN gckOS Os, + IN gctPOINTER Semaphore + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%x Semaphore=0x%x", Os, Semaphore); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL); + + /* Free the sempahore structure. */ + gcmkONERROR(gckOS_Free(Os, Semaphore)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_GetProcessID +** +** Get current process ID. +** +** INPUT: +** +** Nothing. +** +** OUTPUT: +** +** gctUINT32_PTR ProcessID +** Pointer to the variable that receives the process ID. +*/ +gceSTATUS +gckOS_GetProcessID( + OUT gctUINT32_PTR ProcessID + ) +{ + gcmkHEADER(); + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(ProcessID != gcvNULL); + + /* Get process ID. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) + *ProcessID = task_tgid_vnr(current); +#else + *ProcessID = current->tgid; +#endif + + /* Success. */ + gcmkFOOTER_ARG("*ProcessID=%u", *ProcessID); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_GetThreadID +** +** Get current thread ID. +** +** INPUT: +** +** Nothing. +** +** OUTPUT: +** +** gctUINT32_PTR ThreadID +** Pointer to the variable that receives the thread ID. +*/ +gceSTATUS +gckOS_GetThreadID( + OUT gctUINT32_PTR ThreadID + ) +{ + gcmkHEADER(); + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(ThreadID != gcvNULL); + + /* Get thread ID. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) + *ThreadID = task_pid_vnr(current); +#else + *ThreadID = current->pid; +#endif + + /* Success. */ + gcmkFOOTER_ARG("*ThreadID=%u", *ThreadID); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_SetGPUPower +** +** Set the power of the GPU on or off. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctBOOL Clock +** gcvTRUE to turn on the clock, or gcvFALSE to turn off the clock. +** +** gctBOOL Power +** gcvTRUE to turn on the power, or gcvFALSE to turn off the power. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_SetGPUPower( + IN gckOS Os, + IN gctBOOL Clock, + IN gctBOOL Power + ) +{ + gcmkHEADER_ARG("Os=0x%x Clock=%d Power=%d", Os, Clock, Power); + + /* TODO: Put your code here. */ + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + diff --git a/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_os.h b/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_os.h new file mode 100644 index 000000000000..087b55e5ced8 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/os/linux/kernel/gc_hal_kernel_os.h @@ -0,0 +1,106 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_kernel_os_h_ +#define __gc_hal_kernel_os_h_ + +typedef struct _LINUX_MDL_MAP +{ + gctINT pid; + gctPOINTER vmaAddr; + struct vm_area_struct * vma; + struct _LINUX_MDL_MAP * next; +} +LINUX_MDL_MAP, *PLINUX_MDL_MAP; + +typedef struct _LINUX_MDL +{ + gctINT pid; + char * addr; + +#ifdef NO_DMA_COHERENT + gctPOINTER kaddr; +#endif /* NO_DMA_COHERENT */ + + gctINT numPages; + gctINT pagedMem; + gctBOOL contiguous; + dma_addr_t dmaHandle; + PLINUX_MDL_MAP maps; + struct _LINUX_MDL * prev; + struct _LINUX_MDL * next; +} +LINUX_MDL, *PLINUX_MDL; + +extern PLINUX_MDL_MAP +FindMdlMap( + IN PLINUX_MDL Mdl, + IN gctINT PID + ); + +typedef struct _DRIVER_ARGS +{ + gctPOINTER InputBuffer; + gctUINT32 InputBufferSize; + gctPOINTER OutputBuffer; + gctUINT32 OutputBufferSize; +} +DRIVER_ARGS; + +/* Cleanup the signal table. */ +gceSTATUS +gckOS_CleanProcessSignal( + gckOS Os, + gctHANDLE Process + ); + +#ifdef gcdkUSE_MEMORY_RECORD +MEMORY_RECORD_PTR +CreateMemoryRecord( + gckOS Os, + MEMORY_RECORD_PTR List, + gcuVIDMEM_NODE_PTR Node + ); + +void +DestoryMemoryRecord( + gckOS Os, + MEMORY_RECORD_PTR Mr + ); + +MEMORY_RECORD_PTR +FindMemoryRecord( + gckOS Os, + MEMORY_RECORD_PTR List, + gcuVIDMEM_NODE_PTR Node + ); + +void +FreeAllMemoryRecord( + gckOS Os, + MEMORY_RECORD_PTR List + ); +#endif + +#endif /* __gc_hal_kernel_os_h_ */ + diff --git a/drivers/staging/rk29/vivante/hal/os/qnx/inc/gc_hal_common_qnx.h b/drivers/staging/rk29/vivante/hal/os/qnx/inc/gc_hal_common_qnx.h new file mode 100644 index 000000000000..a5d1bfe368c6 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/os/qnx/inc/gc_hal_common_qnx.h @@ -0,0 +1,79 @@ +/**************************************************************************** +* +* Copyright (c) 2005 - 2010 by Vivante Corp. All rights reserved. +* +* The material in this file is confidential and contains trade secrets +* of Vivante Corporation. This is proprietary information owned by +* Vivante Corporation. No part of this work may be disclosed, +* reproduced, copied, transmitted, or used in any way for any purpose, +* without the express written permission of Vivante Corporation. +* +***************************************************************************** +* +* Auto-generated file on 10/12/2010. Do not edit!!! +* +*****************************************************************************/ + + +/* + * gc_hal_common_qnx.h + * + * Created on: Jul 7, 2010 + * Author: tarang + */ + +#ifndef GC_HAL_COMMON_QNX_H_ +#define GC_HAL_COMMON_QNX_H_ + +/******************************************************************************\ +******************************* QNX Control Codes ****************************** +\******************************************************************************/ +#ifndef _IOMGR_VIVANTE +#define _IOMGR_VIVANTE (_IOMGR_PRIVATE_BASE + 0x301) +#endif + +/******************************************************************************* +** Signal management. +** +** Is much simpler in Neutrino versus Linux :-) +** +** Neutrino pulses are equivalent to RT signals (queued, small payload) except +** they are explicitly received on a channel. We therefore dedicate a thread +** to handle them. +** +** We don't use RT signals because: +** 1. They can be delivered on any thread. +** 2. We don't support SA_RESTART so blocking kernel calls can fail. It would be +** impossible to robustly handle this condition in all libraries. +** +** Only downside is that more information needs to be passed between client/server +** (signals require only PID, pulses require connection ID and receive ID). +*/ + +typedef struct _gcsSIGNAL +{ + /* Pointer to gcoOS object. */ + gcoOS os; + + /* Signaled state. */ + gctBOOL state; + + /* Manual reset flag. */ + gctBOOL manual; + + /* Mutex. */ + pthread_mutex_t mutex; + + /* Condition. */ + pthread_cond_t condition; + + /* Number of signals pending in the command queue. */ + gctINT pending; + + /* Number of signals received. */ + gctINT received; +} +gcsSIGNAL; + +#endif /* GC_HAL_COMMON_QNX_H_ */ + diff --git a/drivers/staging/rk29/vivante/hal/os/qnx/kernel/gc_hal_kernel_debug.c b/drivers/staging/rk29/vivante/hal/os/qnx/kernel/gc_hal_kernel_debug.c new file mode 100644 index 000000000000..e8ca7e688c13 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/os/qnx/kernel/gc_hal_kernel_debug.c @@ -0,0 +1,435 @@ +/**************************************************************************** +* +* Copyright (c) 2005 - 2010 by Vivante Corp. All rights reserved. +* +* The material in this file is confidential and contains trade secrets +* of Vivante Corporation. This is proprietary information owned by +* Vivante Corporation. No part of this work may be disclosed, +* reproduced, copied, transmitted, or used in any way for any purpose, +* without the express written permission of Vivante Corporation. +* +***************************************************************************** +* +* Auto-generated file on 10/12/2010. Do not edit!!! +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_qnx.h" +#include + +/* + gcdBUFFERED_OUTPUT + + When set to non-zero, all output is collected into a buffer with the + specified size. Once the buffer gets full, or the token "$$FLUSH$$" has + been received, the debug buffer will be printed to the console. +*/ +#define gcdBUFFERED_OUTPUT 0 + +/******************************************************************************\ +******************************** Debug Variables ******************************* +\******************************************************************************/ + +static gceSTATUS _lastError = gcvSTATUS_OK; +static gctUINT32 _debugLevel = gcvLEVEL_ERROR; +static gctUINT32 _debugZones = gcvZONE_NONE; +static gctINT _indent = 0; + +static void +OutputDebugString( + IN gctCONST_STRING String + ) +{ +#if gcdBUFFERED_OUTPUT + static gctCHAR outputBuffer[gcdBUFFERED_OUTPUT]; + static gctINT outputBufferIndex = 0; + gctINT n, i; + + n = (String != gcvNULL) ? strlen(String) + 1 : 0; + + if ((n == 0) || (outputBufferIndex + n > gcmSIZEOF(outputBuffer))) + { + for (i = 0; i < outputBufferIndex; i += strlen(outputBuffer + i) + 1) + { + printf(outputBuffer + i); + } + + outputBufferIndex = 0; + } + + if (n > 0) + { + memcpy(outputBuffer + outputBufferIndex, String, n); + outputBufferIndex += n; + } +#else + if (String != gcvNULL) + { + printf(String); + } +#endif +} + +static void +_Print( + IN gctCONST_STRING Message, + IN va_list Arguments + ) +{ + char buffer[1024]; + int i, n; + + if (strcmp(Message, "$$FLUSH$$") == 0) + { + OutputDebugString(gcvNULL); + return; + } + + if (strncmp(Message, "--", 2) == 0) + { + if (_indent == 0) + { + printf("ERROR: _indent=0\n"); + } + + _indent -= 2; + } + + for (i = 0; i < _indent; ++i) + { + buffer[i] = ' '; + } + + /* Print message to buffer. */ + n = vsnprintf(buffer + i, sizeof(buffer) - i, Message, Arguments); + if ((n <= 0) || (buffer[i + n - 1] != '\n')) + { + /* Append new-line. */ + strncat(buffer, "\n", sizeof(buffer)); + } + + /* Output to debugger. */ + OutputDebugString(buffer); + + if (strncmp(Message, "++", 2) == 0) + { + _indent += 2; + } +} + +/******************************************************************************\ +********************************* Debug Macros ********************************* +\******************************************************************************/ + +#define _DEBUGPRINT(Message) \ +{ \ + va_list arguments; \ + \ + va_start(arguments, Message); \ + _Print(Message, arguments); \ + va_end(arguments); \ +} + +/******************************************************************************\ +********************************** Debug Code ********************************** +\******************************************************************************/ + +/******************************************************************************* +** +** gckOS_Print +** +** Send a message to the debugger. +** +** INPUT: +** +** gctCONST_STRING Message +** Pointer to message. +** +** ... +** Optional arguments. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_Print( + IN gctCONST_STRING Message, + ... + ) +{ + _DEBUGPRINT(Message); +} + +/******************************************************************************* +** +** gckOS_DebugTrace +** +** Send a leveled message to the debugger. +** +** INPUT: +** +** gctUINT32 Level +** Debug level of message. +** +** gctCONST_STRING Message +** Pointer to message. +** +** ... +** Optional arguments. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_DebugTrace( + IN gctUINT32 Level, + IN gctCONST_STRING Message, + ... + ) +{ + if (Level > _debugLevel) + { + return; + } + + _DEBUGPRINT(Message); +} + +/******************************************************************************* +** +** gckOS_DebugTraceZone +** +** Send a leveled and zoned message to the debugger. +** +** INPUT: +** +** gctUINT32 Level +** Debug level for message. +** +** gctUINT32 Zone +** Debug zone for message. +** +** gctCONST_STRING Message +** Pointer to message. +** +** ... +** Optional arguments. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_DebugTraceZone( + IN gctUINT32 Level, + IN gctUINT32 Zone, + IN gctCONST_STRING Message, + ... + ) +{ + if ((Level > _debugLevel) || !(Zone & _debugZones)) + { + return; + } + + _DEBUGPRINT(Message); +} + +/******************************************************************************* +** +** gckOS_DebugBreak +** +** Break into the debugger. +** +** INPUT: +** +** Nothing. +** +** OUTPUT: +** +** Nothing. +*/ +void +gckOS_DebugBreak( + void + ) +{ + gckOS_DebugTrace(gcvLEVEL_ERROR, "gckOS_DebugBreak"); +} + +/******************************************************************************* +** +** gckOS_DebugFatal +** +** Send a message to the debugger and break into the debugger. +** +** INPUT: +** +** gctCONST_STRING Message +** Pointer to message. +** +** ... +** Optional arguments. +** +** OUTPUT: +** +** Nothing. +*/ +void +gckOS_DebugFatal( + IN gctCONST_STRING Message, + ... + ) +{ + _DEBUGPRINT(Message); + + /* Break into the debugger. */ + gckOS_DebugBreak(); +} + +/******************************************************************************* +** +** gckOS_SetDebugLevel +** +** Set the debug level. +** +** INPUT: +** +** gctUINT32 Level +** New debug level. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_SetDebugLevel( + IN gctUINT32 Level + ) +{ + _debugLevel = Level; +} + +/******************************************************************************* +** +** gckOS_SetDebugZone +** +** Set the debug zone. +** +** INPUT: +** +** gctUINT32 Zone +** New debug zone. +** +** OUTPUT: +** +** Nothing. +*/ +void +gckOS_SetDebugZone( + IN gctUINT32 Zone + ) +{ + _debugZones = Zone; +} + +/******************************************************************************* +** +** gckOS_SetDebugLevelZone +** +** Set the debug level and zone. +** +** INPUT: +** +** gctUINT32 Level +** New debug level. +** +** gctUINT32 Zone +** New debug zone. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_SetDebugLevelZone( + IN gctUINT32 Level, + IN gctUINT32 Zone + ) +{ + _debugLevel = Level; + _debugZones = Zone; +} + +/******************************************************************************* +** +** gckOS_SetDebugZones +** +** Enable or disable debug zones. +** +** INPUT: +** +** gctUINT32 Zones +** Debug zones to enable or disable. +** +** gctBOOL Enable +** Set to gcvTRUE to enable the zones (or the Zones with the current +** zones) or gcvFALSE to disable the specified Zones. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_SetDebugZones( + IN gctUINT32 Zones, + IN gctBOOL Enable + ) +{ + if (Enable) + { + /* Enable the zones. */ + _debugZones |= Zones; + } + else + { + /* Disable the zones. */ + _debugZones &= ~Zones; + } +} + +/******************************************************************************* +** +** gckOS_Verify +** +** Called to verify the result of a function call. +** +** INPUT: +** +** gceSTATUS Status +** Function call result. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_Verify( + IN gceSTATUS Status + ) +{ + _lastError = Status; +} + diff --git a/drivers/staging/rk29/vivante/hal/os/qnx/kernel/gc_hal_kernel_device.c b/drivers/staging/rk29/vivante/hal/os/qnx/kernel/gc_hal_kernel_device.c new file mode 100644 index 000000000000..0ca6f4fab432 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/os/qnx/kernel/gc_hal_kernel_device.c @@ -0,0 +1,812 @@ +/**************************************************************************** +* +* Copyright (c) 2005 - 2010 by Vivante Corp. All rights reserved. +* +* The material in this file is confidential and contains trade secrets +* of Vivante Corporation. This is proprietary information owned by +* Vivante Corporation. No part of this work may be disclosed, +* reproduced, copied, transmitted, or used in any way for any purpose, +* without the express written permission of Vivante Corporation. +* +***************************************************************************** +* +* Auto-generated file on 10/12/2010. Do not edit!!! +* +*****************************************************************************/ + + + + + +#include "gc_hal_kernel_qnx.h" +#include +#include + +#define _GC_OBJ_ZONE gcvZONE_DEVICE + +/******************************************************************************\ +******************************** gckGALDEVICE Code ******************************* +\******************************************************************************/ + +gceSTATUS +gckGALDEVICE_AllocateMemory( + IN gckGALDEVICE Device, + IN gctSIZE_T Bytes, + OUT gctPOINTER *Logical, + OUT gctPHYS_ADDR *Physical, + OUT gctUINT32 *PhysAddr + ) +{ + gceSTATUS status; + + gcmkVERIFY_ARGUMENT(Device != NULL); + gcmkVERIFY_ARGUMENT(Logical != NULL); + gcmkVERIFY_ARGUMENT(Physical != NULL); + gcmkVERIFY_ARGUMENT(PhysAddr != NULL); + + status = gckOS_AllocateContiguous(Device->os, + gcvFALSE, + &Bytes, + Physical, + Logical); + + if (gcmIS_ERROR(status)) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER, + "gckGALDEVICE_AllocateMemory: error status->0x%x", + status); + + return status; + } + + *PhysAddr = (gctUINT32)(*(off_t*) Physical) - Device->baseAddress; + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "gckGALDEVICE_AllocateMemory: phys_addr->0x%x phsical->0x%x Logical->0x%x", + (gctUINT32)*Physical, + (gctUINT32)*PhysAddr, + (gctUINT32)*Logical); + + /* Success. */ + return gcvSTATUS_OK; +} + +gceSTATUS +gckGALDEVICE_FreeMemory( + IN gckGALDEVICE Device, + IN gctPOINTER Logical, + IN gctPHYS_ADDR Physical) +{ + gcmkVERIFY_ARGUMENT(Device != NULL); + + return gckOS_FreeContiguous(Device->os, + Physical, + Logical, + 0); +} + +/* TODO. fix global sigevent to be part of device. */ +struct sigevent irqEvent; + +const struct sigevent* isrRoutine(void* arg, int id) +{ + gckGALDEVICE device = (gckGALDEVICE)arg; + + /* Call kernel interrupt notification. */ + if (gckKERNEL_Notify(device->kernel, + gcvNOTIFY_INTERRUPT, + gcvTRUE) == gcvSTATUS_OK) + { + InterruptUnmask(device->irqLine, device->irqId); + + return &irqEvent; + } + + return gcvNULL; +} + +static void* threadRoutine(void *ctxt) +{ + gckGALDEVICE device = (gckGALDEVICE) ctxt; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "Starting ISR Thread with irq:%d\n", + device->irqLine); + + SIGEV_INTR_INIT(&irqEvent); + + /* Obtain I/O privileges */ + ThreadCtl( _NTO_TCTL_IO, 0 ); + + device->irqId = InterruptAttach(device->irqLine, + isrRoutine, + (void*)device, + gcmSIZEOF(struct _gckGALDEVICE), + 0); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_DRIVER, + "irqId:%d\n", + device->irqId); + + if (device->irqId < 0) { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Setup_ISR: " + "Could not register irq line->%d\n", + device->irqLine); + + device->isrInitialized = gcvFALSE; + + return (void *)1; + } + + printf("[Interrupt] Attached irqLine %d with id %d.\n", + device->irqLine, device->irqId); + + device->isrInitialized = gcvTRUE; + + while (1) + { + if (InterruptWait(0, NULL) == -1) + { + printf("[Interrupt] IST exiting\n"); + /* Either something is wrong or the thread got canceled */ + InterruptUnmask(device->irqLine, device->irqId); + pthread_exit(NULL); + } + + gckKERNEL_Notify(device->kernel, gcvNOTIFY_INTERRUPT, gcvFALSE); + } + + return (void *)0; +} + +/******************************************************************************* +** +** gckGALDEVICE_Setup_ISR +** +** Start the ISR routine. +** +** INPUT: +** +** gckGALDEVICE Device +** Pointer to an gckGALDEVICE object. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** gcvSTATUS_OK +** Setup successfully. +** gcvSTATUS_GENERIC_IO +** Setup failed. +*/ +gceSTATUS +gckGALDEVICE_Setup_ISR( + IN gckGALDEVICE Device + ) +{ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckGALDEVICE_Release_ISR +** +** Release the irq line. +** +** INPUT: +** +** gckGALDEVICE Device +** Pointer to an gckGALDEVICE object. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** Nothing. +*/ +gceSTATUS +gckGALDEVICE_Release_ISR( + IN gckGALDEVICE Device + ) +{ + gcmkVERIFY_ARGUMENT(Device != NULL); + + return gcvSTATUS_OK; +} + + +int +gsl_free_interrupts() +{ + + return 0; +} +/******************************************************************************* +** +** gckGALDEVICE_Start_Thread +** +** Start the daemon thread. +** +** INPUT: +** +** gckGALDEVICE Device +** Pointer to an gckGALDEVICE object. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** gcvSTATUS_OK +** Start successfully. +** gcvSTATUS_GENERIC_IO +** Start failed. +*/ +gceSTATUS +gckGALDEVICE_Start_Thread( + IN gckGALDEVICE Device + ) +{ + pthread_attr_t attr; + struct sched_param sched; + gctINT ret; + gcmkVERIFY_ARGUMENT(Device != NULL); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Start_Thread: Creating threadRoutine\n"); + + pthread_attr_init(&attr); + pthread_attr_getschedparam(&attr, &sched); + sched.sched_priority += 10; + pthread_attr_setschedparam(&attr, &sched); + pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); + + /* Start the interrupt service thread */ + if ((ret = pthread_create(&Device->threadCtxt, &attr, threadRoutine, Device)) != 0) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Start_Thread: Failed with code %d\n", + ret); + + return gcvSTATUS_OUT_OF_RESOURCES; + } + + pthread_setname_np(Device->threadCtxt, "galcore-IST"); + + Device->threadInitialized = gcvTRUE; + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Start_Thread: " + "Start the daemon thread.\n"); + + return gcvSTATUS_OK; +} + + +/******************************************************************************* +** +** gckGALDEVICE_Stop_Thread +** +** Stop the gal device, including the following actions: stop the daemon +** thread, release the irq. +** +** INPUT: +** +** gckGALDEVICE Device +** Pointer to an gckGALDEVICE object. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** Nothing. +*/ +gceSTATUS +gckGALDEVICE_Stop_Thread( + gckGALDEVICE Device + ) +{ + gcmkVERIFY_ARGUMENT(Device != NULL); + + /* stop the thread */ + if (Device->threadInitialized) + { + InterruptDetach(Device->irqId); + Device->irqId = 0; + ConnectDetach(Device->coid); + Device->coid = 0; + ChannelDestroy(Device->chid); + Device->chid = 0; + + pthread_cancel(Device->threadCtxt); + pthread_join(Device->threadCtxt, NULL); + Device->threadCtxt = 0; + + Device->threadInitialized = gcvFALSE; + Device->isrInitialized = gcvFALSE; + } + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckGALDEVICE_Start +** +** Start the gal device, including the following actions: setup the isr routine +** and start the daemon thread. +** +** INPUT: +** +** gckGALDEVICE Device +** Pointer to an gckGALDEVICE object. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** gcvSTATUS_OK +** Start successfully. +*/ +gceSTATUS +gckGALDEVICE_Start( + IN gckGALDEVICE Device + ) +{ + gceSTATUS ret; + /* Start the daemon thread. */ + gcmkVERIFY_OK((ret = gckGALDEVICE_Start_Thread(Device))); + + return ret; +} + +/******************************************************************************* +** +** gckGALDEVICE_Stop +** +** Stop the gal device, including the following actions: stop the daemon +** thread, release the irq. +** +** INPUT: +** +** gckGALDEVICE Device +** Pointer to an gckGALDEVICE object. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** Nothing. +*/ +gceSTATUS +gckGALDEVICE_Stop( + gckGALDEVICE Device + ) +{ + gcmkVERIFY_ARGUMENT(Device != NULL); + + if (Device->threadInitialized) + { + gckGALDEVICE_Stop_Thread(Device); + } + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckGALDEVICE_Construct +** +** Constructor. +** +** INPUT: +** +** OUTPUT: +** +** gckGALDEVICE * Device +** Pointer to a variable receiving the gckGALDEVICE object pointer on +** success. +*/ +gceSTATUS +gckGALDEVICE_Construct( + IN gctINT IrqLine, + IN gctUINT32 RegisterMemBase, + IN gctSIZE_T RegisterMemSize, + IN gctUINT32 ContiguousBase, + IN gctSIZE_T ContiguousSize, + IN gctSIZE_T BankSize, + IN gctINT FastClear, + IN gctINT Compression, + IN gctUINT32 BaseAddress, + OUT gckGALDEVICE *Device + ) +{ + gctUINT32 internalBaseAddress, internalAlignment; + gctUINT32 externalBaseAddress, externalAlignment; + gctUINT32 horizontalTileSize, verticalTileSize; + gctUINT32 physAddr; + gctUINT32 physical; + gckGALDEVICE device; + gceSTATUS status; + + gcmkTRACE(gcvLEVEL_VERBOSE, "[galcore] Enter gckGALDEVICE_Construct\n"); + + /* Allocate device structure. */ + device = calloc(1, sizeof(struct _gckGALDEVICE)); + if (!device) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Construct: Can't allocate memory.\n"); + + return gcvSTATUS_OUT_OF_MEMORY; + } + + physical = RegisterMemBase; + + /* Set up register memory region */ + if (physical != 0) + { + /* Request a region. */ + device->registerBase = (gctPOINTER)mmap_device_io(RegisterMemSize, RegisterMemBase); + + if ((uintptr_t)device->registerBase == MAP_DEVICE_FAILED) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Construct: Unable to map location->0x%lX for size->%ld\n", + RegisterMemBase, + RegisterMemSize); + + return gcvSTATUS_OUT_OF_RESOURCES; + } + + physical += RegisterMemSize; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Construct: " + "RegisterBase after mapping Address->0x%x is 0x%x\n", + (gctUINT32)RegisterMemBase, + (gctUINT32)device->registerBase); + } + + /* construct the gckOS object */ + device->baseAddress = BaseAddress; + gcmkONERROR( + gckOS_Construct(device, &device->os)); + + /* construct the gckKERNEL object. */ + gcmkONERROR( + gckKERNEL_Construct(device->os, device, &device->kernel)); + + gcmkONERROR( + gckHARDWARE_SetFastClear(device->kernel->hardware, + FastClear, + Compression)); + + /* query the ceiling of the system memory */ + gcmkONERROR( + gckHARDWARE_QuerySystemMemory(device->kernel->hardware, + &device->systemMemorySize, + &device->systemMemoryBaseAddress)); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Construct: " + "Will be trying to allocate contiguous memory of 0x%x bytes\n", + (gctUINT32)device->systemMemoryBaseAddress); + +#if COMMAND_PROCESSOR_VERSION == 1 + /* start the command queue */ + gcmkVERIFY_OK(gckCOMMAND_Start(device->kernel->command)); +#endif + + /* initialize the thread daemon */ + memset(&device->isrLock, 0, sizeof(device->isrLock)); + + device->threadInitialized = gcvFALSE; + device->killThread = gcvFALSE; + + /* initialize the isr */ + device->isrInitialized = gcvFALSE; + device->dataReady = gcvFALSE; + device->irqLine = IrqLine; + + /* query the amount of video memory */ + gcmkVERIFY_OK(gckHARDWARE_QueryMemory(device->kernel->hardware, + &device->internalSize, + &internalBaseAddress, + &internalAlignment, + &device->externalSize, + &externalBaseAddress, + &externalAlignment, + &horizontalTileSize, + &verticalTileSize)); + + /* set up the internal memory region */ + if (device->internalSize > 0) + { + gceSTATUS status = gckVIDMEM_Construct(device->os, + internalBaseAddress, + device->internalSize, + internalAlignment, + 0, + &device->internalVidMem); + + if (gcmIS_ERROR(status)) + { + /* error, remove internal heap */ + device->internalSize = 0; + } + else + { + /* map internal memory */ + device->internalPhysical = (gctPHYS_ADDR)physical; + device->internalLogical = (gctPOINTER)mmap_device_io(device->internalSize, physical); + + gcmkASSERT(device->internalLogical != NULL); + + physical += device->internalSize; + } + } + + if (device->externalSize > 0) + { + /* create the external memory heap */ + gceSTATUS status = gckVIDMEM_Construct(device->os, + externalBaseAddress, + device->externalSize, + externalAlignment, + 0, + &device->externalVidMem); + + if (gcmIS_ERROR(status)) + { + /* error, remove internal heap */ + device->externalSize = 0; + } + else + { + /* map internal memory */ + device->externalPhysical = (gctPHYS_ADDR)physical; + device->externalLogical = (gctPOINTER)mmap_device_io(device->externalSize, physical); + + gcmkASSERT(device->externalLogical != NULL); + + physical += device->externalSize; + } + } + + /* set up the contiguous memory */ + device->contiguousSize = ContiguousSize; + + if (ContiguousBase == 0) + { + status = gcvSTATUS_OUT_OF_MEMORY; + + while (device->contiguousSize > 0) + { + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Construct: Will be trying to allocate contiguous memory of %ld bytes\n", + device->contiguousSize + ); + + /* allocate contiguous memory */ + status = gckGALDEVICE_AllocateMemory( + device, + device->contiguousSize, + &device->contiguousBase, + &device->contiguousPhysical, + &physAddr + ); + + if (gcmIS_SUCCESS(status)) + { + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Construct: Contiguous allocated size->0x%08X Virt->0x%08lX physAddr->0x%08X\n", + device->contiguousSize, + device->contiguousBase, + physAddr + ); + + status = gckVIDMEM_Construct( + device->os, + physAddr | device->systemMemoryBaseAddress, + device->contiguousSize, + 64, + BankSize, + &device->contiguousVidMem + ); + + if (gcmIS_SUCCESS(status)) + { + device->contiguousMapped = gcvFALSE; + + /* success, abort loop */ + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_DRIVER, + "Using %u bytes of contiguous memory.\n", + device->contiguousSize + ); + + break; + } + + gcmkVERIFY_OK(gckGALDEVICE_FreeMemory( + device, + device->contiguousBase, + device->contiguousPhysical + )); + + device->contiguousBase = NULL; + } + + device->contiguousSize -= (4 << 20); + } + } + else + { + /* Create the contiguous memory heap. */ + status = gckVIDMEM_Construct( + device->os, + (ContiguousBase - device->baseAddress) | device->systemMemoryBaseAddress, + ContiguousSize, + 64, + BankSize, + &device->contiguousVidMem + ); + + if (gcmIS_ERROR(status)) + { + /* Error, roll back. */ + device->contiguousVidMem = gcvNULL; + device->contiguousSize = 0; + } + else + { + /* Map the contiguous memory. */ + device->contiguousPhysical = (gctPHYS_ADDR) ContiguousBase; + device->contiguousSize = ContiguousSize; + device->contiguousBase = (gctPOINTER) mmap_device_io(ContiguousSize, ContiguousBase); + device->contiguousMapped = gcvTRUE; + + if (device->contiguousBase == gcvNULL) + { + /* Error, roll back. */ + gcmkVERIFY_OK(gckVIDMEM_Destroy(device->contiguousVidMem)); + device->contiguousVidMem = gcvNULL; + device->contiguousSize = 0; + + status = gcvSTATUS_OUT_OF_RESOURCES; + } + } + } + + *Device = device; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Construct: Initialized device->0x%x contiguous->%lu @ 0x%x (0x%08X)\n", + device, + device->contiguousSize, + device->contiguousBase, + device->contiguousPhysical); + + return gcvSTATUS_OK; +OnError: + /* Roll back. */ + + /* Destroy the gckKERNEL object. */ + if ( Device != gcvNULL) + { + gcmkVERIFY_OK(gckGALDEVICE_Destroy(*Device)); + } + + /* Return the status. */ + return status; +} + +/******************************************************************************* +** +** gckGALDEVICE_Destroy +** +** Class destructor. +** +** INPUT: +** +** Nothing. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** Nothing. +*/ +gceSTATUS +gckGALDEVICE_Destroy( + gckGALDEVICE Device) +{ + gcmkVERIFY_ARGUMENT(Device != NULL); + + gcmkTRACE(gcvLEVEL_VERBOSE, "[ENTER] gckGALDEVICE_Destroy\n"); + + /* Destroy the gckKERNEL object. */ + gcmkVERIFY_OK(gckKERNEL_Destroy(Device->kernel)); + + if (Device->internalVidMem != gcvNULL) + { + /* destroy the internal heap */ + gcmkVERIFY_OK(gckVIDMEM_Destroy(Device->internalVidMem)); + + /* unmap the internal memory */ + munmap_device_io((uintptr_t)Device->internalLogical, Device->internalSize); + } + + if (Device->externalVidMem != gcvNULL) + { + /* destroy the internal heap */ + gcmkVERIFY_OK(gckVIDMEM_Destroy(Device->externalVidMem)); + + /* unmap the external memory */ + munmap_device_io((uintptr_t)Device->externalLogical, Device->externalSize); + } + + if (Device->contiguousVidMem != gcvNULL) + { + /* Destroy the contiguous heap */ + gcmkVERIFY_OK(gckVIDMEM_Destroy(Device->contiguousVidMem)); + + if (Device->contiguousMapped) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Destroy: " + "Unmapping contiguous memory->0x%08lX\n", + Device->contiguousBase); + + munmap_device_io((uintptr_t)Device->contiguousBase, Device->contiguousSize); + } + else + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Destroy: " + "Freeing contiguous memory->0x%08lX\n", + Device->contiguousBase); + + gcmkVERIFY_OK(gckGALDEVICE_FreeMemory(Device, + Device->contiguousBase, + Device->contiguousPhysical)); + } + } + + if (Device->registerBase) + { + munmap_device_io((uintptr_t)Device->registerBase, Device->registerSize); + } + + /* Destroy the gckOS object. */ + gcmkVERIFY_OK(gckOS_Destroy(Device->os)); + + free(Device); + + gcmkTRACE(gcvLEVEL_VERBOSE, "[galcore] Leave gckGALDEVICE_Destroy\n"); + + return gcvSTATUS_OK; +} + diff --git a/drivers/staging/rk29/vivante/hal/os/qnx/kernel/gc_hal_kernel_device.h b/drivers/staging/rk29/vivante/hal/os/qnx/kernel/gc_hal_kernel_device.h new file mode 100644 index 000000000000..fea415745289 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/os/qnx/kernel/gc_hal_kernel_device.h @@ -0,0 +1,123 @@ +/**************************************************************************** +* +* Copyright (c) 2005 - 2010 by Vivante Corp. All rights reserved. +* +* The material in this file is confidential and contains trade secrets +* of Vivante Corporation. This is proprietary information owned by +* Vivante Corporation. No part of this work may be disclosed, +* reproduced, copied, transmitted, or used in any way for any purpose, +* without the express written permission of Vivante Corporation. +* +***************************************************************************** +* +* Auto-generated file on 10/12/2010. Do not edit!!! +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_kernel_device_h_ +#define __gc_hal_kernel_device_h_ + +/******************************************************************************\ +******************************* gckGALDEVICE Structure ******************************* +\******************************************************************************/ + +#define GALCORE_INTERRUPT_PULSE 0x5D + +typedef struct _gckGALDEVICE +{ + /* Objects. */ + gckOS os; + gckKERNEL kernel; + + /* Attributes. */ + gctSIZE_T internalSize; + gctPHYS_ADDR internalPhysical; + gctPOINTER internalLogical; + gckVIDMEM internalVidMem; + gctSIZE_T externalSize; + gctPHYS_ADDR externalPhysical; + gctPOINTER externalLogical; + gckVIDMEM externalVidMem; + gckVIDMEM contiguousVidMem; + gctPOINTER contiguousBase; + gctPHYS_ADDR contiguousPhysical; + gctSIZE_T contiguousSize; + gctBOOL contiguousMapped; + gctPOINTER contiguousMappedUser; + gctSIZE_T systemMemorySize; + gctUINT32 systemMemoryBaseAddress; + gctPOINTER registerBase; + gctSIZE_T registerSize; + gctUINT32 baseAddress; + + /* IRQ management. */ + gctINT irqLine; + gctINT irqId; + gctBOOL isrInitialized; + gctBOOL dataReady; + intrspin_t isrLock; + struct sigevent event; + int chid; + int coid; + + /* Thread management. */ + pthread_t threadCtxt; + gctBOOL threadInitialized; + gctBOOL killThread; +} +* gckGALDEVICE; + +typedef struct _gcsHAL_PRIVATE_DATA +{ + gckGALDEVICE device; + gctPOINTER mappedMemory; + gctPOINTER contiguousLogical; +} +gcsHAL_PRIVATE_DATA, * gcsHAL_PRIVATE_DATA_PTR; + +gceSTATUS gckGALDEVICE_Setup_ISR( + IN gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Release_ISR( + IN gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Start_Thread( + IN gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Stop_Thread( + gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Start( + IN gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Stop( + gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Construct( + IN gctINT IrqLine, + IN gctUINT32 RegisterMemBase, + IN gctSIZE_T RegisterMemSize, + IN gctUINT32 ContiguousBase, + IN gctSIZE_T ContiguousSize, + IN gctSIZE_T BankSize, + IN gctINT FastClear, + IN gctINT Compression, + IN gctUINT32 BaseAddress, + OUT gckGALDEVICE *Device + ); + +gceSTATUS gckGALDEVICE_Destroy( + IN gckGALDEVICE Device + ); + +#endif /* __gc_hal_kernel_device_h_ */ + diff --git a/drivers/staging/rk29/vivante/hal/os/qnx/kernel/gc_hal_kernel_driver.c b/drivers/staging/rk29/vivante/hal/os/qnx/kernel/gc_hal_kernel_driver.c new file mode 100644 index 000000000000..0b279925d68f --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/os/qnx/kernel/gc_hal_kernel_driver.c @@ -0,0 +1,1367 @@ +/**************************************************************************** +* +* Copyright (c) 2005 - 2010 by Vivante Corp. All rights reserved. +* +* The material in this file is confidential and contains trade secrets +* of Vivante Corporation. This is proprietary information owned by +* Vivante Corporation. No part of this work may be disclosed, +* reproduced, copied, transmitted, or used in any way for any purpose, +* without the express written permission of Vivante Corporation. +* +***************************************************************************** +* +* Auto-generated file on 10/12/2010. Do not edit!!! +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_qnx.h" +#include "gc_hal_driver.h" +#include "gc_hal_user_context.h" + +# include + +static gckGALDEVICE galDevice; + +/* GN TODO take these from the graphics.conf file. */ +#ifdef MMP2 +int irqLine = 8; +long registerMemBase = 0xd420d000; +#else +int irqLine = 48; +long registerMemBase = 0xf1840000; +#endif + +/* Configurable Memory sizes. */ +unsigned long contiguousSize = ( 64 << 20); /* Video memory pool. */ +unsigned int internalPoolSize = ( 16 << 20); /* Kernel local memory pool. */ +unsigned int sharedPoolSize = ( 8 << 20); /* Shared per-client memory pool initial size. */ +unsigned long registerMemSize = (256 << 10); /* GPU register memory size. */ + +/* ContiguousBase should be 0, + * for video memory to be allocated from the memory pool. */ +unsigned long contiguousBase = 0; +long bankSize = 0; +int fastClear = -1; +int compression = -1; +unsigned long baseAddress = 0; + +/* Global video memory pool. */ +typedef struct _gcsMEM_POOL +{ + gctINT32 freePage; + gctSIZE_T pageCount; + gctUINT32 pageSize; + gctUINT32 poolSize; + pthread_mutex_t mutex; + gctUINT32 addr; + gctUINT32 paddr; + gckPAGE_USAGE pageUsage; + gctCHAR fdName[64]; + gctINT fd; +} gcsMEM_POOL; + +gcsMEM_POOL memPool; + +/* Pointer to list of shared memory pools. */ +gckSHM_POOL shmPoolList; +pthread_mutex_t shmPoolListMutex; + +/* Resource Manager Globals. */ +struct _gcsRESMGR_GLOBALS +{ + dispatch_t *dpp; + dispatch_context_t *ctp; + int id; + thread_pool_attr_t pool_attr; + thread_pool_t *tpp; + pthread_t root; +} resmgr_globals; + +win_gpu_2_cm_iface_t *g_qnx_gpu_2_cm_iface = 0; +static resmgr_connect_funcs_t connect_funcs; +static resmgr_io_funcs_t io_funcs; +static iofunc_attr_t attr; + +gceSTATUS gckVIDMEM_FreeHandleMemory(IN gckVIDMEM Memory, IN gctHANDLE Handle); + +gceSTATUS +drv_mempool_init() +{ + off64_t paddr; + void* addr; + size_t pcontig; + + /* Default 4KB page size. */ + memPool.pageSize = __PAGESIZE; + + /* Compute number of pages. */ + memPool.pageCount = (contiguousSize + internalPoolSize) / memPool.pageSize; + gcmkASSERT(memPool.pageCount <= 65536); + + /* Align memPoolSize to page size. */ + memPool.poolSize = memPool.pageCount * memPool.pageSize; + + /* Allocate a single chunk of physical memory. + * Zero memory with MAP_ANON so we don't leak any sensitive information by chance. */ + snprintf(memPool.fdName, sizeof(memPool.fdName), "galcore:vidmem:%d", getpid()); + memPool.fd = shm_open(memPool.fdName, O_RDWR|O_CREAT, 0777); + if (memPool.fd == -1) { + fprintf(stderr, "galcore:%s[%d]: shm_open failed\n", __FUNCTION__, __LINE__); + return gcvSTATUS_GENERIC_IO; + } + + shm_unlink(memPool.fdName); + + if (shm_ctl_special(memPool.fd, SHMCTL_ANON|SHMCTL_PHYS, 0, memPool.poolSize, 0x9) == -1) { + fprintf(stderr, "galcore:%s[%d]: shm_ctl_special failed\n", __FUNCTION__, __LINE__); + close(memPool.fd); + memPool.fd = -1; + return gcvSTATUS_GENERIC_IO; + } + + addr = mmap64(0, memPool.poolSize, PROT_READ|PROT_WRITE, MAP_SHARED, memPool.fd, 0); + if (addr == MAP_FAILED) { + fprintf(stderr, "galcore:%s[%d]: mmap64 failed\n", __FUNCTION__, __LINE__); + close(memPool.fd); + memPool.fd = -1; + return gcvSTATUS_GENERIC_IO; + } + memPool.addr = (gctUINT32)addr; + + if (mem_offset64(addr, NOFD, memPool.poolSize, &paddr, &pcontig) == -1) + { + fprintf(stderr, "galcore:%s[%d]: mem_offset64 failed\n", __FUNCTION__, __LINE__); + munmap(addr, memPool.poolSize); + close(memPool.fd); + memPool.fd = -1; + memPool.addr = NULL; + return gcvSTATUS_GENERIC_IO; + } + + /* TODO. Truncating 64bit value. */ + memPool.paddr = (gctUINT32)paddr; + + printf( "Mempool Map addr range[%x-%x]\n", memPool.addr, memPool.addr + memPool.poolSize); + printf( "Mempool Map paddr range[%x-%x]\n", memPool.paddr, memPool.paddr + memPool.poolSize ); + + /* Allocate the page usage array and Initialize all pages to free. */ + memPool.pageUsage = (gckPAGE_USAGE)calloc( + memPool.pageCount, + sizeof(struct _gckPAGE_USAGE)); + + if (memPool.pageUsage == gcvNULL) + { + fprintf( stderr, "malloc failed: %s\n", strerror( errno ) ); + munmap(addr, memPool.poolSize); + close(memPool.fd); + memPool.fd = -1; + memPool.addr = NULL; + memPool.paddr = 0; + return gcvSTATUS_GENERIC_IO; + } + + /* The first page is free.*/ + memPool.freePage = 0; + + /* Initialize the semaphore. */ + if (pthread_mutex_init(&memPool.mutex, NULL) != EOK) + { + free(memPool.pageUsage); + munmap(addr, memPool.poolSize); + close(memPool.fd); + memPool.fd = -1; + memPool.addr = NULL; + memPool.paddr = 0; + return gcvSTATUS_GENERIC_IO; + } + + return gcvSTATUS_OK; +} + +void +drv_mempool_destroy() +{ + pthread_mutex_destroy(&memPool.mutex); + free(memPool.pageUsage); + memPool.pageUsage = NULL; + munmap((void*)memPool.addr, memPool.poolSize); + close(memPool.fd); + memPool.fd = -1; + memPool.addr = NULL; + memPool.paddr = 0; +} + +gctINT +drv_mempool_get_fileDescriptor() +{ + return memPool.fd; +} + +gctUINT32 +drv_mempool_get_basePAddress() +{ + return memPool.paddr; +} + +gctUINT32 +drv_mempool_get_baseAddress() +{ + return memPool.addr; +} + +gctUINT32 +drv_mempool_get_page_size() +{ + return memPool.pageSize; +} + +gceSTATUS +drv_mempool_mem_offset( + IN gctPOINTER Logical, + OUT gctUINT32 * Address) +{ + gctUINT32 logical = (gctUINT32)Logical; + + if ( Address == gcvNULL ) + return gcvSTATUS_INVALID_ARGUMENT; + + if ( logical < memPool.addr + || logical > (memPool.addr + memPool.poolSize)) + return gcvSTATUS_INVALID_ARGUMENT; + + *Address = (logical - memPool.addr) + memPool.paddr; + + return gcvSTATUS_OK; +} + +/* Allocate pages from mapped shared memory. + Return Physical and Logical addresses. +*/ +void +drv_mempool_alloc_contiguous( + IN gctUINT32 Bytes, + OUT gctPHYS_ADDR * Physical, + OUT gctPOINTER * Logical + ) +{ + gctSIZE_T i, j; + gctSIZE_T pageCount; + + pthread_mutex_lock(&memPool.mutex); + + /* Compute the number of required pages. */ + pageCount = gcmALIGN(Bytes, drv_mempool_get_page_size()) / drv_mempool_get_page_size(); + + if ( (pageCount <= 0) || (memPool.freePage < 0) ) + { + *Physical = gcvNULL; + *Logical = gcvNULL; + pthread_mutex_unlock(&memPool.mutex); + /* No free pages left. */ + return; + } + + /* Try finding enough contiguous free pages. */ + for (i = memPool.freePage; i < memPool.pageCount;) + { + /* All pages behind this free page should be free. */ + gctSIZE_T j; + for (j = 1; j < pageCount; ++j) + { + if (memPool.pageUsage[i + j].pageCount != 0) + { + /* Bail out if page is allocated. */ + break; + } + } + + if (j == pageCount) + { + /* We found a spot that has enough free pages. */ + break; + } + + /* Move to the page after the allocated page. */ + i += j + 1; + + /* Find the next free page. */ + while ((i < memPool.pageCount) && (memPool.pageUsage[i].pageCount != 0)) + { + ++i; + } + } + + if (i >= memPool.pageCount) + { + *Physical = gcvNULL; + *Logical = gcvNULL; + pthread_mutex_unlock(&memPool.mutex); + /* Not enough contiguous pages. */ + return; + } + + /* Check if we allocate from the first free page. */ + if (i == memPool.freePage) + { + /* Move first free page to beyond the contiguous request. */ + memPool.freePage = i + pageCount; + + /* Find first free page. */ + while ( (memPool.freePage < memPool.pageCount) && + (memPool.pageUsage[memPool.freePage].pageCount != 0) ) + { + ++memPool.freePage; + } + + if (memPool.freePage >= memPool.pageCount) + { + /* No more free pages. */ + memPool.freePage = -1; + } + } + + /* Walk all pages. */ + for (j = 0; j < pageCount; ++j) + { + /* Store page count in each pageUsage to mark page is allocated. */ + memPool.pageUsage[i+j].pageCount = pageCount; + } + + gcmkTRACE(gcvLEVEL_INFO, "Allocated %u contiguous pages from 0x%X\n", + pageCount, i); + + /* Success. */ + *Physical = (gctPHYS_ADDR)(i * memPool.pageSize + (gctUINT32)memPool.paddr); + *Logical = (gctPOINTER)(i * memPool.pageSize + (gctUINT32)memPool.addr); + + pthread_mutex_unlock(&memPool.mutex); +} + +int drv_mempool_free(gctPOINTER Logical) +{ + gctUINT16 pageCount; + gctSIZE_T i; + gctINT32 pageIndex; + + gcmkTRACE(gcvLEVEL_INFO, "Freeing pages @ %x\n", Logical); + + pthread_mutex_lock(&memPool.mutex); + + pageIndex = ((gctUINT32)Logical - (gctUINT32)memPool.addr) / memPool.pageSize; + + /* Verify the memory is valid and unlocked. */ + if ( (pageIndex < 0) || (pageIndex >= memPool.pageCount) ) + { + pthread_mutex_unlock(&memPool.mutex); + gcmkTRACE(gcvLEVEL_ERROR, "Invalid page index @ %d\n", pageIndex); + return -1; + } + + pageCount = memPool.pageUsage[pageIndex].pageCount; + + /* Mark all used pages as free. */ + for (i = 0; i < pageCount; ++i) + { + gcmkASSERT(memPool.pageUsage[i + pageIndex].pageCount == pageCount); + + memPool.pageUsage[i + pageIndex].pageCount = 0; + } + + /* Update first free page. */ + if ( (memPool.freePage < 0) || (pageIndex < memPool.freePage) ) + { + memPool.freePage = pageIndex; + } + + pthread_mutex_unlock(&memPool.mutex); + + gcmkTRACE(gcvLEVEL_INFO, "Free'd %u contiguos pages from 0x%X @ 0x%x\n", + pageCount, pageIndex); + + return 1; +} + +/* + * Initialize shm pool list and mutex. + */ +gceSTATUS +drv_shm_init() +{ + shmPoolList = gcvNULL; + pthread_mutex_init(&shmPoolListMutex, 0); + return gcvSTATUS_OK; +/* resmgr_globals.shmpool = gcvNULL; + return pthread_mutex_init(&resmgr_globals.shmMutex, 0);*/ +} + +gceSTATUS +drv_shm_destroy() +{ + gckSHM_POOL shmPool; + gctUINT32 count = 0; + + pthread_mutex_destroy(&shmPoolListMutex); + + shmPool = shmPoolList; + while (shmPool != gcvNULL) + { + /* Remove this pool from the list. */ + drv_shmpool_destroy(shmPool); + + shmPool = shmPool->nextPool; + count++; + } + + return gcvSTATUS_OK; +/* resmgr_globals.shmpool = gcvNULL; + return pthread_mutex_destroy(&resmgr_globals.shmMutex);*/ +} + +/* + * Get the shm pool associated with this Handle and PID and lock it. + * Create one, if not present. + */ +gckSHM_POOL +drv_shm_acquire_pool( + IN gctUINT32 Pid, + IN gctHANDLE Handle + ) +{ + gckSHM_POOL shmPool, tail = gcvNULL; + + pthread_mutex_lock(&shmPoolListMutex); + + shmPool = shmPoolList; + while (shmPool != gcvNULL) + { + if (shmPool->Handle == Handle && shmPool->pid == Pid) + { + pthread_mutex_unlock(&shmPoolListMutex); + return shmPool; + } + + tail = shmPool; + shmPool = shmPool->nextPool; + } + + /* TODO: Start with smaller shmMemory pool size and increase on demand. */ + /* Default 4KB page size. */ + shmPool = drv_shmpool_create(Pid, Handle, sharedPoolSize, __PAGESIZE); + + /* Add this pool to tail. */ + if ( shmPool != gcvNULL ) + { + if (tail != gcvNULL ) + { + tail->nextPool = shmPool; + } + else + { + /* Set this pool as head. */ + shmPoolList = shmPool; + } + + shmPool->nextPool = gcvNULL; + } + else + { + /* Failed to create new shmPool. */ + } + + pthread_mutex_unlock(&shmPoolListMutex); + return shmPool; +} + +/* + * Get the shm pool associated with this Logical pointer. + */ +gckSHM_POOL +drv_shm_acquire_pool2( + IN gctPOINTER Logical + ) +{ + gckSHM_POOL shmPool, tail = gcvNULL; + + pthread_mutex_lock(&shmPoolListMutex); + + shmPool = shmPoolList; + while (shmPool != gcvNULL) + { + /* Check if this address is in range of this shmPool. */ + if (shmPool->Logical <= (gctUINT32)Logical && + (shmPool->Logical + shmPool->pageCount * shmPool->pageSize) > (gctUINT32)Logical) + { + pthread_mutex_unlock(&shmPoolListMutex); + return shmPool; + } + + tail = shmPool; + shmPool = shmPool->nextPool; + } + + /* Failed to find associated shmPool. */ + pthread_mutex_unlock(&shmPoolListMutex); + return shmPool; +} + +/* + * Remove the shm pool associated with this ocb. + */ +gceSTATUS +drv_shm_remove_pool( + IN gctHANDLE Handle + ) +{ + gckSHM_POOL shmPool, prev = gcvNULL; + + pthread_mutex_lock(&shmPoolListMutex); + + shmPool = shmPoolList; + + while (shmPool != gcvNULL) + { + /* Remove this pool from the list. */ + if (shmPool->Handle == Handle) + { + if (prev == gcvNULL) + { + shmPoolList = shmPool->nextPool; + } + else + { + prev->nextPool = shmPool->nextPool; + } + + drv_shmpool_destroy(shmPool); + + pthread_mutex_unlock(&shmPoolListMutex); + return gcvSTATUS_OK; + } + + prev = shmPool; + shmPool = shmPool->nextPool; + } + + pthread_mutex_unlock(&shmPoolListMutex); + + return gcvSTATUS_INVALID_ARGUMENT; +} + +gceSTATUS +drv_shmpool_mem_offset( + IN gctPOINTER Logical, + OUT gctUINT32 * Address) +{ + gctUINT32 logical = (gctUINT32)Logical; + gckSHM_POOL shmPool; + + if ( Address == gcvNULL ) + return gcvSTATUS_INVALID_ARGUMENT; + + pthread_mutex_lock(&shmPoolListMutex); + + shmPool = shmPoolList; + while (shmPool != gcvNULL) + { + if ( (logical >= shmPool->Logical) + && (logical < (shmPool->Logical + shmPool->pageCount * shmPool->pageSize))) + { + *Address = (logical - shmPool->Logical ) + shmPool->Physical; + pthread_mutex_unlock(&shmPoolListMutex); + return gcvSTATUS_OK; + } + + shmPool = shmPool->nextPool; + } + + pthread_mutex_unlock(&shmPoolListMutex); + + return gcvSTATUS_INVALID_ARGUMENT; +} + +/* Initialize a shm pool with this ocb. */ +gckSHM_POOL drv_shmpool_create( + IN gctUINT32 Pid, + IN gctHANDLE Handle, + IN gctUINT32 PoolSize, + IN gctUINT32 PageSize) +{ + int rc, poolSize; + void* addr; + char shm_file_name[20] = "shm_galcore"; + gctUINT32 i, pid; + gckSHM_POOL shm = (gckSHM_POOL) calloc(1, sizeof(struct _gckSHM_POOL)); + + /* Compute number of pages. */ + shm->pageSize = PageSize; + shm->pageCount = PoolSize / shm->pageSize; + gcmkASSERT(shm->pageCount <= 65536); + + /* Align poolSize to pageSize. */ + poolSize = shm->pageCount * shm->pageSize; + + shm->pid = Pid; + shm->Handle = Handle; + + /* Initialize the semaphore. */ + if (pthread_mutex_init(&shm->mutex, NULL) != EOK) + { + fprintf( stderr, "pthread_mutex_init failed: %s\n", strerror( errno ) ); + free(shm); + return gcvNULL; + } + + /* Create a pseudo unique name, so as to not open + * the same file twice from different threads at the same time. */ + pid = Pid; + i = strlen(shm_file_name); + while(pid) + { + shm_file_name[i++] = (char)(pid % 10 + '0'); + pid /= 10; + } + shm_file_name[i] = '\0'; + + shm->fd = shm_open(shm_file_name, O_RDWR | O_CREAT, 0777); + if (shm->fd == -1) { + free(shm); + return gcvNULL; + } + + shm_unlink(shm_file_name); + + /* Special flags for this shm, to make it write buffered. */ + rc = shm_ctl_special(shm->fd, + SHMCTL_ANON | SHMCTL_PHYS /*| SHMCTL_LAZYWRITE*/, + 0, + poolSize, + 0x9); + if (rc == -1) { + close(shm->fd); + free(shm); + return gcvNULL; + } + + /* Map this memory inside user and galcore. */ + addr = mmap64_join(Pid, + 0, + poolSize, + PROT_READ | PROT_WRITE, + MAP_SHARED, + shm->fd, + 0); + if (addr == MAP_FAILED) + { + free(shm); + return gcvNULL; + } + + /* TODO: Dont close fd if need to truncate shm later. */ + rc = close(shm->fd); + if (rc == -1) { + free(shm); + return gcvNULL; + } + + shm->Logical = (gctUINT32) addr; + + /* fd should be NOFD here, to get physical address. */ + rc = mem_offset( addr, NOFD, 1, (off_t *)&shm->Physical, NULL); + if (rc == -1) { + free(shm); + return gcvNULL; + } + + /* TODO: MLOCK may or may not be needed!. */ + mlock((void*)shm->Logical, poolSize); + + /* Allocate the page usage array and Initialize all pages to free. */ + shm->pageUsage = (gckPAGE_USAGE)calloc(shm->pageCount, sizeof(struct _gckPAGE_USAGE)); + if (shm->pageUsage == gcvNULL) + { + munmap((void*)shm->Logical, poolSize); + munmap_peer(Pid, (void*)shm->Logical, poolSize); + free(shm); + return gcvNULL; + } + + /* The first page is free. */ + shm->freePage = 0; + + return shm; +} + +void +drv_shmpool_destroy( + IN gckSHM_POOL ShmPool) +{ + if (ShmPool) + { + int poolSize = ShmPool->pageCount * ShmPool->pageSize; + if (ShmPool->pageUsage) + free(ShmPool->pageUsage); + if (ShmPool->Logical) + { + munmap((void*)ShmPool->Logical, poolSize); + munmap_peer(ShmPool->pid, (void*)ShmPool->Logical, poolSize); + } + } +} + +gctUINT32 +drv_shmpool_get_BaseAddress( + IN gckSHM_POOL ShmPool + ) +{ + gcmkASSERT(ShmPool != 0); + + if (!ShmPool) + return 0; + + return ShmPool->Logical; +} + +gctUINT32 +drv_shmpool_get_page_size( + IN gckSHM_POOL ShmPool + ) +{ + gcmkASSERT(ShmPool != 0); + + if (!ShmPool) + return 0; + + return ShmPool->pageSize; +} + +/* Allocate pages from mapped shared memory. + Return Logical user address. +*/ +gctPOINTER +drv_shmpool_alloc_contiguous( + IN gctUINT32 Pid, + IN gctHANDLE Handle, + IN gctUINT32 Bytes + ) +{ + gctSIZE_T i, j; + int pageSize; + gctSIZE_T pageCount; + gckSHM_POOL shmPool = drv_shm_acquire_pool(Pid, Handle); + + if (shmPool == gcvNULL) + { + return gcvNULL; + } + /* Compute the number of required pages. */ + pageSize = drv_shmpool_get_page_size(shmPool); + if ( pageSize == 0 ) + { + /* Invalid pageSize. */ + return gcvNULL; + } + + pageCount = gcmALIGN(Bytes, pageSize) / pageSize; + + if ( (pageCount <= 0) || (shmPool->freePage < 0) ) + { + /* No free pages left. */ + return gcvNULL; + } + + if ( (pageCount <= 0) || (shmPool->freePage < 0) ) + { + /* No free pages left. */ + return gcvNULL; + } + + /* Try finding enough contiguous free pages. */ + for (i = shmPool->freePage; i < shmPool->pageCount;) + { + /* All pages behind this free page should be free. */ + gctSIZE_T j; + for (j = 1; j < pageCount; ++j) + { + if (shmPool->pageUsage[i + j].pageCount != 0) + { + /* Bail out if page is allocated. */ + break; + } + } + + if (j == pageCount) + { + /* We found a spot that has enough free pages. */ + break; + } + + /* Move to the page after the allocated page. */ + i += j + 1; + + /* Find the next free page. */ + while ((i < shmPool->pageCount) && (shmPool->pageUsage[i].pageCount != 0)) + { + ++i; + } + } + + if (i >= shmPool->pageCount) + { + /* Not enough contiguous pages. */ + return gcvNULL; + } + + /* Check if we allocate from the first free page. */ + if (i == shmPool->freePage) + { + /* Move first free page to beyond the contiguous request. */ + shmPool->freePage = i + pageCount; + + /* Find first free page. */ + while ( (shmPool->freePage < shmPool->pageCount) && + (shmPool->pageUsage[shmPool->freePage].pageCount != 0) ) + { + ++shmPool->freePage; + } + + if (shmPool->freePage >= shmPool->pageCount) + { + /* No more free pages. */ + shmPool->freePage = -1; + } + } + + /* Walk all pages. */ + for (j = 0; j < pageCount; ++j) + { + /* Store page count in each pageUsage to mark page is allocated. */ + shmPool->pageUsage[i+j].pageCount = pageCount; + } + + gcmkTRACE(gcvLEVEL_INFO, "Allocated %u contiguos pages from 0x%X\n", + pageCount, i); + + /* Success. */ + return (gctPOINTER)(i * shmPool->pageSize + shmPool->Logical); +} + +gctUINT32 +drv_shmpool_free( + IN gctPOINTER Logical + ) +{ + gctUINT16 pageCount; + gctSIZE_T i; + gctINT32 pageIndex; + gckSHM_POOL shmPool = drv_shm_acquire_pool2(Logical); + + if (shmPool == gcvNULL) + { + gcmkTRACE(gcvLEVEL_ERROR, "Invalid Logical addr: %x.\n", Logical); + return 0; + } + + pageIndex = ((gctUINT32)Logical - shmPool->Logical)/shmPool->pageSize; + + gcmkTRACE(gcvLEVEL_INFO, "Freeing pages @ %d\n", pageIndex); + + /* Verify the memory is valid and unlocked. */ + if ( (pageIndex < 0) || (pageIndex >= shmPool->pageCount) ) + { + gcmkTRACE(gcvLEVEL_ERROR, "Invalid page index @ %d\n", pageIndex); + + return 0; + } + + pageCount = shmPool->pageUsage[pageIndex].pageCount; + + /* Mark all used pages as free. */ + for (i = 0; i < pageCount; ++i) + { + gcmkASSERT(shmPool->pageUsage[i + pageIndex].pageCount == pageCount); + + shmPool->pageUsage[i + pageIndex].pageCount = 0; + } + + /* Update first free page. */ + if ( (shmPool->freePage < 0) || (pageIndex < shmPool->freePage) ) + { + shmPool->freePage = pageIndex; + } + + gcmkTRACE(gcvLEVEL_INFO, "Free'd %u contiguos pages from 0x%X @ 0x%x\n", + pageCount, pageIndex); + + return 1; +} + +int drv_msg(resmgr_context_t *ctp, + io_msg_t *msg, + RESMGR_OCB_T *ocb) +{ + gcsDRIVER_ARGS *drvArgs = (gcsDRIVER_ARGS *)msg; + int rc; + gceSTATUS status; + gcsQUEUE_PTR queue; + +#define UNLOCK_RESMGR +#ifdef UNLOCK_RESMGR + iofunc_attr_unlock(&attr); +#endif + + if ((drvArgs->iomsg.i.type != _IO_MSG) + || (drvArgs->iomsg.i.mgrid != _IOMGR_VIVANTE) + || (drvArgs->iomsg.i.subtype != IOCTL_GCHAL_INTERFACE + && drvArgs->iomsg.i.subtype != IOCTL_GCHAL_KERNEL_INTERFACE + && drvArgs->iomsg.i.subtype != IOCTL_GCHAL_TERMINATE)) + { + /* Unknown command. Fail the I/O. */ +#ifdef UNLOCK_RESMGR + iofunc_attr_lock(&attr); +#endif + rc = ENOSYS; + if (ctp->info.scoid != -1) + return _RESMGR_STATUS(ctp, rc); + return _RESMGR_NOREPLY; + } + + if (drvArgs->iomsg.i.subtype == IOCTL_GCHAL_TERMINATE) + { + /* terminate the resource manager */ + pthread_kill(resmgr_globals.root, SIGTERM); +#ifdef UNLOCK_RESMGR + iofunc_attr_lock(&attr); +#endif + return _RESMGR_NOREPLY; + } + + /* Save channel handle and pid for later functions. */ + drvArgs->iface.handle = (gctHANDLE)ocb; + drvArgs->iface.pid = (gctUINT32)ctp->info.pid; + + /* Store receive ID with signal event so that we can later respond via pulse. */ + switch (drvArgs->iface.command) + { + case gcvHAL_SIGNAL: + printf("Setup rcvid as:%d\n", ctp->rcvid); + drvArgs->iface.u.Signal.rcvid = ctp->rcvid; + break; + + case gcvHAL_EVENT_COMMIT: + for (queue = drvArgs->iface.u.Event.queue; queue != gcvNULL; queue = queue->next) + { + if (queue->iface.command == gcvHAL_SIGNAL) + { + queue->iface.u.Signal.rcvid = ctp->rcvid; + } + } + break; + + default: + break; + } + + status = gckKERNEL_Dispatch(galDevice->kernel, + (drvArgs->iomsg.i.subtype == IOCTL_GCHAL_INTERFACE), + &drvArgs->iface); + + if (gcmIS_ERROR(status)) + { + gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DRIVER, + "[galcore] gckKERNEL_Dispatch returned %d.\n", + status); + } + else if (gcmIS_ERROR(drvArgs->iface.status)) + { + gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DRIVER, + "[galcore] IOCTL %d returned %d.\n", + drvArgs->iface.command, + drvArgs->iface.status); + } + + /* Reply data back to the user. */ + MsgReply(ctp->rcvid, EOK, (gctPOINTER) &drvArgs->iface, sizeof(gcsHAL_INTERFACE)); + +#ifdef UNLOCK_RESMGR + iofunc_attr_lock(&attr); +#endif + + gcmkTRACE(gcvLEVEL_INFO, "Replied message with command %d, status %d\n", + drvArgs->iface.command, + drvArgs->iface.status); + + return (_RESMGR_NOREPLY); +} + +static int drv_init(void) +{ + /* TODO: Enable clock by driver support? */ + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_DRIVER, + "Entering drv_init\n"); + + /* Create the GAL device. */ + gcmkVERIFY_OK(gckGALDEVICE_Construct(irqLine, + registerMemBase, + registerMemSize, + contiguousBase, + contiguousSize, + bankSize, + fastClear, + compression, + baseAddress, + &galDevice)); + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_DRIVER, + "galcore device constructed.\n"); + + /* Start the GAL device. */ + if (gcmIS_ERROR(gckGALDEVICE_Start(galDevice))) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER, + "[galcore] Can't start the gal device.\n"); + + /* Roll back. */ + gckGALDEVICE_Stop(galDevice); + gckGALDEVICE_Destroy(galDevice); + + return -1; + } + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "[galcore] irqLine->%ld, contiguousSize->%lu, memBase->0x%lX\n", + irqLine, + contiguousSize, + registerMemBase); + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_DRIVER, + "[galcore] driver registered successfully.\n"); + + return 0; +} + +static void drv_exit(void) +{ + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_DRIVER, + "[galcore] Entering drv_exit\n"); + + gckGALDEVICE_Stop(galDevice); + gckGALDEVICE_Destroy(galDevice); + +} + +/* Invoked by OS, when a connection is closed or dies. */ +int +drv_close_ocb(resmgr_context_t *ctp, void *reserved, RESMGR_OCB_T *ocb) +{ + gckVIDMEM videoMemory; + gceSTATUS status; + + /* Free virtual memory owned by this client. */ + gckMMU_FreeHandleMemory(galDevice->kernel->mmu, (gctHANDLE)ocb); + + /* Free system memory owned by the client. */ + status = gckKERNEL_GetVideoMemoryPool(galDevice->kernel, gcvPOOL_SYSTEM, &videoMemory); + + if (status == gcvSTATUS_OK) + { + gckVIDMEM_FreeHandleMemory(videoMemory, + (gctHANDLE)ocb); + } + + /* Free shared memory and its mapping. */ + drv_shm_remove_pool(ocb); + + return iofunc_close_ocb_default(ctp, reserved, ocb); +} + +int gpu_init() +{ + /* Declare variables we'll be using. */ + resmgr_attr_t resmgr_attr; + sigset_t sigset; + int rc; + + if (drv_mempool_init() != gcvSTATUS_OK) + { + fprintf(stderr, "drv_mempool_init failed."); + goto fail_001; + } + + if (drv_shm_init() != gcvSTATUS_OK) + { + fprintf(stderr, "drv_mempool_init failed."); + goto fail_002; + } + + if (drv_init() != 0) + { + fprintf(stderr, "drv_init failed."); + goto fail_003; + } + + /* initialize dispatch interface */ + if((resmgr_globals.dpp = dispatch_create()) == NULL) + { + fprintf(stderr, "Unable to allocate dispatch handle.\n"); + goto fail_004; + } + + /* initialize resource manager attributes */ + memset(&resmgr_attr, 0, sizeof resmgr_attr); + resmgr_attr.nparts_max = 1; + resmgr_attr.msg_max_size = 2048; + + /* initialize functions for handling messages */ + iofunc_func_init(_RESMGR_CONNECT_NFUNCS, &connect_funcs, + _RESMGR_IO_NFUNCS, &io_funcs); + + /* Register io handling functions. */ + io_funcs.msg = drv_msg; + io_funcs.close_ocb = drv_close_ocb; + + + /* initialize attribute structure used by the device */ + iofunc_attr_init(&attr, S_IFNAM | 0666, 0, 0); + + /* attach our device name */ + resmgr_globals.id = resmgr_attach( + resmgr_globals.dpp,/* dispatch handle */ + &resmgr_attr, /* resource manager attrs */ + GAL_DEV, /* device name */ + _FTYPE_ANY, /* open type */ + _RESMGR_FLAG_SELF, /* flags */ + &connect_funcs, /* connect routines */ + &io_funcs, /* I/O routines */ + &attr); /* handle */ + if (resmgr_globals.id == -1) { + fprintf(stderr, "Unable to attach name.\n"); + goto fail_005; + } + + /* Prevent signals from affecting resmgr threads. */ + sigfillset(&sigset); + sigdelset(&sigset, SIGTERM); + pthread_sigmask(SIG_BLOCK, &sigset, NULL); + + /* initialize thread pool attributes */ + memset(&resmgr_globals.pool_attr, 0, sizeof(resmgr_globals.pool_attr)); + resmgr_globals.pool_attr.handle = resmgr_globals.dpp; + resmgr_globals.pool_attr.context_alloc = resmgr_context_alloc; + resmgr_globals.pool_attr.block_func = resmgr_block; + resmgr_globals.pool_attr.unblock_func = resmgr_unblock; + resmgr_globals.pool_attr.handler_func = resmgr_handler; + resmgr_globals.pool_attr.context_free = resmgr_context_free; + resmgr_globals.pool_attr.lo_water = 2; + resmgr_globals.pool_attr.hi_water = 4; + resmgr_globals.pool_attr.increment = 1; + resmgr_globals.pool_attr.maximum = 50; +#if (defined(_NTO_VERSION) && (_NTO_VERSION >= 650)) + resmgr_globals.pool_attr.tid_name = "galcore-message-handler"; +#endif + + /* allocate a thread pool handle */ + resmgr_globals.tpp = thread_pool_create(&resmgr_globals.pool_attr, POOL_FLAG_EXIT_SELF); + if (resmgr_globals.tpp == NULL) + { + goto fail_006; + } + + rc = pthread_create(NULL, resmgr_globals.pool_attr.attr, (void * (*)(void *))thread_pool_start, resmgr_globals.tpp); + if (rc != 0) + { + goto fail_007; + } + + /* TODO: gpu_suspend, gpu_resume */ + + return EXIT_SUCCESS; + +fail_007: + thread_pool_destroy(resmgr_globals.tpp); +fail_006: + resmgr_detach(resmgr_globals.dpp, resmgr_globals.id, 0); +fail_005: + dispatch_destroy(resmgr_globals.dpp); +fail_004: + drv_exit(); +fail_003: + drv_shm_destroy(); +fail_002: + drv_mempool_destroy(); +fail_001: + return EXIT_FAILURE; +} + +int gpu_fini() +{ + thread_pool_destroy(resmgr_globals.tpp); + resmgr_detach(resmgr_globals.dpp, resmgr_globals.id, 0); + dispatch_destroy(resmgr_globals.dpp); + drv_exit(); + drv_shm_destroy(); + drv_mempool_destroy(); + return EXIT_SUCCESS; +} + +#ifndef QNX_USE_OLD_FRAMEWORK + +int GPU_Startup(win_gpu_2_cm_iface_t *iface) +{ + g_qnx_gpu_2_cm_iface = iface; + return gpu_init(); +} + +int GPU_Shutdown() +{ + g_qnx_gpu_2_cm_iface = NULL; + return gpu_fini(); +} + +void win_gpu_module_getfuncs(win_cm_2_gpu_iface_t *iface) +{ + iface->init = GPU_Startup; + iface->fini = GPU_Shutdown; +} + +#else /* QNX_USE_OLD_FRAMEWORK */ + +int drv_resmgr_loop() +{ + sigset_t sigset; + siginfo_t info; + + resmgr_globals.root = pthread_self(); + + /* Background ourselves */ + procmgr_daemon(EXIT_SUCCESS, PROCMGR_DAEMON_NODEVNULL | + PROCMGR_DAEMON_NOCHDIR | + PROCMGR_DAEMON_NOCLOSE); + + /* + * This thread ignores all signals except SIGTERM. On receipt of + * a SIGTERM, we shut everything down and exit. + */ + sigemptyset(&sigset); + sigaddset(&sigset, SIGTERM); + + while (1) + { + if (SignalWaitinfo(&sigset, &info) == -1) + continue; + if (info.si_signo == SIGTERM) + { + break; + } + } + + return EXIT_SUCCESS; +} + +int drv_start_cmd() +{ + int rc; + + printf("Starting up...\n"); + fflush(stdout); + + pthread_setname_np(pthread_self(), "vivante-monitor"); + + if ((rc = gpu_init()) != EXIT_SUCCESS) + { + fprintf(stderr, "Initialization failed!, Exiting."); + exit(EXIT_FAILURE); + } + + printf("Running galcore...\n"); + fflush(stdout); + rc = drv_resmgr_loop(); + printf("Shutting down galcore...\n"); + fflush(stdout); + + gpu_fini(); + + return EXIT_SUCCESS; +} + +int drv_stop_cmd() +{ + gcsDRIVER_ARGS args; + int fd, rc; + + /* Open the gpu device. */ + fd = open(DRV_NAME, O_RDONLY); + if (fd == -1) + { + fprintf(stderr, "Could not connect to " DRV_NAME); + return EXIT_FAILURE; + } + + /* Send the term message. */ + args.iomsg.i.type = _IO_MSG; + args.iomsg.i.subtype = IOCTL_GCHAL_TERMINATE; + args.iomsg.i.mgrid = _IOMGR_VIVANTE; + args.iomsg.i.combine_len = sizeof(io_msg_t); + + do { + rc = MsgSend_r(fd, &args, args.iomsg.i.combine_len, NULL, 0); + } while ((rc * -1) == EINTR); + + return EXIT_SUCCESS; +} + +int main(int argc, char **argv) +{ + enum { start, stop } cmd = start; + int i; + int rc = EXIT_FAILURE; + + /* Process command lines -start, -stop, -c (file), -d [file]. */ + for (i = 1; i < argc; i++) + { + if (stricmp(argv[i], "-start") == 0) + { + cmd = start; + } + else if (strcmp(argv[i], "-stop") == 0) + { + cmd = stop; + } + else if (strncmp(argv[i], "-poolsize=", strlen("-poolsize=")) == 0) + { + /* The syntax of the poolsize option is -poolsize=(number). + * All we need is to convert the number that starts after the '='.*/ + contiguousSize = atoi(argv[i] + strlen("-poolsize=")); + if (contiguousSize <= 0) + { + fprintf(stderr, "%s: poolsize needs to be a positive number\n", strerror(errno)); + return rc; + } + } + else + { + fprintf(stderr, "%s: bad command line\n", argv[0]); + return rc; + } + } + + switch (cmd) + { + case start: + /* Elevate thread priority to do IO. */ + ThreadCtl(_NTO_TCTL_IO, 0); + rc = drv_start_cmd(); + break; + + case stop: + rc = drv_stop_cmd(); + break; + } + + return rc; +} + +#endif /* QNX_USE_OLD_FRAMEWORK */ + diff --git a/drivers/staging/rk29/vivante/hal/os/qnx/kernel/gc_hal_kernel_os.c b/drivers/staging/rk29/vivante/hal/os/qnx/kernel/gc_hal_kernel_os.c new file mode 100644 index 000000000000..0416ca802c27 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/os/qnx/kernel/gc_hal_kernel_os.c @@ -0,0 +1,3008 @@ +/**************************************************************************** +* +* Copyright (c) 2005 - 2010 by Vivante Corp. All rights reserved. +* +* The material in this file is confidential and contains trade secrets +* of Vivante Corporation. This is proprietary information owned by +* Vivante Corporation. No part of this work may be disclosed, +* reproduced, copied, transmitted, or used in any way for any purpose, +* without the express written permission of Vivante Corporation. +* +***************************************************************************** +* +* Auto-generated file on 10/12/2010. Do not edit!!! +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_qnx.h" + + + +# include + +#define USE_VMALLOC 0 + +#define _GC_OBJ_ZONE gcvZONE_OS + +#define MEMORY_LOCK(os) \ + gcmkVERIFY_OK(gckOS_AcquireMutex( \ + (os), \ + (os)->memoryLock, \ + gcvINFINITE)) + +#define MEMORY_UNLOCK(os) \ + gcmkVERIFY_OK(gckOS_ReleaseMutex((os), (os)->memoryLock)) + +#define MEMORY_MAP_LOCK(os) \ + gcmkVERIFY_OK(gckOS_AcquireMutex( \ + (os), \ + (os)->memoryMapLock, \ + gcvINFINITE)) + +#define MEMORY_MAP_UNLOCK(os) \ + gcmkVERIFY_OK(gckOS_ReleaseMutex((os), (os)->memoryMapLock)) + +/******************************************************************************\ +********************************** Structures ********************************** +\******************************************************************************/ + +struct _gckOS +{ + /* Object. */ + gcsOBJECT object; + + /* Heap. */ + gckHEAP heap; + + /* Pointer to device */ + gckGALDEVICE device; + + /* Memory management */ + gctPOINTER memoryLock; + gctPOINTER memoryMapLock; + gctPOINTER mempoolBaseAddress; + gctPOINTER mempoolBasePAddress; + gctUINT32 mempoolPageSize; + + gctUINT32 baseAddress; + + /* Atomic operation lock. */ + gctPOINTER atomicOperationLock; +}; + + +typedef struct _gcskSIGNAL +{ + pthread_mutex_t *mutex; + + /* Manual reset flag. */ + gctBOOL manualReset; +} +gcskSIGNAL; + +typedef struct _gcskSIGNAL * gcskSIGNAL_PTR; + + +/******************************************************************************* +** +** gckOS_Construct +** +** Construct a new gckOS object. +** +** INPUT: +** +** gctPOINTER Context +** Pointer to the gckGALDEVICE class. +** +** OUTPUT: +** +** gckOS * Os +** Pointer to a variable that will hold the pointer to the gckOS object. +*/ +gceSTATUS gckOS_Construct( + IN gctPOINTER Context, + OUT gckOS * Os + ) +{ + gckOS os; + gceSTATUS status; + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Os != gcvNULL); + + /* Allocate the gckOS object. */ + os = (gckOS) malloc(gcmSIZEOF(struct _gckOS)); + + if (os == gcvNULL) + { + /* Out of memory. */ + return gcvSTATUS_OUT_OF_MEMORY; + } + + /* Zero the memory. */ + memset(os, 0, gcmSIZEOF(struct _gckOS)); + + /* Initialize the gckOS object. */ + os->object.type = gcvOBJ_OS; + + /* Set device device. */ + os->device = Context; + + /* IMPORTANT! No heap yet. */ + os->heap = gcvNULL; + + /* Initialize the memory lock. */ + gcmkONERROR( + gckOS_CreateMutex(os, &os->memoryLock)); + + gcmkONERROR( + gckOS_CreateMutex(os, &os->memoryMapLock)); + + /* Create the gckHEAP object. */ + gcmkONERROR( + gckHEAP_Construct(os, gcdHEAP_SIZE, &os->heap)); + + /* Find the base address of the physical memory. */ + os->baseAddress = os->device->baseAddress; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, + "Physical base address set to 0x%08X.\n", + os->baseAddress); + + os->mempoolBaseAddress = (gctPOINTER) drv_mempool_get_baseAddress(); + os->mempoolBasePAddress = (gctPOINTER) drv_mempool_get_basePAddress(); + os->mempoolPageSize = drv_mempool_get_page_size(); + + + /* Initialize the atomic operations lock. */ + gcmkONERROR( + gckOS_CreateMutex(os, &os->atomicOperationLock)); + + /* Return pointer to the gckOS object. */ + *Os = os; + + /* Success. */ + return gcvSTATUS_OK; + +OnError: + if (os->heap != gcvNULL) + { + gcmkVERIFY_OK( + gckHEAP_Destroy(os->heap)); + } + + if (os->memoryMapLock != gcvNULL) + { + gcmkVERIFY_OK( + gckOS_DeleteMutex(os, os->memoryMapLock)); + } + + if (os->memoryLock != gcvNULL) + { + gcmkVERIFY_OK( + gckOS_DeleteMutex(os, os->memoryLock)); + } + + if (os->atomicOperationLock != gcvNULL) + { + gcmkVERIFY_OK( + gckOS_DeleteMutex(os, os->atomicOperationLock)); + } + + free(os); + + /* Return the error. */ + return status; +} + +/******************************************************************************* +** +** gckOS_Destroy +** +** Destroy an gckOS object. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object that needs to be destroyed. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_Destroy( + IN gckOS Os + ) +{ + gckHEAP heap; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + if (Os->heap != NULL) + { + /* Mark gckHEAP as gone. */ + heap = Os->heap; + Os->heap = NULL; + + /* Destroy the gckHEAP object. */ + gcmkVERIFY_OK( + gckHEAP_Destroy(heap)); + } + + /* Destroy the memory lock. */ + gcmkVERIFY_OK( + gckOS_DeleteMutex(Os, Os->memoryMapLock)); + + gcmkVERIFY_OK( + gckOS_DeleteMutex(Os, Os->memoryLock)); + + /* Destroy the atomic operation lock. */ + gcmkVERIFY_OK( + gckOS_DeleteMutex(Os, Os->atomicOperationLock)); + + /* Mark the gckOS object as unknown. */ + Os->object.type = gcvOBJ_UNKNOWN; + + /* Free the gckOS object. */ + free(Os); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_Allocate +** +** Allocate memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIZE_T Bytes +** Number of bytes to allocate. +** +** OUTPUT: +** +** gctPOINTER * Memory +** Pointer to a variable that will hold the allocated memory location. +*/ +gceSTATUS +gckOS_Allocate( + IN gckOS Os, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ) +{ + gceSTATUS status; + + /*gcmkHEADER_ARG("Os=0x%x Bytes=%lu", Os, Bytes);*/ + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Memory != NULL); + + /* Do we have a heap? */ + if (Os->heap != NULL) + { + /* Allocate from the heap. */ + gcmkONERROR(gckHEAP_Allocate(Os->heap, Bytes, Memory)); + } + else + { + gcmkONERROR(gckOS_AllocateMemory(Os, Bytes, Memory)); + } + + /* Success. */ + /*gcmkFOOTER_ARG("*memory=0x%x", *Memory);*/ + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_Free +** +** Free allocated memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Memory +** Pointer to memory allocation to free. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_Free( + IN gckOS Os, + IN gctPOINTER Memory + ) +{ + gceSTATUS status; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Memory != NULL); + + /* Do we have a heap? */ + if (Os->heap != NULL) + { + /* Free from the heap. */ + gcmkONERROR(gckHEAP_Free(Os->heap, Memory)); + } + else + { + gcmkONERROR(gckOS_FreeMemory(Os, Memory)); + } + + /* Success. */ + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} +/******************************************************************************* +** +** gckOS_AllocateMemory +** +** Allocate memory wrapper. +** +** INPUT: +** +** gctSIZE_T Bytes +** Number of bytes to allocate. +** +** OUTPUT: +** +** gctPOINTER * Memory +** Pointer to a variable that will hold the allocated memory location. +*/ +gceSTATUS +gckOS_AllocateMemory( + IN gckOS Os, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ) +{ + gctPOINTER memory; + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%x Bytes=%lu", Os, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Memory != NULL); + + memory = (gctPOINTER) calloc(1, Bytes); + + if (memory == NULL) + { + /* Out of memory. */ + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + /* Return pointer to the memory allocation. */ + *Memory = memory; + + /* Success. */ + gcmkFOOTER_ARG("*Memory=0x%x", *Memory); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_FreeMemory +** +** Free allocated memory wrapper. +** +** INPUT: +** +** gctPOINTER Memory +** Pointer to memory allocation to free. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_FreeMemory( + IN gckOS Os, + IN gctPOINTER Memory + ) +{ + gcmkHEADER_ARG("Memory=0x%x", Memory); + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Memory != NULL); + + /* Free the memory from the OS pool. */ + free(Memory); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_MapMemory +** +** Map physical memory into the current process. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Start of physical address memory. +** +** gctSIZE_T Bytes +** Number of bytes to map. +** +** OUTPUT: +** +** gctPOINTER * Memory +** Pointer to a variable that will hold the logical address of the +** mapped memory. +*/ +gceSTATUS gckOS_MapMemory( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Logical + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != 0); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Logical != NULL); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "Enter gckOS_MapMemory\n"); + + MEMORY_LOCK(Os); + + /* Map physical address. */ + *Logical = mmap64(0, + Bytes, + PROT_READ | PROT_WRITE, + MAP_PHYS | MAP_SHARED, + NOFD, + (off_t)Physical); + + MEMORY_UNLOCK(Os); + + if (*Logical == MAP_FAILED) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_MapMemory: mmap error: %s\n", + strerror(errno)); + + return gcvSTATUS_OUT_OF_MEMORY; + } + + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_OS, + "gckOS_MapMemory: User Mapped address for 0x%x is 0x%x\n", + (gctUINT32)Physical, + (gctUINT32)*Logical); + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_UnmapMemory +** +** Unmap physical memory out of the current process. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Start of physical address memory. +** +** gctSIZE_T Bytes +** Number of bytes to unmap. +** +** gctPOINTER Memory +** Pointer to a previously mapped memory region. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_UnmapMemory( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + IN gctPOINTER Logical + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != 0); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Logical != NULL); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "in gckOS_UnmapMemory\n"); + + if (Logical) + { + gctUINT32 res; + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, + gcvZONE_OS, + "[gckOS_UnmapMemory] Logical: 0x%x\n", + Logical + ); + + MEMORY_LOCK(Os); + + res = munmap(Logical, Bytes); + + MEMORY_UNLOCK(Os); + + if (res == -1) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_UnmapMemory: munmap error: %s\n", + strerror(errno)); + + return gcvSTATUS_INVALID_ARGUMENT; + } + } + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AllocateNonPagedMemory +** +** Allocate a number of pages from non-paged memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctBOOL InUserSpace +** gcvTRUE if the pages need to be mapped into user space. +** +** gctSIZE_T * Bytes +** Pointer to a variable that holds the number of bytes to allocate. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that hold the number of bytes allocated. +** +** gctPHYS_ADDR * Physical +** Pointer to a variable that will hold the physical address of the +** allocation. +** +** gctPOINTER * Logical +** Pointer to a variable that will hold the logical address of the +** allocation. +*/ +gceSTATUS gckOS_AllocateNonPagedMemory( + IN gckOS Os, + IN gctBOOL InUserSpace, + IN OUT gctSIZE_T * Bytes, + OUT gctPHYS_ADDR * Physical, + OUT gctPOINTER * Logical + ) +{ + + if (InUserSpace) + { + /* TODO: Make a separate OS call for allocating from shared memory pool. */ + *Logical = drv_shmpool_alloc_contiguous((gctUINT32)Physical, (gctHANDLE)Logical, *Bytes); + + if (*Logical == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_AllocateNonPagedMemory: Out of memory."); + + *Bytes = 0; + return gcvSTATUS_OUT_OF_RESOURCES; + } + + /* Used to distinguish from memory allocated in kernel space. */ + *((gctUINT32*)Physical) = 0; + } + else + { + drv_mempool_alloc_contiguous(*Bytes, Physical, Logical); + + if (*Physical == gcvNULL || *Logical == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_AllocateNonPagedMemory: Out of memory."); + + *Bytes = 0; + return gcvSTATUS_OUT_OF_RESOURCES; + } + } + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_AllocateNonPagedMemory: " + "Bytes->0x%x, Logical->0x%x Physical->0x%x\n", + (gctUINT32)*Bytes, + *Logical, + *Physical); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_FreeNonPagedMemory +** +** Free previously allocated and mapped pages from non-paged memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIZE_T Bytes +** Number of bytes allocated. +** +** gctPHYS_ADDR Physical +** Physical address of the allocated memory. +** +** gctPOINTER Logical +** Logical address of the allocated memory. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_FreeNonPagedMemory( + IN gckOS Os, + IN gctSIZE_T Bytes, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical + ) +{ + int rc; + + if (Physical) + { + rc = drv_mempool_free(Logical); + } + else + { + rc = drv_shmpool_free(Logical); + } + + if (rc == -1) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_FreeNonPagedMemory: " + "Unmap Failed Logical->0x%x, Bytes->%d, Physical->0x%x\n", + (gctUINT32)Logical, + Bytes, + (gctUINT32)Physical); + return gcvSTATUS_INVALID_ARGUMENT; + } + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_FreeNonPagedMemory: " + "Logical->0x%x Physical->0x%x\n", + (gctUINT32)Logical, + (gctUINT32)Physical); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_ReadRegister +** +** Read data from a register. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctUINT32 Address +** Address of register. +** +** OUTPUT: +** +** gctUINT32 * Data +** Pointer to a variable that receives the data read from the register. +*/ +gceSTATUS gckOS_ReadRegister( + IN gckOS Os, + IN gctUINT32 Address, + OUT gctUINT32 * Data + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Data != NULL); + + *Data = (gctUINT32)in32((uintptr_t) ((gctUINT8 *)Os->device->registerBase + Address)); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_WriteRegister +** +** Write data to a register. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctUINT32 Address +** Address of register. +** +** gctUINT32 Data +** Data for register. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_WriteRegister( + IN gckOS Os, + IN gctUINT32 Address, + IN gctUINT32 Data + ) +{ + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_WriteRegister: " + "Writing to physical address [%x] = %x\n", + (gctUINT8 *)Os->device->registerBase, + Data); + + out32((uintptr_t) ((gctUINT8 *)Os->device->registerBase + Address), (uint32_t)Data); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_GetPageSize +** +** Get the system's page size. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** OUTPUT: +** +** gctSIZE_T * PageSize +** Pointer to a variable that will receive the system's page size. +*/ +gceSTATUS gckOS_GetPageSize( + IN gckOS Os, + OUT gctSIZE_T * PageSize + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(PageSize != NULL); + + /* Return the page size. */ + *PageSize = (gctSIZE_T) __PAGESIZE; + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_GetPhysicalAddressProcess +** +** Get the physical system address of a corresponding virtual address for a +** given process. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Logical +** Logical address. +** +** gctUINT ProcessID +** Procedd ID. +** +** OUTPUT: +** +** gctUINT32 * Address +** Poinetr to a variable that receives the 32-bit physical adress. +*/ +gceSTATUS +gckOS_GetPhysicalAddressProcess( + IN gckOS Os, + IN gctPOINTER Logical, + IN gctUINT ProcessID, + OUT gctUINT32 * Address + ) +{ + return gckOS_GetPhysicalAddress(Os, Logical, Address); +} + +/******************************************************************************* +** +** gckOS_GetPhysicalAddress +** +** Get the physical system address of a corresponding virtual address. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Logical +** Logical address. +** +** OUTPUT: +** +** gctUINT32 * Address +** Pointer to a variable that receives the 32-bit physical adress. +*/ +gceSTATUS gckOS_GetPhysicalAddress( + IN gckOS Os, + IN gctPOINTER Logical, + OUT gctUINT32 * Address + ) +{ + + gctUINT32 res; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Address != gcvNULL); + + if ( drv_mempool_mem_offset(Logical, Address) != gcvSTATUS_OK) + { + if ( drv_shmpool_mem_offset(Logical, Address) != gcvSTATUS_OK) + { + printf("Warning, using mem_offset for Logical:%x!\n", (gctUINT32) Logical); + + MEMORY_LOCK(Os); + + /* TODO: mem_offset in QNX works only for memory that is allocated + contiguosly using gckOS_AllocateContiguous(). */ + res = mem_offset( Logical, NOFD, 1, (off_t *)Address, NULL); + + if (res == -1) + { + MEMORY_UNLOCK(Os); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_GetPhysicalAddress: " + "Unable to get physical address for 0x%x\n", + (gctUINT32)Logical); + + return gcvSTATUS_INVALID_ARGUMENT; + } + + MEMORY_UNLOCK(Os); + } + } + + /* Subtract base address to get a GPU physical address. */ + gcmASSERT(*Address >= Os->baseAddress); + *Address -= Os->baseAddress; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_GetPhysicalAddress: Logical->0x%x Physical->0x%x\n", + (gctUINT32)Logical, + (gctUINT32)*Address); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_MapPhysical +** +** Map a physical address into kernel space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctUINT32 Physical +** Physical address of the memory to map. +** +** gctSIZE_T Bytes +** Number of bytes to map. +** +** OUTPUT: +** +** gctPOINTER * Logical +** Pointer to a variable that receives the base address of the mapped +** memory. +*/ +gceSTATUS gckOS_MapPhysical( + IN gckOS Os, + IN gctUINT32 Physical, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Logical + ) +{ + gctUINT32 physical; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + + MEMORY_LOCK(Os); + + /* Compute true physical address (before subtraction of the baseAddress). */ + physical = Physical + Os->baseAddress; + + /* Map physical address. */ + *Logical = mmap64(0, + Bytes, + PROT_READ | PROT_WRITE, + MAP_PHYS | MAP_SHARED | MAP_NOINIT, + NOFD, + (off_t)physical); + + MEMORY_UNLOCK(Os); + + if (*Logical == MAP_FAILED) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_MapMemory: mmap error: %s\n", + strerror(errno)); + + return gcvSTATUS_OUT_OF_MEMORY; + } + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, + "gckOS_MapPhysical: " + "Physical->0x%X Bytes->0x%X Logical->0x%X\n", + (gctUINT32) Physical, + (gctUINT32) Bytes, + (gctUINT32) *Logical); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_UnmapPhysical +** +** Unmap a previously mapped memory region from kernel memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Logical +** Pointer to the base address of the memory to unmap. +** +** gctSIZE_T Bytes +** Number of bytes to unmap. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_UnmapPhysical( + IN gckOS Os, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ) +{ + gctUINT32 res; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Logical != NULL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + + MEMORY_LOCK(Os); + + res = munmap(Logical, Bytes); + + MEMORY_UNLOCK(Os); + + if (res == -1) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_UnmapMemory: munmap error: %s\n", + strerror(errno)); + + return gcvSTATUS_INVALID_ARGUMENT; + } + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_UnmapPhysical: " + "Logical->0x%x Bytes->0x%x\n", + (gctUINT32)Logical, + (gctUINT32)Bytes); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_CreateMutex +** +** Create a new mutex. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** OUTPUT: +** +** gctPOINTER * Mutex +** Pointer to a variable that will hold a pointer to the mutex. +*/ +gceSTATUS gckOS_CreateMutex( + IN gckOS Os, + OUT gctPOINTER * Mutex + ) +{ + gctUINT32 res; + + /* Validate the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Mutex != NULL); + + /* Allocate a FAST_MUTEX structure. */ + *Mutex = (gctPOINTER) malloc(sizeof(pthread_mutex_t)); + + if (*Mutex == gcvNULL) + { + return gcvSTATUS_OUT_OF_MEMORY; + } + + /* Initialize the semaphore.. Come up in unlocked state. */ + res = pthread_mutex_init((pthread_mutex_t *)(*Mutex), NULL); + if (res != EOK) + { + return gcvSTATUS_OUT_OF_RESOURCES; + } + + /* Return status. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_DeleteMutex +** +** Delete a mutex. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Mutex +** Pointer to the mute to be deleted. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_DeleteMutex( + IN gckOS Os, + IN gctPOINTER Mutex + ) +{ + gctUINT32 res; + + /* Validate the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Mutex != NULL); + + res = pthread_mutex_destroy((pthread_mutex_t *)(Mutex)); + + if (res != EOK) + { + return gcvSTATUS_INVALID_ARGUMENT; + } + + /* Delete the fast mutex. */ + free(Mutex); + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AcquireMutex +** +** Acquire a mutex. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Mutex +** Pointer to the mutex to be acquired. +** +** gctUINT32 Timeout +** Timeout value specified in milliseconds. +** Specify the value of gcvINFINITE to keep the thread suspended +** until the mutex has been acquired. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_AcquireMutex( + IN gckOS Os, + IN gctPOINTER Mutex, + IN gctUINT32 Timeout + ) +{ + /* Validate the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Mutex != gcvNULL); + + if (Timeout == gcvINFINITE) + { + pthread_mutex_lock((pthread_mutex_t *) Mutex); + + /* Success. */ + return gcvSTATUS_OK; + } + + while (Timeout-- > 0) + { + /* Try to acquire the fast mutex. */ + if (!pthread_mutex_trylock((pthread_mutex_t *) Mutex)) + { + /* Success. */ + return gcvSTATUS_OK; + } + + /* Wait for 1 millisecond. */ + gcmkVERIFY_OK(gckOS_Delay(Os, 1)); + } + + /* Timeout. */ + return gcvSTATUS_TIMEOUT; +} + +/******************************************************************************* +** +** gckOS_ReleaseMutex +** +** Release an acquired mutex. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Mutex +** Pointer to the mutex to be released. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_ReleaseMutex( + IN gckOS Os, + IN gctPOINTER Mutex + ) +{ + /* Validate the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Mutex != NULL); + + /* Release the fast mutex. */ + pthread_mutex_unlock((pthread_mutex_t *) Mutex); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AtomicExchange +** +** Atomically exchange a pair of 32-bit values. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** IN OUT gctINT32_PTR Target +** Pointer to the 32-bit value to exchange. +** +** IN gctINT32 NewValue +** Specifies a new value for the 32-bit value pointed to by Target. +** +** OUT gctINT32_PTR OldValue +** The old value of the 32-bit value pointed to by Target. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_AtomicExchange( + IN gckOS Os, + IN OUT gctUINT32_PTR Target, + IN gctUINT32 NewValue, + OUT gctUINT32_PTR OldValue + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + /* Acquire atomic operation lock. */ + gcmkVERIFY_OK(gckOS_AcquireMutex(Os, + Os->atomicOperationLock, + gcvINFINITE)); + + /* Exchange the pair of 32-bit values. */ + *OldValue = *Target; + *Target = NewValue; + + gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->atomicOperationLock)); + + /* Success. */ + return gcvSTATUS_OK; +} + + +/******************************************************************************* +** +** gckOS_AtomicExchangePtr +** +** Atomically exchange a pair of pointers. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** IN OUT gctPOINTER * Target +** Pointer to the 32-bit value to exchange. +** +** IN gctPOINTER NewValue +** Specifies a new value for the pointer pointed to by Target. +** +** OUT gctPOINTER * OldValue +** The old value of the pointer pointed to by Target. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_AtomicExchangePtr( + IN gckOS Os, + IN OUT gctPOINTER * Target, + IN gctPOINTER NewValue, + OUT gctPOINTER * OldValue + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + /* Acquire atomic operation lock. */ + gcmkVERIFY_OK(gckOS_AcquireMutex(Os, + Os->atomicOperationLock, + gcvINFINITE)); + + /* Exchange the pair of pointers. */ + *OldValue = *Target; + *Target = NewValue; + + gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->atomicOperationLock)); + + /* Success. */ + return gcvSTATUS_OK; +} + + +/******************************************************************************* +** +** gckOS_Delay +** +** Delay execution of the current thread for a number of milliseconds. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctUINT32 Delay +** Delay to sleep, specified in milliseconds. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_Delay( + IN gckOS Os, + IN gctUINT32 Delay + ) +{ + /* Schedule delay. */ + delay(Delay); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_MemoryBarrier +** +** Make sure the CPU has executed everything up to this point and the data got +** written to the specified pointer. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Address +** Address of memory that needs to be barriered. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_MemoryBarrier( + IN gckOS Os, + IN gctPOINTER Address + ) +{ + /* Verify thearguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + __cpu_membarrier(); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AllocatePagedMemory +** +** Allocate memory from the paged pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIZE_T Bytes +** Number of bytes to allocate. +** +** OUTPUT: +** +** gctPHYS_ADDR * Physical +** Pointer to a variable that receives the physical address of the +** memory allocation. +*/ +gceSTATUS +gckOS_AllocatePagedMemory( + IN gckOS Os, + IN gctSIZE_T Bytes, + OUT gctPHYS_ADDR * Physical + ) +{ + return gckOS_AllocatePagedMemoryEx(Os, gcvFALSE, Bytes, Physical); +} + +/******************************************************************************* +** +** gckOS_AllocatePagedMemoryEx +** +** Allocate memory from the paged pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctBOOL Contiguous +** Need contiguous memory or not. +** +** gctSIZE_T Bytes +** Number of bytes to allocate. +** +** OUTPUT: +** +** gctPHYS_ADDR * Physical +** Pointer to a variable that receives the physical address of the +** memory allocation. +*/ +gceSTATUS gckOS_AllocatePagedMemoryEx( + IN gckOS Os, + IN gctBOOL Contiguous, + IN gctSIZE_T Bytes, + OUT gctPHYS_ADDR * Physical + ) +{ + int rc, fd, shm_ctl_flags = SHMCTL_ANON | SHMCTL_LAZYWRITE; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Physical != NULL); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "in gckOS_AllocatePagedMemory\n"); + + if (Contiguous) + { + shm_ctl_flags |= SHMCTL_PHYS; + } + + /* Lock down, to avoid opening same shm file twice. */ + MEMORY_LOCK(Os); + + fd = shm_open("shm_gal", O_RDWR | O_CREAT, 0777); + if (fd == -1) { + printf("shm_open failed. error %s\n", strerror( errno ) ); + return gcvSTATUS_GENERIC_IO; + } + + /* Free to use the same name for next create shm object after shm_unlink. */ + shm_unlink("shm_gal"); + + MEMORY_UNLOCK(Os); + + /* Special flags for this shm, to make it write buffered. */ + /* Virtual memory doesn't need to be physically contiguous. */ + /* Allocations would be page aligned. */ + rc = shm_ctl_special(fd, + SHMCTL_ANON /*| SHMCTL_PHYS*/ | SHMCTL_LAZYWRITE, + 0, + Bytes, + 0x9); + if (rc == -1) { + printf("shm_ctl_special failed. error %s\n", strerror( errno ) ); + close(fd); + return gcvSTATUS_OUT_OF_MEMORY; + } + + /* Use the fd as the handle for the physical memory just allocated. */ + *Physical = (gctPHYS_ADDR) fd; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_AllocatePagedMemory: " + "Bytes->0x%x, Physical->0x%x\n", + (gctUINT32)Bytes, + (gctUINT32)*Physical); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_FreePagedMemory +** +** Free memory allocated from the paged pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Physical address of the allocation. +** +** gctSIZE_T Bytes +** Number of bytes of the allocation. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_FreePagedMemory( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes + ) +{ + int rc; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != NULL); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "in gckOS_FreePagedMemory\n"); + + rc = close((gctINT)Physical); + if ( rc == -1 ) + { + printf("gckOS_FreePagedMemory failed. error: %s\n", strerror( errno ) ); + return gcvSTATUS_GENERIC_IO; + } + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_LockPages +** +** Lock memory allocated from the paged pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Physical address of the allocation. +** +** gctSIZE_T Bytes +** Number of bytes of the allocation. +** +** OUTPUT: +** +** gctPOINTER * Logical +** Pointer to a variable that receives the address of the mapped +** memory. +** +** gctSIZE_T * PageCount +** Pointer to a variable that receives the number of pages required for +** the page table. +*/ +gceSTATUS gckOS_LockPages( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + IN gctUINT32 Pid, + OUT gctPOINTER * Logical, + OUT gctSIZE_T * PageCount + ) +{ + void* addr; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != NULL); + gcmkVERIFY_ARGUMENT(Logical != NULL); + gcmkVERIFY_ARGUMENT(PageCount != NULL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "in gckOS_LockPages\n"); + + /* Map this memory inside user and galcore. */ + addr = mmap64_join(Pid, + 0, + Bytes, + PROT_READ | PROT_WRITE, + MAP_SHARED, + (int)Physical, + 0); + + if (addr == MAP_FAILED) + { + printf("gckOS_LockPages: couldn't map memory of size %d, Pid: %x [errno %s]", + (gctUINT32)Bytes, Pid, strerror( errno ) ); + return gcvSTATUS_GENERIC_IO; + } + + /* TODO: MLOCK may or may not be needed!. */ + mlock((void*)addr, Bytes); + + *Logical = (gctPOINTER)addr; + *PageCount = (gcmALIGN(Bytes, __PAGESIZE)) / __PAGESIZE; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_LockPages: " + "gctPHYS_ADDR->0x%x Bytes->0x%x Logical->0x%x pid->%d\n", + (gctUINT32)Physical, + (gctUINT32)Bytes, + (gctUINT32)*Logical, + Pid); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_MapPages +** +** Map paged memory into a page table. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Physical address of the allocation. +** +** gctSIZE_T PageCount +** Number of pages required for the physical address. +** +** gctPOINTER PageTable +** Pointer to the page table to fill in. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_MapPages( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical, + IN gctSIZE_T PageCount, + IN gctPOINTER PageTable + ) +{ + gctUINT32* table; + gctPOINTER addr; + size_t contigLen = 0; + off_t offset; + gctUINT32 bytes; + int rc; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != NULL); + gcmkVERIFY_ARGUMENT(PageCount > 0); + gcmkVERIFY_ARGUMENT(PageTable != NULL); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "in gckOS_MapPages\n"); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_MapPages: " + "Physical->0x%x PageCount->0x%x Logical->0x%x\n", + (gctUINT32)Physical, + (gctUINT32)PageCount, + (gctUINT32)Logical); + + addr = Logical; + table = (gctUINT32 *)PageTable; + bytes = PageCount * __PAGESIZE; + + /* Try to get the user pages so DMA can happen. */ + while (PageCount > 0) + { + /* fd should be NOFD here, to get physical address. */ + rc = mem_offset( addr, NOFD, bytes, &offset, &contigLen); + if (rc == -1) { + printf("gckOS_MapPages: mem_offset failed: %s\n", strerror( errno ) ); + return gcvSTATUS_GENERIC_IO; + } + + gcmASSERT(contigLen > 0); + + while(contigLen > 0) + { + *table++ = (gctUINT32) offset; + offset += 4096; + addr += 4096; + contigLen -= 4096; + bytes -= 4096; + PageCount--; + } + } + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_UnlockPages +** +** Unlock memory allocated from the paged pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Physical address of the allocation. +** +** gctSIZE_T Bytes +** Number of bytes of the allocation. +** +** gctPOINTER Logical +** Address of the mapped memory. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_UnlockPages( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctUINT32 Pid, + IN gctSIZE_T Bytes, + IN gctPOINTER Logical + ) +{ + int rc = 0; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != NULL); + gcmkVERIFY_ARGUMENT(Logical != NULL); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "in gckOS_UnlockPages\n"); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_MapPages: " + "Physical->0x%x Bytes->0x%x Logical->0x%x Pid->0x%x\n", + (gctUINT32)Physical, + (gctUINT32)Bytes, + (gctUINT32)Logical, + (gctUINT32)Pid); + + rc = munmap((void*)Logical, Bytes); + if (rc == -1) { + printf("munmap failed: %s\n", strerror( errno ) ); + return gcvSTATUS_GENERIC_IO; + } + + rc = munmap_peer(Pid, (void*)Logical, Bytes); + if (rc == -1) { + printf("munmap_peer failed: %s\n", strerror( errno ) ); + return gcvSTATUS_GENERIC_IO; + } + + /* Success. */ + return gcvSTATUS_OK; +} + + +/******************************************************************************* +** +** gckOS_AllocateContiguous +** +** Allocate memory from the contiguous pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctBOOL InUserSpace +** gcvTRUE if the pages need to be mapped into user space. +** +** gctSIZE_T * Bytes +** Pointer to the number of bytes to allocate. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that receives the number of bytes allocated. +** +** gctPHYS_ADDR * Physical +** Pointer to a variable that receives the physical address of the +** memory allocation. +** +** gctPOINTER * Logical +** Pointer to a variable that receives the logical address of the +** memory allocation. +*/ +gceSTATUS gckOS_AllocateContiguous( + IN gckOS Os, + IN gctBOOL InUserSpace, + IN OUT gctSIZE_T * Bytes, + OUT gctPHYS_ADDR * Physical, + OUT gctPOINTER * Logical + ) +{ + /* Same as non-paged memory for now. */ + return gckOS_AllocateNonPagedMemory(Os, + InUserSpace, + Bytes, + Physical, + Logical + ); +} + +/******************************************************************************* +** +** gckOS_FreeContiguous +** +** Free memory allocated from the contiguous pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Physical address of the allocation. +** +** gctPOINTER Logical +** Logicval address of the allocation. +** +** gctSIZE_T Bytes +** Number of bytes of the allocation. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_FreeContiguous( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ) +{ + /* Same of non-paged memory for now. */ + return gckOS_FreeNonPagedMemory(Os, Bytes, Physical, Logical); +} + +/****************************************************************************** +** +** gckOS_GetKernelLogical +** +** Return the kernel logical pointer that corresponds to the specified +** hardware address. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctUINT32 Address +** Hardware physical address. +** +** OUTPUT: +** +** gctPOINTER * KernelPointer +** Pointer to a variable receiving the pointer in kernel address space. +*/ +gceSTATUS +gckOS_GetKernelLogical( + IN gckOS Os, + IN gctUINT32 Address, + OUT gctPOINTER * KernelPointer + ) +{ + gceSTATUS status; + + do + { + gckGALDEVICE device; + gckKERNEL kernel; + gcePOOL pool; + gctUINT32 offset; + gctPOINTER logical; + + /* Extract the pointer to the gckGALDEVICE class. */ + device = (gckGALDEVICE) Os->device; + + /* Kernel shortcut. */ + kernel = device->kernel; + + /* Split the memory address into a pool type and offset. */ + gcmkERR_BREAK(gckHARDWARE_SplitMemory( + kernel->hardware, Address, &pool, &offset + )); + + /* Dispatch on pool. */ + switch (pool) + { + case gcvPOOL_LOCAL_INTERNAL: + /* Internal memory. */ + logical = device->internalLogical; + break; + + case gcvPOOL_LOCAL_EXTERNAL: + /* External memory. */ + logical = device->externalLogical; + break; + + case gcvPOOL_SYSTEM: + /* System memory. */ + logical = device->contiguousBase; + break; + + default: + /* Invalid memory pool. */ + return gcvSTATUS_INVALID_ARGUMENT; + } + + /* Build logical address of specified address. */ + * KernelPointer = ((gctUINT8_PTR) logical) + offset; + + /* Success. */ + return gcvSTATUS_OK; + } + while (gcvFALSE); + + /* Return status. */ + return status; +} + +/******************************************************************************* +** +** gckOS_MapUserPointer +** +** Map a pointer from the user process into the kernel address space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Pointer +** Pointer in user process space that needs to be mapped. +** +** gctSIZE_T Size +** Number of bytes that need to be mapped. +** +** OUTPUT: +** +** gctPOINTER * KernelPointer +** Pointer to a variable receiving the mapped pointer in kernel address +** space. +*/ +gceSTATUS +gckOS_MapUserPointer( + IN gckOS Os, + IN gctPOINTER Pointer, + IN gctSIZE_T Size, + OUT gctPOINTER * KernelPointer + ) +{ + /* A pointer is assumed to be allocated from its shared memory object. + Which is mapped by both user and kernel at the same vitual address. */ + /* TODO: Check if Pointer is a valid pointer? */ + *KernelPointer = Pointer; + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_UnmapUserPointer +** +** Unmap a user process pointer from the kernel address space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Pointer +** Pointer in user process space that needs to be unmapped. +** +** gctSIZE_T Size +** Number of bytes that need to be unmapped. +** +** gctPOINTER KernelPointer +** Pointer in kernel address space that needs to be unmapped. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_UnmapUserPointer( + IN gckOS Os, + IN gctPOINTER Pointer, + IN gctSIZE_T Size, + IN gctPOINTER KernelPointer + ) +{ + /* Nothing to unmap. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_MapUserPhysical +** +** Map a physical address from the user process into the kernel address space. +** The physical address should be obtained by user from gckOS_AllocateNonPagedMemory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** IN gctPHYS_ADDR Phys, +** Physical address of memory that needs to be mapped. +** +** OUTPUT: +** +** gctPHYS_ADDR * KernelPointer +** Pointer to a variable receiving the mapped pointer in kernel address +** space. +*/ +gceSTATUS +gckOS_MapUserPhysical( + IN gckOS Os, + IN gctPHYS_ADDR Phys, + OUT gctPHYS_ADDR * KernelPointer + ) +{ + /* A gctPHYS_ADDR is assumed to be allocated from physical memory pool. */ + /* Dont call this function for pointers already in kernel space. */ + printf("ERROR: %s Not supported.\n", __FUNCTION__); + *KernelPointer = (gctPHYS_ADDR)0xDEADBEEF; + + return gcvSTATUS_NOT_SUPPORTED; +} + + +/******************************************************************************* +** +** gckOS_WriteMemory +** +** Write data to a memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Address +** Address of the memory to write to. +** +** gctUINT32 Data +** Data for register. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_WriteMemory( + IN gckOS Os, + IN gctPOINTER Address, + IN gctUINT32 Data + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Address != NULL); + + /* Write memory. */ + *(gctUINT32 *)Address = Data; + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_CreateSignal +** +** Create a new signal. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctBOOL ManualReset +** If set to gcvTRUE, gckOS_Signal with gcvFALSE must be called in +** order to set the signal to nonsignaled state. +** If set to gcvFALSE, the signal will automatically be set to +** nonsignaled state by gckOS_WaitSignal function. +** Nonsignaled state in QNX is mutex acquired (not free). +** +** OUTPUT: +** +** gctSIGNAL * Signal +** Pointer to a variable receiving the created gctSIGNAL. +*/ +gceSTATUS +gckOS_CreateSignal( + IN gckOS Os, + IN gctBOOL ManualReset, + OUT gctSIGNAL * Signal + ) +{ + gcskSIGNAL_PTR signal; + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%x ManualReset=0x%x", Os, ManualReset); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Signal != NULL); + + /* Create an event structure. */ + signal = (gcskSIGNAL_PTR) malloc(sizeof(gcskSIGNAL)); + + if (signal == gcvNULL) + { + gcmFOOTER_NO(); + return gcvSTATUS_OUT_OF_MEMORY; + } + + signal->manualReset = ManualReset; + + status = gckOS_CreateMutex(Os, (gctPOINTER *)(&signal->mutex)); + + if (gcmIS_ERROR(status)) + { + /* Error. */ + free(signal); + gcmFOOTER(); + return status; + } + + *Signal = (gctSIGNAL) signal; + + /* Success. */ + gcmkFOOTER_ARG("Os=0x%x Signal=0x%x", Os, Signal); + return gcvSTATUS_OK; + +} + +/******************************************************************************* +** +** gckOS_DestroySignal +** +** Destroy a signal. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to the gctSIGNAL. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_DestroySignal( + IN gckOS Os, + IN gctSIGNAL Signal + ) +{ + + gceSTATUS status = gcvSTATUS_OK; + gcskSIGNAL_PTR signal; + + gcmkHEADER_ARG("Os=0x%x Signal=0x%x", Os, Signal); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Signal != NULL); + + signal = (gcskSIGNAL_PTR) Signal; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Signal != NULL); + + if (signal != gcvNULL ) + { + status = gckOS_DeleteMutex(Os, (gctPOINTER)(signal->mutex)); + + free(signal); + } + + /* Success. */ + gcmkFOOTER_NO(); + return status; +} + +/******************************************************************************* +** +** gckOS_Signal +** +** Set a state of the specified signal. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to the gctSIGNAL. +** +** gctBOOL State +** If gcvTRUE, the signal will be set to signaled state. +** If gcvFALSE, the signal will be set to nonsignaled state. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_Signal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctBOOL State + ) +{ + gcskSIGNAL_PTR signal; + gceSTATUS status = gcvSTATUS_OK; + + gcmkHEADER_ARG("Os=0x%x Signal=0x%x State=%d", Os, Signal, State); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Signal != gcvNULL); + + signal = (gcskSIGNAL_PTR) Signal; + + /* Set the new state of the event. */ + if (signal->manualReset && State) + { + /* Set the event to a signaled state. */ + gckOS_ReleaseMutex(Os,(gctPOINTER *)(&signal->mutex)); + } + else + { + gckOS_AcquireMutex(Os, (gctPOINTER *)(&signal->mutex), gcvINFINITE); + } + + /* Success. */ + gcmkFOOTER_NO(); + return status; +} + +/******************************************************************************* +** +** gckOS_UserSignal +** +** Set the specified signal which is owned by a process to signaled state. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to the gctSIGNAL. +** +** gctHANDLE Process +** Handle of process owning the signal. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_UserSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctINT Rcvid, + IN gctINT Coid + ) +{ + gctINT rc; + struct sigevent event; + + SIGEV_PULSE_INIT( &event, Coid, SIGEV_PULSE_PRIO_INHERIT, _PULSE_CODE_MINAVAIL, Signal); + + rc = MsgDeliverEvent_r(Rcvid, &event); + if (rc != EOK) + { + gcmkTRACE(gcvLEVEL_INFO, + "%s(%d): Sent signal to (receive ID = %d, connect ID = %d).", + __FUNCTION__, __LINE__, Rcvid, Coid); + + gcmkTRACE(gcvLEVEL_ERROR, + "%s(%d): MsgDeliverEvent failed (%d).", + __FUNCTION__, __LINE__, rc); + +; + + return gcvSTATUS_GENERIC_IO; + } + + /* Return status. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_WaitSignal +** +** Wait for a signal to become signaled. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to the gctSIGNAL. +** +** gctUINT32 Wait +** Number of milliseconds to wait. +** Pass the value of gcvINFINITE for an infinite wait. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_WaitSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctUINT32 Wait + ) +{ + gceSTATUS status = gcvSTATUS_OK; + + gcskSIGNAL_PTR signal; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Signal != gcvNULL); + + signal = (gcskSIGNAL_PTR) Signal; + + status = gckOS_AcquireMutex(Os, (gctPOINTER *)(&signal->mutex), Wait); + + /* If manualReset is true, use gckOS_Signal to acquire mutex again. */ + if (signal->manualReset) + { + status = gckOS_ReleaseMutex(Os, (gctPOINTER *)(&signal->mutex)); + } + + /* Return status. */ + return status; +} + +/******************************************************************************* +** +** gckOS_MapSignal +** +** Map a signal in to the current process space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to tha gctSIGNAL to map. +** +** gctHANDLE Process +** Handle of process owning the signal. +** +** OUTPUT: +** +** gctSIGNAL * MappedSignal +** Pointer to a variable receiving the mapped gctSIGNAL. +*/ +gceSTATUS +gckOS_MapSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctHANDLE Process, + OUT gctSIGNAL * MappedSignal + ) +{ + printf("ERROR: %s Not supported.\n", __FUNCTION__); + return gcvSTATUS_NOT_SUPPORTED; +} + +/******************************************************************************* +** +** gckOS_MapUserMemory +** +** Lock down a user buffer and return an DMA'able address to be used by the +** hardware to access it. +** +** INPUT: +** +** gctPOINTER Memory +** Pointer to memory to lock down. +** +** gctSIZE_T Size +** Size in bytes of the memory to lock down. +** +** OUTPUT: +** +** gctPOINTER * Info +** Pointer to variable receiving the information record required by +** gckOS_UnmapUserMemory. +** +** gctUINT32_PTR Address +** Pointer to a variable that will receive the address DMA'able by the +** hardware. +*/ +gceSTATUS +gckOS_MapUserMemory( + IN gckOS Os, + IN gctPOINTER Memory, + IN gctSIZE_T Size, + OUT gctPOINTER * Info, + OUT gctUINT32_PTR Address + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Memory != gcvNULL); + gcmkVERIFY_ARGUMENT(Size > 0); + gcmkVERIFY_ARGUMENT(Info != gcvNULL); + gcmkVERIFY_ARGUMENT(Address != gcvNULL); + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, + gcvZONE_OS, + "[gckOS_MapUserMemory] enter.\n" + ); + + printf("ERROR: %s Not supported.\n", __FUNCTION__); + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, + gcvZONE_OS, + "[gckOS_MapUserMemory] leave.\n" + ); + + /* Return the status. */ + return gcvSTATUS_NOT_SUPPORTED; +} + +/******************************************************************************* +** +** gckOS_UnmapUserMemory +** +** Unlock a user buffer and that was previously locked down by +** gckOS_MapUserMemory. +** +** INPUT: +** +** gctPOINTER Memory +** Pointer to memory to unlock. +** +** gctSIZE_T Size +** Size in bytes of the memory to unlock. +** +** gctPOINTER Info +** Information record returned by gckOS_MapUserMemory. +** +** gctUINT32_PTR Address +** The address returned by gckOS_MapUserMemory. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_UnmapUserMemory( + IN gckOS Os, + IN gctPOINTER Memory, + IN gctSIZE_T Size, + IN gctPOINTER Info, + IN gctUINT32 Address + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Memory != gcvNULL); + gcmkVERIFY_ARGUMENT(Size > 0); + gcmkVERIFY_ARGUMENT(Info != gcvNULL); + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, + gcvZONE_OS, + "[gckOS_UnmapUserMemory] enter.\n" + ); + + printf("ERROR: %s Not supported.\n", __FUNCTION__); + + /* Return the status. */ + return gcvSTATUS_NOT_SUPPORTED; +} + +/******************************************************************************* +** +** gckOS_GetBaseAddress +** +** Get the base address for the physical memory. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** OUTPUT: +** +** gctUINT32_PTR BaseAddress +** Pointer to a variable that will receive the base address. +*/ +gceSTATUS +gckOS_GetBaseAddress( + IN gckOS Os, + OUT gctUINT32_PTR BaseAddress + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(BaseAddress != gcvNULL); + + /* Return base address. */ + *BaseAddress = Os->baseAddress; + + /* Success. */ + return gcvSTATUS_OK; +} + +gceSTATUS +gckOS_SuspendInterrupt( + IN gckOS Os + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + InterruptLock(&Os->device->isrLock); + + return gcvSTATUS_OK; +} + +gceSTATUS +gckOS_ResumeInterrupt( + IN gckOS Os + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + InterruptUnlock(&Os->device->isrLock); + + return gcvSTATUS_OK; +} + +gceSTATUS +gckOS_NotifyIdle( + IN gckOS Os, + IN gctBOOL Idle + ) +{ + /* TODO */ + return gcvSTATUS_OK; +} + +/* Perform a memory copy. */ +gceSTATUS +gckOS_MemCopy( + IN gctPOINTER Destination, + IN gctCONST_POINTER Source, + IN gctSIZE_T Bytes + ) +{ + gcmkVERIFY_ARGUMENT(Destination != NULL); + gcmkVERIFY_ARGUMENT(Source != NULL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + + memcpy(Destination, Source, Bytes); + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AllocateNonPagedMemory +** +** Allocate a number of pages from non-paged memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctBOOL InUserSpace +** gcvTRUE if the pages need to be mapped into user space. +** +** gctSIZE_T * Bytes +** Pointer to a variable that holds the number of bytes to allocate. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that hold the number of bytes allocated. +** +** gctPHYS_ADDR * Physical +** Pointer to a variable that will hold the physical address of the +** allocation. +** +** gctPOINTER * Logical +** Pointer to a variable that will hold the logical address of the +** allocation. +*/ +gceSTATUS +gckOS_AllocateNonPagedMemoryShmPool( + IN gckOS Os, + IN gctBOOL InUserSpace, + IN gctUINT32 Pid, + IN gctHANDLE Handle, + IN OUT gctSIZE_T * Bytes, + OUT gctPHYS_ADDR * Physical, + OUT gctPOINTER * Logical + ) +{ + + if (InUserSpace) + { + *Logical = drv_shmpool_alloc_contiguous(Pid, Handle, *Bytes); + + if (*Logical == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_AllocateNonPagedMemory: Out of memory."); + + *Bytes = 0; + return gcvSTATUS_OUT_OF_RESOURCES; + } + + /* Used to distinguish from memory allocated in kernel space. */ + *((gctUINT32*)Physical) = 0; + } + else + { + return gcvSTATUS_INVALID_ARGUMENT; + } + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_AllocateNonPagedMemoryShmPool: " + "Bytes->0x%x, Logical->0x%x Physical->0x%x\n", + (gctUINT32)*Bytes, + *Logical, + *Physical); + + /* Success. */ + return gcvSTATUS_OK; +} + +int +memmgr_peer_sendnc(pid_t pid, int coid, void *smsg, size_t sbytes, void *rmsg, size_t rbytes ) +{ + mem_peer_t peer; + iov_t siov[2]; + int rc; + + peer.i.type = _MEM_PEER; + peer.i.peer_msg_len = sizeof(peer); + peer.i.pid = pid; + + SETIOV(siov + 0, &peer, sizeof peer); + SETIOV(siov + 1, smsg, sbytes); + + do { + rc = MsgSendvsnc(coid, siov, 2, rmsg, rbytes); + } while (rc == -1 && errno == EINTR); + + return rc; +} + +void * +_mmap2_peer(pid_t pid, void *addr, size_t len, int prot, int flags, int fd, off64_t off, + unsigned align, unsigned pre_load, void **base, size_t *size) { + mem_map_t msg; + + msg.i.type = _MEM_MAP; + msg.i.zero = 0; + msg.i.addr = (uintptr_t)addr; + msg.i.len = len; + msg.i.prot = prot; + msg.i.flags = flags; + msg.i.fd = fd; + msg.i.offset = off; + msg.i.align = align; + msg.i.preload = pre_load; + msg.i.reserved1 = 0; + if (memmgr_peer_sendnc(pid, MEMMGR_COID, &msg.i, sizeof msg.i, &msg.o, sizeof msg.o) == -1) { + return MAP_FAILED; + } + if (base) { + *base = (void *)(uintptr_t)msg.o.real_addr; + } + if (size) { + *size = msg.o.real_size; + } + return (void *)(uintptr_t)msg.o.addr; +} + +void * +mmap64_peer(pid_t pid, void *addr, size_t len, int prot, int flags, int fd, off64_t off) { + return _mmap2_peer(pid, addr, len, prot, flags, fd, off, 0, 0, 0, 0); +} + +int +munmap_flags_peer(pid_t pid, void *addr, size_t len, unsigned flags) { + mem_ctrl_t msg; + + msg.i.type = _MEM_CTRL; + msg.i.subtype = _MEM_CTRL_UNMAP; + msg.i.addr = (uintptr_t)addr; + msg.i.len = len; + msg.i.flags = flags; + return memmgr_peer_sendnc(pid, MEMMGR_COID, &msg.i, sizeof msg.i, 0, 0); +} + +int +munmap_peer(pid_t pid, void *addr, size_t len) { + return munmap_flags_peer(pid, addr, len, 0); +} + +int +mem_offset64_peer(pid_t pid, const uintptr_t addr, size_t len, + off64_t *offset, size_t *contig_len) { + int rc; + + struct _peer_mem_off { + struct _mem_peer peer; + struct _mem_offset msg; + }; + typedef union { + struct _peer_mem_off i; + struct _mem_offset_reply o; + } memoffset_peer_t; + memoffset_peer_t msg; + + msg.i.peer.type = _MEM_PEER; + msg.i.peer.peer_msg_len = sizeof(msg.i.peer); + msg.i.peer.pid = pid; + msg.i.peer.reserved1 = 0; + + msg.i.msg.type = _MEM_OFFSET; + msg.i.msg.subtype = _MEM_OFFSET_PHYS; + msg.i.msg.addr = addr; + msg.i.msg.reserved = -1; + msg.i.msg.len = len; + + do { + rc = MsgSendnc(MEMMGR_COID, &msg.i, sizeof msg.i, &msg.o, sizeof msg.o); + } while (rc == -1 && errno == EINTR); + + if (rc == -1) { + return -1; + } + + *offset = msg.o.offset; + *contig_len = msg.o.size; + + return 0; +} + +#if defined(__X86__) +#define CPU_VADDR_SERVER_HINT 0x30000000u +#elif defined(__ARM__) +#define CPU_VADDR_SERVER_HINT 0x20000000u +#else +#error NO CPU SOUP FOR YOU! +#endif + +/* + * map the object into both client and server at the same virtual address + */ +void * +mmap64_join(pid_t pid, void *addr, size_t len, int prot, int flags, int fd, off64_t off) { + void *svaddr, *cvaddr = MAP_FAILED; + uintptr_t hint = (uintptr_t)addr; + uintptr_t start_hint = hint; + + if ( hint == (uintptr_t)0 ) + { + hint = (uintptr_t)CPU_VADDR_SERVER_HINT; + } + + do { + svaddr = mmap64( (void *)hint, len, prot, flags, fd, off ); + if ( svaddr == MAP_FAILED ) { + break; + } + if ( svaddr == cvaddr ) { + return svaddr; + } + + cvaddr = mmap64_peer( pid, svaddr, len, prot, MAP_FIXED | flags, fd, off ); + if ( cvaddr == MAP_FAILED ) { + break; + } + if ( svaddr == cvaddr ) { + return svaddr; + } + + if ( munmap( svaddr, len ) == -1 ) { + svaddr = MAP_FAILED; + break; + } + + svaddr = mmap64( cvaddr, len, prot, flags, fd, off ); + if ( svaddr == MAP_FAILED ) { + break; + } + if ( svaddr == cvaddr ) { + return svaddr; + } + + if ( munmap( svaddr, len ) == -1 ) { + svaddr = MAP_FAILED; + break; + } + if ( munmap_peer( pid, cvaddr, len ) == -1 ) { + cvaddr = MAP_FAILED; + break; + } + hint += __PAGESIZE; + + } while(hint != start_hint); /* do we really want to wrap all the way */ + + if ( svaddr != MAP_FAILED ) { + munmap( svaddr, len ); + } + if ( cvaddr != MAP_FAILED ) { + munmap_peer( pid, cvaddr, len ); + } + + return MAP_FAILED; +} + +/******************************************************************************* +** gckOS_CacheFlush +** +** Flush the cache for the specified addresses. The GPU is going to need the +** data. If the system is allocating memory as non-cachable, this function can +** be ignored. +** +** ARGUMENTS: +** +** gckOS Os +** Pointer to gckOS object. +** +** gctHANDLE Process +** Process handle Logical belongs to or gcvNULL if Logical belongs to +** the kernel. +** +** gctPOINTER Logical +** Logical address to flush. +** +** gctSIZE_T Bytes +** Size of the address range in bytes to flush. +*/ +gceSTATUS +gckOS_CacheFlush( + IN gckOS Os, + IN gctHANDLE Process, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ) +{ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** gckOS_CacheInvalidate +** +** Flush the cache for the specified addresses and invalidate the lines as +** well. The GPU is going to need and modify the data. If the system is +** allocating memory as non-cachable, this function can be ignored. +** +** ARGUMENTS: +** +** gckOS Os +** Pointer to gckOS object. +** +** gctHANDLE Process +** Process handle Logical belongs to or gcvNULL if Logical belongs to +** the kernel. +** +** gctPOINTER Logical +** Logical address to flush. +** +** gctSIZE_T Bytes +** Size of the address range in bytes to flush. +*/ +gceSTATUS +gckOS_CacheInvalidate( + IN gckOS Os, + IN gctHANDLE Process, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ) +{ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** Broadcast interface. +*/ + +gceSTATUS +gckOS_Broadcast( + IN gckOS Os, + IN gckHARDWARE Hardware, + IN gceBROADCAST Reason + ) +{ + return gcvSTATUS_OK; +} + diff --git a/drivers/staging/rk29/vivante/hal/os/qnx/kernel/gc_hal_kernel_os.h b/drivers/staging/rk29/vivante/hal/os/qnx/kernel/gc_hal_kernel_os.h new file mode 100644 index 000000000000..92791d926d69 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/os/qnx/kernel/gc_hal_kernel_os.h @@ -0,0 +1,163 @@ +/**************************************************************************** +* +* Copyright (c) 2005 - 2010 by Vivante Corp. All rights reserved. +* +* The material in this file is confidential and contains trade secrets +* of Vivante Corporation. This is proprietary information owned by +* Vivante Corporation. No part of this work may be disclosed, +* reproduced, copied, transmitted, or used in any way for any purpose, +* without the express written permission of Vivante Corporation. +* +***************************************************************************** +* +* Auto-generated file on 10/12/2010. Do not edit!!! +* +*****************************************************************************/ + + + + + +/* + * Os.h + * + * Created on: Feb 2, 2010 + * Author: Tarang Vaish + */ + +#ifndef __gc_hal_kernel_os_h_ +#define __gc_hal_kernel_os_h_ + +typedef struct +{ + io_msg_t iomsg; + gcsHAL_INTERFACE iface; +} gcsDRIVER_ARGS; + +struct _gckPAGE_USAGE +{ + gctUINT16 pageCount; +}; + +struct _gckSHM_POOL +{ + gctHANDLE Handle; + gctINT32 fd; + gctUINT32 pid; + gctUINT32 freePage; + gctUINT32 pageCount; + gctUINT32 pageSize; + pthread_mutex_t mutex; + gctUINT32 Logical; + gctUINT32 Physical; + struct _gckPAGE_USAGE* pageUsage; + struct _gckSHM_POOL* nextPool; +}; + +typedef struct _gckSHM_POOL* gckSHM_POOL; +typedef struct _gckPAGE_USAGE* gckPAGE_USAGE; + +gceSTATUS +drv_mempool_init(); + +void +drv_mempool_destroy(); + +void +drv_mempool_alloc_contiguous( + IN gctUINT32 Bytes, + OUT gctPHYS_ADDR * Physical, + OUT gctPOINTER * Logical + ); + +int +drv_mempool_free( + IN gctPOINTER Logical + ); + +gctUINT32 +drv_mempool_get_baseAddress(); + +gctUINT32 +drv_mempool_get_basePAddress(); + +gctUINT32 +drv_mempool_get_page_size(); + +gctINT +drv_mempool_get_fileDescriptor(); + +gceSTATUS +drv_mempool_mem_offset( + IN gctPOINTER Logical, + OUT gctUINT32 * Address); + +/* Shared memory pool functions. */ +gckSHM_POOL drv_shmpool_create( + IN gctUINT32 Pid, + IN gctHANDLE Handle, + IN gctUINT32 PoolSize, + IN gctUINT32 PageSize); +void +drv_shmpool_destroy( + IN gckSHM_POOL ShmPool); + +gckSHM_POOL +drv_shm_acquire_pool( + IN gctUINT32 Pid, + IN gctHANDLE Handle + ); + +gckSHM_POOL +drv_shm_acquire_pool2( + IN gctPOINTER Logical + ); + +gceSTATUS +drv_shm_remove_pool( + IN gctHANDLE Handle + ); + +gctUINT32 +drv_shmpool_get_BaseAddress( + IN gckSHM_POOL ShmPool + ); + +gctUINT32 +drv_shmpool_get_page_size( + IN gckSHM_POOL ShmPool + ); + +gceSTATUS +drv_shmpool_mem_offset( + IN gctPOINTER Logical, + OUT gctUINT32 * Address); + +gctPOINTER +drv_shmpool_alloc_contiguous( + IN gctUINT32 Pid, + IN gctHANDLE Handle, + IN gctUINT32 Bytes + ); + +gctUINT32 +drv_shmpool_free( + IN gctPOINTER Logical + ); + +void * +mmap64_join(pid_t pid, void *addr, size_t len, int prot, int flags, int fd, off64_t off); + +int +mem_offset64_peer(pid_t pid, const uintptr_t addr, size_t len, + off64_t *offset, size_t *contig_len); + +int +munmap_peer(pid_t pid, void *addr, size_t len); + +void * +mmap64_peer(pid_t pid, void *addr, size_t len, int prot, int flags, int fd, off64_t off); + +#endif /* __gc_hal_kernel_os_h_ */ + + diff --git a/drivers/staging/rk29/vivante/hal/os/qnx/kernel/gc_hal_kernel_qnx.c b/drivers/staging/rk29/vivante/hal/os/qnx/kernel/gc_hal_kernel_qnx.c new file mode 100644 index 000000000000..7c848dea66c1 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/os/qnx/kernel/gc_hal_kernel_qnx.c @@ -0,0 +1,401 @@ +/**************************************************************************** +* +* Copyright (c) 2005 - 2010 by Vivante Corp. All rights reserved. +* +* The material in this file is confidential and contains trade secrets +* of Vivante Corporation. This is proprietary information owned by +* Vivante Corporation. No part of this work may be disclosed, +* reproduced, copied, transmitted, or used in any way for any purpose, +* without the express written permission of Vivante Corporation. +* +***************************************************************************** +* +* Auto-generated file on 10/12/2010. Do not edit!!! +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_qnx.h" + +#define _GC_OBJ_ZONE gcvZONE_KERNEL + +/******************************************************************************\ +******************************* gckKERNEL API Code ****************************** +\******************************************************************************/ + +/******************************************************************************* +** +** gckKERNEL_QueryVideoMemory +** +** Query the amount of video memory. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** OUTPUT: +** +** gcsHAL_INTERFACE * Interface +** Pointer to an gcsHAL_INTERFACE structure that will be filled in with +** the memory information. +*/ +gceSTATUS +gckKERNEL_QueryVideoMemory( + IN gckKERNEL Kernel, + OUT gcsHAL_INTERFACE * Interface + ) +{ + gckGALDEVICE device; + + gcmkHEADER_ARG("Kernel=0x%x", Kernel); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Interface != NULL); + + /* Extract the pointer to the gckGALDEVICE class. */ + device = (gckGALDEVICE) Kernel->context; + + /* Get internal memory size and physical address. */ + Interface->u.QueryVideoMemory.internalSize = device->internalSize; + Interface->u.QueryVideoMemory.internalPhysical = device->internalPhysical; + + /* Get external memory size and physical address. */ + Interface->u.QueryVideoMemory.externalSize = device->externalSize; + Interface->u.QueryVideoMemory.externalPhysical = device->externalPhysical; + + /* Get contiguous memory size and physical address. */ + Interface->u.QueryVideoMemory.contiguousSize = device->contiguousSize; + Interface->u.QueryVideoMemory.contiguousPhysical = device->contiguousPhysical; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckKERNEL_GetVideoMemoryPool +** +** Get the gckVIDMEM object belonging to the specified pool. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gcePOOL Pool +** Pool to query gckVIDMEM object for. +** +** OUTPUT: +** +** gckVIDMEM * VideoMemory +** Pointer to a variable that will hold the pointer to the gckVIDMEM +** object belonging to the requested pool. +*/ +gceSTATUS +gckKERNEL_GetVideoMemoryPool( + IN gckKERNEL Kernel, + IN gcePOOL Pool, + OUT gckVIDMEM * VideoMemory + ) +{ + gckGALDEVICE device; + gckVIDMEM videoMemory; + + gcmkHEADER_ARG("Kernel=0x%x Pool=0x%x", Kernel, Pool); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(VideoMemory != NULL); + + /* Extract the pointer to the gckGALDEVICE class. */ + device = (gckGALDEVICE) Kernel->context; + + /* Dispatch on pool. */ + switch (Pool) + { + case gcvPOOL_LOCAL_INTERNAL: + /* Internal memory. */ + videoMemory = device->internalVidMem; + break; + + case gcvPOOL_LOCAL_EXTERNAL: + /* External memory. */ + videoMemory = device->externalVidMem; + break; + + case gcvPOOL_SYSTEM: + /* System memory. */ + videoMemory = device->contiguousVidMem; + break; + + default: + /* Unknown pool. */ + videoMemory = NULL; + } + + /* Return pointer to the gckVIDMEM object. */ + *VideoMemory = videoMemory; + + /* Return status. */ + gcmkFOOTER_ARG("*VideoMemory=0x%x", *VideoMemory); + return (videoMemory == NULL) ? gcvSTATUS_OUT_OF_MEMORY : gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckKERNEL_MapMemory +** +** Map video memory into the current process space. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gctPHYS_ADDR Physical +** Physical address of video memory to map. +** +** gctSIZE_T Bytes +** Number of bytes to map. +** +** OUTPUT: +** +** gctPOINTER * Logical +** Pointer to a variable that will hold the base address of the mapped +** memory region. +*/ +gceSTATUS +gckKERNEL_MapMemory( + IN gckKERNEL Kernel, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Logical + ) +{ + return gckOS_MapMemory(Kernel->os, Physical, Bytes, Logical); +} + +/******************************************************************************* +** +** gckKERNEL_UnmapMemory +** +** Unmap video memory from the current process space. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gctPHYS_ADDR Physical +** Physical address of video memory to map. +** +** gctSIZE_T Bytes +** Number of bytes to map. +** +** gctPOINTER Logical +** Base address of the mapped memory region. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckKERNEL_UnmapMemory( + IN gckKERNEL Kernel, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + IN gctPOINTER Logical + ) +{ + return gckOS_UnmapMemory(Kernel->os, Physical, Bytes, Logical); +} + +/******************************************************************************* +** +** gckKERNEL_MapVideoMemory +** +** Map video memory for the current process. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gctBOOL InUserSpace +** gcvTRUE to map the memory into the user space. +** +** gctUINT32 Address +** Hardware specific memory address. +** +** gctUINT32 Pid +** Process ID of the current process. +** +** gctUINT32 Bytes +** Number of bytes to map. +** +** OUTPUT: +** +** gctPOINTER * Logical +** Pointer to a variable that will hold the logical address of the +** specified memory address. +*/ +gceSTATUS +gckKERNEL_MapVideoMemory( + IN gckKERNEL Kernel, + IN gctBOOL InUserSpace, + IN gctUINT32 Address, + IN gctUINT32 Pid, + IN gctUINT32 Bytes, + OUT gctPOINTER * Logical + ) +{ + off64_t offset = (off64_t)Address - (off64_t)drv_mempool_get_basePAddress(); + + gcmkHEADER_ARG("Kernel=0x%x InUserSpace=%d Address=%08x", + Kernel, InUserSpace, Address); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + + *Logical = (gctPOINTER)mmap64_peer(Pid, gcvNULL, Bytes, + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NOINIT, + drv_mempool_get_fileDescriptor(), offset); + if (*Logical == MAP_FAILED) { + *Logical = NULL; + return gcvSTATUS_INVALID_ADDRESS; + } + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckKERNEL_UnmapVideoMemory +** +** Unmap video memory for the current process. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gctUINT32 Address +** Hardware specific memory address. +** +** gctUINT32 Pid +** Process ID of the current process. +** +** gctUINT32 Bytes +** Number of bytes to map. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckKERNEL_UnmapVideoMemory( + IN gckKERNEL Kernel, + IN gctPOINTER Logical, + IN gctUINT32 Pid, + IN gctUINT32 Bytes + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + + if (munmap_peer(Pid, Logical, Bytes) == -1) + { + return gcvSTATUS_INVALID_ADDRESS; + } + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckKERNEL_Notify +** +** This function is called by clients to notify the gckKERNEL object of an event. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gceNOTIFY Notification +** Notification event. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckKERNEL_Notify( + IN gckKERNEL Kernel, + IN gceNOTIFY Notification, + IN gctBOOL Data + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Kernel=0x%x Notification=%d Data=%d", + Kernel, Notification, Data); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + + /* Dispatch on notifcation. */ + switch (Notification) + { + case gcvNOTIFY_INTERRUPT: + /* Process the interrupt. */ +#if COMMAND_PROCESSOR_VERSION > 1 + status = gckINTERRUPT_Notify(Kernel->interrupt, Data); +#else + status = gckHARDWARE_Interrupt(Kernel->hardware, Data); +#endif + break; + + default: + status = gcvSTATUS_OK; + break; + } + + /* Success. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckKERNEL_QuerySettings( + IN gckKERNEL Kernel, + OUT gcsKERNEL_SETTINGS * Settings + ) +{ + gckGALDEVICE device; + + gcmkHEADER_ARG("Kernel=0x%x", Kernel); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Settings != gcvNULL); + + /* Extract the pointer to the gckGALDEVICE class. */ + device = (gckGALDEVICE) Kernel->context; + + /* Fill in signal. */ + Settings->signal = -1; + + /* Success. */ + gcmkFOOTER_ARG("Settings->signal=%d", Settings->signal); + return gcvSTATUS_OK; +} + + diff --git a/drivers/staging/rk29/vivante/hal/os/qnx/kernel/gc_hal_kernel_qnx.h b/drivers/staging/rk29/vivante/hal/os/qnx/kernel/gc_hal_kernel_qnx.h new file mode 100644 index 000000000000..79f7619dff4c --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/os/qnx/kernel/gc_hal_kernel_qnx.h @@ -0,0 +1,58 @@ +/**************************************************************************** +* +* Copyright (c) 2005 - 2010 by Vivante Corp. All rights reserved. +* +* The material in this file is confidential and contains trade secrets +* of Vivante Corporation. This is proprietary information owned by +* Vivante Corporation. No part of this work may be disclosed, +* reproduced, copied, transmitted, or used in any way for any purpose, +* without the express written permission of Vivante Corporation. +* +***************************************************************************** +* +* Auto-generated file on 10/12/2010. Do not edit!!! +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_kernel_qnx_h_ +#define __gc_hal_kernel_qnx_h_ + +#define _QNX_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NTSTRSAFE_NO_CCH_FUNCTIONS +#include "gc_hal.h" +#include "gc_hal_driver.h" +#include "gc_hal_kernel.h" +#include "gc_hal_kernel_device.h" +#include "gc_hal_kernel_os.h" +#include "../inc/gc_hal_common_qnx.h" + +#define _WIDE(string) L##string +#define WIDE(string) _WIDE(string) + +#define countof(a) (sizeof(a) / sizeof(a[0])) + +#ifndef GAL_DEV +#define GAL_DEV "/dev/galcore" +#endif + +#endif /* __gc_hal_kernel_qnx_h_ */ + diff --git a/drivers/staging/rk29/vivante/hal/os/qnx/kernel/makefile.linux b/drivers/staging/rk29/vivante/hal/os/qnx/kernel/makefile.linux new file mode 100644 index 000000000000..59c5c482b1e8 --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/os/qnx/kernel/makefile.linux @@ -0,0 +1,78 @@ +############################################################################## +# +# Copyright (c) 2005 - 2010 by Vivante Corp. All rights reserved. +# +# The material in this file is confidential and contains trade secrets +# of Vivante Corporation. This is proprietary information owned by +# Vivante Corporation. No part of this work may be disclosed, +# reproduced, copied, transmitted, or used in any way for any purpose, +# without the express written permission of Vivante Corporation. +# +############################################################################## +# +# Auto-generated file on 10/12/2010. Do not edit!!! +# +############################################################################## + + +# +# Qnx build file for kernel HAL layer. +# + +################################################################################ +# Include common definitions. + +include $(AQROOT)/makefile.linux.def + +################################################################################ +# Define a shortcut for the main target. + +#ifeq ($(STATIC_LINK),1) + STATIC = 1 +#else + DYNAMIC = 1 +#endif +PROGRAM := 1 + +#ifeq ($(STATIC), 1) + TARGET_NAME = galcore.a +#else + TARGET_NAME = galcore +#endif + +################################################################################ +# Installation directory +INSTALL_DIR := $(SDK_DIR)/drivers + +################################################################################ +# Supply additional include directories. + +INCLUDE += -I$(AQROOT)/hal/inc +INCLUDE += -I$(AQROOT)/hal/user +INCLUDE += -I$(AQROOT)/hal/kernel +INCLUDE += -I$(AQARCH)/hal/kernel +INCLUDE += -I$(AQARCH)/hal/kernel +CFLAGS += $(INCLUDE) +CFLAGS += -fPIC + +################################################################################ +# Supply necessary libraries. + +# Specify Vivante library paths. +LIBS += -L $(AQARCH)/hal/kernel/$(OBJ_DIR) +LIBS += -L $(AQROOT)/hal/kernel/$(OBJ_DIR) +LIBS += -l halarchkernel -l halkernel + +################################################################################ +# Describe object files. + +OBJECTS = \ + $(OBJ_DIR)/gc_hal_kernel_driver.o \ + $(OBJ_DIR)/gc_hal_kernel_os.o \ + $(OBJ_DIR)/gc_hal_kernel_qnx.o \ + $(OBJ_DIR)/gc_hal_kernel_device.o \ + $(OBJ_DIR)/gc_hal_kernel_debug.o \ + +include $(AQROOT)/common.target + + diff --git a/drivers/staging/rk29/vivante/hal/os/qnx/makefile.linux b/drivers/staging/rk29/vivante/hal/os/qnx/makefile.linux new file mode 100644 index 000000000000..0c0cd889624d --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/os/qnx/makefile.linux @@ -0,0 +1,40 @@ +############################################################################## +# +# Copyright (c) 2005 - 2010 by Vivante Corp. All rights reserved. +# +# The material in this file is confidential and contains trade secrets +# of Vivante Corporation. This is proprietary information owned by +# Vivante Corporation. No part of this work may be disclosed, +# reproduced, copied, transmitted, or used in any way for any purpose, +# without the express written permission of Vivante Corporation. +# +############################################################################## +# +# Auto-generated file on 10/12/2010. Do not edit!!! +# +############################################################################## + + +# +# QNX build file for the kernel level HAL libraries. +# + +################################################################################ +# Define make command. +MAKE = make --makefile=makefile.linux + + +################################################################################ +# Define build directories. + +HAL_KERNEL_DRV_ARCH := $(AQARCH)/hal/kernel +HAL_KERNEL_DRV_OS := $(AQROOT)/hal/os/qnx/kernel +HAL_KERNEL_DRV_MAIN := $(AQROOT)/hal/kernel + +$(HAL_KERNEL_DRV_OS): $(HAL_KERNEL_DRV_ARCH) $(HAL_KERNEL_DRV_MAIN) + +MODULES := $(HAL_KERNEL_DRV_ARCH) $(HAL_KERNEL_DRV_OS) $(HAL_KERNEL_DRV_MAIN) +MAIN_MODULE = $(HAL_KERNEL_DRV_OS) + +include $(AQROOT)/common.node + diff --git a/drivers/staging/rk29/vivante/hal/user/gc_hal_user_context.h b/drivers/staging/rk29/vivante/hal/user/gc_hal_user_context.h new file mode 100644 index 000000000000..d2c805e2c47f --- /dev/null +++ b/drivers/staging/rk29/vivante/hal/user/gc_hal_user_context.h @@ -0,0 +1,170 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2010 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_user_context_h_ +#define __gc_hal_user_context_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* gcoCONTEXT structure that hold the current context. */ +struct _gcoCONTEXT +{ + /* Object. */ + gcsOBJECT object; + + /* Pointer to gcoOS object. */ + gcoOS os; + + /* Pointer to gcoHARDWARE object. */ + gcoHARDWARE hardware; + + /* Context ID. */ + gctUINT64 id; + + /* State mapping. */ + gctUINT32_PTR map; + gctSIZE_T stateCount; + + /* State hinting. */ + gctUINT8_PTR hint; + gctUINT8 hintValue; + gctSIZE_T hintCount; + + /* Context buffer. */ + gctUINT32_PTR buffer; + gctUINT32 pipe3DIndex; + gctUINT32 pipe2DIndex; + gctUINT32 linkIndex; + gctUINT32 inUseIndex; + gctSIZE_T bufferSize; + + /* Context buffer used for commitment. */ + gctSIZE_T bytes; + gctPHYS_ADDR physical; + gctPOINTER logical; + + /* Pointer to final LINK command. */ + gctPOINTER link; + + /* Requested pipe select for context. */ + gctUINT32 initialPipe; + gctUINT32 entryPipe; + gctUINT32 currentPipe; + + /* Flag to specify whether PostCommit needs to be called. */ + gctBOOL postCommit; + + /* Busy flag. */ + volatile gctBOOL * inUse; + + /* Variables used for building state buffer. */ + gctUINT32 lastAddress; + gctSIZE_T lastSize; + gctUINT32 lastIndex; + gctBOOL lastFixed; + + /* Hint array. */ + gctUINT32_PTR hintArray; + gctUINT32_PTR hintIndex; +}; + +struct _gcoCMDBUF +{ + /* The object. */ + gcsOBJECT object; + + /* Pointer to gcoOS object. */ + gcoOS os; + + /* Pointer to gcoHARDWARE object. */ + gcoHARDWARE hardware; + + /* Physical address of command buffer. */ + gctPHYS_ADDR physical; + + /* Logical address of command buffer. */ + gctPOINTER logical; + + /* Number of bytes in command buffer. */ + gctSIZE_T bytes; + + /* Start offset into the command buffer. */ + gctUINT32 startOffset; + + /* Current offset into the command buffer. */ + gctUINT32 offset; + + /* Number of free bytes in command buffer. */ + gctSIZE_T free; + +#if gcdSECURE_USER + /* Table of offsets that define the physical addresses to be mapped. */ + gctUINT32_PTR hintTable; + + /* Current index into map table. */ + gctUINT32_PTR hintIndex; + + /* Commit index for map table. */ + gctUINT32_PTR hintCommit; +#endif +}; + +typedef struct _gcsQUEUE * gcsQUEUE_PTR; + +typedef struct _gcsQUEUE +{ + /* Pointer to next gcsQUEUE structure. */ + gcsQUEUE_PTR next; + +#ifdef __QNXNTO__ + /* Size of this object. */ + gctSIZE_T bytes; +#endif + + /* Event information. */ + gcsHAL_INTERFACE iface; +} +gcsQUEUE; + +/* Event queue. */ +struct _gcoQUEUE +{ + /* The object. */ + gcsOBJECT object; + + /* Pointer to gcoOS object. */ + gcoOS os; + + /* Pointer to current event queue. */ + gcsQUEUE_PTR head; + gcsQUEUE_PTR tail; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_user_context_h_ */ +