diff --git a/Makefile b/Makefile index d7cf5448ee7b..a6ff97dec8d4 100644 --- a/Makefile +++ b/Makefile @@ -184,7 +184,7 @@ export KBUILD_BUILDHOST := $(SUBARCH) #CROSS_COMPILE ?= ARCH ?= arm #CROSS_COMPILE :=/opt/android0320/mydroid/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi- -CROSS_COMPILE ?=../toolchain/arm-eabi-4.4.0/bin/arm-eabi- +CROSS_COMPILE ?=../../google/myandroid/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi- # Architecture as present in compile.h UTS_MACHINE := $(ARCH) diff --git a/arch/arm/configs/rk29_sdk_defconfig b/arch/arm/configs/rk29_sdk_defconfig index 22664fc85e3f..c34b9aafcc78 100644 --- a/arch/arm/configs/rk29_sdk_defconfig +++ b/arch/arm/configs/rk29_sdk_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.32.9 -# Wed Oct 20 15:12:34 2010 +# Sat Nov 6 11:33:18 2010 # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -68,16 +68,10 @@ CONFIG_RESOURCE_COUNTERS=y # CONFIG_RELAY is not set # CONFIG_NAMESPACES is not set CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="../initramfs" -CONFIG_INITRAMFS_ROOT_UID=0 -CONFIG_INITRAMFS_ROOT_GID=0 -# CONFIG_RD_GZIP is not set +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y # CONFIG_RD_BZIP2 is not set # CONFIG_RD_LZMA is not set -CONFIG_INITRAMFS_COMPRESSION_NONE=y -# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set -# CONFIG_INITRAMFS_COMPRESSION_BZIP2 is not set -# CONFIG_INITRAMFS_COMPRESSION_LZMA is not set CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_SYSCTL=y CONFIG_ANON_INODES=y @@ -202,6 +196,11 @@ CONFIG_MMU=y CONFIG_ARCH_RK29=y CONFIG_MACH_RK29SDK=y +# +# RK29 VPU (Video Processing Unit) support +# +# CONFIG_RK29_VPU is not set + # # Processor Type # @@ -223,9 +222,9 @@ CONFIG_CPU_CP15_MMU=y # Processor Features # CONFIG_ARM_THUMB=y -# CONFIG_ARM_THUMBEE is not set -CONFIG_CPU_ICACHE_DISABLE=y -CONFIG_CPU_DCACHE_DISABLE=y +CONFIG_ARM_THUMBEE=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set # CONFIG_CPU_BPREDICT_DISABLE is not set CONFIG_HAS_TLS_REG=y CONFIG_ARM_L1_CACHE_SHIFT=5 @@ -425,7 +424,89 @@ CONFIG_EXTRA_FIRMWARE="" # CONFIG_DEBUG_DEVRES is not set # CONFIG_SYS_HYPERVISOR is not set # CONFIG_CONNECTOR is not set -# CONFIG_MTD is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_MTD_OOPS is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +CONFIG_MTD_NAND_IDS=y +CONFIG_MTD_NAND=y +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +# CONFIG_MTD_NAND_GPIO is not set +# CONFIG_MTD_NAND_DISKONCHIP is not set +CONFIG_MTD_NAND_RK29=y +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set # CONFIG_PARPORT is not set CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_COW_COMMON is not set @@ -435,8 +516,9 @@ CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_RAM is not set # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set CONFIG_MISC_DEVICES=y -# CONFIG_ANDROID_PMEM is not set +CONFIG_ANDROID_PMEM=y # CONFIG_ENCLOSURE_SERVICES is not set # CONFIG_KERNEL_DEBUGGER_CORE is not set # CONFIG_UID_STAT is not set @@ -643,7 +725,34 @@ CONFIG_DUMMY_CONSOLE=y # CONFIG_SOUND is not set # CONFIG_HID_SUPPORT is not set # CONFIG_USB_SUPPORT is not set -# CONFIG_MMC is not set +CONFIG_MMC=y +CONFIG_MMC_DEBUG=y +# CONFIG_MMC_UNSAFE_RESUME is not set +# CONFIG_MMC_EMBEDDED_SDIO is not set +# CONFIG_MMC_PARANOID_SD_INIT is not set + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +CONFIG_SDMMC_RK29=y + +# +# Now, there are two SDMMC controllers selected, SDMMC0 and SDMMC1. +# +CONFIG_SDMMC0_RK29=y +CONFIG_SDMMC1_RK29=y +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_AT91 is not set +# CONFIG_MMC_ATMELMCI is not set # CONFIG_MEMSTICK is not set # CONFIG_NEW_LEDS is not set # CONFIG_SWITCH is not set @@ -711,6 +820,11 @@ CONFIG_ANDROID_LOW_MEMORY_KILLER=y # # CONFIG_RK2818_POWER is not set +# +# GPU Vivante +# +CONFIG_VIVANTE=y + # # CMMB # @@ -719,22 +833,12 @@ CONFIG_ANDROID_LOW_MEMORY_KILLER=y # # File systems # -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT2_FS_POSIX_ACL=y -CONFIG_EXT2_FS_SECURITY=y -# CONFIG_EXT2_FS_XIP is not set -CONFIG_EXT3_FS=y -# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_EXT3_FS_XATTR=y -CONFIG_EXT3_FS_POSIX_ACL=y -CONFIG_EXT3_FS_SECURITY=y +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set # CONFIG_EXT4_FS is not set -CONFIG_JBD=y -CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set -CONFIG_FS_POSIX_ACL=y +# CONFIG_FS_POSIX_ACL is not set # CONFIG_XFS_FS is not set # CONFIG_OCFS2_FS is not set # CONFIG_BTRFS_FS is not set @@ -789,6 +893,18 @@ CONFIG_MISC_FILESYSTEMS=y # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set +CONFIG_YAFFS_FS=y +CONFIG_YAFFS_YAFFS1=y +# CONFIG_YAFFS_9BYTE_TAGS is not set +# CONFIG_YAFFS_DOES_ECC is not set +CONFIG_YAFFS_YAFFS2=y +CONFIG_YAFFS_AUTO_YAFFS2=y +# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set +# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set +# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set +CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y +# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set +# CONFIG_JFFS2_FS is not set # CONFIG_CRAMFS is not set # CONFIG_SQUASHFS is not set # CONFIG_VXFS_FS is not set @@ -927,7 +1043,7 @@ CONFIG_DEBUG_ERRORS=y # # CONFIG_KEYS is not set # CONFIG_SECURITY is not set -CONFIG_SECURITYFS=y +# CONFIG_SECURITYFS is not set # CONFIG_SECURITY_FILE_CAPABILITIES is not set CONFIG_CRYPTO=y @@ -1040,6 +1156,8 @@ CONFIG_CRC16=y CONFIG_CRC32=y # CONFIG_CRC7 is not set # CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_DECOMPRESS_GZIP=y CONFIG_REED_SOLOMON=y CONFIG_REED_SOLOMON_ENC8=y CONFIG_REED_SOLOMON_DEC8=y diff --git a/arch/arm/mach-rk2818/devices.c b/arch/arm/mach-rk2818/devices.c index 97dfd87e64b1..b9132b80f863 100755 --- a/arch/arm/mach-rk2818/devices.c +++ b/arch/arm/mach-rk2818/devices.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include /* ddl@rock-chips.com : camera support */ #include diff --git a/arch/arm/mach-rk29/Kconfig b/arch/arm/mach-rk29/Kconfig index f659df860d7e..d2c7dd516f53 100644 --- a/arch/arm/mach-rk29/Kconfig +++ b/arch/arm/mach-rk29/Kconfig @@ -4,4 +4,29 @@ config MACH_RK29SDK bool "ROCKCHIP Board Rk29 For Sdk" select PL330 help - Support for the ROCKCHIP Board For Rk29 Sdk. \ No newline at end of file + Support for the ROCKCHIP Board For Rk29 Sdk. + +menu "RK29 VPU (Video Processing Unit) support" + +config RK29_VPU + tristate "Support for RK29 VPU (Video Processing Unit)" + depends on ARCH_RK29 + default y + +config RK29_VPU_DEBUG + bool "RK29 VPU debugging" + depends on RK29_VPU != n + default n + help + This is an option for the developers; most people should + say N here. This enables RK29 VPU driver debugging. + +config RK29_VPU_HW_PERFORMANCE + bool "RK29 VPU HW_PERFORMANCE ioctl support" + depends on RK29_VPU != n + default n + help + This is an option for the developers; most people should + say N here. This enables RK29 VPU driver HW_PERFORMANCE ioctl. + +endmenu diff --git a/arch/arm/mach-rk29/Makefile b/arch/arm/mach-rk29/Makefile index ba023c534364..e9a3e38df099 100644 --- a/arch/arm/mach-rk29/Makefile +++ b/arch/arm/mach-rk29/Makefile @@ -1,2 +1,3 @@ obj-y += timer.o io.o devices.o iomux.o clock.o rk29-pl330.o dma.o gpio.o +obj-$(CONFIG_RK29_VPU) += vpu.o obj-$(CONFIG_MACH_RK29SDK) += board-rk29sdk.o diff --git a/arch/arm/mach-rk29/board-rk29sdk.c b/arch/arm/mach-rk29/board-rk29sdk.c index 816156cd16f7..5dd72399ac5f 100755 --- a/arch/arm/mach-rk29/board-rk29sdk.c +++ b/arch/arm/mach-rk29/board-rk29sdk.c @@ -22,8 +22,10 @@ #include #include #include +#include #include +#include #include #include #include @@ -35,6 +37,7 @@ #include #include #include +#include #include @@ -44,8 +47,30 @@ #include "../../../drivers/input/touchscreen/xpt2046_cbn_ts.h" +/* Set memory size of pmem */ +#define SDRAM_SIZE SZ_128M +#define PMEM_GPU_SIZE (12 * SZ_1M) +#define PMEM_UI_SIZE SZ_16M +#define PMEM_VPU_SIZE SZ_32M + +#define PMEM_GPU_BASE (RK29_SDRAM_PHYS + SDRAM_SIZE - PMEM_GPU_SIZE) +#define PMEM_UI_BASE (PMEM_GPU_BASE - PMEM_UI_SIZE) +#define PMEM_VPU_BASE (PMEM_UI_BASE - PMEM_VPU_SIZE) +#define LINUX_SIZE (PMEM_VPU_BASE - RK29_SDRAM_PHYS) + extern struct sys_timer rk29_timer; +int rk29_nand_io_init(void) +{ + return 0; +} + +struct rk29_nand_platform_data rk29_nand_data = { + .width = 1, /* data bus width in bytes */ + .hw_ecc = 1, /* hw ecc 0: soft ecc */ + .num_flash = 1, + .io_init = rk29_nand_io_init, +}; static struct rk29_gpio_bank rk29_gpiobankinit[] = { { @@ -78,14 +103,385 @@ static struct rk29_gpio_bank rk29_gpiobankinit[] = { }, }; +/***************************************************************************************** + * lcd devices + * author: zyw@rock-chips.com + *****************************************************************************************/ +//#ifdef CONFIG_LCD_TD043MGEA1 +#define LCD_TXD_PIN RK29_PIN0_PA6 // 乱填,得修改 +#define LCD_CLK_PIN RK29_PIN0_PA7 // 乱填,得修改 +#define LCD_CS_PIN RK29_PIN0_PB6 // 乱填,得修改 +#define LCD_TXD_MUX_NAME GPIOE_U1IR_I2C1_NAME +#define LCD_CLK_MUX_NAME NULL +#define LCD_CS_MUX_NAME GPIOH6_IQ_SEL_NAME +#define LCD_TXD_MUX_MODE 0 +#define LCD_CLK_MUX_MODE 0 +#define LCD_CS_MUX_MODE 0 +//#endif +static int rk29_lcd_io_init(void) +{ + int ret = 0; + +#if 0 + rk29_mux_api_set(LCD_CS_MUX_NAME, LCD_CS_MUX_MODE); + if (LCD_CS_PIN != INVALID_GPIO) { + ret = gpio_request(LCD_CS_PIN, NULL); + if(ret != 0) + { + goto err1; + printk(">>>>>> lcd cs gpio_request err \n "); + } + } + + rk29_mux_api_set(LCD_CLK_MUX_NAME, LCD_CLK_MUX_MODE); + if (LCD_CLK_PIN != INVALID_GPIO) { + ret = gpio_request(LCD_CLK_PIN, NULL); + if(ret != 0) + { + goto err2; + printk(">>>>>> lcd clk gpio_request err \n "); + } + } + + rk29_mux_api_set(LCD_TXD_MUX_NAME, LCD_TXD_MUX_MODE); + if (LCD_TXD_PIN != INVALID_GPIO) { + ret = gpio_request(LCD_TXD_PIN, NULL); + if(ret != 0) + { + goto err3; + printk(">>>>>> lcd txd gpio_request err \n "); + } + } + + return 0; + +err3: + if (LCD_CLK_PIN != INVALID_GPIO) { + gpio_free(LCD_CLK_PIN); + } +err2: + if (LCD_CS_PIN != INVALID_GPIO) { + gpio_free(LCD_CS_PIN); + } +err1: +#endif + return ret; +} + +static int rk29_lcd_io_deinit(void) +{ + int ret = 0; +#if 0 + gpio_direction_output(LCD_CLK_PIN, 0); + gpio_set_value(LCD_CLK_PIN, GPIO_HIGH); + gpio_direction_output(LCD_TXD_PIN, 0); + gpio_set_value(LCD_TXD_PIN, GPIO_HIGH); + + gpio_free(LCD_CS_PIN); + rk29_mux_api_mode_resume(LCD_CS_MUX_NAME); + gpio_free(LCD_CLK_PIN); + gpio_free(LCD_TXD_PIN); + rk29_mux_api_mode_resume(LCD_TXD_MUX_NAME); + rk29_mux_api_mode_resume(LCD_CLK_MUX_NAME); +#endif + return ret; +} + +struct rk29lcd_info rk29_lcd_info = { + //.txd_pin = LCD_TXD_PIN, + //.clk_pin = LCD_CLK_PIN, + //.cs_pin = LCD_CS_PIN, + .io_init = rk29_lcd_io_init, + .io_deinit = rk29_lcd_io_deinit, +}; + + +/***************************************************************************************** + * frame buffe devices + * author: zyw@rock-chips.com + *****************************************************************************************/ + +#define FB_ID 0 +#define FB_DISPLAY_ON_PIN RK29_PIN0_PB1 // 乱填,得修改 +#define FB_LCD_STANDBY_PIN INVALID_GPIO +#define FB_MCU_FMK_PIN INVALID_GPIO + +#if 0 +#define FB_DISPLAY_ON_VALUE GPIO_LOW +#define FB_LCD_STANDBY_VALUE 0 + +#define FB_DISPLAY_ON_MUX_NAME GPIOB1_SMCS1_MMC0PCA_NAME +#define FB_DISPLAY_ON_MUX_MODE IOMUXA_GPIO0_B1 + +#define FB_LCD_STANDBY_MUX_NAME NULL +#define FB_LCD_STANDBY_MUX_MODE 1 + +#define FB_MCU_FMK_PIN_MUX_NAME NULL +#define FB_MCU_FMK_MUX_MODE 0 + +#define FB_DATA0_16_MUX_NAME GPIOC_LCDC16BIT_SEL_NAME +#define FB_DATA0_16_MUX_MODE 1 + +#define FB_DATA17_18_MUX_NAME GPIOC_LCDC18BIT_SEL_NAME +#define FB_DATA17_18_MUX_MODE 1 + +#define FB_DATA19_24_MUX_NAME GPIOC_LCDC24BIT_SEL_NAME +#define FB_DATA19_24_MUX_MODE 1 + +#define FB_DEN_MUX_NAME CXGPIO_LCDDEN_SEL_NAME +#define FB_DEN_MUX_MODE 1 + +#define FB_VSYNC_MUX_NAME CXGPIO_LCDVSYNC_SEL_NAME +#define FB_VSYNC_MUX_MODE 1 + +#define FB_MCU_FMK_MUX_NAME NULL +#define FB_MCU_FMK_MUX_MODE 0 +#endif +static int rk29_fb_io_init(struct rk29_fb_setting_info *fb_setting) +{ + int ret = 0; +#if 0 + if(fb_setting->data_num <=16) + rk29_mux_api_set(FB_DATA0_16_MUX_NAME, FB_DATA0_16_MUX_MODE); + if(fb_setting->data_num >16 && fb_setting->data_num<=18) + rk29_mux_api_set(FB_DATA17_18_MUX_NAME, FB_DATA17_18_MUX_MODE); + if(fb_setting->data_num >18) + rk29_mux_api_set(FB_DATA19_24_MUX_NAME, FB_DATA19_24_MUX_MODE); + + if(fb_setting->vsync_en) + rk29_mux_api_set(FB_VSYNC_MUX_NAME, FB_VSYNC_MUX_MODE); + + if(fb_setting->den_en) + rk29_mux_api_set(FB_DEN_MUX_NAME, FB_DEN_MUX_MODE); + + if(fb_setting->mcu_fmk_en && FB_MCU_FMK_MUX_NAME && (FB_MCU_FMK_PIN != INVALID_GPIO)) + { + rk29_mux_api_set(FB_MCU_FMK_MUX_NAME, FB_MCU_FMK_MUX_MODE); + ret = gpio_request(FB_MCU_FMK_PIN, NULL); + if(ret != 0) + { + gpio_free(FB_MCU_FMK_PIN); + printk(">>>>>> FB_MCU_FMK_PIN gpio_request err \n "); + } + gpio_direction_input(FB_MCU_FMK_PIN); + } + + if(fb_setting->disp_on_en && FB_DISPLAY_ON_MUX_NAME && (FB_DISPLAY_ON_PIN != INVALID_GPIO)) + { + rk29_mux_api_set(FB_DISPLAY_ON_MUX_NAME, FB_DISPLAY_ON_MUX_MODE); + ret = gpio_request(FB_DISPLAY_ON_PIN, NULL); + if(ret != 0) + { + gpio_free(FB_DISPLAY_ON_PIN); + printk(">>>>>> FB_DISPLAY_ON_PIN gpio_request err \n "); + } + } + + if(fb_setting->disp_on_en && FB_LCD_STANDBY_MUX_NAME && (FB_LCD_STANDBY_PIN != INVALID_GPIO)) + { + rk29_mux_api_set(FB_LCD_STANDBY_MUX_NAME, FB_LCD_STANDBY_MUX_MODE); + ret = gpio_request(FB_LCD_STANDBY_PIN, NULL); + if(ret != 0) + { + gpio_free(FB_LCD_STANDBY_PIN); + printk(">>>>>> FB_LCD_STANDBY_PIN gpio_request err \n "); + } + } +#endif + return ret; +} + +struct rk29fb_info rk29_fb_info = { + .fb_id = FB_ID, + //.disp_on_pin = FB_DISPLAY_ON_PIN, + //.disp_on_value = FB_DISPLAY_ON_VALUE, + //.standby_pin = FB_LCD_STANDBY_PIN, + //.standby_value = FB_LCD_STANDBY_VALUE, + //.mcu_fmk_pin = FB_MCU_FMK_PIN, + .lcd_info = &rk29_lcd_info, + .io_init = rk29_fb_io_init, +}; + +static struct android_pmem_platform_data android_pmem_pdata = { + .name = "pmem", + .start = PMEM_UI_BASE, + .size = PMEM_UI_SIZE, + .no_allocator = 0, + .cached = 1, +}; + +static struct platform_device android_pmem_device = { + .name = "android_pmem", + .id = 0, + .dev = { + .platform_data = &android_pmem_pdata, + }, +}; + + +static struct android_pmem_platform_data android_pmem_vpu_pdata = { + .name = "pmem_vpu", + .start = PMEM_VPU_BASE, + .size = PMEM_VPU_SIZE, + .no_allocator = 0, + .cached = 1, +}; + +static struct platform_device android_pmem_vpu_device = { + .name = "android_pmem", + .id = 2, + .dev = { + .platform_data = &android_pmem_vpu_pdata, + }, +}; + +/***************************************************************************************** + * SDMMC devices +*****************************************************************************************/ +#ifdef CONFIG_SDMMC0_RK29 +void rk29_sdmmc0_cfg_gpio(struct platform_device *dev) +{ + rk29_mux_api_set(GPIO1D1_SDMMC0CMD_NAME, GPIO1H_SDMMC0_CMD); + rk29_mux_api_set(GPIO1D0_SDMMC0CLKOUT_NAME, GPIO1H_SDMMC0_CLKOUT); + rk29_mux_api_set(GPIO1D2_SDMMC0DATA0_NAME, GPIO1H_SDMMC0_DATA0); + rk29_mux_api_set(GPIO1D3_SDMMC0DATA1_NAME, GPIO1H_SDMMC0_DATA1); + rk29_mux_api_set(GPIO1D4_SDMMC0DATA2_NAME, GPIO1H_SDMMC0_DATA2); + rk29_mux_api_set(GPIO1D5_SDMMC0DATA3_NAME, GPIO1H_SDMMC0_DATA3); + rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_SDMMC0_DETECT_N); +} + +#define CONFIG_SDMMC0_USE_DMA +struct rk29_sdmmc_platform_data default_sdmmc0_data = { + .num_slots = 1, + .host_ocr_avail = (MMC_VDD_27_28|MMC_VDD_28_29|MMC_VDD_29_30| + MMC_VDD_30_31|MMC_VDD_31_32|MMC_VDD_32_33| + MMC_VDD_33_34|MMC_VDD_34_35| MMC_VDD_35_36), + .host_caps = (MMC_CAP_4_BIT_DATA|MMC_CAP_MMC_HIGHSPEED|MMC_CAP_SD_HIGHSPEED), + .io_init = rk29_sdmmc0_cfg_gpio, + .dma_name = "sd_mmc", +#ifdef CONFIG_SDMMC0_USE_DMA + .use_dma = 1, +#else + .use_dma = 0, +#endif +}; +#endif +#ifdef CONFIG_SDMMC1_RK29 +#define CONFIG_SDMMC1_USE_DMA +void rk29_sdmmc1_cfg_gpio(struct platform_device *dev) +{ + rk29_mux_api_set(GPIO1C2_SDMMC1CMD_NAME, GPIO1H_SDMMC1_CMD); + rk29_mux_api_set(GPIO1C7_SDMMC1CLKOUT_NAME, GPIO1H_SDMMC1_CLKOUT); + rk29_mux_api_set(GPIO1C3_SDMMC1DATA0_NAME, GPIO1H_SDMMC1_DATA0); + rk29_mux_api_set(GPIO1C4_SDMMC1DATA1_NAME, GPIO1H_SDMMC1_DATA1); + rk29_mux_api_set(GPIO1C5_SDMMC1DATA2_NAME, GPIO1H_SDMMC1_DATA2); + rk29_mux_api_set(GPIO1C6_SDMMC1DATA3_NAME, GPIO1H_SDMMC1_DATA3); +} + +struct rk29_sdmmc_platform_data default_sdmmc1_data = { + .num_slots = 1, + .host_ocr_avail = (MMC_VDD_26_27|MMC_VDD_27_28|MMC_VDD_28_29| + MMC_VDD_29_30|MMC_VDD_30_31|MMC_VDD_31_32| + MMC_VDD_32_33|MMC_VDD_33_34), + .host_caps = (MMC_CAP_4_BIT_DATA|MMC_CAP_SDIO_IRQ| + MMC_CAP_MMC_HIGHSPEED|MMC_CAP_SD_HIGHSPEED), + .io_init = rk29_sdmmc1_cfg_gpio, + .dma_name = "sdio", +#ifdef CONFIG_SDMMC1_USE_DMA + .use_dma = 1, +#else + .use_dma = 0, +#endif +}; +#endif + +#ifdef CONFIG_VIVANTE +static struct resource resources_gpu[] = { + [0] = { + .name = "gpu_irq", + .start = IRQ_GPU, + .end = IRQ_GPU, + .flags = IORESOURCE_IRQ, + }, + [1] = { + .name = "gpu_base", + .start = RK29_GPU_PHYS, + .end = RK29_GPU_PHYS + (256 << 10), + .flags = IORESOURCE_MEM, + }, + [2] = { + .name = "gpu_mem", + .start = PMEM_GPU_BASE, + .end = PMEM_GPU_BASE + PMEM_GPU_SIZE, + .flags = IORESOURCE_MEM, + }, +}; +struct platform_device rk29_device_gpu = { + .name = "galcore", + .id = 0, + .num_resources = ARRAY_SIZE(resources_gpu), + .resource = resources_gpu, +}; +#endif + +static void __init rk29_board_iomux_init(void) +{ + #ifdef CONFIG_UART0_RK29 + rk29_mux_api_set(GPIO1B7_UART0SOUT_NAME, GPIO1L_UART0_SOUT); + rk29_mux_api_set(GPIO1B6_UART0SIN_NAME, GPIO1L_UART0_SIN); + #ifdef CONFIG_UART0_CTS_RTS_RK29 + rk29_mux_api_set(GPIO1C1_UART0RTSN_SDMMC1WRITEPRT_NAME, GPIO1H_UART0_RTS_N); + rk29_mux_api_set(GPIO1C0_UART0CTSN_SDMMC1DETECTN_NAME, GPIO1H_UART0_CTS_N); + #endif + #endif + #ifdef CONFIG_UART1_RK29 + rk29_mux_api_set(GPIO2A5_UART1SOUT_NAME, GPIO2L_UART1_SOUT); + rk29_mux_api_set(GPIO2A4_UART1SIN_NAME, GPIO2L_UART1_SIN); + #endif + #ifdef CONFIG_UART2_RK29 + rk29_mux_api_set(GPIO2B1_UART2SOUT_NAME, GPIO2L_UART2_SOUT); + rk29_mux_api_set(GPIO2B0_UART2SIN_NAME, GPIO2L_UART2_SIN); + #ifdef CONFIG_UART2_CTS_RTS_RK29 + rk29_mux_api_set(GPIO2A7_UART2RTSN_NAME, GPIO2L_UART2_RTS_N); + rk29_mux_api_set(GPIO2A6_UART2CTSN_NAME, GPIO2L_UART2_CTS_N); + #endif + #endif + #ifdef CONFIG_UART3_RK29 + rk29_mux_api_set(GPIO2B3_UART3SOUT_NAME, GPIO2L_UART3_SOUT); + rk29_mux_api_set(GPIO2B2_UART3SIN_NAME, GPIO2L_UART3_SIN); + #ifdef CONFIG_UART3_CTS_RTS_RK29 + rk29_mux_api_set(GPIO2B5_UART3RTSN_I2C3SCL_NAME, GPIO2L_UART3_RTS_N); + rk29_mux_api_set(GPIO2B4_UART3CTSN_I2C3SDA_NAME, GPIO2L_UART3_CTS_N); + #endif + #endif +} + static struct platform_device *devices[] __initdata = { -#ifdef CONFIG_UART1_RK29 +#ifdef CONFIG_UART1_RK29 &rk29_device_uart1, #endif #ifdef CONFIG_SPIM_RK29XX &rk29xx_device_spi0m, &rk29xx_device_spi1m, #endif +#ifdef CONFIG_SDMMC0_RK29 + &rk29_device_sdmmc0, +#endif +#ifdef CONFIG_SDMMC1_RK29 + &rk29_device_sdmmc1, +#endif +#ifdef CONFIG_MTD_NAND_RK29 + &rk29_device_nand, +#endif + +#ifdef CONFIG_FB_RK29 + &rk29_device_fb, +#endif +#ifdef CONFIG_VIVANTE + &rk29_device_gpu, +#endif + &android_pmem_device, + &android_pmem_vpu_device, }; /***************************************************************************************** @@ -286,12 +682,23 @@ static void __init machine_rk29_init_irq(void) rk29_gpio_init(rk29_gpiobankinit, MAX_BANK); rk29_gpio_irq_setup(); } + static void __init machine_rk29_board_init(void) { + rk29_board_iomux_init(); platform_add_devices(devices, ARRAY_SIZE(devices)); spi_register_board_info(board_spi_devices, ARRAY_SIZE(board_spi_devices)); } +static void __init machine_rk29_fixup(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ + mi->nr_banks = 1; + mi->bank[0].start = RK29_SDRAM_PHYS; + mi->bank[0].node = PHYS_TO_NID(RK29_SDRAM_PHYS); + mi->bank[0].size = LINUX_SIZE; +} + static void __init machine_rk29_mapio(void) { rk29_map_common_io(); @@ -300,11 +707,11 @@ static void __init machine_rk29_mapio(void) } MACHINE_START(RK29, "RK29board") - -/* UART for LL DEBUG */ + /* UART for LL DEBUG */ .phys_io = RK29_UART1_PHYS, .io_pg_offst = ((RK29_UART1_BASE) >> 18) & 0xfffc, .boot_params = RK29_SDRAM_PHYS + 0x88000, + .fixup = machine_rk29_fixup, .map_io = machine_rk29_mapio, .init_irq = machine_rk29_init_irq, .init_machine = machine_rk29_board_init, diff --git a/arch/arm/mach-rk29/clock.c b/arch/arm/mach-rk29/clock.c index f0d2cb47fdb7..6ba71e9602c5 100755 --- a/arch/arm/mach-rk29/clock.c +++ b/arch/arm/mach-rk29/clock.c @@ -1126,6 +1126,19 @@ static struct clk clk_##NAME = { \ .gate_idx = CLK_GATE_##ID, \ } +GATE_CLK(i2c0, pclk_cpu, I2C0); +GATE_CLK(i2c1, pclk_periph, I2C1); +GATE_CLK(i2c2, pclk_periph, I2C2); +GATE_CLK(i2c3, pclk_periph, I2C3); + +GATE_CLK(gpio0, pclk_cpu, GPIO0); +GATE_CLK(gpio1, pclk_periph, GPIO1); +GATE_CLK(gpio2, pclk_periph, GPIO2); +GATE_CLK(gpio3, pclk_periph, GPIO3); +GATE_CLK(gpio4, pclk_cpu, GPIO4); +GATE_CLK(gpio5, pclk_periph, GPIO5); +GATE_CLK(gpio6, pclk_cpu, GPIO6); + #define CLK(dev, con, ck) \ { \ .dev_id = dev, \ @@ -1231,6 +1244,19 @@ static struct clk_lookup clks[] = { CLK(NULL, "hclk_vdpu", &hclk_vdpu), CLK1(gpu), CLK(NULL, "aclk_gpu", &aclk_gpu), + + CLK("rk29_i2c.0", "i2c", &clk_i2c0), + CLK("rk29_i2c.1", "i2c", &clk_i2c1), + CLK("rk29_i2c.2", "i2c", &clk_i2c2), + CLK("rk29_i2c.3", "i2c", &clk_i2c3), + + CLK1(gpio0), + CLK1(gpio1), + CLK1(gpio2), + CLK1(gpio3), + CLK1(gpio4), + CLK1(gpio5), + CLK1(gpio6), }; static LIST_HEAD(clocks); diff --git a/arch/arm/mach-rk29/devices.c b/arch/arm/mach-rk29/devices.c index a950e87f2f15..6f9b03927938 100755 --- a/arch/arm/mach-rk29/devices.c +++ b/arch/arm/mach-rk29/devices.c @@ -21,7 +21,59 @@ #include #include #include "devices.h" - + + +#ifdef CONFIG_SDMMC0_RK29 +static struct resource resources_sdmmc0[] = { + { + .start = IRQ_SDMMC, + .end = IRQ_SDMMC, + .flags = IORESOURCE_IRQ, + }, + { + .start = RK29_SDMMC0_PHYS, + .end = RK29_SDMMC0_PHYS + RK29_SDMMC0_SIZE -1, + .flags = IORESOURCE_MEM, + } +}; +#endif +#ifdef CONFIG_SDMMC1_RK29 +static struct resource resources_sdmmc1[] = { + { + .start = IRQ_SDIO, + .end = IRQ_SDIO, + .flags = IORESOURCE_IRQ, + }, + { + .start = RK29_SDMMC1_PHYS, + .end = RK29_SDMMC1_PHYS + RK29_SDMMC1_SIZE -1, + .flags = IORESOURCE_MEM, + } +}; +#endif +/* sdmmc */ +#ifdef CONFIG_SDMMC0_RK29 +struct platform_device rk29_device_sdmmc0 = { + .name = "rk29_sdmmc", + .id = 0, + .num_resources = ARRAY_SIZE(resources_sdmmc0), + .resource = resources_sdmmc0, + .dev = { + .platform_data = &default_sdmmc0_data, + }, +}; +#endif +#ifdef CONFIG_SDMMC1_RK29 +struct platform_device rk29_device_sdmmc1 = { + .name = "rk29_sdmmc", + .id = 1, + .num_resources = ARRAY_SIZE(resources_sdmmc1), + .resource = resources_sdmmc1, + .dev = { + .platform_data = &default_sdmmc1_data, + }, +}; +#endif /* * rk29 4 uarts device */ @@ -34,7 +86,7 @@ static struct resource resources_uart0[] = { }, { .start = RK29_UART0_PHYS, - .end = RK29_UART0_PHYS + SZ_1K - 1, + .end = RK29_UART0_PHYS + RK29_UART0_SIZE - 1, .flags = IORESOURCE_MEM, }, }; @@ -48,7 +100,7 @@ static struct resource resources_uart1[] = { }, { .start = RK29_UART1_PHYS, - .end = RK29_UART1_PHYS + SZ_1K - 1, + .end = RK29_UART1_PHYS + RK29_UART1_SIZE - 1, .flags = IORESOURCE_MEM, }, }; @@ -62,7 +114,7 @@ static struct resource resources_uart2[] = { }, { .start = RK29_UART2_PHYS, - .end = RK29_UART2_PHYS + SZ_1K - 1, + .end = RK29_UART2_PHYS + RK29_UART2_SIZE - 1, .flags = IORESOURCE_MEM, }, }; @@ -76,7 +128,7 @@ static struct resource resources_uart3[] = { }, { .start = RK29_UART3_PHYS, - .end = RK29_UART3_PHYS + SZ_1K - 1, + .end = RK29_UART3_PHYS + RK29_UART3_SIZE - 1, .flags = IORESOURCE_MEM, }, }; @@ -186,4 +238,51 @@ struct platform_device rk29xx_device_spi1m = { }, }; +#ifdef CONFIG_FB_RK29 +/* rk29 fb resource */ +static struct resource rk29_fb_resource[] = { + [0] = { + .start = RK29_LCDC_PHYS, + .end = RK29_LCDC_PHYS + RK29_LCDC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_LCDC, + .end = IRQ_LCDC, + .flags = IORESOURCE_IRQ, + }, +}; + +/*platform_device*/ +extern struct rk29fb_info rk29_fb_info; +struct platform_device rk29_device_fb = { + .name = "rk29-fb", + .id = 4, + .num_resources = ARRAY_SIZE(rk29_fb_resource), + .resource = rk29_fb_resource, + .dev = { + .platform_data = &rk29_fb_info, + } +}; +#endif +#if defined(CONFIG_MTD_NAND_RK29) +static struct resource nand_resources[] = { + { + .start = RK29_NANDC_PHYS, + .end = RK29_NANDC_PHYS+RK29_NANDC_SIZE -1, + .flags = IORESOURCE_MEM, + } +}; + +struct platform_device rk29_device_nand = { + .name = "rk29-nand", + .id = -1, + .resource = nand_resources, + .num_resources= ARRAY_SIZE(nand_resources), + .dev = { + .platform_data= &rk29_nand_data, + }, + +}; +#endif diff --git a/arch/arm/mach-rk29/devices.h b/arch/arm/mach-rk29/devices.h index 8911ba3ab457..0d8291020843 100755 --- a/arch/arm/mach-rk29/devices.h +++ b/arch/arm/mach-rk29/devices.h @@ -16,6 +16,7 @@ #ifndef __ARCH_ARM_MACH_RK29_DEVICES_H #define __ARCH_ARM_MACH_RK29_DEVICES_H +extern struct rk29_nand_platform_data rk29_nand_data; extern struct platform_device rk29_device_uart0; extern struct platform_device rk29_device_uart1; @@ -25,5 +26,11 @@ extern struct platform_device rk29xx_device_spi0m; extern struct platform_device rk29xx_device_spi1m; extern struct rk29xx_spi_platform_data rk29xx_spi0_platdata; extern struct rk29xx_spi_platform_data rk29xx_spi1_platdata; +extern struct platform_device rk29_device_fb; +extern struct platform_device rk29_device_nand; +extern struct rk29_sdmmc_platform_data default_sdmmc0_data; +extern struct rk29_sdmmc_platform_data default_sdmmc1_data; +extern struct platform_device rk29_device_sdmmc0; +extern struct platform_device rk29_device_sdmmc1; -#endif \ No newline at end of file +#endif diff --git a/arch/arm/mach-rk29/gpio.c b/arch/arm/mach-rk29/gpio.c index a5acb1b99d90..c1842835fedf 100755 --- a/arch/arm/mach-rk29/gpio.c +++ b/arch/arm/mach-rk29/gpio.c @@ -606,7 +606,8 @@ void __init rk29_gpio_irq_setup(void) irq = IRQ_GPIO6; break; } - set_irq_chip_data(irq+14, this); + + set_irq_chip_data(NR_AIC_IRQS+this->bank->id,this); set_irq_chained_handler(irq, gpio_irq_handler); this += 1; pin += 32; @@ -630,4 +631,4 @@ void __init rk29_gpio_init(struct rk29_gpio_bank *data, int nr_banks) gpiochip_add(&rk29_gpio->chip); } printk("rk29_gpio_init:nr_banks=%d\n",nr_banks); -} \ No newline at end of file +} diff --git a/arch/arm/mach-rk29/include/mach/board.h b/arch/arm/mach-rk29/include/mach/board.h index 682786c51458..52b7c1bb1d50 100755 --- a/arch/arm/mach-rk29/include/mach/board.h +++ b/arch/arm/mach-rk29/include/mach/board.h @@ -34,6 +34,50 @@ struct rk29xx_spi_platform_data { u16 num_chipselect; }; +#define INVALID_GPIO -1 + +struct rk29lcd_info{ + u32 lcd_id; + u32 txd_pin; + u32 clk_pin; + u32 cs_pin; + int (*io_init)(void); + int (*io_deinit)(void); +}; + +struct rk29_fb_setting_info{ + u8 data_num; + u8 vsync_en; + u8 den_en; + u8 mcu_fmk_en; + u8 disp_on_en; + u8 standby_en; +}; + +struct rk29fb_info{ + u32 fb_id; + u32 disp_on_pin; + u8 disp_on_value; + u32 standby_pin; + u8 standby_value; + u32 mcu_fmk_pin; + struct rk29lcd_info *lcd_info; + int (*io_init)(struct rk29_fb_setting_info *fb_setting); + int (*io_deinit)(void); +}; + +struct rk29_sdmmc_platform_data { + unsigned int num_slots; + unsigned int host_caps; + unsigned int host_ocr_avail; + unsigned int use_dma:1; + char dma_name[8]; + int (*io_init)(void); + int (*io_deinit)(void); + int (*status)(struct device *); + int (*register_status_notify)(void (*callback)(int card_present, void *dev_id), void *dev_id); +}; + void __init rk29_map_common_io(void); void __init rk29_clock_init(void); diff --git a/arch/arm/mach-rk29/include/mach/gpio.h b/arch/arm/mach-rk29/include/mach/gpio.h index 155aad3e0404..7953ceb039ce 100755 --- a/arch/arm/mach-rk29/include/mach/gpio.h +++ b/arch/arm/mach-rk29/include/mach/gpio.h @@ -14,7 +14,8 @@ */ #ifndef __ARCH_ARM_MACH_RK29_GPIO_H #define __ARCH_ARM_MACH_RK29_GPIO_H - +#include + typedef enum eGPIOPinLevel { GPIO_LOW=0, @@ -67,236 +68,236 @@ typedef enum GPIOIntType { #define PIN_BASE 0 #define MAX_BANK 7 -#define RK29_PIN0_PA0 (0*NUM_GROUP + PIN_BASE + 0); -#define RK29_PIN0_PA1 (0*NUM_GROUP + PIN_BASE + 1); +#define RK29_PIN0_PA0 (0*NUM_GROUP + PIN_BASE + 0) +#define RK29_PIN0_PA1 (0*NUM_GROUP + PIN_BASE + 1) #define RK29_PIN0_PA2 (0*NUM_GROUP + PIN_BASE + 2) #define RK29_PIN0_PA3 (0*NUM_GROUP + PIN_BASE + 3) -#define RK29_PIN0_PA4 (0*NUM_GROUP + PIN_BASE + 4); -#define RK29_PIN0_PA5 (0*NUM_GROUP + PIN_BASE + 5); -#define RK29_PIN0_PA6 (0*NUM_GROUP + PIN_BASE + 6); -#define RK29_PIN0_PA7 (0*NUM_GROUP + PIN_BASE + 7); -#define RK29_PIN0_PB0 (0*NUM_GROUP + PIN_BASE + 8); -#define RK29_PIN0_PB1 (0*NUM_GROUP + PIN_BASE + 9); -#define RK29_PIN0_PB2 (0*NUM_GROUP + PIN_BASE + 10); -#define RK29_PIN0_PB3 (0*NUM_GROUP + PIN_BASE + 11); -#define RK29_PIN0_PB4 (0*NUM_GROUP + PIN_BASE + 12); -#define RK29_PIN0_PB5 (0*NUM_GROUP + PIN_BASE + 13); -#define RK29_PIN0_PB6 (0*NUM_GROUP + PIN_BASE + 14); -#define RK29_PIN0_PB7 (0*NUM_GROUP + PIN_BASE + 15); -#define RK29_PIN0_PC0 (0*NUM_GROUP + PIN_BASE + 16); -#define RK29_PIN0_PC1 (0*NUM_GROUP + PIN_BASE + 17); -#define RK29_PIN0_PC2 (0*NUM_GROUP + PIN_BASE + 18); -#define RK29_PIN0_PC3 (0*NUM_GROUP + PIN_BASE + 19); -#define RK29_PIN0_PC4 (0*NUM_GROUP + PIN_BASE + 20); -#define RK29_PIN0_PC5 (0*NUM_GROUP + PIN_BASE + 21); -#define RK29_PIN0_PC6 (0*NUM_GROUP + PIN_BASE + 22); -#define RK29_PIN0_PC7 (0*NUM_GROUP + PIN_BASE + 23); -#define RK29_PIN0_PD0 (0*NUM_GROUP + PIN_BASE + 24); -#define RK29_PIN0_PD1 (0*NUM_GROUP + PIN_BASE + 25); -#define RK29_PIN0_PD2 (0*NUM_GROUP + PIN_BASE + 26); -#define RK29_PIN0_PD3 (0*NUM_GROUP + PIN_BASE + 27); -#define RK29_PIN0_PD4 (0*NUM_GROUP + PIN_BASE + 28); -#define RK29_PIN0_PD5 (0*NUM_GROUP + PIN_BASE + 29); -#define RK29_PIN0_PD6 (0*NUM_GROUP + PIN_BASE + 30); -#define RK29_PIN0_PD7 (0*NUM_GROUP + PIN_BASE + 31); +#define RK29_PIN0_PA4 (0*NUM_GROUP + PIN_BASE + 4) +#define RK29_PIN0_PA5 (0*NUM_GROUP + PIN_BASE + 5) +#define RK29_PIN0_PA6 (0*NUM_GROUP + PIN_BASE + 6) +#define RK29_PIN0_PA7 (0*NUM_GROUP + PIN_BASE + 7) +#define RK29_PIN0_PB0 (0*NUM_GROUP + PIN_BASE + 8) +#define RK29_PIN0_PB1 (0*NUM_GROUP + PIN_BASE + 9) +#define RK29_PIN0_PB2 (0*NUM_GROUP + PIN_BASE + 10) +#define RK29_PIN0_PB3 (0*NUM_GROUP + PIN_BASE + 11) +#define RK29_PIN0_PB4 (0*NUM_GROUP + PIN_BASE + 12) +#define RK29_PIN0_PB5 (0*NUM_GROUP + PIN_BASE + 13) +#define RK29_PIN0_PB6 (0*NUM_GROUP + PIN_BASE + 14) +#define RK29_PIN0_PB7 (0*NUM_GROUP + PIN_BASE + 15) +#define RK29_PIN0_PC0 (0*NUM_GROUP + PIN_BASE + 16) +#define RK29_PIN0_PC1 (0*NUM_GROUP + PIN_BASE + 17) +#define RK29_PIN0_PC2 (0*NUM_GROUP + PIN_BASE + 18) +#define RK29_PIN0_PC3 (0*NUM_GROUP + PIN_BASE + 19) +#define RK29_PIN0_PC4 (0*NUM_GROUP + PIN_BASE + 20) +#define RK29_PIN0_PC5 (0*NUM_GROUP + PIN_BASE + 21) +#define RK29_PIN0_PC6 (0*NUM_GROUP + PIN_BASE + 22) +#define RK29_PIN0_PC7 (0*NUM_GROUP + PIN_BASE + 23) +#define RK29_PIN0_PD0 (0*NUM_GROUP + PIN_BASE + 24) +#define RK29_PIN0_PD1 (0*NUM_GROUP + PIN_BASE + 25) +#define RK29_PIN0_PD2 (0*NUM_GROUP + PIN_BASE + 26) +#define RK29_PIN0_PD3 (0*NUM_GROUP + PIN_BASE + 27) +#define RK29_PIN0_PD4 (0*NUM_GROUP + PIN_BASE + 28) +#define RK29_PIN0_PD5 (0*NUM_GROUP + PIN_BASE + 29) +#define RK29_PIN0_PD6 (0*NUM_GROUP + PIN_BASE + 30) +#define RK29_PIN0_PD7 (0*NUM_GROUP + PIN_BASE + 31) -#define RK29_PIN1_PA0 (1*NUM_GROUP + PIN_BASE + 0); -#define RK29_PIN1_PA1 (1*NUM_GROUP + PIN_BASE + 1) -#define RK29_PIN1_PA2 (1*NUM_GROUP + PIN_BASE + 2); +#define RK29_PIN1_PA0 (1*NUM_GROUP + PIN_BASE + 0) +#define RK29_PIN1_PA1 (1*NUM_GROUP + PIN_BASE + 1) +#define RK29_PIN1_PA2 (1*NUM_GROUP + PIN_BASE + 2) #define RK29_PIN1_PA3 (1*NUM_GROUP + PIN_BASE + 3) #define RK29_PIN1_PA4 (1*NUM_GROUP + PIN_BASE + 4) -#define RK29_PIN1_PA5 (1*NUM_GROUP + PIN_BASE + 5); -#define RK29_PIN1_PA6 (1*NUM_GROUP + PIN_BASE + 6); -#define RK29_PIN1_PA7 (1*NUM_GROUP + PIN_BASE + 7); -#define RK29_PIN1_PB0 (1*NUM_GROUP + PIN_BASE + 8); -#define RK29_PIN1_PB1 (1*NUM_GROUP + PIN_BASE + 9); -#define RK29_PIN1_PB2 (1*NUM_GROUP + PIN_BASE + 10); -#define RK29_PIN1_PB3 (1*NUM_GROUP + PIN_BASE + 11); -#define RK29_PIN1_PB4 (1*NUM_GROUP + PIN_BASE + 12); -#define RK29_PIN1_PB5 (1*NUM_GROUP + PIN_BASE + 13); -#define RK29_PIN1_PB6 (1*NUM_GROUP + PIN_BASE + 14); -#define RK29_PIN1_PB7 (1*NUM_GROUP + PIN_BASE + 15); -#define RK29_PIN1_PC0 (1*NUM_GROUP + PIN_BASE + 16); -#define RK29_PIN1_PC1 (1*NUM_GROUP + PIN_BASE + 17); -#define RK29_PIN1_PC2 (1*NUM_GROUP + PIN_BASE + 18); -#define RK29_PIN1_PC3 (1*NUM_GROUP + PIN_BASE + 19); -#define RK29_PIN1_PC4 (1*NUM_GROUP + PIN_BASE + 20); -#define RK29_PIN1_PC5 (1*NUM_GROUP + PIN_BASE + 21); -#define RK29_PIN1_PC6 (1*NUM_GROUP + PIN_BASE + 22); -#define RK29_PIN1_PC7 (1*NUM_GROUP + PIN_BASE + 23); -#define RK29_PIN1_PD0 (1*NUM_GROUP + PIN_BASE + 24); -#define RK29_PIN1_PD1 (1*NUM_GROUP + PIN_BASE + 25); -#define RK29_PIN1_PD2 (1*NUM_GROUP + PIN_BASE + 26); -#define RK29_PIN1_PD3 (1*NUM_GROUP + PIN_BASE + 27); -#define RK29_PIN1_PD4 (1*NUM_GROUP + PIN_BASE + 28); -#define RK29_PIN1_PD5 (1*NUM_GROUP + PIN_BASE + 29); -#define RK29_PIN1_PD6 (1*NUM_GROUP + PIN_BASE + 30); -#define RK29_PIN1_PD7 (1*NUM_GROUP + PIN_BASE + 31); +#define RK29_PIN1_PA5 (1*NUM_GROUP + PIN_BASE + 5) +#define RK29_PIN1_PA6 (1*NUM_GROUP + PIN_BASE + 6) +#define RK29_PIN1_PA7 (1*NUM_GROUP + PIN_BASE + 7) +#define RK29_PIN1_PB0 (1*NUM_GROUP + PIN_BASE + 8) +#define RK29_PIN1_PB1 (1*NUM_GROUP + PIN_BASE + 9) +#define RK29_PIN1_PB2 (1*NUM_GROUP + PIN_BASE + 10) +#define RK29_PIN1_PB3 (1*NUM_GROUP + PIN_BASE + 11) +#define RK29_PIN1_PB4 (1*NUM_GROUP + PIN_BASE + 12) +#define RK29_PIN1_PB5 (1*NUM_GROUP + PIN_BASE + 13) +#define RK29_PIN1_PB6 (1*NUM_GROUP + PIN_BASE + 14) +#define RK29_PIN1_PB7 (1*NUM_GROUP + PIN_BASE + 15) +#define RK29_PIN1_PC0 (1*NUM_GROUP + PIN_BASE + 16) +#define RK29_PIN1_PC1 (1*NUM_GROUP + PIN_BASE + 17) +#define RK29_PIN1_PC2 (1*NUM_GROUP + PIN_BASE + 18) +#define RK29_PIN1_PC3 (1*NUM_GROUP + PIN_BASE + 19) +#define RK29_PIN1_PC4 (1*NUM_GROUP + PIN_BASE + 20) +#define RK29_PIN1_PC5 (1*NUM_GROUP + PIN_BASE + 21) +#define RK29_PIN1_PC6 (1*NUM_GROUP + PIN_BASE + 22) +#define RK29_PIN1_PC7 (1*NUM_GROUP + PIN_BASE + 23) +#define RK29_PIN1_PD0 (1*NUM_GROUP + PIN_BASE + 24) +#define RK29_PIN1_PD1 (1*NUM_GROUP + PIN_BASE + 25) +#define RK29_PIN1_PD2 (1*NUM_GROUP + PIN_BASE + 26) +#define RK29_PIN1_PD3 (1*NUM_GROUP + PIN_BASE + 27) +#define RK29_PIN1_PD4 (1*NUM_GROUP + PIN_BASE + 28) +#define RK29_PIN1_PD5 (1*NUM_GROUP + PIN_BASE + 29) +#define RK29_PIN1_PD6 (1*NUM_GROUP + PIN_BASE + 30) +#define RK29_PIN1_PD7 (1*NUM_GROUP + PIN_BASE + 31) -#define RK29_PIN2_PA0 (2*NUM_GROUP + PIN_BASE + 0); -#define RK29_PIN2_PA1 (2*NUM_GROUP + PIN_BASE + 1); -#define RK29_PIN2_PA2 (2*NUM_GROUP + PIN_BASE + 2); -#define RK29_PIN2_PA3 (2*NUM_GROUP + PIN_BASE + 3); -#define RK29_PIN2_PA4 (2*NUM_GROUP + PIN_BASE + 4); -#define RK29_PIN2_PA5 (2*NUM_GROUP + PIN_BASE + 5); -#define RK29_PIN2_PA6 (2*NUM_GROUP + PIN_BASE + 6); -#define RK29_PIN2_PA7 (2*NUM_GROUP + PIN_BASE + 7); -#define RK29_PIN2_PB0 (2*NUM_GROUP + PIN_BASE + 8); -#define RK29_PIN2_PB1 (2*NUM_GROUP + PIN_BASE + 9); -#define RK29_PIN2_PB2 (2*NUM_GROUP + PIN_BASE + 10); -#define RK29_PIN2_PB3 (2*NUM_GROUP + PIN_BASE + 11); -#define RK29_PIN2_PB4 (2*NUM_GROUP + PIN_BASE + 12); -#define RK29_PIN2_PB5 (2*NUM_GROUP + PIN_BASE + 13); -#define RK29_PIN2_PB6 (2*NUM_GROUP + PIN_BASE + 14); -#define RK29_PIN2_PB7 (2*NUM_GROUP + PIN_BASE + 15); -#define RK29_PIN2_PC0 (2*NUM_GROUP + PIN_BASE + 16); +#define RK29_PIN2_PA0 (2*NUM_GROUP + PIN_BASE + 0) +#define RK29_PIN2_PA1 (2*NUM_GROUP + PIN_BASE + 1) +#define RK29_PIN2_PA2 (2*NUM_GROUP + PIN_BASE + 2) +#define RK29_PIN2_PA3 (2*NUM_GROUP + PIN_BASE + 3) +#define RK29_PIN2_PA4 (2*NUM_GROUP + PIN_BASE + 4) +#define RK29_PIN2_PA5 (2*NUM_GROUP + PIN_BASE + 5) +#define RK29_PIN2_PA6 (2*NUM_GROUP + PIN_BASE + 6) +#define RK29_PIN2_PA7 (2*NUM_GROUP + PIN_BASE + 7) +#define RK29_PIN2_PB0 (2*NUM_GROUP + PIN_BASE + 8) +#define RK29_PIN2_PB1 (2*NUM_GROUP + PIN_BASE + 9) +#define RK29_PIN2_PB2 (2*NUM_GROUP + PIN_BASE + 10) +#define RK29_PIN2_PB3 (2*NUM_GROUP + PIN_BASE + 11) +#define RK29_PIN2_PB4 (2*NUM_GROUP + PIN_BASE + 12) +#define RK29_PIN2_PB5 (2*NUM_GROUP + PIN_BASE + 13) +#define RK29_PIN2_PB6 (2*NUM_GROUP + PIN_BASE + 14) +#define RK29_PIN2_PB7 (2*NUM_GROUP + PIN_BASE + 15) +#define RK29_PIN2_PC0 (2*NUM_GROUP + PIN_BASE + 16) #define RK29_PIN2_PC1 (2*NUM_GROUP + PIN_BASE + 17) -#define RK29_PIN2_PC2 (2*NUM_GROUP + PIN_BASE + 18); -#define RK29_PIN2_PC3 (2*NUM_GROUP + PIN_BASE + 19); -#define RK29_PIN2_PC4 (2*NUM_GROUP + PIN_BASE + 20); +#define RK29_PIN2_PC2 (2*NUM_GROUP + PIN_BASE + 18) +#define RK29_PIN2_PC3 (2*NUM_GROUP + PIN_BASE + 19) +#define RK29_PIN2_PC4 (2*NUM_GROUP + PIN_BASE + 20) #define RK29_PIN2_PC5 (2*NUM_GROUP + PIN_BASE + 21) -#define RK29_PIN2_PC6 (2*NUM_GROUP + PIN_BASE + 22); -#define RK29_PIN2_PC7 (2*NUM_GROUP + PIN_BASE + 23); -#define RK29_PIN2_PD0 (2*NUM_GROUP + PIN_BASE + 24); -#define RK29_PIN2_PD1 (2*NUM_GROUP + PIN_BASE + 25); -#define RK29_PIN2_PD2 (2*NUM_GROUP + PIN_BASE + 26); -#define RK29_PIN2_PD3 (2*NUM_GROUP + PIN_BASE + 27); -#define RK29_PIN2_PD4 (2*NUM_GROUP + PIN_BASE + 28); -#define RK29_PIN2_PD5 (2*NUM_GROUP + PIN_BASE + 29); -#define RK29_PIN2_PD6 (2*NUM_GROUP + PIN_BASE + 30); -#define RK29_PIN2_PD7 (2*NUM_GROUP + PIN_BASE + 31); +#define RK29_PIN2_PC6 (2*NUM_GROUP + PIN_BASE + 22) +#define RK29_PIN2_PC7 (2*NUM_GROUP + PIN_BASE + 23) +#define RK29_PIN2_PD0 (2*NUM_GROUP + PIN_BASE + 24) +#define RK29_PIN2_PD1 (2*NUM_GROUP + PIN_BASE + 25) +#define RK29_PIN2_PD2 (2*NUM_GROUP + PIN_BASE + 26) +#define RK29_PIN2_PD3 (2*NUM_GROUP + PIN_BASE + 27) +#define RK29_PIN2_PD4 (2*NUM_GROUP + PIN_BASE + 28) +#define RK29_PIN2_PD5 (2*NUM_GROUP + PIN_BASE + 29) +#define RK29_PIN2_PD6 (2*NUM_GROUP + PIN_BASE + 30) +#define RK29_PIN2_PD7 (2*NUM_GROUP + PIN_BASE + 31) -#define RK29_PIN3_PA0 (3*NUM_GROUP + PIN_BASE + 0); -#define RK29_PIN3_PA1 (3*NUM_GROUP + PIN_BASE + 1); -#define RK29_PIN3_PA2 (3*NUM_GROUP + PIN_BASE + 2); -#define RK29_PIN3_PA3 (3*NUM_GROUP + PIN_BASE + 3); -#define RK29_PIN3_PA4 (3*NUM_GROUP + PIN_BASE + 4); -#define RK29_PIN3_PA5 (3*NUM_GROUP + PIN_BASE + 5); -#define RK29_PIN3_PA6 (3*NUM_GROUP + PIN_BASE + 6); -#define RK29_PIN3_PA7 (3*NUM_GROUP + PIN_BASE + 7); -#define RK29_PIN3_PB0 (3*NUM_GROUP + PIN_BASE + 8); -#define RK29_PIN3_PB1 (3*NUM_GROUP + PIN_BASE + 9); -#define RK29_PIN3_PB2 (3*NUM_GROUP + PIN_BASE + 10); -#define RK29_PIN3_PB3 (3*NUM_GROUP + PIN_BASE + 11); -#define RK29_PIN3_PB4 (3*NUM_GROUP + PIN_BASE + 12); -#define RK29_PIN3_PB5 (3*NUM_GROUP + PIN_BASE + 13); -#define RK29_PIN3_PB6 (3*NUM_GROUP + PIN_BASE + 14); -#define RK29_PIN3_PB7 (3*NUM_GROUP + PIN_BASE + 15); -#define RK29_PIN3_PC0 (3*NUM_GROUP + PIN_BASE + 16); -#define RK29_PIN3_PC1 (3*NUM_GROUP + PIN_BASE + 17); -#define RK29_PIN3_PC2 (3*NUM_GROUP + PIN_BASE + 18); -#define RK29_PIN3_PC3 (3*NUM_GROUP + PIN_BASE + 19); -#define RK29_PIN3_PC4 (3*NUM_GROUP + PIN_BASE + 20); -#define RK29_PIN3_PC5 (3*NUM_GROUP + PIN_BASE + 21); -#define RK29_PIN3_PC6 (3*NUM_GROUP + PIN_BASE + 22); -#define RK29_PIN3_PC7 (3*NUM_GROUP + PIN_BASE + 23); -#define RK29_PIN3_PD0 (3*NUM_GROUP + PIN_BASE + 24); -#define RK29_PIN3_PD1 (3*NUM_GROUP + PIN_BASE + 25); -#define RK29_PIN3_PD2 (3*NUM_GROUP + PIN_BASE + 26); -#define RK29_PIN3_PD3 (3*NUM_GROUP + PIN_BASE + 27); -#define RK29_PIN3_PD4 (3*NUM_GROUP + PIN_BASE + 28); -#define RK29_PIN3_PD5 (3*NUM_GROUP + PIN_BASE + 29); -#define RK29_PIN3_PD6 (3*NUM_GROUP + PIN_BASE + 30); -#define RK29_PIN3_PD7 (3*NUM_GROUP + PIN_BASE + 31); +#define RK29_PIN3_PA0 (3*NUM_GROUP + PIN_BASE + 0) +#define RK29_PIN3_PA1 (3*NUM_GROUP + PIN_BASE + 1) +#define RK29_PIN3_PA2 (3*NUM_GROUP + PIN_BASE + 2) +#define RK29_PIN3_PA3 (3*NUM_GROUP + PIN_BASE + 3) +#define RK29_PIN3_PA4 (3*NUM_GROUP + PIN_BASE + 4) +#define RK29_PIN3_PA5 (3*NUM_GROUP + PIN_BASE + 5) +#define RK29_PIN3_PA6 (3*NUM_GROUP + PIN_BASE + 6) +#define RK29_PIN3_PA7 (3*NUM_GROUP + PIN_BASE + 7) +#define RK29_PIN3_PB0 (3*NUM_GROUP + PIN_BASE + 8) +#define RK29_PIN3_PB1 (3*NUM_GROUP + PIN_BASE + 9) +#define RK29_PIN3_PB2 (3*NUM_GROUP + PIN_BASE + 10) +#define RK29_PIN3_PB3 (3*NUM_GROUP + PIN_BASE + 11) +#define RK29_PIN3_PB4 (3*NUM_GROUP + PIN_BASE + 12) +#define RK29_PIN3_PB5 (3*NUM_GROUP + PIN_BASE + 13) +#define RK29_PIN3_PB6 (3*NUM_GROUP + PIN_BASE + 14) +#define RK29_PIN3_PB7 (3*NUM_GROUP + PIN_BASE + 15) +#define RK29_PIN3_PC0 (3*NUM_GROUP + PIN_BASE + 16) +#define RK29_PIN3_PC1 (3*NUM_GROUP + PIN_BASE + 17) +#define RK29_PIN3_PC2 (3*NUM_GROUP + PIN_BASE + 18) +#define RK29_PIN3_PC3 (3*NUM_GROUP + PIN_BASE + 19) +#define RK29_PIN3_PC4 (3*NUM_GROUP + PIN_BASE + 20) +#define RK29_PIN3_PC5 (3*NUM_GROUP + PIN_BASE + 21) +#define RK29_PIN3_PC6 (3*NUM_GROUP + PIN_BASE + 22) +#define RK29_PIN3_PC7 (3*NUM_GROUP + PIN_BASE + 23) +#define RK29_PIN3_PD0 (3*NUM_GROUP + PIN_BASE + 24) +#define RK29_PIN3_PD1 (3*NUM_GROUP + PIN_BASE + 25) +#define RK29_PIN3_PD2 (3*NUM_GROUP + PIN_BASE + 26) +#define RK29_PIN3_PD3 (3*NUM_GROUP + PIN_BASE + 27) +#define RK29_PIN3_PD4 (3*NUM_GROUP + PIN_BASE + 28) +#define RK29_PIN3_PD5 (3*NUM_GROUP + PIN_BASE + 29) +#define RK29_PIN3_PD6 (3*NUM_GROUP + PIN_BASE + 30) +#define RK29_PIN3_PD7 (3*NUM_GROUP + PIN_BASE + 31) -#define RK29_PIN4_PA0 (4*NUM_GROUP + PIN_BASE + 0); -#define RK29_PIN4_PA1 (4*NUM_GROUP + PIN_BASE + 1); -#define RK29_PIN4_PA2 (4*NUM_GROUP + PIN_BASE + 2); -#define RK29_PIN4_PA3 (4*NUM_GROUP + PIN_BASE + 3); -#define RK29_PIN4_PA4 (4*NUM_GROUP + PIN_BASE + 4); -#define RK29_PIN4_PA5 (4*NUM_GROUP + PIN_BASE + 5); -#define RK29_PIN4_PA6 (4*NUM_GROUP + PIN_BASE + 6); -#define RK29_PIN4_PA7 (4*NUM_GROUP + PIN_BASE + 7); -#define RK29_PIN4_PB0 (4*NUM_GROUP + PIN_BASE + 8); -#define RK29_PIN4_PB1 (4*NUM_GROUP + PIN_BASE + 9); -#define RK29_PIN4_PB2 (4*NUM_GROUP + PIN_BASE + 10); -#define RK29_PIN4_PB3 (4*NUM_GROUP + PIN_BASE + 11); -#define RK29_PIN4_PB4 (4*NUM_GROUP + PIN_BASE + 12); -#define RK29_PIN4_PB5 (4*NUM_GROUP + PIN_BASE + 13); -#define RK29_PIN4_PB6 (4*NUM_GROUP + PIN_BASE + 14); -#define RK29_PIN4_PB7 (4*NUM_GROUP + PIN_BASE + 15); -#define RK29_PIN4_PC0 (4*NUM_GROUP + PIN_BASE + 16); -#define RK29_PIN4_PC1 (4*NUM_GROUP + PIN_BASE + 17); -#define RK29_PIN4_PC2 (4*NUM_GROUP + PIN_BASE + 18); -#define RK29_PIN4_PC3 (4*NUM_GROUP + PIN_BASE + 19); -#define RK29_PIN4_PC4 (4*NUM_GROUP + PIN_BASE + 20); -#define RK29_PIN4_PC5 (4*NUM_GROUP + PIN_BASE + 21); -#define RK29_PIN4_PC6 (4*NUM_GROUP + PIN_BASE + 22); -#define RK29_PIN4_PC7 (4*NUM_GROUP + PIN_BASE + 23); -#define RK29_PIN4_PD0 (4*NUM_GROUP + PIN_BASE + 24); -#define RK29_PIN4_PD1 (4*NUM_GROUP + PIN_BASE + 25); -#define RK29_PIN4_PD2 (4*NUM_GROUP + PIN_BASE + 26); -#define RK29_PIN4_PD3 (4*NUM_GROUP + PIN_BASE + 27); -#define RK29_PIN4_PD4 (4*NUM_GROUP + PIN_BASE + 28); -#define RK29_PIN4_PD5 (4*NUM_GROUP + PIN_BASE + 29); -#define RK29_PIN4_PD6 (4*NUM_GROUP + PIN_BASE + 30); -#define RK29_PIN4_PD7 (4*NUM_GROUP + PIN_BASE + 31); +#define RK29_PIN4_PA0 (4*NUM_GROUP + PIN_BASE + 0) +#define RK29_PIN4_PA1 (4*NUM_GROUP + PIN_BASE + 1) +#define RK29_PIN4_PA2 (4*NUM_GROUP + PIN_BASE + 2) +#define RK29_PIN4_PA3 (4*NUM_GROUP + PIN_BASE + 3) +#define RK29_PIN4_PA4 (4*NUM_GROUP + PIN_BASE + 4) +#define RK29_PIN4_PA5 (4*NUM_GROUP + PIN_BASE + 5) +#define RK29_PIN4_PA6 (4*NUM_GROUP + PIN_BASE + 6) +#define RK29_PIN4_PA7 (4*NUM_GROUP + PIN_BASE + 7) +#define RK29_PIN4_PB0 (4*NUM_GROUP + PIN_BASE + 8) +#define RK29_PIN4_PB1 (4*NUM_GROUP + PIN_BASE + 9) +#define RK29_PIN4_PB2 (4*NUM_GROUP + PIN_BASE + 10) +#define RK29_PIN4_PB3 (4*NUM_GROUP + PIN_BASE + 11) +#define RK29_PIN4_PB4 (4*NUM_GROUP + PIN_BASE + 12) +#define RK29_PIN4_PB5 (4*NUM_GROUP + PIN_BASE + 13) +#define RK29_PIN4_PB6 (4*NUM_GROUP + PIN_BASE + 14) +#define RK29_PIN4_PB7 (4*NUM_GROUP + PIN_BASE + 15) +#define RK29_PIN4_PC0 (4*NUM_GROUP + PIN_BASE + 16) +#define RK29_PIN4_PC1 (4*NUM_GROUP + PIN_BASE + 17) +#define RK29_PIN4_PC2 (4*NUM_GROUP + PIN_BASE + 18) +#define RK29_PIN4_PC3 (4*NUM_GROUP + PIN_BASE + 19) +#define RK29_PIN4_PC4 (4*NUM_GROUP + PIN_BASE + 20) +#define RK29_PIN4_PC5 (4*NUM_GROUP + PIN_BASE + 21) +#define RK29_PIN4_PC6 (4*NUM_GROUP + PIN_BASE + 22) +#define RK29_PIN4_PC7 (4*NUM_GROUP + PIN_BASE + 23) +#define RK29_PIN4_PD0 (4*NUM_GROUP + PIN_BASE + 24) +#define RK29_PIN4_PD1 (4*NUM_GROUP + PIN_BASE + 25) +#define RK29_PIN4_PD2 (4*NUM_GROUP + PIN_BASE + 26) +#define RK29_PIN4_PD3 (4*NUM_GROUP + PIN_BASE + 27) +#define RK29_PIN4_PD4 (4*NUM_GROUP + PIN_BASE + 28) +#define RK29_PIN4_PD5 (4*NUM_GROUP + PIN_BASE + 29) +#define RK29_PIN4_PD6 (4*NUM_GROUP + PIN_BASE + 30) +#define RK29_PIN4_PD7 (4*NUM_GROUP + PIN_BASE + 31) -#define RK29_PIN5_PA0 (5*NUM_GROUP + PIN_BASE + 0); -#define RK29_PIN5_PA1 (5*NUM_GROUP + PIN_BASE + 1); -#define RK29_PIN5_PA2 (5*NUM_GROUP + PIN_BASE + 2); -#define RK29_PIN5_PA3 (5*NUM_GROUP + PIN_BASE + 3); -#define RK29_PIN5_PA4 (5*NUM_GROUP + PIN_BASE + 4); -#define RK29_PIN5_PA5 (5*NUM_GROUP + PIN_BASE + 5); -#define RK29_PIN5_PA6 (5*NUM_GROUP + PIN_BASE + 6); -#define RK29_PIN5_PA7 (5*NUM_GROUP + PIN_BASE + 7); -#define RK29_PIN5_PB0 (5*NUM_GROUP + PIN_BASE + 8); -#define RK29_PIN5_PB1 (5*NUM_GROUP + PIN_BASE + 9); -#define RK29_PIN5_PB2 (5*NUM_GROUP + PIN_BASE + 10); -#define RK29_PIN5_PB3 (5*NUM_GROUP + PIN_BASE + 11); -#define RK29_PIN5_PB4 (5*NUM_GROUP + PIN_BASE + 12); -#define RK29_PIN5_PB5 (5*NUM_GROUP + PIN_BASE + 13); -#define RK29_PIN5_PB6 (5*NUM_GROUP + PIN_BASE + 14); -#define RK29_PIN5_PB7 (5*NUM_GROUP + PIN_BASE + 15); -#define RK29_PIN5_PC0 (5*NUM_GROUP + PIN_BASE + 16); -#define RK29_PIN5_PC1 (5*NUM_GROUP + PIN_BASE + 17); -#define RK29_PIN5_PC2 (5*NUM_GROUP + PIN_BASE + 18); -#define RK29_PIN5_PC3 (5*NUM_GROUP + PIN_BASE + 19); -#define RK29_PIN5_PC4 (5*NUM_GROUP + PIN_BASE + 20); -#define RK29_PIN5_PC5 (5*NUM_GROUP + PIN_BASE + 21); -#define RK29_PIN5_PC6 (5*NUM_GROUP + PIN_BASE + 22); -#define RK29_PIN5_PC7 (5*NUM_GROUP + PIN_BASE + 23); -#define RK29_PIN5_PD0 (5*NUM_GROUP + PIN_BASE + 24); -#define RK29_PIN5_PD1 (5*NUM_GROUP + PIN_BASE + 25); -#define RK29_PIN5_PD2 (5*NUM_GROUP + PIN_BASE + 26); -#define RK29_PIN5_PD3 (5*NUM_GROUP + PIN_BASE + 27); -#define RK29_PIN5_PD4 (5*NUM_GROUP + PIN_BASE + 28); -#define RK29_PIN5_PD5 (5*NUM_GROUP + PIN_BASE + 29); -#define RK29_PIN5_PD6 (5*NUM_GROUP + PIN_BASE + 30); -#define RK29_PIN5_PD7 (5*NUM_GROUP + PIN_BASE + 31); +#define RK29_PIN5_PA0 (5*NUM_GROUP + PIN_BASE + 0) +#define RK29_PIN5_PA1 (5*NUM_GROUP + PIN_BASE + 1) +#define RK29_PIN5_PA2 (5*NUM_GROUP + PIN_BASE + 2) +#define RK29_PIN5_PA3 (5*NUM_GROUP + PIN_BASE + 3) +#define RK29_PIN5_PA4 (5*NUM_GROUP + PIN_BASE + 4) +#define RK29_PIN5_PA5 (5*NUM_GROUP + PIN_BASE + 5) +#define RK29_PIN5_PA6 (5*NUM_GROUP + PIN_BASE + 6) +#define RK29_PIN5_PA7 (5*NUM_GROUP + PIN_BASE + 7) +#define RK29_PIN5_PB0 (5*NUM_GROUP + PIN_BASE + 8) +#define RK29_PIN5_PB1 (5*NUM_GROUP + PIN_BASE + 9) +#define RK29_PIN5_PB2 (5*NUM_GROUP + PIN_BASE + 10) +#define RK29_PIN5_PB3 (5*NUM_GROUP + PIN_BASE + 11) +#define RK29_PIN5_PB4 (5*NUM_GROUP + PIN_BASE + 12) +#define RK29_PIN5_PB5 (5*NUM_GROUP + PIN_BASE + 13) +#define RK29_PIN5_PB6 (5*NUM_GROUP + PIN_BASE + 14) +#define RK29_PIN5_PB7 (5*NUM_GROUP + PIN_BASE + 15) +#define RK29_PIN5_PC0 (5*NUM_GROUP + PIN_BASE + 16) +#define RK29_PIN5_PC1 (5*NUM_GROUP + PIN_BASE + 17) +#define RK29_PIN5_PC2 (5*NUM_GROUP + PIN_BASE + 18) +#define RK29_PIN5_PC3 (5*NUM_GROUP + PIN_BASE + 19) +#define RK29_PIN5_PC4 (5*NUM_GROUP + PIN_BASE + 20) +#define RK29_PIN5_PC5 (5*NUM_GROUP + PIN_BASE + 21) +#define RK29_PIN5_PC6 (5*NUM_GROUP + PIN_BASE + 22) +#define RK29_PIN5_PC7 (5*NUM_GROUP + PIN_BASE + 23) +#define RK29_PIN5_PD0 (5*NUM_GROUP + PIN_BASE + 24) +#define RK29_PIN5_PD1 (5*NUM_GROUP + PIN_BASE + 25) +#define RK29_PIN5_PD2 (5*NUM_GROUP + PIN_BASE + 26) +#define RK29_PIN5_PD3 (5*NUM_GROUP + PIN_BASE + 27) +#define RK29_PIN5_PD4 (5*NUM_GROUP + PIN_BASE + 28) +#define RK29_PIN5_PD5 (5*NUM_GROUP + PIN_BASE + 29) +#define RK29_PIN5_PD6 (5*NUM_GROUP + PIN_BASE + 30) +#define RK29_PIN5_PD7 (5*NUM_GROUP + PIN_BASE + 31) -#define RK29_PIN6_PA0 (6*NUM_GROUP + PIN_BASE + 0); -#define RK29_PIN6_PA1 (6*NUM_GROUP + PIN_BASE + 1); -#define RK29_PIN6_PA2 (6*NUM_GROUP + PIN_BASE + 2); -#define RK29_PIN6_PA3 (6*NUM_GROUP + PIN_BASE + 3); -#define RK29_PIN6_PA4 (6*NUM_GROUP + PIN_BASE + 4); -#define RK29_PIN6_PA5 (6*NUM_GROUP + PIN_BASE + 5); -#define RK29_PIN6_PA6 (6*NUM_GROUP + PIN_BASE + 6); -#define RK29_PIN6_PA7 (6*NUM_GROUP + PIN_BASE + 7); -#define RK29_PIN6_PB0 (6*NUM_GROUP + PIN_BASE + 8); -#define RK29_PIN6_PB1 (6*NUM_GROUP + PIN_BASE + 9); -#define RK29_PIN6_PB2 (6*NUM_GROUP + PIN_BASE + 10); -#define RK29_PIN6_PB3 (6*NUM_GROUP + PIN_BASE + 11); -#define RK29_PIN6_PB4 (6*NUM_GROUP + PIN_BASE + 12); -#define RK29_PIN6_PB5 (6*NUM_GROUP + PIN_BASE + 13); -#define RK29_PIN6_PB6 (6*NUM_GROUP + PIN_BASE + 14); -#define RK29_PIN6_PB7 (6*NUM_GROUP + PIN_BASE + 15); -#define RK29_PIN6_PC0 (6*NUM_GROUP + PIN_BASE + 16); -#define RK29_PIN6_PC1 (6*NUM_GROUP + PIN_BASE + 17); -#define RK29_PIN6_PC2 (6*NUM_GROUP + PIN_BASE + 18); -#define RK29_PIN6_PC3 (6*NUM_GROUP + PIN_BASE + 19); -#define RK29_PIN6_PC4 (6*NUM_GROUP + PIN_BASE + 20); -#define RK29_PIN6_PC5 (6*NUM_GROUP + PIN_BASE + 21); -#define RK29_PIN6_PC6 (6*NUM_GROUP + PIN_BASE + 22); -#define RK29_PIN6_PC7 (6*NUM_GROUP + PIN_BASE + 23); -#define RK29_PIN6_PD0 (6*NUM_GROUP + PIN_BASE + 24); -#define RK29_PIN6_PD1 (6*NUM_GROUP + PIN_BASE + 25); -#define RK29_PIN6_PD2 (6*NUM_GROUP + PIN_BASE + 26); -#define RK29_PIN6_PD3 (6*NUM_GROUP + PIN_BASE + 27); -#define RK29_PIN6_PD4 (6*NUM_GROUP + PIN_BASE + 28); -#define RK29_PIN6_PD5 (6*NUM_GROUP + PIN_BASE + 29); -#define RK29_PIN6_PD6 (6*NUM_GROUP + PIN_BASE + 30); -#define RK29_PIN6_PD7 (6*NUM_GROUP + PIN_BASE + 31); +#define RK29_PIN6_PA0 (6*NUM_GROUP + PIN_BASE + 0) +#define RK29_PIN6_PA1 (6*NUM_GROUP + PIN_BASE + 1) +#define RK29_PIN6_PA2 (6*NUM_GROUP + PIN_BASE + 2) +#define RK29_PIN6_PA3 (6*NUM_GROUP + PIN_BASE + 3) +#define RK29_PIN6_PA4 (6*NUM_GROUP + PIN_BASE + 4) +#define RK29_PIN6_PA5 (6*NUM_GROUP + PIN_BASE + 5) +#define RK29_PIN6_PA6 (6*NUM_GROUP + PIN_BASE + 6) +#define RK29_PIN6_PA7 (6*NUM_GROUP + PIN_BASE + 7) +#define RK29_PIN6_PB0 (6*NUM_GROUP + PIN_BASE + 8) +#define RK29_PIN6_PB1 (6*NUM_GROUP + PIN_BASE + 9) +#define RK29_PIN6_PB2 (6*NUM_GROUP + PIN_BASE + 10) +#define RK29_PIN6_PB3 (6*NUM_GROUP + PIN_BASE + 11) +#define RK29_PIN6_PB4 (6*NUM_GROUP + PIN_BASE + 12) +#define RK29_PIN6_PB5 (6*NUM_GROUP + PIN_BASE + 13) +#define RK29_PIN6_PB6 (6*NUM_GROUP + PIN_BASE + 14) +#define RK29_PIN6_PB7 (6*NUM_GROUP + PIN_BASE + 15) +#define RK29_PIN6_PC0 (6*NUM_GROUP + PIN_BASE + 16) +#define RK29_PIN6_PC1 (6*NUM_GROUP + PIN_BASE + 17) +#define RK29_PIN6_PC2 (6*NUM_GROUP + PIN_BASE + 18) +#define RK29_PIN6_PC3 (6*NUM_GROUP + PIN_BASE + 19) +#define RK29_PIN6_PC4 (6*NUM_GROUP + PIN_BASE + 20) +#define RK29_PIN6_PC5 (6*NUM_GROUP + PIN_BASE + 21) +#define RK29_PIN6_PC6 (6*NUM_GROUP + PIN_BASE + 22) +#define RK29_PIN6_PC7 (6*NUM_GROUP + PIN_BASE + 23) +#define RK29_PIN6_PD0 (6*NUM_GROUP + PIN_BASE + 24) +#define RK29_PIN6_PD1 (6*NUM_GROUP + PIN_BASE + 25) +#define RK29_PIN6_PD2 (6*NUM_GROUP + PIN_BASE + 26) +#define RK29_PIN6_PD3 (6*NUM_GROUP + PIN_BASE + 27) +#define RK29_PIN6_PD4 (6*NUM_GROUP + PIN_BASE + 28) +#define RK29_PIN6_PD5 (6*NUM_GROUP + PIN_BASE + 29) +#define RK29_PIN6_PD6 (6*NUM_GROUP + PIN_BASE + 30) +#define RK29_PIN6_PD7 (6*NUM_GROUP + PIN_BASE + 31) #define ARCH_NR_GPIOS (NUM_GROUP*MAX_BANK) @@ -325,12 +326,12 @@ extern void __init rk29_gpio_irq_setup(void); static inline int gpio_to_irq(unsigned gpio) { - return gpio + NR_AIC_IRQS; + return (gpio + NR_AIC_IRQS); } static inline int irq_to_gpio(unsigned irq) { - return irq - NR_AIC_IRQS; + return (irq - NR_AIC_IRQS); } #endif /* __ASSEMBLY__ */ diff --git a/arch/arm/mach-rk29/include/mach/rk29_nand.h b/arch/arm/mach-rk29/include/mach/rk29_nand.h new file mode 100644 index 000000000000..0d1b116ec20b --- /dev/null +++ b/arch/arm/mach-rk29/include/mach/rk29_nand.h @@ -0,0 +1,128 @@ + +/* + * arch/arm/mach-rk29/include/mach/rk29_nand.h + * + * Copyright (C) 2010 RockChip, Inc. + * Author: + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#ifndef __ASM_ARCH_RK29_NAND_H +#define __ASM_ARCH_RK29_NAND_H + + +//BCHCTL寄存器 +#define BCH_WR 0x0002 +#define BCH_RST 0x0001 +//FLCTL寄存器 +#define FL_RDY (0x1<<20) +#define FL_LBA_EN (0x1<<11) +#define FL_COR_EN (0x1<<10) +#define FL_INT_EN (0x1<<9) +#define FL_INTCLR (0x1<<8) +#define FL_STMOD (0x1<<7) +#define FL_TRCNT (0x3<<5) +#define FL_STADDR (0x1<<4) +#define FL_BYPASS (0x1<<3) +#define FL_START (0x1<<2) +#define FL_RDN (0x1<<1) +#define FL_RST (0x1<<0) +//FMCTL寄存器 +#define FMC_WP (0x1<<8) +#define FMC_FRDY (0x1<<9) +#define FMC_FRDY_INT_EN (0x1<<10) +#define FMC_FRDY_INT_CLR (0x1<<11) +//FMWAIT寄存器 +#define FMW_RWCS_OFFSET 0 +#define FMW_RWPW_OFFSET 5 +#define FMW_RDY (0x1<<11) +#define FMW_CSRW_OFFSET 12 +#define FMW_DLY_OFFSET 24//16 + +struct rk29_nand_timing { + unsigned int tCH; /* Enable signal hold time */ + unsigned int tCS; /* Enable signal setup time */ + unsigned int tWH; /* ND_nWE high duration */ + unsigned int tWP; /* ND_nWE pulse time */ + unsigned int tRH; /* ND_nRE high duration */ + unsigned int tRP; /* ND_nRE pulse width */ + unsigned int tR; /* ND_nWE high to ND_nRE low for read */ + unsigned int tWHR; /* ND_nWE high to ND_nRE low for status read */ + unsigned int tAR; /* ND_ALE low to ND_nRE low delay */ +}; + +struct rk29_nand_cmdset { + uint16_t read1; + uint16_t read2; + uint16_t program; + uint16_t read_status; + uint16_t read_id; + uint16_t erase; + uint16_t reset; + uint16_t lock; + uint16_t unlock; + uint16_t lock_status; +}; + +typedef volatile struct tagCHIP_IF +{ + uint32_t data; + uint32_t addr; + uint32_t cmd; + uint32_t RESERVED[0x3d]; +}CHIP_IF, *pCHIP_IF; + +//NANDC Registers +typedef volatile struct tagNANDC +{ + volatile uint32_t FMCTL; + volatile uint32_t FMWAIT; + volatile uint32_t FLCTL; + volatile uint32_t BCHCTL; + volatile uint32_t BCHST; + volatile uint32_t RESERVED1[(0x200-0x14)/4]; //FLR + volatile uint32_t spare[0x200/4]; + volatile uint32_t FMCTL1; + volatile uint32_t FMWAIT1; + volatile uint32_t FLCTL1; + volatile uint32_t BCHCTL1; + volatile uint32_t BCHST1; + volatile uint32_t RESERVED2[(0x200-0x14)/4]; + volatile uint32_t RESERVED3[0x200/4]; + volatile CHIP_IF chip[8]; + volatile uint32_t buf[0x800/4]; +}NANDC, *pNANDC; + +struct rk29_nand_flash { + const struct rk29_nand_timing *timing; /* NAND Flash timing */ + const struct rk29_nand_cmdset *cmdset; + + uint32_t page_per_block; /* Pages per block (PG_PER_BLK) */ + uint32_t page_size; /* Page size in bytes (PAGE_SZ) */ + uint32_t flash_width; /* Width of Flash memory (DWIDTH_M) */ + uint32_t num_blocks; /* Number of physical blocks in Flash */ + uint32_t chip_id; +}; + +struct rk29_nand_platform_data { + + int width; /* data bus width in bytes */ + int hw_ecc; /* 1:hw ecc, 0: soft ecc */ + struct mtd_partition *parts; + unsigned int nr_parts; + size_t num_flash; + int (*io_init)(void); + int (*io_deinit)(void); +}; + + +#endif /* __ASM_ARCH_RK29_NAND_H */ + diff --git a/arch/arm/mach-rk29/include/mach/vpu.h b/arch/arm/mach-rk29/include/mach/vpu.h new file mode 100644 index 000000000000..7c0317bc7881 --- /dev/null +++ b/arch/arm/mach-rk29/include/mach/vpu.h @@ -0,0 +1,42 @@ +/* arch/arm/mach-rk29/include/mach/vcodec.h + * + * Copyright (C) 2010 ROCKCHIP, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __ARCH_ARM_MACH_RK29_VPU_H +#define __ARCH_ARM_MACH_RK29_VPU_H + +#include /* needed for the _IOW etc stuff used later */ + +/* + * Ioctl definitions + */ + +/* Use 'k' as magic number */ +#define VPU_IOC_MAGIC 'k' + +#define VPU_IOC_PP_INSTANCE _IO(VPU_IOC_MAGIC, 1) /* the client is pp instance */ +#define VPU_IOC_HW_PERFORMANCE _IO(VPU_IOC_MAGIC, 2) /* get monotonic time (struct timespec) for HW performance */ + +#define VPU_IOC_GHWOFFSET _IOR(VPU_IOC_MAGIC, 3, unsigned long *) +#define VPU_IOC_GHWIOSIZE _IOR(VPU_IOC_MAGIC, 4, unsigned int *) + +#define VPU_IOC_CLI _IO(VPU_IOC_MAGIC, 5) +#define VPU_IOC_STI _IO(VPU_IOC_MAGIC, 6) + +#define VPU_IOC_DEC_INSTANCE _IO(VPU_IOC_MAGIC, 7) +#define VPU_IOC_ENC_INSTANCE _IO(VPU_IOC_MAGIC, 8) + +#define VPU_IOC_MAXNR 8 + +#endif diff --git a/arch/arm/mach-rk29/io.c b/arch/arm/mach-rk29/io.c index 163fffe13c21..9f681ccb3b94 100644 --- a/arch/arm/mach-rk29/io.c +++ b/arch/arm/mach-rk29/io.c @@ -45,6 +45,7 @@ static struct map_desc rk29_io_desc[] __initdata = { RK29_DEVICE(GPIO4), RK29_DEVICE(GPIO5), RK29_DEVICE(GPIO6), + RK29_DEVICE(NANDC), }; void __init rk29_map_common_io(void) diff --git a/arch/arm/mach-rk29/vpu.c b/arch/arm/mach-rk29/vpu.c new file mode 100644 index 000000000000..1749374dddd0 --- /dev/null +++ b/arch/arm/mach-rk29/vpu.c @@ -0,0 +1,604 @@ +/* arch/arm/mach-rk29/vpu.c + * + * Copyright (C) 2010 ROCKCHIP, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifdef CONFIG_RK29_VPU_DEBUG +#define DEBUG +#define pr_fmt(fmt) "VPU: %s: " fmt, __func__ +#else +#define pr_fmt(fmt) "VPU: " fmt +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_RK29_VPU_HW_PERFORMANCE +#include +#endif + +#include + +#include +#include +#include + +#define DEC_INTERRUPT_REGISTER 1 +#define PP_INTERRUPT_REGISTER 60 +#define ENC_INTERRUPT_REGISTER 1 + +#define DEC_INTERRUPT_BIT 0x100 +#define PP_INTERRUPT_BIT 0x100 +#define ENC_INTERRUPT_BIT 0x1 + +#define DEC_IO_SIZE ((100 + 1) * 4) /* bytes */ +#define ENC_IO_SIZE (96 * 4) /* bytes */ + +static const u16 dec_hw_ids[] = { 0x8190, 0x8170, 0x9170, 0x9190, 0x6731 }; +static const u16 enc_hw_ids[] = { 0x6280, 0x7280, 0x8270 }; + +struct vpu_device { + unsigned long iobaseaddr; + unsigned int iosize; + volatile u32 *hwregs; + unsigned int irq; +}; + +static struct vpu_device dec_dev; +static struct vpu_device pp_dev; +static struct vpu_device enc_dev; + +struct vpu_client { + struct vpu_device *dev; + s32 event_count; /* for user */ + atomic_t event; /* inc by irq */ + struct fasync_struct *async_queue; + wait_queue_head_t wait; + struct file *filp; /* for /proc/vpu */ +#ifdef CONFIG_RK29_VPU_HW_PERFORMANCE + struct timespec end_time; +#endif +}; +static struct vpu_client client; + +static void vpu_release_io(void); +#ifdef CONFIG_RK29_VPU_DEBUG +static void dump_regs(struct vpu_device *); +#endif + +static long vpu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int err = 0; + struct vpu_device *dev = client.dev; + + pr_debug("ioctl cmd 0x%08x\n", cmd); + + if (!dev) + return -EINVAL; + + /* + * extract the type and number bitfields, and don't decode + * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok() + */ + if (_IOC_TYPE(cmd) != VPU_IOC_MAGIC) + return -ENOTTY; + if (_IOC_NR(cmd) > VPU_IOC_MAXNR) + return -ENOTTY; + + /* + * the direction is a bitmask, and VERIFY_WRITE catches R/W + * transfers. `Type' is user-oriented, while + * access_ok is kernel-oriented, so the concept of "read" and + * "write" is reversed + */ + if (_IOC_DIR(cmd) & _IOC_READ) + err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); + else if (_IOC_DIR(cmd) & _IOC_WRITE) + err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); + if (err) + return -EFAULT; + + switch (cmd) { + case VPU_IOC_CLI: + disable_irq(dev->irq); + break; + + case VPU_IOC_STI: + enable_irq(dev->irq); + break; + + case VPU_IOC_GHWOFFSET: + put_user(dev->iobaseaddr, (unsigned long *)arg); + break; + + case VPU_IOC_GHWIOSIZE: + put_user(dev->iosize, (unsigned int *)arg); + break; + + case VPU_IOC_DEC_INSTANCE: + client.dev = &dec_dev; + break; + + case VPU_IOC_PP_INSTANCE: + client.dev = &pp_dev; + break; + + case VPU_IOC_ENC_INSTANCE: + client.dev = &enc_dev; + break; + +#ifdef CONFIG_RK29_VPU_HW_PERFORMANCE + case VPU_IOC_HW_PERFORMANCE: + put_user(client.end_time.tv_sec, (long *)arg); + put_user(client.end_time.tv_nsec, (long *)arg + 1); + break; +#endif + } + + return 0; +} + +static int vpu_open(struct inode *inode, struct file *filp) +{ + if (client.filp) + return -EBUSY; + client.dev = &dec_dev; + client.event_count = atomic_read(&client.event); + client.filp = filp; + pr_debug("dev opened\n"); + return nonseekable_open(inode, filp); +} + +static int vpu_fasync(int fd, struct file *filp, int mode) +{ + return fasync_helper(fd, filp, mode, &client.async_queue); +} + +static int vpu_release(struct inode *inode, struct file *filp) +{ +#ifdef CONFIG_RK29_VPU_DEBUG + dump_regs(&enc_dev); /* dump the regs */ + dump_regs(&dec_dev); /* dump the regs */ +#endif + + /* remove this filp from the asynchronusly notified filp's */ + vpu_fasync(-1, filp, 0); + + client.async_queue = NULL; + client.filp = NULL; + + pr_debug("dev closed\n"); + return 0; +} + +static int vpu_check_hw_id(struct vpu_device * dev, const u16 *hwids, size_t num) +{ + u32 hwid = readl(dev->hwregs); + pr_info("HW ID = 0x%08x\n", hwid); + + hwid = (hwid >> 16) & 0xFFFF; /* product version only */ + + while (num--) { + if (hwid == hwids[num]) { + pr_info("Compatible HW found at 0x%08lx\n", dev->iobaseaddr); + return 1; + } + } + + pr_info("No Compatible HW found at 0x%08lx\n", dev->iobaseaddr); + return 0; +} + +static int vpu_reserve_io(void) +{ + if (!request_mem_region(dec_dev.iobaseaddr, dec_dev.iosize, "hx170dec")) { + pr_info("failed to reserve dec HW regs\n"); + return -EBUSY; + } + + dec_dev.hwregs = + (volatile u32 *)ioremap_nocache(dec_dev.iobaseaddr, dec_dev.iosize); + + if (dec_dev.hwregs == NULL) { + pr_info("failed to ioremap dec HW regs\n"); + goto err; + } + + /* check for correct HW */ + if (!vpu_check_hw_id(&dec_dev, dec_hw_ids, ARRAY_SIZE(dec_hw_ids))) { + goto err; + } + + if (!request_mem_region(enc_dev.iobaseaddr, enc_dev.iosize, "hx280enc")) { + pr_info("failed to reserve enc HW regs\n"); + goto err; + } + + enc_dev.hwregs = + (volatile u32 *)ioremap_nocache(enc_dev.iobaseaddr, enc_dev.iosize); + + if (enc_dev.hwregs == NULL) { + pr_info("failed to ioremap enc HW regs\n"); + goto err; + } + + /* check for correct HW */ + if (!vpu_check_hw_id(&enc_dev, enc_hw_ids, ARRAY_SIZE(enc_hw_ids))) { + goto err; + } + return 0; + +err: + vpu_release_io(); + return -EBUSY; +} + +static void vpu_release_io(void) +{ + if (dec_dev.hwregs) + iounmap((void *)dec_dev.hwregs); + release_mem_region(dec_dev.iobaseaddr, dec_dev.iosize); + + if (enc_dev.hwregs) + iounmap((void *)enc_dev.hwregs); + release_mem_region(enc_dev.iobaseaddr, enc_dev.iosize); +} + +static void vpu_event_notify(void) +{ + atomic_inc(&client.event); + wake_up_interruptible(&client.wait); + if (client.async_queue) + kill_fasync(&client.async_queue, SIGIO, POLL_IN); +} + +static irqreturn_t hx170dec_isr(int irq, void *dev_id) +{ + unsigned int handled = 0; + + struct vpu_device *dev = (struct vpu_device *) dev_id; + u32 irq_status_dec; + u32 irq_status_pp; + + handled = 0; + + /* interrupt status register read */ + irq_status_dec = readl(dev->hwregs + DEC_INTERRUPT_REGISTER); + irq_status_pp = readl(dev->hwregs + PP_INTERRUPT_REGISTER); + + if (irq_status_dec & DEC_INTERRUPT_BIT) { +#ifdef CONFIG_RK29_VPU_HW_PERFORMANCE + ktime_get_ts(&client.end_time); +#endif + /* clear dec IRQ */ + writel(irq_status_dec & (~DEC_INTERRUPT_BIT), + dev->hwregs + DEC_INTERRUPT_REGISTER); + + vpu_event_notify(); + + pr_debug("DEC IRQ received!\n"); + handled = 1; + } + + if (irq_status_pp & PP_INTERRUPT_BIT) { +#ifdef CONFIG_RK29_VPU_HW_PERFORMANCE + ktime_get_ts(&client.end_time); +#endif + /* clear pp IRQ */ + writel(irq_status_pp & (~DEC_INTERRUPT_BIT), + dev->hwregs + PP_INTERRUPT_REGISTER); + + vpu_event_notify(); + + pr_debug("PP IRQ received!\n"); + handled = 1; + } + + if (!handled) { + pr_debug("IRQ received, but not x170's!\n"); + } + + return IRQ_RETVAL(handled); +} + +static irqreturn_t hx280enc_isr(int irq, void *dev_id) +{ + struct vpu_device *dev = (struct vpu_device *) dev_id; + u32 irq_status; + + irq_status = readl(dev->hwregs + ENC_INTERRUPT_REGISTER); + + if (irq_status & ENC_INTERRUPT_BIT) { +#ifdef CONFIG_RK29_VPU_HW_PERFORMANCE + ktime_get_ts(&client.end_time); +#endif + /* clear enc IRQ */ + writel(irq_status & (~ENC_INTERRUPT_BIT), + dev->hwregs + ENC_INTERRUPT_REGISTER); + + vpu_event_notify(); + + pr_debug("ENC IRQ handled!\n"); + return IRQ_HANDLED; + } else { + pr_debug("ENC IRQ received, but NOT handled!\n"); + return IRQ_NONE; + } +} + +static void vpu_reset_dec_asic(struct vpu_device * dev) +{ + unsigned int i, n = dev->iosize >> 2; + + writel(0, dev->hwregs + DEC_INTERRUPT_REGISTER); + + for (i = 1; i < n; i++) { + writel(0, dev->hwregs + i); + } +} + +static void vpu_reset_enc_asic(struct vpu_device * dev) +{ + unsigned int i, n = dev->iosize >> 2; + + writel(0, dev->hwregs + 14); + + for (i = 4; i < n; i++) { + writel(0, dev->hwregs + i); + } +} + +#ifdef CONFIG_RK29_VPU_DEBUG +static void dump_regs(struct vpu_device *dev) +{ + unsigned int i, n = dev->iosize >> 2; + + pr_debug("Reg Dump Start\n"); + for (i = 0; i < n; i++) { + pr_debug("\tswreg%d = %08X\n", i, readl(dev->hwregs + i)); + } + pr_debug("Reg Dump End\n"); +} +#endif + +static int vpu_mmap(struct file *fp, struct vm_area_struct *vm) +{ + unsigned long pfn; + + /* Only support the simple cases where we map in a register page. */ + if (((vm->vm_end - vm->vm_start) > RK29_VCODEC_SIZE) || vm->vm_pgoff) + return -EINVAL; + + vm->vm_flags |= VM_IO | VM_RESERVED; + vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot); + pfn = RK29_VCODEC_PHYS >> PAGE_SHIFT; + pr_debug("size = 0x%x, page no. = 0x%x\n", + (int)(vm->vm_end - vm->vm_start), (int)pfn); + return remap_pfn_range(vm, vm->vm_start, pfn, vm->vm_end - vm->vm_start, + vm->vm_page_prot) ? -EAGAIN : 0; +} + +static unsigned int vpu_poll(struct file *filep, poll_table *wait) +{ + poll_wait(filep, &client.wait, wait); + if (client.event_count != atomic_read(&client.event)) + return POLLIN | POLLRDNORM; + return 0; +} + +static ssize_t vpu_read(struct file *filep, char __user *buf, + size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + ssize_t retval; + s32 event_count; + + if (count != sizeof(s32)) + return -EINVAL; + + add_wait_queue(&client.wait, &wait); + + do { + set_current_state(TASK_INTERRUPTIBLE); + + event_count = atomic_read(&client.event); + if (event_count != client.event_count) { + if (copy_to_user(buf, &event_count, count)) + retval = -EFAULT; + else { + client.event_count = event_count; + retval = count; + } + break; + } + + if (filep->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + schedule(); + } while (1); + + __set_current_state(TASK_RUNNING); + remove_wait_queue(&client.wait, &wait); + + return retval; +} + +static const struct file_operations vpu_fops = { + .read = vpu_read, + .poll = vpu_poll, + .unlocked_ioctl = vpu_ioctl, + .mmap = vpu_mmap, + .open = vpu_open, + .release = vpu_release, + .fasync = vpu_fasync, +}; + +static struct miscdevice vpu_misc_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "vpu", + .fops = &vpu_fops, +}; + +static int __init vpu_init(void) +{ + int ret; + + pr_debug("baseaddr = 0x%08x vdpu irq = %d vepu irq = %d\n", RK29_VCODEC_PHYS, IRQ_VDPU, IRQ_VEPU); + + dec_dev.iobaseaddr = RK29_VCODEC_PHYS + 0x200; + dec_dev.iosize = DEC_IO_SIZE; + dec_dev.irq = IRQ_VDPU; + + enc_dev.iobaseaddr = RK29_VCODEC_PHYS; + enc_dev.iosize = ENC_IO_SIZE; + enc_dev.irq = IRQ_VEPU; + + ret = vpu_reserve_io(); + if (ret < 0) { + goto err_reserve_io; + } + pp_dev = dec_dev; + + init_waitqueue_head(&client.wait); + atomic_set(&client.event, 0); + + vpu_reset_dec_asic(&dec_dev); /* reset hardware */ + vpu_reset_enc_asic(&enc_dev); /* reset hardware */ + + /* get the IRQ line */ + ret = request_irq(IRQ_VDPU, hx170dec_isr, 0, "hx170dec", (void *)&dec_dev); + if (ret != 0) { + pr_err("can't request vdpu irq %d\n", IRQ_VDPU); + goto err_req_vdpu_irq; + } + + ret = request_irq(IRQ_VEPU, hx280enc_isr, 0, "hx280enc", (void *)&enc_dev); + if (ret != 0) { + pr_err("can't request vepu irq %d\n", IRQ_VEPU); + goto err_req_vepu_irq; + } + + ret = misc_register(&vpu_misc_device); + if (ret) { + pr_err("misc_register failed\n"); + goto err_register; + } + + pr_info("init success\n"); + + return 0; + +err_register: + free_irq(IRQ_VEPU, (void *)&enc_dev); +err_req_vepu_irq: + free_irq(IRQ_VDPU, (void *)&dec_dev); +err_req_vdpu_irq: + vpu_release_io(); +err_reserve_io: + pr_info("init failed\n"); + return ret; +} + +static void __exit vpu_exit(void) +{ + /* clear dec IRQ */ + writel(0, dec_dev.hwregs + DEC_INTERRUPT_REGISTER); + /* clear pp IRQ */ + writel(0, dec_dev.hwregs + PP_INTERRUPT_REGISTER); + + writel(0, enc_dev.hwregs + 14); /* disable HW */ + /* clear enc IRQ */ + writel(0, enc_dev.hwregs + ENC_INTERRUPT_REGISTER); + +#ifdef CONFIG_RK29_VPU_DEBUG + dump_regs(&enc_dev); /* dump the regs */ + dump_regs(&dec_dev); /* dump the regs */ +#endif + + misc_deregister(&vpu_misc_device); + free_irq(IRQ_VEPU, (void *)&enc_dev); + free_irq(IRQ_VDPU, (void *)&dec_dev); + vpu_release_io(); +} + +module_init(vpu_init); +module_exit(vpu_exit); +MODULE_LICENSE("GPL"); + +#ifdef CONFIG_PROC_FS +#include +#include + +static int proc_vpu_show(struct seq_file *s, void *v) +{ + unsigned int i, n; + + if (client.filp) { + seq_printf(s, "Opened\n"); + seq_printf(s, "%s instance\n", client.dev == &dec_dev ? "DEC" : client.dev == &pp_dev ? "PP" : "ENC"); + } else { + seq_printf(s, "Closed\n"); + } + seq_printf(s, "event_count %d event %d\n", client.event_count, atomic_read(&client.event)); +#ifdef CONFIG_RK29_VPU_HW_PERFORMANCE + seq_printf(s, "end_time: %ld.%09ld\n", client.end_time.tv_sec, client.end_time.tv_nsec); +#endif + + seq_printf(s, "\nENC Registers:\n"); + n = enc_dev.iosize >> 2; + for (i = 0; i < n; i++) { + seq_printf(s, "\tswreg%d = %08X\n", i, readl(enc_dev.hwregs + i)); + } + seq_printf(s, "\nDEC Registers:\n"); + n = dec_dev.iosize >> 2; + for (i = 0; i < n; i++) { + seq_printf(s, "\tswreg%d = %08X\n", i, readl(dec_dev.hwregs + i)); + } + return 0; +} + +static int proc_vpu_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_vpu_show, NULL); +} + +static const struct file_operations proc_vpu_fops = { + .open = proc_vpu_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init vpu_proc_init(void) +{ + proc_create("vpu", 0, NULL, &proc_vpu_fops); + return 0; + +} +late_initcall(vpu_proc_init); +#endif /* CONFIG_PROC_FS */ + diff --git a/drivers/input/touchscreen/xpt2046_cbn_ts.c b/drivers/input/touchscreen/xpt2046_cbn_ts.c index 50353c20eba4..98d3bec83303 100755 --- a/drivers/input/touchscreen/xpt2046_cbn_ts.c +++ b/drivers/input/touchscreen/xpt2046_cbn_ts.c @@ -382,7 +382,7 @@ static int xpt2046_debounce(void *xpt, int data_idx, int *val) static int average_val[2]; - xpt2046printk("***>%s:%d,%d,%d,%d,%d,%d,%d,%d\n",__FUNCTION__, + xpt2046printk("***>%s:%d,%d,%d,%d,%ld,%d,%d,%d\n",__FUNCTION__, data_idx,ts->last_read, ts->read_cnt,ts->debounce_max, abs(ts->last_read - *val),ts->debounce_tol, @@ -700,8 +700,6 @@ static int __devinit xpt2046_probe(struct spi_device *spi) struct spi_transfer *x; int vref; int err; - int i; - if (!spi->irq) { dev_dbg(&spi->dev, "no IRQ?\n"); @@ -955,12 +953,14 @@ static struct spi_driver xpt2046_driver = { static int __init xpt2046_init(void) { + int ret; + xpt2046printk("Touch panel drive XPT2046 driver init...\n"); gADPoint.x = 0; gADPoint.y = 0; - int ret = spi_register_driver(&xpt2046_driver); + ret = spi_register_driver(&xpt2046_driver); if (ret) { printk("Register XPT2046 driver failed.\n"); diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index a73fe94bb0d4..8d2bd242ac63 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -235,11 +235,9 @@ static u32 get_card_status(struct mmc_card *card, struct request *req) cmd.arg = card->rca << 16; cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 0); - #if 0 //[xjh] not printk,save time if (err) printk(KERN_ERR "%s: error %d sending status comand", req->rq_disk->disk_name, err); - #endif return cmd.resp[0]; } @@ -378,9 +376,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) * until later as we need to wait for the card to leave * programming mode even when things go wrong. */ - #if 1/*[xjh] do not retry with cmd17*/ if (brq.cmd.error || brq.data.error || brq.stop.error) { - if (brq.data.blocks > 1 && rq_data_dir(req) == READ) { /* Redo read one sector at a time */ printk(KERN_WARNING "%s: retrying using single " @@ -388,14 +384,11 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) disable_multi = 1; continue; } - status = get_card_status(card, req); } else if (disable_multi == 1) { disable_multi = 0; } - #endif - #if 0 //[xjh] not printk,save time if (brq.cmd.error) { printk(KERN_ERR "%s: error %d sending read/write " "command, response %#x, card status %#x\n", @@ -420,7 +413,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) req->rq_disk->disk_name, brq.stop.error, brq.stop.resp[0], status); } - #endif if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) { do { @@ -453,7 +445,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) } if (brq.cmd.error || brq.stop.error || brq.data.error) { - #if 1/*[xjh] do not retry with cmd17*/ if (rq_data_dir(req) == READ) { /* * After an error, we redo I/O one sector at a @@ -465,7 +456,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) spin_unlock_irq(&md->lock); continue; } - #endif goto cmd_err; } diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 602b150163ee..bdb165f93046 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -268,7 +268,6 @@ int mmc_add_card(struct mmc_card *card) return 0; } -extern int sdmmc0_disable_Irq_ForRemoval; /* * Unregister a new MMC card with the driver model, and * (eventually) free it. @@ -278,7 +277,6 @@ void mmc_remove_card(struct mmc_card *card) #ifdef CONFIG_DEBUG_FS mmc_remove_card_debugfs(card); #endif - unsigned long flags; if (mmc_card_present(card)) { if (mmc_host_is_spi(card->host)) { @@ -288,13 +286,6 @@ void mmc_remove_card(struct mmc_card *card) printk(KERN_INFO "%s: card %04x removed\n", mmc_hostname(card->host), card->rca); } - - if( !strncmp( mmc_hostname(card->host) ,"mmc0" , strlen("mmc0")) ) - { - local_irq_save(flags); - sdmmc0_disable_Irq_ForRemoval = 1; //close the IRQ for insertion or removal - local_irq_restore(flags); - } device_del(&card->dev); } diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 231439a961e2..fb25fd001f4a 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1059,7 +1059,7 @@ void mmc_detect_change(struct mmc_host *host, unsigned long delay) EXPORT_SYMBOL(mmc_detect_change); -#if 0 + void mmc_rescan(struct work_struct *work) { struct mmc_host *host = @@ -1154,102 +1154,6 @@ void mmc_rescan(struct work_struct *work) if (host->caps & MMC_CAP_NEEDS_POLL) mmc_schedule_delayed_work(&host->detect, HZ); } -#else -void mmc_rescan(struct work_struct *work) -{ - struct mmc_host *host = - container_of(work, struct mmc_host, detect.work); - u32 ocr; - int err; - int extend_wakelock = 0; - - mmc_bus_get(host); - if(host->bus_ops == NULL) - { - /* detect a newly inserted card */ - - /* - * Only we can add a new handler, so it's safe to - * release the lock here. - */ - mmc_bus_put(host); - - if (host->ops->get_cd && host->ops->get_cd(host) == 0) - goto out; - - mmc_claim_host(host); - - mmc_power_up(host); - mmc_go_idle(host); - - mmc_send_if_cond(host, host->ocr_avail); - - /* - * First we search for SDIO... - */ - err = mmc_send_io_op_cond(host, 0, &ocr); - if (!err) { - if (mmc_attach_sdio(host, ocr)) - mmc_power_off(host); - extend_wakelock = 1; - goto out; - } - - /* - * ...then normal SD... - */ - err = mmc_send_app_op_cond(host, 0, &ocr); - if (!err) { - if (mmc_attach_sd(host, ocr)) - mmc_power_off(host); - extend_wakelock = 1; - goto out; - } - - /* - * ...and finally MMC. - */ - err = mmc_send_op_cond(host, 0, &ocr); - if (!err) { - if (mmc_attach_mmc(host, ocr)) - mmc_power_off(host); - extend_wakelock = 1; - goto out; - } - - mmc_release_host(host); - mmc_power_off(host); - - } - else - { - /* if there is a card registered, check whether it is still present */ - if ((host->bus_ops != NULL) && host->bus_ops->detect && !host->bus_dead) - host->bus_ops->detect(host); - - /* If the card was removed the bus will be marked - * as dead - extend the wakelock so userspace - * can respond */ - if (host->bus_dead) - extend_wakelock = 1; - - mmc_bus_put(host); - - } - - - -out: - if (extend_wakelock) - wake_lock_timeout(&mmc_delayed_work_wake_lock, HZ / 2); - else - wake_unlock(&mmc_delayed_work_wake_lock); - - if (host->caps & MMC_CAP_NEEDS_POLL) - mmc_schedule_delayed_work(&host->detect, HZ); -} - -#endif void mmc_start_host(struct mmc_host *host) { diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 33747f583df8..32af45c419f4 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -660,9 +660,6 @@ static void mmc_attach_bus_ops(struct mmc_host *host) int mmc_attach_mmc(struct mmc_host *host, u32 ocr) { int err; - - unsigned long flags; - extern int sdmmc0_disable_Irq_ForRemoval; BUG_ON(!host); WARN_ON(!host->claimed); @@ -711,10 +708,6 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr) err = mmc_add_card(host->card); if (err) goto remove_card; - - local_irq_save(flags); - sdmmc0_disable_Irq_ForRemoval = 0; //close the IRQ for insertion or removal - local_irq_restore(flags); return 0; diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index c58ddc0eecc1..0aa0cf0dde24 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -27,6 +27,29 @@ if SDMMC_RK2818 This supports the use of the SDMMC1 controller on rk2818 processors. endif +config SDMMC_RK29 + tristate "RK29 SDMMC controller suppport" + depends on ARCH_RK29 + help + This selects the RK29 SDMMC controller. + SDMMC0 used for sd/mmc card, and SDMMC1 used for sdio. +if SDMMC_RK29 + comment "Now, there are two SDMMC controllers selected, SDMMC0 and SDMMC1." + config SDMMC0_RK29 + tristate "RK29 SDMMC0 controller support(sdmmc)" + default y + depends on ARCH_RK29 + help + This supports the use of the SDMMC0 controller on Rk29 processors. + + config SDMMC1_RK29 + tristate "RK29 SDMMC1 controller support(sdio)" + default y + depends on ARCH_RK29 + help + This supports the use of the SDMMC1 controller on Rk29 processors. +endif + config MMC_ARMMMCI tristate "ARM AMBA Multimedia Card Interface support" depends on ARM_AMBA diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index cf31850676a4..8230c5f949b1 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -6,6 +6,7 @@ ifeq ($(CONFIG_MMC_DEBUG),y) EXTRA_CFLAGS += -DDEBUG endif +obj-$(CONFIG_SDMMC_RK29) += rk29_sdmmc.o obj-$(CONFIG_SDMMC_RK2818) += rk2818-sdmmc.o obj-$(CONFIG_MMC_ARMMMCI) += mmci.o obj-$(CONFIG_MMC_PXA) += pxamci.o diff --git a/drivers/mmc/host/rk2818-sdmmc.h b/drivers/mmc/host/rk2818-sdmmc.h index 15a12f4a5d55..2422958b6fe6 100755 --- a/drivers/mmc/host/rk2818-sdmmc.h +++ b/drivers/mmc/host/rk2818-sdmmc.h @@ -126,7 +126,7 @@ /* Specifies how often in millisecs to poll for card removal-insertion changes * when the timer switch is open */ -#define RK28_SDMMC0_SWITCH_POLL_DELAY 3500 +#define RK_SDMMC0_SWITCH_POLL_DELAY 3500 #endif diff --git a/drivers/mmc/host/rk29_sdmmc.c b/drivers/mmc/host/rk29_sdmmc.c new file mode 100644 index 000000000000..6e1339e0c5dd --- /dev/null +++ b/drivers/mmc/host/rk29_sdmmc.c @@ -0,0 +1,1484 @@ +/* drivers/mmc/host/rk29_sdmmc.c + * + * Copyright (C) 2010 ROCKCHIP, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "rk2818-sdmmc.h" + +#if 0 +#define DBG(x...) printk(KERN_INFO x) +#else +#define DBG(x...) do { } while (0) +#endif + +#define RK29_SDMMC_DATA_ERROR_FLAGS (SDMMC_INT_DTO | SDMMC_INT_DCRC | SDMMC_INT_HTO | SDMMC_INT_SBE | SDMMC_INT_EBE) +#define RK29_SDMMC_CMD_ERROR_FLAGS (SDMMC_INT_RTO | SDMMC_INT_RCRC | SDMMC_INT_RE | SDMMC_INT_HLE) +#define RK29_SDMMC_ERROR_FLAGS (RK29_SDMMC_DATA_ERROR_FLAGS | RK29_SDMMC_CMD_ERROR_FLAGS | SDMMC_INT_HLE) +#define RK29_SDMMC_SEND_STATUS 1 +#define RK29_SDMMC_RECV_STATUS 2 +#define RK29_SDMMC_DMA_THRESHOLD 16 + +enum { + EVENT_CMD_COMPLETE = 0, + EVENT_XFER_COMPLETE, + EVENT_DATA_COMPLETE, + EVENT_DATA_ERROR, + EVENT_XFER_ERROR +}; + +enum rk29_sdmmc_state { + STATE_IDLE = 0, + STATE_SENDING_CMD, + STATE_SENDING_DATA, + STATE_DATA_BUSY, + STATE_SENDING_STOP, + STATE_DATA_ERROR, +}; + +static struct rk29_dma_client rk29_dma_sdmmc0_client = { + .name = "rk29-dma-sdmmc0", +}; + +static struct rk29_dma_client rk29_dma_sdio1_client = { + .name = "rk29-dma-sdio1", +}; + +struct rk29_sdmmc { + spinlock_t lock; + void __iomem *regs; + struct clk *clk; + struct scatterlist *sg; + unsigned int pio_offset; + struct mmc_request *mrq; + struct mmc_request *curr_mrq; + struct mmc_command *cmd; + struct mmc_data *data; + int dma_chn; + //dma_addr_t sg_dma; + //dma_sg_ll_t *sg_cpu; + unsigned int use_dma:1; + char dma_name[8]; + u32 cmd_status; + u32 data_status; + u32 stop_cmdr; + u32 dir_status; + struct tasklet_struct tasklet; + unsigned long pending_events; + unsigned long completed_events; + enum rk29_sdmmc_state state; + struct list_head queue; + u32 bus_hz; + u32 current_speed; + struct platform_device *pdev; + struct mmc_host *mmc; + u32 ctype; + struct list_head queue_node; + unsigned int clock; + unsigned long flags; +#define RK29_SDMMC_CARD_PRESENT 0 +#define RK29_SDMMC_CARD_NEED_INIT 1 +#define RK29_SDMMC_SHUTDOWN 2 + int id; + int irq; + struct timer_list detect_timer; +}; + +#define rk29_sdmmc_test_and_clear_pending(host, event) \ + test_and_clear_bit(event, &host->pending_events) +#define rk29_sdmmc_set_completed(host, event) \ + set_bit(event, &host->completed_events) + +#define rk29_sdmmc_set_pending(host, event) \ + set_bit(event, &host->pending_events) + +static void rk29_sdmmc_write(unsigned char __iomem *regbase, unsigned int regOff,unsigned int val) +{ + __raw_writel(val,regbase + regOff); +} + +static unsigned int rk29_sdmmc_read(unsigned char __iomem *regbase, unsigned int regOff) +{ + return __raw_readl(regbase + regOff); +} + + +#if defined (CONFIG_DEBUG_FS) +/* + * The debugfs stuff below is mostly optimized away when + * CONFIG_DEBUG_FS is not set. + */ +static int rk29_sdmmc_req_show(struct seq_file *s, void *v) +{ + struct rk29_sdmmc *host = s->private; + struct mmc_request *mrq; + struct mmc_command *cmd; + struct mmc_command *stop; + struct mmc_data *data; + + /* Make sure we get a consistent snapshot */ + spin_lock(&host->lock); + mrq = host->mrq; + + if (mrq) { + cmd = mrq->cmd; + data = mrq->data; + stop = mrq->stop; + + if (cmd) + seq_printf(s, + "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", + cmd->opcode, cmd->arg, cmd->flags, + cmd->resp[0], cmd->resp[1], cmd->resp[2], + cmd->resp[2], cmd->error); + if (data) + seq_printf(s, "DATA %u / %u * %u flg %x err %d\n", + data->bytes_xfered, data->blocks, + data->blksz, data->flags, data->error); + if (stop) + seq_printf(s, + "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", + stop->opcode, stop->arg, stop->flags, + stop->resp[0], stop->resp[1], stop->resp[2], + stop->resp[2], stop->error); + } + + spin_unlock(&host->lock); + + return 0; +} + +static int rk29_sdmmc_req_open(struct inode *inode, struct file *file) +{ + return single_open(file, rk29_sdmmc_req_show, inode->i_private); +} + +static const struct file_operations rk29_sdmmc_req_fops = { + .owner = THIS_MODULE, + .open = rk29_sdmmc_req_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +#define SDMMC_CTRL (0x000) +#define SDMMC_PWREN (0x004) +#define SDMMC_CLKDIV (0x008) +#define SDMMC_CLKSRC (0x00c) +#define SDMMC_CLKENA (0x010) +#define SDMMC_TMOUT (0x014) +#define SDMMC_CTYPE (0x018) +#define SDMMC_BLKSIZ (0x01c) +#define SDMMC_BYTCNT (0x020) +#define SDMMC_INTMASK (0x024) +#define SDMMC_CMDARG (0x028) +#define SDMMC_CMD (0x02c) +#define SDMMC_RESP0 (0x030) +#define SDMMC_RESP1 (0x034) +#define SDMMC_RESP2 (0x038) +#define SDMMC_RESP3 (0x03c) +#define SDMMC_MINTSTS (0x040) +#define SDMMC_RINTSTS (0x044) +#define SDMMC_STATUS (0x048) +#define SDMMC_FIFOTH (0x04c) +#define SDMMC_CDETECT (0x050) +#define SDMMC_WRTPRT (0x054) +#define SDMMC_TCBCNT (0x05c) +#define SDMMC_TBBCNT (0x060) +#define SDMMC_DEBNCE (0x064) +static int rk29_sdmmc_regs_show(struct seq_file *s, void *v) +{ + struct rk29_sdmmc *host = s->private; + + seq_printf(s, "SDMMC_CTRL: \t0x%08x\n", SDMMC_CTRL); + seq_printf(s, "SDMMC_PWREN: \t0x%08x\n", SDMMC_PWREN); + seq_printf(s, "SDMMC_CLKDIV: \t0x%08x\n", SDMMC_CLKDIV); + seq_printf(s, "SDMMC_CLKSRC: \t0x%08x\n", SDMMC_CLKSRC); + seq_printf(s, "SDMMC_CLKENA: \t0x%08x\n", SDMMC_CLKENA); + seq_printf(s, "SDMMC_TMOUT: \t0x%08x\n", SDMMC_TMOUT); + seq_printf(s, "SDMMC_CTYPE: \t0x%08x\n", SDMMC_CTYPE); + seq_printf(s, "SDMMC_BLKSIZ: \t0x%08x\n", SDMMC_BLKSIZ); + seq_printf(s, "SDMMC_BYTCNT: \t0x%08x\n", SDMMC_BYTCNT); + seq_printf(s, "SDMMC_INTMASK:\t0x%08x\n", SDMMC_INTMASK); + seq_printf(s, "SDMMC_CMDARG: \t0x%08x\n", SDMMC_CMDARG); + seq_printf(s, "SDMMC_CMD: \t0x%08x\n", SDMMC_CMD); + seq_printf(s, "SDMMC_RESP0: \t0x%08x\n", SDMMC_RESP0); + seq_printf(s, "SDMMC_RESP1: \t0x%08x\n", SDMMC_RESP1); + seq_printf(s, "SDMMC_RESP2: \t0x%08x\n", SDMMC_RESP2); + seq_printf(s, "SDMMC_RESP3: \t0x%08x\n", SDMMC_RESP3); + seq_printf(s, "SDMMC_MINTSTS:\t0x%08x\n", SDMMC_MINTSTS); + seq_printf(s, "SDMMC_RINTSTS:\t0x%08x\n", SDMMC_RINTSTS); + seq_printf(s, "SDMMC_STATUS: \t0x%08x\n", SDMMC_STATUS); + seq_printf(s, "SDMMC_FIFOTH: \t0x%08x\n", SDMMC_FIFOTH); + seq_printf(s, "SDMMC_CDETECT:\t0x%08x\n", SDMMC_CDETECT); + seq_printf(s, "SDMMC_WRTPRT: \t0x%08x\n", SDMMC_WRTPRT); + seq_printf(s, "SDMMC_TCBCNT: \t0x%08x\n", SDMMC_TCBCNT); + seq_printf(s, "SDMMC_TBBCNT: \t0x%08x\n", SDMMC_TBBCNT); + seq_printf(s, "SDMMC_DEBNCE: \t0x%08x\n", SDMMC_DEBNCE); + + return 0; +} + +static int rk29_sdmmc_regs_open(struct inode *inode, struct file *file) +{ + return single_open(file, rk29_sdmmc_regs_show, inode->i_private); +} + +static const struct file_operations rk29_sdmmc_regs_fops = { + .owner = THIS_MODULE, + .open = rk29_sdmmc_regs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void rk29_sdmmc_init_debugfs(struct rk29_sdmmc *host) +{ + struct mmc_host *mmc = host->mmc; + struct dentry *root; + struct dentry *node; + + root = mmc->debugfs_root; + if (!root) + return; + + node = debugfs_create_file("regs", S_IRUSR, root, host, + &rk29_sdmmc_regs_fops); + if (IS_ERR(node)) + return; + if (!node) + goto err; + + node = debugfs_create_file("req", S_IRUSR, root, host, &rk29_sdmmc_req_fops); + if (!node) + goto err; + + node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state); + if (!node) + goto err; + + node = debugfs_create_x32("pending_events", S_IRUSR, root, + (u32 *)&host->pending_events); + if (!node) + goto err; + + node = debugfs_create_x32("completed_events", S_IRUSR, root, + (u32 *)&host->completed_events); + if (!node) + goto err; + + return; + +err: + dev_err(&mmc->class_dev, "failed to initialize debugfs for host\n"); +} +#endif + +static inline unsigned ns_to_clocks(unsigned clkrate, unsigned ns) +{ + u32 clks; + if (clkrate > 1000000) + clks = (ns * (clkrate / 1000000) + 999) / 1000; + else + clks = ((ns/1000) * (clkrate / 1000) + 999) / 1000; + + return clks; +} + +static void rk29_sdmmc_set_timeout(struct rk29_sdmmc *host,struct mmc_data *data) +{ + unsigned timeout; + + timeout = ns_to_clocks(host->clock, data->timeout_ns) + data->timeout_clks; + + rk29_sdmmc_write(host->regs, SDMMC_TMOUT, (timeout << 8) | (70)); +} + +static u32 rk29_sdmmc_prepare_command(struct mmc_host *mmc, + struct mmc_command *cmd) +{ + struct mmc_data *data; + u32 cmdr; + + cmd->error = -EINPROGRESS; + cmdr = cmd->opcode; + + if(cmdr == 12) + cmdr |= SDMMC_CMD_STOP; + else + cmdr |= SDMMC_CMD_PRV_DAT_WAIT; + + if (cmd->flags & MMC_RSP_PRESENT) { + cmdr |= SDMMC_CMD_RESP_EXP; // expect the respond, need to set this bit + if (cmd->flags & MMC_RSP_136) + cmdr |= SDMMC_CMD_RESP_LONG; // expect long respond + + if(cmd->flags & MMC_RSP_CRC) + cmdr |= SDMMC_CMD_RESP_CRC; + } + + data = cmd->data; + if (data) { + cmdr |= SDMMC_CMD_DAT_EXP; + if (data->flags & MMC_DATA_STREAM) + cmdr |= SDMMC_CMD_STRM_MODE; // set stream mode + if (data->flags & MMC_DATA_WRITE) + cmdr |= SDMMC_CMD_DAT_WR; + } + return cmdr; +} + + +static void rk29_sdmmc_start_command(struct rk29_sdmmc *host, + struct mmc_command *cmd, u32 cmd_flags) +{ + int tmo = 50; + host->cmd = cmd; + dev_vdbg(&host->pdev->dev, + "start cmd:%d ARGR=0x%08x CMDR=0x%08x\n", + cmd->opcode, cmd->arg, cmd_flags); + rk29_sdmmc_write(host->regs, SDMMC_CMDARG, cmd->arg); // write to SDMMC_CMDARG register + rk29_sdmmc_write(host->regs, SDMMC_CMD, cmd_flags | SDMMC_CMD_START); // write to SDMMC_CMD register + + /* wait until CIU accepts the command */ + while (--tmo && (rk29_sdmmc_read(host->regs, SDMMC_CMD) & SDMMC_CMD_START)) + cpu_relax(); +} + +static void send_stop_cmd(struct rk29_sdmmc *host, struct mmc_data *data) +{ + rk29_sdmmc_start_command(host, data->stop, host->stop_cmdr); +} + + +#ifdef USE_DMA + +static void rk29_sdmmc_dma_cleanup(struct rk29_sdmmc *host) +{ + struct mmc_data *data = host->data; + + if (data) + dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len, + ((data->flags & MMC_DATA_WRITE) + ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); +} + +static void rk29_sdmmc_stop_dma(struct rk29_sdmmc *host) +{ + if (host->dma_chn > 0) { + dma_stop_channel(host->dma_chn); + rk29_sdmmc_dma_cleanup(host); + } else { + /* Data transfer was stopped by the interrupt handler */ + rk29_sdmmc_set_pending(host, EVENT_XFER_COMPLETE); + } +} + +/* This function is called by the DMA driver from tasklet context. */ +static void rk29_sdmmc_dma_complete(int chn, dma_irq_type_t type, void *arg) +{ + struct rk29_sdmmc *host = arg; + struct mmc_data *data = host->data; + + dev_vdbg(&host->pdev->dev, "DMA complete\n"); + + spin_lock(&host->lock); + rk29_sdmmc_dma_cleanup(host); + + /* + * If the card was removed, data will be NULL. No point trying + * to send the stop command or waiting for NBUSY in this case. + */ + if (data) { + rk29_sdmmc_set_pending(host, EVENT_XFER_COMPLETE); + tasklet_schedule(&host->tasklet); + } + spin_unlock(&host->lock); +} + +static int rk29_sdmmc_submit_data_dma(struct rk29_sdmmc *host, struct mmc_data *data) +{ + struct scatterlist *sg; + unsigned int i, direction, sg_len; + unsigned int j, trans_len; + + /* If we don't have a channel, we can't do DMA */ + if (host->dma_chn < 0) + return -ENODEV; + + /* + * We don't do DMA on "complex" transfers, i.e. with + * non-word-aligned buffers or lengths. Also, we don't bother + * with all the DMA setup overhead for short transfers. + */ + if (data->blocks * data->blksz < RK29_SDMMC_DMA_THRESHOLD) + return -EINVAL; + if (data->blksz & 3) + return -EINVAL; + + for_each_sg(data->sg, sg, data->sg_len, i) { + if (sg->offset & 3 || sg->length & 3) + return -EINVAL; + } + + if (data->flags & MMC_DATA_READ) + direction = DMA_FROM_DEVICE; + else + direction = DMA_TO_DEVICE; + + sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, + direction); + + dev_vdbg(&host->pdev->dev, "sd sg_cpu: 0x%08x sg_dma:0x%08x sg_len:%d \n", + (u32)host->sg_cpu, (u32)host->sg_dma, sg_len); + + for (i = 0, j = 0; i < sg_len; i++) { + unsigned int length = sg_dma_len(&data->sg[i]); + u32 mem_addr = sg_dma_address(&data->sg[i]); + + while (length) { + + host->sg_cpu[j].setup.cfg = DMA_CFG_CMP_CH_EN | DMA_CFG_CMP_CH_NR(host->dma_chn); + + if (data->flags & MMC_DATA_READ) { + host->sg_cpu[j].setup.src_address = SDMMC_DATA_ADR; + host->sg_cpu[j].setup.dest_address = mem_addr; + host->sg_cpu[j].setup.cfg |= DMA_CFG_RD_SLV_NR(DMA_SLV_SDMMC); + } else { + host->sg_cpu[j].setup.src_address = mem_addr; + host->sg_cpu[j].setup.dest_address = SDMMC_DATA_ADR; + host->sg_cpu[j].setup.cfg |= DMA_CFG_WR_SLV_NR(DMA_SLV_SDMMC); + } + host->sg_cpu[j].next_entry = host->sg_dma + (j + 1) * + sizeof(dma_sg_ll_t); + + if (trans_len > DMA_MAX_TRANSFERS) { + trans_len = DMA_MAX_TRANSFERS; + length -= (DMA_MAX_TRANSFERS + 1) << 2; + mem_addr += ((DMA_MAX_TRANSFERS + 1) << 2); + } + else { + length = 0; + } + + host->sg_cpu[j].setup.trans_length = trans_len; + + dev_vdbg(&host->pdev->dev, "sd src: 0x%08x dest:0x%08x cfg:0x%08x nxt:0x%08x len:%d \n", + host->sg_cpu[j].setup.src_address, host->sg_cpu[j].setup.dest_address, + host->sg_cpu[j].setup.cfg, host->sg_cpu[j].next_entry, + host->sg_cpu[j].setup.trans_length); + + /* move to next transfer descriptor */ + j++; + } + } + host->sg_cpu[j].setup.src_address = host->sg_dma; + host->sg_cpu[j].setup.dest_address = DMACH_SOFT_INT_PHYS; + host->sg_cpu[j].setup.trans_length = 1; + host->sg_cpu[j].setup.cfg = 0; + // disable irq of RX & TX, let DMA handle it + //SDMMC_INTMASK &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR); + ///SDMMC_CTRL |= SDMMC_CTRL_DMA_ENABLE; // enable dma + rk29_sdmmc_write(host->regs, SDMMC_CTRL, (rk29_sdmmc_read(host->regs, SDMMC_CTRL))|SDMMC_CTRL_DMA_ENABLE); + dma_prog_sg_channel(host->dma_chn, host->sg_dma); + wmb(); + /* Go! */ + dma_start_channel(host->dma_chn); + + return 0; +} + +#else +static int rk29_sdmmc_submit_data_dma(struct rk29_sdmmc *host, struct mmc_data *data) +{ + return -ENOSYS; +} + +static void rk29_sdmmc_stop_dma(struct rk29_sdmmc *host) +{ + /* Data transfer was stopped by the interrupt handler */ + rk29_sdmmc_set_pending(host, EVENT_XFER_COMPLETE); + +} +#endif + +static void rk29_sdmmc_submit_data(struct rk29_sdmmc *host, struct mmc_data *data) +{ + data->error = -EINPROGRESS; + + WARN_ON(host->data); + host->sg = NULL; + host->data = data; + + if (rk29_sdmmc_submit_data_dma(host, data)) { + host->sg = data->sg; + host->pio_offset = 0; + if (data->flags & MMC_DATA_READ) + host->dir_status = RK29_SDMMC_RECV_STATUS; + else + host->dir_status = RK29_SDMMC_SEND_STATUS; + + rk29_sdmmc_write(host->regs, SDMMC_CTRL, (rk29_sdmmc_read(host->regs, SDMMC_CTRL))&(~SDMMC_CTRL_DMA_ENABLE)); + } + +} + +static void sdmmc_send_cmd(struct rk29_sdmmc *host, unsigned int cmd, int arg) +{ + int tmo = 10000; + + rk29_sdmmc_write(host->regs, SDMMC_CMDARG, arg); + rk29_sdmmc_write(host->regs, SDMMC_CMD, SDMMC_CMD_START | cmd); + while (--tmo && readl(host->regs + SDMMC_CMD) & SDMMC_CMD_START); + if(!tmo) { + printk("%s %d set cmd register timeout error!!!\n",__FUNCTION__,__LINE__); + } +} + +void rk29_sdmmc_setup_bus(struct rk29_sdmmc *host) +{ + u32 div; + + if (host->clock != host->current_speed) { + div = (((host->bus_hz + (host->bus_hz / 5)) / host->clock)) >> 1; + + /* store the actual clock for calculations */ + host->clock = (host->bus_hz / div) >> 1; + /* disable clock */ + rk29_sdmmc_write(host->regs, SDMMC_CLKENA, 0); + rk29_sdmmc_write(host->regs, SDMMC_CLKSRC,0); + /* inform CIU */ + sdmmc_send_cmd(host, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0); + /* set clock to desired speed */ + rk29_sdmmc_write(host->regs, SDMMC_CLKDIV, div); + /* inform CIU */ + sdmmc_send_cmd(host, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0); + /* enable clock */ + rk29_sdmmc_write(host->regs, SDMMC_CLKENA, SDMMC_CLKEN_ENABLE); + /* inform CIU */ + sdmmc_send_cmd(host, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0); + + host->current_speed = host->clock; + } + + /* Set the current bus width */ + rk29_sdmmc_write(host->regs, SDMMC_CTYPE, host->ctype); +} + +static void rk29_sdmmc_start_request(struct rk29_sdmmc *host) +{ + struct mmc_request *mrq; + struct mmc_command *cmd; + struct mmc_data *data; + u32 cmdflags; + + mrq = host->curr_mrq; + + /* Slot specific timing and width adjustment */ + rk29_sdmmc_setup_bus(host); + host->pending_events = 0; + host->completed_events = 0; + host->data_status = 0; + + data = mrq->data; + if (data) { + rk29_sdmmc_set_timeout(host,data); + rk29_sdmmc_write(host->regs, SDMMC_BYTCNT,data->blksz*data->blocks); + rk29_sdmmc_write(host->regs, SDMMC_BLKSIZ,data->blksz); + } + + cmd = mrq->cmd; + cmdflags = rk29_sdmmc_prepare_command(host->mmc, cmd); + + if (unlikely(test_and_clear_bit(RK29_SDMMC_CARD_NEED_INIT, &host->flags))) + cmdflags |= SDMMC_CMD_INIT; //this is the first command, let set send the initializtion clock + + if (data) //we may need to move this code to mci_start_command + rk29_sdmmc_submit_data(host, data); + + rk29_sdmmc_start_command(host, cmd, cmdflags); + + if (mrq->stop) + host->stop_cmdr = rk29_sdmmc_prepare_command(host->mmc, mrq->stop); + +} + +static void rk29_sdmmc_queue_request(struct rk29_sdmmc *host,struct mmc_request *mrq) +{ + spin_lock(&host->lock); + host->mrq = mrq; + if (host->state == STATE_IDLE) { + host->state = STATE_SENDING_CMD; + rk29_sdmmc_start_request(host); + } else { + list_add_tail(&host->queue_node, &host->queue); + } + spin_unlock(&host->lock); +} + + +static void rk29_sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct rk29_sdmmc *host = mmc_priv(mmc); + + WARN_ON(host->mrq); + + if (!test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags)) { + mrq->cmd->error = -ENOMEDIUM; + mmc_request_done(mmc, mrq); + return; + } + + rk29_sdmmc_queue_request(host,mrq); +} + +static void rk29_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct rk29_sdmmc *host = mmc_priv(mmc);; + + host->ctype = 0; // set default 1 bit mode + switch (ios->bus_width) { + case MMC_BUS_WIDTH_1: + host->ctype = 0; + break; + case MMC_BUS_WIDTH_4: + host->ctype = SDMMC_CTYPE_4BIT; + break; + } + + if (ios->clock) { + spin_lock(&host->lock); + /* + * Use mirror of ios->clock to prevent race with mmc + * core ios update when finding the minimum. + */ + host->clock = ios->clock; + + spin_unlock(&host->lock); + } else { + spin_lock(&host->lock); + host->clock = 0; + spin_unlock(&host->lock); + } + + switch (ios->power_mode) { + case MMC_POWER_UP: + set_bit(RK29_SDMMC_CARD_NEED_INIT, &host->flags); + rk29_sdmmc_write(host->regs, SDMMC_PWREN, 1); + break; + default: + break; + } +} + +static int rk29_sdmmc_get_ro(struct mmc_host *mmc) +{ + struct rk29_sdmmc *host = mmc_priv(mmc); + u32 wrtprt = rk29_sdmmc_read(host->regs, SDMMC_WRTPRT); + + return (wrtprt & SDMMC_WRITE_PROTECT)?1:0; +} + + +static int rk29_sdmmc_get_cd(struct mmc_host *mmc) +{ + struct rk29_sdmmc *host = mmc_priv(mmc); + u32 cdetect = rk29_sdmmc_read(host->regs, SDMMC_CDETECT); + + return (cdetect & SDMMC_CARD_DETECT_N)?0:1; +} + +static void rk29_sdmmc_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + u32 intmask; + unsigned long flags; + struct rk29_sdmmc *host = mmc_priv(mmc); + + spin_lock_irqsave(&host->lock, flags); + intmask = rk29_sdmmc_read(host->regs, SDMMC_INTMASK); + if(enable) + rk29_sdmmc_write(host->regs, SDMMC_INTMASK, intmask | SDMMC_INT_SDIO); + else + rk29_sdmmc_write(host->regs, SDMMC_INTMASK, intmask & ~SDMMC_INT_SDIO); + spin_unlock_irqrestore(&host->lock, flags); +} + +static const struct mmc_host_ops rk29_sdmmc_ops[] = { + { + .request = rk29_sdmmc_request, + .set_ios = rk29_sdmmc_set_ios, + .get_ro = rk29_sdmmc_get_ro, + .get_cd = rk29_sdmmc_get_cd, + }, + { + .request = rk29_sdmmc_request, + .set_ios = rk29_sdmmc_set_ios, + .enable_sdio_irq = rk29_sdmmc_enable_sdio_irq, + }, +}; + +static void rk29_sdmmc_request_end(struct rk29_sdmmc *host, struct mmc_request *mrq) + __releases(&host->lock) + __acquires(&host->lock) +{ + struct mmc_host *prev_mmc = host->mmc; + + WARN_ON(host->cmd || host->data); + host->curr_mrq = NULL; + if (!list_empty(&host->queue)) { + host = list_entry(host->queue.next, + struct rk29_sdmmc, queue_node); + list_del(&host->queue_node); + host->state = STATE_SENDING_CMD; + rk29_sdmmc_start_request(host); + } else { + dev_vdbg(&host->pdev->dev, "list empty\n"); + host->state = STATE_IDLE; + } + + spin_unlock(&host->lock); + mmc_request_done(prev_mmc, mrq); + + spin_lock(&host->lock); +} + +static void rk29_sdmmc_command_complete(struct rk29_sdmmc *host, + struct mmc_command *cmd) +{ + u32 status = host->cmd_status; + + host->cmd_status = 0; + + if(cmd->flags & MMC_RSP_PRESENT) { + + if(cmd->flags & MMC_RSP_136) { + + /* Read the response from the card (up to 16 bytes). + * RK29 SDMMC controller saves bits 127-96 in SDMMC_RESP3 + * for easy parsing. But the UNSTUFF_BITS macro in core/mmc.c + * core/sd.c expect those bits be in resp[0]. Hence + * reverse the response word order. + */ + cmd->resp[3] = rk29_sdmmc_read(host->regs, SDMMC_RESP0); + cmd->resp[2] = rk29_sdmmc_read(host->regs, SDMMC_RESP1); + cmd->resp[1] = rk29_sdmmc_read(host->regs, SDMMC_RESP2); + cmd->resp[0] = rk29_sdmmc_read(host->regs, SDMMC_RESP3); + } else { + cmd->resp[0] = rk29_sdmmc_read(host->regs, SDMMC_RESP0); + cmd->resp[1] = 0; + cmd->resp[2] = 0; + cmd->resp[3] = 0; + } + } + + if (status & SDMMC_INT_RTO) + cmd->error = -ETIMEDOUT; + else if ((cmd->flags & MMC_RSP_CRC) && (status & SDMMC_INT_RCRC)) + cmd->error = -EILSEQ; + else if (status & SDMMC_INT_RE) + cmd->error = -EIO; + else + cmd->error = 0; + + if (cmd->error) { + dev_vdbg(&host->pdev->dev, + "command error: status=0x%08x resp=0x%08x\n" + "cmd=0x%08x arg=0x%08x flg=0x%08x err=%d\n", + status, cmd->resp[0], + cmd->opcode, cmd->arg, cmd->flags, cmd->error); + + if (cmd->data) { + host->data = NULL; + rk29_sdmmc_stop_dma(host); + } + } +} + +static void rk29_sdmmc_tasklet_func(unsigned long priv) +{ + struct rk29_sdmmc *host = (struct rk29_sdmmc *)priv; + struct mmc_request *mrq = host->curr_mrq; + struct mmc_data *data = host->data; + struct mmc_command *cmd = host->cmd; + enum rk29_sdmmc_state state = host->state; + enum rk29_sdmmc_state prev_state; + u32 status; + + spin_lock(&host->lock); + + state = host->state; + + do { + prev_state = state; + + switch (state) { + case STATE_IDLE: + break; + + case STATE_SENDING_CMD: + if (!rk29_sdmmc_test_and_clear_pending(host, + EVENT_CMD_COMPLETE)) + break; + + host->cmd = NULL; + rk29_sdmmc_set_completed(host, EVENT_CMD_COMPLETE); + rk29_sdmmc_command_complete(host, mrq->cmd); + if (!mrq->data || cmd->error) { + rk29_sdmmc_request_end(host, host->curr_mrq); + goto unlock; + } + + prev_state = state = STATE_SENDING_DATA; + /* fall through */ + + case STATE_SENDING_DATA: + if (rk29_sdmmc_test_and_clear_pending(host, + EVENT_DATA_ERROR)) { + rk29_sdmmc_stop_dma(host); + if (data->stop) + send_stop_cmd(host, data); + state = STATE_DATA_ERROR; + break; + } + + if (!rk29_sdmmc_test_and_clear_pending(host, + EVENT_XFER_COMPLETE)) + break; + + rk29_sdmmc_set_completed(host, EVENT_XFER_COMPLETE); + prev_state = state = STATE_DATA_BUSY; + /* fall through */ + + case STATE_DATA_BUSY: + if (!rk29_sdmmc_test_and_clear_pending(host, + EVENT_DATA_COMPLETE)) + break; + + host->data = NULL; + rk29_sdmmc_set_completed(host, EVENT_DATA_COMPLETE); + status = host->data_status; + + if (unlikely(status & RK29_SDMMC_DATA_ERROR_FLAGS)) { + if (status & SDMMC_INT_DTO) { + dev_err(&host->pdev->dev, + "data timeout error\n"); + data->error = -ETIMEDOUT; + } else if (status & SDMMC_INT_DCRC) { + dev_err(&host->pdev->dev, + "data CRC error\n"); + data->error = -EILSEQ; + } else { + dev_err(&host->pdev->dev, + "data FIFO error (status=%08x)\n", + status); + data->error = -EIO; + } + } + else { + data->bytes_xfered = data->blocks * data->blksz; + data->error = 0; + } + + if (!data->stop) { + rk29_sdmmc_request_end(host, host->curr_mrq); + goto unlock; + } + + prev_state = state = STATE_SENDING_STOP; + if (!data->error) + send_stop_cmd(host, data); + /* fall through */ + + case STATE_SENDING_STOP: + if (!rk29_sdmmc_test_and_clear_pending(host, + EVENT_CMD_COMPLETE)) + break; + + host->cmd = NULL; + rk29_sdmmc_command_complete(host, mrq->stop); + rk29_sdmmc_request_end(host, host->curr_mrq); + goto unlock; + case STATE_DATA_ERROR: + if (!rk29_sdmmc_test_and_clear_pending(host, + EVENT_XFER_COMPLETE)) + break; + + state = STATE_DATA_BUSY; + break; + } + } while (state != prev_state); + + host->state = state; + +unlock: + spin_unlock(&host->lock); + +} + + + +inline static void rk29_sdmmc_push_data(struct rk29_sdmmc *host, void *buf,int cnt) +{ + u32* pData = (u32*)buf; + + if (cnt % 4 != 0) + printk("error not align 4\n"); + + cnt = cnt >> 2; + while (cnt > 0) { + rk29_sdmmc_write(host->regs, SDMMC_DATA,*pData++); + cnt--; + } +} + +inline static void rk29_sdmmc_pull_data(struct rk29_sdmmc *host,void *buf,int cnt) +{ + u32* pData = (u32*)buf; + + if (cnt % 4 != 0) + printk("error not align 4\n"); + cnt = cnt >> 2; + while (cnt > 0) { + *pData++ = rk29_sdmmc_read(host->regs, SDMMC_DATA); + cnt--; + } +} + +static void rk29_sdmmc_read_data_pio(struct rk29_sdmmc *host) +{ + struct scatterlist *sg = host->sg; + void *buf = sg_virt(sg); + unsigned int offset = host->pio_offset; + struct mmc_data *data = host->data; + u32 status; + unsigned int nbytes = 0,len,old_len,count =0; + + do { + len = SDMMC_GET_FCNT(rk29_sdmmc_read(host->regs, SDMMC_STATUS)) << 2; + if(count == 0) + old_len = len; + if (likely(offset + len <= sg->length)) { + rk29_sdmmc_pull_data(host, (void *)(buf + offset),len); + + offset += len; + nbytes += len; + + if (offset == sg->length) { + flush_dcache_page(sg_page(sg)); + host->sg = sg = sg_next(sg); + if (!sg) + goto done; + offset = 0; + buf = sg_virt(sg); + } + } else { + unsigned int remaining = sg->length - offset; + rk29_sdmmc_pull_data(host, (void *)(buf + offset),remaining); + nbytes += remaining; + + flush_dcache_page(sg_page(sg)); + host->sg = sg = sg_next(sg); + if (!sg) + goto done; + offset = len - remaining; + buf = sg_virt(sg); + rk29_sdmmc_pull_data(host, buf,offset); + nbytes += offset; + } + + status = rk29_sdmmc_read(host->regs, SDMMC_MINTSTS); + rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_RXDR); // clear RXDR interrupt + if (status & RK29_SDMMC_DATA_ERROR_FLAGS) { + host->data_status = status; + data->bytes_xfered += nbytes; + smp_wmb(); + rk29_sdmmc_set_pending(host, EVENT_DATA_ERROR); + tasklet_schedule(&host->tasklet); + return; + } + count ++; + } while (status & SDMMC_INT_RXDR); // if the RXDR is ready let read again + len = SDMMC_GET_FCNT(rk29_sdmmc_read(host->regs, SDMMC_STATUS)); + host->pio_offset = offset; + data->bytes_xfered += nbytes; + return; + +done: + data->bytes_xfered += nbytes; + smp_wmb(); + rk29_sdmmc_set_pending(host, EVENT_XFER_COMPLETE); +} + +static void rk29_sdmmc_write_data_pio(struct rk29_sdmmc *host) +{ + struct scatterlist *sg = host->sg; + void *buf = sg_virt(sg); + unsigned int offset = host->pio_offset; + struct mmc_data *data = host->data; + u32 status; + unsigned int nbytes = 0,len; + + do { + + len = SDMMC_FIFO_SZ - (SDMMC_GET_FCNT(rk29_sdmmc_read(host->regs, SDMMC_STATUS)) << 2); + if (likely(offset + len <= sg->length)) { + rk29_sdmmc_push_data(host, (void *)(buf + offset),len); + + offset += len; + nbytes += len; + if (offset == sg->length) { + host->sg = sg = sg_next(sg); + if (!sg) + goto done; + + offset = 0; + buf = sg_virt(sg); + } + } else { + unsigned int remaining = sg->length - offset; + + rk29_sdmmc_push_data(host, (void *)(buf + offset), remaining); + nbytes += remaining; + + host->sg = sg = sg_next(sg); + if (!sg) { + goto done; + } + + offset = len - remaining; + buf = sg_virt(sg); + rk29_sdmmc_push_data(host, (void *)buf, offset); + nbytes += offset; + } + + status = rk29_sdmmc_read(host->regs, SDMMC_MINTSTS); + rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_TXDR); // clear RXDR interrupt + if (status & RK29_SDMMC_DATA_ERROR_FLAGS) { + host->data_status = status; + data->bytes_xfered += nbytes; + smp_wmb(); + rk29_sdmmc_set_pending(host, EVENT_DATA_ERROR); + tasklet_schedule(&host->tasklet); + return; + } + } while (status & SDMMC_INT_TXDR); // if TXDR, let write again + + host->pio_offset = offset; + data->bytes_xfered += nbytes; + + return; + +done: + data->bytes_xfered += nbytes; + smp_wmb(); + rk29_sdmmc_set_pending(host, EVENT_XFER_COMPLETE); +} + +static void rk29_sdmmc_cmd_interrupt(struct rk29_sdmmc *host, u32 status) +{ + if(!host->cmd_status) + host->cmd_status = status; + + smp_wmb(); + rk29_sdmmc_set_pending(host, EVENT_CMD_COMPLETE); + tasklet_schedule(&host->tasklet); +} + +static irqreturn_t rk29_sdmmc_interrupt(int irq, void *dev_id) +{ + struct rk29_sdmmc *host = dev_id; + u32 status, pending; + unsigned int pass_count = 0; + bool present; + bool present_old; + + spin_lock(&host->lock); + do { + status = rk29_sdmmc_read(host->regs, SDMMC_RINTSTS); + pending = rk29_sdmmc_read(host->regs, SDMMC_MINTSTS);// read only mask reg + if (!pending) + break; + if(pending & SDMMC_INT_CD) { + writel(SDMMC_INT_CD, host->regs + SDMMC_RINTSTS); // clear sd detect int + + present = rk29_sdmmc_get_cd(host->mmc); + present_old = test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); + if(present != present_old) { + + if (present != 0) { + set_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); + } else { + clear_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); + } + if(host->pdev->id ==0) { //sdmmc0 + mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(RK_SDMMC0_SWITCH_POLL_DELAY)); + } else { //sdio + mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(20)); + } + } + } + if(pending & RK29_SDMMC_CMD_ERROR_FLAGS) { + rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,RK29_SDMMC_CMD_ERROR_FLAGS); // clear interrupt + host->cmd_status = status; + smp_wmb(); + rk29_sdmmc_set_pending(host, EVENT_CMD_COMPLETE); + tasklet_schedule(&host->tasklet); + } + + if (pending & RK29_SDMMC_DATA_ERROR_FLAGS) { // if there is an error, let report DATA_ERROR + rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,RK29_SDMMC_DATA_ERROR_FLAGS); // clear interrupt + host->data_status = status; + smp_wmb(); + rk29_sdmmc_set_pending(host, EVENT_DATA_ERROR); + tasklet_schedule(&host->tasklet); + } + + + if(pending & SDMMC_INT_DTO) { + rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_DTO); // clear interrupt + if (!host->data_status) + host->data_status = status; + smp_wmb(); + if(host->dir_status == RK29_SDMMC_RECV_STATUS) { + if(host->sg != NULL) + rk29_sdmmc_read_data_pio(host); + } + rk29_sdmmc_set_pending(host, EVENT_DATA_COMPLETE); + tasklet_schedule(&host->tasklet); + } + + if (pending & SDMMC_INT_RXDR) { + rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_RXDR); // clear interrupt + if(host->sg) + rk29_sdmmc_read_data_pio(host); + } + + if (pending & SDMMC_INT_TXDR) { + rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_TXDR); // clear interrupt + if(host->sg) { + rk29_sdmmc_write_data_pio(host); + } + } + + if (pending & SDMMC_INT_CMD_DONE) { + rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_CMD_DONE); // clear interrupt + rk29_sdmmc_cmd_interrupt(host, status); + } + } while (pass_count++ < 5); + + spin_unlock(&host->lock); + + return pass_count ? IRQ_HANDLED : IRQ_NONE; +} + +/* + * + * MMC card detect thread, kicked off from detect interrupt, 1 timer + * + */ +static void rk29_sdmmc_detect_change(unsigned long data) +{ + struct mmc_request *mrq; + struct rk29_sdmmc *host = (struct rk29_sdmmc *)data;; + + smp_rmb(); + if (test_bit(RK29_SDMMC_SHUTDOWN, &host->flags)) + return; + spin_lock(&host->lock); + /* Clean up queue if present */ + mrq = host->mrq; + if (mrq) { + if (mrq == host->curr_mrq) { + /* reset all blocks */ + rk29_sdmmc_write(host->regs, SDMMC_CTRL, (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET)); + /* wait till resets clear */ + while (rk29_sdmmc_read(host->regs, SDMMC_CTRL) & (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET)); + rk29_sdmmc_write(host->regs, SDMMC_CTRL, SDMMC_CTRL_INT_ENABLE); + host->data = NULL; + host->cmd = NULL; + + switch (host->state) { + case STATE_IDLE: + break; + case STATE_SENDING_CMD: + mrq->cmd->error = -ENOMEDIUM; + if (!mrq->data) + break; + /* fall through */ + case STATE_SENDING_DATA: + mrq->data->error = -ENOMEDIUM; + rk29_sdmmc_stop_dma(host); + break; + case STATE_DATA_BUSY: + case STATE_DATA_ERROR: + if (mrq->data->error == -EINPROGRESS) + mrq->data->error = -ENOMEDIUM; + if (!mrq->stop) + break; + /* fall through */ + case STATE_SENDING_STOP: + mrq->stop->error = -ENOMEDIUM; + break; + } + + rk29_sdmmc_request_end(host, mrq); + } else { + list_del(&host->queue_node); + mrq->cmd->error = -ENOMEDIUM; + if (mrq->data) + mrq->data->error = -ENOMEDIUM; + if (mrq->stop) + mrq->stop->error = -ENOMEDIUM; + + spin_unlock(&host->lock); + mmc_request_done(host->mmc, mrq); + spin_lock(&host->lock); + } + + } + mmc_detect_change(host->mmc, 0); +} + +static int rk29_sdmmc_probe(struct platform_device *pdev) +{ + struct mmc_host *mmc; + struct rk29_sdmmc *host; + struct resource *regs; + struct rk29_sdmmc_platform_data *pdata; + int irq; + int ret = 0; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) + return -ENXIO; + + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + mmc = mmc_alloc_host(sizeof(struct rk29_sdmmc), &pdev->dev); + if (!mmc) + return -ENOMEM; + + host = mmc_priv(mmc); + host->mmc = mmc; + host->pdev = pdev; + pdata = pdev->dev.platform_data; + if (!pdata) { + dev_err(&pdev->dev, "Platform data missing\n"); + ret = -ENODEV; + goto err_freehost; + } + + spin_lock_init(&host->lock); + INIT_LIST_HEAD(&host->queue); + + ret = -ENOMEM; + host->regs = ioremap(regs->start, regs->end - regs->start); + if (!host->regs) + goto err_freehost; + +#ifdef USE_DMA + if((strncmp(host->dma_name, "sdio", strlen("sdio")) == 1) + host->dma_chn = rk29_dma_request(DMACH_SDIO, &rk29_dma_sdio1_client, NULL); + if((strncmp(host->dma_name, "sd_mmc", strlen("sd_mmc")) == 1) + host->dma_chn = rk29_dma_request(DMACH_SDMMC, &rk29_dma_sdmmc0_client, NULL); + rk29_dma_config(host->dma_chn, 16); + rk29_dma_set_buffdone_fn(host->dma_chn, rk29_sdmmc_dma_complete) +#endif + host->bus_hz = 25000000; ////cgu_get_clk_freq(CGU_SB_SD_MMC_CCLK_IN_ID); + + /* reset all blocks */ + rk29_sdmmc_write(host->regs, SDMMC_CTRL,(SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET)); + /* wait till resets clear */ + while (rk29_sdmmc_read(host->regs, SDMMC_CTRL) & (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET)); + + /* Clear the interrupts for the host controller */ + rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, 0xFFFFFFFF); + rk29_sdmmc_write(host->regs, SDMMC_INTMASK, 0); // disable all mmc interrupt first + + /* Put in max timeout */ + rk29_sdmmc_write(host->regs, SDMMC_TMOUT, 0xFFFFFFFF); + + /* FIFO threshold settings */ + rk29_sdmmc_write(host->regs, SDMMC_FIFOTH, ((0x3 << 28) | (0x0f << 16) | (0x10 << 0))); // RXMark = 15, TXMark = 16, DMA Size = 16 + + /* disable clock to CIU */ + rk29_sdmmc_write(host->regs, SDMMC_CLKENA,0); + rk29_sdmmc_write(host->regs, SDMMC_CLKSRC,0); + rk29_sdmmc_write(host->regs, SDMMC_PWREN, 1); + tasklet_init(&host->tasklet, rk29_sdmmc_tasklet_func, (unsigned long)host); + + ret = request_irq(irq, rk29_sdmmc_interrupt, 0, dev_name(&pdev->dev), host); + if (ret) + goto err_dmaunmap; + + platform_set_drvdata(pdev, host); + memcpy(host->dma_name, pdata->dma_name, 8); + mmc->ops = &rk29_sdmmc_ops[pdev->id]; + mmc->f_min = DIV_ROUND_UP(host->bus_hz, 510); + mmc->f_max = host->bus_hz/2; //max f is clock to mmc_clk/2 + mmc->ocr_avail = pdata->host_ocr_avail; + mmc->caps = pdata->host_caps; + mmc->max_phys_segs = 64; + mmc->max_hw_segs = 64; + mmc->max_blk_size = 65536; /* SDMMC_BLKSIZ is 16 bits*/ + mmc->max_blk_count = 512; + mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; + mmc->max_seg_size = mmc->max_req_size; + + /* Assume card is present initially */ + if(!rk29_sdmmc_get_cd(host->mmc)) + set_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); + else + clear_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); + + mmc_add_host(mmc); + + +#if defined (CONFIG_DEBUG_FS) + rk29_sdmmc_init_debugfs(host); +#endif + + /* Create card detect handler thread */ + setup_timer(&host->detect_timer, rk29_sdmmc_detect_change,(unsigned long)host); + + // enable interrupt for command done, data over, data empty, receive ready and error such as transmit, receive timeout, crc error + rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, 0xFFFFFFFF); + rk29_sdmmc_write(host->regs, SDMMC_INTMASK,SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_TXDR | SDMMC_INT_RXDR | RK29_SDMMC_ERROR_FLAGS); + rk29_sdmmc_write(host->regs, SDMMC_CTRL,SDMMC_CTRL_INT_ENABLE); // enable mci interrupt + + + dev_info(&pdev->dev, "RK29 SDMMC controller at irq %d\n", irq); + + return 0; +err_dmaunmap: +#ifdef USE_DMA + if((strncmp(host->dma_name, "sdio", strlen("sdio")) == 1) + rk29_dma_free(DMACH_SDIO, &rk29_dma_sdio1_client); + if((strncmp(host->dma_name, "sd_mmc", strlen("sd_mmc")) == 1) + rk29_dma_free(DMACH_SDMMC, &rk29_dma_sdmmc0_client); +err_freemap: +#endif + iounmap(host->regs); +err_freehost: + kfree(host); + return ret; +} + + + +static int __exit rk29_sdmmc_remove(struct platform_device *pdev) +{ + struct rk29_sdmmc *host = platform_get_drvdata(pdev); + + rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, 0xFFFFFFFF); + rk29_sdmmc_write(host->regs, SDMMC_INTMASK, 0); // disable all mmc interrupt first + + /* Shutdown detect IRQ and kill detect thread */ + del_timer_sync(&host->detect_timer); + + /* Debugfs stuff is cleaned up by mmc core */ + set_bit(RK29_SDMMC_SHUTDOWN, &host->flags); + smp_wmb(); + mmc_remove_host(host->mmc); + mmc_free_host(host->mmc); + + /* disable clock to CIU */ + rk29_sdmmc_write(host->regs, SDMMC_CLKENA,0); + rk29_sdmmc_write(host->regs, SDMMC_CLKSRC,0); + + free_irq(platform_get_irq(pdev, 0), host); +#ifdef USE_DMA + if((strncmp(host->dma_name, "sdio", strlen("sdio")) == 1) + rk29_dma_free(DMACH_SDIO, &rk29_dma_sdio1_client); + if((strncmp(host->dma_name, "sd_mmc", strlen("sd_mmc")) == 1) + rk29_dma_free(DMACH_SDMMC, &rk29_dma_sdmmc0_client); +#endif + iounmap(host->regs); + + kfree(host); + return 0; +} + +static int rk29_sdmmc_suspend(struct platform_device *pdev, pm_message_t state) +{ +#ifdef CONFIG_PM + struct rk29_sdmmc *host = platform_get_drvdata(pdev); + rk29_sdmmc_write(host->regs, SDMMC_CLKENA, 0); + clk_disable(host->clk); +#endif + return 0; +} + +static int rk29_sdmmc_resume(struct platform_device *pdev) +{ +#ifdef CONFIG_PM + struct rk29_sdmmc *host = platform_get_drvdata(pdev); + clk_enable(host->clk); +#endif + return 0; +} + +static struct platform_driver rk29_sdmmc_driver = { + .suspend = rk29_sdmmc_suspend, + .resume = rk29_sdmmc_resume, + .remove = __exit_p(rk29_sdmmc_remove), + .driver = { + .name = "rk29_sdmmc", + }, +}; + +static int __init rk29_sdmmc_init(void) +{ + return platform_driver_probe(&rk29_sdmmc_driver, rk29_sdmmc_probe); +} + +static void __exit rk29_sdmmc_exit(void) +{ + platform_driver_unregister(&rk29_sdmmc_driver); +} + +module_init(rk29_sdmmc_init); +module_exit(rk29_sdmmc_exit); + +MODULE_DESCRIPTION("Rk29 Multimedia Card Interface driver"); +MODULE_AUTHOR("Rockchips"); +MODULE_LICENSE("GPL v2"); + \ No newline at end of file diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 6e999604337e..623a645b808e 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -365,6 +365,11 @@ config MTD_NAND_RK2818 depends on ARCH_RK2818 help This enables the NAND flash controller on the RK2818 SoC +config MTD_NAND_RK29 + tristate "NAND Flash support for RK29sdk" + depends on ARCH_RK29 + help + This enables the NAND flash controller on the RK29 SoC config MTD_NAND_PXA3xx tristate "Support for NAND flash devices on PXA3xx" diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 063518202051..36ee8b51a510 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -43,5 +43,5 @@ obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o obj-$(CONFIG_MTD_NAND_W90P910) += w90p910_nand.o obj-$(CONFIG_MTD_NAND_NOMADIK) += nomadik_nand.o obj-$(CONFIG_MTD_NAND_RK2818) += rk2818_nand.o - +obj-$(CONFIG_MTD_NAND_RK29) += rk29_nand.o nand-objs := nand_base.o nand_bbt.o diff --git a/drivers/mtd/nand/rk29_nand.c b/drivers/mtd/nand/rk29_nand.c new file mode 100644 index 000000000000..dc36e5fbd73f --- /dev/null +++ b/drivers/mtd/nand/rk29_nand.c @@ -0,0 +1,1096 @@ + +/* + * drivers/mtd/nand/rk29_nand.c + * + * Copyright (C) 2010 RockChip, Inc. + * Author: hxy@rock-chips.com + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define PROGRAM_BUSY_COUNT 10000 +#define ERASE_BUSY_COUNT 20000 +#define READ_BUSY_COUNT 5000 +#define RESET_BUSY_COUNT 20000 + +/* Define delays in microsec for NAND device operations */ +#define TROP_US_DELAY 2000 + + +#ifdef CONFIG_DM9000_USE_NAND_CONTROL +static DEFINE_MUTEX(rknand_mutex); +#define RKNAND_LOCK() do { int panic = in_interrupt() | in_atomic(); if (!panic) mutex_lock(&rknand_mutex); } while (0) +#define RKNAND_UNLOCK() do { int panic = in_interrupt() | in_atomic(); if (!panic) mutex_unlock(&rknand_mutex); } while (0) +#else +#define RKNAND_LOCK() do {} while (0) +#define RKNAND_UNLOCK() do {} while (0) +#endif + +struct rk29_nand_mtd { + struct mtd_info mtd; + struct nand_chip nand; + struct mtd_partition *parts; + struct device *dev; + const struct rk29_nand_flash *flash_info; + + struct clk *clk; + unsigned long clk_rate; + void __iomem *regs; + int cs; // support muliple nand chip,record current chip select + u_char accesstime; +#ifdef CONFIG_CPU_FREQ + struct notifier_block freq_transition; +#endif + +}; + +/* OOB placement block for use with software ecc generation */ +static struct nand_ecclayout nand_sw_eccoob_8 = { + .eccbytes = 48, + .eccpos = { 8, 9, 10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, + 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55}, + .oobfree = {{0,8},{56, 72}} +}; + +/* OOB placement block for use with hardware ecc generation */ +static struct nand_ecclayout nand_hw_eccoob_16 = { + .eccbytes = 28, + .eccpos = { 4, 5, 6, 7, 8, 9, 10,11,12,13,14,15,16,17, + 18,19,20,21,22,23,24,25,26,27,28,29,30,31}, + .oobfree = {{0, 4}} +}; + +#ifdef CONFIG_MTD_PARTITIONS +static const char *part_probes[] = { "cmdlinepart", NULL }; +#endif + + +static void rk29_nand_wait_busy(struct mtd_info *mtd, uint32_t timeout) +{ + + struct nand_chip *nand_chip = mtd->priv; + struct rk29_nand_mtd *master = nand_chip->priv; + pNANDC pRK29NC= (pNANDC)(master->regs); + + while (timeout > 0) + { + timeout--; + udelay(10); + if ( pRK29NC->FMCTL& FMC_FRDY) + break; + + } + + return; +} + +static void rk29_nand_wait_bchdone(struct mtd_info *mtd, uint32_t timeout) +{ + + struct nand_chip *nand_chip = mtd->priv; + struct rk29_nand_mtd *master = nand_chip->priv; + pNANDC pRK29NC= (pNANDC)(master->regs); + + while (timeout > 0) + { + timeout--; + udelay(1); + if(pRK29NC->BCHST &(1<<1)) + break; + } + + return; +} + +// only for dma mode +static void wait_op_done(struct mtd_info *mtd, int max_retries, uint16_t param) +{ + struct nand_chip *nand_chip = mtd->priv; + struct rk29_nand_mtd *master = nand_chip->priv; + pNANDC pRK29NC= (pNANDC)(master->regs); + + while (max_retries-- > 0) { + udelay(1); + if (pRK29NC->FLCTL & FL_RDY) + break; + } +} + +static int rk29_nand_dev_ready(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd->priv; + struct rk29_nand_mtd *master = nand_chip->priv; + pNANDC pRK29NC= (pNANDC)(master->regs); + + if(pRK29NC->FMCTL& FMC_FRDY) + return 1; + else + return 0; +} + +/* +* 设置片选 +*/ +static void rk29_nand_select_chip(struct mtd_info *mtd, int chip) +{ + struct nand_chip *nand_chip = mtd->priv; + struct rk29_nand_mtd *master = nand_chip->priv; + pNANDC pRK29NC= (pNANDC)(master->regs); + + + if( chip<0 ) + pRK29NC->FMCTL &=0xffffff00; // release chip select + else + { + master->cs = chip; + pRK29NC->FMCTL &=0xffffff00; + pRK29NC ->FMCTL |= 0x1<priv; + struct rk29_nand_mtd *master = nand_chip->priv; + pNANDC pRK29NC= (pNANDC)(master->regs); + + u_char ret = 0; + + ret = (u_char)(pRK29NC ->chip[master->cs].data); + + return ret; +} + +/* + * 读一个word 长度数据 +*/ +static u16 rk29_nand_read_word(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd->priv; + struct rk29_nand_mtd *master = nand_chip->priv; + pNANDC pRK29NC= (pNANDC)(master->regs); + + + u_char tmp1 = 0,tmp2=0; + u16 ret=0; + + tmp1 = (u_char)(pRK29NC ->chip[master->cs].data); + tmp2 = (u_char)(pRK29NC ->chip[master->cs].data); + + ret = (tmp2 <<8)|tmp1; + + return ret; +} + +static void rk29_nand_read_buf(struct mtd_info *mtd, u_char* const buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + struct rk29_nand_mtd *master = nand_chip->priv; + pNANDC pRK29NC= (pNANDC)(master->regs); + uint32_t i, chipnr; + + RKNAND_LOCK(); + + chipnr = master->cs ; + + rk29_nand_select_chip(mtd,chipnr); + + + + if ( len < mtd->writesize ) // read oob + { + pRK29NC ->BCHCTL = BCH_RST; + pRK29NC ->FLCTL = (0<<4)|FL_COR_EN|(0x1<<5)|FL_BYPASS|FL_START ; + wait_op_done(mtd,TROP_US_DELAY,0); + rk29_nand_wait_bchdone(mtd,TROP_US_DELAY) ; + memcpy(buf,(u_char *)(pRK29NC->spare),4); // only use nandc sram0 + } + else + { + pRK29NC->FLCTL |= FL_BYPASS; // dma mode + for(i=0;iwritesize/0x400;i++) + { + pRK29NC ->BCHCTL = BCH_RST; + pRK29NC ->FLCTL = (0<<4)|FL_COR_EN|(0x1<<5)|FL_BYPASS|FL_START ; + wait_op_done(mtd,TROP_US_DELAY,0); + rk29_nand_wait_bchdone(mtd,TROP_US_DELAY) ; + memcpy(buf+i*0x400,(u_char *)(pRK29NC->buf),0x400); // only use nandc sram0 + } + } + + + + rk29_nand_select_chip(mtd,-1); + + RKNAND_UNLOCK(); + + + return; + +} + +static void rk29_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + struct rk29_nand_mtd *master = nand_chip->priv; + pNANDC pRK29NC= (pNANDC)(master->regs); + + uint32_t i = 0, chipnr; + + + RKNAND_LOCK(); + + chipnr = master->cs ; + + rk29_nand_select_chip(mtd,chipnr); + + pRK29NC->FLCTL |= FL_BYPASS; // dma mode + + + for(i=0;iwritesize/0x400;i++) + { + memcpy((u_char *)(pRK29NC->buf),buf+i*0x400,0x400); // only use nandc sram0 + pRK29NC ->BCHCTL =BCH_WR|BCH_RST; + pRK29NC ->FLCTL = (0<<4)|FL_COR_EN|0x1<<5|FL_RDN|FL_BYPASS|FL_START; + wait_op_done(mtd,TROP_US_DELAY,0); + } + + + + rk29_nand_select_chip(mtd,-1); + + RKNAND_UNLOCK(); + + +} + + +static void rk29_nand_cmdfunc(struct mtd_info *mtd, unsigned command,int column, int page_addr) +{ + struct nand_chip *nand_chip = mtd->priv; + struct rk29_nand_mtd *master = nand_chip->priv; + pNANDC pRK29NC= (pNANDC)(master->regs); + + uint32_t timeout = 1000; + char status,ret; + + + switch (command) { + + case NAND_CMD_READID: + pRK29NC ->chip[master->cs].cmd = command; + pRK29NC ->chip[master->cs].addr = 0x0; + while (timeout>0) + { + timeout --; + udelay(1); + if(pRK29NC->FLCTL&FL_INTCLR) + break; + + } + + rk29_nand_wait_busy(mtd,READ_BUSY_COUNT); + break; + + case NAND_CMD_READ0: + pRK29NC ->chip[master->cs].cmd = command; + if ( column>= 0 ) + { + pRK29NC ->chip[master->cs].addr = column & 0xff; + if( mtd->writesize > 512) + pRK29NC ->chip[master->cs].addr = (column >> 8) & 0xff; + } + if ( page_addr>=0 ) + { + pRK29NC ->chip[master->cs].addr = page_addr & 0xff; + pRK29NC ->chip[master->cs].addr = (page_addr >> 8) & 0xFF; + pRK29NC ->chip[master->cs].addr = (page_addr >> 16) & 0xff; + } + if( mtd->writesize > 512) + pRK29NC ->chip[0].cmd = NAND_CMD_READSTART; + + rk29_nand_wait_busy(mtd,READ_BUSY_COUNT); + + break; + + case NAND_CMD_READ1: + pRK29NC ->chip[master->cs].cmd = command; + break; + + case NAND_CMD_READOOB: + pRK29NC ->BCHCTL = 0x0; + if( mtd->writesize > 512 ) + command = NAND_CMD_READ0; // 全部读,包括读oob + + pRK29NC ->chip[master->cs].cmd = command; + + if ( mtd->writesize >512 ) + { + if ( column>= 0 ) + { + pRK29NC ->chip[master->cs].addr = column & 0xff; + pRK29NC ->chip[master->cs].addr = ( column >> 8) & 0xff; + } + if ( page_addr>=0 ) + { + pRK29NC ->chip[master->cs].addr = page_addr & 0xff; + pRK29NC ->chip[master->cs].addr = (page_addr >> 8) & 0xFF; + pRK29NC ->chip[master->cs].addr = (page_addr >> 16) & 0xff; + } + pRK29NC ->chip[master->cs].cmd = NAND_CMD_READSTART; + } + else + { + pRK29NC ->chip[master->cs].addr = column; + } + + rk29_nand_wait_busy(mtd,READ_BUSY_COUNT); + + + break; + + case NAND_CMD_PAGEPROG: + pRK29NC ->FMCTL |= FMC_WP; //解除写保护 + pRK29NC ->chip[master->cs].cmd = command; + rk29_nand_wait_busy(mtd,PROGRAM_BUSY_COUNT); + + pRK29NC ->chip[master->cs].cmd = NAND_CMD_STATUS; + status = pRK29NC ->chip[master->cs].data; + + if(status&0x1) + ret = -1; + else + ret =0; + + break; + + case NAND_CMD_ERASE1: + pRK29NC ->FMCTL |= FMC_WP; //解除写保护 + pRK29NC ->BCHCTL = 0x0; + pRK29NC ->chip[master->cs].cmd = command; + if ( page_addr>=0 ) + { + pRK29NC ->chip[master->cs].addr = page_addr & 0xff; + pRK29NC ->chip[master->cs].addr = (page_addr>>8)&0xff; + pRK29NC ->chip[master->cs].addr = (page_addr>>16)&0xff; + } + break; + + case NAND_CMD_ERASE2: + pRK29NC ->FMCTL |= FMC_WP; //解除写保护 + pRK29NC ->chip[master->cs].cmd = command; + rk29_nand_wait_busy(mtd,ERASE_BUSY_COUNT); + pRK29NC ->chip[master->cs].cmd = NAND_CMD_STATUS; + status = pRK29NC ->chip[master->cs].data; + + if(status&0x1) + ret = -1; + else + ret =0; + + break; + + case NAND_CMD_SEQIN: + pRK29NC ->FMCTL |= FMC_WP; //解除写保护 + pRK29NC ->chip[master->cs].cmd = command; + udelay(1); + if ( column>= 0 ) + { + pRK29NC ->chip[master->cs].addr = column; + if( mtd->writesize > 512) + pRK29NC ->chip[master->cs].addr = (column >> 8) & 0xff; + } + if( page_addr>=0 ) + { + pRK29NC ->chip[master->cs].addr = page_addr & 0xff; + pRK29NC ->chip[master->cs].addr = (page_addr>>8)&0xff; + pRK29NC ->chip[master->cs].addr = (page_addr>>16)&0xff; + } + + break; + + case NAND_CMD_STATUS: + pRK29NC ->BCHCTL = 0x0; + pRK29NC ->chip[master->cs].cmd = command; + while (timeout>0) + { + timeout --; + udelay(1); + if(pRK29NC->FLCTL&FL_INTCLR) + break; + + } + break; + + case NAND_CMD_RESET: + pRK29NC ->chip[master->cs].cmd = command; + while (timeout>0) + { + timeout --; + udelay(1); + if(pRK29NC->FLCTL&FL_INTCLR) + break; + + } + rk29_nand_wait_busy(mtd,RESET_BUSY_COUNT); + break; + + /* This applies to read commands */ + default: + pRK29NC ->chip[master->cs].cmd = command; + break; + } + + udelay (1); + +} + +int rk29_nand_calculate_ecc(struct mtd_info *mtd,const uint8_t *dat,uint8_t *ecc_code) +{ + struct nand_chip *nand_chip = mtd->priv; + struct rk29_nand_mtd *master = nand_chip->priv; + pNANDC pRK29NC= (pNANDC)(master->regs); + + int eccdata[7],i; + + for(i=0;i<7;i++) + { + eccdata[i] = pRK29NC->spare[i+1]; + + + ecc_code[i*4] = eccdata[i]& 0xff; + ecc_code[i*4+1] = (eccdata[i]>> 8)& 0xff; + ecc_code[i*4+2] = (eccdata[i]>>16)& 0xff; + ecc_code[i*4+3] = (eccdata[i]>>24)& 0xff; + + } + + return 0; +} + + void rk29_nand_hwctl_ecc(struct mtd_info *mtd, int mode) + { + struct nand_chip *nand_chip = mtd->priv; + struct rk29_nand_mtd *master = nand_chip->priv; + pNANDC pRK29NC= (pNANDC)(master->regs); + + pRK29NC->BCHCTL = 1; // reset bch and enable hw ecc + + return; + } + + int rk29_nand_correct_data(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc,uint8_t *calc_ecc) + { + struct nand_chip *nand_chip = mtd->priv; + struct rk29_nand_mtd *master = nand_chip->priv; + pNANDC pRK29NC= (pNANDC)(master->regs); + + // hw correct data + if( pRK29NC->BCHST & (1<<2) ) + { + DEBUG(MTD_DEBUG_LEVEL0, + "rk2818 nand :hw ecc uncorrectable error\n"); + return -1; + } + + return 0; + } + + int rk29_nand_read_page(struct mtd_info *mtd,struct nand_chip *chip,uint8_t *buf, int page) + { + struct nand_chip *nand_chip = mtd->priv; + struct rk29_nand_mtd *master = nand_chip->priv; + pNANDC pRK29NC= (pNANDC)(master->regs); + + int i,chipnr; + + + RKNAND_LOCK(); + + chipnr = master->cs ; + + rk29_nand_select_chip(mtd,chipnr); + + + rk29_nand_wait_busy(mtd,READ_BUSY_COUNT); + + pRK29NC->FLCTL |= FL_BYPASS; // dma mode + + for(i=0;iwritesize/0x400;i++) + { + pRK29NC ->BCHCTL = BCH_RST; + pRK29NC ->FLCTL = (0<<4)|FL_COR_EN|(0x1<<5)|FL_BYPASS|FL_START ; + wait_op_done(mtd,TROP_US_DELAY,0); + rk29_nand_wait_bchdone(mtd,TROP_US_DELAY) ; + + memcpy(buf+i*0x400,(u_char *)(pRK29NC->buf),0x400); // only use nandc sram0 + } + + + rk29_nand_select_chip(mtd,-1); + + RKNAND_UNLOCK(); + + return 0; + + } + +void rk29_nand_write_page(struct mtd_info *mtd,struct nand_chip *chip,const uint8_t *buf) + { + struct nand_chip *nand_chip = mtd->priv; + struct rk29_nand_mtd *master = nand_chip->priv; + pNANDC pRK29NC= (pNANDC)(master->regs); + uint32_t i = 0, chipnr; + + RKNAND_LOCK(); + + chipnr = master->cs ; + + rk29_nand_select_chip(mtd,chipnr); + + pRK29NC->FLCTL |= FL_BYPASS; // dma mode + + + for(i=0;iwritesize/0x400;i++) + { + memcpy((u_char *)(pRK29NC->buf),(buf+i*0x400),0x400); // only use nandc sram0 + if(i==0) + memcpy((u_char *)(pRK29NC->spare),(u_char *)(chip->oob_poi + chip->ops.ooboffs),4); + + pRK29NC ->BCHCTL = BCH_WR|BCH_RST; + pRK29NC ->FLCTL = (0<<4)|FL_COR_EN|(0x1<<5)|FL_RDN|FL_BYPASS|FL_START; + wait_op_done(mtd,TROP_US_DELAY,0); + } + + pRK29NC ->chip[0].cmd = NAND_CMD_PAGEPROG; + + + + rk29_nand_wait_busy(mtd,PROGRAM_BUSY_COUNT); + + rk29_nand_select_chip(mtd,-1); + + RKNAND_UNLOCK(); + + return; + + } + +int rk29_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int page, int sndcmd) +{ + struct nand_chip *nand_chip = mtd->priv; + struct rk29_nand_mtd *master = nand_chip->priv; + pNANDC pRK29NC= (pNANDC)(master->regs); + int i,chipnr; + + + if (sndcmd) { + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + sndcmd = 0; + } + + RKNAND_LOCK(); + + chipnr = master->cs ; + + rk29_nand_select_chip(mtd,chipnr); + + rk29_nand_wait_busy(mtd,READ_BUSY_COUNT); + + + pRK29NC->FLCTL |= FL_BYPASS; // dma mode + + + + + for(i=0;iwritesize/0x400;i++) + { + pRK29NC ->BCHCTL = BCH_RST; + pRK29NC ->FLCTL = (0<<4)|FL_COR_EN|(0x1<<5)|FL_BYPASS|FL_START ; + wait_op_done(mtd,TROP_US_DELAY,0); + rk29_nand_wait_bchdone(mtd,TROP_US_DELAY) ; + if(i==0) + memcpy((u_char *)(chip->oob_poi+ chip->ops.ooboffs),(u_char *)(pRK29NC->spare),4); + } + + + rk29_nand_select_chip(mtd,-1); + + RKNAND_UNLOCK(); + + + return sndcmd; +} + +int rk29_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) +{ + struct nand_chip *nand_chip = mtd->priv; + struct rk29_nand_mtd *master = nand_chip->priv; + pNANDC pRK29NC= (pNANDC)(master->regs); + + int i,chipnr; + + + RKNAND_LOCK(); + + chipnr = master->cs ; + + rk29_nand_select_chip(mtd,chipnr); + + rk29_nand_wait_busy(mtd,READ_BUSY_COUNT); + + pRK29NC->FLCTL |= FL_BYPASS; // dma mode + + + + for(i=0;iwritesize/0x400;i++) + { + pRK29NC ->BCHCTL = BCH_RST; + pRK29NC ->FLCTL = (0<<4)|FL_COR_EN|(0x1<<5)|FL_BYPASS|FL_START ; + wait_op_done(mtd,TROP_US_DELAY,0); + rk29_nand_wait_bchdone(mtd,TROP_US_DELAY) ; + memcpy(buf+i*0x400,(u_char *)(pRK29NC->buf),0x400); // only use nandc sram0 + if(i==0) + memcpy((u_char *)(chip->oob_poi+ chip->ops.ooboffs),(u_char *)(pRK29NC->spare),4); + } + + + rk29_nand_select_chip(mtd,-1); + RKNAND_UNLOCK(); + + + return 0; +} + +static int rk29_nand_setrate(struct rk29_nand_mtd *info) +{ + pNANDC pRK29NC= (pNANDC)(info->regs); + + unsigned long clkrate = clk_get_rate(info->clk); + + u_char accesstime,rwpw,csrw,rwcs; + + unsigned int ns=0,timingcfg; + + unsigned long flags; + + //scan nand flash access time + if ( info->accesstime ==0x00 ) + accesstime=50; + else if ( info->accesstime==0x80) + accesstime=25; + else if ( info->accesstime==0x08) + accesstime=20; + else + accesstime=60; //60ns +#if 0 + info->clk_rate = clkrate; + clkrate /= 1000000; /* turn clock into MHz for ease of use */ + + if(clkrate>0 && clkrate<200) + ns= 1000/clkrate; // ns + else + return -1; + + timingcfg = (accesstime + ns -1)/ns; + + timingcfg = (timingcfg>=3) ? (timingcfg-2) : timingcfg; //csrw+1, rwcs+1 + + rwpw = timingcfg-timingcfg/4; + csrw = timingcfg/4; + rwcs = (timingcfg/4 >=1)?(timingcfg/4):1; +#else + rwpw = 4; + csrw = 1; + rwcs = 2; +#endif + + RKNAND_LOCK(); + + pRK29NC ->FMWAIT |= (rwcs<clk); + + if (val == CPUFREQ_POSTCHANGE && newclk != info->clk_rate) + { + rk29_nand_setrate(info); + } + + return 0; +} + +static inline int rk29_nand_cpufreq_register(struct rk29_nand_mtd *info) +{ + info->freq_transition.notifier_call = rk29_nand_cpufreq_transition; + + return cpufreq_register_notifier(&info->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); +} + +static inline void rk29_nand_cpufreq_deregister(struct rk29_nand_mtd *info) +{ + cpufreq_unregister_notifier(&info->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); +} + +#else +static inline int rk29_nand_cpufreq_register(struct rk29_nand_mtd *info) +{ + return 0; +} + +static inline void rk29_nand_cpufreq_deregister(struct rk29_nand_mtd *info) +{ +} +#endif + + +static int rk29_nand_probe(struct platform_device *pdev) +{ + struct nand_chip *this; + struct mtd_info *mtd; + struct rk29_nand_platform_data *pdata = pdev->dev.platform_data; + struct rk29_nand_mtd *master; + struct resource *res; + int err = 0; + pNANDC pRK29NC; + u_char maf_id,dev_id,ext_id3,ext_id4; + struct nand_chip *chip; + +#ifdef CONFIG_MTD_PARTITIONS + struct mtd_partition *partitions = NULL; + int num_partitions = 0; +#endif + + /* Allocate memory for MTD device structure and private data */ + master = kzalloc(sizeof(struct rk29_nand_mtd), GFP_KERNEL); + if (!master) + return -ENOMEM; + + master->dev = &pdev->dev; + /* structures must be linked */ + this = &master->nand; + mtd = &master->mtd; + mtd->priv = this; + mtd->owner = THIS_MODULE; + mtd->name = dev_name(&pdev->dev); + + /* 50 us command delay time */ + this->chip_delay = 5; + + this->priv = master; + this->dev_ready = rk29_nand_dev_ready; + this->cmdfunc = rk29_nand_cmdfunc; + this->select_chip = rk29_nand_select_chip; + this->read_byte = rk29_nand_read_byte; + this->read_word = rk29_nand_read_word; + this->write_buf = rk29_nand_write_buf; + this->read_buf = rk29_nand_read_buf; + this->options |= NAND_USE_FLASH_BBT; // open bbt options + + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + err = -ENODEV; + goto outres; + } + + master->regs = ioremap(res->start, res->end - res->start + 1); + if (!master->regs) { + err = -EIO; + goto outres; + } + + if (pdata->hw_ecc) { + this->ecc.calculate = rk29_nand_calculate_ecc; + this->ecc.hwctl = rk29_nand_hwctl_ecc; + this->ecc.correct = rk29_nand_correct_data; + this->ecc.mode = NAND_ECC_HW; + this->ecc.read_page = rk29_nand_read_page; + this->ecc.write_page = rk29_nand_write_page; + this->ecc.read_oob = rk29_nand_read_oob; + this->ecc.read_page_raw = rk29_nand_read_page_raw; + this->ecc.size = 1024; + this->ecc.bytes = 28; + this->ecc.layout = &nand_hw_eccoob_16; + } else { + this->ecc.size = 256; + this->ecc.bytes = 3; + this->ecc.layout = &nand_sw_eccoob_8; + this->ecc.mode = NAND_ECC_SOFT; + } + + + + master->clk = clk_get(NULL, "nandc"); + + clk_enable(master->clk); + + pRK29NC = (pNANDC)(master->regs); + pRK29NC ->FMCTL = FMC_WP|FMC_FRDY; + pRK29NC ->FMWAIT |= (1<BCHCTL = 0x1; + + this->select_chip(mtd, 0); + this->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + maf_id = this->read_byte(mtd); + dev_id = this->read_byte(mtd); + ext_id3 = this->read_byte(mtd); + ext_id4 = this->read_byte(mtd); + + master->accesstime = ext_id4&0x88; + + rk29_nand_setrate(master); + + /* Reset NAND */ + this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + /* NAND bus width determines access funtions used by upper layer */ + if (pdata->width == 2) { + this->options |= NAND_BUSWIDTH_16; + this->ecc.layout = &nand_hw_eccoob_16; + } + // iomux flash cs1~cs7 + if (pdata && pdata->io_init) { + pdata->io_init(); + } + + /* Scan to find existence of the device */ +#if 0 + if (nand_scan(mtd, 8)) { // rk2818 nandc support max 8 cs +#else + if (nand_scan(mtd, 1)) { // test for fpga board nand +#endif + DEBUG(MTD_DEBUG_LEVEL0, + "RK2818 NAND: Unable to find any NAND device.\n"); + err = -ENXIO; + goto outscan; + } + + //根据片选情况恢复IO MUX原始值 +#if 0 + chip = mtd->priv; + switch(chip->numchips) + { + case 1: + rk2818_mux_api_mode_resume(GPIOA5_FLASHCS1_SEL_NAME); + case 2: + rk2818_mux_api_mode_resume(GPIOA6_FLASHCS2_SEL_NAME); + case 3: + rk2818_mux_api_mode_resume(GPIOA7_FLASHCS3_SEL_NAME); + case 4: + rk2818_mux_api_mode_resume(GPIOE_SPI1_FLASH_SEL1_NAME); + case 5: + case 6: + rk2818_mux_api_mode_resume(GPIOE_SPI1_FLASH_SEL_NAME); + case 7: + case 8: + break; + default: + DEBUG(MTD_DEBUG_LEVEL0, "RK2818 NAND: numchips error!!!\n"); + } +#endif +#if 0 + // rk281x dma mode bch must (1k data + 32 oob) bytes align , so cheat system writesize =1024,oobsize=32 + mtd->writesize = 1024; + mtd->oobsize = 32; +#endif + +#ifdef CONFIG_MTD_PARTITIONS + num_partitions = parse_mtd_partitions(mtd, part_probes, &partitions, 0); + if (num_partitions > 0) { + printk(KERN_INFO "Using commandline partition definition\n"); + add_mtd_partitions(mtd, partitions, num_partitions); + if(partitions) + kfree(partitions); + } else if (pdata->nr_parts) { + printk(KERN_INFO "Using board partition definition\n"); + add_mtd_partitions(mtd, pdata->parts, pdata->nr_parts); + } else +#endif + { + printk(KERN_INFO "no partition info available, registering whole flash at once\n"); + add_mtd_device(mtd); + } + + platform_set_drvdata(pdev, master); + + err =rk29_nand_cpufreq_register(master); + if (err < 0) { + printk(KERN_ERR"rk2818 nand failed to init cpufreq support\n"); + goto outscan; + } + + return 0; + +outres: +outscan: + iounmap(master->regs); + kfree(master); + + return err; + +} + +static int rk29_nand_remove(struct platform_device *pdev) +{ + struct rk29_nand_mtd *master = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + + if(master == NULL) + return 0; + + rk29_nand_cpufreq_deregister(master); + + + nand_release(&master->mtd); + + if(master->regs!=NULL){ + iounmap(master->regs); + master->regs = NULL; + } + + if (master->clk != NULL && !IS_ERR(master->clk)) { + clk_disable(master->clk); + clk_put(master->clk); + } + + kfree(master); + + return 0; +} + +#ifdef CONFIG_PM +static int rk29_nand_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct mtd_info *info = platform_get_drvdata(pdev); + int ret = 0; + + DEBUG(MTD_DEBUG_LEVEL0, "RK2818_NAND : NAND suspend\n"); + if (info) + ret = info->suspend(info); + return ret; +} + +static int rk29_nand_resume(struct platform_device *pdev) +{ + struct mtd_info *info = platform_get_drvdata(pdev); + int ret = 0; + + DEBUG(MTD_DEBUG_LEVEL0, "RK2818_NAND : NAND resume\n"); + /* Enable the NFC clock */ + + if (info) + info->resume(info); + + return ret; +} +#else +#define rk29_nand_suspend NULL +#define rk29_nand_resume NULL +#endif /* CONFIG_PM */ + + +static struct platform_driver rk29_nand_driver = { + .driver = { + .name = "rk29-nand", + }, + .probe = rk29_nand_probe, + .remove = rk29_nand_remove, + .suspend = rk29_nand_suspend, + .resume = rk29_nand_resume, +}; + +static int __init rk29_nand_init(void) +{ + /* Register the device driver structure. */ + printk("rk29_nand_init\n"); + return platform_driver_register(&rk29_nand_driver);; +} + +static void __exit rk29_nand_exit(void) +{ + /* Unregister the device structure */ + platform_driver_unregister(&rk29_nand_driver); +} + +#ifdef CONFIG_DM9000_USE_NAND_CONTROL +// nandc dma cs mutex for dm9000 interface +void rk29_nand_status_mutex_lock(void) +{ + pNANDC pRK29NC= (pNANDC)RK2818_NANDC_BASE; + mutex_lock(&rknand_mutex); + pRK29NC->FMCTL &=0xffffff00; // release chip select + +} + +int rk29_nand_status_mutex_trylock(void) +{ + pNANDC pRK29NC= (pNANDC)RK2818_NANDC_BASE; + if( mutex_trylock(&rknand_mutex)) + { + pRK29NC->FMCTL &=0xffffff00; // release chip select + return 1; // ready + } + else + return 0; // busy +} + +void rk29_nand_status_mutex_unlock(void) +{ + mutex_unlock(&rknand_mutex); + return; +} +#endif + +module_init(rk29_nand_init); +module_exit(rk29_nand_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("hxy "); +MODULE_DESCRIPTION("MTD NAND driver for rk29 device"); + 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_ */ + diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig old mode 100644 new mode 100755 index b2837066ee0d..cab6a9a4e086 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -18,7 +18,7 @@ config VGASTATE config VIDEO_OUTPUT_CONTROL tristate "Lowlevel video output switch controls" help - This framework adds support for low-level control of the video + This framework adds support for low-level control of the video output switch. menuconfig FB @@ -626,7 +626,7 @@ config FB_STI BIOS routines contained in a ROM chip in HP PA-RISC based machines. Enabling this option will implement the linux framebuffer device using calls to the STI BIOS routines for initialisation. - + If you enable this option, you will get a planar framebuffer device /dev/fb which will work on the most common HP graphic cards of the NGLE family, including the artist chips (in the 7xx and Bxxx series), @@ -1065,36 +1065,36 @@ config FB_I810 select FB_CFB_IMAGEBLIT select VGASTATE help - This driver supports the on-board graphics built in to the Intel 810 + This driver supports the on-board graphics built in to the Intel 810 and 815 chipsets. Say Y if you have and plan to use such a board. To compile this driver as a module, choose M here: the module will be called i810fb. - For more information, please read + For more information, please read config FB_I810_GTF bool "use VESA Generalized Timing Formula" depends on FB_I810 help - If you say Y, then the VESA standard, Generalized Timing Formula + If you say Y, then the VESA standard, Generalized Timing Formula or GTF, will be used to calculate the required video timing values - per video mode. Since the GTF allows nondiscrete timings + per video mode. Since the GTF allows nondiscrete timings (nondiscrete being a range of values as opposed to discrete being a - set of values), you'll be able to use any combination of horizontal + set of values), you'll be able to use any combination of horizontal and vertical resolutions, and vertical refresh rates without having to specify your own timing parameters. This is especially useful - to maximize the performance of an aging display, or if you just - have a display with nonstandard dimensions. A VESA compliant + to maximize the performance of an aging display, or if you just + have a display with nonstandard dimensions. A VESA compliant monitor is recommended, but can still work with non-compliant ones. - If you need or want this, then select this option. The timings may - not be compliant with Intel's recommended values. Use at your own + If you need or want this, then select this option. The timings may + not be compliant with Intel's recommended values. Use at your own risk. - If you say N, the driver will revert to discrete video timings + If you say N, the driver will revert to discrete video timings using a set recommended by Intel in their documentation. - + If unsure, say N. config FB_I810_I2C @@ -1212,10 +1212,10 @@ config FB_MATROX_G G450/G550 secondary head and digital output are supported without additional modules. - The driver starts in monitor mode. You must use the matroxset tool - (available at ) to - swap primary and secondary head outputs, or to change output mode. - Secondary head driver always start in 640x480 resolution and you + The driver starts in monitor mode. You must use the matroxset tool + (available at ) to + swap primary and secondary head outputs, or to change output mode. + Secondary head driver always start in 640x480 resolution and you must use fbset to change it. Do not forget that second head supports only 16 and 32 bpp @@ -1298,7 +1298,7 @@ config FB_RADEON_I2C select FB_DDC default y help - Say Y here if you want DDC/I2C support for your Radeon board. + Say Y here if you want DDC/I2C support for your Radeon board. config FB_RADEON_BACKLIGHT bool "Support for backlight control" @@ -1498,7 +1498,7 @@ config FB_NEOMAGIC select VGASTATE help This driver supports notebooks with NeoMagic PCI chips. - Say Y if you have such a graphics card. + Say Y if you have such a graphics card. To compile this driver as a module, choose M here: the module will be called neofb. @@ -1553,7 +1553,7 @@ config FB_VOODOO1 select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT ---help--- - Say Y here if you have a 3Dfx Voodoo Graphics (Voodoo1/sst1) or + Say Y here if you have a 3Dfx Voodoo Graphics (Voodoo1/sst1) or Voodoo2 (cvg) based graphics card. To compile this driver as a module, choose M here: the @@ -1935,7 +1935,17 @@ config FB_RK2818 select FB_CFB_IMAGEBLIT ---help--- Framebuffer driver for RK2818 Platform,select it if you using rk2818 - + +config FB_RK29 + tristate "RK29 lcd control" + depends on FB + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + Framebuffer driver for RK29 Platform,select it if you using rk29 + + config FB_SM501 tristate "Silicon Motion SM501 framebuffer support" depends on FB && MFD_SM501 diff --git a/drivers/video/Makefile b/drivers/video/Makefile old mode 100644 new mode 100755 index 6777b5a36243..6a0202b22b1e --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -121,6 +121,7 @@ obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/ obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o obj-$(CONFIG_FB_PS3) += ps3fb.o obj-$(CONFIG_FB_RK2818) += rk2818_fb.o +obj-$(CONFIG_FB_RK29) += rk29_fb.o obj-$(CONFIG_FB_SM501) += sm501fb.o obj-$(CONFIG_FB_XILINX) += xilinxfb.o obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o diff --git a/drivers/video/display/screen/hdmi_anx7150.c b/drivers/video/display/screen/hdmi_anx7150.c index 5752803189fa..eed53ae54544 100755 --- a/drivers/video/display/screen/hdmi_anx7150.c +++ b/drivers/video/display/screen/hdmi_anx7150.c @@ -1,6 +1,6 @@ #include #include -#include "../../rk2818_fb.h" +#include "../../rk29_fb.h" #include #include #include "screen.h" @@ -39,9 +39,9 @@ int anx7150_init(void); int anx7150_standby(u8 enable); -void set_hdmi_info(struct rk28fb_screen *screen) +void set_hdmi_info(struct rk29fb_screen *screen) { - struct rk28fb_screen *screen2 = screen + 1; + struct rk29fb_screen *screen2 = screen + 1; /* ****************** 576p ******************* */ /* screen type & face */ diff --git a/drivers/video/display/screen/hdmi_null.c b/drivers/video/display/screen/hdmi_null.c index c39836d4e44e..5aa9f3f4c72e 100755 --- a/drivers/video/display/screen/hdmi_null.c +++ b/drivers/video/display/screen/hdmi_null.c @@ -1,14 +1,14 @@ #include #include -#include "../../rk2818_fb.h" +#include "../../rk29_fb.h" #include #include #include "screen.h" -void set_hdmi_info(struct rk28fb_screen *screen) +void set_hdmi_info(struct rk29fb_screen *screen) { - memset(screen, 0, sizeof(struct rk28fb_screen)); + memset(screen, 0, sizeof(struct rk29fb_screen)); screen->face = OUT_P666; } diff --git a/drivers/video/display/screen/lcd_a060se02.c b/drivers/video/display/screen/lcd_a060se02.c index ac386386f5be..b24540b5f31a 100755 --- a/drivers/video/display/screen/lcd_a060se02.c +++ b/drivers/video/display/screen/lcd_a060se02.c @@ -1,6 +1,6 @@ #include #include -#include "../../rk2818_fb.h" +#include "../../rk29_fb.h" #include #include #include "screen.h" @@ -117,7 +117,7 @@ int lcd_refresh(u8 arg) -void set_lcd_info(struct rk28fb_screen *screen) +void set_lcd_info(struct rk29fb_screen *screen) { /* screen type & face */ screen->type = OUT_TYPE; diff --git a/drivers/video/display/screen/lcd_hl070vm4.c b/drivers/video/display/screen/lcd_hl070vm4.c index e9e51124141b..f81aadaf5954 100755 --- a/drivers/video/display/screen/lcd_hl070vm4.c +++ b/drivers/video/display/screen/lcd_hl070vm4.c @@ -1,6 +1,6 @@ #include #include -#include "../../rk2818_fb.h" +#include "../../rk29_fb.h" #include #include #include @@ -13,7 +13,7 @@ /* Timing */ #define H_PW 10 -#define H_BP 206 +#define H_BP 206 #define H_VD 800 #define H_FP 40 @@ -33,21 +33,21 @@ #define CS_OUT() gpio_direction_output(CS_PORT, 0) #define CS_SET() gpio_set_value(CS_PORT, GPIO_HIGH) #define CS_CLR() gpio_set_value(CS_PORT, GPIO_LOW) -#define CLK_OUT() gpio_direction_output(CLK_PORT, 0) +#define CLK_OUT() gpio_direction_output(CLK_PORT, 0) #define CLK_SET() gpio_set_value(CLK_PORT, GPIO_HIGH) #define CLK_CLR() gpio_set_value(CLK_PORT, GPIO_LOW) -#define TXD_OUT() gpio_direction_output(TXD_PORT, 0) +#define TXD_OUT() gpio_direction_output(TXD_PORT, 0) #define TXD_SET() gpio_set_value(TXD_PORT, GPIO_HIGH) #define TXD_CLR() gpio_set_value(TXD_PORT, GPIO_LOW) -static struct rk2818lcd_info *gLcd_info = NULL; +static struct rk29lcd_info *gLcd_info = NULL; #define DRVDelayUs(i) udelay(i*2) int init(void); int standby(u8 enable); -void set_lcd_info(struct rk28fb_screen *screen, struct rk2818lcd_info *lcd_info ) +void set_lcd_info(struct rk29fb_screen *screen, struct rk2918lcd_info *lcd_info ) { /* screen type & face */ screen->type = OUT_TYPE; @@ -153,7 +153,7 @@ void spi_screenreg_set(u32 Data) CS_SET(); CLK_CLR(); TXD_CLR(); - DRVDelayUs(2); + DRVDelayUs(2); } diff --git a/drivers/video/display/screen/lcd_hsd800x480.c b/drivers/video/display/screen/lcd_hsd800x480.c index 1a3816d5e065..43b96070b0c8 100755 --- a/drivers/video/display/screen/lcd_hsd800x480.c +++ b/drivers/video/display/screen/lcd_hsd800x480.c @@ -1,7 +1,7 @@ /* This Lcd Driver is HSD070IDW1 write by cst 2009.10.27 */ #include #include -#include "../../rk2818_fb.h" +#include "../../rk29_fb.h" #include #include #include @@ -35,21 +35,21 @@ #define CS_OUT() gpio_direction_output(CS_PORT, 0) #define CS_SET() gpio_set_value(CS_PORT, GPIO_HIGH) #define CS_CLR() gpio_set_value(CS_PORT, GPIO_LOW) -#define CLK_OUT() gpio_direction_output(CLK_PORT, 0) +#define CLK_OUT() gpio_direction_output(CLK_PORT, 0) #define CLK_SET() gpio_set_value(CLK_PORT, GPIO_HIGH) #define CLK_CLR() gpio_set_value(CLK_PORT, GPIO_LOW) -#define TXD_OUT() gpio_direction_output(TXD_PORT, 0) +#define TXD_OUT() gpio_direction_output(TXD_PORT, 0) #define TXD_SET() gpio_set_value(TXD_PORT, GPIO_HIGH) #define TXD_CLR() gpio_set_value(TXD_PORT, GPIO_LOW) -static struct rk2818lcd_info *gLcd_info = NULL; +static struct rk29lcd_info *gLcd_info = NULL; #define DRVDelayUs(i) udelay(i*2) int init(void); int standby(u8 enable); -void set_lcd_info(struct rk28fb_screen *screen, struct rk2818lcd_info *lcd_info ) +void set_lcd_info(struct rk29fb_screen *screen, struct rk29lcd_info *lcd_info ) { /* screen type & face */ screen->type = OUT_TYPE; @@ -83,12 +83,12 @@ void set_lcd_info(struct rk28fb_screen *screen, struct rk2818lcd_info *lcd_info /* Operation function*/ /*screen->init = init;*/ - screen->init = NULL; + screen->init = NULL; screen->standby = standby; if(lcd_info) gLcd_info = lcd_info; } -//cannot need init,so set screen->init = null at rk28_fb.c file +//cannot need init,so set screen->init = null at rk29_fb.c file void spi_screenreg_set(u32 Addr, u32 Data) { @@ -218,19 +218,19 @@ int standby(u8 enable) if(gLcd_info) gLcd_info->io_deinit(); #else - + GPIOSetPinDirection(GPIOPortB_Pin3, GPIO_OUT); GPIOSetPinDirection(GPIOPortB_Pin2, GPIO_OUT); if(enable) { - GPIOSetPinLevel(GPIOPortB_Pin3, GPIO_LOW); - GPIOSetPinLevel(GPIOPortB_Pin2, GPIO_HIGH); + GPIOSetPinLevel(GPIOPortB_Pin3, GPIO_LOW); + GPIOSetPinLevel(GPIOPortB_Pin2, GPIO_HIGH); } else { - GPIOSetPinLevel(GPIOPortB_Pin3, GPIO_HIGH); - GPIOSetPinLevel(GPIOPortB_Pin2, GPIO_LOW); + GPIOSetPinLevel(GPIOPortB_Pin3, GPIO_HIGH); + GPIOSetPinLevel(GPIOPortB_Pin2, GPIO_LOW); } #endif return 0; diff --git a/drivers/video/display/screen/lcd_hx8357.c b/drivers/video/display/screen/lcd_hx8357.c index f84ed97ceaa5..4990d9aeee53 100755 --- a/drivers/video/display/screen/lcd_hx8357.c +++ b/drivers/video/display/screen/lcd_hx8357.c @@ -1,6 +1,6 @@ #include #include -#include "../../rk2818_fb.h" +#include "../../rk29_fb.h" #include #include #include @@ -15,7 +15,7 @@ /* Timing */ #define H_PW 8 #define H_BP 6 -#define H_VD 320 //***800 +#define H_VD 320 //***800 #define H_FP 60 #define V_PW 12 @@ -24,10 +24,10 @@ #define V_FP 40 /* Other */ -#define DCLK_POL 0 +#define DCLK_POL 0 #define SWAP_RB 0 -static struct rk2818lcd_info *gLcd_info = NULL; +static struct rk29lcd_info *gLcd_info = NULL; int init(void); int standby(u8 enable); @@ -39,10 +39,10 @@ int standby(u8 enable); #define CS_OUT() gpio_direction_output(CS_PORT, 0) #define CS_SET() gpio_set_value(CS_PORT, GPIO_HIGH) #define CS_CLR() gpio_set_value(CS_PORT, GPIO_LOW) -#define CLK_OUT() gpio_direction_output(CLK_PORT, 0) +#define CLK_OUT() gpio_direction_output(CLK_PORT, 0) #define CLK_SET() gpio_set_value(CLK_PORT, GPIO_HIGH) #define CLK_CLR() gpio_set_value(CLK_PORT, GPIO_LOW) -#define TXD_OUT() gpio_direction_output(TXD_PORT, 0) +#define TXD_OUT() gpio_direction_output(TXD_PORT, 0) #define TXD_SET() gpio_set_value(TXD_PORT, GPIO_HIGH) #define TXD_CLR() gpio_set_value(TXD_PORT, GPIO_LOW) @@ -52,41 +52,41 @@ static void screen_set_iomux(u8 enable) int ret=-1; if(enable) { - rk2818_mux_api_set(GPIOH6_IQ_SEL_NAME, 0); - ret = gpio_request(RK2818_PIN_PH6, NULL); + rk29_mux_api_set(GPIOH6_IQ_SEL_NAME, 0); + ret = gpio_request(RK29_PIN_PH6, NULL); if(0)//(ret != 0) { - gpio_free(RK2818_PIN_PH6); - printk(">>>>>> lcd cs gpio_request err \n "); + gpio_free(RK29_PIN_PH6); + printk(">>>>>> lcd cs gpio_request err \n "); goto pin_err; - } - - rk2818_mux_api_set(GPIOE_I2C0_SEL_NAME, 1); + } - ret = gpio_request(RK2818_PIN_PE5, NULL); + rk29_mux_api_set(GPIOE_I2C0_SEL_NAME, 1); + + ret = gpio_request(RK29_PIN_PE5, NULL); if(0)//(ret != 0) { - gpio_free(RK2818_PIN_PE5); - printk(">>>>>> lcd clk gpio_request err \n "); + gpio_free(RK29_PIN_PE5); + printk(">>>>>> lcd clk gpio_request err \n "); goto pin_err; - } - - ret = gpio_request(RK2818_PIN_PE4, NULL); + } + + ret = gpio_request(RK29_PIN_PE4, NULL); if(0)//(ret != 0) { - gpio_free(RK2818_PIN_PE4); - printk(">>>>>> lcd txd gpio_request err \n "); + gpio_free(RK29_PIN_PE4); + printk(">>>>>> lcd txd gpio_request err \n "); goto pin_err; - } + } } else { - gpio_free(RK2818_PIN_PH6); - // rk2818_mux_api_set(CXGPIO_HSADC_SEL_NAME, 1); + gpio_free(RK29_PIN_PH6); + // rk29_mux_api_set(CXGPIO_HSADC_SEL_NAME, 1); - gpio_free(RK2818_PIN_PE5); - gpio_free(RK2818_PIN_PE4); - rk2818_mux_api_set(GPIOE_I2C0_SEL_NAME, 0); + gpio_free(RK29_PIN_PE5); + gpio_free(RK29_PIN_PE4); + rk29_mux_api_set(GPIOE_I2C0_SEL_NAME, 0); } return ; pin_err: @@ -100,8 +100,8 @@ void spi_screenreg_set(u32 Addr, u32 Data) #define DRVDelayUs(i) udelay(i*2) u32 i; - u32 control_bit; - + u32 control_bit; + TXD_OUT(); CLK_OUT(); @@ -114,10 +114,10 @@ void spi_screenreg_set(u32 Addr, u32 Data) CLK_SET(); DRVDelayUs(2); - CS_CLR(); - control_bit = 0x70<<8; - Addr = (control_bit | Addr); - //printk("addr is 0x%x \n", Addr); + CS_CLR(); + control_bit = 0x70<<8; + Addr = (control_bit | Addr); + //printk("addr is 0x%x \n", Addr); for(i = 0; i < 16; i++) //reg { if(Addr &(1<<(15-i))) @@ -130,17 +130,17 @@ void spi_screenreg_set(u32 Addr, u32 Data) DRVDelayUs(2); CLK_SET(); DRVDelayUs(2); - } + } CS_SET(); - TXD_SET(); - CLK_SET(); + TXD_SET(); + CLK_SET(); DRVDelayUs(2); - CS_CLR(); - - control_bit = 0x72<<8; - Data = (control_bit | Data); - //printk("data is 0x%x \n", Data); + CS_CLR(); + + control_bit = 0x72<<8; + Data = (control_bit | Data); + //printk("data is 0x%x \n", Data); for(i = 0; i < 16; i++) //data { if(Data &(1<<(15-i))) @@ -161,29 +161,29 @@ void spi_screenreg_set(u32 Addr, u32 Data) DRVDelayUs(2); } -void set_lcd_info(struct rk28fb_screen *screen, struct rk2818lcd_info *lcd_info ) +void set_lcd_info(struct rk29fb_screen *screen, struct rk29lcd_info *lcd_info ) { - //printk("lcd_hx8357 set_lcd_info \n"); + //printk("lcd_hx8357 set_lcd_info \n"); /* screen type & face */ screen->type = OUT_TYPE; screen->face = OUT_FACE; - + /* Screen size */ screen->x_res = H_VD; screen->y_res = V_VD; /* Timing */ screen->pixclock = OUT_CLK; - screen->left_margin = H_BP; /*>2*/ - screen->right_margin = H_FP; /*>2*/ - screen->hsync_len = H_PW; /*>2*/ //***all > 326, 4upper_margin = V_BP; /*>2*/ - screen->lower_margin = V_FP; /*>2*/ - screen->vsync_len = V_PW; /*>6*/ + screen->left_margin = H_BP; /*>2*/ + screen->right_margin = H_FP; /*>2*/ + screen->hsync_len = H_PW; /*>2*/ //***all > 326, 4upper_margin = V_BP; /*>2*/ + screen->lower_margin = V_FP; /*>2*/ + screen->vsync_len = V_PW; /*>6*/ /* Pin polarity */ - screen->pin_hsync = 0; - screen->pin_vsync = 0; + screen->pin_hsync = 0; + screen->pin_vsync = 0; screen->pin_den = 0; screen->pin_dclk = DCLK_POL; @@ -202,12 +202,12 @@ void set_lcd_info(struct rk28fb_screen *screen, struct rk2818lcd_info *lcd_info } int init(void) -{ +{ if(gLcd_info) gLcd_info->io_init(); -#if 0 //***这句代码是不是写错了 +#if 0 //***这句代码是不是写错了 spi_screenreg_set(0x02, 0x07); spi_screenreg_set(0x03, 0x5f); spi_screenreg_set(0x04, 0x17); @@ -243,136 +243,136 @@ int init(void) spi_screenreg_set(0x20, 0xF0); spi_screenreg_set(0x21, 0xF0); spi_screenreg_set(0x22, 0x09); -#else - spi_screenreg_set(0xff, 0x00); - spi_screenreg_set(0x16, 0x08); - spi_screenreg_set(0x01, 0x02); - spi_screenreg_set(0xe2, 0x00); - spi_screenreg_set(0xe3, 0x00); - spi_screenreg_set(0xf2, 0x00); - spi_screenreg_set(0xe4, 0x1c); - spi_screenreg_set(0xe5, 0x1c); - spi_screenreg_set(0xe6, 0x00); - spi_screenreg_set(0xe7, 0x1c); - - spi_screenreg_set(0x19, 0x01); - mdelay(10); - spi_screenreg_set(0x2a, 0x00); - spi_screenreg_set(0x2b, 0x13); - spi_screenreg_set(0x2f, 0x01); - spi_screenreg_set(0x02, 0x00); - spi_screenreg_set(0x03, 0x00); - spi_screenreg_set(0x04, 0x01); - spi_screenreg_set(0x05, 0x3f); - spi_screenreg_set(0x06, 0x00); - spi_screenreg_set(0x07, 0x00); +#else + spi_screenreg_set(0xff, 0x00); + spi_screenreg_set(0x16, 0x08); + spi_screenreg_set(0x01, 0x02); + spi_screenreg_set(0xe2, 0x00); + spi_screenreg_set(0xe3, 0x00); + spi_screenreg_set(0xf2, 0x00); + spi_screenreg_set(0xe4, 0x1c); + spi_screenreg_set(0xe5, 0x1c); + spi_screenreg_set(0xe6, 0x00); + spi_screenreg_set(0xe7, 0x1c); - spi_screenreg_set(0x08, 0x01); - spi_screenreg_set(0x09, 0xdf); - spi_screenreg_set(0x24, 0x91); - spi_screenreg_set(0x25, 0x8a); - spi_screenreg_set(0x29, 0x01); - spi_screenreg_set(0x18, 0x22); - spi_screenreg_set(0x1b, 0x30); - mdelay(10); - spi_screenreg_set(0x1d, 0x22); - mdelay(10); - spi_screenreg_set(0x40, 0x00); - spi_screenreg_set(0x41, 0x3c); - spi_screenreg_set(0x42, 0x38); - spi_screenreg_set(0x43, 0x34); - spi_screenreg_set(0x44, 0x2e); - spi_screenreg_set(0x45, 0x2f); - spi_screenreg_set(0x46, 0x41); - spi_screenreg_set(0x47, 0x7d); - spi_screenreg_set(0x48, 0x0b); - spi_screenreg_set(0x49, 0x05); - spi_screenreg_set(0x4a, 0x06); - spi_screenreg_set(0x4b, 0x12); - spi_screenreg_set(0x4c, 0x16); - spi_screenreg_set(0x50, 0x10); - spi_screenreg_set(0x51, 0x11); - spi_screenreg_set(0x52, 0x0b); - spi_screenreg_set(0x53, 0x07); - spi_screenreg_set(0x54, 0x03); - spi_screenreg_set(0x55, 0x3f); - spi_screenreg_set(0x56, 0x02); - spi_screenreg_set(0x57, 0x3e); - spi_screenreg_set(0x58, 0x09); - spi_screenreg_set(0x59, 0x0d); - spi_screenreg_set(0x5a, 0x19); - spi_screenreg_set(0x5b, 0x1a); - spi_screenreg_set(0x5c, 0x14); - spi_screenreg_set(0x5d, 0xc0); - spi_screenreg_set(0x1a, 0x05); - mdelay(10); - - spi_screenreg_set(0x1c, 0x03); - mdelay(10); - spi_screenreg_set(0x1f, 0x90); - mdelay(10); - spi_screenreg_set(0x1f, 0xd2); - mdelay(10); - spi_screenreg_set(0x28, 0x04); - mdelay(40); - spi_screenreg_set(0x28, 0x38); - mdelay(40); - spi_screenreg_set(0x28, 0x3c); - mdelay(40); - spi_screenreg_set(0x80, 0x00); - spi_screenreg_set(0x81, 0x00); - spi_screenreg_set(0x82, 0x00); - spi_screenreg_set(0x83, 0x00); - - spi_screenreg_set(0x60, 0x08); - spi_screenreg_set(0x31, 0x02); - spi_screenreg_set(0x32, 0x08 /*0x00*/); - spi_screenreg_set(0x17, 0x60); //***RGB666 - spi_screenreg_set(0x2d, 0x1f); - spi_screenreg_set(0xe8, 0x90); -#endif + spi_screenreg_set(0x19, 0x01); + mdelay(10); + spi_screenreg_set(0x2a, 0x00); + spi_screenreg_set(0x2b, 0x13); + spi_screenreg_set(0x2f, 0x01); + spi_screenreg_set(0x02, 0x00); + spi_screenreg_set(0x03, 0x00); + spi_screenreg_set(0x04, 0x01); + spi_screenreg_set(0x05, 0x3f); + spi_screenreg_set(0x06, 0x00); + spi_screenreg_set(0x07, 0x00); + + spi_screenreg_set(0x08, 0x01); + spi_screenreg_set(0x09, 0xdf); + spi_screenreg_set(0x24, 0x91); + spi_screenreg_set(0x25, 0x8a); + spi_screenreg_set(0x29, 0x01); + spi_screenreg_set(0x18, 0x22); + spi_screenreg_set(0x1b, 0x30); + mdelay(10); + spi_screenreg_set(0x1d, 0x22); + mdelay(10); + spi_screenreg_set(0x40, 0x00); + spi_screenreg_set(0x41, 0x3c); + spi_screenreg_set(0x42, 0x38); + spi_screenreg_set(0x43, 0x34); + spi_screenreg_set(0x44, 0x2e); + spi_screenreg_set(0x45, 0x2f); + spi_screenreg_set(0x46, 0x41); + spi_screenreg_set(0x47, 0x7d); + spi_screenreg_set(0x48, 0x0b); + spi_screenreg_set(0x49, 0x05); + spi_screenreg_set(0x4a, 0x06); + spi_screenreg_set(0x4b, 0x12); + spi_screenreg_set(0x4c, 0x16); + spi_screenreg_set(0x50, 0x10); + spi_screenreg_set(0x51, 0x11); + spi_screenreg_set(0x52, 0x0b); + spi_screenreg_set(0x53, 0x07); + spi_screenreg_set(0x54, 0x03); + spi_screenreg_set(0x55, 0x3f); + spi_screenreg_set(0x56, 0x02); + spi_screenreg_set(0x57, 0x3e); + spi_screenreg_set(0x58, 0x09); + spi_screenreg_set(0x59, 0x0d); + spi_screenreg_set(0x5a, 0x19); + spi_screenreg_set(0x5b, 0x1a); + spi_screenreg_set(0x5c, 0x14); + spi_screenreg_set(0x5d, 0xc0); + spi_screenreg_set(0x1a, 0x05); + mdelay(10); + + spi_screenreg_set(0x1c, 0x03); + mdelay(10); + spi_screenreg_set(0x1f, 0x90); + mdelay(10); + spi_screenreg_set(0x1f, 0xd2); + mdelay(10); + spi_screenreg_set(0x28, 0x04); + mdelay(40); + spi_screenreg_set(0x28, 0x38); + mdelay(40); + spi_screenreg_set(0x28, 0x3c); + mdelay(40); + spi_screenreg_set(0x80, 0x00); + spi_screenreg_set(0x81, 0x00); + spi_screenreg_set(0x82, 0x00); + spi_screenreg_set(0x83, 0x00); + + spi_screenreg_set(0x60, 0x08); + spi_screenreg_set(0x31, 0x02); + spi_screenreg_set(0x32, 0x08 /*0x00*/); + spi_screenreg_set(0x17, 0x60); //***RGB666 + spi_screenreg_set(0x2d, 0x1f); + spi_screenreg_set(0xe8, 0x90); +#endif if(gLcd_info) gLcd_info->io_deinit(); return 0; } -int standby(u8 enable) //***enable =1 means suspend, 0 means resume +int standby(u8 enable) //***enable =1 means suspend, 0 means resume { - + if(gLcd_info) gLcd_info->io_init(); if(enable) { //printk("---------hx8357 screen suspend--------------\n"); - #if 0 - spi_screenreg_set(0x03, 0xde); + #if 0 + spi_screenreg_set(0x03, 0xde); #else //modify by robert #if 0 - spi_screenreg_set(0x1f, 0x91); + spi_screenreg_set(0x1f, 0x91); spi_screenreg_set(0x19, 0x00); #else - spi_screenreg_set(0x28, 0x38); + spi_screenreg_set(0x28, 0x38); msleep(10); spi_screenreg_set(0x28, 0x24); msleep(10); spi_screenreg_set(0x28, 0x04); #endif //modify end - #endif - } else { + #endif + } else { //printk("--------- hx8357 screen resume--------------\n "); - #if 0 - spi_screenreg_set(0x03, 0x5f); - #else + #if 0 + spi_screenreg_set(0x03, 0x5f); + #else //modify by robert #if 0 - spi_screenreg_set(0x19, 0x01); - spi_screenreg_set(0x1f, 0x90); - mdelay(10); + spi_screenreg_set(0x19, 0x01); + spi_screenreg_set(0x1f, 0x90); + mdelay(10); spi_screenreg_set(0x1f, 0xd2); #else - spi_screenreg_set(0x28, 0x38); + spi_screenreg_set(0x28, 0x38); msleep(10); spi_screenreg_set(0x28, 0x3c); msleep(10); @@ -380,10 +380,10 @@ int standby(u8 enable) //***enable =1 means suspend, 0 means resume spi_screenreg_set(0x81, 0x00); spi_screenreg_set(0x82, 0x00); spi_screenreg_set(0x83, 0x00); - + #endif //modify end - #endif + #endif } if(gLcd_info) diff --git a/drivers/video/display/screen/lcd_nt35580.c b/drivers/video/display/screen/lcd_nt35580.c index aadad64f8426..e1b63fef9569 100755 --- a/drivers/video/display/screen/lcd_nt35580.c +++ b/drivers/video/display/screen/lcd_nt35580.c @@ -1,6 +1,6 @@ #include #include -#include "../../rk2818_fb.h" +#include "../../rk29_fb.h" #include #include #include @@ -34,10 +34,10 @@ #define CS_OUT() gpio_direction_output(CS_PORT, 0) #define CS_SET() gpio_set_value(CS_PORT, GPIO_HIGH) #define CS_CLR() gpio_set_value(CS_PORT, GPIO_LOW) -#define CLK_OUT() gpio_direction_output(CLK_PORT, 0) +#define CLK_OUT() gpio_direction_output(CLK_PORT, 0) #define CLK_SET() gpio_set_value(CLK_PORT, GPIO_HIGH) #define CLK_CLR() gpio_set_value(CLK_PORT, GPIO_LOW) -#define TXD_OUT() gpio_direction_output(TXD_PORT, 0) +#define TXD_OUT() gpio_direction_output(TXD_PORT, 0) #define TXD_SET() gpio_set_value(TXD_PORT, GPIO_HIGH) #define TXD_CLR() gpio_set_value(TXD_PORT, GPIO_LOW) #define TXD_IN() gpio_direction_input(TXD_PORT) @@ -45,7 +45,7 @@ #define delay_us(i) udelay(i) -static struct rk2818lcd_info *gLcd_info = NULL; +static struct rk29lcd_info *gLcd_info = NULL; u32 spi_screenreg_get(u32 Addr) { @@ -422,7 +422,7 @@ int lcd_standby(u8 enable) } -void set_lcd_info(struct rk28fb_screen *screen, struct rk2818lcd_info *lcd_info ) +void set_lcd_info(struct rk29fb_screen *screen, struct rk2918lcd_info *lcd_info ) { /* screen type & face */ screen->type = OUT_TYPE; diff --git a/drivers/video/display/screen/lcd_nt35582.c b/drivers/video/display/screen/lcd_nt35582.c index 99ed77bc62fa..66941e23910c 100755 --- a/drivers/video/display/screen/lcd_nt35582.c +++ b/drivers/video/display/screen/lcd_nt35582.c @@ -1,6 +1,6 @@ #include #include -#include "../../rk2818_fb.h" +#include "../../rk29_fb.h" #include #include #include "screen.h" @@ -378,7 +378,7 @@ int lcd_disparea(u8 area) } -void set_lcd_info(struct rk28fb_screen *screen) +void set_lcd_info(struct rk29fb_screen *screen) { /* screen type & face */ screen->type = OUT_TYPE; diff --git a/drivers/video/display/screen/lcd_null.c b/drivers/video/display/screen/lcd_null.c index f363e5cc622e..d03cbd615d1e 100755 --- a/drivers/video/display/screen/lcd_null.c +++ b/drivers/video/display/screen/lcd_null.c @@ -1,13 +1,13 @@ #include #include -#include "../../rk2818_fb.h" +#include "../../rk29_fb.h" #include #include #include "screen.h" -void set_lcd_info(struct rk28fb_screen *screen) +void set_lcd_info(struct rk29fb_screen *screen) { - memset(screen, 0, sizeof(struct rk28fb_screen)); + memset(screen, 0, sizeof(struct rk29fb_screen)); screen->face = OUT_P666; } diff --git a/drivers/video/display/screen/lcd_s1d13521.c b/drivers/video/display/screen/lcd_s1d13521.c index cf4b6adea87a..804170aeb25a 100755 --- a/drivers/video/display/screen/lcd_s1d13521.c +++ b/drivers/video/display/screen/lcd_s1d13521.c @@ -1,6 +1,6 @@ #include #include -#include "../../rk2818_fb.h" +#include "../../rk29_fb.h" #include #include #include "screen.h" @@ -118,41 +118,41 @@ void s1d13521if_init_gpio(void) { int i; int ret=0; - - rk2818_mux_api_set(GPIOC_LCDC18BIT_SEL_NAME, IOMUXB_GPIO0_C01); - rk2818_mux_api_set(GPIOC_LCDC24BIT_SEL_NAME, IOMUXB_GPIO0_C2_7); - + + rk29_mux_api_set(GPIOC_LCDC18BIT_SEL_NAME, IOMUXB_GPIO0_C01); + rk29_mux_api_set(GPIOC_LCDC24BIT_SEL_NAME, IOMUXB_GPIO0_C2_7); + for(i = 0; i < 8; i++) { if(i == 1 || i == 6)//HIRQ, HRDY { - ret = gpio_request(GPIO_RESET_L+i, NULL); + ret = gpio_request(GPIO_RESET_L+i, NULL); if(ret != 0) { gpio_free(GPIO_RESET_L+i); - printk(">>>>>> lcd cs gpio_request err \n "); - } + printk(">>>>>> lcd cs gpio_request err \n "); + } gpio_direction_input(GPIO_RESET_L+i); gpio_free(GPIO_RESET_L+i); - } + } else //RESET_L, HD/C, HCS_L, HRD_L, HWE_L, RMODE { ret = gpio_request(GPIO_RESET_L+i, NULL); if(ret != 0) { gpio_free(GPIO_RESET_L+i); - printk(">>>>>> lcd cs gpio_request err \n "); - } + printk(">>>>>> lcd cs gpio_request err \n "); + } gpio_direction_output(GPIO_RESET_L+i, 0); gpio_set_value(GPIO_RESET_L+i, GPIO_HIGH); - gpio_free(GPIO_RESET_L+i); + gpio_free(GPIO_RESET_L+i); } } } void s1d13521if_set_reset(void) { - gpio_request(GPIO_RMODE, 0); + gpio_request(GPIO_RMODE, 0); gpio_set_value(GPIO_RMODE, GPIO_HIGH); gpio_request(GPIO_RESET_L, 0); diff --git a/drivers/video/display/screen/lcd_td043mgea1.c b/drivers/video/display/screen/lcd_td043mgea1.c index cbaee4902bea..6764031d9298 100755 --- a/drivers/video/display/screen/lcd_td043mgea1.c +++ b/drivers/video/display/screen/lcd_td043mgea1.c @@ -1,6 +1,6 @@ #include #include -#include "../../rk2818_fb.h" +#include "../../rk29_fb.h" #include #include #include @@ -31,21 +31,24 @@ #define CLK_PORT gLcd_info->clk_pin #define CS_PORT gLcd_info->cs_pin +#if 0 #define CS_OUT() gpio_direction_output(CS_PORT, 0) #define CS_SET() gpio_set_value(CS_PORT, GPIO_HIGH) #define CS_CLR() gpio_set_value(CS_PORT, GPIO_LOW) -#define CLK_OUT() gpio_direction_output(CLK_PORT, 0) +#define CLK_OUT() gpio_direction_output(CLK_PORT, 0) #define CLK_SET() gpio_set_value(CLK_PORT, GPIO_HIGH) #define CLK_CLR() gpio_set_value(CLK_PORT, GPIO_LOW) -#define TXD_OUT() gpio_direction_output(TXD_PORT, 0) +#define TXD_OUT() gpio_direction_output(TXD_PORT, 0) #define TXD_SET() gpio_set_value(TXD_PORT, GPIO_HIGH) #define TXD_CLR() gpio_set_value(TXD_PORT, GPIO_LOW) +#endif -static struct rk2818lcd_info *gLcd_info = NULL; + +static struct rk29lcd_info *gLcd_info = NULL; int init(void); int standby(u8 enable); -void set_lcd_info(struct rk28fb_screen *screen, struct rk2818lcd_info *lcd_info ) +void set_lcd_info(struct rk29fb_screen *screen, struct rk29lcd_info *lcd_info ) { /* screen type & face */ screen->type = OUT_TYPE; @@ -84,7 +87,7 @@ void set_lcd_info(struct rk28fb_screen *screen, struct rk2818lcd_info *lcd_info gLcd_info = lcd_info; } - +#if 0 void spi_screenreg_set(u32 Addr, u32 Data) { @@ -155,13 +158,15 @@ void spi_screenreg_set(u32 Addr, u32 Data) DRVDelayUs(2); } +#endif int init(void) -{ +{ if(gLcd_info) gLcd_info->io_init(); +#if 0 spi_screenreg_set(0x02, 0x07); spi_screenreg_set(0x03, 0x5f); spi_screenreg_set(0x04, 0x17); @@ -197,6 +202,7 @@ int init(void) spi_screenreg_set(0x20, 0xF0); spi_screenreg_set(0x21, 0xF0); spi_screenreg_set(0x22, 0x09); +#endif if(gLcd_info) gLcd_info->io_deinit(); @@ -204,14 +210,16 @@ int init(void) } int standby(u8 enable) -{ +{ if(gLcd_info) gLcd_info->io_init(); +#if 0 if(enable) { spi_screenreg_set(0x03, 0xde); } else { spi_screenreg_set(0x03, 0x5f); } +#endif if(gLcd_info) gLcd_info->io_deinit(); return 0; diff --git a/drivers/video/display/screen/lcd_tj048nc01ca.c b/drivers/video/display/screen/lcd_tj048nc01ca.c index b952281443e6..d9f0e133e1b2 100755 --- a/drivers/video/display/screen/lcd_tj048nc01ca.c +++ b/drivers/video/display/screen/lcd_tj048nc01ca.c @@ -1,12 +1,12 @@ #include #include -#include "../../rk2818_fb.h" +#include "../../rk29_fb.h" #include #include #include #include "screen.h" - + /* Base */ #define OUT_TYPE SCREEN_RGB #define OUT_FACE OUT_P888 @@ -34,20 +34,20 @@ #define CS_OUT() gpio_direction_output(CS_PORT, 0) #define CS_SET() gpio_set_value(CS_PORT, GPIO_HIGH) #define CS_CLR() gpio_set_value(CS_PORT, GPIO_LOW) -#define CLK_OUT() gpio_direction_output(CLK_PORT, 0) +#define CLK_OUT() gpio_direction_output(CLK_PORT, 0) #define CLK_SET() gpio_set_value(CLK_PORT, GPIO_HIGH) #define CLK_CLR() gpio_set_value(CLK_PORT, GPIO_LOW) -#define TXD_OUT() gpio_direction_output(TXD_PORT, 0) +#define TXD_OUT() gpio_direction_output(TXD_PORT, 0) #define TXD_SET() gpio_set_value(TXD_PORT, GPIO_HIGH) #define TXD_CLR() gpio_set_value(TXD_PORT, GPIO_LOW) #define DRVDelayUs(i) udelay(i*2) -static struct rk2818lcd_info *gLcd_info = NULL; +static struct rk29lcd_info *gLcd_info = NULL; int lcd_init(void); int lcd_standby(u8 enable); -void set_lcd_info(struct rk28fb_screen *screen, struct rk2818lcd_info *lcd_info ) +void set_lcd_info(struct rk29fb_screen *screen, struct rk29lcd_info *lcd_info ) { /* screen type & face */ screen->type = OUT_TYPE; diff --git a/drivers/video/display/screen/screen.h b/drivers/video/display/screen/screen.h index 5794c3d708db..b56e40841cd2 100755 --- a/drivers/video/display/screen/screen.h +++ b/drivers/video/display/screen/screen.h @@ -33,7 +33,7 @@ typedef enum _MCU_STATUS { /* Sceen description */ -struct rk28fb_screen { +struct rk29fb_screen { /* screen type & out face */ u16 type; u16 face; @@ -79,8 +79,8 @@ struct rk28fb_screen { }; -extern void set_lcd_info(struct rk28fb_screen *screen, struct rk2818lcd_info *lcd_info); -extern void set_tv_info(struct rk28fb_screen *screen); -extern void set_hdmi_info(struct rk28fb_screen *screen); +extern void set_lcd_info(struct rk29fb_screen *screen, struct rk29lcd_info *lcd_info); +extern void set_tv_info(struct rk29fb_screen *screen); +extern void set_hdmi_info(struct rk29fb_screen *screen); diff --git a/drivers/video/display/screen/tv_null.c b/drivers/video/display/screen/tv_null.c index 80064b19e2c0..ac80ccfb987c 100755 --- a/drivers/video/display/screen/tv_null.c +++ b/drivers/video/display/screen/tv_null.c @@ -1,15 +1,15 @@ #include #include -#include "../../rk2818_fb.h" +#include "../../rk29_fb.h" #include #include #include "screen.h" -void set_tv_info(struct rk28fb_screen *screen) +void set_tv_info(struct rk29fb_screen *screen) { - memset(screen, 0, sizeof(struct rk28fb_screen)); + memset(screen, 0, sizeof(struct rk29fb_screen)); screen->face = OUT_P666; } diff --git a/drivers/video/rk29_fb.c b/drivers/video/rk29_fb.c new file mode 100755 index 000000000000..e11f57fe8036 --- /dev/null +++ b/drivers/video/rk29_fb.c @@ -0,0 +1,2150 @@ +/* + * drivers/video/rk29_fb.c + * + * Copyright (C) 2010 ROCKCHIP, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include + +#include "rk29_fb.h" + +#ifdef CONFIG_PM +#include +#endif + +#include +#include +#include +#include +//#include + +#include "./display/screen/screen.h" + + +#define WIN1_USE_DOUBLE_BUF 0 //win1 use double buf to accelerate display +#define CURSOR_BUF_SIZE 256 //rk29 cursor need 256B buf + +#if 0 + #define fbprintk(msg...) printk(msg); +#else + #define fbprintk(msg...) +#endif + + +#if 0 + #define fbprintk2(msg...) printk(msg); +#else + #define fbprintk2(msg...) +#endif + +#define LcdReadBit(inf, addr, msk) ((inf->regbak.addr=inf->preg->addr)&(msk)) +#define LcdWrReg(inf, addr, val) inf->preg->addr=inf->regbak.addr=(val) +#define LcdRdReg(inf, addr) (inf->preg->addr) +#define LcdSetBit(inf, addr, msk) inf->preg->addr=((inf->regbak.addr) |= (msk)) +#define LcdClrBit(inf, addr, msk) inf->preg->addr=((inf->regbak.addr) &= ~(msk)) +#define LcdSetRegBit(inf, addr, msk) inf->preg->addr=((inf->preg->addr) |= (msk)) +#define LcdMskReg(inf, addr, msk, val) (inf->regbak.addr)&=~(msk); inf->preg->addr=(inf->regbak.addr|=(val)) + + +#define IsMcuLandscape() ((SCREEN_MCU==inf->cur_screen->type) && (0==inf->mcu_scandir)) +#define IsMcuUseFmk() ( (2==inf->cur_screen->mcu_usefmk) || (1==inf->cur_screen->mcu_usefmk)) + +#define CalScaleW0(x, y) (((u32)x*0x1000)/y) + +struct rk29fb_rgb { + struct fb_bitfield red; + struct fb_bitfield green; + struct fb_bitfield blue; + struct fb_bitfield transp; +}; + +static struct rk29fb_rgb def_rgb_16 = { + red: { offset: 11, length: 5, }, + green: { offset: 5, length: 6, }, + blue: { offset: 0, length: 5, }, + transp: { offset: 0, length: 0, }, +}; + +struct win0_par { + u32 refcount; + u32 pseudo_pal[16]; + u32 y_offset; + u32 uv_offset; + + u8 par_seted; + u8 addr_seted; +}; + +struct win1_par { + u32 refcount; + u32 pseudo_pal[16]; + int lstblank; +}; + +struct rk29fb_inf { + struct fb_info *win0fb; + struct fb_info *win1fb; + + void __iomem *reg_vir_base; // virtual basic address of lcdc register + u32 reg_phy_base; // physical basic address of lcdc register + u32 len; // physical map length of lcdc register + + struct clk *clk; + struct clk *dclk; //lcdc dclk + struct clk *dclk_parent; //lcdc dclk divider frequency source + struct clk *dclk_divider; //lcdc demodulator divider frequency + struct clk *clk_share_mem; //lcdc share memory frequency + unsigned long dclk_rate; + + /* lcdc reg base address and backup reg */ + LCDC_REG *preg; + LCDC_REG regbak; + + int in_suspend; + + /* variable used in mcu panel */ + int mcu_needflush; + int mcu_isrcnt; + u16 mcu_scandir; + struct timer_list mcutimer; + int mcu_status; + u8 mcu_fmksync; + int mcu_usetimer; + int mcu_stopflush; + + /* external memery */ + char __iomem *screen_base2; + __u32 smem_len2; + unsigned long smem_start2; + + char __iomem *cursor_base; /* cursor Virtual address*/ + __u32 cursor_size; /* Amount of ioremapped VRAM or 0 */ + unsigned long cursor_start; + + struct rk29fb_screen lcd_info; + struct rk29fb_screen tv_info[5]; + struct rk29fb_screen hdmi_info[2]; + struct rk29fb_screen *cur_screen; +#ifdef CONFIG_CPU_FREQ + struct notifier_block freq_transition; +#endif + +}; + +typedef enum _TRSP_MODE +{ + TRSP_CLOSE = 0, + TRSP_FMREG, + TRSP_FMREGEX, + TRSP_FMRAM, + TRSP_FMRAMEX, + TRSP_MASK, + TRSP_INVAL +} TRSP_MODE; + + +struct platform_device *g_pdev = NULL; +static int win1fb_set_par(struct fb_info *info); + +#if 0 +#define CHK_SUSPEND(inf) \ + if(inf->in_suspend) { \ + fbprintk(">>>>>> fb is in suspend! return! \n"); \ + return -EPERM; \ + } +#else +#define CHK_SUSPEND(inf) +#endif + +static DECLARE_WAIT_QUEUE_HEAD(wq); +static int wq_condition = 0; + +void set_lcd_pin(struct platform_device *pdev, int enable) +{ + struct rk29fb_info *mach_info = pdev->dev.platform_data; + + unsigned display_on = mach_info->disp_on_pin; + unsigned lcd_standby = mach_info->standby_pin; + + int display_on_pol = mach_info->disp_on_value; + int lcd_standby_pol = mach_info->standby_value; + + fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__); + fbprintk(">>>>>> display_on(%d) = %d \n", display_on, enable ? display_on_pol : !display_on_pol); + fbprintk(">>>>>> lcd_standby(%d) = %d \n", lcd_standby, enable ? lcd_standby_pol : !lcd_standby_pol); + + // set display_on + + if(display_on != INVALID_GPIO) + { + gpio_direction_output(display_on, 0); + gpio_set_value(display_on, enable ? display_on_pol : !display_on_pol); + } + if(lcd_standby != INVALID_GPIO) + { + gpio_direction_output(lcd_standby, 0); + gpio_set_value(lcd_standby, enable ? lcd_standby_pol : !lcd_standby_pol); + } +} + +int mcu_do_refresh(struct rk29fb_inf *inf) +{ + if(inf->mcu_stopflush) return 0; + + if(SCREEN_MCU!=inf->cur_screen->type) return 0; + + // use frame mark + if(IsMcuUseFmk()) + { + inf->mcu_needflush = 1; + return 0; + } + + // not use frame mark + if(LcdReadBit(inf, MCU_TIMING_CTRL, m_MCU_HOLDMODE_SELECT)) + { + if(!LcdReadBit(inf, MCU_TIMING_CTRL, m_MCU_HOLD_STATUS)) + { + inf->mcu_needflush = 1; + } + else + { + if(inf->cur_screen->refresh) inf->cur_screen->refresh(REFRESH_PRE); + inf->mcu_needflush = 0; + inf->mcu_isrcnt = 0; + LcdSetRegBit(inf, MCU_TIMING_CTRL, m_MCU_HOLDMODE_FRAME_ST); + } + } + return 0; +} + + +void mcutimer_callback(unsigned long arg) +{ + struct rk29fb_inf *inf = platform_get_drvdata(g_pdev); + static int waitcnt = 0; + + mod_timer(&inf->mcutimer, jiffies + HZ/10); + + switch(inf->mcu_status) + { + case MS_IDLE: + inf->mcu_status = MS_MCU; + break; + case MS_MCU: + if(inf->mcu_usetimer) mcu_do_refresh(inf); + break; + case MS_EWAITSTART: + inf->mcu_status = MS_EWAITEND; + waitcnt = 0; + break; + case MS_EWAITEND: + if(0==waitcnt) { + mcu_do_refresh(inf); + } + if(waitcnt++>14) { + inf->mcu_status = MS_EEND; + } + break; + case MS_EEND: + inf->mcu_status = MS_MCU; + break; + default: + inf->mcu_status = MS_MCU; + break; + } +} + +int mcu_refresh(struct rk29fb_inf *inf) +{ + static int mcutimer_inited = 0; + + if(SCREEN_MCU!=inf->cur_screen->type) return 0; + + if(!mcutimer_inited) + { + mcutimer_inited = 1; + init_timer(&inf->mcutimer); + inf->mcutimer.function = mcutimer_callback; + inf->mcutimer.expires = jiffies + HZ/5; + inf->mcu_status = MS_IDLE; + add_timer(&inf->mcutimer); + } + + if(MS_MCU==inf->mcu_status) mcu_do_refresh(inf); + + return 0; +} + +int mcu_ioctl(unsigned int cmd, unsigned long arg) +{ + struct rk29fb_inf *inf = NULL; + if(!g_pdev) return -1; + + inf = dev_get_drvdata(&g_pdev->dev); + + switch(cmd) + { + case MCU_WRCMD: + LcdClrBit(inf, MCU_TIMING_CTRL, m_MCU_RS_SELECT); + LcdWrReg(inf, MCU_BYPASS_WPORT, arg); + LcdSetBit(inf, MCU_TIMING_CTRL, m_MCU_RS_SELECT); + break; + + case MCU_WRDATA: + LcdSetBit(inf, MCU_TIMING_CTRL, m_MCU_RS_SELECT); + LcdWrReg(inf, MCU_BYPASS_WPORT, arg); + break; + + case MCU_SETBYPASS: + LcdMskReg(inf, MCU_TIMING_CTRL, m_MCU_BYPASSMODE_SELECT, v_MCU_BYPASSMODE_SELECT(arg)); + LcdWrReg(inf, REG_CFG_DONE, 0x01); + break; + + default: + break; + } + + return 0; +} + +static irqreturn_t mcu_irqfmk(int irq, void *dev_id) +{ + struct platform_device *pdev = (struct platform_device*)dev_id; + struct rk29fb_inf *inf = platform_get_drvdata(pdev); + struct rk29fb_screen *screen; + + if(!inf) return IRQ_HANDLED; + + screen = inf->cur_screen; + + if(0==screen->mcu_usefmk) { + return IRQ_HANDLED; + } + + if(inf->mcu_fmksync == 1) + return IRQ_HANDLED; + + inf->mcu_fmksync = 1; + if(inf->mcu_needflush) + { + inf->mcu_needflush = 0; + inf->mcu_isrcnt = 0; + if(inf->cur_screen->refresh) + inf->cur_screen->refresh(REFRESH_PRE); + LcdSetBit(inf, MCU_TIMING_CTRL, m_MCU_HOLDMODE_FRAME_ST); + } + inf->mcu_fmksync = 0; + + return IRQ_HANDLED; +} + +int init_lcdc(struct fb_info *info) +{ + struct rk29fb_inf *inf = dev_get_drvdata(info->device); + u32 msk=0, clr=0; + + fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__); + + // set AHB access rule and disable all windows + LcdWrReg(inf, SYS_CONFIG, 0x20000000); + LcdWrReg(inf, SWAP_CTRL, 0); + LcdWrReg(inf, FIFO_WATER_MARK, 0x00000860); + + // and mcu holdmode; and set win1 top. + LcdMskReg(inf, MCU_TIMING_CTRL, m_MCU_HOLDMODE_SELECT | m_MCU_HOLDMODE_FRAME_ST | m_MCU_BYPASSMODE_SELECT , + v_MCU_HOLDMODE_SELECT(0)| v_MCU_HOLDMODE_FRAME_ST(0) |v_MCU_BYPASSMODE_SELECT(0)); + + // disable blank out, black out, tristate out, yuv2rgb bypass + LcdMskReg(inf, BLEND_CTRL,m_W2_BLEND_EN | m_W1_BLEND_EN | m_W0_BLEND_EN | m_HWC_BLEND_EN | + m_HWC_BLEND_FACTOR | m_W1_BLEND_FACTOR | m_W0_BLEND_FACTOR, + v_W2_BLEND_EN(0) |v_W1_BLEND_EN(0) | v_W0_BLEND_EN(0) | v_HWC_BLEND_EN(0) | + v_HWC_BLEND_FACTOR(0) | v_W2_BLEND_FACTOR(0) | v_W1_BLEND_FACTOR(0) | v_W0_BLEND_FACTOR(0) + ); + + LcdMskReg(inf, WIN0_COLOR_KEY_CTRL, m_COLORKEY_EN, v_COLORKEY_EN(0)); + LcdMskReg(inf, WIN1_COLOR_KEY_CTRL, m_COLORKEY_EN, v_COLORKEY_EN(0)); + + LcdWrReg(inf, DSP_CTRL0, 0); + LcdWrReg(inf, DSP_CTRL1, 0); + + // initialize all interrupt + clr = v_HOR_STARTCLEAR(1) | v_FRM_STARTCLEAR(1) | v_SCANNING_CLEAR(1); + + msk = v_HOR_STARTMASK(1) | v_FRM_STARTMASK(0) | v_SCANNING_MASK(1); + + LcdWrReg(inf, INT_STATUS, clr | msk); + + // let above to take effect + LcdWrReg(inf, REG_CFG_DONE, 0x01); + + return 0; +} + +void load_screen(struct fb_info *info, bool initscreen) +{ + int ret = -EINVAL; + struct rk29fb_inf *inf = dev_get_drvdata(info->device); + struct rk29fb_screen *screen = inf->cur_screen; + u16 face = screen->face; + u16 mcu_total, mcu_rwstart, mcu_csstart, mcu_rwend, mcu_csend; + u16 right_margin = screen->right_margin, lower_margin = screen->lower_margin; + u16 x_res = screen->x_res, y_res = screen->y_res; + u32 clk_rate = 0; + u32 dclk_rate = 0; + + fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__); + + // set the rgb or mcu + LcdMskReg(inf, MCU_TIMING_CTRL, m_MCU_OUTPUT_SELECT, v_MCU_OUTPUT_SELECT((SCREEN_MCU==screen->type)?(1):(0))); + + // set out format and mcu timing + mcu_total = (screen->mcu_wrperiod*150*1000)/1000000; + if(mcu_total>31) mcu_total = 31; + if(mcu_total<3) mcu_total = 3; + mcu_rwstart = (mcu_total+1)/4 - 1; + mcu_rwend = ((mcu_total+1)*3)/4 - 1; + mcu_csstart = (mcu_rwstart>2) ? (mcu_rwstart-3) : (0); + mcu_csend = (mcu_rwend>15) ? (mcu_rwend-1) : (mcu_rwend); + + fbprintk(">> mcu_total=%d, mcu_rwstart=%d, mcu_csstart=%d, mcu_rwend=%d, mcu_csend=%d \n", + mcu_total, mcu_rwstart, mcu_csstart, mcu_rwend, mcu_csend); + + LcdMskReg(inf, MCU_TIMING_CTRL, + m_MCU_CS_ST | m_MCU_CS_END| m_MCU_RW_ST | m_MCU_RW_END | + m_MCU_WRITE_PERIOD | m_MCU_HOLDMODE_SELECT | m_MCU_HOLDMODE_FRAME_ST, + v_MCU_CS_ST(mcu_csstart) | v_MCU_CS_END(mcu_csend) | v_MCU_RW_ST(mcu_rwstart) | + v_MCU_RW_END(mcu_rwend) | v_MCU_WRITE_PERIOD(mcu_total) | + v_MCU_HOLDMODE_SELECT((SCREEN_MCU==screen->type)?(1):(0)) | v_MCU_HOLDMODE_FRAME_ST(0) + ); + + // set synchronous pin polarity and data pin swap rule + LcdMskReg(inf, DSP_CTRL0, + m_DISPLAY_FORMAT | m_HSYNC_POLARITY | m_VSYNC_POLARITY | m_DEN_POLARITY | + m_DCLK_POLARITY | m_COLOR_SPACE_CONVERSION, + v_DISPLAY_FORMAT(face) | v_HSYNC_POLARITY(screen->pin_hsync) | v_VSYNC_POLARITY(screen->pin_vsync) | + v_DEN_POLARITY(screen->pin_den) | v_DCLK_POLARITY(screen->pin_dclk) | v_COLOR_SPACE_CONVERSION(0) + ); + + LcdMskReg(inf, DSP_CTRL1, m_BG_COLOR, v_BG_COLOR(0x000000) ); + + LcdMskReg(inf, SWAP_CTRL, m_OUTPUT_RB_SWAP | m_OUTPUT_RG_SWAP | m_DELTA_SWAP | m_DUMMY_SWAP, + v_OUTPUT_RB_SWAP(screen->swap_rb) | v_OUTPUT_RG_SWAP(screen->swap_rg) | v_DELTA_SWAP(screen->swap_delta) | v_DUMMY_SWAP(screen->swap_dumy)); + + // set horizontal & vertical out timing + if(SCREEN_MCU==inf->cur_screen->type) + { + right_margin = x_res/6; + } + + printk("screen->hsync_len =%d, screen->left_margin =%d, x_res =%d, right_margin = %d \n", + screen->hsync_len , screen->left_margin , x_res , right_margin ); + LcdMskReg(inf, DSP_HTOTAL_HS_END, m_BIT11LO | m_BIT11HI, v_BIT11LO(screen->hsync_len) | + v_BIT11HI(screen->hsync_len + screen->left_margin + x_res + right_margin)); + LcdMskReg(inf, DSP_HACT_ST_END, m_BIT11LO | m_BIT11HI, v_BIT11LO(screen->hsync_len + screen->left_margin + x_res) | + v_BIT11HI(screen->hsync_len + screen->left_margin)); + + LcdMskReg(inf, DSP_VTOTAL_VS_END, m_BIT11LO | m_BIT11HI, v_BIT11LO(screen->vsync_len) | + v_BIT11HI(screen->vsync_len + screen->upper_margin + y_res + lower_margin)); + LcdMskReg(inf, DSP_VACT_ST_END, m_BIT11LO | m_BIT11HI, v_BIT11LO(screen->vsync_len + screen->upper_margin+y_res)| + v_BIT11HI(screen->vsync_len + screen->upper_margin)); + + LcdMskReg(inf, DSP_VS_ST_END_F1, m_BIT11LO | m_BIT11HI, v_BIT11LO(0) | v_BIT11HI(0)); + LcdMskReg(inf, DSP_VACT_ST_END_F1, m_BIT11LO | m_BIT11HI, v_BIT11LO(0) | v_BIT11HI(0)); + + // let above to take effect + LcdWrReg(inf, REG_CFG_DONE, 0x01); + + // set lcdc clk + if(SCREEN_MCU==screen->type) screen->pixclock = 150; //mcu fix to 150 MHz + + clk_set_parent(inf->dclk_divider, inf->dclk_parent); + clk_set_parent(inf->dclk, inf->dclk_divider); + + dclk_rate = screen->pixclock * 1000000; + + fbprintk(">>>>>> set lcdc dclk need %d HZ, clk_parent = %d hz \n ", screen->pixclock, clk_rate); + +#if 0 + ret = clk_set_rate(inf->dclk_divider, dclk_rate); + + if(ret) + { + printk(KERN_ERR ">>>>>> set lcdc dclk_divider faild \n "); + } + + clk_enable(inf->dclk); + clk_enable(inf->clk); + clk_enable(inf->clk_share_mem); +#endif + + // init screen panel + if(screen->init && initscreen) + { + screen->init(); + } +} +#ifdef CONFIG_CPU_FREQ +/* +* CPU clock speed change handler. We need to adjust the LCD timing +* parameters when the CPU clock is adjusted by the power management +* subsystem. +*/ +#define TO_INF(ptr,member) container_of(ptr,struct rk29fb_inf,member) + +static int +rk29fb_freq_transition(struct notifier_block *nb, unsigned long val, void *data) +{ + struct rk29fb_inf *inf = TO_INF(nb, freq_transition); + struct rk29fb_screen *screen = inf->cur_screen; + u32 dclk_rate = 0; + + switch (val) + { + case CPUFREQ_PRECHANGE: + break; + case CPUFREQ_POSTCHANGE: + { + dclk_rate = screen->pixclock * 1000000; + + fbprintk(">>>>>> set lcdc dclk need %d HZ, clk_parent = %d hz \n ", screen->pixclock, dclk_rate); + + clk_set_rate(inf->dclk_divider, dclk_rate); + break; + } + } + return 0; +} +#endif + +static inline unsigned int chan_to_field(unsigned int chan, + struct fb_bitfield *bf) +{ + chan &= 0xffff; + chan >>= 16 - bf->length; + return chan << bf->offset; +} + +static int fb_setcolreg(unsigned regno, + unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *info) +{ + unsigned int val; +// fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__); + + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + /* true-colour, use pseudo-palette */ + if (regno < 16) { + u32 *pal = info->pseudo_palette; + val = chan_to_field(red, &info->var.red); + val |= chan_to_field(green, &info->var.green); + val |= chan_to_field(blue, &info->var.blue); + pal[regno] = val; + } + break; + default: + return -1; /* unknown type */ + } + + return 0; +} +#if 0 + +int rk29_set_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + struct rk29fb_inf *inf = dev_get_drvdata(info->device); + + //fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__); + + /* check not being asked to exceed capabilities */ + + if (cursor->image.width > 32) + return -EINVAL; + + if (cursor->image.height > 32) + return -EINVAL; + + if (cursor->image.depth > 1) + return -EINVAL; + + if (cursor->enable) + LcdSetBit(inf, SYS_CONFIG, m_HWC_ENABLE); + else + LcdClrBit(inf, SYS_CONFIG, m_HWC_ENABLE); + + /* set data */ + if (cursor->set & FB_CUR_SETPOS) + { + unsigned int x = cursor->image.dx; + unsigned int y = cursor->image.dy; + + if (x >= 0x800 || y >= 0x800 ) + return -EINVAL; + LcdWrReg(inf, HWC_DSP_ST, v_BIT11LO(x)|v_BIT11HI(y)); + } + + + if (cursor->set & FB_CUR_SETCMAP) + { + unsigned int bg_col = cursor->image.bg_color; + unsigned int fg_col = cursor->image.fg_color; + + fbprintk("%s: update cmap (%08x,%08x)\n", + __func__, bg_col, fg_col); + + LcdMskReg(inf, HWC_COLOR_LUT0, m_HWC_R|m_HWC_G|m_HWC_B, + v_HWC_R(info->cmap.red[bg_col]>>8) | v_HWC_G(info->cmap.green[bg_col]>>8) | v_HWC_B(info->cmap.blue[bg_col]>>8)); + + LcdMskReg(inf, HWC_COLOR_LUT2, m_HWC_R|m_HWC_G|m_HWC_B, + v_HWC_R(info->cmap.red[fg_col]>>8) | v_HWC_G(info->cmap.green[fg_col]>>8) | v_HWC_B(info->cmap.blue[fg_col]>>8)); + } + + if ((cursor->set & FB_CUR_SETSIZE || + cursor->set & (FB_CUR_SETIMAGE | FB_CUR_SETSHAPE)) + && info->screen_base && info->fix.smem_start && info->fix.smem_len) + { + /* rk29 cursor is a 2 bpp 32x32 bitmap this routine + * clears it to transparent then combines the cursor + * shape plane with the colour plane to set the + * cursor */ + int x, y; + const unsigned char *pcol = cursor->image.data; + const unsigned char *pmsk = cursor->mask; + void __iomem *dst; + unsigned long cursor_mem_start; + unsigned char dcol = 0; + unsigned char dmsk = 0; + unsigned int op; + + dst = info->screen_base + info->fix.smem_len - CURSOR_BUF_SIZE; + cursor_mem_start = info->fix.smem_start + info->fix.smem_len - CURSOR_BUF_SIZE; + + fbprintk("%s: setting shape (%d,%d)\n", + __func__, cursor->image.width, cursor->image.height); + + memset(dst, 0, CURSOR_BUF_SIZE); + + for (y = 0; y < cursor->image.height; y++) + { + for (x = 0; x < cursor->image.width; x++) + { + if ((x % 8) == 0) { + dcol = *pcol++; + dmsk = *pmsk++; + } else { + dcol >>= 1; + dmsk >>= 1; + } + + if (dmsk & 1) { + op = (dcol & 1) ? 1 : 3; + op <<= ((x % 4) * 2); + *(u8*)(dst+(x/4)) |= op; + } + } + dst += (32*2)/8; + } + LcdSetBit(inf, SYS_CONFIG,m_HWC_RELOAD_EN); + LcdWrReg(inf, HWC_MST, cursor_mem_start); + // flush end when wq_condition=1 in mcu panel, but not in rgb panel + if(SCREEN_MCU == inf->cur_screen->type) { + wait_event_interruptible_timeout(wq, wq_condition, HZ/20); + wq_condition = 0; + } else { + wq_condition = 0; + wait_event_interruptible_timeout(wq, wq_condition, HZ/20); + } + LcdClrBit(inf, SYS_CONFIG, m_HWC_RELOAD_EN); + } + + return 0; +} +#endif + +static int win0fb_blank(int blank_mode, struct fb_info *info) +{ + struct rk29fb_inf *inf = dev_get_drvdata(info->device); + + fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__); + + CHK_SUSPEND(inf); + + switch(blank_mode) + { + case FB_BLANK_UNBLANK: + LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE, v_W0_ENABLE(1)); + break; + default: + LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE, v_W0_ENABLE(0)); + break; + } + LcdWrReg(inf, REG_CFG_DONE, 0x01); + + mcu_refresh(inf); + return 0; +} + +static int win0fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct rk29fb_inf *inf = dev_get_drvdata(info->device); + struct rk29fb_screen *screen = inf->cur_screen; + + u32 ScaleYRGBY=0x1000; + u16 xpos = (var->nonstd>>8) & 0xfff; //offset in panel + u16 ypos = (var->nonstd>>20) & 0xfff; + u16 xsize = (var->grayscale>>8) & 0xfff; //visiable size in panel + u16 ysize = (var->grayscale>>20) & 0xfff; + u16 xlcd = screen->x_res; //size of panel + u16 ylcd = screen->y_res; + u16 yres = 0; + + if(inf->win0fb->var.rotate == 270) { + xlcd = screen->y_res; + ylcd = screen->x_res; + } + + fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__); + + CHK_SUSPEND(inf); + + if( 0==var->xres_virtual || 0==var->yres_virtual || + 0==var->xres || 0==var->yres || var->xres<16 || + 0==xsize || 0==ysize || xsize<16 || + ((16!=var->bits_per_pixel)&&(32!=var->bits_per_pixel)) ) + { + printk(">>>>>> win0fb_check_var fail 1!!! \n"); + printk("0==%d || 0==%d || 0==%d || 0==%d || %d<16 \n ||0==%d || 0==%d || %d<16 ||((16!=%d)&&(32!=%d)) \n", + var->xres_virtual, var->yres_virtual, var->xres, var->yres, var->xres, xsize, ysize, xsize, + var->bits_per_pixel, var->bits_per_pixel); + return -EINVAL; + } + + if( (var->xoffset+var->xres)>var->xres_virtual || + (var->yoffset+var->yres)>var->yres_virtual || + (xpos+xsize)>xlcd || (ypos+ysize)>ylcd ) + { + printk(">>>>>> win0fb_check_var fail 2!!! \n"); + printk("(%d+%d)>%d || (%d+%d)>%d || (%d+%d)>%d || (%d+%d)>%d \n ", + var->xoffset, var->xres, var->xres_virtual, var->yoffset, var->yres, + var->yres_virtual, xpos, xsize, xlcd, ypos, ysize, ylcd); + return -EINVAL; + } + + switch(var->nonstd&0x0f) + { + case 0: // rgb + switch(var->bits_per_pixel) + { + case 16: // rgb565 + var->xres_virtual = (var->xres_virtual + 0x1) & (~0x1); + var->xres = (var->xres + 0x1) & (~0x1); + var->xoffset = (var->xoffset) & (~0x1); + break; + default: // rgb888 + var->bits_per_pixel = 32; + break; + } + var->nonstd &= ~0xc0; //not support I2P in this format + break; + case 1: // yuv422 + var->xres_virtual = (var->xres_virtual + 0x3) & (~0x3); + var->xres = (var->xres + 0x3) & (~0x3); + var->xoffset = (var->xoffset) & (~0x3); + break; + case 2: // yuv4200 + var->xres_virtual = (var->xres_virtual + 0x3) & (~0x3); + var->yres_virtual = (var->yres_virtual + 0x1) & (~0x1); + var->xres = (var->xres + 0x3) & (~0x3); + var->yres = (var->yres + 0x1) & (~0x1); + var->xoffset = (var->xoffset) & (~0x3); + var->yoffset = (var->yoffset) & (~0x1); + break; + case 3: // yuv4201 + var->xres_virtual = (var->xres_virtual + 0x3) & (~0x3); + var->yres_virtual = (var->yres_virtual + 0x1) & (~0x1); + var->xres = (var->xres + 0x3) & (~0x3); + var->yres = (var->yres + 0x1) & (~0x1); + var->xoffset = (var->xoffset) & (~0x3); + var->yoffset = (var->yoffset) & (~0x1); + var->nonstd &= ~0xc0; //not support I2P in this format + break; + case 4: // yuv420m + var->xres_virtual = (var->xres_virtual + 0x7) & (~0x7); + var->yres_virtual = (var->yres_virtual + 0x1) & (~0x1); + var->xres = (var->xres + 0x7) & (~0x7); + var->yres = (var->yres + 0x1) & (~0x1); + var->xoffset = (var->xoffset) & (~0x7); + var->yoffset = (var->yoffset) & (~0x1); + var->nonstd &= ~0xc0; //not support I2P in this format + break; + case 5: // yuv444 + var->xres_virtual = (var->xres_virtual + 0x3) & (~0x3); + var->xres = (var->xres + 0x3) & (~0x3); + var->xoffset = (var->xoffset) & (~0x3); + var->nonstd &= ~0xc0; //not support I2P in this format + break; + default: + printk(">>>>>> win0fb var->nonstd=%d is invalid! \n", var->nonstd); + return -EINVAL; + } + + if(var->rotate == 270) + { + yres = var->xres; + } + else + { + yres = var->yres; + } + ScaleYRGBY = CalScaleW0(yres, ysize); + + if((ScaleYRGBY>0x8000) || (ScaleYRGBY<0x200)) + { + return -EINVAL; // multiple of scale down or scale up can't exceed 8 + } + + return 0; +} + +static int win0fb_set_par(struct fb_info *info) +{ + struct rk29fb_inf *inf = dev_get_drvdata(info->device); + struct rk29fb_screen *screen = inf->cur_screen; + struct fb_var_screeninfo *var = &info->var; + struct fb_fix_screeninfo *fix = &info->fix; + struct win0_par *par = info->par; + + u8 format = 0; + u32 cblen=0, crlen=0, map_size=0, smem_len=0; + + u32 xact = var->xres; /* visible resolution */ + u32 yact = var->yres; + u32 xvir = var->xres_virtual; /* virtual resolution */ + u32 yvir = var->yres_virtual; + u32 xact_st = var->xoffset; /* offset from virtual to visible */ + u32 yact_st = var->yoffset; /* resolution */ + + u16 xpos = (var->nonstd>>8) & 0xfff; //visiable pos in panel + u16 ypos = (var->nonstd>>20) & 0xfff; + u16 xsize = (var->grayscale>>8) & 0xfff; //visiable size in panel + u16 ysize = (var->grayscale>>20) & 0xfff; + + u32 ScaleYrgbX=0x1000,ScaleYrgbY=0x1000; + u32 ScaleCbrX=0x1000, ScaleCbrY=0x1000; + + u8 data_format = var->nonstd&0x0f; + u32 win0_en = var->reserved[2]; + u32 y_addr = var->reserved[3]; //user alloc buf addr y + u32 uv_addr = var->reserved[4]; + + fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__); + + CHK_SUSPEND(inf); + + /* calculate y_offset,uv_offset,line_length,cblen and crlen */ + switch (data_format) + { + case 0: // rgb + switch(var->bits_per_pixel) + { + case 16: // rgb565 + format = 1; + fix->line_length = 2 * xvir; + par->y_offset = (yact_st*xvir + xact_st)*2; + break; + case 32: // rgb888 + format = 0; + fix->line_length = 4 * xvir; + par->y_offset = (yact_st*xvir + xact_st)*4; + break; + default: + return -EINVAL; + } + break; + case 1: // yuv422 + format = 2; + fix->line_length = xvir; + cblen = crlen = (xvir*yvir)/2; + par->y_offset = yact_st*xvir + xact_st; + par->uv_offset = yact_st*xvir + xact_st; + break; + case 2: // yuv4200 + format = 3; + fix->line_length = xvir; + cblen = crlen = (xvir*yvir)/4; + + par->y_offset = yact_st*xvir + xact_st; + par->uv_offset = (yact_st/2)*xvir + xact_st; + + break; + case 3: // yuv4201 + format = 4; + fix->line_length = xvir; + par->y_offset = (yact_st/2)*2*xvir + (xact_st)*2; + par->uv_offset = (yact_st/2)*xvir + xact_st; + cblen = crlen = (xvir*yvir)/4; + break; + case 4: // yuv420m + format = 5; + fix->line_length = xvir; + par->y_offset = (yact_st/2)*3*xvir + (xact_st)*3; + cblen = crlen = (xvir*yvir)/4; + break; + case 5: // yuv444 + format = 6; + fix->line_length = xvir; + par->y_offset = yact_st*xvir + xact_st; + par->uv_offset = yact_st*2*xvir + xact_st*2; + cblen = crlen = (xvir*yvir); + break; + default: + return -EINVAL; + } + + smem_len = fix->line_length * yvir + cblen + crlen; + map_size = PAGE_ALIGN(smem_len); + + if (info->screen_base) { + printk(">>>>>> win0fb unmap memory(%d)! \n", info->fix.smem_len); + dma_free_writecombine(NULL, PAGE_ALIGN(info->fix.smem_len),info->screen_base, info->fix.smem_start); + info->screen_base = 0; + } + fix->smem_start = y_addr; + fix->smem_len = smem_len; + fix->mmio_start = uv_addr; + + par->addr_seted = ((-1==(int)y_addr)&&(-1==(int)uv_addr)) ? 0 : 1; + fbprintk("buffer alloced by user fix->smem_start = %8x, fix->smem_len = %8x, fix->mmio_start = %8x \n", (u32)fix->smem_start, (u32)fix->smem_len, (u32)fix->mmio_start); + + // calculate the display phy address + y_addr = fix->smem_start + par->y_offset; + uv_addr = fix->mmio_start + par->uv_offset; + + fbprintk("y_addr 0x%08x = 0x%08x + %d\n", y_addr, (u32)fix->smem_start, par->y_offset); + fbprintk("uv_addr 0x%08x = 0x%08x + %d\n", uv_addr, (u32)fix->mmio_start , par->uv_offset); + + ScaleYrgbX = CalScaleW0(xact, xsize); + ScaleYrgbY = CalScaleW0(yact, ysize); + + switch (data_format) + { + case 1:// yuv422 + ScaleCbrX= CalScaleW0((xact/2), xsize); + ScaleCbrY = CalScaleW0(yact, ysize); + break; + case 2: // yuv4200 + case 3: // yuv4201 + case 4: // yuv420m + ScaleCbrX= CalScaleW0(xact/2, xsize); + ScaleCbrY = CalScaleW0(yact/2, ysize); + break; + case 5:// yuv444 + ScaleCbrX= CalScaleW0(xact, xsize); + ScaleCbrY = CalScaleW0(yact, ysize); + break; + } + + xpos += (screen->left_margin + screen->hsync_len); + ypos += (screen->upper_margin + screen->vsync_len); + + LcdWrReg(inf, WIN0_YRGB_MST, y_addr); + LcdWrReg(inf, WIN0_CBR_MST, uv_addr); + + LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE | m_W0_FORMAT, v_W0_ENABLE(win0_en) | v_W0_FORMAT(format)); + + LcdMskReg(inf, WIN0_VIR, m_WORDLO | m_WORDHI, v_VIRWIDTH(xvir) | v_VIRHEIGHT((yvir)) ); + LcdMskReg(inf, WIN0_ACT_INFO, m_WORDLO | m_WORDHI, v_WORDLO(xact) | v_WORDHI(yact)); + LcdMskReg(inf, WIN0_DSP_ST, m_BIT11LO | m_BIT11HI, v_BIT11LO(xpos) | v_BIT11HI(ypos)); + LcdMskReg(inf, WIN0_DSP_INFO, m_BIT11LO | m_BIT11HI, v_BIT11LO(xsize) | v_BIT11HI(ysize)); + LcdMskReg(inf, WIN0_SCL_FACTOR_YRGB, m_WORDLO | m_WORDHI, v_WORDLO(ScaleYrgbX) | v_WORDHI(ScaleYrgbY)); + LcdMskReg(inf, WIN0_SCL_FACTOR_CBR, m_WORDLO | m_WORDHI, v_WORDLO(ScaleCbrX) | v_WORDHI(ScaleCbrY)); + + switch(format) + { + case 1: //rgb565 + LcdMskReg(inf, SWAP_CTRL, m_W0_YRGB_8_SWAP | m_W0_YRGB_16_SWAP | m_W0_YRGB_R_SHIFT_SWAP | m_W0_565_RB_SWAP | m_W0_YRGB_M8_SWAP | m_W0_CBR_8_SWAP, + v_W0_YRGB_8_SWAP(0) | v_W0_YRGB_16_SWAP(0) | v_W0_YRGB_R_SHIFT_SWAP(0) | v_W0_565_RB_SWAP(1) | v_W0_YRGB_M8_SWAP(0) | v_W0_CBR_8_SWAP(0)); + break; + case 4: //yuv4201 + LcdMskReg(inf, SWAP_CTRL, m_W0_YRGB_8_SWAP | m_W0_YRGB_16_SWAP | m_W0_YRGB_R_SHIFT_SWAP | m_W0_565_RB_SWAP | m_W0_YRGB_M8_SWAP | m_W0_CBR_8_SWAP, + v_W0_YRGB_8_SWAP(0) | v_W0_YRGB_16_SWAP(0) | v_W0_YRGB_R_SHIFT_SWAP(0) | v_W0_565_RB_SWAP(0) | + v_W0_YRGB_M8_SWAP((var->rotate==0)) | v_W0_CBR_8_SWAP(0)); + break; + default: + LcdMskReg(inf, SWAP_CTRL, m_W0_YRGB_8_SWAP | m_W0_YRGB_16_SWAP | m_W0_YRGB_R_SHIFT_SWAP | m_W0_565_RB_SWAP | m_W0_YRGB_M8_SWAP | m_W0_CBR_8_SWAP, + v_W0_YRGB_8_SWAP(0) | v_W0_YRGB_16_SWAP(0) | v_W0_YRGB_R_SHIFT_SWAP(0) | v_W0_565_RB_SWAP(0) | v_W0_YRGB_M8_SWAP(0) | v_W0_CBR_8_SWAP(0) ); + } + + LcdWrReg(inf, REG_CFG_DONE, 0x01); + + return 0; +} + +static int win0fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct rk29fb_inf *inf = dev_get_drvdata(info->device); + // struct fb_var_screeninfo *var0 = &info->var; + struct fb_fix_screeninfo *fix0 = &info->fix; + struct win0_par *par = info->par; + u32 y_addr=0, uv_addr=0; + + fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__); + + CHK_SUSPEND(inf); + + y_addr = fix0->smem_start + par->y_offset;//y_offset; + uv_addr = fix0->mmio_start + par->uv_offset ;//uv_offset; + + LcdWrReg(inf, WIN0_YRGB_MST, y_addr); + LcdWrReg(inf, WIN0_CBR_MST, uv_addr); + LcdWrReg(inf, REG_CFG_DONE, 0x01); + + // enable win0 after the win0 addr is seted + par->par_seted = 1; + LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE, v_W0_ENABLE((1==par->addr_seted)?(1):(0))); + mcu_refresh(inf); + + return 0; +} + +int win0fb_open(struct fb_info *info, int user) +{ + struct win0_par *par = info->par; + + fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__); + + par->par_seted = 0; + par->addr_seted = 0; + + if(par->refcount) { + printk(">>>>>> win0fb has opened! \n"); + return -EACCES; + } else { + par->refcount++; + return 0; + } +} + +int win0fb_release(struct fb_info *info, int user) +{ + struct win0_par *par = info->par; + struct fb_var_screeninfo *var0 = &info->var; + + fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__); + + if(par->refcount) { + par->refcount--; + + win0fb_blank(FB_BLANK_POWERDOWN, info); + // wait for lcdc stop access memory + msleep(50); + + // unmap memory + if (info->screen_base) { + printk(">>>>>> win0fb unmap memory(%d)! \n", info->fix.smem_len); + dma_free_writecombine(NULL, PAGE_ALIGN(info->fix.smem_len),info->screen_base, info->fix.smem_start); + info->screen_base = 0; + info->fix.smem_start = 0; + info->fix.smem_len = 0; + } + + // clean the var param + memset(var0, 0, sizeof(struct fb_var_screeninfo)); + } + + return 0; +} + +static int win0fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +{ + struct rk29fb_inf *inf = dev_get_drvdata(info->device); + struct win0_par *par = info->par; + void __user *argp = (void __user *)arg; + + fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__); + fbprintk("win0fb_ioctl cmd = %8x, arg = %8x \n", (u32)cmd, (u32)arg); + + CHK_SUSPEND(inf); + + switch(cmd) + { + case FB1_IOCTL_GET_PANEL_SIZE: //get panel size + { + u32 panel_size[2]; + if(inf->win0fb->var.rotate == 270) { + panel_size[0] = inf->cur_screen->y_res; + panel_size[1] = inf->cur_screen->x_res; + } else { + panel_size[0] = inf->cur_screen->x_res; + panel_size[1] = inf->cur_screen->y_res; + } + + if(copy_to_user(argp, panel_size, 8)) return -EFAULT; + } + break; + + case FB1_IOCTL_SET_YUV_ADDR: //set y&uv address to register direct + { + u32 yuv_phy[2]; + if (copy_from_user(yuv_phy, argp, 8)) + return -EFAULT; + + yuv_phy[0] += par->y_offset; + yuv_phy[1] += par->uv_offset; + + LcdWrReg(inf, WIN0_YRGB_MST, yuv_phy[0]); + LcdWrReg(inf, WIN0_CBR_MST, yuv_phy[1]); + LcdWrReg(inf, REG_CFG_DONE, 0x01); + // enable win0 after the win0 par is seted + par->addr_seted = 1; + if(par->par_seted) { + LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE, v_W0_ENABLE(1)); + mcu_refresh(inf); + } + } + break; + + case FB1_IOCTL_SET_ROTATE: //change MCU panel scan direction + fbprintk(">>>>>> change lcdc direction(%d) \n", (int)arg); + return -1; + break; + default: + break; + } + return 0; +} + +static struct fb_ops win0fb_ops = { + .owner = THIS_MODULE, + .fb_open = win0fb_open, + .fb_release = win0fb_release, + .fb_check_var = win0fb_check_var, + .fb_set_par = win0fb_set_par, + .fb_blank = win0fb_blank, + .fb_pan_display = win0fb_pan_display, + .fb_ioctl = win0fb_ioctl, + .fb_setcolreg = fb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +}; + +static int win1fb_blank(int blank_mode, struct fb_info *info) +{ + struct rk29fb_inf *inf = dev_get_drvdata(info->device); + + fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__); + + CHK_SUSPEND(inf); + + switch(blank_mode) + { + case FB_BLANK_UNBLANK: + LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE, v_W1_ENABLE(1)); + break; + default: + LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE, v_W1_ENABLE(0)); + break; + } + LcdWrReg(inf, REG_CFG_DONE, 0x01); + + mcu_refresh(inf); + return 0; +} + +static int win1fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct rk29fb_inf *inf = dev_get_drvdata(info->device); + struct rk29fb_screen *screen = inf->cur_screen; + u16 xpos = (var->nonstd>>8) & 0xfff; + u16 ypos = (var->nonstd>>20) & 0xfff; + u16 xlcd = screen->x_res; + u16 ylcd = screen->y_res; + u8 trspmode = (var->grayscale>>8) & 0xff; + u8 trspval = (var->grayscale) & 0xff; + + fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__); + + CHK_SUSPEND(inf); + +#if (0==WIN1_USE_DOUBLE_BUF) + if(var->yres_virtual>ylcd) + var->yres_virtual = ylcd; +#endif + + if( 0==var->xres_virtual || 0==var->yres_virtual || + 0==var->xres || 0==var->yres || var->xres<16 || + trspmode>5 || trspval>16 || + ((16!=var->bits_per_pixel)&&(32!=var->bits_per_pixel)) ) + { + printk(">>>>>> win1fb_check_var fail 1!!! \n"); + printk(">>>>>> 0==%d || 0==%d ", var->xres_virtual,var->yres_virtual); + printk("0==%d || 0==%d || %d<16 || ", var->xres,var->yres,var->xres<16); + printk("%d>5 || %d>16 \n", trspmode,trspval); + printk("bits_per_pixel=%d \n", var->bits_per_pixel); + return -EINVAL; + } + + if( (var->xoffset+var->xres)>var->xres_virtual || + (var->yoffset+var->yres)>var->yres_virtual || + (xpos+var->xres)>xlcd || (ypos+var->yres)>ylcd ) + { + printk(">>>>>> win1fb_check_var fail 2!!! \n"); + printk(">>>>>> (%d+%d)>%d || ", var->xoffset,var->xres,var->xres_virtual); + printk("(%d+%d)>%d || ", var->yoffset,var->yres,var->yres_virtual); + printk("(%d+%d)>%d || (%d+%d)>%d \n", xpos,var->xres,xlcd,ypos,var->yres,ylcd); + return -EINVAL; + } + + switch(var->bits_per_pixel) + { + case 16: // rgb565 + var->xres_virtual = (var->xres_virtual + 0x1) & (~0x1); + var->xres = (var->xres + 0x1) & (~0x1); + var->xoffset = (var->xoffset) & (~0x1); + break; + default: // rgb888 + var->bits_per_pixel = 32; + break; + } + + return 0; +} + +static int win1fb_set_par(struct fb_info *info) +{ + struct rk29fb_inf *inf = dev_get_drvdata(info->device); + struct fb_var_screeninfo *var = &info->var; + struct fb_fix_screeninfo *fix = &info->fix; + struct rk29fb_screen *screen = inf->cur_screen; + + + u8 format = 0; + dma_addr_t map_dma; + u32 offset=0, addr=0, map_size=0, smem_len=0; + + u16 xres_virtual = var->xres_virtual; //virtual screen size + //u16 yres_virtual = var->yres_virtual; + + u16 xpos_virtual = var->xoffset; //visiable offset in virtual screen + u16 ypos_virtual = var->yoffset; + + u16 xpos = 0; //visiable offset in panel + u16 ypos = 0; + u16 xsize = screen->x_res; //visiable size in panel + u16 ysize = screen->y_res; + u8 trspmode = TRSP_CLOSE; + u8 trspval = 0; + + fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__); + + CHK_SUSPEND(inf); + + switch(var->bits_per_pixel) + { + case 16: // rgb565 + format = 1; + fix->line_length = 2 * xres_virtual; + offset = (ypos_virtual*xres_virtual + xpos_virtual)*2; + break; + case 32: // rgb888 + default: + format = 0; + fix->line_length = 4 * xres_virtual; + offset = (ypos_virtual*xres_virtual + xpos_virtual)*4; + break; + } + + smem_len = fix->line_length * var->yres_virtual + CURSOR_BUF_SIZE; //cursor buf also alloc here + map_size = PAGE_ALIGN(smem_len); + +#if WIN1_USE_DOUBLE_BUF + if( var->yres_virtual == 2*screen->y_res ) { + inf->mcu_usetimer = 0; + } + if(0==fix->smem_len) { + smem_len = smem_len*2; + map_size = PAGE_ALIGN(smem_len); + fbprintk(">>>>>> first alloc, alloc double!!! \n "); + } +#endif + +#if WIN1_USE_DOUBLE_BUF + if (smem_len > fix->smem_len) // buffer need realloc +#else + if (smem_len != fix->smem_len) // buffer need realloc +#endif + { + fbprintk(">>>>>> win1 buffer size is change(%d->%d)! remap memory!\n",fix->smem_len, smem_len); + fbprintk(">>>>>> smem_len %d = %d * %d \n", smem_len, fix->line_length, var->yres_virtual); + fbprintk(">>>>>> map_size = %d\n", map_size); + LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE, v_W1_ENABLE(0)); + LcdWrReg(inf, REG_CFG_DONE, 0x01); + msleep(50); + if (info->screen_base) { + printk(">>>>>> win1fb unmap memory(%d)! \n", info->fix.smem_len); + dma_free_writecombine(NULL, PAGE_ALIGN(info->fix.smem_len), info->screen_base, info->fix.smem_start); + info->screen_base = 0; + fix->smem_start = 0; + fix->smem_len = 0; + } + + info->screen_base = dma_alloc_writecombine(NULL, map_size, &map_dma, GFP_KERNEL); + if(!info->screen_base) { + printk(">>>>>> win1fb dma_alloc_writecombine fail!\n"); + return -ENOMEM; + } + memset(info->screen_base, 0, map_size); + fix->smem_start = map_dma; + fix->smem_len = smem_len; + fbprintk(">>>>>> alloc succ, mem=%08x, len=%d!\n", (u32)fix->smem_start, fix->smem_len); + } + + addr = fix->smem_start + offset; + + + LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE|m_W1_FORMAT, v_W1_ENABLE(1)|v_W1_FORMAT(format)); + + xpos += (screen->left_margin + screen->hsync_len); + ypos += (screen->upper_margin + screen->vsync_len); + + LcdWrReg(inf, WIN1_YRGB_MST, addr); + + LcdMskReg(inf, WIN1_DSP_ST, m_BIT11LO|m_BIT11HI, v_BIT11LO(xpos) | v_BIT11HI(ypos)); + LcdMskReg(inf, WIN1_DSP_INFO, m_BIT11LO|m_BIT11HI, v_BIT11LO(xsize) | v_BIT11HI(ysize)); + + LcdMskReg(inf, WIN1_VIR, m_WORDLO | m_WORDHI , v_WORDLO(xres_virtual) | v_WORDHI(var->yres_virtual)); + + LcdMskReg(inf, BLEND_CTRL, m_W1_BLEND_EN | m_W1_BLEND_FACTOR, + v_W1_BLEND_EN((TRSP_FMREG==trspmode) || (TRSP_MASK==trspmode)) | v_W1_BLEND_FACTOR(trspval)); + + // enable win1 color key and set the color to black(rgb=0) + LcdMskReg(inf, WIN1_COLOR_KEY_CTRL, m_COLORKEY_EN | m_KEYCOLOR, v_COLORKEY_EN(1) | v_KEYCOLOR(0)); + + if(1==format) //rgb565 + { + LcdMskReg(inf, SWAP_CTRL, m_W1_8_SWAP | m_W1_16_SWAP | m_W1_R_SHIFT_SWAP | m_W1_565_RB_SWAP, + v_W1_8_SWAP(0) | v_W1_16_SWAP(0) | v_W1_R_SHIFT_SWAP(0) | v_W1_565_RB_SWAP(0) ); + } + else + { + LcdMskReg(inf, SWAP_CTRL, m_W1_8_SWAP | m_W1_16_SWAP | m_W1_R_SHIFT_SWAP | m_W1_565_RB_SWAP, + v_W1_8_SWAP(0) | v_W1_16_SWAP(0) | v_W1_R_SHIFT_SWAP(0) | v_W1_565_RB_SWAP(0) ); + + LcdMskReg(inf, DSP_CTRL0, m_W1_TRANSP_FROM, v_W1_TRANSP_FROM(TRSP_FMRAM==trspmode) ); + } + + LcdWrReg(inf, REG_CFG_DONE, 0x01); + + return 0; +} + +static int win1fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct rk29fb_inf *inf = dev_get_drvdata(info->device); + struct fb_var_screeninfo *var1 = &info->var; + struct fb_fix_screeninfo *fix1 = &info->fix; + int i; + u32 offset = 0, addr = 0; + + fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__); + + CHK_SUSPEND(inf); + + switch(var1->bits_per_pixel) + { + case 16: // rgb565 + var->xoffset = (var->xoffset) & (~0x1); + offset = (var->yoffset*var1->xres_virtual + var->xoffset)*2; + break; + case 32: // rgb888 + offset = (var->yoffset*var1->xres_virtual + var->xoffset)*4; + break; + default: + return -EINVAL; + } + + addr = fix1->smem_start + offset; + + fbprintk("info->screen_base = %8x ; fix1->smem_len = %d , addr = %8x\n",(u32)info->screen_base, fix1->smem_len, addr); + + LcdWrReg(inf, WIN1_YRGB_MST, addr); + LcdWrReg(inf, REG_CFG_DONE, 0x01); + + mcu_refresh(inf); + + // flush end when wq_condition=1 in mcu panel, but not in rgb panel + if(SCREEN_MCU == inf->cur_screen->type) { + wait_event_interruptible_timeout(wq, wq_condition, HZ/20); + wq_condition = 0; + } else { + wq_condition = 0; + wait_event_interruptible_timeout(wq, wq_condition, HZ/20); + } + +#if 0 + for(i=0;i<=(0xc0/4);i+=4) + { + fbprintk("0x%02X: 0x%08X 0x%08X 0x%08X 0x%08X \n", i*4, + *((u32*)inf->reg_vir_base+i), + *((u32*)inf->reg_vir_base+i+1), + *((u32*)inf->reg_vir_base+i+2), + *((u32*)inf->reg_vir_base+i+3)); + } +#endif + + return 0; +} + + +static int win1fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +{ + struct rk29fb_inf *inf = dev_get_drvdata(info->device); + struct rk29fb_info *mach_info = info->device->platform_data; + unsigned display_on; + int display_on_pol; + + fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__); + + CHK_SUSPEND(inf); + + switch(cmd) + { + case FB0_IOCTL_STOP_TIMER_FLUSH: //stop timer flush mcu panel after android is runing + if(1==arg) + { + inf->mcu_usetimer = 0; + } + break; + + case FB0_IOCTL_SET_PANEL: + if(arg>7) return -1; + + /* Black out, because some display device need clock to standby */ + //LcdMskReg(inf, DSP_CTRL_REG1, m_BLACK_OUT, v_BLACK_OUT(1)); + LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE, v_W0_ENABLE(0)); + LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE, v_W1_ENABLE(0)); + LcdMskReg(inf, DSP_CTRL1, m_BLACK_MODE, v_BLACK_MODE(1)); + LcdWrReg(inf, REG_CFG_DONE, 0x01); + if(inf->cur_screen) + { + if(inf->cur_screen->standby) inf->cur_screen->standby(1); + // operate the display_on pin to power down the lcd + if(SCREEN_RGB==inf->cur_screen->type || SCREEN_MCU==inf->cur_screen->type) + { + if(mach_info && mach_info->disp_on_pin) + { + display_on = mach_info->disp_on_pin; + display_on_pol = mach_info->disp_on_value; + gpio_direction_output(display_on, 0); + gpio_set_value(display_on, !display_on_pol); + } + } + } + + /* Load the new device's param */ + switch(arg) + { + case 0: inf->cur_screen = &inf->lcd_info; break; //lcd + case 1: inf->cur_screen = &inf->tv_info[0]; break; //tv ntsc cvbs + case 2: inf->cur_screen = &inf->tv_info[1]; break; //tv pal cvbs + case 3: inf->cur_screen = &inf->tv_info[2]; break; //tv 480 ypbpr + case 4: inf->cur_screen = &inf->tv_info[3]; break; //tv 576 ypbpr + case 5: inf->cur_screen = &inf->tv_info[4]; break; //tv 720 ypbpr + case 6: inf->cur_screen = &inf->hdmi_info[0]; break; //hdmi 576 + case 7: inf->cur_screen = &inf->hdmi_info[1]; break; //hdmi 720 + default: break; + } + load_screen(info, 1); + mcu_refresh(inf); + break; + default: + break; + } + return 0; +} + + +static struct fb_ops win1fb_ops = { + .owner = THIS_MODULE, + .fb_check_var = win1fb_check_var, + .fb_set_par = win1fb_set_par, + .fb_blank = win1fb_blank, + .fb_pan_display = win1fb_pan_display, + .fb_ioctl = win1fb_ioctl, + .fb_setcolreg = fb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + //.fb_cursor = rk29_set_cursor, +}; + + +static irqreturn_t rk29fb_irq(int irq, void *dev_id) +{ + struct platform_device *pdev = (struct platform_device*)dev_id; + struct rk29fb_inf *inf = platform_get_drvdata(pdev); + if(!inf) + return IRQ_HANDLED; + + //fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__); + + LcdMskReg(inf, INT_STATUS, m_FRM_STARTCLEAR, v_FRM_STARTCLEAR(1)); + + if(SCREEN_MCU == inf->cur_screen->type) + { + inf->mcu_isrcnt = !inf->mcu_isrcnt; + if(inf->mcu_isrcnt) + return IRQ_HANDLED; + + if(IsMcuUseFmk()) + { + if(LcdReadBit(inf, MCU_TIMING_CTRL, m_MCU_HOLD_STATUS) && (inf->mcu_fmksync == 0)) + { + inf->mcu_fmksync = 1; + if(inf->cur_screen->refresh) + inf->cur_screen->refresh(REFRESH_END); + inf->mcu_fmksync = 0; + } + else + { + return IRQ_HANDLED; + } + } + else + { + if(inf->mcu_needflush) { + if(inf->cur_screen->refresh) + inf->cur_screen->refresh(REFRESH_PRE); + inf->mcu_needflush = 0; + inf->mcu_isrcnt = 0; + LcdSetRegBit(inf, MCU_TIMING_CTRL, m_MCU_HOLDMODE_FRAME_ST); + } else { + if(inf->cur_screen->refresh) + inf->cur_screen->refresh(REFRESH_END); + } + } + } + + wq_condition = 1; + wake_up_interruptible(&wq); + + return IRQ_HANDLED; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND + +struct suspend_info { + struct early_suspend early_suspend; + struct rk29fb_inf *inf; +}; + +void suspend(struct early_suspend *h) +{ + struct suspend_info *info = container_of(h, struct suspend_info, + early_suspend); + + struct rk29fb_inf *inf = info->inf; + + fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__); + + if(!inf) { + printk("inf==0, rk29fb_suspend fail! \n"); + return; + } + + set_lcd_pin(g_pdev, 0); + + if(inf->cur_screen->standby) + { + fbprintk(">>>>>> power down the screen! \n"); + inf->cur_screen->standby(1); + } + + LcdMskReg(inf, DSP_CTRL1, m_BLANK_MODE , v_BLANK_MODE(1)); + LcdMskReg(inf, SYS_CONFIG, m_STANDBY, v_STANDBY(1)); + LcdWrReg(inf, REG_CFG_DONE, 0x01); + + if(!inf->in_suspend) + { + fbprintk(">>>>>> diable the lcdc clk! \n"); + msleep(100); + if (inf->dclk){ + clk_disable(inf->dclk); + } + if(inf->clk){ + clk_disable(inf->clk); + } + + inf->in_suspend = 1; + } + +} + +void resume(struct early_suspend *h) +{ + struct suspend_info *info = container_of(h, struct suspend_info, + early_suspend); + + struct rk29fb_inf *inf = info->inf; + + fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__); + if(!inf) { + printk("inf==0, rk29fb_resume fail! \n"); + return ; + } + + if(inf->in_suspend) + { + inf->in_suspend = 0; + fbprintk(">>>>>> enable the lcdc clk! \n"); + if (inf->dclk){ + clk_enable(inf->dclk); + } + if(inf->clk){ + clk_enable(inf->clk); + } + msleep(100); + } + LcdMskReg(inf, DSP_CTRL1, m_BLANK_MODE , v_BLANK_MODE(0)); + LcdMskReg(inf, SYS_CONFIG, m_STANDBY, v_STANDBY(0)); + LcdWrReg(inf, REG_CFG_DONE, 0x01); + + if(inf->cur_screen->standby) + { + fbprintk(">>>>>> power on the screen! \n"); + inf->cur_screen->standby(0); + } + msleep(100); + set_lcd_pin(g_pdev, 1); + memcpy(inf->preg, &inf->regbak, 0xa4); //resume reg +} + +struct suspend_info suspend_info = { + .early_suspend.suspend = suspend, + .early_suspend.resume = resume, + .early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB, +}; +#endif + +static int __init rk29fb_probe (struct platform_device *pdev) +{ + struct rk29fb_inf *inf = NULL; + struct resource *res = NULL; + struct resource *mem = NULL; + struct rk29fb_info *mach_info = NULL; + struct rk29fb_screen *screen = NULL; + int irq = 0; + int ret = 0; + + fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__); + + /* Malloc rk29fb_inf and set it to pdev for drvdata */ + fbprintk(">> Malloc rk29fb_inf and set it to pdev for drvdata \n"); + inf = kmalloc(sizeof(struct rk29fb_inf), GFP_KERNEL); + if(!inf) + { + dev_err(&pdev->dev, ">> inf kmalloc fail!"); + ret = -ENOMEM; + goto release_drvdata; + } + memset(inf, 0, sizeof(struct rk29fb_inf)); + platform_set_drvdata(pdev, inf); + + mach_info = pdev->dev.platform_data; + /* Fill screen info and set current screen */ + fbprintk(">> Fill screen info and set current screen \n"); + set_lcd_info(&inf->lcd_info, mach_info->lcd_info); + set_tv_info(&inf->tv_info[0]); + set_hdmi_info(&inf->hdmi_info[0]); + inf->cur_screen = &inf->lcd_info; + screen = inf->cur_screen; + if(SCREEN_NULL==screen->type) + { + dev_err(&pdev->dev, ">> Please select a display device! \n"); + ret = -EINVAL; + goto release_drvdata; + } + + /* get virtual basic address of lcdc register */ + fbprintk(">> get virtual basic address of lcdc register \n"); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) + { + dev_err(&pdev->dev, "failed to get memory registers\n"); + ret = -ENOENT; + goto release_drvdata; + } + inf->reg_phy_base = res->start; + inf->len = (res->end - res->start) + 1; + mem = request_mem_region(inf->reg_phy_base, inf->len, pdev->name); + if (mem == NULL) + { + dev_err(&pdev->dev, "failed to get memory region\n"); + ret = -ENOENT; + goto release_drvdata; + } + fbprintk("inf->reg_phy_base = 0x%08x, inf->len = %d \n", inf->reg_phy_base, inf->len); + inf->reg_vir_base = ioremap(inf->reg_phy_base, inf->len); + if (inf->reg_vir_base == NULL) + { + dev_err(&pdev->dev, "ioremap() of registers failed\n"); + ret = -ENXIO; + goto release_drvdata; + } + inf->preg = (LCDC_REG*)inf->reg_vir_base; + + if(0) + { + struct resource *rtc_mem = NULL; + u32 rtc_reg_vir_base = NULL; + rtc_mem = request_mem_region(RK29_RTC_PHYS, RK29_RTC_SIZE, NULL); + rtc_reg_vir_base = (u32)ioremap(RK29_RTC_PHYS, RK29_RTC_SIZE); + u32 rtc_reg = __raw_readl(rtc_reg_vir_base+0x04); + __raw_writel( rtc_reg | 0x02, rtc_reg_vir_base+0x04 ); + rtc_reg = __raw_readl(rtc_reg_vir_base+0x04); + } + + + /* Prepare win1 info */ + fbprintk(">> Prepare win1 info \n"); + inf->win1fb = framebuffer_alloc(sizeof(struct win1_par), &pdev->dev); + if(!inf->win1fb) + { + dev_err(&pdev->dev, ">> win1fb framebuffer_alloc fail!"); + inf->win1fb = NULL; + ret = -ENOMEM; + goto release_win1fb; + } + + strcpy(inf->win1fb->fix.id, "win1fb"); + inf->win1fb->fix.type = FB_TYPE_PACKED_PIXELS; + inf->win1fb->fix.type_aux = 0; + inf->win1fb->fix.xpanstep = 1; + inf->win1fb->fix.ypanstep = 1; + inf->win1fb->fix.ywrapstep = 0; + inf->win1fb->fix.accel = FB_ACCEL_NONE; + inf->win1fb->fix.visual = FB_VISUAL_TRUECOLOR; + inf->win1fb->fix.smem_len = 0; + inf->win1fb->fix.line_length = 0; + inf->win1fb->fix.smem_start = 0; + + inf->win1fb->var.xres = screen->x_res; + inf->win1fb->var.yres = screen->y_res; + inf->win1fb->var.bits_per_pixel = 16; + inf->win1fb->var.xres_virtual = screen->x_res; + inf->win1fb->var.yres_virtual = screen->y_res; + inf->win1fb->var.width = screen->x_res; + inf->win1fb->var.height = screen->y_res; + inf->win1fb->var.pixclock = screen->pixclock; + inf->win1fb->var.left_margin = screen->left_margin; + inf->win1fb->var.right_margin = screen->right_margin; + inf->win1fb->var.upper_margin = screen->upper_margin; + inf->win1fb->var.lower_margin = screen->lower_margin; + inf->win1fb->var.vsync_len = screen->vsync_len; + inf->win1fb->var.hsync_len = screen->hsync_len; + inf->win1fb->var.red = def_rgb_16.red; + inf->win1fb->var.green = def_rgb_16.green; + inf->win1fb->var.blue = def_rgb_16.blue; + inf->win1fb->var.transp = def_rgb_16.transp; + + inf->win1fb->var.nonstd = 0; //win1 format & ypos & xpos (ypos<<20 + xpos<<8 + format) + inf->win1fb->var.grayscale = 0; //win1 transprent mode & value(mode<<8 + value) + inf->win1fb->var.activate = FB_ACTIVATE_NOW; + inf->win1fb->var.accel_flags = 0; + inf->win1fb->var.vmode = FB_VMODE_NONINTERLACED; + + inf->win1fb->fbops = &win1fb_ops; + inf->win1fb->flags = FBINFO_FLAG_DEFAULT; + inf->win1fb->pseudo_palette = ((struct win1_par*)inf->win1fb->par)->pseudo_pal; + inf->win1fb->screen_base = 0; + + memset(inf->win1fb->par, 0, sizeof(struct win1_par)); + ret = fb_alloc_cmap(&inf->win1fb->cmap, 256, 0); + if (ret < 0) + goto release_cmap; + + /* Prepare win0 info */ + fbprintk(">> Prepare win0 info \n"); + inf->win0fb = framebuffer_alloc(sizeof(struct win0_par), &pdev->dev); + if(!inf->win0fb) + { + dev_err(&pdev->dev, ">> win0fb framebuffer_alloc fail!"); + inf->win0fb = NULL; + ret = -ENOMEM; + goto release_win0fb; + } + + strcpy(inf->win0fb->fix.id, "win0fb"); + inf->win0fb->fix.type = FB_TYPE_PACKED_PIXELS; + inf->win0fb->fix.type_aux = 0; + inf->win0fb->fix.xpanstep = 1; + inf->win0fb->fix.ypanstep = 1; + inf->win0fb->fix.ywrapstep = 0; + inf->win0fb->fix.accel = FB_ACCEL_NONE; + inf->win0fb->fix.visual = FB_VISUAL_TRUECOLOR; + inf->win0fb->fix.smem_len = 0; + inf->win0fb->fix.line_length = 0; + inf->win0fb->fix.smem_start = 0; + + inf->win0fb->var.xres = screen->x_res; + inf->win0fb->var.yres = screen->y_res; + inf->win0fb->var.bits_per_pixel = 16; + inf->win0fb->var.xres_virtual = screen->x_res; + inf->win0fb->var.yres_virtual = screen->y_res; + inf->win0fb->var.width = screen->x_res; + inf->win0fb->var.height = screen->y_res; + inf->win0fb->var.pixclock = screen->pixclock; + inf->win0fb->var.left_margin = screen->left_margin; + inf->win0fb->var.right_margin = screen->right_margin; + inf->win0fb->var.upper_margin = screen->upper_margin; + inf->win0fb->var.lower_margin = screen->lower_margin; + inf->win0fb->var.vsync_len = screen->vsync_len; + inf->win0fb->var.hsync_len = screen->hsync_len; + inf->win0fb->var.red = def_rgb_16.red; + inf->win0fb->var.green = def_rgb_16.green; + inf->win0fb->var.blue = def_rgb_16.blue; + inf->win0fb->var.transp = def_rgb_16.transp; + + inf->win0fb->var.nonstd = 0; //win0 format & ypos & xpos (ypos<<20 + xpos<<8 + format) + inf->win0fb->var.grayscale = ((inf->win0fb->var.yres<<20)&0xfff00000) + ((inf->win0fb->var.xres<<8)&0xfff00);//win0 xsize & ysize + inf->win0fb->var.activate = FB_ACTIVATE_NOW; + inf->win0fb->var.accel_flags = 0; + inf->win0fb->var.vmode = FB_VMODE_NONINTERLACED; + + inf->win0fb->fbops = &win0fb_ops; + inf->win0fb->flags = FBINFO_FLAG_DEFAULT; + inf->win0fb->pseudo_palette = ((struct win0_par*)inf->win0fb->par)->pseudo_pal; + inf->win0fb->screen_base = 0; + + memset(inf->win0fb->par, 0, sizeof(struct win0_par)); + + /* Init all lcdc and lcd before register_framebuffer. */ + /* because after register_framebuffer, the win1fb_check_par and winfb_set_par execute immediately */ + fbprintk(">> Init all lcdc and lcd before register_framebuffer \n"); + init_lcdc(inf->win1fb); +#if 0 + inf->clk = clk_get(&pdev->dev, "lcdc_hclk"); + if (!inf->clk || IS_ERR(inf->clk)) + { + printk(KERN_ERR "failed to get lcdc_hclk source\n"); + ret = -ENOENT; + goto unregister_win1fb; + } + + inf->dclk = clk_get(&pdev->dev, "lcdc"); + if (!inf->dclk || IS_ERR(inf->dclk)) + { + printk(KERN_ERR "failed to get lcd dclock source\n"); + ret = -ENOENT; + goto unregister_win1fb; + } + inf->dclk_parent = clk_get(&pdev->dev, "arm_pll"); + if (!inf->dclk_parent || IS_ERR(inf->dclk_parent)) + { + printk(KERN_ERR "failed to get lcd dclock parent source\n"); + ret = -ENOENT; + goto unregister_win1fb; + } + inf->dclk_divider= clk_get(&pdev->dev, "lcdc_divider"); + if (!inf->dclk_divider || IS_ERR(inf->dclk_divider)) + { + printk(KERN_ERR "failed to get lcd clock lcdc_divider source \n"); + ret = -ENOENT; + goto unregister_win1fb; + } + + inf->clk_share_mem = clk_get(&pdev->dev, "lcdc_share_memory"); + if (!inf->clk_share_mem || IS_ERR(inf->clk_share_mem)) + { + dev_err(&pdev->dev, "failed to get lcd clock clk_share_mem source \n"); + ret = -ENOENT; + goto unregister_win1fb; + } + #ifdef CONFIG_CPU_FREQ + inf->freq_transition.notifier_call = rk29fb_freq_transition; + cpufreq_register_notifier(&inf->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); + #endif + fbprintk("got clock\n"); +#endif + + if(mach_info) + { + struct rk29_fb_setting_info fb_setting; + if( OUT_P888==inf->lcd_info.face || + OUT_P888==inf->tv_info[0].face || + OUT_P888==inf->hdmi_info[0].face ) // set lcdc iomux + { + fb_setting.data_num = 24; + } + else if(OUT_P666 == inf->lcd_info.face ) + { + fb_setting.data_num = 18; + } + else + { + fb_setting.data_num = 16; + } + fb_setting.den_en = 1; + fb_setting.vsync_en = 1; + fb_setting.disp_on_en = 1; + fb_setting.standby_en = 1; + if( inf->lcd_info.mcu_usefmk ) + fb_setting.mcu_fmk_en =1; + mach_info->io_init(&fb_setting); + } + + //set_lcd_pin(pdev, 1); + mdelay(10); + g_pdev = pdev; + inf->mcu_usetimer = 1; + inf->mcu_fmksync = 0; + load_screen(inf->win1fb, 1); + + /* Register framebuffer(win1fb & win0fb) */ + fbprintk(">> Register framebuffer(win1fb) \n"); + ret = register_framebuffer(inf->win1fb); + if(ret<0) + { + printk(">> win1fb register_framebuffer fail!\n"); + ret = -EINVAL; + goto release_win0fb; + } + fbprintk(">> Register framebuffer(win0fb) \n"); + + ret = register_framebuffer(inf->win0fb); + if(ret<0) + { + printk(">> win0fb register_framebuffer fail!\n"); + ret = -EINVAL; + goto unregister_win1fb; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + suspend_info.inf = inf; + register_early_suspend(&suspend_info.early_suspend); +#endif + + /* get and request irq */ + fbprintk(">> get and request irq \n"); + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "no irq for device\n"); + ret = -ENOENT; + goto unregister_win1fb; + } + ret = request_irq(irq, rk29fb_irq, IRQF_DISABLED, pdev->name, pdev); + if (ret) { + dev_err(&pdev->dev, "cannot get irq %d - err %d\n", irq, ret); + ret = -EBUSY; + goto release_irq; + } + + if( inf->lcd_info.mcu_usefmk && (mach_info->mcu_fmk_pin != -1) ) + { + ret = request_irq(gpio_to_irq(mach_info->mcu_fmk_pin), mcu_irqfmk, GPIOEdgelFalling, pdev->name, pdev); + if (ret) + { + dev_err(&pdev->dev, "cannot get fmk irq %d - err %d\n", irq, ret); + ret = -EBUSY; + goto release_irq; + } + } + + printk(" %s ok\n", __FUNCTION__); + return ret; + +release_irq: + if(irq>=0) + free_irq(irq, pdev); +unregister_win1fb: + unregister_framebuffer(inf->win1fb); +release_win0fb: + if(inf->win0fb) + framebuffer_release(inf->win0fb); + inf->win0fb = NULL; +release_cmap: + if(&inf->win1fb->cmap) + fb_dealloc_cmap(&inf->win1fb->cmap); +release_win1fb: + if(inf->win1fb) + framebuffer_release(inf->win1fb); + inf->win1fb = NULL; +release_drvdata: + if(inf && inf->reg_vir_base) + iounmap(inf->reg_vir_base); + if(inf && mem) + release_mem_region(inf->reg_phy_base, inf->len); + if(inf) + kfree(inf); + platform_set_drvdata(pdev, NULL); + return ret; +} + +static int rk29fb_remove(struct platform_device *pdev) +{ + struct rk29fb_inf *inf = platform_get_drvdata(pdev); + struct fb_info *info = NULL; + //pm_message_t msg; + struct rk29fb_info *mach_info = NULL; + int irq = 0; + + fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__); + + if(!inf) { + printk("inf==0, rk29_fb_remove fail! \n"); + return -EINVAL; + } + + irq = platform_get_irq(pdev, 0); + if (irq >0) + { + free_irq(irq, pdev); + } + + mach_info = pdev->dev.platform_data; + if(mach_info->mcu_fmk_pin) + { + free_irq(gpio_to_irq(mach_info->mcu_fmk_pin), pdev); + } + + set_lcd_pin(pdev, 0); + + // blank the lcdc + if(inf->win0fb) + win0fb_blank(FB_BLANK_POWERDOWN, inf->win0fb); + if(inf->win1fb) + win1fb_blank(FB_BLANK_POWERDOWN, inf->win1fb); + + // suspend the lcdc + //rk29fb_suspend(pdev, msg); + // unmap memory and release framebuffer + if(inf->win0fb) { + info = inf->win0fb; + if (info->screen_base) { + //dma_free_writecombine(NULL, PAGE_ALIGN(info->fix.smem_len),info->screen_base, info->fix.smem_start); + info->screen_base = 0; + info->fix.smem_start = 0; + info->fix.smem_len = 0; + } + unregister_framebuffer(inf->win0fb); + framebuffer_release(inf->win0fb); + inf->win0fb = NULL; + } + if(inf->win1fb) { + info = inf->win1fb; + if (info->screen_base) { + dma_free_writecombine(NULL, PAGE_ALIGN(info->fix.smem_len),info->screen_base, info->fix.smem_start); + info->screen_base = 0; + info->fix.smem_start = 0; + info->fix.smem_len = 0; + } + unregister_framebuffer(inf->win1fb); + framebuffer_release(inf->win1fb); + inf->win1fb = NULL; + } + + #ifdef CONFIG_CPU_FREQ + cpufreq_unregister_notifier(&inf->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); + #endif + + if (inf->clk) + { + clk_disable(inf->clk); + clk_put(inf->clk); + inf->clk = NULL; + } + if (inf->dclk) + { + clk_disable(inf->dclk); + clk_put(inf->dclk); + inf->dclk = NULL; + } + + kfree(inf); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static void rk29fb_shutdown(struct platform_device *pdev) +{ + struct rk29fb_inf *inf = platform_get_drvdata(pdev); + mdelay(300); + //printk("----------------------------rk29fb_shutdown----------------------------\n"); + set_lcd_pin(pdev, 0); + if (inf->dclk) + { + clk_disable(inf->dclk); + } + if (inf->clk) + { + clk_disable(inf->clk); + } +} + +static struct platform_driver rk29fb_driver = { + .probe = rk29fb_probe, + .remove = rk29fb_remove, + .driver = { + .name = "rk29-fb", + .owner = THIS_MODULE, + }, + .shutdown = rk29fb_shutdown, +}; + +static int __init rk29fb_init(void) +{ + return platform_driver_register(&rk29fb_driver); +} + +static void __exit rk29fb_exit(void) +{ + platform_driver_unregister(&rk29fb_driver); +} + +//subsys_initcall(rk29fb_init); + +module_init(rk29fb_init); +module_exit(rk29fb_exit); + + +MODULE_AUTHOR(" zyw@rock-chips.com"); +MODULE_DESCRIPTION("Driver for rk29 fb device"); +MODULE_LICENSE("GPL"); + + diff --git a/drivers/video/rk29_fb.h b/drivers/video/rk29_fb.h new file mode 100755 index 000000000000..74bd6baa0c61 --- /dev/null +++ b/drivers/video/rk29_fb.h @@ -0,0 +1,436 @@ +/* drivers/video/rk29_fb.h + * + * Copyright (C) 2010 ROCKCHIP, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __ARCH_ARM_MACH_RK29_FB_H +#define __ARCH_ARM_MACH_RK29_FB_H + +/******************************************************************** +** 宏定义 * +********************************************************************/ +/* 输往屏的数据格式 */ +#define OUT_P888 0 +#define OUT_P666 1 +#define OUT_P565 2 +#define OUT_S888x 4 +#define OUT_CCIR656 6 +#define OUT_S888 8 +#define OUT_S888DUMY 12 +#define OUT_P16BPP4 24 //模拟方式,控制器并不支持 + + +/* SYS_CONFIG */ +#define m_W2_FORMAT (3<<0) +#define m_W1_FORMAT (1<<2) +#define m_W0_FORMAT (7<<3) +#define m_W0_CBR_DEFLICK_EN (1<<6) +#define m_W0_YRGB_DEFLICK_EN (1<<7) +#define m_INTERIACE_EN (1<<8) +#define m_W2_ENABLE (1<<9) +#define m_W1_ENABLE (1<<10) +#define m_W0_ENABLE (1<<11) +#define m_HWC_ENABLE (1<<12) +#define m_HWC_RELOAD_EN (1<<13) +#define m_W2_INTERLACE_READ (1<<14) +#define m_W1_INTERLACE_READ (1<<15) +#define m_W0_INTERLACE_READ (1<<16) +#define m_STANDBY (1<<17) +#define m_HWC_BURST (3<<18) +#define m_W2_BURST (3<<20) +#define m_W1_BURST (3<<22) +#define m_W0_BURST (3<<24) +#define m_W2_LUT_CTL (1<<26) +#define m_DSIP_LUT_CTL (1<<27) +#define m_HWC_REVERSED_COLOR (1<<28) +#define m_W1_AXI_OUTSTANDING2 (1<<29) +#define m_W0_AXI_OUTSTANDING2 (1<<30) + +#define v_W2_FORMAT(x) (((x)&3)<<0) +#define v_W1_FORMAT(x) (((x)&1)<<2) +#define v_W0_FORMAT(x) (((x)&7)<<3) +#define v_W0_CBR_DEFLICK_EN(x) (((x)&1)<<6) +#define v_W0_YRGB_DEFLICK_EN(x) (((x)&1)<<7) +#define v_INTERIACE_EN(x) (((x)&1)<<8) +#define v_W2_ENABLE(x) (((x)&)1<<9) +#define v_W1_ENABLE(x) (((x)&1)<<10) +#define v_W0_ENABLE(x) (((x)&1)<<11) +#define v_HWC_ENABLE(x) (((x)&1)<<12) +#define v_HWC_RELOAD_EN(x) (((x)&1)<<13) +#define v_W2_INTERLACE_READ(x) (((x)&1)<<14) +#define v_W1_INTERLACE_READ(x) (((x)&1)<<15) +#define v_W0_INTERLACE_READ(x) (((x)&1)<<16) +#define v_STANDBY(x) (((x)&1)<<17) +#define v_HWC_BURST(x) (((x)&3)<<18) +#define v_W2_BURST(x) (((x)&3)<<20) +#define v_W1_BURST(x) (((x)&3)<<22) +#define v_W0_BURST(x) (((x)&3)<<24) +#define v_W2_LUT_CTL(x) (((x)&1)<<26) +#define v_DSIP_LUT_CTL(x) (((x)&1)<<27) +#define v_HWC_REVERSED_COLOR(x) (((x)&1)<<28) +#define v_W1_AXI_OUTSTANDING2(x) (((x)&1)<<29) +#define v_W0_AXI_OUTSTANDING2(x) (((x)&1)<<30) + +//LCDC_SWAP_CTRL +#define m_W1_565_RB_SWAP (1<<0) +#define m_W0_565_RB_SWAP (1<<1) +#define m_W0_YRGB_M8_SWAP (1<<2) +#define m_W0_YRGB_R_SHIFT_SWAP (1<<3) +#define m_W0_CBR_R_SHIFT_SWAP (1<<4) +#define m_W0_YRGB_16_SWAP (1<<5) +#define m_W0_YRGB_8_SWAP (1<<6) +#define m_W0_CBR_16_SWAP (1<<7) +#define m_W0_CBR_8_SWAP (1<<8) +#define m_W1_16_SWAP (1<<9) +#define m_W1_8_SWAP (1<<10) +#define m_W1_R_SHIFT_SWAP (1<<11) +#define m_OUTPUT_BG_SWAP (1<<12) +#define m_OUTPUT_RB_SWAP (1<<13) +#define m_OUTPUT_RG_SWAP (1<<14) +#define m_DELTA_SWAP (1<<15) +#define m_DUMMY_SWAP (1<<16) +#define m_W2_BYTE_SWAP (1<<17) +#define v_W1_565_RB_SWAP(x) (((x)&1)<<0) +#define v_W0_565_RB_SWAP(x) (((x)&1)<<1) +#define v_W0_YRGB_M8_SWAP(x) (((x)&1)<<2) +#define v_W0_YRGB_R_SHIFT_SWAP(x) (((x)&1)<<3) +#define v_W0_CBR_R_SHIFT_SWAP(x) (((x)&1)<<4) +#define v_W0_YRGB_16_SWAP(x) (((x)&1)<<5) +#define v_W0_YRGB_8_SWAP(x) (((x)&1)<<6) +#define v_W0_CBR_16_SWAP(x) (((x)&1)<<7) +#define v_W0_CBR_8_SWAP(x) (((x)&1)<<8) +#define v_W1_16_SWAP(x) (((x)&1)<<9) +#define v_W1_8_SWAP(x) (((x)&1)<<10) +#define v_W1_R_SHIFT_SWAP(x) (((x)&1)<<11) +#define v_OUTPUT_BG_SWAP(x) (((x)&1)<<12) +#define v_OUTPUT_RB_SWAP(x) (((x)&1)<<13) +#define v_OUTPUT_RG_SWAP(x) (((x)&1)<<14) +#define v_DELTA_SWAP(x) (((x)&1)<<15) +#define v_DUMMY_SWAP(x) (((x)&1)<<16) +#define v_W2_BYTE_SWAP(x) (((x)&1)<<17) + +//LCDC_MCU_TIMING_CTRL +#define m_MCU_WRITE_PERIOD (31<<0) +#define m_MCU_CS_ST (31<<5) +#define m_MCU_CS_END (31<<10) +#define m_MCU_RW_ST (31<<15) +#define m_MCU_RW_END (31<<20) +#define m_MCU_HOLD_STATUS (1<<26) +#define m_MCU_HOLDMODE_SELECT (1<<27) +#define m_MCU_HOLDMODE_FRAME_ST (1<<28) +#define m_MCU_RS_SELECT (1<<29) +#define m_MCU_BYPASSMODE_SELECT (1<<30) +#define m_MCU_OUTPUT_SELECT (1<<31) +#define v_MCU_WRITE_PERIOD(x) (((x)&31)<<0) +#define v_MCU_CS_ST(x) (((x)&31)<<5) +#define v_MCU_CS_END(x) (((x)&31)<<10) +#define v_MCU_RW_ST(x) (((x)&31)<<15) +#define v_MCU_RW_END(x) (((x)&31)<<20) +#define v_MCU_HOLD_STATUS(x) (((x)&1)<<26) +#define v_MCU_HOLDMODE_SELECT(x) (((x)&1)<<27) +#define v_MCU_HOLDMODE_FRAME_ST(x) (((x)&1)<<28) +#define v_MCU_RS_SELECT(x) (((x)&1)<<29) +#define v_MCU_BYPASSMODE_SELECT(x) (((x)&1)<<30) +#define v_MCU_OUTPUT_SELECT(x) (((x)&1)<<31) + +//LCDC_ BLEND_CTRL +#define m_HWC_BLEND_EN (1<<0) +#define m_W2_BLEND_EN (1<<1) +#define m_W1_BLEND_EN (1<<2) +#define m_W0_BLEND_EN (1<<3) +#define m_HWC_BLEND_FACTOR (15<<4) +#define m_W2_BLEND_FACTOR (0xff<<8) +#define m_W1_BLEND_FACTOR (0xff<<16) +#define m_W0_BLEND_FACTOR (0xff<<24) + +#define v_HWC_BLEND_EN(x) (((x)&1)<<0) +#define v_W2_BLEND_EN(x) (((x)&1)<<1) +#define v_W1_BLEND_EN(x) (((x)&1)<<2) +#define v_W0_BLEND_EN(x) (((x)&1)<<3) +#define v_HWC_BLEND_FACTOR(x) (((x)&15)<<4) +#define v_W2_BLEND_FACTOR(x) (((x)&0xff)<<8) +#define v_W1_BLEND_FACTOR(x) (((x)&0xff)<<16) +#define v_W0_BLEND_FACTOR(x) (((x)&0xff)<<24) + + +//LCDC_WIN0_COLOR_KEY_CTRL / LCDC_WIN1_COLOR_KEY_CTRL +#define m_KEYCOLOR (0xffffff<<0) +#define m_KEYCOLOR_B (0xff<<0) +#define m_KEYCOLOR_G (0xff<<8) +#define m_KEYCOLOR_R (0xff<<16) +#define m_COLORKEY_EN (1<<24) +#define v_KEYCOLOR(x) (((x)&0xffffff)<<0) +#define v_KEYCOLOR_B(x) (((x)&0xff)<<0) +#define v_KEYCOLOR_G(x) (((x)&0xff)<<8) +#define v_KEYCOLOR_R(x) (((x)&0xff)<<16) +#define v_COLORKEY_EN(x) (((x)&1)<<24) + +//LCDC_DEFLICKER_SCL_OFFSET +#define m_W0_YRGB_VSD_OFFSET (0xff<<0) +#define m_W0_YRGB_VSP_OFFSET (0xff<<8) +#define m_W1_VSD_OFFSET (0xff<<16) +#define m_W1_VSP_OFFSET (0xff<<24) +#define v_W0_YRGB_VSD_OFFSET(x) (((x)&0xff)<<0) +#define v_W0_YRGB_VSP_OFFSET(x) (((x)&0xff)<<8) +#define v_W1_VSD_OFFSET(x) (((x)&0xff)<<16) +#define v_W1_VSP_OFFSET(x) (((x)&0xff)<<24) + +//LCDC_DSP_CTRL_REG0 +#define m_DISPLAY_FORMAT (0xf<<0) +#define m_HSYNC_POLARITY (1<<4) +#define m_VSYNC_POLARITY (1<<5) +#define m_DEN_POLARITY (1<<6) +#define m_DCLK_POLARITY (1<<7) +#define m_COLOR_SPACE_CONVERSION (3<<8) +#define m_DITHER_UP_EN (1<<10) +#define m_DITHER_DOWN_MODE (1<<11) +#define m_DITHER_DOWN_EN (1<<12) +#define m_INTERLACE_FIELD_POLARITY (1<<13) +#define m_YUV_CLIP (1<<14) +#define m_W1_TRANSP_FROM (1<<15) +#define m_W0_TRANSP_FROM (1<<16) +#define m_W0_ON_TOP (1<<17) +#define m_W1_CLIP_EN (1<<18) +#define m_W0_CLIP_EN (1<<19) +#define m_W0_YCBR_PRIORITY_MODE (1<<20) +#define m_CBR_FILTER_656 (1<<21) +#define m_W2_CHIP_EN (1<<22) + +#define v_DISPLAY_FORMAT(x) (((x)&0xf)<<0) +#define v_HSYNC_POLARITY(x) (((x)&1)<<4) +#define v_VSYNC_POLARITY(x) (((x)&1)<<5) +#define v_DEN_POLARITY(x) (((x)&1)<<6) +#define v_DCLK_POLARITY(x) (((x)&1)<<7) +#define v_COLOR_SPACE_CONVERSION(x) (((x)&3)<<8) +#define v_DITHER_UP_EN(x) (((x)&1)<<10) +#define v_DITHER_DOWN_MODE(x) (((x)&1)<<11) +#define v_DITHER_DOWN_EN(x) (((x)&1)<<12) +#define v_INTERLACE_FIELD_POLARITY(x) (((x)&1)<<13) +#define v_YUV_CLIP(x) (((x)&1)<<14) +#define v_W1_TRANSP_FROM(x) (((x)&1)<<15) +#define v_W0_TRANSP_FROM(x) (((x)&1)<<16) +#define v_W0_ON_TOP(x) (((x)&1)<<17) +#define v_W1_CLIP_EN(x) (((x)&1)<<18) +#define v_W0_CLIP_EN(x) (((x)&1)<<19) +#define v_W0_YCBR_PRIORITY_MODE(x) (((x)&1)<<20) +#define v_CBR_FILTER_656(x) (((x)&1)<<21) +#define v_W2_CHIP_EN(x) (((x)&1)<<22) + + +//LCDC_DSP_CTRL_REG1 +#define m_BG_COLOR (0xffffff<<0) +#define m_BG_B (0xff<<0) +#define m_BG_G (0xff<<8) +#define m_BG_R (0xff<<16) +#define m_BLANK_MODE (1<<24) +#define m_BLACK_MODE (1<<25) +#define m_DISP_FILTER_FACTOR (3<<26) +#define m_DISP_FILTER_MODE (1<<28) +#define m_DISP_FILTER_EN (1<<29) +#define v_BG_COLOR(x) (((x)&0xffffff)<<0) +#define v_BG_B(x) (((x)&0xff)<<0) +#define v_BG_G(x) (((x)&0xff)<<8) +#define v_BG_R(x) (((x)&0xff)<<16) +#define v_BLANK_MODE(x) (((x)&1)<<24) +#define v_BLACK_MODE(x) (((x)&1)<<25) +#define v_DISP_FILTER_FACTOR(x) (((x)&3)<<26) +#define v_DISP_FILTER_MODE(x) (((x)&1)<<28) +#define v_DISP_FILTER_EN(x) (((x)&1)<<29) + +//LCDC_INT_STATUS +#define m_HOR_START (1<<0) +#define m_FRM_START (1<<1) +#define m_SCANNING_FLAG (1<<2) +#define m_HOR_STARTMASK (1<<3) +#define m_FRM_STARTMASK (1<<4) +#define m_SCANNING_MASK (1<<5) +#define m_HOR_STARTCLEAR (1<<6) +#define m_FRM_STARTCLEAR (1<<7) +#define m_SCANNING_CLEAR (1<<8) +#define m_SCAN_LINE_NUM (0x7ff<<9) +#define v_HOR_START(x) (((x)&1)<<0) +#define v_FRM_START(x) (((x)&1)<<1) +#define v_SCANNING_FLAG(x) (((x)&1)<<2) +#define v_HOR_STARTMASK(x) (((x)&1)<<3) +#define v_FRM_STARTMASK(x) (((x)&1)<<4) +#define v_SCANNING_MASK(x) (((x)&1)<<5) +#define v_HOR_STARTCLEAR(x) (((x)&1)<<6) +#define v_FRM_STARTCLEAR(x) (((x)&1)<<7) +#define v_SCANNING_CLEAR(x) (((x)&1)<<8) +#define v_SCAN_LINE_NUM(x) (((x)&0x7ff)<<9) + +//AXI MS ID +#define m_W0_YRGB_CH_ID (0xF<<0) +#define m_W0_CBR_CH_ID (0xF<<4) +#define m_W1_YRGB_CH_ID (0xF<<8) +#define m_W2_CH_ID (0xF<<12) +#define m_HWC_CH_ID (0xF<<16) +#define v_W0_YRGB_CH_ID(x) (((x)&0xF)<<0) +#define v_W0_CBR_CH_ID(x) (((x)&0xF)<<4) +#define v_W1_YRGB_CH_ID(x) (((x)&0xF)<<8) +#define v_W2_CH_ID(x) (((x)&0xF)<<12) +#define v_HWC_CH_ID(x) (((x)&0xF)<<16) + + +/* Low Bits Mask */ +#define m_WORDLO (0xffff<<0) +#define m_WORDHI (0xffff<<16) +#define v_WORDLO(x) (((x)&0xffff)<<0) +#define v_WORDHI(x) (((x)&0xffff)<<16) + +#define m_BIT11LO (0x7ff<<0) +#define m_BIT11HI (0x7ff<<16) +#define v_BIT11LO(x) (((x)&0x7ff)<<0) +#define v_BIT11HI(x) (((x)&0x7ff)<<16) + + +#define m_VIRWIDTH (0xffff<<0) +#define m_VIRHEIGHT (0xffff<<16) +#define v_VIRWIDTH(x) (((x)&0xffff)<<0) +#define v_VIRHEIGHT(x) (((x)&0xffff)<<16) + +#define m_ACTWIDTH (0xffff<<0) +#define m_ACTHEIGHT (0xffff<<16) +#define v_ACTWIDTH(x) (((x)&0xffff)<<0) +#define v_ACTHEIGHT(x) (((x)&0xffff)<<16) + +#define m_VIRST_X (0xffff<<0) +#define m_VIRST_Y (0xffff<<16) +#define v_VIRST_X(x) (((x)&0xffff)<<0) +#define v_VIRST_Y(x) (((x)&0xffff)<<16) + +#define m_PANELST_X (0x3ff<<0) +#define m_PANELST_Y (0x3ff<<16) +#define v_PANELST_X(x) (((x)&0x3ff)<<0) +#define v_PANELST_Y(x) (((x)&0x3ff)<<16) + +#define m_PANELWIDTH (0x3ff<<0) +#define m_PANELHEIGHT (0x3ff<<16) +#define v_PANELWIDTH(x) (((x)&0x3ff)<<0) +#define v_PANELHEIGHT(x) (((x)&0x3ff)<<16) + +#define m_HWC_B (0xff<<0) +#define m_HWC_G (0xff<<8) +#define m_HWC_R (0xff<<16) +#define m_W0_YRGB_HSP_OFFSET (0xff<<24) +#define m_W0_YRGB_HSD_OFFSET (0xff<<24) +#define v_HWC_B(x) (((x)&0xff)<<0) +#define v_HWC_G(x) (((x)&0xff)<<8) +#define v_HWC_R(x) (((x)&0xff)<<16) +#define v_W0_YRGB_HSP_OFFSET(x) (((x)&0xff)<<24) +#define v_W0_YRGB_HSD_OFFSET(x) (((x)&0xff)<<24) + + +//Panel display scanning +#define m_PANEL_HSYNC_WIDTH (0x3ff<<0) +#define m_PANEL_HORIZONTAL_PERIOD (0x3ff<<16) +#define v_PANEL_HSYNC_WIDTH(x) (((x)&0x3ff)<<0) +#define v_PANEL_HORIZONTAL_PERIOD(x) (((x)&0x3ff)<<16) + +#define m_PANEL_END (0x3ff<<0) +#define m_PANEL_START (0x3ff<<16) +#define v_PANEL_END(x) (((x)&0x3ff)<<0) +#define v_PANEL_START(x) (((x)&0x3ff)<<16) + +#define m_PANEL_VSYNC_WIDTH (0x3ff<<0) +#define m_PANEL_VERTICAL_PERIOD (0x3ff<<16) +#define v_PANEL_VSYNC_WIDTH(x) (((x)&0x3ff)<<0) +#define v_PANEL_VERTICAL_PERIOD(x) (((x)&0x3ff)<<16) +//----------- + +#define m_HSCALE_FACTOR (0xffff<<0) +#define m_VSCALE_FACTOR (0xffff<<16) +#define v_HSCALE_FACTOR(x) (((x)&0xffff)<<0) +#define v_VSCALE_FACTOR(x) (((x)&0xffff)<<16) + +#define m_W0_CBR_HSD_OFFSET (0xff<<0) +#define m_W0_CBR_HSP_OFFSET (0xff<<8) +#define m_W0_CBR_VSD_OFFSET (0xff<<16) +#define m_W0_CBR_VSP_OFFSET (0xff<<24) +#define v_W0_CBR_HSD_OFFSET(x) (((x)&0xff)<<0) +#define v_W0_CBR_HSP_OFFSET(x) (((x)&0xff)<<8) +#define v_W0_CBR_VSD_OFFSET(x) (((x)&0xff)<<16) +#define v_W0_CBR_VSP_OFFSET(x) (((x)&0xff)<<24) + + +#define FB0_IOCTL_STOP_TIMER_FLUSH 0x6001 +#define FB0_IOCTL_SET_PANEL 0x6002 + +#define FB1_IOCTL_GET_PANEL_SIZE 0x5001 +#define FB1_IOCTL_SET_YUV_ADDR 0x5002 +//#define FB1_TOCTL_SET_MCU_DIR 0x5003 +#define FB1_IOCTL_SET_ROTATE 0x5003 +#define FB1_IOCTL_SET_I2P_ODD_ADDR 0x5005 +#define FB1_IOCTL_SET_I2P_EVEN_ADDR 0x5006 + + +/******************************************************************** +** 结构定义 * +********************************************************************/ +/* LCDC的寄存器结构 */ + +typedef volatile struct tagLCDC_REG +{ + /* offset 0x00~0xc0 */ + unsigned int SYS_CONFIG; //0x00 SYSTEM configure register + unsigned int SWAP_CTRL; //0x04 Data SWAP control + unsigned int MCU_TIMING_CTRL; //0x08 MCU TIMING control register + unsigned int BLEND_CTRL; //0x0c Blending control register + unsigned int WIN0_COLOR_KEY_CTRL; //0x10 Win0 blending control register + unsigned int WIN1_COLOR_KEY_CTRL; //0x14 Win1 blending control register + unsigned int WIN2_VIR; //0x18 WIN2 virtual display width + unsigned int DSP_CTRL0; //0x1c Display control register0 + unsigned int DSP_CTRL1; //0x20 Display control register1 + unsigned int INT_STATUS; //0x24 Interrupt status register + unsigned int WIN0_VIR; //0x28 WIN0 virtual display width/height + unsigned int WIN0_YRGB_MST; //0x2c Win0 active YRGB memory start address + unsigned int WIN0_CBR_MST; //0x30 Win0 active Cbr memory start address + unsigned int WIN0_ACT_INFO; //0x34 Win0 active window width/height + unsigned int WIN0_DSP_ST; //0x38 Win0 display start point on panel + unsigned int WIN0_DSP_INFO; //0x3c Win0 display width/height on panel + unsigned int WIN1_VIR; //0x40 Win1 virtual display width/height + unsigned int WIN1_YRGB_MST; //0x44 Win1 active memory start address + unsigned int WIN1_DSP_INFO; //0x48 Win1 display width/height on panel + unsigned int WIN1_DSP_ST; //0x4c Win1 display start point on panel + unsigned int WIN2_MST; //0X50 Win2 memory start address + unsigned int WIN2_DSP_INFO; //0x54 Win1 display width/height on panel + unsigned int WIN2_DSP_ST; //0x58 Win1 display start point on panel + unsigned int HWC_MST; //0x5C HWC memory start address + unsigned int HWC_DSP_ST; //0x60 HWC display start point on panel + unsigned int HWC_COLOR_LUT0; //0x64 Hardware cursor color 2’b01 look up table 0 + unsigned int HWC_COLOR_LUT1; //0x68 Hardware cursor color 2’b10 look up table 1 + unsigned int HWC_COLOR_LUT2; //0x6c Hardware cursor color 2’b11 look up table 2 + unsigned int DSP_HTOTAL_HS_END; //0x70 Panel scanning horizontal width and hsync pulse end point + unsigned int DSP_HACT_ST_END; //0x74 Panel active horizontal scanning start/end point + unsigned int DSP_VTOTAL_VS_END; //0x78 Panel scanning vertical height and vsync pulse end point + unsigned int DSP_VACT_ST_END; //0x7c Panel active vertical scanning start/end point + unsigned int DSP_VS_ST_END_F1; //0x80 Vertical scanning start point and vsync pulse end point of even filed in interlace mode + unsigned int DSP_VACT_ST_END_F1; //0x84 Vertical scanning active start/end point of even filed in interlace mode + unsigned int WIN0_SCL_FACTOR_YRGB; //0x88 Win0 YRGB scaling down factor setting + unsigned int WIN0_SCL_FACTOR_CBR; //0x8c Win0 YRGB scaling up factor setting + unsigned int WIN0_SCL_OFFSET; //0x90 Win0 Cbr scaling start point offset + unsigned int FIFO_WATER_MARK; //0x94 Fifo water mark + unsigned int AXI_MS_ID; //0x98 Axi master ID + unsigned int reserved0; //0x9c + unsigned int REG_CFG_DONE; //0xa0 REGISTER CONFIG FINISH + unsigned int reserved1[(0x100-0xa4)/4]; + unsigned int MCU_BYPASS_WPORT; //0x100 MCU BYPASS MODE, DATA Write Only Port + unsigned int reserved2[(0x200-0x104)/4]; + unsigned int MCU_BYPASS_RPORT; //0x200 MCU BYPASS MODE, DATA Read Only Port +} LCDC_REG, *pLCDC_REG; + + +extern void __init rk29_add_device_lcdc(void); +extern int mcu_ioctl(unsigned int cmd, unsigned long arg); + +#endif diff --git a/fs/yaffs2/yaffs_fs.c b/fs/yaffs2/yaffs_fs.c index b3f4f0312760..2910bac817b4 100644 --- a/fs/yaffs2/yaffs_fs.c +++ b/fs/yaffs2/yaffs_fs.c @@ -2189,7 +2189,7 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, dev->nReservedBlocks = 5; dev->nShortOpCaches = (options.no_cache) ? 0 : 10; dev->inbandTags = options.inband_tags; -#ifdef CONFIG_ARCH_RK2818 +#if defined (CONFIG_ARCH_RK2818) || (CONFIG_ARCH_RK29) dev->inbandTags = 1; #endif